Phone and opening hours
The phone field (an E.164 number parsed in a region, with accepted number types) and the opening_hours field (a weekly pattern, seasons, exceptions and public holidays), with parameters, validation, stored shapes and template values.
phone
A telephone number, parsed and checked for its region and stored in international E.164 form beside what the editor typed. Held once for every locale.
fields:
- { name: phone, type: phone, index: true }
- { name: mobile, type: phone, region: GB, types: [mobile] } | Parameter | Type | Default | What it does |
|---|---|---|---|
region | ISO 3166 code | the site’s country, in the admin’s editor | The region a number typed without its country code is read in. A number typed with + needs none. A seed file and content create do not read the site’s country, so there a bare national number needs this parameter, or { raw, region } in the value. |
types | list of fixed_line, mobile, toll_free, premium_rate, voip | any | The number types accepted. A number the dataset cannot tell between fixed line and mobile is accepted by either. |
| Code | Message |
|---|---|
region | Enter the number with its country code, starting with + (no region to read it in) |
phone_empty | Enter a telephone number |
phone_invalid | This is not a valid telephone number |
phone_region | This is not a valid telephone number for GB |
phone_type | Must be a mobile number |
Stored value:
{ "raw": "01295 123456", "region": "GB", "e164": "+441295123456", "national": "01295 123456", "type": "fixed_line" } raw and region are what the editor typed and where; the rest is derived on save. In a seed file or import, { raw, region } is enough, and a bare string is read in the field’s region parameter (without one it must start with +). With index: true the E.164 form is projected.
Template value:
| Property | What it is |
|---|---|
display | The number as a reader in this locale expects it: national inside the number’s own region, international outside it. The locale’s region decides, so a UK number shows as 01600 712345 under en-GB and +44 1600 712345 under plain en. |
telHref | tel: and the E.164 number, for a link. A variable in href must go through the url filter, which keeps tel:. |
e164 | +441295123456. |
national, international | The two written forms. |
region | The number’s region. |
type | fixed_line, mobile, toll_free and so on. |
valid | Whether the number is valid. A number that cannot be parsed shows what was typed in display and has an empty telHref. |
{% if entry.phone %}<a href="{{ entry.phone.telHref|url }}">{{ entry.phone.display }}</a>{% endif %} opening_hours
When a place is open: a regular week, seasons that replace it between two dates each year, exceptions for single days, behaviour on public holidays, a note per locale and a by-appointment flag. The structure is held once for every locale; only the notes are per locale, inside the value.
fields:
- name: openingHours
type: opening_hours
holiday_calendar: uk-england-wales
timezone: Europe/London
max_periods: 2 | Parameter | Type | Default | What it does |
|---|---|---|---|
holiday_calendar | calendar key | none | The public holiday calendar offered by default; a value may choose another. Built in: uk-england-wales, uk-scotland, uk-northern-ireland. |
timezone | IANA zone | the site’s, then the locale’s | The zone offered by default. |
max_periods | whole number | 3 | How many periods per day the editor offers. |
The editor takes one row per weekday with a closed switch and the periods as shorthand (12:00-15:00, 18:00-23:00; a close at or before the open runs into the next day), seasons and exceptions as rows, the holiday calendar and behaviour, and this locale’s note.
Stored value:
{
"timezone": "Europe/London",
"regular": [
{ "day": "mon", "periods": [{ "open": "09:30", "close": "16:30" }] },
{ "day": "sun", "closed": true }
],
"seasons": [
{ "from": "11-01", "to": "02-28", "regular": [{ "day": "sat", "periods": [{ "open": "10:00", "close": "14:00" }] }] }
],
"exceptions": [
{ "date": "2026-12-24", "periods": [{ "open": "09:30", "close": "12:00" }], "note": "Christmas Eve" }
],
"holiday_calendar": "uk-england-wales",
"holiday_behaviour": "closed",
"notes": { "en-GB": "Tours at 11:00 and 14:00; booking essential." },
"by_appointment": false
} | Key | What it is |
|---|---|
timezone | Required. The zone the times are in. |
regular | The week: each day mon to sun at most once, closed or periods of { open, close } in HH:MM. A period whose close is at or before its open runs past midnight. |
seasons | Weeks that replace regular between from and to, each MM-DD and inclusive; a season may wrap the year end. |
exceptions | Single dates, YYYY-MM-DD, either closed or with periods (not both), with an optional note. |
holiday_calendar | A calendar key, as above. |
holiday_behaviour | closed, normal, or hours with holiday_periods. |
notes | A note per locale code. |
by_appointment | Open by appointment. |
On save the value is normalised (Monday first, empty days dropped, exceptions sorted by date), so two edits that mean the same store the same bytes. Each problem is reported at its path with code opening_hours: timezone: a time zone is required, seasons[0].from: must be MM-DD, exceptions[1]: closed and periods cannot both be set, regular[2].day: mon appears twice, holiday_behaviour: must be closed, normal or hours, holiday_calendar: unknown holiday calendar.
With index: true the field projects one boolean, whether any hours are set, which is what a “places with no opening hours” list reads.
Template value. Methods take a time; pass the now global for the current moment.
| Property or method | What it is |
|---|---|
isOpenAt(t) | Whether the place is open at t. |
closesAt(t) | When the current period ends, or nothing. |
nextOpenAt(t) | When it next opens, or nothing. |
nextChange(t) | When it next opens or closes, or nothing. |
todayLabel(t) | The day’s hours in words for the request locale. |
week(t) | The seven days from the locale’s first day of the week (Monday under en-GB, Sunday under plain en), each with date, weekday, label, isToday, closed, periods (each open, close, spansMidnight), periodsLabel, note and source (regular, season, exception or holiday). |
jsonld(t) | The schema.org openingHoursSpecification entries. |
note | This locale’s note, else one in the same language. |
notes | Every note by locale. |
timezone, calendar, byAppointment, isEmpty | As stored. |
{% set hours = entry.openingHours %}
{% if hours and not hours.isEmpty %}
<p>{% if hours.isOpenAt(now) %}{{ t('hours.open_now') }}{% else %}{{ t('hours.closed_now') }}{% endif %}</p>
<table>
<caption>{{ t('hours.caption') }}</caption>
<thead><tr><th scope="col">{{ t('hours.day') }}</th><th scope="col">{{ t('hours.times') }}</th></tr></thead>
<tbody>
{% for day in hours.week(now) %}
<tr{% if day.isToday %} aria-current="date"{% endif %}><th scope="row">{{ day.label }}</th><td>{{ day.periodsLabel }}</td></tr>
{% endfor %}
</tbody>
</table>
{% if hours.note %}<p>{{ hours.note }}</p>{% endif %}
{% endif %} Places
The geo field (a point), the geo_shape field (an area boundary as GeoJSON) and the address field (a country-aware postal address), with parameters, validation, stored shapes and template values.
Asset
The asset field (one or several media library files: images, documents, audio or library videos) with kinds, file and image constraints, per-use alt text, captions and framing, the stored shape and the image value templates receive.