Reduce Product Stock Quantities Conditionally

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', 'rudr_can_reduce_stock', 25, 2 );

function rudr_can_reduce_stock( $can_reduce, $order ) {
	
	if( Any kind of condition here ) {
		$can_reduce = false; // or true
	}
	
	return $can_reduce; // the default value
	
}

If you don’t know where to insert code snippets from this tutorial, please check this guide.

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', 'rudr_can_reduce_stock', 25, 2 );
function rudr_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:

add_filter( 'woocommerce_can_reduce_order_stock', 'rudr_no_stock_changes_for_cod', 25, 2 );
function rudr_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', 'rudr_reduce_stock_completed_orders', 20, 4 );
function rudr_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 my plugin.

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X