Meridian handbook
Content modellingFields

Text and slug

The text field (single or multi-line, length limits, pattern, email format) and the slug field (a per-locale URL segment generated from another field), with parameters, validation and template values.

text

A plain string: a title, a strapline, a reference number, an email address. Translated per locale by default. For formatted prose use portable_text.

fields:
  - { name: title, type: text, required: true, index: true }
  - { name: strapline, type: text, max: 120 }
  - { name: intro, type: text, multiline: true, min: 40, max: 400 }
  - name: reference
    type: text
    pattern: "^[A-Z]{2}[0-9]{4}$"
    unique: true
    help: "Two letters then four digits, such as BX1234."
  - { name: bookingEmail, type: text, format: email }

Parameters

ParameterTypeDefaultWhat it does
multilinebooleanfalseA text area in the editor instead of a single line. The value keeps its line breaks.
maxwhole numbernoneThe most characters, counted as grapheme clusters (what a reader sees as one character, so an emoji or an accented letter counts once).
minwhole numbernoneThe fewest characters, when the field is not empty.
patternregular expressionnoneThe value must match. The expression is Go’s RE2 syntax and is not anchored: write ^ and $ to match the whole value. Checked only when the field is not empty.
formatemail or urlnoneemail requires an @. url is accepted but not checked; use a link field for addresses.

Validation

CodeMessageWhen
max_lengthMust be N characters or fewerlonger than max
min_lengthMust be at least N charactersshorter than min, and not empty
patternDoes not match the required formatpattern does not match
formatMust be an email addressformat: email and no @

Each is an error, so it blocks the save as well as the publish. required, unique and the other common keys are on Fields.

Stored value and template value

The value is a JSON string. A template receives the string, escaped when printed:

<h1>{{ entry.title }}</h1>
{% if entry.intro %}<p>{{ entry.intro|linebreaksbr }}</p>{% endif %}
{% if entry.bookingEmail %}<a href="mailto:{{ entry.bookingEmail }}">{{ entry.bookingEmail }}</a>{% endif %}

Useful filters: |truncate:n, |excerpt:n, |linebreaksbr, |upper, |lower, |length (Filters).

Changing type

A text field reads an old slug or select value exactly, and an old portable_text value lossily as plain text, which is how a schema plan judges a retype (Schema changes).

slug

A URL segment, one per locale, which a route places in the address with {slug}. The admin generates it from a source field using the locale’s slug mode from config/locales.yaml (transliterated or native script), and an editor may change it by hand.

fields:
  - { name: title, type: text, required: true }
  - { name: slug, type: slug, source: title, max: 60, required: true }

Parameters

ParameterTypeDefaultWhat it does
sourcefield namenoneThe field the slug is generated from in the editor.
maxwhole numbernoneThe most characters, counted as grapheme clusters.

Validation

CodeMessageWhen
slugUse lowercase letters, numbers and single hyphensnot a canonical slug
max_lengthMust be N characters or fewerlonger than max

A valid slug is lowercase where the script has case, in Unicode NFC, made of letters, marks and digits of any script joined by single hyphens. So old-town-hall and hook-norton-jouzousho-tour are valid, as is a slug in a non-Latin script that follows the same rules; Old Town, old--town and -old are not.

The reserved value __home__ is valid as the whole slug and makes the document the site’s home page, on a site whose routes.yaml does not name a home: (Sites, locales and routes).

The core types all have a required, indexed slug with source: title. A slug field cannot be site_overridable: it builds the document’s address on every site.

Stored value and template value

A JSON string per locale. A template receives the string. To link to a document, use its uri or url rather than building an address from the slug (Links).