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.

Updated 16.10.2026

On this page
Share: Telegram WhatsApp
You can save things without signing in: they stay in this browser and you can move them to your account after signing in. Sign in
Discussion

Comments

No discussion yet

No one has commented yet. Be the first.

Report this post