Display "In Stock" notice for WooCommerce variations with no Managed Stock - php

I need help for a particular situation. In WooCommerce, if "Manage Stock" is enabled for a simple product or variation, then a notification is being displayed in the product page => such as [this example][1]
However, if "Manage Stock" is not enabled, then there is no notification which I find it a pity because I still want to inform my customers that it's precisely in stock even if I don't manage the stock quantities.
I've found the below code. For simple products, it works without any problem. However, for variable product, this message is being displayed even before that a variation is selected. This is of course not okay, this code should be displayed only after that a variation is selected.
Can someone help me to fix this? For variable products, this message should only be displayed after that a particular variation is selected.
I've made a video capture to be a bit more illustrative : https://sgevcen.tinytake.com/tt/NDQzNTU2OF8xNDAyNTU2NA
function mycustom_shop_display_stock() {
global $product;
if ( !$product->get_manage_stock() && $product->is_in_stock() ) {
echo '<p class="stock in-stock">In Stock</p>';
}
}
add_action( 'woocommerce_before_add_to_cart_button', 'mycustom_shop_display_stock', 11 );
[1]: https://i.stack.imgur.com/aFnN1.png

Try the following instead that should allow to display your custom stock availability only for the variations of a variable product (and also on simple products):
add_filter( 'woocommerce_get_stock_html', 'filter_wc_get_stock_html', 10, 2 );
function filter_wc_get_stock_html( $html, $product ) {
if ( ! $product->is_type('variable') && ! $product->get_manage_stock() && $product->is_in_stock() ) {
$html = '<p class="stock in-stock">' . __( "In Stock", "woocommerce" ) . '</p>';
}
return $html;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
To exclude some product categories use the following (related to your comment):
add_filter( 'woocommerce_get_stock_html', 'filter_wc_get_stock_html', 10, 2 );
function filter_wc_get_stock_html( $html, $product ) {
// Here define the product categories to be excluded (can be term Ids, slugs or names)
$terms_excl = array('hoodies', 'albums');
$product_id = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();
if ( ! $product->is_type('variable') && ! $product->get_manage_stock() && $product->is_in_stock()
&& ! has_term( $terms_excl, 'product_cat', $product_id ) ) {
$html = '<p class="stock in-stock">' . __( "In Stock", "woocommerce" ) . '</p>';
}
return $html;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Related thread: Display custom stock message if "Manage Stock" is not enabled in WooCommerce

Related

Change the Label on the shop page to display stock quantity

Right now, my shop only displays only 2 badges on my shop page. Special Offer and out of stock. I would also want to include stock quantity below 10 and Allow for back order. I have looked at multiple plugins as well as php code, but nothing seems to work. What I want to do is display "Only {QTY} Is Available" is the stock drops below 10 and if it is 0 then "available on back order". Website is built in WooCommerce and WordPress
I would like these messages to replace the special offer badge if these conditions are met. I have attached a screenshot below:-
Any assistance is greatly appriciated
There are in fact two parts to your question: how to change the stock availability text and how to remove the sale badge, when some criteria on the product stock level is met.
Changing the stock availability text should be easily achieved by hooking in the woocommerce_get_availability filter. Get the product stock quantity and amend the text accordingly. E.g.:
add_filter( 'woocommerce_get_availability', 'custom_override_get_availability', 10, 2 );
function custom_override_get_availability( $availability, $_product ) {
$stock_quantity = $_product->get_stock_quantity();
if ( 0 === $stock_quantity ) {
$availability['availability'] = 'Available on backorder';
} elseif ( $stock_quantity < 10 ) {
$availability['availability'] = sprintf( 'Only %s available', $stock_quantity );
} else {
$availability['availability'] = sprintf( '%s left in stock', $stock_quantity );
}
return $availability;
}
As for removing the sale badge, I think the plugin you're using provides templates that can be overridden. Have a look in the Views folder, you should find the sale-flash.php templates. You can then override those templates in your theme and apply a similar logic, as you have access to the product. E.g. this shows the sale badge only when the product is on sale and the stock quantity is greater than or equal to 10:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
global $post, $product;
?>
<?php if ( $product->is_on_sale() && $product->get_stock_quantity() >= 10 ) : ?>
<?php echo apply_filters( 'woocommerce_sale_flash', '<span class="onsale wdr-onsale">' . esc_html__( 'Sale!', 'woocommerce' ) . '</span>', $post, $product ); ?>
<?php endif;
Although I'm not really sure if you want to remove the sale badge when the product stock quantity is less than 10.

Add a prefix/suffix to Woocommerce product name everywhere, including cart and email

I am using Woocommerce and I have integrated some custom fields to allow the user to specify new values that I will later append to the product title.
I am using update_post_meta/get_post_meta to save the new information. This part works fine.
Then I used the filter woocommerce_product_title to update the title. This filter is working fine when there is the use of $product->get_title() but will do nothing when using $product->get_name()which isn't an issue because in some places I don't want to append the new information.
I also used the filter the_title for the product page.
Basically my code looks like below where return_custom() will be the function than will build the new information based on the product ID.
function update_title($title, $id = null ) {
$prod=get_post($id);
if (empty($prod->ID) || strcmp($prod->post_type,'product')!=0 ) {
return $title;
}
return $title.return_custom($id);
}
function update_product_title($title, $product) {
$id = $product->get_id();
return $title.return_custom($id);
}
add_filter( 'woocommerce_product_title', 'update_product_title', 9999, 2);
add_filter( 'the_title', 'update_title', 10, 2 );
The issue arise when adding the product to the cart. The name used is the default one so my below code isn't enough to update the product name used in the cart. Same thing for the notification mails. I suppose this is logical since the email will use the information of the cart.
I am pretty sure that everything is happening inside add_to_cart() but I am not able to find any filter/hook related to the product name.
How to make sure the name used in the cart is good? What filter/hook shoud I consider in addition to the ones I am already using in order to append my new information to the product title within the cart?
I want to make sure that the new title will be seen during all the shopping process. From the product page until the notification mail.
The following will allow you to customize the product name in cart, checkout, orders and email notifications, just with one hooked function:
// Just used for testing
function return_custom( $id ) {
return ' - (' . $id . ')';
}
// Customizing cart item name in cart, checkout, orders and email notifications
add_action( 'woocommerce_before_calculate_totals', 'set_custom_cart_item_name', 10, 1 );
function set_custom_cart_item_name( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Required since Woocommerce version 3.2 for cart items properties changes
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get the product name and the product ID
$product_name = $cart_item['data']->get_name();
$product_id = $cart_item['data']->get_id();
// Set the new product name
$cart_item['data']->set_name( $product_name . return_custom($product_id) );
}
}
Code goes on function.php file of your active child theme (or active theme). Tested and works.
Try using woocommerce_cart_item_name filter.
[woocommerce_cart] shortcode uses cart/cart.php template, and the code displaying the title is this:
if ( ! $product_permalink ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' ' );
} else {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '%s', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
}

Replace "Sale" badge by "Out of Stock" in Woocommerce archive pages

I am working on woocommerce shop and here is the link of the website shop page
On this page the first product is out of stock. I would like to show Out of stock instead of "Sale!" badge on the image.
How can I do this?
If you look at the loop/sale-flash.php template you can see it has a filter for the sale flash. You can add this to your functions.php file to modify that output.
add_filter( 'woocommerce_sale_flash', 'sale_flash_stock_status' );
function sale_flash_stock_status( $output_html, $post, $product ){
if( $product->is_in_stock() ){
// Leave the sale flash unchanged if it's in stock.
return $output_html;
}
else {
// Change the html output custom stock status
$output_html = '<span class="stock-status">' . esc_html__( 'Out of stock', 'woocommerce' ) . '</span>'
return $output_html;
}
}
Add in the functions.php file of your theme:
add_filter('woocommerce_sale_flash', 'woocommerce_custom_sale_text', 10, 3);
function woocommerce_custom_sale_text($text, $post, $_product)
{
return '<span class="onsale">out of stock</span>';
}
The following code will add, on Woocommerce archives pages (as shop), a "Out of Stock" badge for out of stock products replacing the "Sale!" badge when products are on sale:
// Add badge "Out of stock" (and replace sale badge)
add_action('woocommerce_before_shop_loop_item_title','custom_before_shop_loop_item_title', 2 ); // Archives pages
function custom_before_shop_loop_item_title(){
remove_action('woocommerce_before_shop_loop_item_title','woocommerce_show_product_loop_sale_flash', 10 );
remove_action('woocommerce_after_shop_loop_item_title','woocommerce_show_product_loop_sale_flash', 6 ); // For storefront theme
add_action('woocommerce_before_shop_loop_item_title','show_product_loop_outofstock_badge', 10 );
}
function show_product_loop_outofstock_badge(){
global $post, $product;
if ( $product->get_stock_status() == 'outofstock' ) :
echo '<span class="onsale outofstock">'. esc_html__('Out of stock', 'woocommerce') .'</span>';
elseif ( $product->is_on_sale() ) :
echo '<span class="onsale">'. esc_html__( 'Sale!', 'woocommerce' ) .'</span>';
endif;
}
You might have to make some hook priority changes, depending on your theme. This code support also storefront theme.
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Add a custom text to Woocommerce product availability and display it for cart items

I'm trying to find a way to place custom text before availability info (out of stock, in stock etc.) on woocommerce single product page.
I am using something like that:
add_filter( 'woocommerce_get_availability', 'change_product_availability_display' );
add_filter( 'unknown filter', 'change_product_availability_display' );
function change_product_availability_display( $availability ) {
// Additional text
$text = __('Availability:');
// returning the text before the availability
return $text . ' ' . $availability;
}
Its's based on: Add a custom text before the price display in WooCommerce.
In case of price filter named in my code "unknown filter" was woocommerce_cart_item_price. I've looked for this kind of filter for availability/stock item, but can't find it.
Maybe someone could review this code and help me to find this "unknown_filter" or have other idea how I can put custom text before availability info?
I have revisited your code as your are trying to merge a string with an array. Also I have added a 2nd hooked function that will allow to display your "labeled" availability to items in cart and checkout.
The code:
add_filter( 'woocommerce_get_availability', 'add_label_to_availability_display' );
function add_label_to_availability_display( $availability ) {
if( is_product() || is_cart() || is_checkout() ){
$label = __( 'Availability', 'woocommerce' ) . ': ';
$availability['availability'] = $label . $availability['availability'];
}
return $availability;
}
add_filter( 'woocommerce_cart_item_name', 'add_availability_below_cart_item_name', 10, 3);
function add_availability_below_cart_item_name( $item_name, $cart_item, $cart_item_key ) {
$availability = $cart_item['data']->get_availability();
return $item_name . '<br>' . $availability['availability'];
}
Code goes in function.php file of your active child theme (active theme).
Tested and works.

Adding "Sale" product category to products that are on sale in Woocommerce

As part of a WooCommerce site I want to have a sale page that lists sale items (with pagination and filtering). I think the best way to do this is to have a 'Sale' category that is added automatically to any posts that are part of the sale (as category pages allow for filtering and pagination automatically.
I have this code so far to programatically add the sale category to products when you save them:
function update_test( $product) {
wp_set_object_terms($product, 'sale', 'product_cat', true );
}
add_action( 'save_post', 'update_test', 1, 2);`
However, I only want this to happen if a product is on sale (i.e has sale price set) so that saving posts that are not on sale does not add the sale category. I have tried several different things, but have had no luck. I tried this, but it didnt work:
function update_test( $product ) {
if($product->is_on_sale()){
wp_set_object_terms($product, 'sale', 'product_cat', true );
}
}
add_action( 'save_post', 'update_test', 1, 2);`
but this just made my site freeze on save.
Any ideas?
Andy
Updated 2 (October 2018)
save_post is a WordPress hook that works with $post_id argument and target all kind of posts. You need to target product custom WooCommerce post_type first in a condition (and publish post_status).
Also as it's not a post object you can't use is_on_sale() method with it. But you can use get_post_meta() function to check if the sale price is set in the product.
Here is the fully functional and tested code (for simple products only):
add_action( 'save_post_product', 'update_product_set_sale_cat' );
function update_product_set_sale_cat( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
if ( ! current_user_can( 'edit_product', $post_id ) ) {
return $post_id;
}
if( get_post_status( $post_id ) == 'publish' && isset($_POST['_sale_price']) ) {
$sale_price = $_POST['_sale_price'];
if( $sale_price >= 0 && ! has_term( 'Sale', 'product_cat', $post_id ) ){
wp_set_object_terms($post_id, 'sale', 'product_cat', true );
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related: Auto remove Sale product category from not on sale products in Woocommerce
I think a more convenient way of doing this, that also works on variable products, would be adding the following in child theme's function.php (or via a plugin, etc):
add_action( 'woocommerce_update_product', 'update_product_set_sale_cat', 10, 2 );
function update_product_set_sale_cat( $product_id, $product ) {
if ( $product->is_on_sale() ) {
wp_add_object_terms($product_id, "sale", 'product_cat');
} else { // this will also remove the sale category when the product in no longer on sale
wp_remove_object_terms($product_id, "sale", 'product_cat');
}
}
It uses the woocommerce_update_product hook which runs whenever a product is updated/created in the database.

Categories