Relations
The relation field: references from a document to other documents, tags, smart lists, assets, organisations or people, with targets, cardinality, tag filters, publish checks, stored shape, and how templates receive resolved entries.
A relation field points at other records by id: a walk’s nearby places, an article’s related articles, a listing’s category tag, a page’s featured list. A relation to a document becomes that document’s entry in templates, in the visitor’s locale, and a target that is not live is left out, so a page never links to nothing.
Use a relation when the template needs the target’s fields (its title, image, address). Use a link when the editor is making a link with its own text.
fields:
- name: nearbyListings
type: relation
to: [listing]
multiple: true
max: 12
index: true
- { name: relatedArticles, type: relation, to: [article, page], multiple: true, max: 3 }
- name: theme
type: relation
to: tag
filter: { kind: topic, depth: 1 }
- { name: featuredList, type: relation, to: smart_list } These four fields, on a walk type, give this model. Each line is one relation field, read from the type that declares it; a multiple field points at many targets, a single one at one or none:
erDiagram
walk }o--o{ listing : "nearbyListings (max 12)"
walk }o--o{ article : "relatedArticles (max 3)"
walk }o--o{ page : "relatedArticles (max 3)"
walk }o--o| tag : "theme (topic, depth 1)"
walk }o--o| smart_list : "featuredList"
listing }o--|| tag : "primaryTag (core, depth 2)"Relations point one way: a listing does not gain a field when a walk names it. To find the walks that name a listing, query by the relation (below).
Parameters
| Parameter | Type | Default | What it does |
|---|---|---|---|
to | a key or a list of keys | required | What may be chosen: document type keys (listing, article, a custom type), tag, smart_list, asset, and in engine-dmo organisation and person. |
multiple | boolean | false | An ordered list of targets. |
min | whole number | none | The fewest targets, when the field is not empty. Use required for “at least one”. |
max | whole number | none | The most targets. |
filter | mapping | none | For to: tag: { kind, depth } limits the picker to tags of a kind and an exact depth in the vocabulary (depth 1 is a top-level tag). Other targets accept filter but do not apply it. |
engine-dmo check does not check that the keys in to name real types: a misspelt type key gives a field whose picker offers nothing. Check the field in the admin, or with engine-dmo describe type <key>.
What the editor picks from
| Target | The picker offers |
|---|---|
| Document types | Documents of those types on the site, in the editing locale, through the reference picker. |
tag | The tag vocabulary as a tree, narrowed by filter. |
smart_list | The public document lists of the site. |
asset, organisation, person | No picker: a plain input that takes the record’s id as type:id. Prefer an asset field for media. |
Validation
| Code | Message |
|---|---|
multiple | Choose one |
max_choices | Choose 12 or fewer |
min_choices | Choose at least 2 |
relation_type | Must be one of listing |
At publish:
| Code | Severity | When |
|---|---|---|
tag | error | A tag relation names a candidate tag or an unknown key: a candidate must be promoted into the vocabulary before it is published. |
relation_unpublished | warning | A target is not published in this locale or its fallbacks; visitors will not see it. |
relation_fallback | warning | A target is not published in this locale but is in a fallback locale, which visitors see. |
relation_missing | warning | A target is in the trash or no longer exists. |
Stored value
{ "id": "5b0c9d7e-...", "type": "listing" } With multiple, a list of these in the editor’s order. type is the target’s type key, or tag, smart_list, asset, organisation or person. A tag and a smart list are named by their key ({ "id": "eat-drink.brewery", "type": "tag" }). When to names a single target, type may be left out of an imported or seeded value.
In a seed file, a document is named by its seed key and type, { id: hook-norton-brewery-tours, type: listing } (Seeding and importing).
Every relation to a document is recorded as a reference, whether or not the field is indexed, which is how the engine knows what points at a document. With index: true, the targets are also projected (documents by id, tags and smart lists by key), so lists and query() can filter by them.
Template value
A relation to a document becomes the target’s entry: its fields, title, uri, url and the rest, as the target’s own page would see it. uri is the target’s path on this site with the locale prefix, and url the same address made absolute; link with uri|url, and keep url for addresses that must be absolute (a feed, an email). Both are empty when the target has no route on the site (Links and URLs).
- The entry is the target in the request locale, else in the first locale of the fallback chain where it is published on the site.
- A target that is not live anywhere in the chain, is trashed, or is not on the site is dropped. A single relation becomes nothing; a multiple relation becomes a shorter list.
- The target’s own relations resolve when a template reads them, so
entry.nearbyListings[0].primaryTagworks without loading every relation of every target up front. - Targets that are not documents (
tag,smart_list,asset,organisation,person) arrive as references withidandtype.
{% if entry.nearbyListings %}
<h2>Nearby</h2>
<ul>
{% for place in entry.nearbyListings %}
<li><a href="{{ place.uri|url }}">{{ place.title }}</a>, {{ place.summary }}</li>
{% endfor %}
</ul>
{% endif %} To list the documents that point at this one, filter by the relation with query(), which needs index: true on the field:
{% for w in query('walk').where('nearbyListings', entry.id).limit(5).all() %}
<a href="{{ w.uri|url }}">{{ w.title }}</a>
{% endfor %} See Globals for query() and nearby().
Relations the engine adds
- Guides. The core
guidetype’sitemsis a repeater whosedocumentrelation may point at any type that has a route on some site. - Collections. The core
collectiontype’ssmartListis a relation to a public smart list. - Nesting. A type routed with nesting carries a
parentrelation to its own type (Sites, locales and routes); templates readentry.ancestorsandentry.children. - engine-dmo. A listing’s
primaryTagis a relation to a topic tag at depth 2 (filter: { kind: topic, depth: 2 }), and listings belong to an organisation through the CRM, not a relation field (Partners and the portal).
Validation
When a document is checked (save and publish), required fields and required_in, visible_when and required_when, the expression language, cross-field validation rules with severity and timing, and the publish checks.
Blocks and rich text
Repeaters (a list of items with the same fields), blocks (a flexible page body of typed blocks, each with its own template), shared blocks, and Portable Text rich text with styles, lists, marks, link annotations and object blocks, and how each renders.