How to change the 'stock management' availability text on single product page with products on backorder in WooCommerce - php

I'm trying to change the stock management availability text on single product page based on different conditions in WooCommerce. I almost succeded with only one problem. When product is out of stock but avalaible on back order it shows the message for product in stock.
// Change In Stock Text
function filter_woocommerce_get_availability( $availability, $product ) {
// Managing stock is activated
if ( $product->managing_stock() ) {
// Stock quantity
$stock_quantity = $product->get_stock_quantity();
// Backorders allowed
$backorders_allowed = $product->backorders_allowed();
// Compare
if ( $stock_quantity <= 0 ) {
if ( $backorders_allowed ) {
$availability['availability'] = __('Product not available, but can be backordered', 'woocommerce' );
} else {
$availability['availability'] = __('Product not available', 'woocommerce' );
}
} elseif ( $stock_quantity > 0 ) {
$availability['availability'] = __('Product available in local shop and order', 'woocommerce' );
}
} else {
// In stock
if ( $product->is_in_stock() ) {
$availability['availability'] = __('Product available for order', 'woocommerce' );
} elseif ( $product->is_on_backorder() ) {
$availability['availability'] = __('Product on backorder', 'woocommerce' );
} else {
$availability['availability'] = __('Product not available for order', 'woocommerce' );
}
}
return $availability;
}
add_filter( 'woocommerce_get_availability', 'filter_woocommerce_get_availability', 10, 2 );
When I test on a product with variations.
managing stock works fine
stock 0 - allow, but notify - works
stock 0 - allow - works
in stock works fine
out of stock works fine
out of stock back orders shows - 'Product available for order' - can't figure it out...

Related

Change the display of woocommerce stock values

I would like to limit the display of stocks on my product pages (only on the frontend) in order to limit the stocks that are too high.
My question is similar to this article: Set a max displayed available stock quantity on Woocommerce archives for variable products
In it, the code below displays something similar but has several drawbacks:
It displays the new stock on the product catalog pages and not directly replacing the stock on the product page
It only works for variable products and not for simple products
add_action( 'woocommerce_after_shop_loop_item', 'wc_loop_get_product_stock_availability_text', 10 );
function wc_loop_get_product_stock_availability_text() {
global $wpdb, $product;
$max_stock_qty = 50; // Maximum Number of Available Stock qty
// For variable products
if( $product->is_type('variable') ) {
// Get the stock quantity sum of all product variations (children)
$stock_quantity = $wpdb->get_var("
SELECT SUM(pm.meta_value) FROM {$wpdb->prefix}posts as p
JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE p.post_type = 'product_variation'
AND p.post_status = 'publish' AND p.post_parent = '".get_the_id()."'
AND pm.meta_key = '_stock' AND pm.meta_value IS NOT NULL
");
if ( $stock_quantity > 0 ) {
// Here we limit the sock quantity display to 50 when it's up to 50
$stock_quantity = $stock_quantity >= $max_stock_qty ? $max_stock_qty : $stock_quantity;
echo '<p class="stock in-stock">'. sprintf( __("%s in stock", "woocommerce"), $stock_quantity ).'</p>';
} else {
if ( is_numeric($stock_quantity) )
echo '<p class="stock out-of-stock">' . __("Out of stock", "woocommerce") . '</p>';
else
return;
}
}
// Other products types
else {
echo wc_get_stock_html( $product );
}
}
The returned value should replace the stock displayed on the product pages taking into account these conditions:
When a stock is greater than 50, display a random number between 50 and 100.
If the stock is less than 50, display the real value of the stock.
I am stuck and I don't know if I am going in the right direction,
Thanks a lot in advance!
You could filter the woocommerce_get_availability_text and check the stock quantity.
add_filter( 'woocommerce_get_availability_text', 'custom_availability_text', 10, 2 );
function custom_availability_text( $availability, $product ) {
if ( ! $product->is_in_stock() ) {
$availability = __( 'Out of stock', 'woocommerce' );
} elseif ( $product->managing_stock() && $product->is_on_backorder( 1 ) ) {
$availability = $product->backorders_require_notification() ? __( 'Available on backorder', 'woocommerce' ) : '';
} elseif ( ! $product->managing_stock() && $product->is_on_backorder( 1 ) ) {
$availability = __( 'Available on backorder', 'woocommerce' );
} elseif ( $product->managing_stock() ) {
$stock_amount = $product->get_stock_quantity();
// Check if Stock is less than 50.
if ( 50 > $stock_amount ) {
$availability = wc_format_stock_for_display( $product );
} else {
if ( false === ( $custom_availability = get_transient( 'custom_availability_text_' . $product->get_id() ) ) ) {
$random = wp_rand( 50, 100 );
$availability = sprintf( __( '%s in stock', 'woocommerce' ), wc_format_stock_quantity_for_display( $random, $product ) );
// Store for 6 hours. YMMV.
set_transient( 'custom_availability_text_' . $product->get_id(), $availability, 6 * HOUR_IN_SECONDS );
} else {
return $custom_availability;
}
}
} else {
$availability = '';
}
return $availability;
}
I've updated the answer to include a 6 hour cache.

WooCommerce Product get_stock_quantity() method return null

I have a problem when I try to retrieve the available quantity of a product in my view.
This is my code :
function wcs_custom_get_availability( $availability, $_product ) {
global $product;
// Change In Stock Text
if ( $_product->is_in_stock() ) {
$availability['availability'] = __( 'Plenty available in our store!', 'woocommerce');
}
// Change in Stock Text to only 1 or 2 left
if ( $_product->is_in_stock() && $product->get_stock_quantity() <= 2 ) {
$availability['availability'] = sprintf( __('Only %s left in store!', 'woocommerce'), $product->get_stock_quantity() );
}
// Change Out of Stock Text
if ( ! $_product->is_in_stock() ) {
$availability['availability'] = __('Sorry, All sold out!', 'woocommerce');
}
return $availability;
}
The result of the execution is as follows : Only left in store!
I have access to the product variable but the result is null but I would like to retrieve the quantity.
Correction :
Replace $product->get_stock_quantity() by $_product->get_stock_quantity().
function wcs_custom_get_availability( $availability, $_product ) {
global $product;
// Change In Stock Text
if ( $_product->is_in_stock() ) {
$availability['availability'] = __( 'Plenty available in our store!', 'woocommerce');
}
// Change in Stock Text to only 1 or 2 left
if ( $_product->is_in_stock() && $_product->get_stock_quantity() <= 2 ) {
$availability['availability'] = sprintf( __('Only %s left in store!', 'woocommerce'), $_product->get_stock_quantity() );
}
// Change Out of Stock Text
if ( ! $_product->is_in_stock() ) {
$availability['availability'] = __('Sorry, All sold out!', 'woocommerce');
}
return $availability;
}
Using WC_Product method get_manage_stock() with it, you will be able to avoid this problem. I have also simplified a bit your code:
add_filter( 'woocommerce_get_availability', 'filter_wc_get_availability', 10, 2);
function filter_wc_get_availability( $availability, $product ) {
// In Stock
if ( $product->is_in_stock() ) {
$stock_quantity = $product->get_stock_quantity();
// Change Text for low stock (1 or 2 left)
if ( $product->get_manage_stock() && $stock_quantity == ( 1 || 2 ) ) {
$availability['availability'] = sprintf( __('Only %s left in store!', 'woocommerce'), $stock_quantity );
}
// Change in Stock Text (when more than 2)
else {
$availability['availability'] = __( 'Plenty available in our store!', 'woocommerce');
}
}
// Change Out of Stock Text
else {
$availability['availability'] = __('Sorry, All sold out!', 'woocommerce');
}
return $availability;
}
It should solve this problem.
Don't use global $product; as for variable products it will take the variable product object instead of the variations of this variable product. The WC_Product object is already included in the function as an argument. Stock is decreased on the products variatons and not on the parent variable product.
in my case none of the answers worked, so I figured it out by myself. The thing is you should check first if managing_stock() is on. If it is, then we're good to go.
So, the final code is:
/**
* Change the test for "In Stock / Quantity Left / Out of Stock".
*/
add_filter( 'woocommerce_get_availability', 'wcs_custom_get_availability', 1, 2);
function wcs_custom_get_availability( $availability, $_product ) {
global $product;
// Change In Stock Text
if ( $_product->managing_stock() && $_product->is_in_stock() ) {
echo '<p class="store-inside__number">';
$availability['availability'] = __( 'Plenty available in our store!', 'woocommerce');
echo '</p>';
}
// Change in Stock Text to only 1 or 2 left
if ( $_product->managing_stock() && $_product->is_in_stock() && $_product->get_stock_quantity() <= 2 ) {
$availability['availability'] = sprintf( __('Only %s left in store!', 'woocommerce'), $_product->get_stock_quantity() );
}
// Change Out of Stock Text
if ( $_product->managing_stock() && ! $_product->is_in_stock() ) {
$availability['availability'] = __('Sorry, All sold out!', 'woocommerce');
}
return $availability;
}

WooCommerce dynamic minimum order amount based fee

I need to set a minimum order fee in the shopping cart so if products in the cart don't total more than £10 then an extra fee is applied to bring the price up to £10.
Here is the code I have at the moment which works well in the cart phase however when you reach the checkout the pricing section doesn't stop loading for some reason and you can't checkout, can anyone help?
Code from functions.php:
function woocommerce_custom_surcharge() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$minimumprice = 10;
$currentprice = $woocommerce->cart->cart_contents_total;
$additionalfee = $minimumprice - $currentprice;
if ( $additionalfee >= 0 ) {
wc_print_notice(
sprintf( 'We have a minimum %s per order. As your current order is only %s, an additional fee will be applied at checkout.' ,
wc_price( $minimumprice ),
wc_price( $currentprice )
), 'error'
);
$woocommerce->cart->add_fee( 'Minimum Order Adjustment', $additionalfee, true, '' );
}
}
add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_surcharge' );
Enhanced and updated on May 2019.
The infinite loading spin issue that you are facing is due to wc_print_notice() when it's used in woocommerce_cart_calculate_fees hook. It's seems like a bug.
If you use instead wc_add_notice(), the problem is gone but the notice is displayed 2 times.
Additionally I have revisited your code.The only solution is to split it in 2 separated functions (and a third one for the message):
// Add a custom fee (displaying a notice in cart page)
add_action( 'woocommerce_cart_calculate_fees', 'add_custom_surcharge', 10, 1 );
function add_custom_surcharge( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_cart_calculate_fees' ) >= 2 )
return;
$min_price = 100; // The minimal cart amount
$current_price = $cart->cart_contents_total;
$custom_fee = $min_price - $current_price;
if ( $custom_fee > 0 ) {
$cart->add_fee( __('Minimum Order Adjustment'), $custom_fee, true );
// NOTICE ONLY IN CART PAGE
if( is_cart() ){
wc_print_notice( get_custom_fee_message( $min_price, $current_price ), 'error' );
}
}
}
// Displaying the notice on checkout page
add_action( 'woocommerce_before_checkout_form', 'custom_surcharge_message', 10 );
function custom_surcharge_message( ) {
$min_price = 100; // The minimal cart amount
$cart = WC()->cart;
$current_price = $cart->cart_contents_total;
$custom_fee = $min_price - $current_price;
// NOTICE ONLY IN CHECKOUT PAGE
if ( $custom_fee > 0 ) {
wc_print_notice( get_custom_fee_message( $min_price, $current_price ), 'error' );
}
}
// The fee notice message
function get_custom_fee_message( $min_price, $current_price ) {
return sprintf(
__('We have a minimum %s per order. As your current order is only %s, an additional fee will be applied.', 'woocommerce'),
wc_price( $min_price ),
wc_price( $current_price )
);
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Conditionally apply coupons automatically for specific Product IDs and quantities

I am trying to automatically apply coupons in my WooCommerce store based on product ID and quantity conditions. My end goal is for a particular coupon to apply automatically when TWO (2) of the desired products are added to the cart, and for another coupon to app,y automatically whenever THREE (3) of the desired products are added to the cart. A single quantity of the product should have no discount. The following is the CORRECTED version of the code, which now works:
add_action( 'woocommerce_before_cart', 'conditional_auto_add_coupons' );
function conditional_auto_add_coupons() {
if ( !WC()->cart->is_empty() ){
// Define HERE your Targeted Product ID and coupons codes
$target_pid = 103;
$coupon1 = 'soccer-sibling-2';
$coupon2 = 'soccer-sibling-3';
// First cart loop: Counting number of subactegory items in cart
foreach ( WC()->cart->get_cart() as $cart_item ){
if( $target_pid == $cart_item['data']->id ){
// Removes any coupons in the cart already
WC()->cart->remove_coupons();
if( 2 == WC()->cart->get_cart_contents_count() && !WC()->cart->has_discount( $coupon1 ) ){
WC()->cart->remove_coupons();
WC()->cart->add_discount( $coupon1 );
wc_add_notice( __( 'The multiple sibling discount has been applied.', 'theme_domain' ), 'success' );
} elseif( 3 == WC()->cart->get_cart_contents_count() && !WC()->cart->has_discount( $coupon2 ) ){
WC()->cart->remove_coupons();
WC()->cart->add_discount( $coupon2 );
wc_add_notice( __( 'The multiple sibling discount has been applied.', 'theme_domain' ), 'success' );
}
// Recalculates Cart Totals to show correct price
WC()->cart->calculate_totals();
}
}
}
}
Theres is a lot of errors in your code and it's a little obsolete too...
I have rewrite everithing in your function and hooked it in another hook.
Here is your revisited code:
add_action( 'woocommerce_before_cart', 'conditional_auto_add_coupons' );
function conditional_auto_add_coupons() {
if ( !WC()->cart->is_empty() ){
// Define HERE your Targeted Product ID and coupons codes
$target_pid = 103;
$coupon1 = 'soccer-sibling-2';
$coupon2 = 'soccer-sibling-3';
// First cart loop: Counting number of subactegory items in cart
foreach ( WC()->cart->get_cart() as $cart_item ){
if( $target_pid == $cart_item['data']->id ){
if( 2 == WC()->cart->get_cart_contents_count() && !WC()->cart->has_discount( $coupon1 ) ){
WC()->cart->add_discount( $coupon1 );
wc_add_notice( __( 'A quantity discount of <strong>5%</strong> has been added.', 'theme_domain' ), 'success' );
} elseif( 3 == WC()->cart->get_cart_contents_count() && !WC()->cart->has_discount( $coupon2 ) ){
WC()->cart->add_discount( $coupon2 );
wc_add_notice( __( 'A quantity discount of <strong>10%</strong> has been added.', 'theme_domain' ), 'success' );
}
}
}
}
}
This code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This should work and will not make your website crash, but I haven't really test it, as this is very particular.
Coming back here a few years later: I found a loophole that caused an issue. Because the function was counting the total cart contents, rather than just the quantity of the product the coupon is applied to, customers could exploit this to add non-coupon related products to get the additional coupons for the discounted product. The following code closes the loophole by checking the quantity of just the product in question:
add_action( 'woocommerce_before_cart', 'conditional_auto_add_coupons_tourney' );
function conditional_auto_add_coupons_tourney() {
if ( !WC()->cart->is_empty() ){
// Define HERE your Targeted Product ID and coupons codes
$target_pid = 96;
$coupon1 = 'multiple-25';
$coupon2 = 'multiple-50';
// UPDATE: switched WC()->cart->get_cart_contents_count() for $quantity on 236 and 240
// First cart loop: Counting number of subcategory items in cart
foreach ( WC()->cart->get_cart() as $cart_item ){
if( $target_pid == $cart_item['product_id'] ){
WC()->cart->remove_coupons();
$quantity = $cart_item['quantity']; // Added to find quantity of specific product
if( 5 <= $quantity && !WC()->cart->has_discount( $coupon2 ) ){
WC()->cart->remove_coupons();
WC()->cart->add_discount( $coupon2 );
wc_add_notice( __( 'The multiple team discount has been applied.', 'theme_domain' ), 'success' );
} elseif( 2 <= $quantity && !WC()->cart->has_discount( $coupon1 ) ){
WC()->cart->remove_coupons();
WC()->cart->add_discount( $coupon1 );
wc_add_notice( __( 'The multiple team discount has been applied.', 'theme_domain' ), 'success' );
}
WC()->cart->calculate_totals();
}
}
}
}

Woocommerce change add to cart text if stock status is 0

I'm trying to check if a product is at 0 stock, and if so, change the text on the cart button. I don't want to check if they're out of stock because backorders are allowed so products will never be out of stock, they'll stop at 0. What am I missing from this code?
add_filter( 'woocommerce_product_single_add_to_cart_text', 'woo_custom_cart_button_text' );
function woo_custom_cart_button_text() {
global $product;
$product->get_stock_quantity();
if( $product == 0 ) {
return __( 'Backorder', 'woocommerce' );
} else {
return __( 'Add to cart ', 'woocommerce' );
}
}
you can use following code:
add_filter( 'woocommerce_get_availability', 'custom_get_stock', 1, 2);
function custom_get_stock( $availability, $_product ) {
if ( !$_product->is_in_stock() ) $availability['availability'] = __('Backorder', 'woocommerce');
return $availability;
}

Categories