15

I need so help. I'm trying to update the woocommerce product stock quantity programmatically. We have a vendor feed to us through some JSON. I can read the stock from the feed and can pull the data from the post meta correctly. I'm using the latest version of WP and WOO. PHP is 7.2

Below is how I am finding the Product ID from the SKU.

$product_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $sku ) );

This is returning the correct ID and I can use it to see the current metadata that is already there:

$website_stock = get_post_meta($product_id, '_stock', true);
echo "Website Stock -  " . $website_stock . "</br>";
$website_stock_status = get_post_meta($product_id, '_stock_status', true);
echo "Website Stock Status -  " . $website_stock_status . "</br>";

I then update the stock I am getting from the feed. This can be stock going from zero to x or x to zero and anywhere in between. This is how I am updating the out of stock:

$out_of_stock_staus = 'outofstock';

update_post_meta($product_id, '_stock', 0);
update_post_meta($product_id, '_stock_status', wc_clean( $out_of_stock_staus ));
wc_delete_product_transients( $product_id ); // Clear/refresh the variation cache

This is where it gets weird.

Updated sku

The data is showing correctly inside the product view in the admin panel. As a side note, this SKU can belong to a variation (we have tons of them) or it could be a simple product. In the end, they all seem to update ok. No errors are being generated that I can see.

I use a little PHP snippet in my functions.php that greys the out of stock items in the drop down. Here it is:

    /* Grey out out of stock items in the product dropdown */
add_filter( 'woocommerce_variation_is_active', 'grey_out_variations_when_out_of_stock', 10, 2 );

function grey_out_variations_when_out_of_stock( $grey_out, $variation ) {

   if ( ! $variation->is_in_stock() )
        return false;

    return true;
}

So the issues are:

  • The now out of stock item should not show as clickable in the dropdown, but it still is.
  • The stock on the front end is not always saying zero, it lets you select one then says there is no stock, so the add to cart button is active and should not be. So the front end it not seeing the updates.
  • The Woocommerce admin panel for products is not rolling up the out of stock to the parent, I have to do a quick edit and update for that to happen.
  • Basically, the back end sees the changes, but the frontend is not really showing up correctly.

Any help that anyone can provide would be greatly appreciated!

Thank you

LoicTheAztec
  • 184,753
  • 20
  • 224
  • 275
Dave
  • 163
  • 1
  • 2
  • 10
  • 1
    I want to thank @LoicTheAztec for going above and beyond in helping! Also as a side note I did find this function worked too - $new_quantity=wc_update_product_stock( $product_id, 0). Thanks again! – Dave Aug 22 '18 at 00:44

2 Answers2

24

Update 2

Since woocommerce 3 "outofstock" product status is saved in 2 locations:

  1. As post meta data for _stock_status meta key (just as before).
  2. As a post term name outofstock remaining to product_visibility custom taxonomy

That means that you missed just a step (the step 3):

$out_of_stock_staus = 'outofstock';

// 1. Updating the stock quantity
update_post_meta($product_id, '_stock', 0);

// 2. Updating the stock quantity
update_post_meta( $product_id, '_stock_status', wc_clean( $out_of_stock_staus ) );

// 3. Updating post term relationship
wp_set_post_terms( $product_id, 'outofstock', 'product_visibility', true );

// And finally (optionally if needed)
wc_delete_product_transients( $product_id ); // Clear/refresh the variation cache

It hope that it will work with your cron job.


Original answer

Your code is a bit outdated since woocommerce 3 and there is no specifically a stock status setting for product variations...

There is a dedicated function in woocommerce to get the product Id from the sku that you could use:

wc_get_product_id_by_sku( $product_sku );

For the parent variable product, you should not need to enabled stock management as this is done in each of its product variations (so at the product variation level).

Since woocommerce 3, the "outofstock" stock status is also managed thought a custom taxonomy product_visibility which term name is outofstock. So updating post meta is not enough.

Also is better to use the new CRUD setters and getters methods introduced with woocommerce 3.

So try the following code instead:

// get the product ID from the SKU
$product_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $sku ) );

// Get an instance of the WC_Product object
$product = new WC_Product( $product_id );

// Get product stock quantity and stock status
$stock_quantity = $product->get_stock_quantity();
$stock_status   = $product->get_stock_status();

// Display stock quantity and status
echo '<p>Product Stock quantity: ' . $stock_quantity . '</br>
    Product Stock status: ' . $stock_status . '</p></br>';

// Set product stock quantity (zero) and stock status (out of stock)
$product->set_stock_quantity();
$product->set_stock_status('outofstock');

// Save the data and refresh caches
$product->save();

Tested and works in a normal context (but apparently not with a cron job)

LoicTheAztec
  • 184,753
  • 20
  • 224
  • 275
  • Thank you @LoicTheAztec! I am getting an error when I go to use the $product_id = wc_get_product_id_by_sku( $sku ); $product = get_wc_product( $product_id ); PHP Fatal error: Uncaught Error: Call to undefined function get_wc_product() I think this is because it is a standalone PHP file being called from a CRON job. My load files look like this: define('WP_USE_THEMES', false); /** Loads the WordPress Environment and Template */ require(dirname( __FILE__ ) . '/wp-blog-header.php' ); require(dirname( __FILE__ ) . '/wp-load.php'); – Dave Aug 21 '18 at 21:31
  • @DavidPitzer yes of course, you should have mention that in your question. I will revisit my code later on trying to add a working code version for that particular case. – LoicTheAztec Aug 21 '18 at 21:42
  • Sorry for the confusion. I had not really thought much of it because all the other WC calls are returning data and a valid product ID. – Dave Aug 21 '18 at 22:07
  • @DavidPitzer So the issue is may be just related to the function wc_get_product_id_by_sku() … What happen if you use your sql query for that and the rest of my code. Does it works? – LoicTheAztec Aug 21 '18 at 22:16
  • I have tried it two ways. If I use the SQL query It is still says: Call to undefined function get_wc_product() When it tries to return the product. If I insert the call $product = new WC_Product( $product_id ); It works with both theSQL and the call to wc_get_product_id_by_sku( $sku );. The problem in that case is when it gets to your code it is saying Uncaught Exception: Invalid product.. – Dave Aug 21 '18 at 22:29
  • @DavidPitzer I can't test my code in your very specific context. I don't know what works or not. I have tested my code in a normal context and it works… So I keep my answer there … I Will make you a SQL query to update the stock status … so that should work with your cronjob. – LoicTheAztec Aug 21 '18 at 22:40
  • Thank you @LoicTheAztec! – Dave Aug 21 '18 at 22:54
  • @DavidPitzer Updated my answer … I hope it will work . I can't do anything more. – LoicTheAztec Aug 21 '18 at 23:26
  • For correcting reports, including out of stock report, you should also update `wc_product_meta_lookup` table. – Hamid Mohayeji Feb 22 '20 at 23:19
  • @HamidMohayeji This table is something new, that was not existing yet when I made this answer. Now when using CRUD methods as setters and using `save()` method, does update everything needed. – LoicTheAztec Feb 23 '20 at 00:21
  • how can i enable "Manage stock" programitically – Nadia Feb 19 '21 at 12:35
  • 1
    @nadia Use: `$product->set_manage_stock( true );` – LoicTheAztec Feb 19 '21 at 12:44
6

LoicTheAztecs update works fine (thank you)

But I was thinking: Why isn't there a WC-standard function for this?

So I found the:

wc_update_product_stock function

 wc_update_product_stock($product, $stock_quantity=null, $operation='set', $updating = false)
  • @param int|WC_Product | $product |Product ID or product instance.
  • @param int|null | $stock_quantity Stock quantity.
  • @param string | $operation Type of opertion, allows 'set', 'increase' and 'decrease'.
  • @param bool | $updating | If true, the product object won't be saved here as it will be updated later.
  • @return bool|int|null
oleviolin
  • 507
  • 5
  • 8