Experience slot calendar

Render a calendar showing availability and pricing for Experience products.

The experience_slot_calendar tag generates a calendar for one or more Experience products.

Within the tag, a Calendar object is made available. This object contains information about the current month, adjacent months, and each day within the calendar.

Each Date provides information about the availability for that day, including:

  • Available slot count
  • Sold out status
  • Display price
  • Remaining stock
  • Slots grouped by variant

This makes it possible to build booking calendars, availability pickers, and month navigation for Experience products.

Unlike the product_search and experience_slot_search tags, experience_slot_calendar does not automatically use values from the search query parameters. If you want the calendar to respond to URL parameters, you must pass them explicitly to the tag.

Basic usage

{% experience_slot_calendar experience: product, month: 2, year: 2024 %}
  <ul>
    {% for date in calendar.dates %}
      <li>
        {{ date.date | date: "%Y-%m-%d" }}

        {% if date.slot_count == 0 %}
          (no availability)
        {% elsif date.sold_out %}
          (sold out)
        {% else %}
          (from {{ date.display_price.fractional | money }})
        {% endif %}
      </li>
    {% endfor %}
  </ul>
{% endexperience_slot_calendar %}

This might render:

<ul>
  <li>2024-02-01 (from £18.00)</li>
  <li>2024-02-02 (from £18.00)</li>
  <li>2024-02-03 (from £18.00)</li>
  <li>2024-02-04 (sold out)</li>
  <li>2024-02-05 (sold out)</li>
  <li>2024-02-06 (sold out)</li>
  <li>2024-02-07 (sold out)</li>
  <li>2024-02-08 (sold out)</li>
  <li>2024-02-09 (sold out)</li>
  <li>2024-02-10 (from £5.00)</li>
  <li>2024-02-11 (from £5.00)</li>
  <li>2024-02-12 (from £5.00)</li>
  <li>2024-02-13 (from £5.00)</li>
  <li>2024-02-14 (no availability)</li>
  <li>2024-02-15 (no availability)</li>
  <li>2024-02-16 (no availability)</li>
  <li>2024-02-17 (no availability)</li>
  <li>2024-02-18 (no availability)</li>
  <li>2024-02-19 (from £18.00)</li>
  <li>2024-02-20 (from £18.00)</li>
  <li>2024-02-21 (from £18.00)</li>
  <li>2024-02-22 (from £18.00)</li>
  <li>2024-02-23 (from £18.00)</li>
  <li>2024-02-24 (from £18.00)</li>
  <li>2024-02-25 (from £18.00)</li>
  <li>2024-02-26 (from £18.00)</li>
  <li>2024-02-27 (from £18.00)</li>
  <li>2024-02-28 (from £18.00)</li>
  <li>2024-02-29 (from £18.00)</li>
</ul>

Parameters

ParameterRequiredDescription
experience✓A ProductDrop, product ID, or an array containing either.
monthMonth number (1–12). Must be provided together with year.
yearFour-digit year. Must be provided together with month.
variant_idA variant ID. Filters the calendar to show only slots for a specific variant.
guest_countNumber of guests (defaults to 1). Affects sold_out and remaining_stock calculations on dates and slots.

When both month and year are omitted, the calendar defaults to the month containing the next available slot. If no slots exist, it falls back to the current month.

Build a navigable calendar

A common pattern is to allow users to move between months.

You can pass month and year through the URL using the search query parameter:

https://my-easol-site.com/my-calendar-page?search[month]=2&search[year]=2024

These values are available through the Search object and can be passed directly into the tag.

The calendar object also exposes the previous and next months, making it easy to build month navigation.

{% experience_slot_calendar experience: product, month: search.month, year: search.year %}
  <h5>{{ calendar.first_day | date: "%B %Y" }}</h5>

  <ul>
    {% for date in calendar.dates %}
      <li>{{ date.date | date: "%Y-%m-%d" }}</li>
    {% endfor %}
  </ul>

  <nav>
    <a href="?search[month]={{ calendar.prev.month }}&search[year]={{ calendar.prev.year }}">
      {{ calendar.prev.first_day | date: "%B %Y" }}
    </a>

    <a href="?search[month]={{ calendar.next.month }}&search[year]={{ calendar.next.year }}">
      {{ calendar.next.first_day | date: "%B %Y" }}
    </a>
  </nav>
{% endexperience_slot_calendar %}

Display multiple time slots

Experiences can have multiple time slots on the same day.

Use date.slots_by_variant to display availability, pricing, and stock for each individual time slot. Each slot also provides a shop_url that links directly to the booking page for that slot. Use slot.limited for a low-availability message instead of deriving one from remaining_stock, which can be unavailable for externally managed stock.

{% experience_slot_calendar experience: product %}

  <ul>
    {% for date in calendar.dates %}
      <li>
        {{ date.date | date: "%Y-%m-%d" }}
        {% for slot_variant in date.slots_by_variant %}
          <details>
            <summary>{{ slot_variant.variant.name }}</summary>
            <ul>
              {% for slot in slot_variant.slots %}
                <li>
                  <a href="{{ slot.shop_url }}">
                    {{ slot.start_time }}
                    ({{ slot.price.fractional | money }})
                  </a>

                  {% if slot.sold_out %}
                    sold out
                  {% elsif slot.limited %}
                    limited availability
                  {% endif %}
                </li>
              {% endfor %}
            </ul>
          </details>
        {% endfor %}
      </li>
    {% endfor %}
  </ul>
{% endexperience_slot_calendar %}

Multi-experience calendars

The experience parameter accepts an array, allowing you to aggregate availability across multiple products into a single calendar.

{% assign experiences = page.experiences %}
{% experience_slot_calendar experience: experiences %}
  {% for date in calendar.dates %}
    {% if date.slot_count > 0 %}
      {{ date.date | date: "%Y-%m-%d" }}: {{ date.slot_count }} slots available
    {% endif %}
  {% endfor %}
{% endexperience_slot_calendar %}

When using multiple experiences, date.experiences returns the products with availability on that day.

Developer considerations

When implementing an Experience calendar:

  • Use date.display_price when displaying a "From" price.
  • Respect date.slot_count and date.sold_out when communicating availability.
  • Use date.remaining_stock to show aggregate stock for a day. This returns nil if any variant has infinite stock.
  • Pass month and year explicitly if building a navigable calendar.
  • Use date.slots_by_variant when displaying multiple time slots on the same day.
  • Use slot.shop_url to link directly to the booking page for a specific slot.
  • Guard against nil when comparing remaining_stock — it returns nil for infinite stock.
  • Hidden variants are automatically excluded from the calendar data.
  • Always format prices using the money filter.

On this page