Woocommerce – Hide out of stock items that appears using “Layered nav: filter”

I come across a pretty annoying bug-feature in woocommerce. If someone uses Layered navigation filters and has variable products based on a specific attribute, the filtering will return all the products with the specific attribute, even if this variation is out of stock.  If someone  is selling clothes-shoes for example this is quite disturbing.

This bug is reported to Woocommerce github issue tracker here. It is rated as a won’t fix mainly because the attributes of a variable product is not directly connected with the Taxonomy Terms.

Building upon a solution from http://www.stimart.net/web/woocommerce-hide-out-of-stock-items-that-appears-using-layered-nav-filter-widget/ which is removing the products before showing in the template pages , I went deeper in the woocommerce core. This was mainly because the aforementioned solution had trouble with more advanced themes and especially with the pagination. In simple themes it worked almost perfectly.

So this is my solution.

Open file in woocommerce plugin -> includes -> class-wc-query.php

Find Function

[php]

public function layered_nav_query( $filtered_posts ) {

[/php]

After

[php]

global $_chosen_attributes;

[/php]

Add

[php]     global $wpdb;[/php]

And after

[php]
$posts = get_posts(
array(
‘post_type’     = > ‘product’,
‘numberposts’     = > -1,
‘post_status’     = > ‘publish’,
‘fields’         => ‘ids’,
‘no_found_rows’ => true,
‘tax_query’ => array(
array(
‘taxonomy’     => $attribute,
‘terms’     => $value,
‘field’     => ‘term_id’
)
)
)
);[/php]

Add

[php]

//continue fix
if ($attribute ==”pa_size”)    {
$new_ids= array();
$queryslug =”SELECT *  FROM {$wpdb->prefix}term_taxonomy as taxonomy, {$wpdb->prefix}terms as term  where taxonomy.term_id= $value and taxonomy.term_id = term.term_id ” ;
$slugr = $wpdb->get_results( $queryslug );
$slug = $slugr[0]->slug;
foreach ($posts as $post_id)
{
$query =”SELECT *  FROM {$wpdb->prefix}posts as posts , {$wpdb->prefix}postmeta as postmeta where posts.post_parent= $post_id  AND posts.ID = postmeta.post_id AND meta_key like ‘attribute_$attribute’  AND meta_value like ‘$slug’ ” ;
$variation_ids = $wpdb->get_results( $query );
foreach ($variation_ids as $variation_id){
$var_id = $variation_id->ID;
$query2 =”SELECT post_id  FROM {$wpdb->prefix}postmeta as postsmeta  where post_id= $var_id and meta_key like ‘_stock_status’ and meta_value like ‘instock’ ” ;
$result = $wpdb->get_results( $query2 );
if($result){
$new_ids[]=$post_id;
}
}
}
$posts=$new_ids;
}
//END fix

[/php]

Where pa_size can be renamed to your attribute.

17 comments on “Woocommerce – Hide out of stock items that appears using “Layered nav: filter”
  1. stimart says:

    Dear bekatoros, thank you to post my link. I’ve a new solution based on functions.php hook. I’ll post it as soon as possible. Bye 😉 Stay tuned.

  2. Bobbi says:

    Thank you both for working on a fix for this! 🙂

  3. Pat says:

    hey
    interesting solution

    how will this work with products with more than one attribute?
    lets say – a size attribute and a gender attribute

    • bekatoros says:

      It only filters the size attribute that was used in the creation of the variable product. If it has 2 attributes for the variable product you can copy the code twice and change the attribute name for the second copy.

      • pat says:

        Could you tell me what exactly is the code doing in lay man’s terms?

        Thanks!

        • bekatoros says:

          It basically refilters the products based on the availability of their variable product. If the variable product with the attribute we are looking for is available then it will show the product in the results. If it is not available it will not be shown.

  4. pat says:

    Haha, I understand that.
    I should’ve probably asked HOW in stead of what.

    What I meant is, what is happening behind the scenes.

    Like the wooteam developers am worried about the queries. For 30 products with ten variations each, it will have to run 300 queries every time someone tries to filter out variations.

    I want to understand the solution if you’re not doing the above.

    • bekatoros says:

      For each product that the woocommerce returns , that have this attribute, it makes 3 sql selects. So its not so much more per product. A believe that an average retrieval for of a woocommerce product requires more than 5-10 sql queries just for the archive-product page. So its not so sql heavy.

  5. stimart says:

    Hi 🙂 I think I’ve solved it using hook function. Please, take a look at my solution 3 and let me know if it works: http://www.stimart.net/web/woocommerce-hide-out-of-stock-items-that-appears-using-layered-nav-filter-widget-solution-3/

  6. Guilherme Henrique says:

    This don’t work anymore.

    • bekatoros says:

      It work fine for Woocommerce 2.3 till 2.4.4 did you set your attribute correctly and also added the global $wpdb; in the function?

  7. Steve says:

    Hi
    I did as instructions but does not work for me?
    Steve

    • bekatoros says:

      It work fine for Woocommerce 2.3 till 2.4.4 did you set your attribute correctly and also added the global $wpdb; in the function?

  8. Velicu says:

    Your solution dosent work any ideea ?

    • bekatoros says:

      It work fine for Woocommerce 2.3 till 2.4.4 did you set your attribute correctly and also added the global $wpdb; in the function?

1 Pings/Trackbacks for "Woocommerce – Hide out of stock items that appears using “Layered nav: filter”"
  1. […] Special thanks to Marios Bekatoros for mentioning my post on its website and for his solution […]

Leave a Reply to Steve Cancel reply

Your email address will not be published. Required fields are marked *

*