Sort Order Items by “menu order” in WooCommerce order edit pages

Amir rajaei zadeh picture Amir rajaei zadeh · Nov 26, 2017 · Viewed 8.1k times · Source

I use this function to sort Woocommerce order admin items by menu order but But products with variables do not display properly. And if there are several product with variables in the order, only one of them will be displayed.

edit: we have problem with multiple items of a product with different attributes:

item1: product A,variable a,attribute: red color, qty 12

item2: Product A, variable a, attribute: green color, qty 18

after sort it only shows :

item1: product A,variable a,attribute: red color, qty 12

In other words product items with same variation id have problem.

add_filter('woocommerce_order_get_items', 'custom_woocommerce_order_get_items', 10, 2);


function custom_woocommerce_order_get_items($items, $object)
       {
           //no need to reorder if less than 2 products
           if(count($items)   <    2)
               return $items;

       //create a list of products within the order
       $products   =   array();
       foreach($items  as  $key    =>  $item)
           {
               $products[  $item['product_id']   ] =   $key;
           }

       $sorted_items  =   array();

       global $post;

       $args   =   array(
                           'posts_per_page'    =>  -1,
                           'post_type'         =>  'product',
                           'orderby'           =>  'menu_order',
                           'order'             =>  'ASC',
                           'post__in'          =>  array_keys($products)
                           );
       $custom_query   =   new WP_Query($args);
       while($custom_query->have_posts())
           {
               $custom_query->the_post();
               $sorted_items[  $products[$post->ID]    ]   =   $items[ $products[$post->ID]    ];
           }

       //check for any left outside items
       foreach($items  as  $key    =>  $item)
           {
               if(isset($sorted_items[$key]))
                   $sorted_items[  $key   ]    =   $item;
           }

       return $sorted_items;

   }

Answer

LoicTheAztec picture LoicTheAztec · Nov 26, 2017

Updated: (to include variations IDs when product it's a variable product)

The main issues in your code is in the query where you need to get the also product_variation post type and also in the first loop where you need to get the variation ID for variable products.

Also this code is outdated for WooCommerce 3+ as Order items are now a WC_Order_Item_Product Object and you need to use the available methods of this class instead.

You don't need the global $post; object as it's already as an argument in the function.

I have revisited all your code:

add_filter( 'woocommerce_order_get_items', 'filter_order_get_items', 10, 2 );
function filter_order_get_items( $items, $order ){

    // no need to reorder if less than 2 items
    if(count($items) < 2) return $items;

    $sorted_items = $products_items_ids = array();

    // Get the array of product/variation IDs with Item IDs within the order
    foreach( $items as $item_id => $item ){
        // Get the product ID (Added WC 3+ compatibility)
        $product_id = method_exists( $item, 'get_product_id' ) ? $item->get_product_id() : $item['product_id'];
        // Get the variation ID (Added WC 3+ compatibility)
        $variation_id = method_exists( $item, 'get_variation_id' ) ? $item->get_variation_id() : $item['variation_id'];
        if( $variation_id > 0 )
            $product_id = $variation_id;
        $products_items_ids[ $product_id ] = $item_id;
    }

    // The WP Query based on the product Ids from this order
    $query = new WP_Query( array(
       'posts_per_page'  =>  -1,
       'post_type'       =>  array( 'product', 'product_variation' ), // <== HERE MISSING
       'orderby'         =>  'menu_order',
       'order'           =>  'ASC',
       'post__in'        =>  array_keys( $products_items_ids ),
    ) );

    // Loop in the Query
    if( $query->have_posts() ){
        while( $query->have_posts() ): $query->the_post();
            // Get the post ID
            $post_id = $query->post->ID;

            // Get the corresponding item ID for the current product ID
            $item_id = $products_items_ids[ $post_id ];

            // Get the new sorted array of items
            $sorted_items[$item_id] = $items[$item_id];
        endwhile;
    }
    wp_reset_query();

    return $sorted_items;
}

Code goes in function.php file of your active child theme (or active theme) or in any plugin file.

Tested and works for all products including product variations on WooCommerce v2.5.x to v3.2+