Updating Product Stock Programmatically

Since I’ve been working a lot lately with synchronising product stock quantities between multiple WooCommerce stores or within a WordPress Multisite network, I can share with you some interesting insights how it is working.

CRUD-objects vs Updating Product Meta Directly

Trying to update product stock using update_post_meta() function

Let’s begin with the thing that product stock information is stored in the post meta wp_postmeta table for now. WooCommerce has plans to move on to a custom database table, but it is just their plans in the future.

The meta keys used:

  • _manage_stock – whether stock managemant is turned on or not.
  • _stock – product stock quantity (stock management is on).
  • _stock_statusinstock, outofstock etc (stock management is off).

So, when you find those values in the database, the first thing that may come to your mind is to do something like this:

$product_id = 123;

update_post_meta( $product_id, '_manage_stock', 'yes' ); // yes or no
update_post_meta( $product_id, '_stock', 100 );
update_post_meta( $product_id, '_stock_status', 'instock' );

And it is actually working without even refreshing the caches:

But this method doesn’t work properly with product variations. Using WC_Product_Variable::sync() or wc_delete_product_transients() doesn’t help.

set_stock_status() and set_stock_quantity() methods of WC_Product

But the most correct way to update product stock data is to use CRUD layers of course.

$product_id = 123;
$product = wc_get_product( $product_id ); // object of WC_Product class
// for variations
// $product = wc_get_product_object( 'variation', $product_id );

$product->set_manage_stock( true ); // true/false
$product->set_stock_quantity( 100 );
// $product->set_stock_status( 'instock' );

// always
$product->save();

In this case you don’t even need to use set_stock_status() method because WooCommerce will figure it out itself that this specific product is in stock now.

Using WooCommerce REST API

$product_id = 123;

wp_remote_request(
	"https://YOUR STORE/wp-json/wc/v3/products/{$product_id}",
	array(
		'method' => 'PUT',
		'headers' => array(
			'Authorization' => 'Basic ' . base64_encode( "$login:$pwd" )
		),
		'body' => array(
			'manage_stock' => true,
			//'stock_status' => 'instock',
			'stock_quantity' => 100,
		)
	)
);

If you don’t know where to get $login and $pwd values, please read this.

In order to make it work for product variations just change the endpoint to /wp-json/wc/v3/products/{$product_id}/variations/{$variation_id}.

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 Twitter