HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux wordpress-ubuntu-s-2vcpu-4gb-fra1-01 5.4.0-169-generic #187-Ubuntu SMP Thu Nov 23 14:52:28 UTC 2023 x86_64
User: root (0)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/dinamo-shop/wp-content/plugins/bulk-edit/index.php
<?php
/*
Plugin Name: Dinamo Bulk edit
Plugin URI: http://gnkdinamo.hr
Description: Dinamo bulk edit plugin
Version: 1.0
Author: Dinamo
Author URI: http://www.gnkdinamo.hr/
Text Domain: dinamo
*/


add_action( 'admin_enqueue_scripts', function(){
  wp_enqueue_script( 'jquery-toast-js', plugins_url() . '/bulk-edit/jquery-toast-plugin-master/dist/jquery.toast.min.js', array('jquery'), '1.0', true );
  //wp_enqueue_style( 'jquery-toast-css', plugins_url() . '/bulk-edit/jquery-toast-plugin-master/dist/jquery.toast.min.css', array(), '1.0', true );
});




add_action( 'admin_menu', 'sitepoint_settings_page' );

function sitepoint_settings_page() {
  add_menu_page( "Bulk edit", "Bulk edit", "manage_bulk", "dinamo-bulk-edit", "bulk_page_display" );
  $admin_role = get_role( 'administrator' );
  $admin_role->add_cap( 'manage_bulk', true );
}

add_action( 'init', function(){
  /* remove_role( 'product_manager' ); */
  add_role( 'product_manager', 'Product Manager', array(
      'read'         => true,
      'edit_posts' => true,
      "manage_bulk" => true,
  ));  
});




add_action( 'admin_menu', function(){
  $curr_user = wp_get_current_user();

  $menus = $GLOBALS[ 'menu' ];

  if( in_array( 'product_manager', $curr_user->roles ) ){
    foreach( $menus as $menu ){
      if( $menu['2'] != 'dinamo-bulk-edit' ){
      remove_menu_page( $menu['2'] );
      }
    }
  }

}, 999);


add_action( 'current_screen', function(){
  $screen = get_current_screen();
  
  $curr_user = wp_get_current_user();

    if( $screen->id != 'toplevel_page_dinamo-bulk-edit' && in_array( 'product_manager', $curr_user->roles ) ){
      wp_redirect( admin_url('admin.php?page=dinamo-bulk-edit' ) );
    }

});







function bulk_get_products( $query ){
  ob_start();

  if ( $query->have_posts() ) :
    while ( $query->have_posts() ) : $query->the_post();

    $product = wc_get_product(get_the_ID());

    $lowstock = get_option('woocommerce_notify_low_stock_amount');

    if($product->is_type('simple')){ ?>

      <?php $stock = $product->get_total_stock(); ?>

      <tr data-product-row="<?= get_the_ID(); ?>" <?= ( $stock <= $lowstock ) ? 'style="background-color: #fee"' : '' ?> >
        <td><?= $product->get_sku(); ?></td>

        <td><?= the_title(); ?></td>

        <td>
          <input data-product-price="<?= get_the_ID(); ?>"  type="number" style="width:100px;" value="<?= $product->get_regular_price(); ?>" />
        </td>

        <td>
          <input data-product-sale="<?= get_the_ID(); ?>" type="number" style="width:100px;" value="<?= $product->get_sale_price(); ?>" />

          <?php
          $sale_start = get_post_meta( get_the_ID(), '_sale_price_dates_from', true );

          $sale_end   = get_post_meta( get_the_ID(), '_sale_price_dates_to', true ); ?>
          <br>
          <?php
          if($sale_start) {
            $sale_start_val = date('Y-m-d', $sale_start);
          }else{
            $sale_start_val = "";
          }
          ?>
          <div style="display:none;">
          <input  data-product-sale-start="<?= get_the_ID(); ?>" style="width:100px;" type="text" value="<?= $sale_start_val ?>" placeholder="dd/mm/yyyy" onfocus="(this.type='date')" />
          <br>
          <?php
          if($sale_end) {
            $sale_end_val = date('Y-m-d', $sale_end);
          }else{
            $sale_end_val = "";
          }
          ?>
          <input  data-product-sale-end="<?= get_the_ID(); ?>" style="width:100px;" type="text" value="<?= $sale_end_val ?>" placeholder="dd/mm/yyyy" onfocus="(this.type='date')" />
          </div>
        </td>

        <td>
          <input   data-product-qt="<?= get_the_ID(); ?>" style="width:100px;" value="<?= $product->get_stock_quantity(); ?>" />
        </td>

        <td>
          <button data-save-product="<?= get_the_ID(); ?>">Spremi</button>
        </td>
      </tr>
    <?php } else {

      $available_variations = $product->get_available_variations();

      foreach ($available_variations as $variation) {
        // var_dump($value);

        $variation = new WC_Product_Variation( $variation['variation_id'] );

        $manage_stock = $variation->get_manage_stock();

        $stock = ( $manage_stock === true ) ? $variation->get_stock_quantity() : 0;


        ?>
        <tr data-product-row="<?= $variation->get_id() ?>" <?= ( $variation->get_manage_stock() && ($stock <= $lowstock) ) ? 'style="background-color: #fee"' : '' ?>>
          <td><?= $product->get_sku(); ?></td>

          <td><?= $variation->name ?></td>

          <td>
            <input data-product-price="<?= $variation->get_id() ?>" type="number" style="width:100px;" value="<?= $variation->regular_price ?>" />
          </td>

          <td>


            <input data-product-sale="<?= $variation->get_id() ?>" type="number" style="width:100px;" value="<?= $variation->sale_price ?>" />


            <?php
            $sale_start = get_post_meta( $variation->get_id(), '_sale_price_dates_from', true );
            $sale_end   = get_post_meta( $variation->get_id(), '_sale_price_dates_to', true ); ?>

            <?php
            if($sale_start) {
              $sale_start_val = date('Y-m-d', $sale_start);
            }else{
              $sale_start_val = "";
            }
            ?>

            <?php
            if($sale_end) {
              $sale_end_val = date('Y-m-d', $sale_end);
            }else{
              $sale_end_val = "";
            }
            ?>

            <br>
            <div style="display:none;">
            <input data-product-sale-start="<?= $variation->get_id() ?>" style="width:100px;" type="text" value="<?= $sale_start_val ?>" placeholder="dd/mm/yyyy" onfocus="(this.type='date')" /> početak akcije
            <br>
            <input data-product-sale-end="<?= $variation->get_id() ?>" style="width:100px;" type="text" value="<?= $sale_end_val ?>" placeholder="dd/mm/yyyy" onfocus="(this.type='date')" /> kraj akcije
            </div>
          </td>

          <td>
          <?php if( $manage_stock !== true ) {
              echo '<br>';
              echo 'Upravljanje zalihama nije uključeno za varijaciju';
            } else { ?>
            <input data-product-qt="<?= $variation->get_id() ?>" style="width:100px;" value="<?= ( $manage_stock === true ) ? $variation->get_stock_quantity() : '' ?>" />
            <?php } ?>
          </td>


          <td>
            <button data-save-product="<?= $variation->get_id() ?>">Spremi</button>
          </td>
        </tr>

      <?php }
      ?>



    <?php } ?>

  <?php
endwhile;
endif;

$content = ob_get_clean();

echo $content;
}


function bulk_page_display() {

  $args = array(
    'post_type'      => 'product',
    'posts_per_page'  => -1,
  );

  $products_query = new WP_Query($args);


  ?>
    <style>
      .jq-toast-wrap,.jq-toast-wrap *{margin:0;padding:0}.jq-toast-wrap{display:block;position:fixed;width:250px;pointer-events:none!important;letter-spacing:normal;z-index:9000!important}.jq-toast-wrap.bottom-left{bottom:20px;left:20px}.jq-toast-wrap.bottom-right{bottom:20px;right:40px}.jq-toast-wrap.top-left{top:20px;left:20px}.jq-toast-wrap.top-right{top:20px;right:40px}.jq-toast-single{display:block;width:100%;padding:10px;margin:0 0 5px;border-radius:4px;font-size:12px;font-family:arial,sans-serif;line-height:17px;position:relative;pointer-events:all!important;background-color:#444;color:#fff}.jq-toast-single h2{font-family:arial,sans-serif;font-size:14px;margin:0 0 7px;background:0 0;color:inherit;line-height:inherit;letter-spacing:normal}.jq-toast-single a{color:#eee;text-decoration:none;font-weight:700;border-bottom:1px solid #fff;padding-bottom:3px;font-size:12px}.jq-toast-single ul{margin:0 0 0 15px;background:0 0;padding:0}.jq-toast-single ul li{list-style-type:disc!important;line-height:17px;background:0 0;margin:0;padding:0;letter-spacing:normal}.close-jq-toast-single{position:absolute;top:3px;right:7px;font-size:14px;cursor:pointer}.jq-toast-loader{display:block;position:absolute;top:-2px;height:5px;width:0;left:0;border-radius:5px;background:red}.jq-toast-loaded{width:100%}.jq-has-icon{padding:10px 10px 10px 50px;background-repeat:no-repeat;background-position:10px}.jq-icon-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=);background-color:#31708f;color:#d9edf7;border-color:#bce8f1}.jq-icon-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=);background-color:#8a6d3b;color:#fcf8e3;border-color:#faebcc}.jq-icon-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=);background-color:#a94442;color:#f2dede;border-color:#ebccd1}.jq-icon-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==);color:#dff0d8;background-color:#3c763d;border-color:#d6e9c6}
      .jq-toast-single{
        font-size: 24px;
        line-height: normal;
      }

    </style>
  <h1>Dinamo bulk edit</h1>

  <div id="save_success"></div>
  <div id="save_fail"></div>

  <form id="bulk_edit_search" method="POST">
    <p class="search-box">
      <label class="screen-reader-text" for="bulk-edit-search-input">Pretraži proizvode</label>
      <input id="bulk-edit-search-input" type="search" name="bulk-edit-search-input" value="">
      <input class="button" type="submit" value="Pretraži proizvode">
    </p>
  </form>

  <table class="wp-list-table widefat fixed striped pages">
    <thead>
      <tr>
        <td>
          Šifra
        </td>
        <td>
          Naziv
        </td>
        <td>
          Cijena
        </td>
        <td>
          Akcijska cijena
        </td>
        <td>
          Količina
        </td>
        <td>
          Akcije
        </td>
      </tr>
    </thead>
    <tbody id="bulk_edit_products">

      <?php bulk_get_products( $products_query ); ?>

  </tbody>
</table>


<script>

(function($){

  $("body").on('click', '[data-save-product]', function(e){

    var pid = $(e.currentTarget).attr('data-save-product');
    var price = $("[data-product-price='" + pid + "']").val();
    var sale = $("[data-product-sale='" + pid + "']").val();
    var sale_start = $("[data-product-sale-start='" + pid + "']").val();
    var sale_end = $("[data-product-sale-end='" + pid + "']").val();
    var qt = $("[data-product-qt='" + pid + "']").val();

    $("[data-product-row='" + pid + "']").css('opacity', '0.5');
    $.ajax({
      type: 'POST',
      dataType: 'json',
      url: ajaxurl,
      data: {
        'action': 'change_price_qt',
        'id' : pid,
        'price' : price,
        'sale' : sale,
        'sale_start' : sale_start,
        'sale_end' : sale_end,
        'qt' : qt

      }
    }).done(function(){
      $("[data-product-row='" + pid + "']").css('opacity', '1');
      $.toast({

        text: "Vaše promjene su uspješno pohranjene.",
        position:"bottom-right"
      })

    });
  });

  $("form#bulk_edit_search").on( 'submit', function(e){

    e.preventDefault();

    var table = $("tbody#bulk_edit_products");
    table.css( 'opacity', 0.5 );

    $.ajax({
      type: 'POST',
      dataType: 'json',
      url: ajaxurl,
      data: {
        'action': 'bulk_edit_search',
        's': $('form#bulk_edit_search #bulk-edit-search-input').val()
      },
    success: function(data){

      table.html(data.content);
      table.css( 'opacity', 1 );



    }
    });

  });
})(jQuery);

</script>
<?php
}



add_action( 'wp_ajax_change_price_qt', 'change_price_qt' );
function change_price_qt(){


  $id = $_POST["id"];
  $price = $_POST["price"];
  $sale = $_POST["sale"];
  $sale_start = $_POST["sale_start"];
  $sale_end = $_POST["sale_end"];
  $qt = $_POST["qt"];

  update_post_meta($id, '_regular_price', (float)$price);
  if( ! empty ($sale) ){
    update_post_meta($id, '_sale_price', (float)$sale);
    update_post_meta($id, '_price', (float)$sale);
  } else {
    update_post_meta($id, '_price', (float)$price);
  }
  if( ! empty ($sale_start) ){
    update_post_meta($id, '_sale_price_dates_from', strtotime($sale_start) );
  }
  if( ! empty ($sale_end) ){
    update_post_meta($id, '_sale_price_dates_to', strtotime($sale_end) );
  }
  wc_update_product_stock($id,(float)$qt);
  if((float)$qt > 0){
    wc_update_product_stock_status($id, 'instock');
  }else{
    wc_update_product_stock_status($id, 'outofstock');
  }

  if( $sale == (0 || false || null) ){
    delete_post_meta( $id, '_sale_price' );
  }

  $product = wc_get_product( $id );


  if( $product->is_type( 'simple' ) ){

    $price = get_post_meta( '_regular_price', $id );
    $sale  = get_post_meta( '_sale_price', $id );

    if( metadata_exists( 'post', $id, '_sale_price' ) ){
      update_post_meta( $id, 'is_sale', 1 );
    } else {
      delete_post_meta( $id, 'is_sale');
    }

    algolia_add_product( $id );

  } else {

    $variation = wc_get_product( $id );
    //
    $parent = wc_get_product( $variation->get_parent_id() );
    delete_transient("wc_var_prices_" . $variation->get_parent_id() );
    $parent->get_variation_prices();
    $variations = $parent->get_available_variations();

    foreach( $variations as $v ){
      $var_id = $v['variation_id'];

      if( metadata_exists( 'post', $var_id, '_sale_price' ) ){
        $result[] = $var_id;
      } 

    }


    if( ! empty( $result ) ){

      update_post_meta( $parent->id, 'is_sale', 1 );
    } else {
        delete_post_meta( $parent->id, 'is_sale');
    }

    algolia_add_product( $parent->id );


  }



}

function title_filter($where, &$wp_query){
  global $wpdb;
  if($search_term = $wp_query->get( 'title_filter' )){
      $search_term = $wpdb->esc_like($search_term);
      $search_term = ' \'%' . $search_term . '%\'';
      $title_filter_relation = (strtoupper($wp_query->get( 'title_filter_relation'))=='OR' ? 'OR' : 'AND');
      $where .= ' '.$title_filter_relation.' ' . $wpdb->posts . '.post_title LIKE '.$search_term;
  }
  return $where;
}

add_action( 'wp_ajax_bulk_edit_search', 'bulk_edit_search' );
function bulk_edit_search(){
  $s = $_POST['s'];

  add_filter( 'posts_where', 'title_filter', 10, 2 );

    $query = new WP_Query( array(
        'post_type' => 'product',
        'posts_per_page' => -1,
        'title_filter' => $s,
        'title_filter_relation' => 'OR',
        'orderby'     => 'title',
        'order'       => 'ASC',
        'meta_query' => array(
            'relation' => 'OR',
            array(
                'key' => '_sku',
                'value' => $s,
                'compare' => 'LIKE'
            )
        )
    ));
remove_filter( 'posts_where', 'title_filter', 10, 2 );


  ob_start();

   bulk_get_products($query);

 $content = ob_get_clean();


  wp_send_json(array(
    'content' => $content
  ));

die();
}


?>