When you turn the option “Manage Stock” on for your WooCommerce products (or variations), then every time an order is made, stock quantity of the products from the order is going to be automatically decreased.
But sometimes you don’t need that, or just need it for specific order statuses or payment methods. In this tutorial I will show you how you can do that.
Let’s begin with a filter hook woocommerce_can_reduce_order_stock which returns either true or false depending whether product stock quantity can be decreased or not. But the amazing part is that this hook also has a second argument which is WC_Order object and it allows us to make any kind of conditions!
It is as simple as that:
add_filter( 'woocommerce_can_reduce_order_stock', 'wpdev_can_reduce_stock', 25, 2 );
function wpdev_can_reduce_stock( $can_reduce, $order ) {
if( Any kind of condition here ) {
$can_reduce = false; // or true
}
return $can_reduce; // the default value
}
Now let’s take a look at more practical examples.
Examples
Don’t reduce product stock for orders with a specific custom field
add_filter( 'woocommerce_can_reduce_order_stock', 'wpdev_can_reduce_stock', 25, 2 );
function wpdev_can_reduce_stock( $can_reduce, $order ) {
if( 'META VALUE' === $order->get_meta( 'META KEY' ) ) {
$can_reduce = false;
}
return $can_reduce;
}
Don’t reduce product stock if a specific product is in the order
In this example please keep in mind that the product stock quanity will remain untouched for all products in the order.
add_filter( 'woocommerce_can_reduce_order_stock', function( $can_reduce, $order ) {
$is_product_in_order = false;
// get all order items
$items = $order->get_items();
if( $items ) {
foreach ( $items as $item_id => $item ) {
if( 'SPECIFIC PRODUCT ID' == $item->get_product_id() ) {
$is_product_in_order = true;
break;
}
}
}
return $is_product_in_order ? false : $can_reduce;
}, 25, 2 );
As you probably remember, products are stored in orders as order items.
Don’t reduce product stock for specific payment methods and specific order statuses
This example is more practical one, I assume. Our goal here is to not decrease product stock quantities if order have been made without actual payment. So for example if “Cash on delivery” payment method was selected. Here we are stick to a specific order statuses:
- processing – order has been made by a customer, in this case the product stock quantities remain unchanged.
- completed – order has been approved by a shop manager in WooCommerce admin, now we are ready to decrease stock quantities. We will need one more action hook here which will be fired when order status is changed – woocommerce_order_status_changed.
add_filter( 'woocommerce_can_reduce_order_stock', 'wpdev_no_stock_changes_for_cod', 25, 2 );
function wpdev_no_stock_changes_for_cod( $reduce_stock, $order ) {
if( $order->has_status( 'processing' ) && 'cod' === $order->get_payment_method() ) {
$reduce_stock = false;
}
return $reduce_stock;
}
add_action( 'woocommerce_order_status_changed', 'wpdev_reduce_stock_completed_orders', 20, 4 );
function wpdev_reduce_stock_completed_orders( $order_id, $old_status, $new_status, $order ){
// do nothing if this order was not not with cash on delivery payment method
if( 'cod' !== $order->get_payment_method() ) {
return;
}
// do nothing if it is not changing order status to "completed"
if ( 'completed' !== $new_status ){
return;
}
// reduce stock levels manually
wc_reduce_stock_levels( $order_id );
}
In case you would like to sync product stock quantities between products on different WooCommerce stores, then I recommend you to look at this plugin.