Sync WooCommerce Products Between Sites
Below, you will find two ways to configure product sync with multiple WooCommerce stores:
- using a plugin,
- or programmatically, with the help of the WooCommerce REST API.
The idea is that when you create or update a product on one (primary) store, it will be automatically created or updated on connected WooCommerce stores. The two-way sync is also possible.
The WooCommerce Product Sync Plugin
Let’s begin with the product sync plugin approach. Still, continue reading this article if you want to learn how to use the WooCommerce API for product sync. For sure, the plugin uses the API as well, but you don’t need to code anything here or even know what it is and how it works under the hood.
I can recommend two options as a WooCommerce product sync plugin:
| Product sync plugin | How it works |
|---|---|
| Simple WP Crossposting | This is the full version of the plugin; it can sync not only WooCommerce products, but also posts, pages, and custom post types. It can also handle complex custom fields and more. |
| Simple Product Sync for WooCommerce | The free version of the plugin; it easily allows you to sync WooCommerce products. However, if you’re using complex ACF fields, or maybe you want to bulk sync multiple products, then consider using the full version. |
No matter which plugin version you’ve decided to use on your WooCommerce store, the whole process of product syncing is similar. When you edit a specific store, you can use checkboxes to select one of the connected stores to which you want to sync this product:

Multiple WooCommerce products sync (using WordPress bulk actions)
Another cool feature of the plugin is the possibility to sync multiple WooCommerce products at the same time using WordPress bulk actions. However, it is only available in the Pro version.
Here is how this feature is going to look in your store:

Exclude product data from WooCommerce API product sync
One of the cool things about the plugin is that you can easily exclude unneeded product data from syncing, for example, product stock, prices, or even product statuses (which basically allows you to create products as drafts on other stores).
This can be easily achieved on the plugin settings page:

More plugin features:
- Of course, product images and product gallery images are fully supported.
- Sync not only simple products but also variable products with variations and other types of products.
- Sync meta fields – ACF and other plugins are supported (but for complex custom fields you will need the Pro version).
- Compatibility with many popular third-party plugins like WPML, Polylang, Elementor, Yoast, JetEngine, etc. (tested specifically in the Pro version).
- Prices (and other product data) can be modified during the synchronization process using the rudr_swc_pre_crosspost_product_data hook.
You can take a closer look at my WooCommerce product sync plugin, which also allows you to work with regular WordPress posts, pages, and custom post types.
Feel free to take a closer look at my WooCommerce product sync plugin, whether you choose the Pro or Lite version.
Using WooCommerce REST API to Sync Products Between Sites
Maybe you don’t need the product sync plugin, or maybe you’re creating some custom functionality for your client store – either way, I am going to describe step-by-step how to use the WooCommerce API for product sync with multiple WooCommerce stores.
1. Prepare authentication data from your target stores
I assume you would like to perform the product sync with multiple stores (not only with a single one), so for each of them, we have to prepare a set of data. Depending on the chosen way of syncing products, it could be different:
| WordPress HTTP API product sync | WooCommerce API product sync |
|---|---|
| Store URL | Store URL |
| Username (login) | Consumer key |
| Application password | Consumer secret |
Now, let’s specify it in our application. In this tutorial, I am going to use PHP and store the authentication data as an array.
// an array of multiple WooCommerce stores you would like to sync products between
$stores = array(
// store 1
array(
'url' => '', // the store URL goes here with https://
'login' => '', // a username or a consumer key
'pwd' => '', // an application password or a consumer secret
),
// store 2
array(
'url' => '',
'login' => '',
'pwd' => '',
),
// store 3 etc
);In case you’re going to use the WordPress HTTP API, provide an application password in the pwd parameter, or for WooCommerce API product sync, you need to provide a consumer key in the login parameter and consumer secret in the pwd parameter.
2. Decide how you’re going to interact with WooCommerce REST API
Previously, I already said that I am going to use PHP in order to interact with WooCommerce REST API, and it is perfectly fine if you’re about to do the same.
But I think I have to tell you that there are different ways of how you can do that:
- WordPress HTTP API in PHP,
- Requests library,
- Official WooCommerce PHP and JavaScript libraries.
It is absolutely up to you to decide which method you’re going to use. In this tutorial, I will show you both WordPress HTTP API and WooCommerce API product sync methods in PHP.
3. Sync products between sites using the REST API
In this chapter, we are going to create multiple REST API requests to sync (publish or update) a product on connected stores automatically when it is published or updated on the main store.
/*
* Plugin name: WooCommerce API Product Sync with Multiple Stores
* Plugin URI: https://rudrastyh.com/woocommerce/product-sync-with-multiple-stores.html
* Version: 1.0.0
* Author: Misha Rudrastyh
*/
class Misha_Sync_Woo_Products {
public function __construct() {
add_action( 'save_post_product', array( $this, 'sync' ), 99, 2 );
}
public function sync( $product_id, $post ) {
// do nothing if WooCommerce is not installed
if( ! function_exists( 'wc_get_product' ) ) {
return;
}
// get product object
$product = wc_get_product( $product_id );
// do the sync for published products only
if( 'publish' !== $product->get_status() ) {
return;
}
// do the product sync with multiple WooCommerce stores from this array
$stores = array( ... );
// prepare product data before the loop
$product_data = $product->get_data();
// Fix: "Error 400. Bad Request. Cannot create existing product."
unset( $product_data[ 'id' ] );
// Fix: "Error 400 Bad Request low_stock_amount is not of type integer,null." error
$product_data[ 'low_stock_amount' ] = (int) $product_data[ 'low_stock_amount' ];
// In order to sync a product image we have to do some additional stuff
if( $product_data[ 'image_id' ] ) {
$product_data[ 'images' ] = array(
array(
'src' => wp_get_attachment_url( $product_data[ 'image_id' ] )
)
);
unset( $product_data[ 'image_id' ] );
}
// let's loop through multiple stores and sync the product with each of them
foreach( $stores as $store ) {
$endpoint = "{$store[ 'url' ]}/wp-json/wc/v3/products";
$method = 'POST';
// let's check if the product with the same SKU already exists
if( $product_id_2 = $this->product_exists( $product, $store ) ) {
$endpoint = "{$endpoint}/{$product_id_2}";
$method = 'PUT';
}
// WooCommerce API product sync request
wp_remote_request(
$endpoint,
array(
'method' => $method,
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( "{$store[ 'login' ]}:{$store[ 'pwd' ]}" )
),
'body' => $product_data
)
);
}
}
private function product_exists( $product, $store ) {
$sku = $product->get_sku();
$request = wp_remote_get(
add_query_arg( 'sku', $sku, "{$store[ 'url' ]}/wp-json/wc/v3/products" ),
array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( "{$store[ 'login' ]}:{$store[ 'pwd' ]}" )
)
)
);
if( 'OK' === wp_remote_retrieve_response_message( $request ) ) {
$products = json_decode( wp_remote_retrieve_body( $request ) );
if( $products ) {
$product = reset( $products );
return $product->id;
}
}
return false;
}
}
new Misha_Sync_Woo_Products;Keep in mind the following:
- When working with WooCommerce products, you have a choice to use either
save_postorsave_post_{post type}hook, I recommend the second one because it allows you to skip one more conditional statement. $stores = array( … )we created in the previous step. You have to provide application passwords here.$product->get_data()is an amazing method ofWC_Productclass that allows you to get all the product information and pass it almost without changes into a REST API request.- In this example, I only sync the main product image, but if you need to sync gallery images as well, I recommend using my plugin.
- I’m pretty sure you don’t want product duplicates to be created on other stores every time you hit the “Update” button, so I created a method
product_exists()that performs one more REST API request in order to check whether a product with the same SKU already exists or not. But it is also possible to do it with product metadata (and faster).
Now, let’s take a look at using the WooCommerce API for product sync instead of the WordPress HTTP API. To do so, I am just going to slightly change the sync() method:
foreach( $stores as $store ) {
$woocommerce = new Client( $store[ 'url' ], $store[ 'login' ], $store[ 'pwd' ] ) );
if( $product_id_2 = $this->product_exists( $product, $woocommerce ) ) {
try{
$woocommerce->put( "products/{$product_id_2}", $product_data );
} catch( Exception $error ) {
// processing errors here
}
} else {
try{
$woocommerce->post( "products", $product_data );
} catch( Exception $error ) {
// processing errors here
}
}
}Please don’t forget that in this case, we’re using a Consumer Key as $store[ 'login' ] and a Consumer Secret as $store[ 'pwd' ].
We also need to completely change the product_exists() method:
private function product_exists( $product, $woocommerce ) {
$sku = $product->get_sku();
$products = $woocommerce->get( 'products', array( 'sku' => $sku ) );
if( $products ) {
$product = reset( $products );
return $product->id;
}
return false;
}Please let me know in the comments if you have any questions about the code or about my plugin.
Misha Rudrastyh
Hey guys and welcome to my website. For more than 15 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
Hi, I would like to know the following about the plugin:
1- Does it comes with an auto-sync functionally to monitor shop A in case a new product is added or inventory changes replicate it in shop B?
2- If shop A does not have an SKU, is it possible to use ID instead?
3- I have 600 products in shop A, is it possible to use an auto-sync function or do I have to do it manually?
5- I have all the media already loaded in shop B, but I have deleted the products because I have been doing the job export/import manually. Do I have to delete all media in Shop B and then start syncing? Or the plugin automatically identifies the images from shop A (preloaded in B ) and attaches them to the new product created in shop B
Thanks
Hi Augusto,
1. Yes
2. The WooCommerce product sync plugin sets a connection between products using meta field (you can choose either SKU or meta field in plugin settings).
3. Currently there is a bulk sync add-on but I have plans to create auto-sync tool.
5. Yes, better to delete those media (it is possible to make the automatic media identification of course but it will slow down the plugin, so I didn’t add that).
You’re always welcome if you have any other questions :)
Hi Misha.
First of all, thank you for the detailed description of the processes in your posts.
I’d like to know if where’s an easy way to get a product by ID via API and import it. I guess it would be similar to what you describe here, but from the “destination” store.
Thanks in advance!
Hi Esteban,
You can get a product by ID using this endpoint
/wp-json/wc/v3/products/<id>, not sure whether it is an easy way though :)Hello Misha,
first of all thank you for your great codes that you are sharing with us!
I have tried this code and almost I was done but i have faced the following issue:
syntax error, unexpected variable “$product_data”
what did i miss here?
Thank you!
Hi Omar,
Maybe you’ve missed
;or)or something…Hi Misha,
Does the plugin has to be installed on the source site(s)? Is it possible to Get content rather than push?
I mean, I need to sync multiple e-commerce sites from third parties brands to a single marketplace (which I manage). Would your plugin work for that use case?
Thanks !
Hi Jérémy,
Sure, the plugin will work great for your scenario, and yes, you will need to install it to every third-party brand site.
But the idea of using “get” rather than “push” is very interesting, maybe I will create another plugin for that or will add it as the additional functionality.
Hi,
I am using WooCommerce API Product sync with multiple stores plugin. I tried to sync a product, it got synced but the images, categories and tags etc were not synced. Is there a way to achieve this?
Thanks.
Hi,
Could you please clarify the exact plugin name you are using?
Hi Misha, is it possible to choose fields to sync, for example only title, price and image and not the description?
Hi Diego,
Yes, sure
Hello Misha! I have considered coding something similar but using a different approach. I like this way though even though “GET” would in some cases be better than “POST” in my personal opinion — depending on what kind of stores you run.
My questions:
1) Have you considered implementing a conditional solution where you could sync some products, but not all? For example; if this product tag exists, then post to stores. My stores do not always cross paths so to speak. If store A sells clothes and store A sells shoes, then the shows would cross paths only.
2) My stores could not share SKU either even if selling two identical products. How would you recommend going by this if your code was used as a baseline?
Hey Leonardo,
1) Yes, I’ve been asking about this from time to time, but it can be implemented with this filter hook.
2) A custom field or a custom database table with relationships