Built with Chinaski

Template Files

A Chinaski theme is a directory of Template Toolkit files that the static builder renders into every page, post, blog index, feed, and error page. This page covers the template set and search rules; block templates and template variables each get more depth on linked pages, and the complete variable reference lives in the admin’s built-in Theme Authoring doc (Admin → Docs).

The site templates directory

Site templates live in builder/site_templates/ (or a theme directory override; see below). One file per page-shaped output, plus optionals:

File Rendered as
page.tt every published page (default)
post.tt every published post
blog_index.tt the paginated blog listings (+ per-category/author archives via the shared renderer)
landing.tt pages that select the landing template
404.tt the per-language 404 page
offline.tt PWA offline fallback page
_head.tt <head> partial (meta tags, canonical, JSON-LD)
_header.tt / _footer.tt site header/footer partials
_cookie_notice.tt optional consent banner
_sidebar.tt, _meta_tags.tt, _password_gate.tt other shared partials
<anything>.tt any page that selects that template by name

Conventions: files starting with _ are partials; they never render as standalone pages. Zero-viable requirements: pages can type a custom template name (landing.tt etc.) and the builder picks it from this directory (or from your active theme if it lives there first).

A starter’s skeleton is minimal:

<!DOCTYPE html>
<html lang="[% lang | html %]" dir="[% dir %]">
<head>
  [% INCLUDE '_head.tt' %]
</head>
<body>
  [% INCLUDE '_header.tt' %]
  <main>[% title | html %][% body %]</main>
  [% INCLUDE '_footer.tt' %]
</body>
</html>

The one deliberate non-escaping: [% body %] emits stored HTML on purpose; page authors are the trust boundary; don’t extend raw output to other fields.

Searching and fallback (themes tweak the default)

When a non-default theme is active, its directory is searched first and builder/site_templates/ second, so a theme only needs to ship what it customizes; missing files fall back to the built-ins automatically rather than failing a build.

Forking _head.tt rather than rewriting it is recommended: it already emits the full meta set (canonical, OG/Twitter, hreflang, JSON-LD, noindex, and analytics with consent gating) and the builder hand-computes those values for the template’s stash.

What each build renders

For each configured language the builder renders: published pages, published posts, the paginated blog index, per-category archives, the post feed (RSS), the sitemap, robots.txt, and the 404 page. Output is written file-by-file (with a wall-clock ceiling of 30 minutes and a 2 GiB write budget that abort safely past the cap), and any stale files from a previous run are removed.

A template render failure doesn’t stop the build: the failure is recorded in the build log and the loop continues. The dashboard names the first few failing templates; the first place to look at debugging is the builds screen.

The escape hatch: per-page templates

Every page’s editor has a template dropdown populated automatically from non-partial .tt files in the standard directory plus the active theme’s directory, and it always keeps the page’s currently-set template in the list even if that file belongs to an inactive theme, so a routine re-save can’t silently swap templates.

Snippets (injections with an audit trail)

A snippet is a hand-controlled chunk of HTML inserted verbatim at the bottom of <head> or before </body>: analytics, precedes, verification tags. They can be global (injected site-wide) or attached to individual pages/posts (also by tick-box in those editors). Since snippet content is injected verbatim, anyone with snippet-edit rights can install arbitrary JavaScript on every page. Treat it as server access.

Testing your theme

  1. Edit .tt files in the theme directory (or site_templates/ for core tweaks).
  2. Click Build on the dashboard (or run the builder by hand).
  3. Errors include the failing template name and a reason; the full log is in the Builds screen.

The build system catches template errors even in validation; failures record the file and error, not just a blanket “done”.

Security rules

  • Escape everything user-controlled with | html; the intentional exceptions are body (raw rich-text by design) and json_ld (pre-serialized, </script> already neutralized).
  • | uri to encode URL components; never concatenate raw values into hrefs or attributes.
  • Minimal inline scripts only: every inline script widens the break-glass surface.
  • Block field values arrive from admin forms unescaped; escape them.
  • Snippet access equals server access: whoever can edit snippets can run content on every page.
Read this site in