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.
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.
As promised, take a look at my new solution: http://www.stimart.net/web/woocommerce-hide-out-of-stock-items-that-appears-using-layered-nav-filter-widget-solution-2/
Thank you both for working on a fix for this! 🙂
You’re welcome Bobbi 🙂
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.
Could you tell me what exactly is the code doing in lay man’s terms?
Thanks!
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.
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.
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/
This don’t work anymore.
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?
Hi
I did as instructions but does not work for me?
Steve
Your solution dosent work any ideea ?
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?