How to Link Directly to a WooCommerce Product Variation

Build a WooCommerce variation URL that opens with options pre-selected, or adds one variation to the cart. Global vs custom attributes, blocks, SEO.

Cover image for "How to Link Directly to a WooCommerce Product Variation": the title on a dark green background next to an illustration of the topic

To link directly to a WooCommerce product variation, add each attribute to the product URL as a query parameter: /product/tee/?attribute_pa_color=blue&attribute_pa_size=large. The page opens with those options already chosen. To put the variation straight into the cart instead, use its variation ID: /cart/?add-to-cart=1234.

That is the short answer to "woocommerce variation url". WooCommerce does this without a plugin, but the details trip people up: global and custom attributes use different parameter names, the add-to-cart link needs the variation ID rather than the parent, and an SEO plugin setting can quietly strip the parameters. I checked every claim below in the WooCommerce source on GitHub (version 11.2.2, the current release, and the development branch), and I link the files so you can check them too. I also ran every link in this guide on a test store with WooCommerce 11.2.2 and WordPress 7.1.4, logged out, on Storefront and on Twenty Twenty-Five. If you'd rather not build the links by hand, my free WooCommerce variation link generator does it for you.

The two variation URLs WooCommerce understands

Link Example Use it for
Pre-selected product page /product/tee/?attribute_pa_color=blue&attribute_pa_size=large Ads, emails and social posts where the shopper should see the product with the right options picked
Add-to-cart link /cart/?add-to-cart=1234 "Buy now" buttons, reorder links and landing pages where the shopper should skip the product page

Both work on any WooCommerce store. The next sections explain how to build each one correctly.

Pre-select a variation: attribute_pa_ vs attribute_

On the classic product page, the function that prints each variation dropdown, wc_dropdown_variation_attribute_options() in includes/wc-template-functions.php, looks for a request parameter named attribute_ plus the sanitized attribute name. If it finds one, that option is selected. If not, it falls back to the product's default variation. The name you need depends on what kind of attribute it is.

Global attributes are the ones created under Products › Attributes. WooCommerce stores them as taxonomies called pa_{slug}, so the parameter is attribute_pa_{slug}, and the value is the term's slug:

  • Attribute "Color" with slug color, term "Light Blue" with slug light-blue: ?attribute_pa_color=light-blue
  • You'll find both slugs under Products › Attributes › Configure terms.
  • The comparison runs the value through sanitize_title(), so Light Blue, light blue and light-blue all match. Stick to the slug anyway; it is the form WooCommerce itself writes.

Custom attributes are typed directly into one product's Attributes tab. They have no pa_: the parameter is attribute_ plus the attribute name run through sanitize_title(), and the value is the option as you typed it:

  • Attribute "Fabric Type" with option "Organic Cotton": ?attribute_fabric-type=Organic%20Cotton
  • On the product page, WooCommerce also accepts the lowercase slug form (organic-cotton), but an all-capitals version such as ORGANIC COTTON won't match.
  • For add-to-cart links the exact value is required (see below), so the safest habit is to use the value exactly as it appears in the product editor, URL-encoded.

You can combine as many attributes as the product has, joined with &. Leave out an attribute and the shopper simply picks it.

WooCommerce's own variation permalink uses exactly this format. WC_Product_Variation::get_permalink() in includes/class-wc-product-variation.php returns the parent product URL with the variation's attributes added as attribute_* parameters, skipping any attribute set to "Any".

Find the variation ID

Open the product, go to Product data › Variations and expand a variation. The number after the # is its ID. You need it for add-to-cart links, because WooCommerce does not look up a variation from its attributes when the link names only the parent product.

There are two working formats:

  1. ?add-to-cart={variation ID}, for example /cart/?add-to-cart=1234. This is the shortest form and the one my generator uses. The form handler in includes/class-wc-form-handler.php sees that the ID belongs to a variation, and WC_Cart::add_to_cart() adds it under its parent product.
  2. ?add-to-cart={parent ID}&variation_id={variation ID}, plus the attributes. This is the URL WooCommerce itself builds in WC_Product_Variation::add_to_cart_url().

What doesn't work is the format many old tutorials show: ?add-to-cart={parent ID}&attribute_pa_color=blue without a variation_id. WooCommerce stops there with "Please choose product options", because the handler refuses to add a parent variable product on its own.

A few rules from WC_Cart::add_to_cart():

  • Attributes are only required when the variation uses "Any…". A variation set to "Blue / Any size" needs &attribute_pa_size=large in the link, or the shopper sees "Size is a required field". Attributes the variation fixes are filled in automatically.
  • Custom "Any" values must match exactly. For custom attributes the posted value has to equal one of the product's options, capital letters included.
  • quantity works: /cart/?add-to-cart=1234&quantity=3.
  • The parameter works on any front-end page. WooCommerce handles it on wp_loaded, so /?add-to-cart=1234, /cart/?add-to-cart=1234 and /checkout/?add-to-cart=1234 all add the product. Where the shopper ends up depends on the URL and one setting, below.

The "redirect to cart" setting overrides checkout links. If WooCommerce › Settings › Products has "Redirect to the cart page after successful addition" turned on, a /checkout/?add-to-cart=1234 link sends the shopper to the cart, not the checkout. Turn the setting off, or link to the cart and let the shopper continue from there.

Keep the trailing slash. On current versions, /checkout?add-to-cart=1234 (no slash) adds the product, WordPress redirects to /checkout/?add-to-cart=1234, and the product is added a second time. WooCommerce fixed this in PR #70131, which is scheduled for version 11.4. Until then, always write the slash. Refreshing a page whose address still contains ?add-to-cart= also adds the product again, which is expected behaviour.

WooCommerce 10.0 added shareable checkout links: /checkout-link/?products=1234:2&coupon=SAVE10. Two things to know before you use them in a campaign:

  • They empty the shopper's existing cart first. The handler in src/Blocks/Domain/Services/CheckoutLink.php calls empty_cart() before adding the products.
  • Up to version 11.2, pass the variation ID (1234:2 means variation 1234, quantity 2). WooCommerce 11.3, which is due this week, also accepts the parent ID or SKU with attributes, for example ?products=15:2:color=white;size=M. If an "Any" attribute is missing, the shopper lands on the product page with the known options pre-selected.

Does it work on block themes?

Yes, on current versions, as long as your block theme's single product template uses the Add to Cart + Options block. Its variation selector (VariationSelectorAttribute.php in src/Blocks/BlockTypes/AddToCartWithOptions/) reads the same attribute_* parameters and compares each value after sanitize_title(), so on block themes custom values are matched without regard to capital letters. That server-side support has been in WooCommerce since 10.9. One difference from the classic page: if the parameter is present but matches no option, the block selects nothing rather than falling back to the default variation.

Check which block your template actually uses, though. On my test store, Twenty Twenty-Five's default single product template with WooCommerce 11.2.2 still uses the older Add to Cart Form block, which renders the classic form. There the classic rules apply: attribute_pa_color=red was pre-selected, while an all-capitals custom value was not.

Swatch plugins are a separate question. Some replace the dropdowns with their own buttons and don't read the parameters. If a link pre-selects correctly with your plugin turned off but not with it on, the plugin is the cause.

Variation URLs and SEO

A pre-selected link is the same product page with parameters added, and that is exactly what Google recommends for variants:

  • Google's ecommerce URL guidance asks that each variant can be identified by its own URL, gives a query parameter such as ?color=green as a good form, and says to use the URL without the parameter as the canonical. URL fragments such as #green are ignored.
  • WooCommerce prints no canonical tag of its own. WordPress core's rel_canonical() outputs the plain product permalink, so every variation link already points its canonical at the product. Yoast and Rank Math replace that tag with their own; check your page source to confirm the canonical is the product URL without parameters.
  • Google's product variants documentation requires that each variant can be pre-selected with a distinct URL using query parameters, and Merchant Center asks for the same in each item's link, so the feed should use these URLs.
  • Since WooCommerce 11.0 (PR #66043), a URL that selects every attribute of one variation outputs structured data for that variation: a single offer with its own price, SKU and stock, instead of the price range. That helps avoid price-mismatch warnings in Merchant Center.

So there is no reason to create a separate product for each colour just to get a URL. One product with parameter links and a canonical to the base URL is the setup Google describes.

Symptom Cause Fix
Nothing is pre-selected attribute_color used for a global attribute Global attributes need pa_: attribute_pa_color
Global attribute not selected Term name used where the slug differs Use the slug from Configure terms
Worked last month, not now The attribute or term slug was renamed Rebuild the link with the new slug
Custom attribute not selected Value in a different case or spelling Use the value exactly as in the product editor
Works for you, not for shoppers Yoast's "Remove unregistered URL parameters" is on Add each attribute_ key to its allow-list (below)
Shows the default variation for everyone Page cache ignores query strings Exclude attribute_ URLs from the cache, or vary the cache on query strings
Correct dropdowns, wrong buttons A swatch plugin that doesn't read the parameters Check the plugin's settings or ask its developer

The Yoast case deserves a note, because it fools store owners. This one comes from reading Yoast's code rather than my test store. Under Settings › Crawl optimization, the "Remove unregistered URL parameters" option (off by default) redirects away every parameter that isn't on its allow-list. It is not applied to logged-in users, so the owner sees the links working while shoppers don't. Add attribute_pa_color and each of your other keys under "Additional URL parameters to allow". The match is exact, with no wildcards.

My free WooCommerce variation link generator builds both link types from the attribute names and values you enter. It applies the slug rules above, keeps the exact value for custom attributes, writes the trailing slash on cart and checkout links, and can point add-to-cart links at the product page, the cart or the checkout.

If you'd like the address bar to update while shoppers pick options, so they can copy and share the exact variation, I also wrote a small free plugin, Variation URLs for WooCommerce. It is on GitHub and listed on my plugins page. WooCommerce doesn't need it to read variation links; it only keeps the URL in sync with the selection.

Frequently asked questions

Add the attributes to the product URL: ?attribute_pa_{slug}=term-slug for global attributes and ?attribute_{name}=Value for custom ones. The product page opens with those options selected.

What does attribute_pa_ mean in a WooCommerce URL?

pa_ marks a global product attribute, which WooCommerce stores as a taxonomy named pa_{slug}. Custom attributes created on a single product have no pa_ in their parameter name.

Can I add a variation to the cart with just the variation ID?

Yes. /cart/?add-to-cart=1234, where 1234 is the variation ID, adds that variation. Add attributes only for options the variation leaves as "Any". The parent ID with attributes but no variation_id fails.

Usually a wrong parameter name (missing pa_), a term name instead of its slug, an SEO plugin removing unknown parameters, a page cache that ignores query strings, or a swatch plugin that doesn't read the parameters. The table above covers each one.

Do variation URLs cause duplicate content?

No. The canonical tag points to the product URL without parameters, which is the setup Google recommends for product variants.

Yes: /checkout/?add-to-cart=1234, unless "Redirect to the cart page after successful addition" is turned on, in which case the shopper lands on the cart. From WooCommerce 10.0 you can also use /checkout-link/?products=1234:1, which empties the cart first.

Do I need a plugin for WooCommerce variation URLs?

No. WooCommerce reads the parameters itself. A plugin only helps if you want the address bar to update as shoppers change options.

When to get help

Variation links get harder once swatch plugins, product configurators, multi-currency or Merchant Center feeds are involved. If your links behave differently from what this guide describes, I can find out why and fix it as part of my WooCommerce development work. Projects start at $500, with a fixed quote after a short call.

Have a project in mind? Let’s talk.

Tell me what you are building and where you need support. I’ll respond with a clear, practical next step.

Start your project