WooCommerce Get Products
Version | Date | Created / Updated | Notes |
---|---|---|---|
v1.0 | ??/05/2025 | Hristiyan Georgiev | Initial version |
We want to be able to use the customer’s store and existing products in order to download & store them in MC Pro.
There are two separate calls for getting products and then getting the product’s variations. We will have to handle both. We can either incorporate them into one cron or build two separate crons. What we have to do is first get the main product ID and then use this ID to query it’s variations. It is up to the devs to decide how to handle this.
All triggers, validations, etc. are as per the abstraction - Get Products General Requirements
Get Product
API Call : GET /wp-json/wc/v3/products?status=publish
API Docs : https://woocommerce.github.io/woocommerce-rest-api-docs/?shell#list-all-products
We pick the status
param from Channel WooCommerce
> Product Status for Get Products
There is a possibility for pagination so we need to be able to handle this thorugh the page
and per_page
params. Default per_page
is 10 but we want to increase it to 50.
Example Response :
[
{
"id": 74,
"name": "Hoodie with stripes",
"slug": "hoodie-with-stripes-2",
"permalink": "https://sociable-sable-b1ae91.instawp.xyz/product/hoodie-with-stripes-2/",
"date_created": "2025-05-21T13:37:50",
"date_created_gmt": "2025-05-21T13:37:50",
"date_modified": "2025-05-23T08:21:23",
"date_modified_gmt": "2025-05-23T08:21:23",
"type": "variable",
"status": "publish",
"featured": false,
"catalog_visibility": "visible",
"description": "<p>WEweweqweqweqweqweqweqweqw</p>\n",
"short_description": "<p>Test testov testovak</p>\n",
"sku": "321321",
"price": "125",
"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": true,
"purchasable": true,
"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": false,
"weight": "150",
"dimensions": {
"length": "10",
"width": "20",
"height": "30"
},
"shipping_required": true,
"shipping_taxable": true,
"shipping_class": "",
"shipping_class_id": 0,
"reviews_allowed": true,
"average_rating": "0.00",
"rating_count": 0,
"upsell_ids": [],
"cross_sell_ids": [],
"parent_id": 0,
"purchase_note": "",
"categories": [
{
"id": 21,
"name": "Hoodies",
"slug": "hoodies"
},
{
"id": 38,
"name": "Bacho",
"slug": "bacho"
},
{
"id": 36,
"name": "Gacho",
"slug": "gacho"
}
],
"tags": [
{
"id": 20,
"name": "cool_product",
"slug": "cool_product"
},
{
"id": 22,
"name": "mamka ti",
"slug": "mamka-ti"
}
],
"images": [
{
"id": 80,
"date_created": "2025-05-21T14:55:08",
"date_created_gmt": "2025-05-21T14:55:08",
"date_modified": "2025-05-21T14:55:08",
"date_modified_gmt": "2025-05-21T14:55:08",
"src": "https://sociable-sable-b1ae91.instawp.xyz/wp-content/uploads/2025/05/lion-2071739_1280.jpg",
"name": "lion-2071739_1280",
"alt": ""
},
{
"id": 81,
"date_created": "2025-05-21T14:56:28",
"date_created_gmt": "2025-05-21T14:56:28",
"date_modified": "2025-05-21T14:56:28",
"date_modified_gmt": "2025-05-21T14:56:28",
"src": "https://sociable-sable-b1ae91.instawp.xyz/wp-content/uploads/2025/05/nature-13298_1280.jpg",
"name": "nature-13298_1280",
"alt": ""
}
],
"attributes": [
{
"id": 1,
"name": "Size",
"slug": "pa_size",
"position": 0,
"visible": true,
"variation": true,
"options": [
"L",
"M",
"S"
]
}
],
"default_attributes": [
{
"id": 21,
"name": "Color",
"option": "black"
}
],
"variations": [
77,
78,
79
],
"grouped_products": [],
"menu_order": 0,
"price_html": "<span class=\"woocommerce-Price-amount amount\"><bdi><span class=\"woocommerce-Price-currencySymbol\">$</span>125.00</bdi></span> – <span class=\"woocommerce-Price-amount amount\"><bdi><span class=\"woocommerce-Price-currencySymbol\">$</span>140.00</bdi></span>",
"related_ids": [],
"meta_data": [
{
"id": 146,
"key": "_children",
"value": []
}
],
"stock_status": "instock",
"has_options": true,
"post_password": "",
"global_unique_id": "",
"brands": [
{
"id": 24,
"name": "Guma",
"slug": "guma"
}
],
"_links": {
"self": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products/74",
"targetHints": {
"allow": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE"
]
}
}
],
"collection": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products"
}
]
}
}
]
Response Mapping :
WooCommerce Field | MCPro Field | Notes | |||
---|---|---|---|---|---|
id |
Listing > Channel Item ID |
||||
name |
Product > Product Title AND |
||||
Listing > Listing Title |
|||||
slug |
N/A | ||||
permalink |
N/A | ||||
date_created |
N/A | ||||
date_created_gmt |
N/A | ||||
date_modified |
N/A | ||||
date_modified_gmt |
N/A | ||||
type |
Here we have 4 possibilities : |
variable, simple, grouped and external.
We can implement a logic :
-If we have “variable” in this field, we also store the id
into Product
> Product Variation Group
. This way we will know that the product has variations and we need to perform the GET variants call.
-If we have “simple” this means it is a single product and there are no variations.
If we have “grouped” then this is a bundle item. In this case we want to store the main item with Product
> Is Bundle
= Yes, and then check the grouped_products
> related_ids
for the bundle components. When we have the IDs we then save the products as bundle components of this product.
-If we have external this means the product is dropshipped and we won’t cover this at the moment.
|
| status
| | | | Listing
> Product Status
| Options: draft, pending, private and publish.
- If we receive “draft” we set the product status to Product not created
-If we receive “pending” we set status to Awaiting Creation
-If we receive “publish” we set product status to Product Published
-If we receive private we set product status to “Awaiting Creation” |
|
featured
| | | | N/A | | |catalog_visibility
| | | | N/A | | |description
| | | |Listing
>Description
| | |short_description
| | | |Listing WooCommerce
>Short Description
| New field! WooCommerce allows for short descriptions which are displayed on the item separately from the main description. We want to have a logic and if thedescription
field above is empty, we want to store this intoListing
>Description
instead. | |sku
| | | |Product
>SKU
| | |price
| | | | N/A | If the product is variant or grouped here will be displayed the lowest price in the variation or group. If both of the below prices are empty, we want to store this asListing
>Price
, in all other cases we don’t map it. | |regular_price
| | | |Listing
>RRP
| We need a logic and ifsale_price
is empty, we import theregular_price
intoListing
>Price
. If the product is variant or grouped, this will be empty. | |sale_price
| | | |Listing
>Price
| | |date_on_sale_from
| | | |Listing WooCommerce
>Promotion Date Start
| New field! It will be in a format of2025-05-22T11:49:53
we need to convert it to unix timestamp | |date_on_sale_from_gmt
| | | | N/A | | |date_on_sale_to
| | | |Listing WooCommerce
>Promotion Date End
| New field! It will be in a format of2025-05-22T11:49:53
we need to convert it to unix timestamp | |date_on_sale_to_gmt
| | | | N/A | | |on_sale
| | | | N/A | | |purchasable
| | | | N/A | | |total_sales
| | | | N/A | | |virtual
| | | | N/A | | |downloadable
| | | | N/A | | |downloads
| | | | N/A | | |download_limit
| | | | N/A | | |download_expiry
| | | | N/A | | |external_url
| | | | N/A | | |button_text
| | | | N/A | | |tax_status
| | | | N/A | | |tax_class
| | | | N/A | | |manage_stock
| | | | N/A | | |stock_quantity
| | | |Listing
>Quantity
| | |backorders
| | | | N/A | | |backorders_allowed
| | | | N/A | | |backordered
| | | | N/A | | |low_stock_amount
| | | | N/A | | |sold_individually
| | | | N/A | | |weight
| | | |Product
>Weight
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in lbs so we need to convert it to grams -If it is any other country, we import it as it is without converting. | |dimensions
| | | | | | | |length
| | |Product
>Length
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in inches so we need convert it to cm -If it is any other country, we import it as it is without converting. | | |width
| | |Product
>Width
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in inches so we need convert it to cm -If it is any other country, we import it as it is without converting. | | |height
| | |Product
>Height
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in inches so we need convert it to cm -If it is any other country, we import it as it is without converting. | |shipping_required
| | | | N/A | | |shipping_taxable
| | | | N/A | | |shipping_class
| | | | N/A | | |shipping_class_id
| | | | N/A | | |reviews_allowed
| | | | N/A | | |average_rating
| | | | N/A | | |rating_count
| | | | N/A | | |upsell_ids
| | | | N/A | | |cross_sell_ids
| | | | N/A | | |parent_id
| | | | N/A | | |purchase_note
| | | | N/A | | |categories
| | | | | We may have more than one category. Each additional category will be a separate object.In such case we want to store the category with the lowestid
intoPrimary Category ID
and the rest we store into a new field inListing WooCommerce
>More Categories
which will be a Table field. | | |id
| | | N/A | | | |name
| | |Listing
>Primary Category ID
ANDListing WooCommerce
>More Categories
| Note! We store intoListing WooCommerce
only if we have more than 1 category! | | |slug
| | | N/A | | |tags
| | | | | | | |id
| | | N/A | | | |name
| | |Listing
WooCommerce
>Tags
| New field! The field should be table type.We may have more than one tag and for each tag we will have separate object. We want to store each tag as separate row . | | |slug
| | | | | |images
| | | | | | | |id
| | | N/A | | | |date_created
| | | N/A | | | |date_created_gmt
| | | N/A | | | |date_modified
| | | N/A | | | |date_modified_gmt
| | | N/A | | | |src
| | | Listing Image AND More Images | We store them as per the abstraction - Images Handling Additional Explanation Since we don’t know which image is main, we always store the first image in theimages
object as Listing Image and the rest we store as More Images . We don’t store Main Image from here. If we are storing a variation, we need to make sure that we store these images across all the products in the variation. | | |name
| | | N/A | | | |alt
| | | N/A | | |attributes
| | | | | | | |id
| | | | | | |name
| | |Listing
>Item Specific Name
| We only want to map this if we havetype
= simple, otherwise we skip it | | |slug
| | | N/A | | | |position
| | | N/A | | | |visible
| | | N/A | | | |variation
| | | N/A | | | |options
| | |Listing
>Item Specific Value
| We only want to map this if we havetype
= simple, otherwise we skip it. | |default_attributes
| | | | N/A | | | |id
| | | | | | |name
| | |Listing
>Item Specific Name
| We only want to map this if we havetype
= variable or grouped , otherwise we skip it | | |option
| | |Listing
>Item Specific Value
| We only want to map this if we havetype
= variable or grouped , otherwise we skip it | |variations
| | | | | We could use the values in this array for our next call which is Get Variations | |grouped_products
| | | | | If we have bundled products, the components ids will be listed in this array. We could use this to identify the product ids that we need to add as components. | |menu_order
| | | | N/A | | |price_html
| | | | N/A | | |related_ids
| | | | N/A | | |meta_data
| | | | N/A | | | |id
| | | N/A | | | |key
| | | N/A | | | |value
| | | N/A | | |stock_status
| | | |Listing
>Listing Status
| Possible values : instock, outofstock, onbackorder. We need a logic : -If we receive instock, we store the listing status as “Active” -If we receive outofstock or onbackorder, we store the listing status as “Inactive” | |has_options
| | | | N/A | | |post_password
| | | | N/A | | |global_unique_id
| | | | N/A | | |brands
| | | | | | | |id
| | | N/A | | | |name
| | |Product
>Brand
ANDListing
WooCommerce
>More Brands
| It is possible that we receive more than 1 brand. Each will be a separate object in brands. In this case we want to store the one wit the lowestid
intoProduct
>Brand
and the rest we store intoListing
WooCommerce
>More Brands
as a table field | | |slug
| | | N/A | | |_links
| | | | | | | |self
| | | | | | | |href
| | N/A | | | | |targetHints
| | | | | | | |allow
| N/A | | | |collection
| | | | | | | |href
| | N/A | |
As advised above, we also need to perform another call in order to get the product’s variants.
Get Variants
API Call : GET
/wp-json/wc/v3/products/{productId}/variations
API Docs : https://woocommerce.github.io/woocommerce-rest-api-docs/?shell#list-all-product-variations
There is a possibility for pagination so we need to be able to handle this thorugh the page
and per_page
params. Default per_page
is 10 but we want to increase it to 50.
Depending on if we are handling this in one cron or two separate, we either pick the productId
from the id
in the response from the above call, or if we have a separate cron we pick it from Product
> Product Variation Group
Example response :
[
{
"id": 79,
"type": "variation",
"date_created": "2025-05-21T13:45:04",
"date_created_gmt": "2025-05-21T13:45:04",
"date_modified": "2025-05-22T11:49:53",
"date_modified_gmt": "2025-05-22T11:49:53",
"description": "<p>Wow Pretty Much Wow Variant 3</p>\n",
"permalink": "https://sociable-sable-b1ae91.instawp.xyz/product/hoodie-with-stripes-2/?attribute_pa_size=s",
"sku": "SKU456",
"global_unique_id": "",
"price": "129",
"regular_price": "130",
"sale_price": "129",
"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": "",
"manage_stock": "parent",
"stock_quantity": 20,
"stock_status": "instock",
"backorders": "no",
"backorders_allowed": false,
"backordered": false,
"low_stock_amount": null,
"weight": "150",
"dimensions": {
"length": "10",
"width": "20",
"height": "30"
},
"shipping_class": "",
"shipping_class_id": 0,
"image": {
"id": 80,
"date_created": "2025-05-21T14:55:08",
"date_created_gmt": "2025-05-21T14:55:08",
"date_modified": "2025-05-21T14:55:08",
"date_modified_gmt": "2025-05-21T14:55:08",
"src": "https://sociable-sable-b1ae91.instawp.xyz/wp-content/uploads/2025/05/lion-2071739_1280.jpg",
"name": "lion-2071739_1280",
"alt": ""
},
"attributes": [
{
"id": 1,
"name": "Size",
"slug": "pa_size",
"option": "S"
}
],
"menu_order": 3,
"meta_data": [],
"name": "S",
"parent_id": 74,
"_links": {
"self": [
{
"href": "https://sociable-sable-b1ae91.instawp.xyz/wp-json/wc/v3/products/74/variations/79",
"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"
}
]
}
}
]
Response Mapping :
WooCommerce Field | MCPro Field | Notes | |||
---|---|---|---|---|---|
id |
Listing WooCommerce > Variant ID |
New field! | |||
type |
N/A | ||||
date_created |
N/A | ||||
date_created_gmt |
N/A | ||||
date_modified |
N/A | ||||
date_modified_gmt |
N/A | ||||
description |
Listing > Listing Title |
||||
permalink |
N/A | ||||
sku |
Product > SKU |
||||
global_unique_id |
N/A | ||||
price |
If for any reason regular_price and sale_price are empty, we want to import this into Listing > Price . In all other cases we ignore it. |
||||
regular_price |
Listing > RRP |
We need a logic and if sale_price is empty, we import the regular_price into Listing > Price . |
|||
sale_price |
Listing > Price |
||||
date_on_sale_from |
N/A | ||||
date_on_sale_from_gmt |
Listing WooCommerce > Promotion Date Start |
New field! | |||
It will be in a format of 2025-05-22T11:49:53 we need to convert it to unix timestamp |
|||||
date_on_sale_to |
N/A | ||||
date_on_sale_to_gmt |
Listing WooCommerce > Promotion Date End |
New field! | |||
It will be in a format of 2025-05-22T11:49:53 we need to convert it to unix timestamp |
|||||
on_sale |
N/A | ||||
status |
Listing > Product Status |
Options: draft, pending, private and publish. |
- If we receive “draft” we set the product status to Product not created
-If we receive “pending” we set status to Awaiting Creation
-If we receive “publish” we set product status to Product Published
-If we receive private we set product status to “Awaiting Creation” |
|
purchasable
| | | | N/A | | |virtual
| | | | N/A | | |downloadable
| | | | N/A | | |downloads
| | | | N/A | | |download_limit
| | | | N/A | | |download_expiry
| | | | N/A | | |tax_status
| | | | N/A | | |tax_class
| | | | N/A | | |manage_stock
| | | | N/A | | |stock_quantity
| | | |Listing
>Quantity
| | |stock_status
| | | |Listing
>Listing Status
| Possible values : instock, outofstock, onbackorder. We need a logic : -If we receive instock, we store the listing status as “Active” -If we receive outofstock or onbackorder, we store the listing status as “Inactive” | |backorders
| | | | N/A | | |backorders_allowed
| | | | N/A | | |backordered
| | | | N/A | | |low_stock_amount
| | | | N/A | | |weight
| | | |Product
>Weight
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in lbs so we need to convert it to grams -If it is any other country, we import it as it is without converting. | |dimensions
| | | | | | | |length
| | |Product
>Length
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in inches so we need convert it to cm -If it is any other country, we import it as it is without converting. | | |width
| | |Product
>Width
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in inches so we need convert it to cm -If it is any other country, we import it as it is without converting. | | |height
| | |Product
>Height
| We need a logic based on theChannel
>Country
: -If it is United States, this field will be in inches so we need convert it to cm -If it is any other country, we import it as it is without converting. | |shipping_class
| | | | N/A | | |shipping_class_id
| | | | N/A | | |image
| | | | | | | |id
| | | N/A | | | |date_created
| | | N/A | | | |date_created_gmt
| | | N/A | | | |date_modified
| | | N/A | | | |date_modified_gmt
| | | N/A | | | |src
| | | Main Image AND More Images | As per the abstraction - Images Handling Additional Explanation In case we have more than one image for the variation, we store the first one as Main Image and the rest as More Images. We need to have a check and if we already have stored the More Images (from the get product call) we don’t want to overwrite them but rather skip them. | | |name
| | | N/A | | | |alt
| | | N/A | | |attributes
| | | | | | | |id
| | | N/A | | | |name
| | |Listing
>Item Specific Name
| Since we can’t identify if an attribute is variation or item level, we keep everything as item attribute. | | |slug
| | | N/A | | | |option
| | |Listing
>Item Specific Value
| Since we can’t identify if an attribute is variation or item level, we keep everything as item attribute. | |menu_order
| | | | N/A | | |meta_data
| | | | N/A | | |name
| | | | N/A | | |parent_id
| | | |Listing
>Listing Variation Group
| | |_links
| | | | | | | |self
| | | | | | | |href
| | N/A | | | | |targetHints
| | | | | | | |allow
| N/A | | | |collection
| | | | | | | |href
| | N/A | | | |up
| | | | | | | |href
| | N/A | |
Apart from the mapping we will have to set as default also some of the internal fields because we are not receiving them from the marketplace.
MCPro field | Default Value |
---|---|
Listing > Dispatch Time Max |
-1 |
Listing > Immediate Payment |
Yes |
Listing > VAT |
-1 |