The site’s main template on tags
The frame of every page without PHP: plain markup and tags for the header, menu, content, sidebar and footer.
The main template is the frame of every page: header, menu, a place for the content, the sidebar and the footer. Put the file layouts/main.tpl.html into views/ of your theme (themes/NAME/views/layouts/main.tpl.html) and the page is built from it. If the file is missing or broken, the ordinary view works and the site does not break. The page head, the engine’s scripts and the “to top” button stay with the engine: connect styles and fonts through theme.json and assets.
A ready sample: header, menu, sidebar, footer
<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}">Sign in</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>The classes site-head, wrap, brand, nav, has-side, side-col, site-foot are ready classes of the engine’s common styling: with them the sample looks like part of the site at once and follows the theme colours.
On a phone. The sidebar moves under the content, search opens under the header. The section menu in the sample’s row is not shown on a phone; put the {menu_toggle} tag into the header instead of the nav row — a “Menu” button appears on a phone and opens the menu with sections, while on a computer the menu stands in the header row.
What the tags print
| Tag | What it prints |
|---|---|
{site_name} | the site name from “Settings → General” |
{home} | the home page address |
{year} | the current year |
{locale} | the page language code |
{canonical} | the main address of this page |
{theme} | the address of the theme files folder (assets), for example {theme}/img/logo.svg |
{content} | the page content (entry, shop, forum…) in the engine’s container: it does not overflow the screen width and suits the account, forum and forms |
{content_raw} | the same without the wrapper and the width limit: only for your own full-page layouts; for the account, forum and forms use {content} |
{languages} | language choice (a ready block) |
{search} | the search box (a ready block) |
{login} | the “Sign in / Register” block or the signed-in name (ready) |
{poll} | the site’s current poll |
{logout_button} | the “Sign out” button with a protection key |
{menu_toggle} | the “Menu” button and the section menu that opens by the button on a phone |
{user_menu} | the member menu: profile, messages, panel, sign out |
{region:header} {region:before_content} {region:sidebar} {region:after_content} {region:footer} {region:head_actions} | module blocks placed into this spot of the theme |
[each:menu]…[/each] | the site menu items; inside, {item.title}, {item.url}, {item.active} |
About the signed-in visitor
| Tag | What it prints |
|---|---|
[if:user.logged]…[else]…[/if] | different text for a guest and a signed-in person |
{user.name} {user.url} | the name and the profile address |
{user.avatar} | the avatar address; empty if there is no avatar |
{user.role} | the role name |
{user.pm_unread} | the number of unread private messages; empty if the module is off |
{user.favorites_count} | the number of bookmarks |
{user.pm_url} {user.favorites_url} | the addresses of messages and bookmarks |
{user.admin_url}, [if:user.can_admin]…[/if] | the panel address and the condition “allowed into the panel” |
{user.login_url} {user.register_url} {user.forgot_url} | the addresses of sign-in, registration, recovery |
{user.field:name} | the signed-in person’s own profile field (the owner creates the field); empty for a guest, a disabled and a non-existent field; the value is escaped |
Where we are and who came
Only the tags the file refers to are computed: a page without them spends nothing.
| Tag | What it prints |
|---|---|
{page.title} {page.description} | the title and description of this page (as in the page head) |
{page.route}, [if:page.home] | the page’s route name and the condition “this is the home page”, for example [if:page.route=news.show]…[/if] |
{page.path} | the page address without the domain |
[if:module.name] | the module is on (any name from the modules folder), for example [if:module.shop]…[/if] |
{category.title} {category.url} {category.key} | the current category, if the module named it |
[each:crumbs] {item.title} {item.url} [if:item.last] | breadcrumbs: “Home” + the module’s chain (or this page’s menu item); the last item is marked last |
{visitor.country} | the visitor’s country code (“UA”); from a CDN header or a local address database; empty if unknown |
[if:visitor.mobile] [if:visitor.tablet] [if:visitor.desktop] {visitor.device} | the device type by the browser string |
{propose_url} | the “Suggest an entry” link; empty if the module or the setting is off |
{social_login} | ready “Sign in with …” buttons (only enabled networks; no app keys on the page); empty if there are no networks |
[if:social.google] {social.google.url} {social.google.title} | sign-in through a particular network (google, github, yandex, vk): whether it is on, the sign-in start address and the name — the button can be put into your own markup |
[if:social.any] | whether at least one network is on |
{social_profile} | the “Linked services” block for the account: link and unlink by password; empty for a guest |
The category and the chain of sections are named by the module: it puts the key pageContext into the shared view data (category with title, url, key and crumbs — a list with title and url) or adds them with the theme.page_context filter. Only the site’s own address is accepted — a path from the root.
Conditions and loops
[if:name]…[/if] shows if the value exists; [ifnot:name]…[/ifnot] if it does not; [if:name=value]…[else]…[/if] compares; [each:list]…[/each] repeats over a list with {item}, {item.key}, {index}. Values from the page data are available by name; each view has its own.
Safety
PHP, include and function calls do not work in a tag file; the markup is cleaned by an allow-list (no script, style and iframe tags, no event handlers and data-*); addresses only http(s)://, a path from the root and #; the engine adds rel="noopener" to links from the template. Values are escaped. Limits: 20000 characters, 400 tags, nesting 6, repeats 60.