Modifiers
A modifier is the most flexible of the three template extension points. The same modifier works three ways:
{$title|upper} {* as a filter *}
{upper($title)} {* as a function *}
{set $t = $title|upper} {* in an expression *}That is what separates it from a pseudo-tag, which only works in the first position of a tag and never inside an expression. The rule is simple: need a value — write a modifier; need a chunk of HTML — write a pseudo-tag.
🛠 Your own modifiers
core/App/Helpers/fenom/modifiers.phpThe file returns a name → function map:
return [
'upper' => function ($value) {
return mb_strtoupper((string) $value);
},
'excerpt' => function ($text, int $length = 100) {
return mb_substr(strip_tags((string) $text), 0, $length);
},
];<h2>{$title|upper}</h2>
<p>{$content|excerpt:200}</p>Arguments after the first are passed with colons: {$x|mod:$a:$b}.
$this->modx is available
The file is included from inside View, so closures in it see $this — meaning $this->modx is the current MODX instance. The global modx() helper works too.
Your file is read after the built-in modifiers, so a modifier with the same name overrides the built-in one. A component upgrade never touches this file.
🔧 Built-in modifiers
Text
| Modifier | Signature | What it does |
|---|---|---|
trim | ($input, $chars = " \n\r\t\v\0") | trims both ends |
truncate | ($input, ['length' => 160, 'suffix' => '...']) | strips tags, cuts on a word boundary |
ellipsis | ($input, $length = 100) | same, but keeps HTML and repairs unclosed tags |
notags | ($string, $allowable_tags = null) | strip_tags() |
uppercase | ($input) | aliases: upper, up, strtoupper |
lowercase | ($input) | aliases: lower, low, strtolower |
preg_replace | ($value, $pattern, $replacement = '', $limit = -1) | value first, not the pattern |
split | ($input, $delimiter = ',') | string → array |
join | ($input, $glue = ',') | array or iterator → string |
decl | ($number, $forms, $showNumber = false, $sep = '|') | plural forms for Slavic languages |
date | ($value, $format = 'j F Y, H:i', $locale = null) | $locale = 'ru' gives Russian month and day names |
default | ($input, $fallback) | replaces null, '', [] and false |
phone | ($value) | keeps digits and + |
parseNumber | ($text) | first number in the string |
editorjs | ($json, $options = '') | renders Editor.js blocks |
print | ($input, $wrap = true) | print_r() inside <pre> — for debugging |
Links, settings, translations
| Modifier | Signature | What it does |
|---|---|---|
route | ($name, $parameters = []) | route URL by name, with the language prefix |
lang_url | ($uri = '') | prepends the current language prefix to a URL |
url | ($id, $context = '', $args = '', $scheme = -1, $options = []) | modX::makeUrl() by resource id |
lang | ($key, $params = [], $language = '') | a string from App/lang/ |
lexicon | ($key, $params = [], $language = '') | a MODX lexicon entry |
config | ($key, $default = null) | Config first, then the MODX system setting |
placeholder | ($key) | a MODX placeholder |
Objects and lists
| Modifier | Signature | Returns |
|---|---|---|
resource | ($id, $field = '') | one field, or the whole site_content row |
user | ($id, $field = 'username') | a user field merged with the profile; 'photo' falls back to a Gravatar, and passwords and sessions are stripped |
resources | ($ids = null, $options = []) | a flat list of resources |
pbresources | ($ids = null, $options = []) | the same from pb_resources; alias pbResources |
users | ($ids = null, $options = []) | a list of users |
menu | ($rootId = 0, $level = 3) | a menu tree |
blocks | ($where = []) | published blocks in their own order |
resources, pbresources and users accept ids as a '12,7,3' string, an array or a number — and then preserve the order of the ids. An associative array as the first argument is read as options: parent, template, context, where, sortby, sortdir, limit, offset. See Helpers.
Nested rendering
| Modifier | Signature | What it does |
|---|---|---|
render | ($template, $params = []) | renders a string as a template (@INLINE) |
chunk | ($template, $data = []) | a MODX chunk; understands file: and path: |
snippet | ($name, $params = []) | a MODX snippet; !name skips the cache, file:name runs a file |
pbJson | ($data, $options = '') | serialisation through the pbJson snippet |
Images
| Modifier | Signature |
|---|---|
glide | ($url, $options = 'fm=webp&q=85') |
pthumb | ($url, $options = []) |
phpthumbon | ($url, $options = []) |
JSON and arrays
| Modifier | Signature |
|---|---|
toJSON | ($array, $options = 320, $depth = 512) |
fromJSON | ($string, $assoc = true, $depth = 512, $options = 0) |
slice | ($array, $start = 0, $length = null) |
Assets
cssToHead($css, $media = null), jsToHead($js, $plaintext = false), jsToBottom($js, $plaintext = false), htmlToHead($html), htmlToBottom($html) wrap the MODX regClient* methods. They return nothing and are called for the side effect.
Access
| Modifier | Signature |
|---|---|
isloggedin | ($ctx = null) — current context by default |
isnotloggedin | ($ctx = null) |
ismember | ($id, $groups = [], $matchAll = false) — empty $id means the current user |
In markup the same checks read better as block tags: {auth}, {guest}, {admin}.
Miscellaneous
button(array $button) builds an <a> or a <button> from an array with the keys published, type, caption, classes, href, file, attr, disabled, target_blank, name, value. Without published it returns nothing.