Skip to content

Commerce Foundations is our pre-built Craft Commerce store. See what it includes

Craft CMS plugins

Variant Manager

A Craft CMS plugin that imports and exports Craft Commerce product variants from CSV files.

Recipe: select a variant and add to cart

A full storefront example: a product page with a select element for every attribute (Color, Size, Material), where changing a selection picks the matching variant and the form adds that variant to the cart on submit.

Replace variantAttributes with the handle of your Variant Attributes field.

Twig#

{% set attributeOptions = craft.variantManager.getAttributeOptions(product.id) %}
{% set selection = {} %}
{% for attribute in attributeOptions %}
  {# Find the selected option for the attribute using a kebab-case query param #}
  {% set selected = craft.app.request.getParam(attribute.name|kebab|ascii) ?? attribute.values|first %}
  {% set selection = selection|merge({(attribute.name): selected}) %}
{% endfor %}
{% set variant = craft.variants().productId(product.id).variantAttributes(selection).one() %}

<form method="post">
  {{ csrfInput() }}
  {{ actionInput('commerce/cart/update-cart') }}
  {{ hiddenInput('purchasableId', variant.id) }}

  <div>
    <h1>{{ product.title }}</h1>
    <div>
      {{ variant.onPromotion ? variant.salePriceAsCurrency : variant.priceAsCurrency }}
      {% if variant.onPromotion %}
        <span>
          (was <s aria-label="{{ 'Reduced from {price}'|t('site', { price: variant.priceAsCurrency }) }}">{{ variant.priceAsCurrency }}</s>)
        </span>
      {% endif %}
    </div>

    {% for attribute in attributeOptions %}
      <div>
        <label>
          {{ attribute.name }}
          <select class="attribute-select" name="{{ attribute.name|kebab|ascii }}">
            {% for value in attribute.values %}
              <option value="{{ value }}" {{ selection[attribute.name] == value ? 'selected' }}>{{ value }}</option>
            {% endfor %}
          </select>
        </label>
      </div>
    {% endfor %}

    <button type="submit">{{ 'Add to cart'|t('site') }}</button>
  </div>
</form>

{% js %}
  document.addEventListener('DOMContentLoaded', function () {
    document.querySelectorAll('.attribute-select').forEach(function (select) {
      select.addEventListener('change', attributeSelectionChanged);
    });
  });

  function attributeSelectionChanged(event) {
    const queryParams = new URLSearchParams(window.location.search);
    queryParams.set(event.target.name, event.target.value);
    window.location.search = queryParams.toString();
  }
{% endjs %}

How it works#

  1. getAttributeOptions pulls the distinct attribute names and their possible values across the product’s variants.
  2. For each attribute, the selected value comes from a query parameter (kebab-cased name) or falls back to the first value.
  3. craft.variants().productId(product.id).variantAttributes(selection).one() finds the single variant that matches every selection.
  4. The form posts purchasableId to commerce/cart/update-cart, adding the matched variant to the cart.
  5. Changing a <select> updates the URL’s query string; the page reloads with the new selection in the URL, and the Twig at the top picks up the new value.

We can take it from here.

We take on the Craft and Craft Commerce sites you built, so you can get back to building. Introduce a client who signs a management contract and you get a $3,000 partnership fee.

How the Dev Partnership Program works
See if we’re a fit