Show Out of stock products at the end in Woocommerce [closed]
Asked Answered
A

11

28

Is it possible to show out of stock products at the end of a category or page in wordpress?

So the customer first see the products that are available and after that the products that are out of stock.

Adama answered 4/8, 2014 at 7:21 Comment(0)
P
48

This is the same as Viktor & Bogdan's answer, but without the extra Class code.

It uses the post_clause filter to modify the product query. We JOIN the wp_postmeta table to the query and prepend an orderby _stock_status clause to the existing query. This way any other orderby clauses remain in the query as well.

add_filter('posts_clauses', 'order_by_stock_status');
function order_by_stock_status($posts_clauses) {
    global $wpdb;
    // only change query on WooCommerce loops
    if (is_woocommerce() && (is_shop() || is_product_category() || is_product_tag() || is_product_taxonomy())) {
        $posts_clauses['join'] .= " INNER JOIN $wpdb->postmeta istockstatus ON ($wpdb->posts.ID = istockstatus.post_id) ";
        $posts_clauses['orderby'] = " istockstatus.meta_value ASC, " . $posts_clauses['orderby'];
        $posts_clauses['where'] = " AND istockstatus.meta_key = '_stock_status' AND istockstatus.meta_value <> '' " . $posts_clauses['where'];
    }
    return $posts_clauses;
}

You could change istockstatus.meta_value ASC to istockstatus.meta_value DESC if you for some reason wanted the Out Of Stock items first.

Tested on WP: 4.8; WC 3.0.8

Pindus answered 16/6, 2017 at 20:25 Comment(11)
It's possible to make it work in visual composer "recent products" and "Product Loop" components? I use a customized page for show my products and your code works only in the page selected as shop (works very well, thanks!) in Woocomerce.Eventful
With the mention that it should be added at the very end of the query build sequence add_filter('posts_clauses', 'order_by_stock_status', 999); Without the 999 priority, it produces no effect for me.Taunyataupe
And you can also add is_tax() in the condition for custom taxonomies like product brands.Taunyataupe
Getting PHP Notice: Trying to get property 'post_type' of non-object in [path]\wp-includes\class-wp-query.php on line 4103 WooCommerce version: 3.9.1 WordPress version: 5.3.2Caterer
How can we handle the variable products ? @PindusStereotyped
Worked like a charm on Woocommerce 3.8.0 Does anybody have tried it with 4.x?Huan
with WP5.8.3 + Woo6.1.1 works perfectly, thanks!Believe
Should also check for admin interface in order to don't disturb product list inside product manager. if (!is_admin() && is_woocommerce() && (is_shop() || is_product_category() || is_product_tag() || is_product_taxonomy()))Ciel
With this in place, orders on backorder are moved down the list. However, is it possible to modify to consider backorder status the same as instock and therefore keep its position as if it were in stock? @PindusNorland
This works well in shop page, can anyone show how to do exact same thing for homepage?Blockus
Is there a way to make this work when it sorts by popularity? It seems to work with all other sorting methods except popularity (sales).Cowley
M
12

I tried all the solutions above, they worked but resulted in other issues on the site (probably due to theme conflict), Im sure they are all good in different situations / themes. The below code finally worked great for me (source mentioned)

source: https://www.businessbloomer.com/woocommerce-show-in-stock-products-first-shop/

/**
 * @snippet       Sort Products By Stock Status - WooCommerce Shop
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 3.9
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
 
add_filter( 'woocommerce_get_catalog_ordering_args', 'bbloomer_first_sort_by_stock_amount', 9999 );
 
function bbloomer_first_sort_by_stock_amount( $args ) {
   $args['orderby'] = 'meta_value';
   $args['order'] = 'ASC';
   $args['meta_key'] = '_stock_status';
   return $args;
}
Mortonmortuary answered 29/9, 2020 at 6:42 Comment(2)
I use this filter, and I think it's better solution. Thanks.Bailment
I can't say it works for me. It messes with the existing ordering, rather than leaving the existing ordering as-is except for moving the out-of-stock items to the end.Ganister
T
5

Here is a snippet for rearranging products (in stock come first):

<?php

/**
 * Order product collections by stock status, instock products first.
 */
class iWC_Orderby_Stock_Status
{

    public function __construct()
    {
        // Check if WooCommerce is active
        if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
            add_filter('posts_clauses', array($this, 'order_by_stock_status'), 2000);
        }
    }

    public function order_by_stock_status($posts_clauses)
    {
        global $wpdb;
        // only change query on WooCommerce loops
        if (is_woocommerce() && (is_shop() || is_product_category() || is_product_tag())) {
            $posts_clauses['join'] .= " INNER JOIN $wpdb->postmeta istockstatus ON ($wpdb->posts.ID = istockstatus.post_id) ";
            $posts_clauses['orderby'] = " istockstatus.meta_value ASC, " . $posts_clauses['orderby'];
            $posts_clauses['where'] = " AND istockstatus.meta_key = '_stock_status' AND istockstatus.meta_value <> '' " . $posts_clauses['where'];
        }
        return $posts_clauses;
    }
}

new iWC_Orderby_Stock_Status;

?>

https://www.snip2code.com/Snippet/114858/WooCommerce-Products-Order-by-Stock-Stat

Taveda answered 11/1, 2016 at 10:39 Comment(3)
please also post some content from the linkDupaix
Thanks but this doesn't work with latest Woocoommerce version? It moved the Outofstock products down but cloned many instock items too. What went wrong?Karyokinesis
this is worked but after change the page of products and load ajax, don't work !Obmutescence
C
4

@dacrosby answer really should be the best answer here. I've had a few issues with compatibility with some plugins but in most use cases it seems to work with no issues at all.

That being said here are a few caveats

  • Plugins that create products programmatically can sometimes fail to add the stock status meta key and if this key doesn't exist this solution will filter them out of the results entirely.
  • There are also use cases where this solution can conflict with existing ordering because we're ordering alphabetically on the stockstatus value. If multiple stock status' types are used they are artificially grouped in the results due to this ordering.

This version built on top of the same implementation should provide wider compatibility without sacrificing the desired result.


/**
 * Sorts the Woocommerce Archive product query to push out of stock products to the end 
 */
function _nok_order_by_stock_status( $posts_clauses, $query ) {

    // only change query on WooCommerce loops
    if ( $query->is_main_query() && ( is_product_category() || is_product_tag() || is_product_taxonomy() || is_shop() ) ) {
        global $wpdb;

        $posts_clauses['join'] .= 
        " LEFT JOIN ( 
            SELECT post_id, meta_id, meta_value FROM $wpdb->postmeta 
            WHERE meta_key = '_stock_status' AND meta_value <> '' 
        ) istockstatus ON ($wpdb->posts.ID = istockstatus.post_id) ";

        $posts_clauses['orderby'] = 
        " CASE istockstatus.meta_value WHEN 
            'outofstock' THEN 1 
            ELSE 0 
        END ASC, " . $posts_clauses['orderby'];
    }

    return $posts_clauses;
}
add_filter( 'posts_clauses', '_nok_order_by_stock_status', 2000, 2 );

Calamitous answered 25/5, 2021 at 4:45 Comment(0)
D
3

As an alternative, simple solution, if your product list is in a flexbox, you could do it with CSS too with the following rule:

ul.products li.product.outofstock {order:1}
Deliladelilah answered 29/8, 2021 at 9:20 Comment(0)
S
2

Access the global configuration options for inventory management in WooCommerce, look to the left of your WordPress admin and click on WooCommerce, then on Settings, then click on the Inventory tab.

You will find this "Out of Stock Visibility"

Out of Stock Visibility - This checkbox will allow you to determine if you want to hide out of inventory items within the WooCommerce catalog.

http://www.inmotionhosting.com/support/website/woocommerce/managing-inventory-in-woocommerce

For making them appear at the end of the category you could use pre_get_posts to order based on the stock, but then you'll lose your other sorting.

Sinewy answered 4/8, 2014 at 7:32 Comment(6)
Thanks. How can we use pre_get_posts here?Adama
check here remicorson.com/modifying-the-current-query-with-pre_get_postsSinewy
Does making this out of stock change in the display cause the pages that are hidden to be redirected somewhere? or does it show up as a 404 error page in Google analytics? We are trying to avoid 404 errors in google analytics when hiding out of stock items so I wonder if they are automatically redirected to the primary shop page or if this is something that needs to get done manually through a 301 redirect htaccess file or php configuration. Thank you for your help.Hepsiba
I don't see the "Inventory" tab - did they rename it in a UI update or something?Nesta
This answer doesn't actually answer the question, namely, how to display the out-of-stock items last.Ganister
Making out-of-stock products visible somehow works only for my admin user. The regular visitors still do not see it on the product list.Lora
G
2

Try this code (put in functions.php of your theme):

class iWC_Orderby_Stock_Status {
public function __construct() {
    if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
        add_filter('posts_clauses', array($this, 'order_by_stock_status'), 2000);
    }
}
public function order_by_stock_status($posts_clauses) {
    global $wpdb;   
    if (is_woocommerce() && (is_shop() || is_product_category() || is_product_tag())) {
        $posts_clauses['join'] .= " INNER JOIN $wpdb->postmeta istockstatus ON ($wpdb->posts.ID = istockstatus.post_id) ";
        $posts_clauses['orderby'] = " istockstatus.meta_value ASC, " . $posts_clauses['orderby'];
        $posts_clauses['where'] = " AND istockstatus.meta_key = '_stock_status' AND istockstatus.meta_value <> '' " . $posts_clauses['where'];
    }
    return $posts_clauses;
    }
}
new iWC_Orderby_Stock_Status;

Taken here.

For the last versions of WooCommerce see answer below: https://mcmap.net/q/486869/-show-out-of-stock-products-at-the-end-in-woocommerce-closed

Gittle answered 27/12, 2016 at 8:13 Comment(0)
D
2

This code work for me:

add_action( 'pre_get_posts', function( $query ) {
    if ( $query->is_main_query() && is_woocommerce() && ( is_shop() || is_product_category() || is_product_tag() ) ) {
        if( $query->get( 'orderby' ) == 'menu_order title' ) {  // only change default sorting
            $query->set( 'orderby', 'meta_value' );
            $query->set( 'order', 'ASC' );
            $query->set( 'meta_key', '_stock_status' );
        }
    }
});
Decompose answered 28/2, 2017 at 20:52 Comment(0)
B
2

This is the best solution:

add_action( 'pre_get_posts', function ( $q ) {
    if (   !is_admin()                 // Target only front end 
         && $q->is_main_query()        // Only target the main query
         && $q->is_post_type_archive() // Change to suite your needs
    ) {
        $q->set( 'meta_key', '_stock_status' );
        $q->set( 'orderby',  'meta_value'    );
        $q->set( 'order',    'ASC'           );
    }
}, PHP_INT_MAX );
Balmacaan answered 10/10, 2017 at 8:21 Comment(1)
Why would you use the max priority?Greenwell
R
2

Edited one answer above:

/**
 * @snippet     Order product collections by stock status, instock products first.
 * @author      Rkoms
 */

class iWC_Orderby_Stock_Status {

    public function __construct() {
        if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
            add_filter('posts_clauses', array($this, 'order_by_stock_status'), 2000, 2);
        }
    }

    public function order_by_stock_status($posts_clauses, $query) {
        global $wpdb;   
        if ( $query->is_main_query() && is_woocommerce() && (is_shop() || is_product_category() || is_product_tag())) {
            $posts_clauses['join'] .= " INNER JOIN $wpdb->postmeta istockstatus ON ($wpdb->posts.ID = istockstatus.post_id) ";
            $posts_clauses['orderby'] = " istockstatus.meta_value ASC, " . $posts_clauses['orderby'];
            $posts_clauses['where'] = " AND istockstatus.meta_key = '_stock_status' AND istockstatus.meta_value <> '' " . $posts_clauses['where'];
        }
        return $posts_clauses;
    }

}
new iWC_Orderby_Stock_Status;
Radiomicrometer answered 13/4, 2020 at 2:16 Comment(0)
P
2

I think this query can be better, because if a site sells its products by pre-order, it will be displayed at the end of the list. This query is the optimized version that you can use. Also, pre-order products will remain in place:

function custom_product_query( $clauses, $query ) {
    global $wpdb;

    // Add join clause to filter out-of-stock products
    $clauses['join'] .= $wpdb->prepare(
        " LEFT JOIN {$wpdb->postmeta} AS out_of_stock_meta
          ON {$wpdb->posts}.ID = out_of_stock_meta.post_id
          AND out_of_stock_meta.meta_key = %s
          AND out_of_stock_meta.meta_value = %s",
        '_stock_status', 'outofstock'
    );

    // Modify the orderby clause to sort by stock status
    $clauses['orderby'] = "out_of_stock_meta.meta_value ASC, {$clauses['orderby']}";

    return $clauses;
}

add_filter( 'posts_clauses', 'custom_product_query', 10, 2 );

updated: Use $wpdb->prepare: This ensures that your SQL queries are safely prepared and helps prevent SQL injection attacks.

This code adds a left join to the postmeta table to retrieve the _stock_status meta value, and orders the results first by whether the product is out of stock, and then by the original orderby value. This filter only applies to product category queries, and won't affect other queries.

This approach should be relatively efficient because it doesn't require an additional query, but rather modifies the existing query with a small additional join and sort.

Poltroon answered 13/2, 2023 at 11:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.