Hide 'out of stock' products in Woocommerce - wordpress

Under "Products" and "Inventory" I have checked the following setting:
"Hide out of stock items from the catalog"
Now all sold out products are hidden in the archive/category view. So far so good.
The problem is that the hidden (out of stock) products are counted per page. So if there are 3 products that are sold out on the first page, only the ones in stock are showing (6).
It also seems that these "hidden" products still are searchable as well, and visible through the different widgets.
Any ideas how to fix this? I mean to REALLY hide products that are out of stock. Or do I need to manuallly remove them?

You can try adding this to your theme's functions.php file:
add_action( 'pre_get_posts', 'custom_pre_get_posts_query' );
function custom_pre_get_posts_query( $q ) {
if ( ! $q->is_main_query() ) return;
if ( ! $q->is_post_type_archive() ) return;
if ( ! is_admin() ) {
$q->set( 'meta_query', array(array(
'key' => '_stock_status',
'value' => 'outofstock',
'compare' => 'NOT IN'
)));
}
remove_action( 'pre_get_posts', 'custom_pre_get_posts_query' );
}
I modified the code from this URL: http://www.wptaskforce.com/how-to-exclude-one-or-more-category-in-woocommerce-shop-page/
Saved here again just in case that site goes offline: (this code excludes certain product categories)
add_action( 'pre_get_posts', 'custom_pre_get_posts_query' );
function custom_pre_get_posts_query( $q ) {
if ( ! $q->is_main_query() ) return;
if ( ! $q->is_post_type_archive() ) return;
if ( ! is_admin() ) {
$q->set( 'tax_query', array(array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => array( 'PUT YOUR CATEGORY HERE' ), // Don't display products in the membership category on the shop page . For multiple category , separate it with comma.
'operator' => 'NOT IN'
)));
}
remove_action( 'pre_get_posts', 'custom_pre_get_posts_query' );
}

Note to self: Always read the changelog from developer.
Found the answer here: http://develop.woothemes.com/woocommerce/2014/02/solving-common-issues-after-updating-to-woocommerce-2-1/#category-counts-incorrect
In case the product counts for categories are showing a too high or
too low number, after updating to WooCommerce 2.1 there is an easy
workaround.
Go to the ‘Tools’ tab inside the WooCommerce > System Status of your
WordPress administration panel. Here you first use the ‘Recount terms’
button and after that use the ‘Clear transients’ button. This will
force the system to recount all the products the next time a category
is loaded.
Update: Also remember that it is not enough to change stock quantity to 0. You must also set "Stock status" to "Out of stock". If not the product will be counted in the shop, even if there are no products in stock.

I found easier way, if anybody is still looking for hiding out of stock products in woocommerce, follow these easy steps without editing html !
Go to WooCommerce -> Settings
Go to Inventory
There's a checkbox that says something about our problem, however it goes in english :-) you'll find what you need
Save

that will only work if you are using the official woocommerce shortcodes , but if you creating a page with visual composer and using customized plugins or 3rd party plugins or shortcodes , the first step is to for the query that run from the loop then you modify it to something like this
$params = array(
'posts_per_page' => 5,
'post_type' => array('product', 'product_variation'),
'meta_query' => array(
array(
'key' => '_stock_status',
'value' => 'instock'
)
)
);
the most important part that you have to be sure of is
'meta_query' => array(
array(
'key' => '_stock_status',
'value' => 'instock'
)
)

Steps to Hide Out of Stock Products
Go to WooCommerce -> Settings submenu in the WordPress dashboard
Click on the Products Tab > Inventory sub-tab
Check the option Out Of Stock Visibility that hides the out of stock products

I know that this question was asked long time ago but the solution of the problem is now different, so I post this for people who had the same problem as I did. Tested on WooCommerce 5.3.0
SOLUTION:
First of all make sure that checkbox "Hide products that are out of stock" in Woocomerce > Settings is unchecked than add this PHP code to your child-theme functions.php file:
add_action('woocommerce_product_query', 'show_only_instock_products');
function show_only_instock_products($query) {
$meta_query = $query->get( 'meta_query' );
$meta_query[] = array(
'key' => '_stock_status',
'compare' => '=',
'value' => 'instock'
);
$query->set( 'meta_query', $meta_query );
}
It works well in my store, which is integrated with a wholesaler, where inventory levels are updated every hour and there are thousands of products.

You can place PHP snippet at the bottom of your child theme functions.php file.
add_action('woocommerce_product_query', 'custom_woocommerce_product_query');
function custom_woocommerce_product_query($q)
{
if (!is_admin())
{
$oos_query = new WP_Query(['meta_query' => [['key' => '_stock_status', 'value' => 'outofstock', 'compare' => '=', ], ], 'post_type' => 'product', 'posts_per_page' => - 1, 'fields' => 'ids', ]);
$exclude_ids = $oos_query->posts;
$q->set('post__not_in', $exclude_ids);
}
}

Related

woocommerce_product_query dont work on pages with shop (dont show specific product)

i have some categories, product can be in some of them but when its in cat with ID 46 its should not list anymore in the product list.
The following code work in the shop sites but not when i add the shop over the bb/shortshort , thanks
<!-- wp:woocommerce/product-category {"columns":4,"rows":6,"categories":[31]} /-->
add_action( 'woocommerce_product_query','custom_pre_get_posts_query' );
function custom_pre_get_posts_query( $q ) {
$tax_query = (array) $q->get( 'tax_query' );
$tax_query[] = array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => [46],
'operator' => 'NOT IN'
);
$q->set( 'tax_query', $tax_query );
}
edit:
after some research i found a way, not the best but solved the problem.
Its seems like the data used for these pages are written in the options, so maybe here is a way to block adding the id of the unwanted
The working code is following and on this way it would be maybe a good hook for use same html/functions like used in the shop pages because all the product hooks of wc don't work usually on none shop pages.
Maybe WC adds someday direct a ignore product cats in the code, im sure im not the only one who need it
function my_product_block( $html, $data, $product ) {
if(in_array(46, $product->category_ids) || $product->stock_status === "outofstock"){
return "";
}
return $html;
}
add_filter( 'woocommerce_blocks_product_grid_item_html','my_product_block', 10,3)

Woocommerce display Reviews and Ratings by tags

I am building an e-commerce website and I have installed the following plugin (Customer reviews for Commerce - https://wordpress.org/plugins/customer-reviews-woocommerce/) for Reviews and Ratings of Orders once user completes the order process.
However, the nature of the products we deal with (like fabrics, dresses, sarees etc.) will run out of stock and the same product will not be available again to procure. So, I would want to display the reviews and ratings of old orders using the 'tags' of the products which the order had (For this reason, I would like to have review at order line item). Further, the new product page should fetch the reviews and ratings using it's own tags from old orders which had the same tags.
Any guidance would be helpful in this matter!
To approach this problem, first thing to do is to get all tags associated with a given product into an array. And then, WP_Comments_Query needs to be queried with the array of product ids generated in the first step.
Here is a snippet with the above mentioned approach.
function get_reviews_by_tags(){
global $product;
$productid = $product->get_id();
// get all product_tags of the current product in an array
$current_tags = get_the_terms( $productid, 'product_tag' );
//only start if we have some tags
if ( $current_tags && ! is_wp_error( $current_tags ) ) {
//get all related product ids mapped by tags array we created earlier
$relatedproductids_by_tags = get_posts( array(
'post_type' => 'product',
'numberposts' => -1,
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'product_tag',
'field' => 'term_id',
'terms' => $current_tags,
'operator' => 'IN'
)
),
));
// create a wp comment query object as wc uses comments for reviews
$reviews_args = array(
'post__in' => $relatedproductids_by_tags
);
$reviews_query = new WP_Comment_Query;
$reviews = $reviews_query->query( $reviews_args );
if ( !empty( $reviews ) ) {
foreach ( $reviews as $review ) {
echo '<p>' . $review->comment_content . '</p>';
}
} else {
echo 'No reviews found.';
}
}
add_action( 'woocommerce_after_single_product_summary', 'get_reviews_by_tags', 10, 2 );
}
The above code does not consider any modifications being made by the plugin you mentioned in your question. Also, please note that this code is for fetching and displaying reviews as mentioned in your question. This is not for creating reviews.

Woocommerce URL to hide out of stock product

I create a catalog website using Woocommerce to display all the product. When the product is sell, i dont remove it from the website (because we dont have a lot of product and we want to show to the customer what we sell before).
So, when you go on "All the products" you see the Sell products and the products available. I want, on the sidebar create a button "Show only available product". I dont find a plugin who can do this..
Whis woocommerce, can i create a URL like "mywebsite.com/products&instock=true" for example or something like this ? or if you know another solution. Thanks
You can use pre_get_posts to achieve it. Set the tax_query to not get the term outofstock of the product_visibility taxonomy.
In addition to my code, you will of course need to create a link with the prefix_instock=true parameter. You also can store it in a cookie, so it will be easily persistent.
add_action( 'pre_get_posts', 'prefix_hide_out_of_stock_products' );
function prefix_hide_out_of_stock_products( $q ) {
if ( ! $q->is_main_query() || is_admin() || empty($_GET['prefix_instock'])) {
return;
}
if ( $outofstock_term = get_term_by( 'name', 'outofstock', 'product_visibility' ) && $_GET['prefix_instock'] == 'true') {
$tax_query = (array) $q->get('tax_query');
$tax_query[] = array(
'taxonomy' => 'product_visibility',
'field' => 'term_taxonomy_id',
'terms' => array( $outofstock_term->term_taxonomy_id ),
'operator' => 'NOT IN'
);
$q->set( 'tax_query', $tax_query );
}
remove_action( 'pre_get_posts', 'prefix_hide_out_of_stock_products' );
}

WooCommerce: Display on-sale products in shop

There are plenty of questions and answers regarding making only on-sale products display, but no matter what one I try, it doesn't work.
I have the following query
function my_modify_main_query($query) {
if ($query -> query['post_type'] == 'product' && $query -> is_main_query() && is_shop()) {// Run only on the shop
if (isset($_GET['sale'])):
$query -> set('meta_query',
array(
'relation' => 'OR',
array(// Simple products type
'key' => '_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric'
),
array(// Variable products type
'key' => '_min_variation_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric'
)
)
);
endif;
}
}
// Hook my above function to the pre_get_posts action
add_action( 'pre_get_posts', 'my_modify_main_query' );
The query itself is being applied, BUT the problem is.
If the Product has been a variable with a sale price, the Product is then changed to a Simple Product, the "_min_variation_sale_price" meta value is still in the database.
Does anybody know of a workaround for this? I believe it to be a bug, but their support is closed currently.
Thanks.
EDIT
What I think I need is a way to only check _sale_price if the product is in the "simple" or "external" terms, then do similar for _min_variation_sale_price.
I have created an issue on their github.
https://github.com/woothemes/woocommerce/issues/10096
EDIT
Issue is fixed using #helgatheviking answer.
Although, take note that to resolve the issue completely, you must delete the variations, save, change the type, save, run delete_transient( 'wc_products_onsale' );
Only then did it work for me.
From my tutorial on modifying the product query
I believe this should modify the loop to only show the on-sale products:
add_action( 'woocommerce_product_query', 'so_20990199_product_query' );
function so_20990199_product_query( $q ){
$product_ids_on_sale = wc_get_product_ids_on_sale();
$q->set( 'post__in', (array) $product_ids_on_sale );
}

How to create/modfiy WP_Query to search in post title OR custom field?

I need to modify or create a WP_Query that will search for a search term in both the post title OR a custom field (called 'my_field').
I have been reading and trying for hours, but I am right back to this code (below) which, alas, only searches in 'my_field' and does not take the post_title into account.
function my_pre_get_posts_2( $query ) {
if ( is_admin() && $query->is_main_query() && $query->query['post_type'] === 'post' && isset($query->query['s']) ) {
$search_word = $query->query['s'];
$args = array(
//'s' => $search_word, //If I include this line, the WP query seems to AND post_title and my_field. If I comment out this line, the WP query only searches in my_field. (I need WP to OR post_title and my_field.)
'post_type' => 'post',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'my_field',
'value' => $search_word,
'compare' => 'IN'
),
array(
'key' => 'post_title',
'value' => $search_word,
'compare' => 'IN',
)
)
);
//$query = new WP_Query( $args ); //Need to modify the existing WP_Query
$query->init();
$query->parse_query($args);
}
}
add_action( 'pre_get_posts', 'my_pre_get_posts_2' );
The reason I need to do this is because I need to modify the behaviour of the the 'Search Posts' button in the 'All Posts' (admin) page so that whatever the admin user searches for, it will return the posts that have a matching post title OR my_field value.
To do an OR search, I tried merging two separate WP_Query results as shown here - https://wordpress.stackexchange.com/questions/55519/can-i-merge-2-new-wp-queryvariable-s - in guidod's answer. That wasn't a great solution though, and resulted in erratic behaviour.
The correct solution I found was to modify the query using the WP Custom Query as shown in the code (which requires some modifications) here - http://codex.wordpress.org/Custom_Queries .

Resources