01273 264503 info@mootpoint.org

I recently needed to write a sync function that was triggered when a WooCommerce product is saved in the admin, i.e. added or updated. Strangely, there isn’t a WooCommerce-specific hook in the documentation. Since WooCommerce products are a WordPress custom post type, we should be able to make use of the save_post_{$post_type} action. When I tried the following:

add_action('save_post_product', 'mp_sync_on_product_save', 10, 3);
function mp_sync_on_product_save( $post_id, $post, $update ) {
	$product = wc_get_product( $post_id );
	// do something with this product
}

I found that the retrieved product contained the data from before the latest changes had been saved. But the hook runs after the post has been saved to the database – how could that be? Then it hit me – most of the WooCommerce product data is stored as post_meta. And the save_post hook runs before the post_meta is updated. So we need to use a hook which fires after the post_meta is updated or added. It turns out we have to hook on 2 separate actions in our case (added_post_meta, when the product post_meta is added; and updated_post_meta, when it is updated). We also want to use added_post_meta, rather than add_post_meta as this runs after the changes are saved to the database.

The post_meta hooks fire when any post_meta is changed, which means we need to check a few things:

  • If multiple product fields have been updated, the hook will be triggered for each. Luckily, there is a meta_key called ‘_edit_lock’ which is always set when editing a post, so we can trigger our function when this is set.
  • We also need to check that we are working with a product post_type.

Putting all this together gives us our modified hook which runs when all the WooCommerce product data has been saved to the database:

add_action( 'added_post_meta', 'mp_sync_on_product_save', 10, 4 );
add_action( 'updated_post_meta', 'mp_sync_on_product_save', 10, 4 );
function mp_sync_on_product_save( $meta_id, $post_id, $meta_key, $meta_value ) {
    if ( $meta_key == '_edit_lock' ) { // we've been editing the post
        if ( get_post_type( $post_id ) == 'product' ) { // we've been editing a product
            $product = wc_get_product( $post_id );
            // do something with this product
        }
    }
}

Updated method for WooCommerce 3.x

As of 3.0, WooCommerce has a specific hook which runs when a product is updated, woocommerce_update_product. This allows us to use a much simpler function where we no longer have to check if a product is being updated, or if the _edit_lock flag is set:

add_action( 'woocommerce_update_product', 'mp_sync_on_product_save', 10, 1 );
function mp_sync_on_product_save( $product_id ) {
     $product = wc_get_product( $product_id );
     // do something with this product
}