Accent

Template API

The `cms` object every template renders with — the asset, queries over the site, outputs as values.


Every topic

The asset

cms.asset — the asset this template renders, its shape, and the gates applied before a template sees it.

Queries

cms.assets.get / find / all — the query surface over the whole site, and the row shape it returns.

Outputs

Output handles — a named projection as a value that knows its address and can render itself.

Every template Accent renders — a document template, a layout, a partial, a type's fragment renderer — is EJS with one object in scope: cms. It is the CMS's own API for templates, the same in dev and in production, and it never depends on which engine renders the file. This section is its reference: what cms holds, what an asset looks like from a template, how to query the site, and how outputs read as values.

Vocabulary. An asset is an instantiated content type — the one noun for every instance. A page is a role, not a kind: an asset whose type has a document output at an IA address. A section is a role too: an asset placed inside a page's document. cms.asset is always the asset this template is rendering; nothing hangs off a "page" object any more.

The cms object

Key What it is Where it exists
cms.asset the asset this template renders — The asset every render
cms.assets the query surface over the whole site — Queries every render
cms.site { label, display_name } — the site's display label twice, for the two spellings templates already use every render
cms.locale the request locale: the asset's own locale, else the site default (en, fr, …) every render
cms.partial inside a partial's own render, that partial's context: { id, data, attrs } partial and fragment renders
cms.media the media permalink being rendered (src, permalink, prev, next, …) media permalink pages only

Two names you will meet in older files and must not write anew: cms.page is retired — the write boundary rejects a template that introduces it and the boot log flags any that remain; and cms.partial() as a function (the entity mount) is deprecated in favour of composition data — see Including templates.

What else is in scope

A document template (the file a page renders through) also receives plain locals beside cms:

  • content — the rendered page body, placed with <%- content %> or by marking an element data-accent-content (see the content region).
  • head values — meta_title, meta_description, canonical_url, robots_content, the og_* set, twitter_card, hreflang_alternates.
  • theme plumbing — theme_css, theme_js, include_theme_js, include_htmx_js, htmx_js_url, assets_root, document_base_url.
  • editor plumbing — cms_edit_url (the admin address of this page when the viewer may edit), accent_island_boot.

A partial or fragment renderer receives its field values as plain locals as well (<%= headline %>), and when it renders a mounted asset — a fragment view, a placed record, a section — cms.asset is that asset and content is its children's HTML. Options arrive both as locals and as cms.asset.options, so a renderer can read either.

Files are composed with require() and include(); that grammar has its own page, Including templates.

Reading the code

<h1><%= cms.asset.title %></h1>
<p class="mk-eyebrow"><%= cms.asset.content.tagline %></p>

<% cms.assets.find({ type: 'post', under: cms.asset.path, sort: '-publishedAt', limit: 3 })
     .forEach(function (post) { %>
  <a href="<%= post.url %>"><%= post.title %></a>
<% }) %>

<% var home = cms.assets.get('') %>
<a href="<%= home ? home.url : '/' %>"><%= cms.site.display_name %></a>

Everything a template reads is a value — decoded field values, portable URLs, rows — never a store handle or a live query object. Public renders see published content only; the editor and preview lanes see drafts. That gate is applied once, at the seam where values are built, so a template never branches on it.

Not yet

Reaching the page from inside a section (cms.asset.root, cms.asset.parents) and walking the IA by identity are specified but unbuilt; the design and the decisions still open are in the engineering canon, Template ancestry. Until then, home is cms.assets.get('') and an ancestor is cms.assets.get(<its path>).

Deep records

  • The runtime API — cms.asset — the settled shape and its rules.
  • Field namespaces — the render address is the same shape — why cms.asset.data.<namespace>.<field> mirrors storage.
  • RULED: a mounted fragment renders an asset — cms.asset inside a mount.
  • Content lanes — where values live and the sixteen seams that wake them into locals.
  • Page queries and metadata — the query surface's history.
  • Template ancestry — the planned root / parents / cms.site.root grammar.