Use this pattern for product cards that let visitors choose size, color, width, or another WooCommerce variation attribute before adding the item to the cart.
Smallest Variable Product Card#
Place variation controls inside {{ cart:add }}. The form belongs to the current product from the surrounding loop:
{{ query:products limit="4" }} <article> <a href="{{ url }}"> <h2>{{ title }}</h2> </a> <div>{{ price_html }}</div> {{ cart:add open_cart }} {{ if type == "variable" }} <p>Size</p> {{ variation:pills for="size" class="border px-3 py-2" active_class="bg-black text-white" unavailable_class="opacity-40" }} {{ label }} {{ /variation:pills }} {{ /if }} <button type="submit">Add to cart</button> {{ /cart:add }} </article>{{ /query:products }}TemplateX handles the WooCommerce field names, submitted values, required selection, selected variation ID, active state, and unavailable options. Your template owns the card markup, classes, labels, and button.
Choose The Control Type#
Use one control for each variation attribute:
{{ cart:add }} <p>Size</p> {{ variation:pills for="size" class="border px-3 py-2" active_class="border-black" }} {{ label }} {{ /variation:pills }} <p>Color</p> {{ variation:select for="color" class="border px-3 py-2" placeholder="Choose color" }} <p>Width</p> {{ variation:radios for="width" class="border px-3 py-2" active_class="bg-black text-white" }} {{ label }} {{ /variation:radios }} <button type="submit">Add to cart</button>{{ /cart:add }}for accepts the WooCommerce attribute slug, taxonomy name, submitted input name, or label. For example, for="size", for="pa_size", and for="attribute_size" can target the same option when they match the product attribute.
Show Variation Images#
Use {{ product:image }} when the main image should update after a variation is selected:
{{ product:image class="product-image" size="large" }}{{ cart:add }} {{ variation:pills for="color" image="variation" class="border p-2" active_class="border-black" }} {{ if image.src }} <img src="{{ image.src }}" alt="{{ image.alt }}"> {{ /if }} <span>{{ label }}</span> {{ /variation:pills }} <button type="submit">Add to cart</button>{{ /cart:add }}{{ product:image }} is a value tag. Attributes such as class, loading, and alt are added to the generated <img>. The optional size argument chooses the WordPress image size and is not rendered as an HTML attribute.
Values Inside Variation Choices#
Inside {{ variation:pills }} and {{ variation:radios }}, each choice exposes the option value and matching variation data:
| Value | Prints |
|---|---|
label | Human label. |
value | Submitted value. |
slug | Sanitized slug. |
selected | Whether this choice is selected. |
available | Whether at least one matching variation is purchasable and in stock. |
image.src | Selected variation image URL for this choice when available. |
image.alt | Variation image alt text. |
price | Matching variation price. |
regular_price | Matching variation regular price. |
sale_price | Matching variation sale price. |
discount | Matching variation discount percentage as a number. |
price_html | Matching variation formatted price HTML. |
sku | Matching variation SKU. |
stock_status | Matching variation stock status. |
stock_quantity | Matching variation stock quantity. |
prices.min, prices.max, prices.html | Aggregate price data when a choice can match multiple variations. |
Example:
{{ variation:pills for="color" image="variation" class="border p-2" active_class="border-black" }} {{ if image.src }} <img src="{{ image.src }}" alt="{{ image.alt }}"> {{ /if }} <span>{{ label }}</span> <small>{{ price | currency }}</small>{{ /variation:pills }}Update Card Values#
When a visitor changes a variation option, TemplateX updates nearby product value tags with the selected variation data. This includes {{ price_html }}, {{ price }}, {{ regular_price }}, {{ sale_price }}, {{ discount }}, {{ sku }}, and {{ stock_status }}.
{{ query:products limit="4" }} <article> <h2>{{ title }}</h2> <div>{{ price_html }}</div> <p>{{ sku }}</p> {{ cart:add }} {{ variation:select for="size" placeholder="Choose size" }} <button type="submit">Add to cart</button> {{ /cart:add }} </article>{{ /query:products }}For {{ description }} and {{ short_description }}, TemplateX uses the variation text when it exists. If the selected variation has no description, the tag keeps showing the parent product description.
Raw Option Loops#
Use {{ options }} and {{ values }} only when you need complete control over the form controls:
{{ cart:add }} {{ options }} {{ if variation }} <label for="{{ name }}-{{ product_id }}">{{ label }}</label> <select id="{{ name }}-{{ product_id }}" name="{{ name }}"> {{ values }} <option value="{{ value }}">{{ label }}</option> {{ /values }} </select> {{ /if }} {{ /options }} <button type="submit">Add to cart</button>{{ /cart:add }}Raw radio controls must keep the submitted field name from the parent option:
{{ cart:add }} {{ options }} {{ if variation }} <fieldset> <legend>{{ label }}</legend> {{ values }} <label> <input type="radio" name="{{ parent.name }}" value="{{ value }}" required> <span>{{ label }}</span> </label> {{ /values }} </fieldset> {{ /if }} {{ /options }} <button type="submit">Add to cart</button>{{ /cart:add }}Prefer {{ variation:pills }}, {{ variation:select }}, and {{ variation:radios }} unless you need custom controls. They handle more WooCommerce variation state for you.