Шаблонизатор Fenom в MODX: полное практическое руководство

Fenom Дополнения

Fenom — это мощный, быстрый и гибкий шаблонизатор для MODX, который заменяет стандартные теги [[...]] на более удобный синтаксис с фигурными скобками {...}. Он интегрируется через компонент pdoTools, ускоряет разработку до 30–50%, позволяет писать циклы, условия и модификаторы прямо в шаблонах, сокращая количество чанков и запросов к БД. Ниже разберём всё от установки до продвинутых возможностей: синтаксис, модификаторы, работу с TV и пользователями, примеры для реальных проектов и типичные ошибки.

Что такое Fenom и зачем он нужен в MODX

Fenom — это standalone-шаблонизатор на PHP, похожий на Twig/Smarty, но легче и быстрее. В MODX он появился в 2015 году с pdoTools 2.0 и стал стандартом для сложных шаблонов.

Преимущества Fenom в MODX:

  • Скорость: компилирует шаблоны в PHP-код, кэширует их. На больших сайтах ускорение до 30–50%.
  • Удобство: циклы {foreach}, условия {if}, модификаторы | modifier вместо громоздких сниппетов.
  • Массивы и объекты: прямой доступ к $_modx->resource, $_modx->config без [[*...]].
  • Безопасность: экранирование по умолчанию, защита от инъекций.
  • Совместимость: работает с 90% существующих чанков (pdoTools парсит MODX-теги внутри Fenom).

Минусы:

  • Требует установки дополнения pdoTools.
  • Фигурные скобки конфликтуют с JS/JSON (решается {*комментарии*} или modParser).
  • Непривычно для новичков.

Важно: Fenom появился в MODX с pdoTools 2.0 в 2015 году и полностью совместим с MODX Revolution 3.x через pdoTools 3.x.

Когда использовать Fenom:

  • Сложные шаблоны (списки товаров, блоги, формы).
  • Проекты на pdoTools (pdoResources, pdoMenu, pdoPage).
  • Когда нужно меньше чанков и быстрее рендер.

Установка и настройка Fenom

Fenom работает только с pdoTools (версия 3.x+ для MODX 3).

Шаг 1: Установка pdoTools

  • Перейдите в Управление пакетами → найдите pdoTools → Установить.
  • Автоматически установятся Fenom и связанные сниппеты.

Шаг 2: Системные настройки (путь: Система → Настройки → pdoTools)

Вот ключевые опции (префикс pdotools_):

Настройка Значение Описание
pdotools_fenom_default Yes Fenom для чанков pdoTools (включено по умолчанию).
pdotools_fenom_parser Yes/No Fenom для всех страниц/шаблонов сайта (рекомендуем Yes для новых проектов).
pdotools_fenom_php No PHP-функции в шаблонах (опасно, только для dev).
pdotools_fenom_modx No Доступ к {$_modx}, {$pdoTools} (опасно).
pdotools_fenom_options {"auto_escape":true} JSON опции Fenom (экранирование, include).
pdotools_fenom_cache Yes Кэш скомпилированных шаблонов (для продакшена).
parser_class pdoParser Только для продвинутых: переключает весь MODX на pdoParser. Нужен только если включена pdotools_fenom_parser

Важные уточнения по настройкам:

  • pdotools_fenom_default — работает только для чанков, вызываемых через pdoTools (pdoResources, pdoMenu, pdoPage и т.п.). Безопасно включать на любых проектах.
  • pdotools_fenom_parser — включает Fenom для всех страниц сайта (контент ресурсов, шаблоны). Требует осторожности на существующих проектах.
  • pdotools_fenom_php и pdotools_fenom_modxопасные настройки! Дают доступ к PHP-функциям и полному объекту $modx прямо из чанков. Включайте только на dev-окружении и для доверенных администраторов.
  • parser_class — менять на pdoParser нужно только если хотите использовать Fenom на всём сайте вместе с pdotools_fenom_parser. Иначе оставьте стандартный modParser.

Рекомендуемые настройки для новых проектов:

  • pdotools_fenom_default: Yes
  • pdotools_fenom_parser: Yes (для использования Fenom везде)
  • pdotools_fenom_cache: Yes (для продакшена)
  • pdotools_fenom_php: No (безопасность)
  • pdotools_fenom_modx: No (безопасность)
  • pdotools_fenom_options: {"auto_escape":true,"force_include":true}
  • parser_class: pdoParser (если включили pdotools_fenom_parser)

Для существующих проектов: включайте только pdotools_fenom_default и не меняйте parser_class — это позволит использовать Fenom в новых чанках pdoTools без риска поломать старую разметку.

После изменений: Очистить кеш (Система → Очистить кеш).

Шаг 3: Проверка

Создайте чанк testFenom:
{$_modx->resource.pagetitle | upper} (ID: {$_modx->resource.id})

Вызовите: [[!pdoResources? &tpl=`testFenom`]].

Если работает — Fenom активен.

Базовый синтаксис Fenom

Fenom использует синтаксис {...} вместо классических тегов MODX [[...]]. Доступ к данным MODX реализован через специальные переменные $_modx (объект modX), $_pls (плейсхолдеры с точками/дефисами) и обычные переменные для простых плейсхолдеров.

Таблица-шпаргалка: сравнение синтаксиса MODX и Fenom

Назначение Классический MODX Fenom
Поле ресурса [[*pagetitle]] {$_modx->resource.pagetitle} или {$_modx->resource['pagetitle']}
Плейсхолдер [[+placeholder]] {$placeholder} или {$_pls['placeholder']} (для имён с точками или тире)
Чанк [[$header]] {$_modx->getChunk('header')} или {include 'header'} или {'header' | chunk}
Системная настройка [[++site_name]] {$_modx->config.site_name} или {'site_name' | config}
Ссылка на ресурс [[~15]] {$_modx->makeUrl(15)} или {15 | url}
Лексикон [[%lexicon_key]] {$_modx->lexicon('lexicon_key')}
Вызов сниппета [[snippetName? &param=`value`]] {$_modx->runSnippet('snippetName', ['param' => 'value'])} или {'snippetName' | snippet : ['param' => 'value']}
Переменная шаблона (TV) [[*tvname]] {$_modx->resource.tvname} или {$_modx->resource['tvname']}
Модификатор вывода [[*field:modifier=`param`]] {$field | modifier : 'param'} (модификатор должен быть зарегистрирован как сниппет)
Условный оператор [[If? &subject=`[[*field]]` &operator=`eq` &operand=`value` &then=`...`]] {if $resource.field == 'value'} ... {else} ... {/if}
Цикл [[pdoResources? &parents=`0` &tpl=`rowTpl`]] (через сниппет) {foreach $_modx->getResources(['parents' => 0]) as $res} {$res.pagetitle} {/foreach}
Поле пользователя [[+modx.user.id]] (после вызова сниппета вроде Login) {$_modx->user.id} или {$_modx->user['fullname']}
Поле ресурса по ID (FastField) [[#15.pagetitle]] {var $res = $_modx->getResource(15)} {$res.pagetitle}
Присвоение переменной [[setPlaceholder? &name=`var` &value=`value`]] (через сниппет) {var $var = 'value'} или {var $date = 'dateAgo' | snippet : ['input' => '2023-01-01']}
Доступ к глобальным массивам [[getServerInfo? &key=`REQUEST_URI`]] (через сниппет) {$$ .server.REQUEST_URI} или { $$.get.query}

Практические примеры использования

Доступ к полям ресурса

Поля текущего ресурса доступны через объект $_modx->resource. Можно использовать как свойства или массив для имен с спецсимволами.

<h1>{$_modx->resource.pagetitle}</h1> 
<div class="content">{$_modx->resource.content}</div> 
<div class="intro">{$_modx->resource['introtext']}</div> 
{* Доступ как к массиву *} 
<p>Дата публикации: {$_modx->resource.publishedon | date : 'd.m.Y'}</p>

Работа с TV-параметрами и специальными плейсхолдерами

TV-параметры доступны через массив $_modx->resource:

{* Обычный TV-параметр *}
<div class="price">{$_modx->resource.price}</div>

{* TV-параметр с точками или дефисами в имени *}
{set $specialTV = $_modx->resource['tv-name-with-dashes']}
<div>{$specialTV}</div>

Для работы с плейсхолдерами, установленными через сниппеты, используйте переменную {$_pls}:

{* Установка плейсхолдера в сниппете *}
{set $_pls['page.title'] = 'Новое название'}

{* Вывод плейсхолдера *}
<h2>{$_pls['page.title']}</h2>

Примеры использования плейсхолдеров и выражений

<!-- Плейсхолдер из сниппета --> {$pagetitle}
<!-- TV текущего ресурса --> {$_modx->resource.my_tv}
<!-- С конкатенацией строк --> "Страница: " ~ $_modx->resource.pagetitle
<!-- Тернарный оператор для значения по умолчанию --> {$image ?: '/no-photo.jpg'}
<!-- Сложный тернарный с условием --> {$price > 1000 ? 'Дорогой' : 'Доступный'} товар
<!-- Арифметические операции --> {$quantity * $price | number : 2}
<!-- Доступ к массиву --> {$user['email']}

Важно: переменная $_pls нужна для доступа к плейсхолдерам с точками или дефисами в именах, так как Fenom компилирует переменные в PHP, который не поддерживает такие символы. Для обычных имён используйте просто {$variable}.

Условия {if}

Условные конструкции позволяют динамически отображать контент на основе проверок. Поддерживаются логические операторы, сравнения и вложенные условия.

{* Простое условие *}
{if $id == 1} Главная {elseif $id > 10} Блог {else} Другое {/if}
{* Логические операторы (AND, OR, NOT) *}
{if $user.id > 0 && $_modx->hasPermission('save')} Редактировать {/if}
{if $isAdmin || $isModerator} Админ-панель {/if}
{if !$isEmpty} Содержимое {/if}
{* Сравнение строк и чисел *}
{if $status == 'active'} Активен {else} Неактивен {/if}
{if $count <= 5} Мало элементов {elseif $count <= 20} Средне {else} Много {/if}
{* Вложенные условия *}
{if $user.id} {if $user.group == 'admin'} Полный доступ {else} Ограниченный доступ {/if} {else} Гость {/if}

Switch/case

Альтернатива множественным if-elseif для проверки одного значения на несколько вариантов. Поддерживает default для случаев по умолчанию.

{switch $type}
    {case 'news'} Новости {/case}
    {case 'blog'} Блог {/case}
    {case 'shop'} Магазин {/case}
    {default} Другое {/default}
{/switch}
{* С несколькими case на один блок *}
{switch $code}
 {case 200} {case 201} Успех {/case}
 {case 404} Не найдено {/case}
 {default} Ошибка {/default}
{/switch}

Циклы {foreach}

Циклы позволяют итерировать по массивам или объектам. Поддерживаются ключи, индексы, else для пустых коллекций и break/continue.

{* Простой цикл по массиву *}
{foreach $products as $product}
  <div>{$product.name} — {$product.price | number : 2} руб.</div>
{/foreach}
{* С индексом и ключом *} 
{foreach $items as $key => $item}
 {$key + 1}: {$item.title} (ID: {$item.id}) 
{/foreach} 
{* Обработка пустого массива *} 
{foreach $comments as $comment}
 <p>{$comment.text}</p>
 {foreachelse} Нет комментариев 
{/foreach} 
{* С break и continue *} 
{foreach $numbers as $num}
 {if $num % 2 == 0} {continue} {/if} {* Пропустить четные *}
 {$num}
 {if $num > 10} {break} {/if} {* Прервать после 10 *} {/foreach} 
{* Вложенный цикл *} 
{foreach $categories as $cat}
 <h3>{$cat.name}</h3>
 {foreach $cat.products as $prod} - {$prod.name} {/foreach} 
{/foreach}

Комментарии и экранирование

Комментарии не рендерятся в выводе. Экранирование предотвращает выполнение тегов MODX внутри Fenom.

{* Это однострочный комментарий, не рендерится *} 
{* Многострочный комментарий. Можно описывать логику. *} 
<!-- Экранирование тегов MODX/JS --> 
{* [[!pdoResources]] *} {* Не выполнится как сниппет *} 
{* <script>alert('test');</script> *} {* Не выполнится как JS *} 
{* Игнорирование блока для стилей/скриптов *} 
{ignore} <style> .header { color: red; } </style> {/ignore}

Работа с пользователями

Объект $_modx->user предоставляет доступ к данным авторизованного пользователя, включая профиль и разрешения.

{* Проверка авторизации пользователя *} 
{if $_modx->user.id}
 <div>Добро пожаловать, {$_modx->user.fullname}!</div>
 <p>Email: {$_modx->user.email}</p>
 {if $_modx->user.photo} <img src="{$_modx->user.photo}" alt="Фото"> {/if}
 {if $_modx->hasPermission('edit_document')} <a href="edit">Редактировать</a> {/if}
 {else} <div>Пожалуйста, авторизуйтесь</div> <a href="{ $$.php.url}?service=login">Войти</a> 
{/if}

Использование системных настроек

Системные настройки доступны через $_modx->config или модификатор | config.

<title>{$_modx->config.site_name} {if $_modx->resource.pagetitle?}- {$_modx->resource.pagetitle}{/if}</title> 
<meta name="description" content="{$_modx->config.site_description}"> 
<link rel="stylesheet" href="{$_modx->config.assets_url}css/style.css"> 
<p>Валюта: {'currency' | config}</p>

Модификаторы Fenom в MODX

Fenom поддерживает встроенные модификаторы (унаследованные от Smarty), а также интеграцию с MODX output modifiers через pdoTools . Модификаторы применяются к переменным с помощью символа |, например: {$var | modifier : 'param'} . Параметры передаются через двоеточие.

Важно: не все модификаторы встроены в Fenom «из коробки». Некоторые реализованы как сниппеты MODX и требуют регистрации через параметр &fenomModifiers в вызове pdoTools-сниппетов. Ниже приведена таблица с основными модификаторами.

Модификатор Описание Пример в Fenom
upper, ucase, uppercase, strtoupper Преобразует строку в верхний регистр. {$text | upper} → «HELLO WORLD»
lower, lcase, lowercase, strtolower Преобразует строку в нижний регистр. {$text | lower} → «hello world»
truncate Обрезает строку до указанной длины, добавляя суффикс (по умолчанию «…»). Параметры: длина, суффикс. {$long_text | truncate : 10 : '...'} → «Long tex…»
ucwords Делает первую букву каждого слова заглавной. {$title | ucwords} → «Hello World»
ucfirst Делает первую букву строки заглавной. {$name | ucfirst} → «Hello»
escape, esc Экранирует специальные символы (HTML, JS и т.д.). Параметры: ‘html’, ‘url’, ‘quotes’ и др. {$html | escape : 'html'} → «<div>»
strip_tags, striptags, stripTags, notags Удаляет HTML-теги. Можно указать разрешенные теги. {$html | strip_tags : '<p><a>'} → текст без тегов, кроме p и a
replace Заменяет подстроку на другую. Параметры: ‘from==to’. {$text | replace : 'old==new'} → замена «old» на «new»
date Форматирует Unix-временную метку в дату (использует strftime). {$timestamp | date : '%Y-%m-%d'} → «2023-01-01»
nl2br Преобразует новые строки (\n) в теги <br>. {$text | nl2br} → текст с <br> вместо \n
ellipsis Обрезает строку и добавляет многоточие, если длина превышает указанную (по умолчанию 100). {$description | ellipsis : 50} → «Short desc…»
limit Ограничивает строку указанным количеством символов (по умолчанию 100). {$text | limit : 20} → первые 20 символов
urlencode Кодирует строку для URL. {$query | urlencode} → «hello%20world»
urldecode Декодирует URL-кодированную строку. {$encoded | urldecode} → «hello world»
strtotime Преобразует строку даты в Unix-временную метку. {$date_str | strtotime} → 1672531200
ago Выводит время «назад» (секунды, минуты, часы и т.д.). {$timestamp | ago} → «2 часа назад»
md5 Генерирует MD5-хеш строки. {$password | md5}
number, number_format Форматирует число с разделителями (по умолчанию: 0 десятичных, запятая для тысяч, точка для десятичных). {$price | number : 2 : ',' : '.'} → «1.234,56»
cat, append, after Добавляет строку в конец (если обе не пустые). {$num | cat : ' books'} → «5 books»
prepend, before Добавляет строку в начало (если обе не пустые). {$num | prepend : 'Book #'} → «Book #5»
default, ifempty, empty, isempty Возвращает значение по умолчанию, если переменная пустая. {$name | default : 'anonymous'} → «anonymous» если $name пусто
contains Проверяет, содержит ли строка подстроку, и выводит «then» или «else». {$text | contains : 'word' : 'Yes' : 'No'} → «Yes» если содержит «word»
eq, is, equals (и аналоги: ne, gt, lt и т.д.) Условные сравнения (равно, не равно, больше, меньше). Используется с then/else. {$num | eq : 5 : 'Five' : 'Not five'} → «Five» если $num == 5
memberof, ismember Проверяет, является ли пользователь членом группы. {$_modx->user.id | memberof : 'Administrator'} → true если в группе
userinfo Возвращает поле пользователя по ID. {$_modx->user.id | userinfo : 'username'} → имя пользователя
print Выводит экранированную переменную (дополнительный в некоторых пакетах). {$var | print} → экранированный вывод
config Доступ к системной настройке MODX. {'site_name' | config} → значение настройки site_name
resource Доступ к полю ресурса по ID. {15 | resource : 'pagetitle'} → заголовок ресурса с ID 15
url Генерирует URL ресурса по ID. {15 | url} → «/page-url»
snippet Вызывает сниппет с параметрами. {'snippetName' | snippet : ['param' => 'value']}
chunk Вставляет чанк. {'header' | chunk}

Встроенные (работают без настройки):

  • Работа со строками: upper, lower, trim, truncate, ucwords, ucfirst, strip_tags, replace, nl2br, split, join
  • Форматирование: escape, urlencode, urldecode, base64_encode, base64_decode
  • Числа и хеши: number_format, md5, sha1, crc32
  • JSON: json_encode, json_decode
  • Массивы: count, join, split

Требуют регистрации через сниппеты MODX:

  • MODX-специфичные: config, resource, url, chunk, snippet, lexicon
  • Пользовательские: userinfo, memberof, isloggedin
  • Временные: ago, dateAgo (нужно указать &fenomModifiers=dateAgo« в pdoResources)
  • Кастомные модификаторы из ваших сниппетов

Пример регистрации модификатора-сниппета:

[[!pdoResources?
  &fenomModifiers=`dateAgo,myCustomModifier`
  &parents=`0`
  &tpl=`@INLINE {$pagetitle} ({$publishedon | dateAgo})`
]]

Примечания:

  • Модификаторы можно цепочкой комбинировать: {$text | lower | truncate : 50} .
  • В MODX любые сниппеты можно использовать как модификаторы через параметр &fenomModifiers в вызове pdoTools-сниппетов.
  • Для полного списка встроенных Smarty-подобных модификаторов смотрите официальную документацию Fenom.

Типичные ошибки и подводные камни

Конфликт фигурных скобок с JavaScript и JSON

Fenom использует {...} для своих тегов, что может конфликтовать с JS-кодом или JSON-данными.

Решения:

  1. Комментарии Fenom: оборачивайте JS/JSON в {* ... *} или {ignore} ... {/ignore}
  2. Выносите скрипты в отдельные файлы вместо inline-кода
  3. Используйте <script src="..."></script> для подключения JS

Пример:

{ignore}
<script>
  var config = {
    "key": "value",
    "array": [1, 2, 3]
  };
</script>
{/ignore}

Забыли очистить кеш после включения Fenom

После изменения настроек pdotools_fenom_* обязательно очищайте кеш MODX. Иначе старые версии чанков будут продолжать работать.

Путь: Система → Очистить кеш → Очистить кеш сайта.

Включили опасные настройки на продакшене

Никогда не включайте на боевом сайте:

  • pdotools_fenom_php (доступ к любым PHP-функциям из чанков)
  • pdotools_fenom_modx (доступ к полному объекту $modx, можно удалить весь сайт)

Эти настройки только для dev-окружения и доверенных администраторов.

Плейсхолдеры с точками и дефисами не работают

Если у вас TV или плейсхолдер с именем вроде my-tv или page.title, используйте $_pls:

{* Неправильно *}
{$my-tv}  {* Ошибка синтаксиса *}
{$page.title}  {* Ищет свойство объекта *}

{* Правильно *}
{$_pls['my-tv']}
{$_pls['page.title']}

Смешивание синтаксиса MODX и Fenom снижает производительность

Когда в одном чанке используются и [[...]] и {...}, запускаются оба парсера — сначала Fenom, потом modParser. Это замедляет работу.

Рекомендация: переводите чанки полностью на Fenom или полностью оставляйте на классических тегах MODX. Смешанный синтаксис используйте только для плавной миграции.

Заключение

Fenom — это современный, быстрый и удобный шаблонизатор для MODX Revolution 2.x и 3.x, который интегрируется через компонент pdoTools. Вы научились:

  • Устанавливать и настраивать Fenom через системные параметры pdoTools.
  • Использовать базовый синтаксис Fenom: переменные, условия {if}, циклы {foreach}, модификаторы |.
  • Работать с данными MODX через $_modx->resource, $_modx->user, $_modx->config.
  • Применять модификаторы для форматирования строк, дат, чисел и других данных.
  • Избегать типичных ошибок: конфликтов с JS, забытого кеша, опасных настроек.

Используя Fenom вместе с pdoTools (pdoResources, pdoMenu, pdoPage), вы можете полностью перевести проект на современный, быстрый и гибкий шаблонизатор, значительно упростить поддержку кода и ускорить рендер страниц до 30–50%.

Лучшие практики работы с Fenom:

  1. Не смешивайте классический синтаксис MODX [[...]] и Fenom {...} в одном чанке — это замедляет работу.
  2. Выносите повторяющиеся куски в отдельные чанки через {include 'chunkName'}.
  3. Регистрируйте кастомные модификаторы через параметр &fenomModifiers при вызове pdoTools-сниппетов.
  4. Используйте $_pls для плейсхолдеров с точками и дефисами в именах.
  5. Никогда не включайте pdotools_fenom_php и pdotools_fenom_modx на продакшене.
  6. Очищайте кеш после любых изменений настроек Fenom.

С этими знаниями вы готовы создавать сложные, производительные и легко поддерживаемые шаблоны для MODX.

Оцените статью
MODX 3
Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.