Главный шаблон сайта на тегах
Главный шаблон — рамка каждой страницы: шапка, меню, место для содержимого, боковая колонка и подвал. Пишется обычной разметкой с тегами, без PHP.
Главный шаблон — рамка каждой страницы: шапка, меню, место для содержимого, боковая колонка и подвал. Положите файл layouts/main.tpl.html в views/ своей темы (themes/<имя>/views/layouts/main.tpl.html), и страница строится по нему. Файла нет или он сломан — работает обычный вид, сайт не ломается. <head>, скрипты движка и кнопка «наверх» остаются от движка: стили и шрифты подключайте через theme.json и assets.
Готовый образец: шапка, меню, колонка, подвал
<header class="site-head"><div class="wrap">
<a class="brand" href="{home}"><span class="brand-name">{site_name}</span></a>
{languages} {search}
[if:user.logged]<a href="{user.url}">{user.name}</a> {logout_button}[else]<a href="{user.login_url}">Войти</a>[/if]
</div><div class="wrap"><nav class="nav">[each:menu]<a href="{item.url}">{item.title}</a>[/each]</nav></div></header>
<main id="content" class="wrap has-side">
<div>{content}</div>
<aside class="side-col region region--side">{region:sidebar}</aside>
</main>
<footer class="site-foot"><div class="wrap">© {year} {site_name}</div></footer>Классы site-head, wrap, brand, nav, has-side, side-col, site-foot — готовые классы общего оформления движка: с ними образец сразу выглядит как часть сайта и подстраивается под цвета темы.
Что видно на телефоне (390). Колонка уходит под содержимое, поиск раскрывается под шапкой. Меню разделов в образце выше на телефоне не показывается: кнопка меню в него не вошла. Теперь для неё есть тег {menu_toggle}: поставьте его в шапку вместо строки <nav class="nav">…[each:menu]…</nav> — на телефоне появится кнопка «Меню».
Что выводят теги
| Тег | Что выводит | Пример |
|---|---|---|
{site_name} | название сайта из «Настройки → Общие» | <a href="{home}">{site_name}</a> |
{home} | адрес главной | <a href="{home}"> |
{year} | текущий год | © {year} |
{locale} | код языка страницы | {locale} |
{canonical} | основной адрес этой страницы | <link rel="canonical" href="{canonical}"> |
{theme} | адрес папки файлов темы (assets) | <img src="{theme}/img/logo.svg"> |
{content} | содержимое страницы (запись, магазин, форум…) в контейнере движка: не вылезает за ширину экрана, годится для кабинета, форума и форм | <main>{content}</main> |
{content_raw} | то же содержимое без обёртки и без ограничения ширины: только для своих полностраничных раскладок; для кабинета, форума и форм берите {content} | <div class="full">{content_raw}</div> |
{languages} | выбор языка (готовый блок) | {languages} |
{search} | строка поиска (готовый блок) | {search} |
{login} | блок «Войти / Регистрация» или имя вошедшего (готовый) | {login} |
{poll} | текущий опрос сайта | {poll} |
{logout_button} | кнопка «Выйти» с ключом защиты | [if:user.logged]{logout_button}[/if] |
{menu_toggle} | кнопка «Меню» и меню разделов, которое на телефоне открывается кнопкой | {menu_toggle} |
{user_menu} | меню участника: профиль, сообщения, панель, выход | [if:user.logged]{user_menu}[/if] |
{region:header}, {region:before_content}, {region:sidebar}, {region:after_content}, {region:footer}, {region:head_actions} | блоки модулей, поставленные в это место темы | <aside>{region:sidebar}</aside> |
[each:menu]…[/each] | пункты меню сайта; внутри {item.title}, {item.url}, {item.active} | [each:menu]<a href="{item.url}">{item.title}</a>[/each] |
Про вошедшего посетителя
| Тег | Что выводит | Пример |
|---|---|---|
[if:user.logged]…[else]…[/if] | разный текст гостю и вошедшему | [if:user.logged]Привет![else]Войдите[/if] |
{user.name}, {user.url} | имя и адрес профиля | <a href="{user.url}">{user.name}</a> |
{user.avatar} | адрес аватара; пусто, если аватара нет | [if:user.avatar]<img src="{user.avatar}">[/if] |
{user.role} | название роли | {user.role} |
{user.pm_unread} | число непрочитанных личных сообщений; пусто, если модуль выключен | [if:user.pm_unread]Писем: {user.pm_unread}[/if] |
{user.favorites_count} | число закладок | {user.favorites_count} |
{user.pm_url}, {user.favorites_url} | адреса сообщений и закладок | <a href="{user.pm_url}">Сообщения</a> |
{user.admin_url}, [if:user.can_admin]…[/if] | адрес панели и условие «в панель пускают» | [if:user.can_admin]<a href="{user.admin_url}">Панель</a>[/if] |
{user.login_url}, {user.register_url}, {user.forgot_url} | адреса входа, регистрации, восстановления | <a href="{user.register_url}">Регистрация</a> |
Где мы и кто пришёл
Считаются только те теги, на которые файл ссылается: страница без них ничего не тратит.
| Тег | Что выводит | Пример |
|---|---|---|
{page.title}, {page.description} | название и описание этой страницы (как в <head>) | <h1>{page.title}</h1> |
{page.route}, [if:page.home] | имя маршрута страницы и условие «это главная» | [if:page.home]…[else]…[/if], [if:page.route=news.show]…[/if] |
{page.path} | адрес страницы без домена | {page.path} |
[if:module.имя] | модуль включён (любое имя из папки modules) | [if:module.shop]<a href="/shop">Магазин</a>[/if] |
{category.title}, {category.url}, {category.key} | текущая рубрика, если модуль её назвал | [if:category.title]<a href="{category.url}">{category.title}</a>[/if] |
[each:crumbs] {item.title} {item.url} [if:item.last] | хлебные крошки: «Главная» + цепочка модуля (или пункт меню этой страницы); последний пункт помечен last | [each:crumbs][ifnot:item.last]<a href="{item.url}">{item.title}</a> › [else]{item.title}[/ifnot][/each] |
{visitor.country} | код страны посетителя («UA»); из заголовка CDN или локальной базы адресов; пусто, если неизвестна | [if:visitor.country=UA]…[/if] |
[if:visitor.mobile], [if:visitor.tablet], [if:visitor.desktop], {visitor.device} | тип устройства по строке браузера | [if:visitor.mobile]{menu_toggle}[/if] |
{propose_url} | ссылка «Предложить запись»; пусто, если модуль или настройка выключены | [if:propose_url]<a href="{propose_url}">Предложить запись</a>[/if] |
{social_login} | готовые кнопки «Войти через …» (только включённые сети; ключей приложения на странице нет); пусто, если сетей нет | <div class="soc">{social_login}</div> |
[if:social.google], {social.google.url}, {social.google.title} | вход через конкретную сеть (google, github, yandex, vk): включена ли, адрес начала входа и название — кнопку можно поставить в свою разметку | [if:social.google]<a class="btn-g" href="{social.google.url}">{social.google.title}</a>[/if] |
[if:social.any] | включена ли хоть одна сеть | [if:social.any]или[/if] |
{social_profile} | блок «Привязанные сервисы» для кабинета: привязать и отвязать по паролю; гостю пусто | {social_profile} |
{user.field:имя} | своё поле профиля вошедшего (поле заводит владелец); гостю, выключенному и несуществующему полю — пусто; значение экранируется | <p>Город: {user.field:city}</p> |
Рубрику и цепочку разделов называет модуль: кладёт в общие данные вида (View::share) ключ pageContext — ['category' => ['title' => '…', 'url' => '/r/…', 'key' => '…'], 'crumbs' => [['title' => '…', 'url' => '/…']]] — или добавляет их фильтром theme.page_context. Адрес берётся только свой («/…»).
Условия и повторы
[if:имя]…[/if] — показать, если значение есть; [ifnot:имя]…[/ifnot] — если нет; [if:имя=значение]…[else]…[/if] — сравнение; [each:список]…[/each] — повтор по списку с {item}, {item.ключ}, {index}. Значения из данных страницы доступны по имени; у каждого вида свои (страница «Виды на тегах»).
Безопасность
PHP, include и вызов функций в файле тегов не работают; разметка очищается по белому списку (без script, style, iframe, обработчиков событий и data-*); адреса только http(s)://, /путь, #; к ссылкам из шаблона движок добавляет rel="noopener". Значения экранируются. Пределы: 20000 знаков, 400 тегов, вложенность 6, повторов 60.
Обновлено 16.10.2026
Пока никто не высказался. Будьте первым.