Guides / Variable products
WooCommerce Variable Products: Schema & Feeds for Variations
Variable products — a t-shirt in five sizes and three colors — are where most WooCommerce schema and feeds quietly break. Get them right and each variation can rank and list on its own; get them wrong and you get “missing offers” warnings and disapprovals.
Why variations are tricky
A variable product is really many purchasable items behind one page. Naive schema describes only the parent with a vague price range, and the offer often renders only after the shopper picks options — so crawlers see no price at all. Feeds have the mirror problem: submitting one row for the parent hides the actual buyable variants.
The right schema shape: ProductGroup
Google supports a ProductGroup that holds the shared
information and contains each variant as a Product with its own
SKU, identifier, price, and availability, linked by a
productGroupID and the attributes that vary:
{
"@context": "https://schema.org",
"@type": "ProductGroup",
"name": "TrailMaster Tee",
"productGroupID": "TM-TEE",
"variesBy": ["https://schema.org/size", "https://schema.org/color"],
"hasVariant": [
{
"@type": "Product",
"sku": "TM-TEE-S-BLU",
"size": "S",
"color": "Blue",
"gtin13": "0012345678905",
"offers": {
"@type": "Offer",
"price": "24.00",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock"
}
}
]
}
If a full ProductGroup isn’t feasible, the minimum bar is a
single Product whose offers renders server-side with
a valid price (a range via lowPrice/highPrice on an
AggregateOffer works) so crawlers never see “missing
offers.”
The right feed shape: item_group_id
In Merchant Center (and Meta, Bing, TikTok), submit one item per
purchasable variation. Tie them together with a shared
item_group_id and differentiate by attributes:
<g:id>TM-TEE-S-BLU</g:id>
<g:item_group_id>TM-TEE</g:item_group_id>
<g:size>S</g:size>
<g:color>Blue</g:color>
<g:price>24.00 USD</g:price>
<g:availability>in_stock</g:availability>
<g:gtin>0012345678905</g:gtin>
Common variation mistakes
- One feed row for the parent. Shoppers can’t buy “the parent” — submit each variation.
- Reusing the parent GTIN. Each variation usually has its own identifier; don’t copy one across all.
- JS-only offers. If price appears only after selecting options, crawlers see none. Render it server-side.
- Inconsistent stock. A variation marked in-stock in the feed but out-of-stock on the page gets disapproved.
Doing it without hand-maintaining every variant
Mapping every variation into both ProductGroup schema and
per-variant feed items — with correct identifiers and live stock —
is exactly the repetitive accuracy work that’s easy to get wrong by
hand. Easy Woo API reads your variations and emits correct
per-variant schema and feed data automatically from one live source.