Variants

Display and manage product variants.

See also: Variant object

Variants represent the different options available for a product.

Every product must have at least one variant. Common examples include:

  • Ticket
  • VIP Ticket
  • Adult Ticket
  • Child Ticket

Each variant defines its own pricing, availability, stock, and booking behaviour.

Variant fields

Each variant exposes the following fields for display:

FieldDescription
variant.nameThe variant name.
variant.taglineA short marketing description.
variant.imageThe variant's image, if one has been set.
variant.min_occupancyThe minimum number of guests.
variant.max_occupancyThe maximum number of guests.
variant.typeEither experience_variant or accommodation_variant.

Use variant.type when your theme needs to render differently for experiences and accommodations.

Variant pricing models

Easol supports several pricing models depending on how the product is sold.

Experience pricing

Pricing modelDescriptionExample
Per personEach quantity purchased represents one guest.£50 per person. Quantity 2 = 2 guests (£100).
Per unitThe variant has a fixed price regardless of guest count.Kayak hire: £80 per kayak, regardless of whether it's hired by 1 or 2 people.
Per unit with guest tiersOne unit is purchased, but pricing is based on the number of guests assigned to that unit.Cabin: £250 for 1–2 guests, £350 for 3–4 guests.
Per unit with per-person pricingOne unit is purchased, but each guest within that unit is charged individually.Tent pitch accommodating up to 4 guests at £35 per guest.

You can check the pricing strategy on an experience variant:

{% if variant.pricing_strategy_per_person %}
  Per person pricing
{% elsif variant.pricing_strategy_per_item %}
  Per unit pricing
{% endif %}

Accommodation pricing

Accommodation variants are always priced per night. Guests are charged for the number of nights booked, with optional per-day price overrides and occupancy-based discounts.

Accommodation variants also expose:

PropertyDescription
variant.minimum_nightsThe minimum number of nights required for a booking.
variant.min_price_of_stay_fractionalThe minimum total price for a stay in fractional subunits.

Your theme should display pricing in a way that clearly communicates how guests are charged.

Displaying prices

Use variant.price to access the variant's price and the money filter to format it:

{{ variant.price.fractional | money }}

For variants with occupancy-based tiers, use variant.prices to display each tier:

{% for tier in variant.prices %}
  {{ tier.occupancy }} guests: {{ tier.fractional | money }}
{% endfor %}

Promotional pricing

If a variant has an active promotion, apply it using the apply_promotion filter:

{% if variant.promotion %}
  {% assign promo_price = variant.price | apply_promotion: variant.promotion %}
  <s>{{ variant.price.fractional | money }}</s>
  {{ promo_price.fractional | money }}
{% else %}
  {{ variant.price.fractional | money }}
{% endif %}

Slot context

For experience variants, many properties — including price, stock, and sold-out status — behave differently depending on how the variant is accessed.

  • Through experience_slot.variants — values are scoped to that specific slot (date).
  • Through product.variants — values are aggregated across all upcoming slots.

When displaying per-date information such as remaining stock or pricing, always use the slot's variants:

{% for variant in experience_slot.variants %}
  {{ variant.name }}: {{ variant.remaining_stock }} remaining
{% endfor %}

Using product.variants in this context would sum stock across all upcoming dates, which is typically not what you want.

Availability and stock

When displaying variants, consider the following states.

Coming soon

product.variants returns only visible variants — those that are public and within their booking window. If a published product has no visible variants:

product.variants.size == 0

the product should be treated as Coming Soon. The product may still have variants configured, but none are currently available for booking.

Sold out

A variant is sold out when:

  • Its stock has been exhausted.
  • It has been manually marked as sold out.
  • All associated slots are in the past.

You can determine this using:

variant.sold_out

A product is considered sold out when all of its visible variants are sold out:

product.sold_out

variant.sold_out always returns false if the variant belongs to an experience with an active recurring schedule. Because new slots are continually generated, the variant is never considered fully sold out.

Remaining stock

Display the remaining stock using:

variant.remaining_stock

This returns nil if the variant has unlimited stock. Use variant.has_infinite_stock to check for this and avoid displaying a nil value:

{% if variant.has_infinite_stock %}
  Available
{% elsif variant.sold_out %}
  Sold out
{% else %}
  {{ variant.remaining_stock }} remaining
{% endif %}

Grouping variants

Variants can be organised into Segments to improve presentation.

Use the group_by filter to group variants by their segment_name.

{% assign variant_groups = product.variants | group_by: "segment_name" | sort: "segment_name" %}

{% for group in variant_groups %}
  <h2>{{ group.name }}</h2>

  <ul>
    {% for variant in group.items %}
      <li>{{ variant.name }}</li>
    {% endfor %}
  </ul>
{% endfor %}

This renders output similar to:

<h2>Double Rooms</h2>
<ul>
  <li>Winter Wonderland Room</li>
  <li>Bears Den Room</li>
  <li>Log Cabin Room</li>
</ul>

<h2>Single Rooms</h2>
<ul>
  <li>Winter Wonderland Room</li>
  <li>Bears Den Room</li>
  <li>Log Cabin Room</li>
</ul>

On this page