Functions
Every function a Meridian template can call (links and URLs, interface strings and locale helpers, content queries, head and structured data, feeds, forms and security, analytics, assets and images, embeds, sigmx, upstream sources, and the DMO functions) with arguments, keywords, return values and examples.
Functions are globals called with parentheses: {{ path('/places') }}. Some take keyword arguments (name=value, see Keyword arguments); engine-dmo check refuses a keyword a function does not take, and any keyword to a function that takes none. A function that returns markup returns a safe value that prints as it is.
This page is the complete list. Field values have functions of their own (an image’s picture(), a link’s link(), opening hours’ isOpenAt()), listed per field type by engine-dmo describe fieldtypes.
Summary
| Function | Returns |
|---|---|
path(), url(), siteUrl() | A path or URL on this or another site |
localeUrl(), localeSwitcher() | The current page in another locale; a language switcher |
t(), plural(), dir(), bidi() | Interface strings and locale helpers |
query(), nearby(), children(), ancestors(), smartList(), search() | Content |
head(), jsonld() | The head metadata and structured data |
feedUrl(), feedLinks(), calendarUrl() | Feeds and calendars |
searchForm() | The search form |
csrfToken(), csrfInput() | The form token |
enquiryForm(), subscribeForm() | A declared endpoint’s form |
track(), reveal(), impressions(), analytics() | Measured links and the analytics script |
assets.*, preload(), images.file() | Static files, bundles and images |
embed() | A privacy-preserving embed |
sigmx.fragment() | Attributes for in-place updates |
source() | An upstream data source |
aiDisclosure() | The AI-assistance disclosure |
dump() | A debugging view (development only) |
promoted(), promotionLabel(), memberTier(), hasAffiliateLinks() | DMO bundle only |
Links
path
path('/literal') a path on this site, with the request locale's prefix
path('type') the type's index page in the request locale
path('type', entry) the entry's path (any document value)
path() the home page in the request locale
path(..., locale='code') the same in another locale
path(locale='code') the current page in that locale <a href="{{ path('/') }}">{{ site.name }}</a>
<a href="{{ path('listing') }}">{{ t('nav.places') }}</a>
<a href="{{ path('/about', locale='ja-JP') }}">日本語</a> path('listing') gives the index’s segment in each locale (/places, /ja/spots), so a template links to an index without knowing it. A literal path is prefixed and not translated: path('/places', locale='ja-JP') is /ja/places. locale= returns empty for a locale the site does not enable. With no locale=, an argument that is neither a path nor a type with an index is returned unchanged. Keywords: locale.
url
url(...) takes what path() takes and returns an absolute URL on the origin the visitor is on, port included, so a page served on localhost:8080 links to localhost:8080. The canonical URL and structured data use the site’s configured domain instead. Keywords: locale.
<link rel="alternate" hreflang="ja-jp" href="{{ url(locale='ja-JP') }}"> siteUrl
siteUrl(path or type, site=, locale=) is an absolute URL on a site of the project, on that site’s configured domain. The argument is a path starting with / (prefixed for the locale) or a type key (the type’s index page there). site= is the other site’s key, this site when not given; locale= the locale to link to where that site enables it, its default locale otherwise. When the request came in on a port and the other site lists its domain without one, the link keeps the port.
<a href="{{ siteUrl('/events', site='towns') }}">{{ t('nav.events') }}</a>
<a href="{{ siteUrl('event', site='towns', locale=locale.code) }}">{{ t('nav.events') }}</a> localeUrl
localeUrl('cy-GB') is the current page’s path in another locale, or empty where the page has no translation published on this site. A page with no alternates of its own (the search page, an endpoint’s response) exists in every locale at the same path.
localeSwitcher
localeSwitcher() prints a <nav> listing the locales the current page exists in, the current one marked with aria-current="page", each link with hreflang and lang. It is labelled from the string nav.language when the catalogue has it, and prints nothing when the page exists in one locale only.
<nav class="mrd-locales" aria-label="Language"><ul><li><span aria-current="page" lang="en-GB">English</span></li><li><a href="/ja/access" hreflang="ja-jp" lang="ja-JP">日本語</a></li></ul></nav> Interface strings and locale
t
Every piece of interface text a template prints comes from the string catalogue, config/strings/<locale>.yaml, so a template carries no literal English and a new locale is a file:
strings:
nav.places: Places
index.count:
one: "{count} place"
other: "{count} places"
pager.page_of: "Page {page} of {pages}" {{ t('nav.places') }}
{{ t('index.count', pagination.total) }}
{{ t('pager.page_of', 'page', pagination.page, 'pages', pagination.pages) }} | Call | Result |
|---|---|
t(id) | The string in the request locale |
t(id, count) | When the second argument is a number: the plural form for it by the locale’s CLDR rules (zero, one, two, few, many, other), with {count} filled |
t(id, name, value, ...) | {name} filled with each value. After a count, the pairs follow it |
The lookup walks the request locale, its fallback chain and the source locale. An id defined nowhere prints as the id itself, and engine-dmo check warns at the line (unknown-string). t() takes no keyword arguments.
plural
plural(n) is the CLDR plural category of n in the request locale (one, few, other and so on), for the rare branch t(id, n) cannot express.
dir
dir() is the request locale’s direction, ltr or rtl, the same as locale.direction.
bidi
bidi(text) wraps text in <bdi>, so a name in another script does not disturb the order of the text around it. Returns markup.
Content
These are described in full on Querying content:
| Function | Returns |
|---|---|
query('type') | A query over one type: .where(), .tag(), .near(), .orderBy(), .limit(), .offset(), .exclude(), .organisation(), .onePer(), .with(), then .all(), .first(), .count(), .exists() or .ids() |
nearby(entry, km, type) | Up to 12 documents near the entry, nearest first |
children(doc), ancestors(doc) | A nesting document’s children (title order) or ancestors (root first) |
smartList('key') | A public smart list: .limit(n), .all(), .first(), .count() |
search(q) | The search service: .types(), .tags(), .near(), .sort(), .facets(), then .paginate(n) or .limit(n) |
Head and structured data
head
head() prints the page’s <title>, meta description, canonical link, hreflang alternates with x-default, the robots directive, Open Graph and Twitter card tags, and rel=prev and rel=next on a paged page, all from what the page context already holds. Print it once, in <head>. See SEO and structured data.
jsonld
jsonld() prints the page’s structured data as one JSON-LD @graph, cross-referenced by @id, built from the types’ structured_data mappings and the site’s settings; jsonld(entry) prints one document’s entity alone. See SEO and structured data.
<head>
<meta charset="utf-8">
{{ head() }}
{{ jsonld() }}
</head> Feeds and calendars
feedUrl
feedUrl(type, format=) is the path of a type’s feed in the request locale, empty when its route has none. format= is rss (the default), atom or json.
feedLinks
feedLinks() prints a <link rel="alternate"> for each of the site’s feeds in the request locale; feedLinks(type) for one type’s. Put it in <head>.
calendarUrl
calendarUrl(type) is the path of a type’s calendar feed in the request locale, empty when its route has none. For one event’s .ics, use the icsUrl filter: {{ entry|icsUrl }}.
Feeds and calendars are declared on a route; see the routes reference.
Forms and security
searchForm
searchForm() prints a GET form to the site’s search route that works without JavaScript, with a labelled search input named q. It prints nothing when the site routes no search.
<form class="mrd-search" role="search" method="get" action="/search"><label for="mrd-q">What are you looking for?</label> <input id="mrd-q" type="search" name="q" value="" autocomplete="off"> <button type="submit">Search</button></form> csrfToken and csrfInput
csrfToken() is the token a form posting back to the engine must carry, the same value the csrf global prints. csrfInput() prints the hidden input that carries it. For an anonymous visitor both print nothing and set no cookie, since an anonymous post is checked by its origin; for a signed-in visitor they print a token bound to the session, and such a page is not stored in the page cache. A {% cache %} block that names either is an error. Under engine-dmo render both are always empty. See The CSRF token.
enquiryForm and subscribeForm
enquiryForm('endpoint') describes a declared endpoint’s form: its action, its inputs with labels, rules and errors, and its hidden fields. Printed as it is, {{ enquiryForm('contact') }}, it draws the complete accessible form. It has no render() method (only a form field’s value has one), and an unknown key prints nothing; engine-dmo check reports neither. subscribeForm('endpoint') does the same for a subscription endpoint. Both come from the forms module, in both bundles. See Forms.
Measured links and analytics
track
track(entry, kind, url) returns a tracked outbound URL (/r/v1/...) that records the click against the document, then redirects to the destination. kind is one of website, booking, phone, email, directions, social, event, download or share (anything else counts as website). url is a string, a link value or a phone value. An empty destination returns empty. On a staff preview it returns the destination itself. In an href, put it through |url as any variable there must be.
<a href="{{ track(entry, 'website', entry.website)|url }}" rel="noopener">{{ t('listing.website') }}</a> reveal
reveal(entry, kind, value) is track() for a contact detail: with phone the value becomes a tel: link, with email a mailto: link, and the returned tracked URL records the interaction before handing over to it. It works without JavaScript.
<a href="{{ reveal(entry, 'phone', entry.phone)|url }}">{{ entry.phone.display }}</a> impressions
impressions() prints the script that reports which cards marked data-mrd-impression a visitor actually saw (in the viewport for half a second, once per session per page). With no JavaScript nothing is recorded.
analytics
analytics() prints the cookieless analytics client that records impressions and in-page interactions. Print it once, before </body>. See Analytics.
Assets and images
assets and preload
assets.url(path), assets.css(bundle) and assets.js(bundle, module) print files and bundles from public/ (see Globals). preload(bundle, ...) prints the preload hints of the named bundles (main when none is named) from the build manifest, and nothing without a build integration or under the dev server. See The frontend build.
images.file
images.file('img/team.jpg') turns a file under public/ into an image value, with the same img(), picture() and figure() a media asset has, through the same image pipeline. A path with no image under public/ fails the render. See Images.
{{ images.file('img/team.jpg').img('card') }} embed
embed(url, title=) prints a third party’s player, map or post as a facade: a notice, a button that loads it, and a plain link to it. Nothing loads from the provider until the visitor presses the button. title= names what is embedded, for the button and the announcement; the provider’s name when not given. YouTube embeds use the privacy domain.
{{ embed('https://www.youtube.com/watch?v=dQw4w9WgXcQ', title='A walk along the canal') }} sigmx.fragment
sigmx.fragment(names, on=, debounce=, history=, focus=) prints the attributes that make a form or link ask the server for the named fragments of the page and swap them in place, the address bar following:
| Keyword | Value |
|---|---|
on | The event that asks: change (the default), input, submit, or click on a link |
debounce | Wait this long after the last event, such as '300ms' |
history | push (the default), replace or none |
focus | new: move focus to the first item an append added |
<form method="get" action="{{ path('listing') }}" {{ sigmx.fragment('results', on='input', debounce='300ms') }}> Every name must be a fragment some template on the site declares with {% fragment %}; engine-dmo check refuses one that none does. See Forms for fragments and in-place updates.
source
source('name') reads an upstream declared in sources.yaml, cached and behind its circuit breaker. It is empty when the source is not declared or cannot answer, so a template must handle the empty case. See Integrating.
aiDisclosure
aiDisclosure(entry) prints the disclosure sentence when the entry carries AI-assisted text that the site’s policy discloses (entry.aiAssisted), and nothing otherwise. The sentence is the catalogue’s ai.disclosure string in the request locale, or the engine’s English sentence when the catalogue has none.
{% if entry.aiAssisted %}<p class="disclosure">{{ aiDisclosure(entry) }}</p>{% endif %} dump
Development only. dump(value) prints a value as a navigable tree, and dump() the whole context. It is not registered when engine.environment is production, so a stray call fails to compile there.
DMO functions
engine-dmo
engine-cms a template that uses one fails the check with the name of the module it belongs to.promoted and promotionLabel
promoted('slot') is the documents of a promotion slot’s live promotions, oldest start first, each an entry with promotion (id, slot, label, startsAt, endsAt) and organisationId. For a slot sold per landing page, promoted('slot', landing) names the page; on a landing page promoted('slot') reads it. promotionLabel(item) prints the site’s promotion label as visible text, to put inside each placement’s link. A slot must be declared in the site’s promotions.yaml, and a template that renders promoted() without printing promotionLabel() fails the check (promoted-unlabelled).
{% set items = promoted('home-feature') %}
{% if items %}<ul class="cards">
{% for item in items %}<li data-mrd-promotion="{{ item.promotion.id }}"><a href="{{ item.uri|url }}">{{ promotionLabel(item) }} {{ item.title }}</a></li>{% endfor %}
</ul>{% endif %} See Promotions.
memberTier
memberTier(entry) is the tier key of the active membership the entry’s organisation holds on the page’s site, or empty when it holds none or the document has no organisation. See Memberships.
hasAffiliateLinks
hasAffiliateLinks(value) is whether a value (an entry, its relations included) holds a link through an affiliate programme, so the page can print the disclosure:
{% if hasAffiliateLinks(entry) %}<p class="affiliate-disclosure">{{ t('affiliate.disclosure') }}</p>{% endif %} See Affiliates.
Tags
Every tag a Meridian template can use (Pongo2's control flow, inheritance and include tags, and the engine's blocks, nav, component, slot, fragment, cache, announce, focus, patch, location and requireMember tags) with syntax, options and errors.
Components
How to write, call and override a template component with a declared contract of props, slots and attributes that engine-dmo check enforces at every call site.