Шаблон задаёт вид страницы, чанк хранит повторяющийся кусок разметки. Остались вещи, которые нельзя ни нарисовать заранее, ни скопировать: меню, которое само знает обо всех разделах, и картинка-анонс, которой у страницы по умолчанию нет. Этим занимаются сниппеты и TV-поля.

Сниппет — кусок программы

Сниппет (snippet, «фрагмент») — небольшая программа на PHP, которая запускается в момент сборки страницы и возвращает готовый HTML. Вызывается так же коротко, как чанк, только скобки другие — квадратные:

Вызов сниппета в шаблоне
<nav class="main-nav">
  [[DocLister? &parents=`3` &tpl=`menu-item`]]
</nav>

Что здесь происходит: движок дошёл до этой строки, запустил сниппет DocLister, передал ему два параметра — откуда брать страницы и каким чанком рисовать каждую. Сниппет сходил в базу, собрал детей третьего раздела, обернул каждого в разметку чанка и вернул готовый кусок HTML. На странице этот вызов не виден вообще — вместо него стоит результат.

Разница с чанком ровно в одном слове. Чанк подставляется, сниппет выполняется. Чанк вернёт то же самое на любой странице; сниппет каждый раз считает заново и на разных страницах вернёт разное.

Писать свои сниппеты не придётся

Хорошая новость для человека, который не знает PHP: девять задач из десяти закрываются готовыми сниппетами. Они ставятся из админки, а от вас требуется только правильно их вызвать.

Что берут готовым в Evolution
Сниппет Что делает Где на этом сайте
DocLister Выводит список страниц по дереву: меню, каталог, лента материалов Мегаменю, боковое меню этапа, маршрут, подвал
DLCrumbs Считает путь от главной до текущей страницы Крошки на каждой внутренней странице
DLPrevNext Находит соседей страницы в дереве Кнопки «Назад» и «Дальше» внизу страницы
ElForm Проверяет форму и отправляет письмо. Свой: готового в поставке нет Форма обратной связи

Каждый из них настраивается параметрами — теми самыми &имя=`значение` после знака вопроса. Их бывает много, но выучивать нечего: список параметров лежит в документации сниппета, а нужны обычно три-четыре.

Разметку задаёте вы, а не сниппет

У DocLister и его родни есть параметры вроде &tpl — в них передают имя чанка, по которому рисовать каждый пункт. Значит, сниппет отвечает только за то, какие страницы вывести, а как они выглядят, решает ваш чанк. Вёрстка остаётся вашей — ради этого и выбиралась Evolution.

Другие скобки и кэш

Evolution запоминает собранные страницы, чтобы не пересобирать их на каждое открытие. Обычно это хорошо: меню меняется редко, и считать его сто раз незачем.

Но есть вещи, которые обязаны быть свежими всегда: результат поиска, форма, вывод случайной цитаты. Такой вызов пишут в других скобках — вместо [[Сниппет]]. Это и значит «не бери из памяти, посчитай сейчас».

Кэшируемый и некэшируемый вызов
[[DocLister? &parents=`3`]]   <!-- меню: можно из кэша -->
   <!-- свежий список: заново -->

Нужен только для ответа. Никаких рассылок.

<!-- форма: всегда заново -->

Самая частая потеря времени новичка

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

Вторая ловушка — запись [[!Сниппет]], привычная по другим движкам. Evolution читает её как имя сниппета «!Сниппет»: не находит и выводит пустое место. Без ошибки и без следа в журнале.

TV-поле — своё поле у страницы

У каждой страницы есть готовый набор полей: заголовок, текст, описание. Их хватает ровно до первой задачи из жизни. Например, карточке мануала на хабе нужны картинка и время чтения. Куда их положить? В текст нельзя — он идёт в статью целиком.

Для этого и придуманы TV-поля (template variables, «переменные шаблона»). Вы создаёте новое поле в админке, привязываете его к нужным шаблонам — и в форме редактирования страницы появляется ещё одно поле для заполнения.

Вызывается TV-поле так же, как встроенное, — по имени в скобках со звёздочками. Отличить его от родного поля по коду нельзя, и это удобно:

Карточка с TV-полями
<article class="card">
  <img src="[*cover*]" alt="" width="640" height="360" loading="lazy">
  <h3 class="card__title">[*pagetitle*]</h3>
  <p class="card__text">[*introtext*]</p>
  <span class="chip">[*reading_time*] мин</span>
</article>

Здесь [*pagetitle*] и [*introtext*] — встроенные поля, а [*cover*] и [*reading_time*] — придуманные мной TV. В админке они выглядят как обычные поля формы: у первого — кнопка выбора файла, у второго — строка ввода.

У TV есть тип

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

Типы, которые нужны чаще всего
Тип Как выглядит в админке Для чего
Текст Однострочное поле Время чтения, подпись, короткий слоган
Изображение Кнопка выбора файла из менеджера Обложка материала, картинка для Open Graph
Список Выпадающий список с готовыми значениями Уровень сложности: новичок, средний, продвинутый
Флажок Галочка «Показывать на главной», «Материал готов»
Дата Календарь Дата публикации, если нужна своя

Как это выглядит в админке

Четыре понятия рядом

Теперь можно собрать всё вместе. Эта таблица — короткий ответ на вопрос «что из них что», ради которого и затевался этап.

Из чего собирается страница в Evolution
Понятие Что это Как вызвать
Шаблон Вёрстка страницы целиком, с метками вместо текста Выбирается у страницы в админке
Чанк Повторяющийся кусок разметки {{header}}
Сниппет Программа: считает и возвращает готовый HTML [[DocLister]]
TV-поле Своё поле страницы сверх встроенных [*cover*]

Что я спросил у нейросети

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

Мой запрос

Evolution CMS, сниппет DocLister. Нужно боковое меню страниц одного раздела: выводить только детей текущего раздела, один уровень, без вложенности.

Разметка должна получиться такая: <ul class="sidebar-nav__list">, внутри <li> со ссылкой class="sidebar-nav__link", а у текущей страницы к ссылке добавляется aria-current="page".

Напиши вызов сниппета с параметрами и чанки, которые в нём используются. К каждому параметру — строчку, что он делает, чтобы я мог поменять сам.

Получилось с третьего раза, и это нормально: первые два ответа были для MODX Revolution, где синтаксис другой. Помогла приписка «именно Evolution CMS, не Revolution» — в запросе выше она стоит с самого начала.

Просите нужную разметку сразу

Если не сказать, какой HTML вы хотите получить, нейросеть выдаст свой — с чужими классами, которых нет в ваших стилях. Приложите к запросу кусок готовой вёрстки и попросите повторить её один в один. Так ответ приходит сразу рабочим.

Что теперь понятно

  • Чанк подставляется, сниппет выполняется и возвращает результат
  • Готовых сниппетов хватает на меню, списки и крошки; форму пришлось написать свою
  • в других скобках считается заново, без кэша
  • TV-поле добавляет странице своё поле и вызывается как встроенное: [*cover*]