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.

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

  1. 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. hey
    interesting solution

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

    • 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.

        • 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.

  3. 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.

    • 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.

    • 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?

    • 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?

Leave a Reply

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

*

47  +    =  50