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
| Parameter | Required | Description |
|---|---|---|
experience | ✓ | A ProductDrop, product ID, or an array containing either. |
month | Month number (1–12). Must be provided together with year. | |
year | Four-digit year. Must be provided together with month. | |
variant_id | A variant ID. Filters the calendar to show only slots for a specific variant. | |
guest_count | Number 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]=2024These 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_pricewhen displaying a "From" price. - Respect
date.slot_countanddate.sold_outwhen communicating availability. - Use
date.remaining_stockto show aggregate stock for a day. This returnsnilif any variant has infinite stock. - Pass
monthandyearexplicitly if building a navigable calendar. - Use
date.slots_by_variantwhen displaying multiple time slots on the same day. - Use
slot.shop_urlto link directly to the booking page for a specific slot. - Guard against
nilwhen comparingremaining_stock— it returnsnilfor infinite stock. - Hidden variants are automatically excluded from the calendar data.
- Always format prices using the
moneyfilter.