If you run your online shop using the excellent woocommerce plugin, built on top of the wordpress platform, and you want to set a custom (category specific) sort order for your products, sadly you are out of luck. The built in ‘sort products’ function works well if you dont mind having a global product sort order which remains the same across all categories, but if you want to have more fine-grained control over your sort order you need a little something extra. Having recently encountered this exact problem whilst working on some customisations for a client, and after 30 minutes of fruitless searching to find a pre-rolled solution, I thought it was time to roll up my sleeves instead. Some requirements for our solution;
I am assuming that you already have WordPress and WooCommerce installed and are know your way around your active theme (or at the very least can edit functions.php within your theme directory), and have commented the code to explain what each part does;
Here are the steps involved to achieve custom product wort order nirvana;
function my_custom_product_order($q)
{
if(!is_admin())
{
// fetch current category id from active query
$category_id = $q->get_queried_object_id();
// get array of all product IDs in current category
$product_ids = get_category_product_ids($category_id);
// get preferred order from ACF field
$product_ids_order_preferred = get_field('product_order', 'product_cat_' . $category_id);
// if we have some product sort order set…
if($product_ids_order_preferred)
{
// merge our preferred category ids array with the array of all products ids, and remove duplicates
$product_ids = array_unique(array_merge($product_ids_order_preferred, $product_ids));
}
// set the 'posts__in' argument to the new array of post IDs (unfortunately wordpress doesn’t let you just pass an array of IDs straight in here)
$q->set('post__in', $product_ids);
// set the query orderby value to observe the posts__in field
$q->set('orderby', 'post__in');
}
remove_action('woocommerce_product_query', 'custom_pre_get_posts_query');
}
add_action('woocommerce_product_query', ‘my_custom_product_order’);
and the following helper function to allow us to more easily fetch an array of all product IDs from within a specific category, which may come in handy for other things (stay DRY!)
// helper function to fetch all product IDs from a specific category ID
function get_category_product_ids($category_id)
{
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $category_id,
'operator' => 'IN'
)
)
);
$ids = get_posts($args);
return $ids;
}
Hopefully this will be of some use to people looking to have more granular control over their product sort order on a per category basis. Let us know in the comments if you think we missed anything, or if we can improve it.