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;
}
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+