MODX. Шаблонизатор Fenom. Что это и как им пользоваться

Fenom — удобный шаблонизатор, поставляющийся вместе с пакетом pdoTools. Позволяет заменить родные теги MODX, при этом увеличивая скорость обработки кода.

Достоинства

Работает быстрее чем родной парсер MODX — modParser;

Недостатки

Конфликтует с фигурными скобками в контенте. Надо учитывать это при проектировании архитектуры сайта, чтобы не гадать в последствии «почему новая статья ломает сайт?».

Системные настройки

  • pdotools_fenom_default — включает обработку через Fenom чанков pdoTools. Включено по умолчанию.
  • pdotools_fenom_parser — включает обработку шаблонизатором всех страниц сайта. То есть, не только чанков, но и шаблонов.
  • pdotools_fenom_php — включает поддержку PHP функций в шаблонизаторе. Очень опасная функция, так как любой менеджер получит доступ к PHP прямо из чанка.
  • pdotools_fenom_modx — добавляет системные переменные {$modx} и {$pdoTools} в шаблоны Fenom. Тоже очень опасно — любой менеджер может управлять объектами MODX из чанков.
  • pdotools_fenom_options — JSON строка с массивом настроек согласно официальной документации. Например: {"auto_escape":true,"force_include":true}
  • pdotools_fenom_cache — кэширование скопмилированных шаблонов. Имеет смысл только для сложных чанков на рабочих сайтах, по умолчанию отключено.
  • pdotools_fenom_save_on_errors — сохраняет ошибки компиляции Fenom в специальный файл, для последующей отладки.

Синтаксис

Комментарии для шаблонизатора Fenom:

  • {ignore}{/ignore}
  • {**}

Далеко не всегда теги-комментарии помогают запретить обработку фигурных скобок, поэтому для надежности, в случае применения фигурных скобок на сайте, ставьте после них пробел. Тоже самое касается ситуаций когда скрипты яндекс метрики, гугл аналитики и подобные ломают сайт на котором применен fenom. Подробнее о том почему не всегда работает тег ignore можно узнать на сайте Сергея Шлокова, если вкратце, то дело в последовательности подготовки ответа пользователю. Когда 1 часть шаблона прогружается раньше другой, и другая уже не видит нужного тега.

Символ конкатенации (присоединение строк):

  • ~

Экранирование:

  • \

Теги MODX

Простой вызов

MODX Fenom
[[+id]] {$id}
[[+id:default=`test`]] {$id ?: 'test'}
[[+id:is=``:then=`test`:else=`[[+pagetitle]]`]] {$id == ''? 'test': $pagetitle}

{$_modx} — безопасный доступ к переменным и методам системы (обращение к классу microMODX)

[[*id]] {$_modx->resource.id}
[[*tv_param]] {$_modx->resource.tv_param} или {$_modx->resource['tv_param']
[[%lexicon]] {$_modx->lexicon('lexicon')}
[[~15]] {$_modx->makeUrl(15)}
[[~[[*id]]]] {$_modx->makeUrl($_modx->resource.id)}
[[++system_setting]] {$_modx->config.system_setting}

{$_modx->config} — системные настройки

{$_modx->config.site_name}
{$_modx->config.emailsender}
{$_modx->config['site_url']}
{$_modx->config['any_system_setting']}

{$_modx->user} — массив текущего пользователя. Если он авторизован, то добавляются и данные из профиля:

{if $_modx->user.id > 0}
    Привет, {$_modx->user.fullname}!
{else}
    Вам нужно авторизоваться.
{/if}
{$_modx->context} — массив с текущим контекстом
Вы находитесь в контексте {$_modx->context.key}
{$_modx->resource} — массив с текущим ресурсом
{$_modx->resource.id}
{$_modx->resource.pagetitle}
{$_modx->makeUrl($_modx->resource.id)}
{$_modx->lexicon} — объект (не массив!) modLexicon, который можно использовать для загрузки произвольных словарей:
{$_modx->lexicon->load('ms2gallery:default')}
Проверка словарей ms2Gallery: {$_modx->lexicon('ms2gallery_err_gallery_exists')}

{$_modx->lexicon()}  вывод записей из lexicon

Особенности плейсхолдеров

В отличие от стандартных тегов MODX, феном обрабатывает код за один проход. Такой подход повышает скорость работы, но заставляет учитывать тот факт, что плейсхолдеры будут доступны только после отработки соответствующей части кода, их создающей. Т.е. при использовании тегов MODX заполненные плейсхолдеры доступны даже если тег вызова снипета указан ниже, при использовании fenom, тег плейсхолдера должен быть ниже вызова снипета.

Обычные плейсхолдеры можно вывести так:

{$pagetitle}

{$_pls} — вывод плейсхолдеров с точкой или дефисом в названии

Fenom использует точку для доступа к значению массива, а MODX обычно выствляет так плейсхолдеры из массивов. Поэтому для подобных плейсхолдеров необходимо использовать вторую служебную переменную — {$_pls}:
{$_pls['tag.sub_tag']}

<!-- Вывод доп поля со стандартным префиксом tv. -->
{$_pls['tv.img']}

<!-- Вывод через переменную -->
{var $tv_name = $_pls['tv-name']}
{$tv_name}

Если плейсхолдер был выставлен в глобальный массив modX::placeholders, то его можно получить так:

{$_modx->getPlaceholder('placeholder')}

{$_modx->getPlaceholder('placeholder')} помогает когда плейсхолдер устанавливается в сниппете при помощи $modx->setPlaceholder($value,'placeholder'); но в шаблоне и чанках не видны результаты при вызове вида {$placeholder}. 

Иногда в сниппете чанк вызывают через переменную $modx (или другой сервис, не умеющий интерпретировать fenom), и тогда плейсхолдеры fenom в них не обрабатываются, чтобы это исправить, добавьте в сниппет pdoTools, и вызовите чанк через него:

$pdo = $modx->getService('pdoTools');

// сервис $_modx или другой меняем на $pdo
$pdo->getChunk('anyChunk',$params);

После добавления этих строк плейсхолдеры fenom в чанках начнут корректно обрабатываться.

Если сниппет не умеет сохранять результаты своей работы в плейсхолдер, можно присвоить их переменной Fenom:

{set $date = 'dateAgo' | snippet : ['input' => '2016-09-10 12:55:35']}

...

Дата: {$date}.

В шаблонах могут возникнуть проблемы с выводом доп. поля (tv) у которого в названии есть точки или дефисы, в этом случае поможет следующая конструкция:

{$_modx->resource['tv-name']}

С помощью fenom плейсхолдеры можно устанавливать:

{$_modx->setPlaceholder('placeholdersName', $anyVariable)}

Переменные

Если надо установить переменную, не выводя ее результат, используются тег {set} (в старом синтаксисе {var})

{set $var=(expr)}

{set $var}
  ... any content ...
{/set}

{set $var|modifiers}
  ... any content ...
{/set}

{set $v = 5}
{set $v = "value"}
{set $v = $x+$y}
{set $v = 4}
{set $v = $z++ + 1}
{set $v = --$z}
{set $v = $y/$x}
{set $v = $y-$x}
{set $v = $y*$x-2}
{set $v = ($y^$x)+7}

{set $v = [1,2,3]}
{set $v = []}
{set $v = ["one"|upper => 1, 4 => $x, "three" => 3]}
{set $v = ["key1" => $y*$x-2, "key2" => ["z" => $z]]}

{set $v = count([1,2,3])+7}

// В качестве значения переменной можно задать результат отрисовки фрагмента шаблона
{set $v}
    Some long {$text|trim}
{/set}

// применение модификатора к данным перед тем как они будут сохранены в переменную
{set $v|escape} {* применение можификатора к значению *}
    Some long {$text|trim}
{/set}

Тег {add} делает тоже самое что и тег {set} за исключением того что сначала проверяет наличие переменной и если переменной нет — задет новое значение.

{add $var = 'value'}

// схема работы тега
{if $var is not set}
    {set $var = 'value'}
{/if}

Работа с массивами в fenom

Заполнение массива:

{set $array = [
    "key" => "value",
    "key2" => "value2",
]}

{set $array.key = value}

{set $array[] = value}

Для проверки присутствия значения в массиве или строке используется оператор in, или его инвертированная версия not in.

  • $a in list $b — значение $a содержится в массиве значений $b;
  • $a in keys $b — массив $b имеет ключ $a;
  • $a in string $b — значение $a содержится в $b как подстрока;
  • $a in $b — значение $a содержится в $b, где $b может быть строкой, обычным или ассоциативным массивом. Этот вариант долгий так как требуется проверить типы переменной $b. Однако если вместо $b явно задан массив или строка то оператор сам адаптируется для быстрого поиска.

Проверка присутствия в массиве:

{'df' in 'abcdefg'}
{5 in [1, 5, 25, 125]}
{99 in keys [1, 5, 25, 99 => 125]}

Вывод единичного значения из массива:

// Простой массив
{$array['key']}

// Многомерный массив
{$array[0]['key']}
{$array['key.key']}

Массивы Get и Post

<!-- шаблон -->
{$.method.var_name}

<!-- выведет данные с именем tag из массива get -->
{$.get.tag}

<!-- выведет данные с именем page из массива post -->
{$.post.page}

Условия if, else, switch, foreach

Список возможных операторов fenom

Условие «если, то»:

{if $idx == 1}
    idx = 1
{elseif $idx == 4 || ($idx > 3 && $idx < 5)}
    idx = 4
{else}
    idx = ?
{/if}

Короткая запись if (тернарный оператор)

// выбор между полями
{$_modx->resource.longtitle ? $_modx->resource.longtitle : $_modx->resource.pagetitle}

// значение по умолчанию
{$_modx->resource.introtext ?: 'аннотация не заполнена'}

Дополнительная информация про условие if, else

Проверка, если дополнительное поле заполнено:

{if $_modx->resource.tags != ''}
    Вывод информации
{/if}

Проверка, если длинна массива больше чем (работает также с итератором или символами в строке в кодировке UTF8):

{if $videos | length < 1}
  Тут только 1 видео
{/if}

 

Переключение switch

{switch $idx}
   {case 1} idx=1
   {case 4} idx=4 {break}
   {default} idx = $idx
{/switch }

Можно указывать несколько значений:

{switch $color}
   {case 'blue'} синий
   {case 'red','pink'} оттенки красного
   {default,'mix'} цветной
{/switch}

Цикл foreach:

{var $array = [
               0 => 'val1', 
               1 => 'val2'
              ]}

{foreach $array as $key => $value}
    key = {$key}, value = {$value}
{/foreach}

Дополнительная информация про цикл foreach

Foreach работает только с массивами, объектами и интервалами. Имеет несколько дополнительных параметров для гибкой настройки. К примеру, можно добавить теги:

  • {break} — выходит из цикла до достижения последней итерации. 
  • {continue} — прерывает текущую итерацию. Если текущая итерация была последней, цикл завершается.
  • {foreachelse} — ограничивает код, который должен быть выполнен, если итерируемый объект пуст.
{var $list = []}
{foreach $list as $value}
 <div>Значение: {$value}</div>
{foreachelse}
 <div>Массив пуст</div>
{/foreach}

Цикл foreach умеет работать с интервалами (как замена для for()):

{foreach 1..11 as $value}
 <ul>
  <li>{$value}</li>
 </ul>
{/foreach}

Помимо этого присутствует возможность указать номер итерации в цикле:

  • index — указание номера итерации;
  • first — первая итерация;
  • last — последняя итерация.

 Вычисление итерации путем создания соответствующей переменной index=$index:

<!-- Определение первой итерации -->
{foreach $list as $value first=$first}
 <div>{if $first} Первое значение {/if} {$value}</div>
{/foreach}

<!-- Определение последней итерации -->
{foreach $list as $value last=$last}
 <div>{if $last} Последнее значение {/if} {$value}</div>
{/foreach}

<!-- Определение номера итерации -->
{foreach $list as $value index=$index}
 <div>№{$index}: {$value}</div>
{/foreach}


Вычисление итерации путем указания постфикса для переменной {$value@index}:

<!-- Настройка первой итерации в цикле --> 
{foreach $list as $value}
 <div>{if $value@first} Первое значение {/if} {$value}</div>
{/foreach}

<!-- Настройка последней итерации в цикле --> 
{foreach $list as $value}
 <div>{if $value@first} Первое значение {/if} {$value}</div>
{/foreach}

<!-- Вычисление номера итерации в цикле --> 
{foreach $list as $value}
 <div>№{$value@index}: {$value}</div>
{/foreach}

 Можно сделать собственный счетчик итераций:

{set $count = 0}
{foreach 5..10 as $row}
    {do  ++$count}
    <p>{$row} - {$count}</p>
{/foreach}

Можно ограничить количество выводимых циклом foreach элементов, или указать пропуск от начала таблицы:

{* Выведет первые 5 элементов *}

{foreach $items as $item index=$index}
   {if $index < 5}
         <p>Элемент № #{$index}</p>
   {/if}
{/foreach}


{* Выведет элементы начиная с 5 *}

{foreach $items as $item index=$index}
   {if $index > 5}
         <p>Элемент № #{$index}</p>
   {/if}
{/foreach}

Циклу foreach можно задать чресстрочную запись:

{foreach $items as $index => $value}
	<div {$index is odd ? ' class="odd"' : ''}>"Эллемент № {$index} - {$value}</div>
{/foreach}

С помощью цикла foreach можно задать условия для выполнения операций через N итераций:

{foreach $items as $item}
    {if $item@index % 4 == 0}
        // условия в этом блоке выполняются каждые 4 итерации
    {/if}
        // условия для выполнения при каждой итерации
{/foreach}

 

Вывод сниппетов и чанков

// упрощенная конструкция
{'pdoSitemap' | snippet}

// упрощенная конструкция с параметрами и отсутствием кеширования
{'!pdoPage' | snippet : [
    'parents' => 0,
    'showLog' => 1,
    'element' => 'psoResources',
    'where' => ['isfolder' => 1],
    'showLog' => 1,
]}

// полная конструкция через класс microMODX
{$_modx->runSnippet('pdoSitemap')}

// конструкция через microMODX, с добавленным запретом кеширования "!" и параметрами
{$_modx->runSnippet('!pdoPage@PropertySet', [
    'parents' => '2,'~$_modx->resource.id,  // конкатенация внутри fenom
    'showLog' => 1,
    'element' => 'psoResources',
    'where' => ['isfolder' => 1],
    'showLog' => 1,
])}
{$_modx->getPlaceholder('page.total')}
{$_modx->getPlaceholder('page.nav')}

По умолчанию все сниппеты вызываются кэшированными, для некешированного вызова добавляется ! — как и в тегах MODX.

Для вывода чанков запускается pdoTools, можно использовать все его возможности:

{$_modx->getChunk('MyChunk@PropertySet')}

{$_modx->parseChunk('MyChunk', [
    'pl1' => 'placeholder1',
    'pl2' => 'placeholder2',
])}

{$_modx->getChunk('@TEMPLATE Base Template')}

{$_modx->getChunk('@INLINE
    Имя сайта: {$_modx->config.site_name}
')}

{$_modx->getChunk(
    '@INLINE Передача перемнной в чанк: {$var}',
    ['var' => 'Тест']
)}

{$_modx->getChunk('
    @INLINE Передача переменной в вызов сниппета:
    {$_modx->runSnippet("pdoResources", [
        "parents" => $parents
    ])}
    Всего результатов: {$_modx->getPlaceholder("total")}
    ',
    ['parents' => 0]
)}

Управление кэшированием

В объекте {$_modx} доступен сервиc modX::cacheManager, который позволяет устанавливать произвольное время кэширования вызываемых сниппетов:
{if !$snippet = $_modx->cacheManager->get('cache_key')}
    {set $snippet = $_modx->runSnippet('!pdoResources', [
        'parents' => 0,
        'tpl' => '@INLINE {$id} - {$pagetitle}',
        'showLog' => 1,
    ])}
    // set $null — чтобы cacheManager->set не вывел 1 (т.е. true) на страницу
    {set $null = $_modx->cacheManager->set('cache_key', $snippet, 1800)} // 30 минут
{/if}

{$snippet}

Посмотреть этот кэш можно в /core/cache/default/

Системные процессоры

Можно запускать системные процессоры (если хватит прав ):

{$_modx->runProcessor('resource/update', [
    'id' => 10,
    'alias' => 'test',
    'context_key' => 'web',
])}

Проверка авторизации

Так как объекта с пользователем в {$_modx} нет, методы проверки авторизации и прав доступа вынесены в классы:
{$_modx->isAuthenticated()}                    // если авторизован
{$_modx->hasSessionContext('web')}             // есть ли доступ к контексту
{$_modx->hasPermission('load')}                // есть ли права

Вывод информации только пользователям, которые авторизованы в менеджере:

{if $_modx->hasSessionContext('mgr')}
    {$_modx->getInfo()}
{/if}

Обработка по id (fastField)

{id | параметр : [доп указания]}

{3 | url : ['scheme' => 'full'] : ['param' => 'value']}   // устанавливает ссылку на ресурс с заданными параметрами
{3 | ismember : ['Administrator', 'Manager']}             // проверяет, состоит ли пользователь с указанным id в группах
{3 | user : 'fullname'}                                   // выводит указанное поле пользователя
{3 | resource : 'my_tv'}                                  // выводит указанное поле ресурса

Обработка данных

// разбивает строку на массив
{$string|split:","}

{var $fruits1 = "banana,apple,pear"|split:','}
$fruits1 is array ["banana", "apple", "pear"]

{var $fruits2 = "banana,apple,pear"|split:',apple,'}
$fruits2 is array ["banana", "pear"]

Можно использовать php функции. Например, разобьем массив на части с помощью функции array_chunk, для того чтобы обернуть каждые N элементов массива:

{if $elements}
  {set $elements = array_chunk($elements, 4)}
  <div class="wrap">
  {foreach $elements as $elementsGroup}
      <div class="elem">
      {foreach $elementsGroup as $element}
          {$element}
      {/foreach}
      </div>
   {/foreach}
  </div>
{/if}

Работа с ресурсами

Получить и вывести один ресурс без использования сниппета:

{var $resource = $_modx->getResource(1)}

{$_modx->getChunk('@INLINE <p>{$id} {$pagetitle}</p>', $resource)}

Получить и вывести ресурсы без использования сниппета:

{var $resources = $_modx->getResources(
    ['published' => 1, 'deleted' => 0],
    ['sortby' => 'id', 'sortdir' => 'ASC', 'limit' => 50]
)}
{foreach $resources as $resource}
    {$_modx->getChunk('@INLINE <p>{$id} {$pagetitle}</p>', $resource)}
{/foreach}

Получить данные родителя ресурса:

{$_modx->resource.parent}

// выводим tv поле родителя
{$_modx->resource.parent | resource : 'tv-name'}

Получить родителей ресурса:

// параметры по умолчанию
// $id (id ресурса) = null
// $height (уровни вложенности) = 10
// array $options (настройки) = array()

// выведет 5 уровней родителей ресурса с id 25
{$_modx->getParentIds(25,5)} 

// выведет 10 уровней текущего ресурса в контексте web
{$modx->getParentIds($id, 10, array('context' => 'web'))}

Получить значение дедушки ресурса:

{$_modx->resource.parent | resource : 'parent'}

Выводим информацию в зависимости от id родителей ресурса:

// Получаем всех родителей ресурса
{set $parentIDs = $_modx->getParentIds($id)}

// Если среди родителей есть ресурс с id 12, то...
{if 12 in $parentIDs}
	у этого ресурса есть прородитель с id 12
{/if}

// Если у одного из прородителей заполнено поле tv, то ... 
{foreach $parentIDs as $id}
	{if $id | resource : 'tv' != ''}
		У ресурса с id {$id} поле tv заполнено
	{/if}
{/foreach}

Получить 1 уровень потомков ресурса с id 3:

// параметры по умолчанию
// $id = null, $depth = 10, array $options = array()

{$_modx->getChildIds(3, 1)} 

Применение модификаторов

// { объект | модификатор : 'значение' | модификатор : 'значение'}

{$_modx->resource.pagetitle | limit : '3' | lowercase}

Список встроенных в fenom модификаторов

Список встроенных в MODX модификаторов

Применение модификаторов на практике
// Устанавливает лимит на длинну строки и обрезает ее, добавляя три точки в конце
{$_modx->resource.pagetitle | ellipsis : '100'}

// Прописывает файл JS в <link> элемент перед закрывающим тегом </body>.
{'<script type="text/javascript" >Скрипт JS</script>'| jsToBottom : true}
Встроенные модификаторы Fenom

Модификатор lexicon для замены и указания языка:

{'string' | lexicon}
// или
{'string' | lexicon : ['key' => 'value'] : 'ru'}

// Грузим английский словарь и выводим из него запись
{$_modx->lexicon->load('en:core:default')}
{'action_err_nfs' | lexicon : ['id' => 25] : 'en'}

url генерирует ссылку на ресурс:

{10 | url}
// или
{10 | url : ['scheme' => 'full'] : ['param' => 'value']}
Собственные модификаторы Fenom

Начиная с версии 2.6.0 в fenom появилась возможность создавать собственные модификаторы, при помощи плагина и события pdoToolsOnFenomInit

<?php
/** @var modX $modx */
switch ($modx->event->name) {
    case 'pdoToolsOnFenomInit':
        /** @var Fenom $fenom
            Получаем переменную $fenom при его первой инициализации. 
            Теперь можем вызывать его методы.*/

        /** Добавим модификатор вывода имени домена сайта из произвольной ссылки.*/

        $fenom->addModifier('website', function ($input) {
            if (!$url = parse_url($input)) {
                return $input;
            }
            $output = str_replace('www.', '', $url['host']);

            return strtolower($output);
        });
        break;
}

Данный плагин позволяет вызывать модификатор website из любого места в коде. Поскольку этот модификатор является внутренним методом Fenom и загружается один раз — при его инициализации, то и работает он быстрее любого сниппета.

Пример создания собственного модификатора ignore

<?php
/** @var modX $modx */
switch ($modx->event->name) {
    case 'pdoToolsOnFenomInit':
        $fenom->addModifier('ignore', function ($input) {
            $output = '{ignore}' . $input . '{/ignore}';
            return $output;
        });
        break;
}

Применение:

<div data-attr='{'{"0":{"items":1,"nav":"false"},"100":{"items":2}}' | ignore}'>

Собственные теги Fenom

Помимо модификаторов можно создавать собственные теги:

<?php
/** @var modX $modx */
switch ($modx->event->name) {
    case 'pdoToolsOnFenomInit':
            /** @var Fenom $fenom
            Получаем переменную $fenom при его первой инициализации. 
            Теперь можем вызывать его методы.*/

        $fenom->addCompiler('exit', function () {
            return "return;";
        });
        break;
}

Данный тег прервет дальнейшую обработку шаблонизатора fenom, которая вставлена после тега {exit}.

Какой-то код и текст вставленный до тега exit

{exit}

Код и текст вставленный после тега exit

Выведется только «Какой-то код и текст вставленный до тега exit». Все что оказалось после обрабатываться не будет.

Остальные методы

{$_modx->regClientCss('/assets/css/style.css')}             // регистрация css
{$_modx->regClientScript('/assets/js/script.js')}          // регистрация js

{$_modx->sendForward(10)}                                   // загрузить ресурс без изменения url
{$_modx->sendRedirect('http://yandex.ru')}                  // перенаправление, редирект

{$_modx->setPlaceholder('key', 'value')}                    // установить плейсхолдер
{$_modx->getPlaceholder('key')}                             // получить плейсхолдер

{if $res = $_modx->findResource('url-to/doc/')}             // найти ресурс
    {$_modx->sendRedirect( $_modx->makeUrl($res) )}         // создать url
{/if}

                                                            // найти ресурс по алиасу
{var $resource = $_modx->getResource(                       
    ['alias' => $alias]
)}
{$resource.pagetitle}                                       // и вывести его название

                                                            // получить список ресурсов
{var $resources = $_modx->getResources(                     
    ['published' => 1, 'hidemenu' => 0],
    ['sortby' => 'date', 'sortdir' => 'ASC', 'limit' => 10]
)}                                                          
                                                            // вывести данные из массива
{foreach $resources as $resource}                       
    {$resource.id} - {$resource.pagetitle}
{/foreach}

                                                            // вывод с использованием чанка
{foreach $resources as $resource}
    {$_modx->getChunk('@INLINE 
    <p>{$id} - {$pagetitle}</p>', $resource)}
{/foreach}

Полный список методов можно узнать в классе microMODX

Усложненный синтаксис

В некоторых случаях появляется потребность вставить тег fenom в тег fenom. Такая возможность существует:

{"Название страницы: {$pagetitle}"}      

Допускаются не только переменные, но и различные имеющиеся возможности шаблонизатора феном. Но, если необходимо вывести именно код, без его обработки, то можно добавить экранирование. Поскольку экранировать фигурную скобку нельзя, экранируется знак $: 

{"Название страницы: {\$pagetitle}"}
<!-- выведет "Название страницы: {$pagetitle}" -->

Вывод полей MIGX

Поля MIGX используют JSON, поэтому при попытке вывода такого поля стандартным способом, будет показана строка с JSON массивом. Чтобы достать из этой строки данные нужно сначала строку декодировать, потом обработать массив:

{set $tvFild = json_decode($_modx->resource.tvMIGX, true)}
{$tvFild[0][title]}

Либо обработать данные методом foreach: 

{set $rows = json_decode($_modx->resource.tvMIGX, true)}
{foreach $rows as $row}
    <p>{$row.id}-{$row.text}</p>
{/foreach}

Служебная информация

В MODX предусмотрен метод для получения данных о скорости работы системы в данный момент.

{$_modx->getInfo(string, bool, string)}
  • string — вывести определённый ключ из массива данных (пусто, по умолчанию);
  • bool — вывести все данные как строку, а не массив (true, по умолчанию);
  • string — оформить строки в чанк (Например: @INLINE {$key}: ${value}).

Вывод по умолчанию (строка со всеми данными):

{$_modx->getInfo()}
// queries: 39
// totalTime: 0.1067 s
// queryTime: 0.0069 s
// phpTime: 0.0998 s
// source: database

Вывод конкретного значения:

{$_modx->getInfo('totalTime')}
// 0.1067 s
{$_modx->getInfo('source')}
// database

Оформление строк в свой чанк:

{$_modx->getInfo('', true, '@INLINE {$key} => {$value}')}
// queries => 39
// totalTime => 0.1155 s
// queryTime => 0.0091 s
// phpTime => 0.1064 s
// source => database

Можете добавить строки в лексикон и выводить ключи через него:

{$_modx->lexicon->load('pdotools:default')}
{$_modx->getInfo('', true, '@INLINE {$_modx->lexicon("pdotools_" ~ $key)} => {$value}')}

Или оформить без лексиконов, произвольно. Просто присваиваем переменной массив данных и выводим его ключи:

{set $info = $_modx->getInfo('', false)}
Время работы: {$info.totalTime}
Время запросов: {$info.totalTime}
Количество запросов: {$info.queries}
Источник: {$info.source}

Вывод информации только пользователям, которые авторизованы в менеджере:

{if $_modx->hasSessionContext('mgr')}
    {$_modx->getInfo()}
{/if}

Расширение шаблонов

Использование шаблонизатора Fenom позволяет включать одни чанки (шаблоны в другие) и даже расширять их.

{include} — используются для включения других шаблонов в текущий.
Например, можно просто подгрузить содержимое чанка:

Обычный чанк 
{include 'имя чанка'}

Шаблон modTemplate 
{include 'template:имя шаблона'}

Чанк с набором параметров
{include 'chunk@propertySet'}
{include 'template:Name@propertySet'}

Передача переменных в блок, например чанк:

{include 'divChankName' class=“col-md-12“}

<!-- Вызывается в чанке с помощью переменной $class -->
<div $class>
  У этого блока установлен класс col-md-12
</div>

{include} в официальной документации

{extend} —  возможность подключения шаблона или чанка для последующего его расширения.

требует включенной системной настройки pdotools_fenom_parser.

Пример: базовый шаблон «Fenom Base» включает обычные чанки и определяет несколько блоков {block}, которые можно расширить в другом шаблоне:

<!DOCTYPE html>
<html lang="en">
<head>
    {include 'head'}
</head>
<body>
    {block 'navbar'}
        {include 'navbar'}
    {/block}
    <div class="container">
            <div class="content">
                {block 'content'}
                    {$_modx->resource.content}
                {/block}
            </div>
            <div class="sidebar">
                {block 'sidebar'}
                    Sidebar
                {/block}
            </div>
        {block 'footer'}
                {include 'footer'}
        {/block}
    </div>
</body>
</html>

Дочерний шаблон «Fenom Extended», в котором подключается «Fenom Base» и расширяется блок content:

{extends 'template:Fenom Base'}
{block 'content'}
    <h3>{$_modx->resource.pagetitle}</h3>
    <div class="jumbotron">
        {parent}
    </div>
{/block}

Также можно расширять чанки, но, для чанков не нужен префикс template.

{extends} в официальной документации