WooCommerce

Product Loop With Variations

A product loop can include variation controls when each product card is also an add-to-cart form for the current product.

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:

phpresources/views/front-page.php
{{ 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:

php
{{ 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:

php
{{ 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:

ValuePrints
labelHuman label.
valueSubmitted value.
slugSanitized slug.
selectedWhether this choice is selected.
availableWhether at least one matching variation is purchasable and in stock.
image.srcSelected variation image URL for this choice when available.
image.altVariation image alt text.
priceMatching variation price.
regular_priceMatching variation regular price.
sale_priceMatching variation sale price.
discountMatching variation discount percentage as a number.
price_htmlMatching variation formatted price HTML.
skuMatching variation SKU.
stock_statusMatching variation stock status.
stock_quantityMatching variation stock quantity.
prices.min, prices.max, prices.htmlAggregate price data when a choice can match multiple variations.

Example:

php
{{ 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 }}.

php
{{ 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:

php
{{ 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:

php
{{ 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.