Concepts

Templates and shortcodes

How a page is assembled from small templates and shortcodes, and how templates are found.

Templates use shortcodes enclosed in [# and #].

[#shortcode#]
[#shortcode param#]
[#shortcode key=value key2=value2#]

Shortcodes can be nested - any parameter value or shortcode name can itself contain a shortcode:

[#get data.users.[#get selected-id#]#]

This also works inside tpl= parameters and shortcode names, which lets you compose template names dynamically:

[#if current_image=(not-empty) tpl=card-image[#if current_image=(empty) echo=-placeholder#]#]

Resolves to tpl=card-image when an image exists, tpl=card-image-placeholder when it doesn't.

A particularly powerful application is content-type dispatch - embed a type field directly in the shortcode name to route to a type-specific template without any branching:

[#card-[#get item.type#]#]

Resolves to [#card-news#], [#card-event#], [#card-download#], etc. based on the item's type. This pattern eliminates chains of [#if item.type=X tpl=Y#] conditions and scales cleanly as new types are added.

Use default= to guarantee a valid shortcode name when the value may be missing or unrecognised - an unresolved shortcode renders as literal text in the output:

[#card-[#get item.type default=unknown#]#]

Implement [#card-unknown#] as a generic fallback (or leave it empty to render nothing).

Templates are plain files in the target output format (HTML, JSON, CSS, etc.). They have a .tpl extension.

Route templates

Every URL maps to a file in ext/uri/:

ext/uri/index.tpl              → /
ext/uri/about/index.tpl        → /about/
ext/uri/blog/(slug)/index.tpl  → /blog/<anything>/

A route template renders the page:

[#html#]

The main.tpl in the same folder contains the page body, rendered inside the HTML shell. It is always scoped to that route - even ext/uri/main.tpl is only the body for the home page (/), not a global layout.

Reusable templates

Stored in ext/tpl/<name>/index.tpl. Called with their name as a shortcode:

[#hero-section#]

Template components do not receive parameters directly. To pass data to a template, use [#set ... overwrite#] before calling it:

[#set back_url=/agenda overwrite#]
[#back-button#]

Inside the template, read the variable with [#get back_url default=/#]. Lib shortcodes (ext/lib/<name>/) are different - they receive $params and can be called with inline parameters.

URI-scoped templates

Templates can also live flat inside a URI folder (not in a subfolder). These are not routes - they are partial templates included from within that route's index.tpl or main.tpl.

ext/uri/new/page-settings-fields.tpl   ← partial, not a route
ext/uri/new/index.tpl                  ← route
ext/uri/new/main.tpl                   ← route body

Important: a subfolder inside ext/uri/ always creates a new route. A flat .tpl file in a URI folder is a partial template scoped to that route.

View this page as Markdown