Свой сниппет в MODX: рабочие приёмы без лишней логики
Сниппет в MODX превращает повторяющийся PHP-код в вызываемый элемент шаблона. Разбираем, как передавать параметры, когда использовать чанк, чем отличаются кэшируемые и некэшируемые вызовы и какие ошибки чаще всего ломают вывод.

В MODX один небольшой сниппет может заменить копии PHP-кода в шаблонах, чанках и ресурсах. Но если смешать в нём запросы к базе, HTML, проверку доступа и форматирование, через месяц такой код станет труднее менять, чем исходную копию. Ниже — практические приёмы для MODX Revolution 2.8.x и 3.x: от простого параметризованного вывода до связки «сниппет плюс чанк», с рабочими примерами и критериями выбора.
Что считать хорошим сниппетом в MODX
Сниппет — это PHP-код, который MODX выполняет во время разбора страницы и подставляет его возвращаемое значение в результат. Вызов выглядит так:
[[!SiteLabel? &label=`Каталог`]]
В админке код сниппета обычно сохраняют без открывающего тега <?php. MODX сам выполняет содержимое как PHP. В примерах ниже используется синтаксис PHP 7+; перед публикацией проверьте версию PHP, установленную на вашем хостинге.
У сниппета есть два важных источника данных:
$scriptProperties— массив параметров, переданных в вызове;$modx— объект MODX, через который можно получать настройки, ресурсы, чанки и другие сервисы.
Сниппет должен возвращать готовый результат, а не печатать его через
echo. Возврат делает поведение предсказуемым для кэширования и вложенных вызовов.
Параметр сниппета — значение после символа & в вызове. Например, в &label=`Каталог` имя параметра — label, а его значение — «Каталог».
Приём 1. Маленький сниппет с одним ответственным действием
Начинайте с кода, который принимает параметры, проверяет их и возвращает один результат. Такой сниппет легко вызвать в шаблоне и отдельно протестировать на странице.
Пример: безопасно вывести подпись
Создайте сниппет SiteLabel и вставьте в него этот код:
$label = trim((string)($scriptProperties['label'] ?? ''));
if ($label === '') {
return '';
}
return htmlspecialchars($label, ENT_QUOTES, 'UTF-8');
В шаблоне вызов будет таким:
<span class="section-label">[[!SiteLabel? &label=`Каталог`]]</span>
Здесь параметр приводится к строке, пустое значение отбрасывается, а HTML-символы экранируются. Последнее важно, если значение приходит из поля ресурса, TV-параметра или пользовательского ввода.
Когда этот приём подходит
Используйте прямой возврат для коротких операций: форматирования даты, проверки флага, выбора подписи, построения одного URL. Не помещайте в такой код большой HTML-шаблон: разметка быстро начнёт мешать чтению PHP.
Приём 2. PHP отвечает за данные, чанк — за HTML
Если результат содержит несколько тегов, классы и вложенные поля, вынесите разметку в чанк. Сниппет подготовит значения, а чанк останется удобным для редактирования контент-менеджером.
Пример карточки ссылки
Создайте чанк SiteLink:
<a class="site-link" href="[[+url]]">[[+label]]</a>
Создайте сниппет SiteLinkSnippet:
$resourceId = (int)($scriptProperties['id'] ?? 0);
$label = trim((string)($scriptProperties['label'] ?? ''));
if ($resourceId <= 0 || $label === '') {
return '';
}
$url = $modx->makeUrl($resourceId);
$placeholders = [
'url' => htmlspecialchars($url, ENT_QUOTES, 'UTF-8'),
'label' => htmlspecialchars($label, ENT_QUOTES, 'UTF-8'),
];
return $modx->getChunk('SiteLink', $placeholders);
Вызов в ресурсе или чанке:
[[!SiteLinkSnippet?
&id=`[[*id]]`
&label=`Подробнее`
]]
Вложенный вызов параметра допустим, но проверяйте итоговый HTML в браузере. Если URL или подпись строятся из внешних данных, экранируйте их до передачи в чанк. Чанк не должен считаться автоматической защитой: плейсхолдер вставляет переданное значение как есть.
Приём 3. Отделяйте выбор данных от представления
Сниппет часто разрастается потому, что в одном месте одновременно решает три задачи: получает данные, решает, показывать ли блок, и рисует HTML. Рабочая граница проще:
- Получите и нормализуйте входные параметры.
- Проверьте условия, при которых вывод должен быть пустым.
- Подготовьте простые значения: строки, числа, URL, флаги.
- Передайте значения в чанк или верните короткую строку.
Если сниппет обращается к базе, не добавляйте туда ещё и разбор сложного HTML. Для списка элементов лучше заранее определить формат одного элемента и отдельно решить, где будет цикл: в сниппете или в специализированном инструменте проекта. Подключение стороннего компонента вроде pdoTools — отдельная тема; здесь важна сама граница ответственности.
Какой подход выбрать
| Задача | Подход | Цена решения |
|---|---|---|
| Вернуть одну строку или число | Прямой return из сниппета | Быстро написать, но HTML неудобно поддерживать в PHP |
| Вывести один блок с разметкой | Сниппет и чанк | Нужно создать два элемента и договориться о плейсхолдерах |
| Показать блок только при условии | Проверка в сниппете, разметка в чанке | Нужно явно определить поведение для пустых данных |
| Один и тот же результат на разных страницах | Параметризованный сниппет | Ошибку в параметрах можно незаметно повторить во всех вызовах |
Кэширование: почему вывод бывает «застывшим»
Вызов [[SnippetName]] может попасть в кэш страницы, а вызов с восклицательным знаком — [[!SnippetName]] — выполняется некэшируемым способом. Это принципиальная разница для персональных данных, случайных значений, корзины и блоков, зависящих от текущего пользователя или запроса.
Для подписи раздела или ссылки на ресурс кэширование обычно выгодно. Для вывода, который меняется после авторизации, не полагайтесь на очистку кэша как на механизм персонализации. Выберите некэшируемый вызов и проверьте поведение в анонимном и авторизованном сеансе.
Что чаще всего ломается
Параметр назван не так
В коде читается $scriptProperties['title'], а в вызове передаётся &label. В результате сниппет получает пустое значение. Держите имена параметров одинаковыми и задавайте значения по умолчанию через ??.
В сниппете используется echo
echo может дать неожиданный результат при вложенных вызовах и усложняет контроль кэширования. Для обычного сниппета возвращайте строку через return. Если нужно завершить вывод при ошибке входных данных, используйте return ''.
HTML смешан с неэкранированными данными
Значение из поля ресурса не всегда безопасно считать готовым HTML. Для обычного текста используйте htmlspecialchars. Если вы сознательно разрешаете HTML, задайте отдельное правило очистки и не применяйте его к URL без проверки.
Кэшируется персональный блок
Проверяйте вызов, а не только код сниппета. Если результат зависит от пользователя, сессии, cookie или параметров запроса, кэширование может показать одному посетителю данные другого или устаревшее состояние.
Сниппет вызывается внутри атрибута без проверки результата
Пустая строка, пробелы или неожиданные кавычки могут испортить HTML-атрибут. Для URL и текстовых значений готовьте отдельные правила экранирования, а итог проверяйте через инспектор браузера.
Что делать дальше
Возьмите один повторяющийся фрагмент на сайте и опишите его контракт: какие параметры он принимает, что возвращает при пустом значении и должен ли кэшироваться. Затем вынесите HTML в чанк, если он занимает больше одной-двух строк, и проверьте четыре сценария: обычный вызов, отсутствие параметра, спецсимволы в значении и включённый кэш.
После этого посмотрите журнал ошибок PHP и итоговый HTML страницы. Для больших списков отдельно измеряйте число запросов к базе и время генерации страницы: вынесение кода в сниппет само по себе не делает запрос быстрее.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: MODX Documentation: Snippets, MODX Documentation: Cacheable and Uncacheable Tags
Частые вопросы
Нужно ли добавлять тег <?php в сниппет MODX?
Чем отличаются [[Snippet]] и [[!Snippet]]?
Почему параметр сниппета приходит пустым?
Можно ли хранить весь HTML прямо в PHP-сниппете?
Что делать, если сниппет работает в MODX 2, но не работает в MODX 3?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.