В этой главе рассматривается шаблонизатор XTemplate SE (Seditio Edition), встроенный в ядро Seditio CMS, описываются его синтаксические конструкции (блоки, логические условия, циклы, фильтры), файловая архитектура тем оформления (скинов), PHP API для интеграции шаблонов в код, а также механизмы кастомизации интерфейса модулей и плагинов.
8.1. Введение и концепция XTemplate SE
Шаблонизатор Seditio CMS обеспечивает полное отделение логики приложения от его визуального представления.
8.1.1. Происхождение и назначение
Класс XTemplate в Seditio CMS (файл system/templates.php) представляет собой глубокую адаптацию шаблонизатора CoTemplate, используемого в проекте Cotonti, который, в свою очередь, наследует и развивает классическую концепцию XTemplate. Основные цели использования шаблонизатора в системе:
- Безопасность разработки: Верстальщик работает исключительно с HTML-разметкой и плейсхолдерами шаблонизатора, не имея возможности напрямую выполнять произвольный PHP-код в шаблонах.
- Чистота кода: Контроллеры ядра, модулей и плагинов формируют данные в PHP, а шаблонизатор занимается исключительно их рендерингом.
- Быстродействие: Шаблонизатор компилирует исходные TPL-файлы в промежуточную структуру (структуру блоков), которая кэшируется классом
XtplCache. При последующих запросах кэшированный шаблон считывается моментально, минуя ресурсоемкую стадию парсинга регулярными выражениями.
8.1.2. Механизм компиляции и кэширования
При первом вызове шаблона ядро считывает исходный .tpl файл, обрабатывает директивы динамического включения файлов, удаляет BOM-символы и компилирует шаблон в промежуточную структуру (структуру блоков), которая кэшируется классом XtplCache. При последующих запросах кэшированный шаблон считывается моментально, минуя ресурсоемкую стадию парсинга регулярными выражениями.
8.1.3. Отличия XTemplate SE от CoTemplate и преимущества
Несмотря на общую кодовую базу с CoTemplate (Cotonti), версия XTemplate SE (Seditio) имеет ключевые архитектурные отличия:
Безопасность (Фильтрация функций):
- XTemplate SE: Ограничивает вызовы функций-фильтров в шаблонах (режимы
whitelist/blacklist). По умолчанию разрешены только безопасные хелперы (например,trim,date,crop,resize). - CoTemplate: Позволяет верстальщику вызывать любые PHP-функции без ограничений, что несет риски RCE.
- XTemplate SE: Ограничивает вызовы функций-фильтров в шаблонах (режимы
Арифметические выражения в тегах вывода:
- XTemplate SE: Поддерживает вычисление простых выражений непосредственно внутри плейсхолдеров переменных:
{SOME_TAG + 5}или{VAR_1 * VAR_2}. - CoTemplate: Ограничивает использование арифметики только тегами условий
<!-- IF ... -->.
- XTemplate SE: Поддерживает вычисление простых выражений непосредственно внутри плейсхолдеров переменных:
Чистота и декомпозиция кода компиляции (
compile):- XTemplate SE: Логика разбора блоков (
XtplBlock::compile()) разбита на компактные методы (detectNextConstruct,extractConstruct,compileConstruct). - CoTemplate: Компиляция представляет собой монолитный 150-строчный метод с вложенными циклами и регулярными выражениями.
- XTemplate SE: Логика разбора блоков (
Оптимальный RPN-парсер выражений (
XtplExpr):- XTemplate SE: Хранит операторы в RPN-стеке в виде строк.
- CoTemplate: Использует более 20 глобальных констант для кодирования операторов, усложняя код и засоряя глобальную область видимости.
Оптимизированное дисковое кэширование:
- XTemplate SE: Класс
XtplCacheсериализует скомпилированный шаблон в один файл на диске. - CoTemplate: Создает три отдельных файла (
.tpl,.idx,.tags) на каждый шаблон, увеличивая нагрузку на файловую систему (I/O).
- XTemplate SE: Класс
Выделенная отладка (
XtplDebugger):- XTemplate SE: Сбор отладочной информации вынесен в отдельный класс
XtplDebugger. - CoTemplate: Логика отладки жестко встроена в методы рендеринга
parse()иout().
- XTemplate SE: Сбор отладочной информации вынесен в отдельный класс
Глобальная конфигурация:
- XTemplate SE: Настройка всех опций выполняется через единую статическую точку входа
XTemplate::configure(). - CoTemplate: Конфигурируется через метод
init().
- XTemplate SE: Настройка всех опций выполняется через единую статическую точку входа
8.2. Синтаксис шаблонов: блоки, циклы и логические условия
Шаблоны в Seditio используют стандартное расширение .tpl. Синтаксис состоит из плейсхолдеров (тегов) и управляющих комментариев.
8.2.1. Именованные блоки
Вся разметка в XTemplate SE строится на иерархической структуре блоков. Блок объявляется специальными HTML-комментариями:
<!-- BEGIN: MAIN -->
<div class="wrapper">
<h1>{PAGE_TITLE}</h1>
<!-- BEGIN: SUBBLOCK -->
<p>Дополнительный текст подблока: {SUB_INFO}</p>
<!-- END: SUBBLOCK -->
</div>
<!-- END: MAIN -->
- Корневым (главным) блоком в файле почти всегда является блок
MAIN. - Блоки могут быть вложенными на любую глубину.
- В PHP-коде для вывода блока используется его путь относительно корня (например,
MAINилиMAIN.SUBBLOCK).
8.2.2. Логические условия (IF/ELSE)
Условия позволяют управлять отображением элементов в зависимости от переданных переменных:
<!-- IF {PAGE_AUTHOR} == 'Admin' -->
<span class="badge red">Администратор</span>
<!-- ELSE -->
<span>Автор: {PAGE_AUTHOR}</span>
<!-- ENDIF -->
Внутри управляющего тега <!-- IF {EXPR} --> используется анализатор выражений XtplExpr. Поддерживаются следующие операции:
- Арифметические:
+,-,*,/,%. - Сравнения:
==(эквивалентно),===(тождественно),!=,!==,<,>,<=,>=. - Логические:
AND(или&&),OR(или||),XOR,!(логическое отрицание). - Специфические для Seditio:
HAS— проверка вхождения элемента в массив (аналогin_array()в PHP). Например:<!-- IF {USER_GROUP_ID} HAS 5 -->...<!-- ENDIF -->.~=— проверка вхождения подстроки (аналогstrpos() !== false). Например:<!-- IF {PAGE_TITLE} ~= 'Важно' -->...<!-- ENDIF -->.
8.2.3. Циклы (FOR)
Шаблонизатор XTemplate SE поддерживает автоматический обход массивов:
<ul>
<!-- FOR {VAL} IN {PHP.cfg.menu_links} -->
<li><a href="{VAL.url}">{VAL.title}</a></li>
<!-- ENDFOR -->
</ul>
Также поддерживается получение ключа ассоциативного массива:
<!-- FOR {KEY}, {VAL} IN {PHP.usr.auth_groups} -->
<li>Группа ID: {KEY}, Название: {VAL}</li>
<!-- ENDFOR -->
</ul>
При использовании циклов FOR шаблонизатор самостоятельно вычисляет размерность массива и выводит внутреннее содержимое блока для каждой итерации, автоматически подставляя переменные цикла в область видимости.
8.2.4. Директивы включения файлов (FILE)
Для сборки страницы из составных частей (например, подключение общей шапки, подвала или виджета) используется тег FILE:
{FILE "skins/default/header.tpl"}
Путь к файлу может указываться в кавычках (одинарных или двойных). Включаемый шаблон может содержать собственные блоки, условия, циклы и теги, которые будут скомпилированы в единое дерево шаблона.
8.3. Синтаксис плейсхолдеров (тегов) и фильтры
Плейсхолдеры — это переменные в фигурных скобках, которые во время выполнения заменяются на конкретные текстовые или HTML-данные.
8.3.1. Базовые переменные и массивы
- Простой тег:
{PAGE_TITLE}. - Элемент многомерного массива:
{PAGE_ROW.page_cat}или{PAGE_ROW.page_owner.user_name}.
8.3.2. Применение функций-фильтров (Callbacks)
Значения плейсхолдеров можно изменять «на лету» с помощью цепочек фильтров. Фильтр отделяется символом вертикальной черты |:
<p>{PAGE_TEXT|strip_tags|trim}</p>
Фильтры могут принимать аргументы, которые передаются в скобках через запятую:
<h2>{PAGE_TITLE|strtolower|ucfirst}</h2>
<p>Отрезок текста: {PAGE_TEXT|strip_tags|substr(0, 150)}</p>
<p>Дата публикации: {PAGE_DATE|date("d.m.Y H:i", $this)}</p>
[!IMPORTANT] Фильтрация функций (Function Filtering): Для обеспечения безопасности в классе
XTemplateреализован белый список разрешенных функций (whitelist). В шаблоне можно вызывать только одобренные ядром безопасные функции (по умолчанию:trim,nl2br,date,htmlspecialchars,strip_tags,substr,sprintf,count,resize,cropи др.). Попытка вызвать системные функции вродеeval,system,file_get_contentsприведет к ошибке безопасности или их блокировке.
8.3.3. Глобальный контекст (Префикс PHP)
Шаблонизатор Seditio предоставляет прямой доступ к глобальным массивам и переменным ядра CMS через специальный префикс PHP.:
{PHP.cfg.mainurl}— адрес главной страницы сайта.{PHP.usr.name}— имя текущего авторизованного пользователя.{PHP.usr.id}— ID текущего пользователя (0 для гостей).{PHP.L.Yes}/{PHP.L.No}— языковые строки локализации.{PHP.out.subtitle}— текущий подзаголовок страницы.
8.4. Структура скинов и шаблонов
Пользовательские темы оформления (скины) сайта хранятся в каталоге /skins/. При этом стандартные шаблоны модулей и плагинов по умолчанию поставляются в их собственных каталогах: /modules/{имя_модуля}/tpl/ и /plugins/{код_плагина}/ (или /plugins/{код_плагина}/tpl/).
Скин в Seditio представляет собой набор переопределяющих шаблонов (.tpl), файлов стилей (.css), скриптов (.js) и медиа-ресурсов, которые позволяют полностью изменить интерфейс CMS без изменения исходных файлов модулей и плагинов.
8.4.1. Локализация папки скина
Папка конкретного скина имеет вид: /skins/{код_скина}/ (например, /skins/default/).
8.4.2. Системные шаблоны и шаблоны модулей
В Seditio шаблоны могут храниться как непосредственно в папке активного скина (/skins/{код_скина}/), так и в папке соответствующего модуля (/modules/{имя_модуля}/tpl/). Функция sed_skinfile() выполняет автоматический поиск шаблона, отдавая приоритет файлам в папке скина, а при их отсутствии загружая стандартный шаблон из папки модуля.
Ниже приведен список реальных файлов шаблонов, сгруппированных по их назначению:
Общие системные шаблоны (Общие компоненты)
header.tpl— общая шапка сайта. Содержит HTML-заголовок, метатеги, тег{HEADER_STYLESHEET}для подключения стилей и верхнюю панель навигации.footer.tpl— общий подвал сайта. Содержит закрывающие теги, счетчики посещаемости, информацию о разработчиках и тег{FOOTER_DEVINFO}(время генерации, количество SQL-запросов и использование ОЗУ).index.tpl— макет главной страницы сайта.message.tpl— вывод системных предупреждений, сообщений об успешных операциях и ошибок.popup.tpl— разметка для всплывающих окон (например, для вставки смайликов или BB-кодов).plugin.tpl— стандартная обёртка для standalone-плагинов, не имеющих собственного шаблона.breadcrumbs.tpl— шаблон для оформления хлебных крошек (навигационной цепочки).maintenance.tpl— экран заглушки при проведении технических работ.
Модуль «Страницы» (Page)
page.tpl— отображение полной версии отдельной страницы.page.add.tpl— форма добавления страницы пользователем с фронтенда.page.edit.tpl— форма редактирования и обновления страницы.page.print.tpl— упрощенный шаблон для версии печати страницы.list.tpl— отображение списка страниц внутри выбранной категории.list.group.tpl— вывод списка страниц с группировкой по подразделам.admin.page.tpl— управление страницами и списком в панели администрирования.admin.page.add.tpl/admin.page.edit.tpl— формы создания/редактирования страниц в панели администрирования.admin.page.manager.tpl— инструмент быстрого менеджмента страниц в админке.
Модуль «Форумы» (Forums)
forums.sections.tpl— главная страница форумов (таблица категорий и разделов).forums.topics.tpl— список тем внутри конкретного раздела форума.forums.posts.tpl— список сообщений и форма ответа внутри конкретной темы.forums.newtopic.tpl— форма создания новой темы.forums.editpost.tpl— форма редактирования сообщений.admin.forums.tpl/admin.forums.structure.tpl— управление структурой и настройками форумов в панели администрирования.
Модуль «Персональная файловая система» (PFS)
pfs.tpl— личный кабинет файлового хранилища (загрузка файлов, список созданных папок).pfs.edit.tpl— форма редактирования описания и параметров файла/папки.pfs.standalone.tpl— интерфейс PFS во всплывающем окне (для прикрепления файлов/изображений в редакторе).pfs.edit.standalone.tpl— форма редактирования файла во всплывающем окне.admin.pfs.tpl— управление файловой системой пользователей в админке.
Модуль «Пользователи» (Users)
users.tpl— общая таблица (список) зарегистрированных участников.users.details.tpl— страница просмотра публичного профиля пользователя.users.profile.tpl— форма редактирования собственного профиля текущим пользователем.users.register.tpl— форма онлайн-регистрации нового аккаунта.users.auth.tpl— страница авторизации (входа на сайт).users.edit.tpl— редактирование чужого профиля (для модераторов/администраторов).admin.users.tpl— управление учетными записями и правами в панели администрирования.
Модуль «Личные сообщения» (PM)
pm.tpl— списки входящих, исходящих и архивных личных сообщений.pm.send.tpl— форма отправки нового личного сообщения.admin.pm.tpl/admin.pm.stat.tpl— управление и статистика ЛС в админке.
Модуль «Опросы» (Polls)
polls.tpl— вывод результатов опроса.polls.poll.tpl— форма для голосования.polls.standalone.tpl— вывод опросов в отдельном всплывающем окне или блоке.admin.polls.tpl— управление опросами в панели администрирования.
Модуль «Галерея» (Gallery)
gallery.home.tpl— главная страница галереи (список фотоальбомов).gallery.browse.tpl— сетка эскизов изображений в выбранном альбоме.gallery.details.tpl— страница детального просмотра изображения с комментариями/оценками.admin.gallery.tpl/admin.config.gallery.tpl— управление галереей и альбомами в админке.
8.5. PHP API шаблонизатора (для разработчиков)
Разработчики модулей и плагинов взаимодействуют с шаблонизатором через экземпляр класса XTemplate.
8.5.1. Создание экземпляра и компиляция
Конструктор принимает путь к файлу шаблона:
$t = new XTemplate(sed_skinfile('index'));
Функция sed_skinfile('имя_файла') автоматически проверяет наличие файла шаблона в активном скине сайта, подставляя правильный системный путь.
8.5.2. Присвоение значений тегам
Метод assign() осуществляет передачу переменных в область видимости шаблона:
// Передача одиночной переменной
$t->assign('PAGE_TITLE', $page_title);
// Массовое назначение через ассоциативный массив
$t->assign(array(
'PAGE_ID' => $row['page_id'],
'PAGE_CAT' => $row['page_cat'],
'PAGE_OWNER' => $row['page_owner']
));
// Использование префиксов (например, для вывода массива с префиксом PAGE_ROW_)
$t->assign($row, null, 'PAGE_ROW_');
8.5.3. Парсинг блоков
После заполнения тегов внутри конкретного блока данными, этот блок отправляется на рендеринг методом parse():
// Рендеринг вложенного блока внутри цикла
foreach ($items as $item) {
$t->assign(array(
'ITEM_ID' => $item['id'],
'ITEM_NAME' => $item['name']
));
$t->parse('MAIN.ITEMS_LIST.ITEM_ROW');
}
// Парсинг родительских блоков
$t->parse('MAIN.ITEMS_LIST');
$t->parse('MAIN');
- Блоки условий
IFи цикловFORвнутри шаблонов вычисляются автоматически при рендеринге их родительских блоков. Вызывать методparse()для блоковIF/FORв PHP-коде не нужно.
8.5.4. Получение HTML-кода и вывод
- Метод
$t->text('MAIN')возвращает сгенерированный HTML-код в виде PHP-строки (удобно для передачи HTML в буфер или кэш). - Метод
$t->out('MAIN')выводит сгенерированный блок напрямую в поток вывода (браузер).
8.6. Переопределение и кастомизация TPL модулей и плагинов
В Seditio CMS реализован гибкий механизм кастомизации визуального стиля плагинов и модулей без изменения их системного кода.
8.6.1. Приоритеты переопределения шаблонов плагинов
При вызове шаблона плагина (в его direct, standalone или popup частях) ядро выполняет поиск файла .tpl в следующем приоритетном порядке:
- Каталог активной темы (скина):
/skins/{имя_активного_скина}/plugins/{код_плагина}.tpl(наивысший приоритет — позволяет верстальщику переопределить стандартный вид плагина под дизайн конкретной темы). - Каталог плагина по умолчанию:
/plugins/{код_плагина}/tpl/{код_плагина}.tpl(базовый шаблон, поставляемый разработчиком плагина).
Для реализации этого поиска в коде плагина вызов шаблона должен осуществляться через функцию sed_skinfile():
// Загрузит шаблон из скина, если он там есть, иначе из папки плагина
$t = new XTemplate(sed_skinfile('myplugin', true));
Второй аргумент true указывает функции sed_skinfile, что ищется шаблон плагина.
8.6.2. Кастомизация шаблонов модулей
Шаблоны страниц и списков контента в модуле page могут гибко переопределяться для разных категорий сайта:
- Если в скине создан файл
page.news.tpl, модуль страниц автоматически подключит его для отображения контента категорииnews. - Если специального файла категории нет, модуль подключит стандартный шаблон
page.tpl.
8.7. Практическое руководство по созданию скина
Для создания новой темы оформления (скина) в Seditio CMS необходимо придерживаться структуры стандартного скина sympfy. Рассмотрим процесс создания темы с кодовым именем mytheme.
8.7.1. Структура файлов скина
Создайте в папке /skins/ каталог mytheme/. Внутри него расположите следующие папки и файлы:
mytheme.php— конфигурационный файл темы и метаданные.mytheme.ru.lang.php— файл русской локализации интерфейса темы.mytheme.png— превью скина для панели администратора (рекомендуемый размер — 240x180 пикселей).header.tpl— общая шапка сайта.footer.tpl— общий подвал сайта.index.tpl— шаблон главной страницы.css/style.css— основной файл стилей.js/— каталог для JavaScript-скриптов.
[!NOTE] Скин в Seditio CMS не обязан содержать шаблоны модулей (например,
page.tpl,forums.tpl,users.tpl). Если они отсутствуют в папке скина, система автоматически подгрузит стандартные шаблоны из каталогов самих модулей (например,/modules/page/tpl/page.tpl).
8.7.2. Конфигурация темы (mytheme.php)
Этот файл содержит обязательный информационный блок SED для движка и переопределяет глобальные массивы настроек пагинации, хлебных крошек и масок плагинов:
<?php /* ==================== Seditio - Website engine Copyright © Seditio Team https://seditio.org [BEGIN_SED] File=skins/mytheme/mytheme.php Version=1.0.0 Updated=2026-jul-06 Type=Skin Name=My Custom Theme Author=Developer Url=https://mysite.com Description=My custom responsive skin for Seditio CMS [END_SED] ==================== */ // Переопределение стилей пагинации $cfg['pagination'] = '<li class="page-item">%s</li>'; $cfg['pagination_cur'] = '<li class="page-item active"><span class="page-link">%s</span></li>'; $cfg['pagination_arrowleft'] = '<i class="icon-chevron-left"></i>'; $cfg['pagination_arrowright'] = '<i class="icon-chevron-right"></i>'; // Настройка разделителя хлебных крошек $cfg['separator'] = '<i class="icon-arrow-right"></i>'; // Иконки элементов интерфейса (поддерживаются Font Awesome или другие иконочные шрифты) $out['ic_arrow_up'] = '<i class="icon-arrow-up"></i>'; $out['ic_folder'] = '<i class="icon-folder"></i>'; $out['ic_checked'] = '<i class="icon-check"></i>'; $out['ic_close'] = '<i class="icon-close"></i>'; // Маски вывода плагина RecentItems (недавние публикации) $cfg['plu_mask_pages'] = '<span class="date">%3\$s</span> %1\$s ' . $cfg['separator'] . ' %2\$s<br />'; $cfg['plu_mask_comments'] = '<span class="date">%3\$s</span> %1\$s ' . $cfg['separator'] . ' %2\$s (%4\$s)<br />';
8.7.3. Локализация темы (mytheme.ru.lang.php)
Файл содержит переводы статических фраз интерфейса темы, сгруппированные в массив $skinlang по именам шаблонов:
<?php /* ==================== [BEGIN_SED] File=skins/mytheme/mytheme.ru.lang.php Version=1.0.0 Updated=2026-jul-06 Type=Skin Name=My Custom Theme (Russian Localization) [END_SED] ==================== */ // Локализация для header.tpl $skinlang['header']['Login'] = "Вход на сайт"; $skinlang['header']['Register'] = "Регистрация"; $skinlang['header']['Lostyourpassword'] = "Забыли пароль?"; // Локализация для index.tpl $skinlang['index']['Newinforums'] = "Новое на форумах"; $skinlang['index']['Recentadditions'] = "Последние обновления"; $skinlang['index']['Online'] = "Сейчас на сайте";
В шаблонах темы локализованные фразы выводятся через теги глобального массива: {PHP.skinlang.header.Login} или {PHP.skinlang.index.Online}.
8.7.4. Базовая верстка файлов темы
[!IMPORTANT] Автоматическое подключение шапки и подвала: В Seditio CMS шаблоны шапки (
header.tpl) и подвала (footer.tpl) подключаются контроллерами ядра автоматически (через выполнение скриптов/system/header.phpи/system/footer.phpперед и после рендеринга основного шаблона). В файлах страниц (таких какindex.tpl,page.tplи др.) не нужно вручную использовать директиву{FILE ...}для подключения шапки и подвала.
Шапка сайта (header.tpl)
<!-- BEGIN: HEADER -->{HEADER_DOCTYPE}
<html>
<head>
<title>{HEADER_TITLE}</title>
{HEADER_METAS}
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="skins/{PHP.skin}/css/style.css" type="text/css" rel="stylesheet" />
{HEADER_CSS}
</head>
<body>
<!-- BEGIN: USER -->
<div class="userpanel">
<ul>
<li><span>{HEADER_LOGSTATUS}</span></li>
<!-- IF {HEADER_USER_ADMINPANEL} -->
<li>{HEADER_USER_ADMINPANEL}</li>
<!-- ENDIF -->
<!-- IF {HEADER_USER_PROFILE} -->
<li>{HEADER_USER_PROFILE}</li>
<!-- ENDIF -->
<!-- IF {HEADER_USER_LOGINOUT} -->
<li>{HEADER_USER_LOGINOUT}</li>
<!-- ENDIF -->
</ul>
</div>
<!-- END: USER -->
<header class="main-header">
<div class="logo">
<a href="{PHP.sys.dir_uri}" alt="{HEADER_TITLE}">{PHP.cfg.maintitle}</a>
</div>
<div class="menu">
{PHP.sed_menu.1.childrens}
</div>
</header>
<!-- END: HEADER -->
Подвал сайта (footer.tpl)
<!-- BEGIN: FOOTER -->
<footer class="main-footer">
<div class="copyright">{FOOTER_BOTTOMLINE}</div>
<div class="stats">
{FOOTER_CREATIONTIME}<br />{FOOTER_SQLSTATISTICS}
</div>
{FOOTER_DEVMODE}
</footer>
{FOOTER_JAVASCRIPT}
</body>
</html>
<!-- END: FOOTER -->
Главная страница (index.tpl)
<!-- BEGIN: MAIN -->
<div class="content-wrapper">
<section class="intro">
<h1>{PHP.cfg.maintitle}</h1>
<p>{PHP.cfg.subtitle}</p>
</section>
<aside class="sidebar-box">
<h3>{PHP.skinlang.index.Online}</h3>
<p><a href="{PHP.out.whosonline_link}">{PHP.out.whosonline}</a> : {PHP.out.whosonline_reg_list}</p>
</aside>
</div>
<!-- END: MAIN -->
Comments: (0)