WooCommerce Update Product
Version | Date | Created / Updated | Notes |
---|---|---|---|
v1.0 | Hristiyan Georgiev | Initial version |
Much like the rest of the flows, we need to separate the updates to product update an variant update. We want to use the product update when updating a simple product, and the variant update when updating a product that is part of a variation.
Protect flags handle :
The good thing is that we do not need to block any communication but rather we can exclude fields that we don’t want to update.
Protect the whole item
- This field blocks all content updates for the relevant product to the marketplace except for Stock & Price update. WooCommerce allows us to only update the stock & price in a single “full” update call, but it will be misleading for the end user and if we have this flag, we want to skip the update and leave theList/Update the whole item
on Pending.Protect Price
- This means we include everything except the price related fields in our payload -regular_price, sale_price, date_on_sale_from_gmt
anddate_on_sale_to_gmt
Protect Stock
- This means we include everything exceptstock_quantity
field in our payload.
Product Update
API Call: POST /wp-json/wc/v3/products/batch
API Docs: https://woocommerce.github.io/woocommerce-rest-api-docs/?shell#batch-update-products
We want to use this call when updating a simple product (not a variation). We also need to perform this call for the parent product update as part of our variation call. Since we cannot identify when the user wants to update the parent and when the parent’s variant, we will always perform both calls for the parent and it’s variant.
All triggers, validations except the protect flags mentioned above, are as per the listing abstraction for product update - Product Listing general requirements.
Since we will be updating the parent with this call, we need to add an additional trigger - Listing WooCommerce
> Is Parent
= Yes . This trigger should be on an OR basis meaning that we pick a product that is NOT part of a variation OR if part of a variation, it needs to be the parent. In all other cases we should use the Variant update call.
Please note that we can include up to 100 objects in the body.
Example call :
{
"update": [
{
"id": 130,
"name": "Trash",
"description": "Its no good",
"short_description": "The almsot best product",
"sku": "STAMAT14213135",
"global_unique_id": "",
"regular_price": "1123",
"sale_price": "999",
"date_on_sale_from_gmt": null,
"date_on_sale_to_gmt": null,
"manage_stock": true,
"stock_quantity": 22,
"sold_individually": "true",
"weight": "123",
"dimensions": {
"length": "22",
"width": "12",
"height": "5"
},
"categories": [
{
"id": 15
}
],
"tags": [
{
"name": "blablaBLA"
}
],
"images": [
{
"src": "https://cdn.pixabay.com/photo/2017/08/09/04/53/texture-2613518_1280.jpg"
}
],
"attributes": [
{
"id": 1,
"variation": true,
"visible": true,
"options": [
"S",
"M"
]
}
],
"brands": [
{
"id": 24
}
]
},
{
"id": 128,
"name": "TestTest",
"description": "ITestTest",
"short_description": "The test product ever",
"sku": "STA4533744",
"global_unique_id": "",
"regular_price": "100",
"sale_price": "59",
"date_on_sale_from_gmt": null,
"date_on_sale_to_gmt": null,
"manage_stock": true,
"stock_quantity": 22,
"sold_individually": "true",
"weight": "123",
"dimensions": {
"length": "22",
"width": "12",
"height": "5"
},
"categories": [
{
"id": 15
}
],
"tags": [
{
"name": "UnoDosTres"
}
],
"images": [
{
"src": "https://cdn.pixabay.com/photo/2017/08/09/04/53/texture-2613518_1280.jpg"
}
],
"attributes": [
{
"id": 1,
"variation": true,
"visible": true,
"options": [
"S",
"M"
]
}
],
"brands": [
{
"id": 24
}
]
}
]
}
Mapping :
WooCommerce Field | MCPro Field | Notes | |
---|---|---|---|
id |
Listing > Channel Item ID |
||
name |
Listing > Title |
||
description |
Listing > Description |
Description is html friendly. | |
The design template logic remains so if we have design template we pick as per abstraction. | |||
short_description |
Listing WooCommerce > Short Description |
||
sku |
Product > SKU |
||
global_unique_id |
Product Account > |
Marketplace EAN
OR
Product
> EAN
OR
Product
> Barcode
OR
Product
> MPN
OR
Product
>UPC
| Product Account
is with priority. The priority in the other fields is : EAN, Barcode, MPN, UPC |
| regular_price
| | Listing
> RRP
| We need to have a logic and if RRP
is empty, we send Price
as regular_price
and sale_price
as empty.
Please note that we exclude this field when updating a variation parent. |
| sale_price
| | Listing
> Price
| Please note that it looks like Woo does not have any validations for prices whatsoever, so it is possible that we send sale_price
higher than regular_price
. They will still return success response but the higher sale price will not show, only the lower price will show. We want to have internal validation and if we have Price
> RRP
, we want to store internal error.
Please note that we exclude this field when updating a variation parent. |
| date_on_sale_from_gmt
| | Listing WooCommerce
> Promotion Date Start
| We need to convert it into an ISO8601 format. We only need to send if both fields are filled. If one or both are not filled, we exclude them BOTH from the payload.
Please note that we exclude this field when updating a variation parent. |
| date_on_sale_to_gmt
| | Listing WooCommerce
> Promotion Date End
| We need to convert it into an ISO8601 format. We only need to send if both fields are filled. If one or both are not filled, we exclude them BOTH from the payload.
Please note that we exclude this field when updating a variation parent. |
| manage_stock
| | | Hardcoded to “true”.
Please note that we exclude this field when updating a variation parent. |
| stock_quantity
| | Listing
> Quantity
| Please note that we exclude this field when updating a variation parent. |
| sold_individually
| | Listing WooCommerce
> Sold Individually
| New field! This should be a tickbox field and if checked, we send “true”, if unchecked we send “false”. Default should be unchecked.
Please note that we exclude this field when updating a variation parent. |
| weight
| | Product
> Weight
| We need a logic based on the Channel
> Country
:
-If it is United States we need to convert to lbs
-If it is any other country, we send it without converting. |
| dimensions
| | | |
| | length
| Product
> Length
| We need a logic based on the Channel
> Country
:
-If it is United States we need to convert to inches
-If it is any other country, we send it without converting. |
| | width
| Product
> Width
| We need a logic based on the Channel
> Country
:
-If it is United States we need to convert to inches
-If it is any other country, we send it without converting. |
| | height
| Product
> Height
| We need a logic based on the Channel
> Country
:
-If it is United States we need to convert to inches
-If it is any other country, we send it without converting. |
| categories
| | | |
| | id
| Listing
> Primary Category ID
AND
Listing WooCommerce
> More Categories
| If we have more than one category we need to send them as separate objects. If we have more than 1 record in More Categories
they will be separated by comma. We need to split and send them as separate objects. We will have the name filled but we need to send the id
. We need to have the same taxonomy validation for More Categories
as Primary Category ID
. |
| tags
| | | |
| | name
| Listing WooCommerce
> Tags
| New field! This should be a field with the possibility to “add more features”. Similar to the Item/Variation specifics fields. The only difference is that here we will have only one box for input instead of two. Then each row should be sent as separate object into the tags
array |
| images
| | | |
| | src
| Listing Image + More Images
OR
All Images (Leading + Additional | As per abstraction - Images Handling Additional Explanation
We need to have a logic
-If we are updating a simple product, we send All Images
-If we are updating a variation parent, we send Listing Image + More Images |
| attributes
| | | Each separate attribute needs to be in a separate attributes array |
| | id
| Listing
> Item Specific Name
| |
| | variation
| | -If we are updating simple product, we send this as “false”
-If we are updating a variation parent, we send this as “true” |
| | visible
| | Hardcoded as “true” |
| | options
| Listing
> Item Specific
Value
| Please note that if we are sending a variation parent, we MUST include all of the variations’ item specific attributes. So for example if we have a variation that varies by Size and we have values of S,M,L across the variation products, then we need to include them all when updating the variation parent (just like in the payload example.
If it is a simple product, it will have just one option and we still need to add it in the options
array. |
| brands
| | | Each separate brand (if more than 1) needs to be in a separate brands array |
| | id
| Product
> Brand
AND
Listing
WooCommerce
> More Brands
| If we have more than one brand we need to send them as separate objects. If we have more than 1 record in More Brands
they will be separated by comma. We need to split and send them as separate objects. We will have the name filled but we need to send the id
. We need to have the same taxonomy validation for More Brands
as Product
> Brand
|
Example response :
{
"id": 145,
"name": "Hoodie with VariantNEW",
"slug": "hoodie-with-variantnew-4",
"permalink": "https://sociable-sable-b1ae91.instawp.xyz/product/hoodie-with-variantnew-4/",
"date_created": "2025-06-03T08:08:44",
"date_created_gmt": "2025-06-03T08:08:44",
"date_modified": "2025-06-03T08:08:44",
"date_modified_gmt": "2025-06-03T08:08:44",
"type": "variable",
"status": "publish",
"featured": false,
"catalog_visibility": "visible",
"description": "<p style=\"text-align: left\">Hoody very best and ogod</p>",
"short_description": "The best product in the whole world",
"sku": "",
"price": "",
"regular_price": "",
"sale_price": "",
"date_on_sale_from": null,
"date_on_sale_from_gmt": null,
"date_on_sale_to": null,
"date_on_sale_to_gmt": null,
"on_sale": false,
"purchasable": false,
"total_sales": 0,
"virtual": false,
"downloadable": false,
"downloads": [],
"download_limit": -1,
"download_expiry": -1,
"external_url": "",
"button_text": "",
"tax_status": "taxable",
"tax_class": "",
"manage_stock": true,
"stock_quantity": 20,
"backorders": "no",
"backorders_allowed": false,
"backordered": false,
"low_stock_amount": null,
"sold_individually": true,
"weight": "123",
"dimensions": {
"length": "22",
"width": "12",
"height": "5"
},
"shipping_required": true,
"shipping_taxable": true,
"shipping_class": "",
"shipping_class_id": 0,
"reviews_allowed": true,
"average_rating": "0",
"rating_count": 0,
"upsell_ids": [],
"cross_sell_ids": [],
"parent_id": 0,
"purchase_note": "",
"categories": [
{
"id": 15,
"name": "Uncategorized",
"slug": "uncategorized"
}
],
"tags": [
{
"id": 41,
"name": "blabla",
"slug": "blabla"
}
],
"images": [
{
"id": 144,
"date_created": "2025-06-03T08:08:44",
"date_created_gmt": "2025-06-03T08:08:44",
"date_modified": "2025-06-03T08:08:44",
"date_modified_gmt": "2025-06-03T08:08:44",
"src": "https://sociable-sable-b1ae91.instawp.xyz/wp-content/uploads/2025/06/texture-2613518_1280-3.jpg",
"name": "texture-2613518_1280-3.jpg",
"alt": ""
}
],
"attributes": [
{
"id": 1,
"name": "Size",
"slug": "pa_size",
"position": 0,
"visible": true,
"variation": true,
"options": [
"M",
"S"
]
}
],
"default_attributes": [],
"variations": [],
"grouped_products": [],
"menu_order": 0,
"price_html": "",
"related_ids": [
105,
112,
97,
93,
110
],
"meta_data": [],
"stock_status": "instock",
"has_options": true,
"post_password": "",
"global_unique_id": "",
"permalink_template": "https://sociable-sable-b1ae91.instawp.xyz/product/%pagename%/",
"generated_slug": "hoodie-with-variantnew-4",
"brands": [
{
"id": 24,
"name": "Guma",
"slug": "guma"
}
],
"_links": {
"self": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products/145",
"targetHints": {
"allow": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE"
]
}
}
],
"collection": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products"
}
]
}
}
We don’t need to map anything from the response, if success we need to act as per the abstraction - Product Listing general requirements. If there was an error, we want to store the message
into Listing
> Update Item Error
and set the Listing
> List/Update the whole item
= Error.
Variant Update
API Call : POST /wp-json/wc/v3/products/{product_id}/variations/batch
API Docs : https://woocommerce.github.io/woocommerce-rest-api-docs/?shell#batch-update-product-variations
We use this call when we need to update a product that is part of a variation. Remember we still need to update the parent product but this time as part of the variation.
The {productId}
we pick from Listing
> Channel Item ID
Example call :
{
"update": [
{
"id": 77,
"name": "Hoodie with Variant - L",
"description": "LLLLLLLLLLLLLLLLLLL",
"sku": "SKU789",
"global_unique_id": "",
"regular_price": "110",
"sale_price": "99",
"date_on_sale_from_gmt": null,
"date_on_sale_to_gmt": null,
"manage_stock": true,
"stock_quantity": 20,
"weight": "123",
"dimensions": {
"length": "22",
"width": "12",
"height": "5"
},
"categories": [
{
"id": 15
}
],
"tags": [],
"images": [
{
"src": "https://cdn.pixabay.com/photo/2017/08/09/04/53/texture-2613518_1280.jpg"
}
],
"attributes": [
{
"id": 1,
"option": "L"
}
],
"brands": [
{
"id": 24
}
]
},
{
"id": 78,
"name": "Hoodie with Variant - M",
"description": "Mmmmmmmmmmmmmmmmm",
"sku": "SKU123",
"global_unique_id": "",
"regular_price": "150",
"sale_price": "129",
"date_on_sale_from_gmt": null,
"date_on_sale_to_gmt": null,
"manage_stock": true,
"stock_quantity": 20,
"weight": "123",
"dimensions": {
"length": "22",
"width": "12",
"height": "5"
},
"categories": [
{
"id": 15
}
],
"tags": [],
"images": [
{
"src": "https://cdn.pixabay.com/photo/2017/08/09/04/53/texture-2613518_1280.jpg"
}
],
"attributes": [
{
"id": 1,
"option": "M"
}
],
"brands": [
{
"id": 24
}
]
}
]
}
Mapping :
WooCommerce Field | MCPro Field | Notes | |
---|---|---|---|
name |
Listing > Title |
||
description |
Listing > Description |
Description is html friendly. | |
The design template logic remains so if we have design template we pick as per abstraction. | |||
sku |
Product > SKU |
Please note. If we are sending the parent’s info, we need to send this as empty. We can find out if we are sending the parent’s details if we have Listing WooCommerce > Is Parent flag to Yes. |
|
global_unique_id |
Product Account > |
Marketplace EAN
OR
Product > EAN
OR
Product > Barcode
OR
Product > MPN
OR
Product >UPC |
Product Account is with priority. The priority in the other fields is : EAN, Barcode, MPN, UPC.
Please note. If we are sending the parent’s info, we need to send this as empty. We can find out if we are sending the parent’s details if we have Listing WooCommerce > Is Parent flag to Yes. |
regular_price |
Listing > RRP |
We need to have a logic and if RRP is empty, we send Price as regular_price and sale_price as empty. |
||
---|---|---|---|---|---|---|
sale_price |
Listing > Price |
Please note that it looks like Woo does not have any validations for prices whatsoever, so it is possible that we send sale_price higher than regular_price . They will still return success response but the higher sale price will not show, only the lower price will show. We want to have internal validation and if we have Price > RRP , we want to store internal error. |
||||
date_on_sale_from_gmt |
Listing WooCommerce > Promotion Date Start |
We need to convert it into an ISO8601 format. We only need to send if both fields are filled. If one or both are not filled, we exclude them BOTH from the payload. | ||||
date_on_sale_to_gmt |
Listing WooCommerce > Promotion Date End |
We need to convert it into an ISO8601 format. We only need to send if both fields are filled. If one or both are not filled, we exclude them BOTH from the payload. | ||||
manage_stock |
Hardcoded to “true”. | |||||
stock_quantity |
Listing > Quantity |
|||||
sold_individually |
Listing WooCommerce > Sold Individually |
New field! This should be a tickbox field and if checked, we send “true”, if unchecked we send “false”. Default should be unchecked. | ||||
weight |
Product > Weight |
We need a logic based on the Channel > Country : |
-If it is United States we need to convert to lbs -If it is any other country, we send it without converting. | dimensions |
length |
Product > Length |
We need a logic based on the Channel > Country :
-If it is United States we need to convert to inches
-If it is any other country, we send it without converting. |
width |
Product > Width |
We need a logic based on the Channel > Country :
-If it is United States we need to convert to inches
-If it is any other country, we send it without converting. |
height |
Product > Height |
We need a logic based on the Channel > Country :
-If it is United States we need to convert to inches
-If it is any other country, we send it without converting. |
categories |
id |
Listing > Primary Category ID
AND
Listing WooCommerce > More Categories |
If we have more than one category we need to send them as separate objects. If we have more than 1 record in More Categories they will be separated by comma. We need to split and send them as separate objects. We will have the name filled but we need to send the id . We need to have the same taxonomy validation for More Categories as Primary Category ID . |
tags |
name |
Listing WooCommerce > Tags |
New field! This should be a field with the possibility to “add more features”. Similar to the Item/Variation specifics fields. The only difference is that here we will have only one box for input instead of two. Then each row should be sent as separate object into the tags array |
images |
src |
Main Image | As per abstraction - Images Handling Additional Explanation | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
attributes |
Each separate attribute needs to be in a separate attributes array | |||||||||||||||||||||||||||||||||||||||||||||||||
id |
Listing > Item Specific Name |
We will have the name, but we send the id |
||||||||||||||||||||||||||||||||||||||||||||||||
option |
Listing > Item Specific Value |
|||||||||||||||||||||||||||||||||||||||||||||||||
brands |
Each separate brand (if more than 1) needs to be in a separate brands array | |||||||||||||||||||||||||||||||||||||||||||||||||
id |
Product > Brand |
AND
Listing
WooCommerce
> More Brands
| If we have more than one brand we need to send them as separate objects. If we have more than 1 record in More Brands
they will be separated by comma. We need to split and send them as separate objects. We will have the name filled but we need to send the id
. We need to have the same taxonomy validation for More Brands
as Product
> Brand
|
Example response with error :
{
"update": [
{
"id": 77,
"type": "variation",
"date_created": "2025-05-21T13:45:04",
"date_created_gmt": "2025-05-21T13:45:04",
"date_modified": "2025-06-03T08:32:54",
"date_modified_gmt": "2025-06-03T08:32:54",
"description": "<p>LLLLLLLLLLLLLLLLLLL</p>\n",
"permalink": "https://sociable-sable-b1ae91.instawp.xyz/product/hoodie-with-stripes-2/?attribute_pa_size=l",
"sku": "SKU789",
"global_unique_id": "",
"price": "99",
"regular_price": "110",
"sale_price": "99",
"date_on_sale_from": null,
"date_on_sale_from_gmt": null,
"date_on_sale_to": null,
"date_on_sale_to_gmt": null,
"on_sale": true,
"status": "publish",
"purchasable": true,
"virtual": false,
"downloadable": false,
"downloads": [],
"download_limit": -1,
"download_expiry": -1,
"tax_status": "taxable",
"tax_class": "parent",
"manage_stock": true,
"stock_quantity": 20,
"stock_status": "instock",
"backorders": "no",
"backorders_allowed": false,
"backordered": false,
"low_stock_amount": null,
"weight": "123",
"dimensions": {
"length": "22",
"width": "12",
"height": "5"
},
"shipping_class": "",
"shipping_class_id": 0,
"image": {
"id": 63,
"date_created": "2025-05-20T13:13:53",
"date_created_gmt": "2025-05-20T13:13:53",
"date_modified": "2025-05-20T13:13:53",
"date_modified_gmt": "2025-05-20T13:13:53",
"src": "https://sociable-sable-b1ae91.instawp.xyz/wp-content/uploads/2025/05/1715726245686.jpg",
"name": "1715726245686",
"alt": ""
},
"attributes": [
{
"id": 1,
"name": "Size",
"slug": "pa_size",
"option": "L"
}
],
"menu_order": 1,
"meta_data": [],
"name": "L",
"parent_id": 74,
"_links": {
"self": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products/74/variations/77",
"targetHints": {
"allow": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE"
]
}
}
],
"collection": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products/74/variations"
}
],
"up": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products/74"
}
]
}
},
{
"id": 78,
"error": {
"code": "product_invalid_sku",
"message": "Invalid or duplicated SKU.",
"data": {
"status": 400,
"resource_id": 79,
"unique_sku": "SKU456-1"
}
}
}
]
}
From the success response we need to act as per the abstraction Product Listing general requirements.
From the error response we want to store the message
into Listing
> Update Item Error
and set the Listing
> List/Update the whole item
= Error.