WooCommerce Display “Out of Stock” Products Last

Share on facebook
Share on twitter
Share on linkedin
Share on email

If you have a WooCommerce store you may encounter a situation where you wish to sort your products to display “Out of Stock” items last. This prevents unavailable items from cluttering the list and and distracting your customers. This is especially important if all of the items on the first page of search results are out of stock. Visitors who see only out of stock items on your first page may assume wrongly that everything is out of stock and leave. Fortunately, it is quite simple to add a custom code snippet to your functions.php file to order by out of stock items last.

Here is the complete code snippet for your functions.php file. We’ll break down each step in a moment, but the basic idea is that we use WordPress hooks to modify the query arguments.

function woocommerce_out_of_stock_last($args) {
	// Query to get the ORDER BY clause
	$args['meta_query']['order_clause'] = array(
		'key' => '_stock_status',
		//'value' => array('instock', 'onbackorder', 'outofstock'),	// Implicitly added. But can contain custom statuses. 'outofstock' MUST come last.
		//'compare' => 'IN',	// Implicitly added
	);
	$vals = array();
	if (is_array($args['orderby'])) {
		$vals = $args['orderby'];	// Get default ORDER BY from existing array
	}
	else {
		$vals = explode(' ', $args['orderby']);	// Get default ORDER BY from space-delimited string
	}
	$args['orderby'] = array(
		'order_clause' => 'ASC'	// Set our custom ORDER BY
	);
	foreach ($vals as $v) {	// Add default order by AFTER our custom order by
		$args['orderby'][$v] = $args['order'];
	}
    return $args;
}
add_filter('woocommerce_get_catalog_ordering_args', 'woocommerce_out_of_stock_last');	// WooCommerce product filter
add_filter('woocommerce_shortcode_products_query', 'woocommerce_out_of_stock_last');	// WooCommerce product filter

Code Explanation – Finding “Out of Stock” products

It’s good to not only know that something works but also how and why it works. The first segment of code adds a clause to the “meta_query” array. (This will become part of a WHERE statement in the traditional SQL query.) There are two very important things that happen here.

First, we are able to give the condition a handle (a name). In this case we named the clause ‘order_clause‘. Named meta_query clauses have been available since WordPress 4.2 and is the only reason this code works.

Second, we are including ALL expected products as opposed to filtering products out. This is because we are more interested in getting the value of ‘_stock_status’ in a format we can use later than in actually filtering the products in the query. The default options for _stock_status are ‘instock’, ‘onbackorder’, and ‘outofstock’. This works for us because letters in ‘outofstock’ will always alphabetically order it after the other two options. But beware if you have added custom stock statuses that alphabetically come after ‘outofstock’.

// Query to get the ORDER BY clause
$args['meta_query']['order_clause'] = array(
	'key' => '_stock_status',
	//'value' => array('instock', 'onbackorder', 'outofstock'),	// Implicitly added. But can contain custom statuses. 'outofstock' MUST come last.
	//'compare' => 'IN',	// Implicitly added
);

Sorting “Out of Stock” Products Last

The second segment of code actually orders the results of the query. The existing ORDER BY columns are stored in the space delimited variable $args[‘orderby’]. The single default sorting direction (ASC or DESC) is stored in $args[‘order’]. We will use this default sorting direction later. For now we explode those ‘orderby’ columns out of a string and into an array of default values.

Next, we overwrite the $args[‘orderby’] variable as an array with a default value of our ‘order_clause’ sorted ascending.

Finally, we loop through the default ‘orderby’ values and add them back into the array with the default ‘order’ direction.

$vals = array();
	if (is_array($args['orderby'])) {
		$vals = $args['orderby'];	// Get default ORDER BY from existing array
	}
	else {
		$vals = explode(' ', $args['orderby']);	// Get default ORDER BY from space-delimited string
	}
$args['orderby'] = array(
	'order_clause' => 'ASC'	// Set our custom ORDER BY
);
foreach ($vals as $v) {	// Add default order by AFTER our custom order by
	$args['orderby'][$v] = $args['order'];
}

The last step is simply to set the hooks properly. The default WooCommerce hooks that should work for most people are:

add_filter('woocommerce_get_catalog_ordering_args', 'woocommerce_out_of_stock_last');	// WooCommerce product filter
add_filter('woocommerce_shortcode_products_query', 'woocommerce_out_of_stock_last');	// WooCommerce product filter

However, if you happen to use the WOOF product filter you will also want to add the following line of code:

add_filter('woof_products_query', 'woocommerce_out_of_stock_last');	// For the WOOF product filter

Conclusion

Sorting WooCommerce products to display “Out of Stock” items last instead of leaving them scattered throughout the product list can improve your website and conversion rates.

Please be aware that there is some question if _stock_status will be replaced by something else or if it will be kept as product metadata. With that being said, our solution worked perfectly on our own website and will continue to do so for the foreseeable future.

Need more help? Check out our knowledge base for more help articles or contact us for help with your website.

Sign up to get our latest articles

Don’t worry. We won’t sell your email. We are also really busy managing our clients, so we won’t be filling your inbox with articles every day. We only write them when we have a compelling reason to do so, and some spare time too!

preloader