Шаблонизатор Fenom – это надстройка для MODX Revo, включённая в состав пакета pdoTools. Позволяет полностью заменить "родные" теги MODX с увеличением скорости и удобства работы с информацией из таблиц базы данных и значительно расширить возможности шаблонизации.
Для тех, кто начинал изучение MODX по официальной документации, поначалу работа с Fenom может показаться неудобной и более сложной, а, открыв первый раз сайт на Fenom, вообще не сообразить, что и как работает.
Это быстро проходит) и, возвращаясь при необходимости к стандартным тегам, начинает не хватать возможностей парсера pdoTools.
Включение Fenom
Для того, чтобы теги Fenom начали обрабатываться в шаблонах, чанках и тексте ресурса, нужно включить следующие настройки: Системные настройки - pdotools:
Шаблонизатор имеет такую особенность – если парсер не может обработать страницу, она может выйти пустой, либо с исходными тегами. Причина пишется в Журнале ошибок. Первоначально, нужно обратить внимание на инлайновые стили и скрипты Java, потому что парсер срабатывает на фигурные скобки {}
.
Для указания парсеру Fenom фрагментов, не подлежащих обработке, используются теги {ignore}фрагмент{/ignore}
. Помогает не всегда, это связано с особенностями работы парсера.
Часто бывает проще расставить пробелы или переносы строки после открывающей скобки и перед закрывающей.
Базовые понятия
Основные источники информации по работе с Fenom – в документации modx.pro и в исходной документации.
Желательно сразу освоить файловые элементы (официальное руководство).
Начнём с шаблонов. По умолчанию, путь к файлам core/elements
(папку elements нужно будет создать). Дальше, на усмотрение, кому как удобно.
Например, создадим папки templates, chunks и snippets (в директории elements, понятное дело). Пускай базовый шаблон будет main.html
(или с расширением tpl, неважно). Весь текст, соответственно, будет храниться в файле core/elements/templates/main.html
.
Для связи со структурой MODX нужно будет создать обычным способом шаблон, в поле Код шаблона которого записывается ссылка на файл в виде {include 'file:templates/main.html'}
.
Чанки и сниппеты в админ панели создавать не нужно. Файловый чанк прописывается в шаблоне через include – {include 'file:chunks/header.html'}
, или insert, запуск сниппета из файла – {'@FILE snippets/cache.php' | snippet}
.
В шаблонах и чанках нежелательно мешать теги Fenom со стандартными тегами, поскольку в этом случае запускается встроенный парсер MODX.
Как работает наследование и расширение шаблонов (чанков) в Minishop2 можно увидеть на примере чанков писем. Здесь 6 видов оповещений построены на 1 базовом шаблоне.
Аналоги тегов MODX
Поля текущего ресурса (теги со *): {$_modx->resource.id}
, {$_modx->resource.pagetitle}
, {$_modx->resource['description']}
, либо {$_modx->resource['имя_тв_поля']}
и т.д. (разные варианты обращения к элементам массива $_modx->resource).
Плейсхолдеры сниппета (теги с +): {$id}
, {$longtitle}
Системные настройки (теги с ++): {'site_url' | option}
или {$_modx->config['site_url']}
Ссылка на ресурс (теги с ~): {88 | url}
. Например, генерация абсолютной ссылки на документ с id = 88, [[++site_url]][[~88]]
= {'site_url' | option ~ (88 | url)}
или {'site_url' | option}{88 | url)}
(в Fenom символ ~ выполняет объединение строк)
Поля любого ресурса: {11 | resource : 'longtitle'}
Вызов сниппета: {'pdoSitemap' | snippet}
,
некешированный {'!pdoSitemap' | snippet}
,
с параметрами {'!pdoMenu' | snippet : ['parents' => 0, 'resources' => '-1,-6', 'showHidden' => 1]}
Поля любого пользователя по его id: {5 | user : 'fullname'}
Массив полей текущего пользователя $_modx->user
. Например, посмотреть все поля {$_modx->user | print}
Закомментировать теги Fenom можно так: {*'!pdoPage' | snippet*}
Разумеется, это не все возможности шаблонизатора, есть ещё масса модификаторов, полностью заменяющих "родные" теги MODX и расширяющие их функции.
Условия и циклы
Это как раз то, что меняет подход к построению страницы сайта. При всём уважении, условия в стандартном синтаксисе MODX, в особенности вложенные, напоминают фразу из "Собачьего сердца": "Кто на ком стоял??? Потрудитесь излагать Ваши мысли яснее."
Условия в Fenom задаются так же, как в большинстве языков программирования:
условие if:
{if $_modx->resource.parent == 1}
{$_modx->resource.pagetitle}
{elseif $_modx->resource.parent == 5}
{$_modx->resource.longtitle}
{else}
Другой текст заголовка
{/if}
использование логических И (&&), ИЛИ (||) и группировка условий (тут же пример присвоения значения переменной):
{var $u = 5}{var $e = 9}
{if $u > 2 || ($e >= 3 && $e < 100)}
Выполненное условие
{/if}
короткая запись if (тернарный оператор),
{$_modx->resource.longtitle ? $_modx->resource.longtitle : $_modx->resource.pagetitle}
или аналог стандартного default в случае пустого значения:
{$_modx->resource.introtext ?: 'аннотация не заполнена'}
условие switch:
{switch $_modx->resource.id}
{case 5}
Текст
{case 7,8}
Другой текст
{case default}
Пусто
{/switch}
Полноценный цикл foreach:
{var $array = [0 => 'val1', 1 => 'val2']}
{foreach $array as $key => $value}
key = {$key}, value = {$value}
{/foreach}
Пример вывода дочерних ресурсов без вызова сниппета
В Fenom переменная $_modx – обращение к классу microMODX, имеющему несколько очень полезных методов.
перенаправление на заданный url, либо ресурс (здесь, с id = 101) {$_modx->sendRedirect(101 | resource : 'uri')}
получение потомков документа (здесь, id документа 47, глубина вложенности 1). Поскольку возвращает массив, для наглядности показан с простым выводом на экран. {$_modx->getChildIds(47, 1) | print}
То же, для родителей документа $_modx->getParentIds()
Получение масивов полей ресурсов без сниппета и вывод без чанка:
{var $parents = $_modx->getResources(
['published' => 1, 'deleted' => 0, 'isfolder' => 1],
['sortby' => 'menuindex', 'select' => 'id,pagetitle'])}
{foreach $parents as $parent}
{var $childs = $_modx->getResources(
['published' => 1, 'deleted' => 0, 'parent' => $parent.id],
['select' => 'pagetitle', 'sortby' => 'menuindex'])}
{if $childs}
<div>
<h5>{$parent.pagetitle}</h5>
{foreach $childs as $child}
<div>
{$child.pagetitle}
</div>
{/foreach}
</div>
{/if}
{/foreach}
Этот пример показывает, как, пользуясь только средствами Fenom, вывести дочерние ресурсы, сгруппированные по родительскому документу.
Произвольная группировка товаров и порядок вывода категорий miniShop2 в корзине
Товары в корзине выводятся с помощью сниппета msCart, чанк вывода, по умолчанию, tpl.msCart. Добавленные в корзину покупки хранятся в переменной $_SESSION
в таком виде:
[minishop2] => Array
(
[cart] => Array
(
[19540dc928fb772d846a78d33c108a6e] => Array
(
[id] => 821
[price] => 150
[weight] => 0
[count] => 1
[options] => Array
(
)
[ctx] => web
)
[9537fcc265888919ea41499d68ce0317] => Array
(
[id] => 371
[price] => 400
[weight] => 0
[count] => 1
[options] => Array
(
[prs] => 400
[age] => 3-6
[month] => 400
)
[ctx] => web
)
[c158d4dca43e0a30c567c0b2f415d04e] => Array
(
[id] => 822
[price] => 400
[weight] => 0
[count] => 1
[options] => Array
(
)
[ctx] => web
)
)
Где ключ элемента массива с покупкой, например, такой [c158d4dca43e0a30c567c0b2f415d04e]
, формируется динамически при добавлении товара в корзину при помощи функции md5 следующим образом: $key = md5($id . $price . $weight . (json_encode($options)));
(исходник).
Соответственно, товары в корзине выводятся по очерёдности их добавления, без учёта id товара, либо его категории.
Стандартный чанк tpl.msCart сделан на Fenom, поэтому, можно, с минимальными изменениями, задать нужную группировку и порядок вывода категорий товаров.
Чанк принимает массив товаров $products
, поэтому в чанке, до цикла {foreach $products as $product}
(это 16 строка), раскидываем общий массив на несколько массивов категорий, например, cat_15
и cat_16
, где число – id категории.
{foreach $products as $product}
{if $product.parent == 15}
{set $cat_15[] = $product}
{elseif $product.parent == 16}
{set $cat_16[] = $product}
{else}
{set $other_products[] = $product}
{/if}
{/foreach}
И вывод товаров из категорий:
{if count($cat_15)}
{foreach $cat_15 as $product}
{*здесь вывод товара*}
{/foreach}
{/if}
{if count($cat_16)}
{foreach $cat_16 as $product}
{*аналогично стандартному выводу*}
{/foreach}
{/if}
{if count($other_products)}
{foreach $other_products as $product}
{*внутри цикла foreach (строки 17...69)*}
{/foreach}
{/if}
Таким образом можно не только определить последовательность вывода категорий товаров, но и задать общий заголовок и футер товаров одной категории и использовать разное оформление.