Skip to content

Псевдо-теги

Псевдо-тег — функция, которая вызывается как тег шаблона и возвращает готовый кусок HTML:

fenom
{icon 'edit' class='icon-sm'}

Удобно для повторяющихся фрагментов — иконок, кнопок, бэйджей, — которые не хочется заводить отдельным чанком.

Скобок нет, и в выражение тег не встаёт

Это тег, а не функция, и синтаксис у него теговый: параметры через пробел, без скобок и запятых. Всё остальное — ошибка компиляции Function icon not found, то есть белая страница и 500:

fenom
{icon 'edit' class='icon-sm'}     {* так *}
{icon('edit')}                    {* 500 *}
{set $i = icon('edit')}           {* 500 *}
{if icon('edit')}                 {* 500 *}

Нужно значение в переменной или в условии — заводите модификатор: он работает и фильтром, и функцией, и внутри выражения.

📁 Где объявлять

core/App/Helpers/fenom/inline_tags.php

Файл возвращает массив «имя → функция». Первым аргументом приходит массив параметров: безымянные лежат под числовыми ключами, именованные — под своими.

php
return [
    'icon' => function ($params) {
        // {icon 'edit' class='icon-sm'} → ['edit', 'class' => 'icon-sm']
        $name = array_shift($params);

        $attrs = [];
        foreach ($params as $key => $value) {
            $attrs[] = htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"';
        }
        $attrStr = $attrs ? ' ' . implode(' ', $attrs) : '';

        $path = MODX_BASE_PATH . "assets/icons/{$name}.svg";
        if (!file_exists($path)) {
            return "<!-- icon '{$name}' not found -->";
        }

        $svg = file_get_contents($path);
        return preg_replace('/<svg\b(.*?)>/', '<svg$1' . $attrStr . '>', $svg, 1);
    },
];
fenom
{icon 'edit' class='icon-sm text-muted'}
{icon 'user' class='icon-lg' aria-hidden='true'}

Как и у модификаторов, внутри доступен $this->modx — файл подключается изнутри View.

🔧 Готовые псевдо-теги

Компонент регистрирует свои — их не нужно объявлять:

ТегЧто возвращает
{csrf}<input type="hidden" name="_token" …>
{csrf_token}только значение токена
{meta_csrf}<meta name="csrf-token" …> для fetch-запросов
{spam}скрытое поле-приманка honeypot
{recaptcha 'login'}поле reCAPTCHA v3 с действием и публичным ключом
{route 'home'}адрес зарегистрированного маршрута
{lang 'auth.title'}строка перевода
{pb_filters table='Products'}готовая форма фильтров таблицы
{heroicon $block.icon style='solid'}инлайновая Heroicon
{pbList parent=$id tpl='item' limit=10}листер ресурсов с AJAX-пагинацией

route и lang есть и модификаторами — там они умеют больше (подстановки, язык) и работают в выражениях: {$item.uri|lang_url}, {route('order', ['id' => $id])}.

Контракт колбэка

pbFenom сохраняет исторический контракт addFunction(): колбэк получает ($params, $tpl, $var), где $params — разобранный массив параметров тега. Именно так подключаются inline_tags.php.

Если хочется, чтобы API тега задавала сама сигнатура функции, регистрируйте её через addFunctionSmart(). Готового файла-хука под это нет: View::init() кладёт экземпляр движка в modx()->fenom, оттуда его и берут — например из плагина на OnLoadWebDocument или из сниппета:

php
modx()->fenom->addFunctionSmart('excerpt', function (string $text, int $length = 100) {
    return mb_substr(strip_tags($text), 0, $length);
});
fenom
{excerpt text=$page.introtext length=200}

В форке addFunctionSmart() принимает любой callable — замыкание, массив-колбэк, объект с __invoke; в upstream работали только строки. Пропущенный обязательный аргумент сообщается на компиляции («Function excerpt requires the 'text' argument»), а не взрывается посреди рендера.

© PageBlocks 2019-present