In case the customer pays online (using for example PayPal) the WooCommerce creates order and then wait for the payment. This "waiting" is order status pending
. No stock is being reduced during this period which is very bad. The stock is reduced after the succesfull payment by changing the order status to on-hold
. But sometimes the payment can take up 30minutes and during these 30minutes the order keeps in pending
status and the stock is not reduced, therefore if its a last piece of a product on stock, it is still available during this period. Therefore if I have only 1-3 pieces of each product on stock, there is a big possibility, that if I will have only one last piece of a product on stock, someone else will come and buy it during these 30 minutes, which leads to situation, where the last piece can be sold twice, which is inacceptible. Therefore I need to reduce the stock immediately after creating any order with any type of payment and any type of shipping. Therefore I tried to create a snippet, which will use a hook woocommerce_order_status_changed
and it should reduce the stock always when the order status changed to pending
, because pending
status does not reduces the stock. I do not know if this is the right attitude how to solve it. Could anyone help pls? I tried these two snippets, but without any changes of behaviour:
add_filter( 'woocommerce_can_reduce_order_stock', 'wcs_do_not_reduce_onhold_stock', 10, 2 );
function wcs_do_not_reduce_onhold_stock( $reduce_stock, $order ) {
if ( $order->has_status( 'pending' )) {
$reduce_stock = true;
}
return $reduce_stock;
}
add_action( 'woocommerce_order_status_pending', 'wc_maybe_reduce_stock_levels' );
add_action( 'woocommerce_order_status_changed', 'order_stock_reduction_based_on_status', 20, 4 );
function order_stock_reduction_based_on_status( $order_id, $old_status, $new_status, $order ){
if ( $new_status == 'pending'){
$stock_reduced = get_post_meta( $order_id, '_order_stock_reduced', true );
if( empty($stock_reduced) && $order->get_payment_method() == 'barion' ){
wc_reduce_stock_levels($order_id);
}
}
}
3
Answers
Well this is the only working solution I found now:
There is only one problem: in case of failed payment the stock is not getting back. Therefore there must be another action made like automatic cancelling of non-paid orders after (for example) 60mins, or use specific hook(s) from the payment gateway. Anyway what I have learned today, that there is a massive difference between
set_status
andupdate_status
. Beginners like me, beware! :-) So this way I switch every new order made by WooCommerce automatically inpending
state (which is not reducing the ordered stock) toon-hold
state (which does reducing the ordered stock) which is working solution to my problem. Maybe too easy for advanced programmers but because I did not find correct working solution of my question for two days of searching, I am posting it even it is so trivial to save another beginner's time, because as I found during searching: I am not the only one who needs to reduce the stock immediately when the order is made. So this is the way! :-)You can simply add the following code line to allow stock to be reduced on pending order status (WooCommerce will do the job triggering the function
wc_maybe_reduce_stock_levels()
on pending orders):Code goes in functions.php file of your active child theme (or active theme). It should works.
You need to add stock reducing hook (as LoicTheAztec already answered), but you need to also remove the opposite wc_maybe_increase_stock_levels hook too. To remove it correctly, you need to run it when it is already hooked, so you need to wrap it into init hook.
Following works for me (Woocommerce 5.4.1) – ensure the Pending status reduce stock levels: