N1 Nex1on

Main site template with tags

The main template is the frame of every page: header, menu, content area, side column and footer. You write it in plain markup with tags, no PHP.

The main template is the frame of every page: header, menu, content area, side column and footer. Put the file layouts/main.tpl.html in the views/ folder 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 default view is used and the site keeps working. <head>, the engine scripts and the “back to top” button stay with the engine: connect styles and fonts through theme.json and assets.

Ready-made sample: header, menu, column, 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-made classes of the engine’s shared styling: with them the sample immediately looks like part of the site and follows the theme colors.

What you see on a phone (390). The column moves below the content and the search opens under the header. In the sample above, the section menu is not shown on a phone: the menu button is not part of it. There is now a tag for the button, {menu_toggle}: put it in the header instead of the line <nav class="nav">…[each:menu]…</nav> and a "Menu" button appears on the phone.

What the tags output

TagWhat it outputsExample
{site_name}the site name from “Settings → General”<a href="{home}">{site_name}</a>
{home}the home page address<a href="{home}">
{year}the current year© {year}
{locale}the language code of the page{locale}
{canonical}the main address of this page<link rel="canonical" href="{canonical}">
{theme}the address of the theme files folder (assets)<img src="{theme}/img/logo.svg">
{content}the page content (post, shop, forum…) in an engine container: it stays within the screen width and suits the account area, the forum and forms<main>{content}</main>
{content_raw}the same content without the wrapper and without the width limit: only for your own full-page layouts; for the account area, the forum and forms use {content}<div class="full">{content_raw}</div>
{languages}the language switcher (ready-made block){languages}
{search}the search box (ready-made block){search}
{login}the “Sign in / Register” block or the name of the signed-in user (ready-made){login}
{poll}the current poll of the site{poll}
{logout_button}the “Sign out” button with a protection key[if:user.logged]{logout_button}[/if]
{menu_toggle}the “Menu” button and the section menu, which opens with the button on a phone{menu_toggle}
{user_menu}the member menu: profile, messages, panel, sign out[if:user.logged]{user_menu}[/if]
{region:header}, {region:before_content}, {region:sidebar}, {region:after_content}, {region:footer}, {region:head_actions}module blocks placed in this spot of the theme<aside>{region:sidebar}</aside>
[each:menu]…[/each]the items of the site menu; inside, use {item.title}, {item.url}, {item.active}[each:menu]<a href="{item.url}">{item.title}</a>[/each]

About the signed-in visitor

TagWhat it outputsExample
[if:user.logged]…[else]…[/if]different text for a guest and a signed-in user[if:user.logged]Hello![else]Sign in[/if]
{user.name}, {user.url}the name and the profile address<a href="{user.url}">{user.name}</a>
{user.avatar}the avatar address; empty if there is no avatar[if:user.avatar]<img src="{user.avatar}">[/if]
{user.role}the role name{user.role}
{user.pm_unread}the number of unread private messages; empty if the module is off[if:user.pm_unread]Mail: {user.pm_unread}[/if]
{user.favorites_count}the number of bookmarks{user.favorites_count}
{user.pm_url}, {user.favorites_url}the addresses of messages and bookmarks<a href="{user.pm_url}">Messages</a>
{user.admin_url}, [if:user.can_admin]…[/if]the panel address and the condition "the user may enter the panel"[if:user.can_admin]<a href="{user.admin_url}">Panel</a>[/if]
{user.login_url}, {user.register_url}, {user.forgot_url}the sign-in, registration and password recovery addresses<a href="{user.register_url}">Sign up</a>

Where we are and who came

Only the tags that the file refers to are evaluated: a page without them spends nothing.

TagWhat it outputsExample
{page.title}, {page.description}the title and description of this page (as in <head>)<h1>{page.title}</h1>
{page.route}, [if:page.home]the route name of the page and the condition "this is the home page"[if:page.home]…[else]…[/if], [if:page.route=news.show]…[/if]
{page.path}the page address without the domain{page.path}
[if:module.name]the module is enabled (any name from the modules folder)[if:module.shop]<a href="/shop">Shop</a>[/if]
{category.title}, {category.url}, {category.key}the current category, if a module has named it[if:category.title]<a href="{category.url}">{category.title}</a>[/if]
[each:crumbs] {item.title} {item.url} [if:item.last]breadcrumbs: “Home” plus the module's chain (or the menu item of this page); the last item is marked last[each:crumbs][ifnot:item.last]<a href="{item.url}">{item.title}</a> › [else]{item.title}[/ifnot][/each]
{visitor.country}the visitor's country code (“UA”); taken from a CDN header or the local address database; empty if unknown[if:visitor.country=UA]…[/if]
[if:visitor.mobile], [if:visitor.tablet], [if:visitor.desktop], {visitor.device}the device type, detected from the browser string[if:visitor.mobile]{menu_toggle}[/if]
{propose_url}the “Suggest a post” link; empty if the module or the setting is off[if:propose_url]<a href="{propose_url}">Suggest a post</a>[/if]
{social_login}ready-made “Sign in with …” buttons (only for the networks that are on; the page contains no app keys); empty if there are no networks<div class="soc">{social_login}</div>
[if:social.google], {social.google.url}, {social.google.title}sign-in through a specific network (google, github, yandex, vk): whether it is on, the sign-in start address and the name; you can place the button in your own markup[if:social.google]<a class="btn-g" href="{social.google.url}">{social.google.title}</a>[/if]
[if:social.any]whether at least one network is on[if:social.any]or[/if]
{social_profile}the “Linked services” block for the account area: link and unlink with a password; empty for a guest{social_profile}
{user.field:name}a custom profile field of the signed-in user (the owner creates the field); empty for a guest, for a disabled field and for a field that does not exist; the value is escaped<p>City: {user.field:city}</p>

A module names the category and the chain of sections: it puts the key pageContext into the shared view data (View::share) — ['category' => ['title' => '…', 'url' => '/r/…', 'key' => '…'], 'crumbs' => [['title' => '…', 'url' => '/…']]] — or adds them with the filter theme.page_context. Only own addresses are accepted ("/…").

Conditions and loops

[if:name]…[/if] shows the part if the value exists; [ifnot:name]…[/ifnot] shows it 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 (see the page “Views on tags”).

Security

PHP, include and function calls do not work in a tag file; the markup is cleaned against an allowlist (no script, style, iframe, event handlers or data-*); addresses may only be http(s)://, /path or #; the engine adds rel="noopener" to links from the template. Values are escaped. Limits: 20000 characters, 400 tags, nesting depth 6, 60 repeats.

Обновлено 16.10.2026

На этой странице
Поделиться: Telegram WhatsApp
Откладывать можно и без входа: закладки сохранятся в этом браузере, а после входа их можно перенести в учётную запись. Вход
Обсуждение

Комментарии

Обсуждение ещё не началось

Пока никто не высказался. Будьте первым.

Пожаловаться на запись