Filters
Every filter a Meridian template can use, grouped (text, locale-aware formatting of numbers, dates and money, rich text, URLs and encoding, lists, and the Pongo2 built-ins), with its argument, default, output and example.
A filter transforms the value to its left: {{ value|filter }}, or with its one argument {{ value|filter:arg }}. Filters chain left to right. This page lists every filter a site’s templates can use, in both bundles; engine-dmo template api prints the same list from the engine itself.
{{ entry.title|upper }}
{{ entry.summary|truncate:120 }}
{{ entry.publishedAt|date:"long" }}
{{ entry.description|plain|excerpt:160 }}
{{ listing.website|url }} Two things hold for every filter:
- The output is escaped unless the filter says it returns markup. A filter that returns markup returns one of the engine’s safe values, which prints as it is.
- Locale-aware filters read the request locale. You never pass a locale: the same template prints
14 September 2026on an English page and2026年9月14日on a Japanese one, with the locale’s numerals, calendar and hour cycle, and times in the site’s time zone unless the value carries its own.
A filter that does not recognise its input (a date filter given text that is not a date, say) returns the input unchanged.
Dates and times
| Filter | Argument | Output |
|---|---|---|
date | A style or skeleton; medium by default | The date in the locale’s words and order |
datetime | "<date style> <time style>"; "medium short" by default, or "relative" | The date and time joined as the locale joins them |
time | short (default) or medium (with seconds) | The time of day in the locale’s hour cycle |
iso | none | RFC 3339 with the value’s own offset, the same in every locale, for a datetime attribute |
relative | none | Relative to now: in 3 days, yesterday, 2 hours ago |
daterange | An end date, or a style (short, medium, long, full) | Two dates with their shared parts collapsed: 2–3 Nov 2026, 14 Aug – 2 Nov 2026 |
duration | long (default), short or narrow | A length of time in words: 2 hours, 30 minutes |
date styles are short, medium, long and full; the skeletons yMd, yMMMd, yMMMMd, yMMMEd, yMMMMEEEEd, Md, MMMd, MMMMd, MMMEd, yMMM, yMMMM, y and Ed; relative; and zone, which prints the IANA name of the zone the value is shown in. Each renders in the locale’s own order. An unknown style renders as medium.
{{ a.publishedAt|date }} {# 14 Aug 2026 #}
{{ a.publishedAt|date:"short" }} {# 14/08/2026 #}
{{ a.publishedAt|date:"full" }} {# Friday, 14 August 2026 #}
{{ a.publishedAt|date:"yMMMM" }} {# August 2026 #}
{{ a.publishedAt|date:"MMMEd" }} {# Fri 14 Aug #}
{{ a.publishedAt|datetime:"long short" }} {# 14 August 2026 at 10:00 #}
{{ a.publishedAt|time }} {# 10:00 #}
<time datetime="{{ a.publishedAt|iso }}">{{ a.publishedAt|date:"long" }}</time>
{{ event.startsAt|relative }} {# in 3 days #}
{{ today|daterange:tomorrow }} {# 2–3 Nov 2026 #}
{{ "PT2H30M"|duration }} {# 2 hours, 30 minutes #}
{{ 5400|duration:"short" }} {# 1 hr, 30 mins #} The date filters accept a date or datetime field’s value, now, today, tomorrow, yesterday, the engine’s dates (entry.publishedAt), and text in RFC 3339 or YYYY-MM-DD form. A wall-clock time that carries its own zone (an event in Paris on a London site) keeps it; any other instant is shown in the site’s time zone.
daterange takes either a start with the end as the argument (start|daterange:end), or one value holding both: a list of two dates, or a map with start and end, from and to, startsAt and endsAt, or local and localEnd.
duration reads an ISO 8601 duration (PT2H30M, days allowed), a Go duration (2h30m) or a number of seconds.
A Go reference layout (|date:"2 Jan 2006") still renders, the same way in every locale, and engine-dmo check warns about it (date-layout) with the named format to use instead.
Numbers and money
| Filter | Argument | Output |
|---|---|---|
number | Fixed decimal places; without it, up to three as needed | The locale’s grouping, decimal separator and digits: 1,234.5, 1 234,5, ١٬٢٣٤٫٥ |
currency | An ISO 4217 code | An amount in that currency for the locale, with the currency’s own minor units: £12.50, JP¥1,500 |
money | none | A money value, which carries its own currency, formatted as currency |
percentage | Most decimal places; 0 by default | A fraction as a percentage: 0.125 is 13% |
ordinal | none | An ordinal by the locale’s rules: 3rd, 3., 第3 |
unit | "<unit> <width>", width short (default), long or narrow | A quantity of a unit: 12.3 kilometres |
distance | none | Metres in the viewer’s measurement system: 7.5 mi in en-GB and en-US, 12,1 km in de |
filesize | none | Bytes as a size in decimal units: 1.6 MB |
list | and (default), or, unit, unit-narrow, and-short | A list joined as the locale writes it: A, B and C, A, B or C |
{{ 1234.567|number }} {# 1,234.567 in en-GB, 1.234,567 in de #}
{{ walk.lengthKm|number:1 }} km {# 12.3 km #}
{{ 12.5|currency:"GBP" }} {# £12.50 #}
{{ listing.fee|money }}
{{ 0.1234|percentage:2 }} {# 12.34% #}
{{ 22|ordinal }} {# 22nd #}
{{ 20|unit:"celsius long" }} {# 20 degrees Celsius #}
{{ walk.metres|distance }} {# 4.7 mi #}
{{ asset.bytes|filesize }} {# 1.6 MB #}
{{ ["Banbury", "Bicester"]|list:"or" }} {# Banbury or Bicester #} currency accepts a number, a decimal written as text, or a money value; with no code and no currency in the value it returns the input unchanged. The units unit knows are year, month, week, day, hour, minute, second, millisecond, kilometer, meter, centimeter, millimeter, mile, yard, foot, inch, hectare, acre, kilogram, gram, pound, ounce, liter, milliliter, celsius, fahrenheit, kilometer-per-hour, mile-per-hour, byte, kilobyte, megabyte, gigabyte, terabyte and percent.
Text
| Filter | Argument | Output |
|---|---|---|
upper, lower | none | Upper or lower case by the locale’s rules (Turkish i upper-cases to İ) |
title | none | Title case by the locale’s rules |
capfirst, ucfirst | none | The first character upper-cased by the locale’s rules |
ucwords | none | The first letter of each word upper-cased |
camel, pascal, kebab, snake | none | openingHours, OpeningHours, opening-hours, opening_hours. Words split on anything that is not a letter or digit and on a change from lower to upper case |
truncate | Length in grapheme clusters; 80 by default | Cut to that length with an ellipsis, only when longer |
words | Number of words | The first n words, with an ellipsis when cut |
excerpt | Length in grapheme clusters; 160 by default | Plain text, markup and Markdown removed, whitespace collapsed, cut at a word with an ellipsis |
trim | none | Leading and trailing whitespace removed |
length | none | A string’s length in grapheme clusters (what a reader counts as characters), or a list’s or map’s length |
wordcount | none | The number of words |
striptags | none | HTML tags removed, entities decoded (the result is escaped again when printed) |
replace | "from=>to", or a map of replacements | Every occurrence replaced. Any other argument is an error |
mask | Characters to keep; 4 by default | All but the last n characters as bullets: ••••••7890 |
ascii | none | Accents folded, anything with no ASCII form dropped: Café Ætna becomes Cafe tna |
transliterate | A language code | Each word romanised, with the language’s rules: Straße becomes Strasse with de |
slugify | mixed (default), transliterate or native | A URL slug: cafe-strasse; native keeps scripts such as 東京-tower |
contains, startsWith, endsWith | The text to look for | true or false |
nl2br | none | Newlines as <br>, the text escaped. Returns markup |
widont | none | The last two words joined with a no-break space, the text escaped. Returns markup |
markdown | none | A safe subset of Markdown as HTML. Returns markup |
stripMarkdown | none | Markdown as plain text |
{{ entry.title|truncate:40 }}
{{ entry.summary|excerpt:155 }}
<h2>{{ entry.title|widont }}</h2>
{{ entry.notes|nl2br }}
{{ entry.title|replace:"&=>and" }}
{{ entry.reference|mask:4 }} markdown renders ATX headings, paragraphs and hard breaks, emphasis and strong, inline code and fenced code blocks, block quotes, bullet and numbered lists one level deep, and links whose scheme url accepts. Every character of the input is escaped first, raw HTML stays text, and a link to javascript: keeps its text and loses its link.
There is no translation filter: interface text comes from t(), which knows the request locale (see Functions).
Rich text
| Filter | Argument | Output |
|---|---|---|
ptext | A serialiser set; default by default | A portable_text value as HTML. Headings get id anchors from their text (getting-here, then getting-here-2). Object blocks render through ptext/<set>/<block key>.html. Returns markup |
plain | none | Portable Text or Markdown as plain text |
toc | none | A <nav> of nested lists linking to the rich text’s headings, the same ids ptext gives them; empty when there are none. Returns markup |
<nav>{{ entry.body|toc }}</nav>
{{ entry.body|ptext }}
{{ entry.body|ptext:"compact" }}
<meta name="description" content="{{ entry.body|plain|excerpt:155 }}"> ptext renders every span escaped. An object block with no serialiser template renders nothing on a public page. A serialiser template receives the block as node, its position as index, and the page’s globals; naming a set that has no templates at all is an error. See Rich text serialisers.
URLs, JSON and attributes
| Filter | Argument | Output |
|---|---|---|
url | none | The URL when its scheme is safe (relative, #, ?, http, https, mailto, tel, sms, otpauth), otherwise #. A protocol-relative //host becomes #. Escaped for an attribute. Required on a variable in href, src and the other URL attributes |
json | none | The value as JSON with <, >, & and the JavaScript line separators escaped, safe inside a <script> element. Required on a variable inside <script> |
attr | none | A map as escaped HTML attributes: true prints the bare name, false and nothing leave it out, a list is joined with spaces |
urlencode | none | Percent-encoded for a query string (spaces as +) |
iriencode | none | An IRI encoded for use in a URL |
escapejs | none | Escaped for a JavaScript string. Prefer json |
icsUrl | none | An event entry’s .ics address when its route has a calendar, otherwise empty |
<a href="{{ listing.website|url }}">{{ t('listing.website') }}</a>
<script>window.page = {{ entry.title|json }};</script>
<a href="{{ entry|icsUrl }}">{{ t('event.add_to_calendar') }}</a> json fails the render on a value that holds helper functions, such as a geo value or a document from a list; print its plain parts instead ({{ entry.location.lat|json }}). The page’s own entry, tags, addresses, strings and numbers encode.
A template has no map literal, so attr is for a map that comes from the context, such as part of settings.
Escaping
| Filter | Output |
|---|---|
escape | The value escaped for HTML. Escaping is automatic; this is for an explicit call |
raw | Prints an engine-produced safe value as it is. On anything else it is an error: raw requires a Safe value |
safe, safeseq, e, escapeseq and json_script are not available. See Autoescaping.
Lists and values
| Filter | Argument | Output |
|---|---|---|
default | A fallback | The argument when the value is empty, zero or false |
default_if_none | A fallback | The argument only when the value is nothing |
first, last | none | The first or last item of a list, or character of a string |
join | A separator | A list joined with it |
split | A separator | A string split into a list |
slice | "start:end", either side optional, negative from the end | A slice of a list or string |
make_list | none | A string as a list of characters |
length_is | A number | Whether the length equals it |
random | none | A random item of a list |
add | A number, string or list | Adds to a number, appends to a string or list |
divisibleby | A number | Whether the value divides by it |
yesno | "yes,no,maybe" | One of the words for true, false and nothing |
pluralize | "suffix" or "singular,plural"; s by default | The plural suffix by count. Prefer t(id, count), which follows the locale’s plural rules |
integer, float | none | The value as an integer or a float |
floatformat | Decimal places; negative to drop trailing zeros | A float rounded. Prefer number for display |
stringformat | A Go format verb, such as "%05d" | The value formatted with it |
get_digit | A position from the right | That digit |
Pongo2 text built-ins
These come from Pongo2 and are available unchanged. They do not know the locale.
| Filter | Argument | Output |
|---|---|---|
addslashes | none | Quotes escaped with backslashes |
center, ljust, rjust | A width | Padded with spaces to the width |
cut | Text | Every occurrence removed |
truncatechars | A length | Cut to that many characters, with an ellipsis |
truncatewords | A number | Cut to that many words, with ... |
wordwrap | A width in words | Wrapped onto new lines |
linenumbers | none | Each line numbered |
phone2numeric | none | Letters on a phone keypad as digits |
linebreaks, linebreaksbr, urlize, urlizetrunc, removetags | These produce HTML, which is then escaped and prints as visible tags. Use nl2br and markdown instead | |
truncatechars_html, truncatewords_html | A length | Cut HTML and close its tags. They print their input as markup without escaping it, so never apply them to content; use truncate, words or excerpt |
Development only
dump prints a value as a navigable tree. It is not registered when engine.environment is production, so a stray |dump fails to compile there rather than leaking data.
Not available
timesince, timeuntil, filesizeformat, dictsort, dictsortreversed and unordered_list are removed: use relative, filesize, orderBy() in a query, and a loop or {% nav %}. A filter that does not exist is a compile error naming it: Filter 'frobnicate' does not exist.
Querying content
How a template fetches published documents with query() (where, tag, near, orderBy, limit, offset, exclude, organisation, onePer, with, and the terminal methods), nearby(), children(), ancestors(), smartList() and search(), with every rule, limit and error.
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.