Beta documentation. This is an early preview — content is still in active development. Feedback helps shape the final release. Share your thoughts or join the discussion.

Inheritance & Includes

Every page shouldn't copy-paste ``, ``, ``, ``. Create one base template, extend it everywhere.

On this page

Don't repeat your layout

Every page shouldn't copy-paste <html>, <head>, <nav>, <footer>. Create one base template, extend it everywhere.

Base template (layout)

Save this as a DB page named "layout":

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>{% block title %}My Site{% endblock %}</title>
    <link rel="stylesheet" href="/style.css">
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/blog">Blog</a>
        <a href="/about">About</a>
    </nav>

    <main>
        {% block content %}{% endblock %}
    </main>

    <footer>
        <p>&copy; {{ "now"|date("Y") }} My Site</p>
    </footer>
</body>
</html>

Child template (home page)

Save as DB page "home":

{% extends "layout" %}

{% block title %}Home — My Site{% endblock %}

{% block content %}
    <h1>Welcome</h1>
    <p>{{ introduction }}</p>
{% endblock %}

The child replaces only the blocks it defines. Everything else comes from the parent.

How references resolve

When you write {% extends "layout" %}, Twig searches for "layout" in this order:

  1. Database pages — looks for a page named "layout"
  2. Inline templates — templates defined with app:set_template("layout", ...)

This means you can mix DB-backed pages with inline templates freely.

Including partials

Break large templates into small, reusable pieces:

{% include "header" %}
{% include "sidebar" with { menu: nav_items } %}
{% include "footer" %}

Each include gets its own scope. Pass variables explicitly with with.

Building a macro library

Macros are reusable functions inside templates. Create a page "macros":

{% macro input(name, label, type, value) %}
    <div class="form-group">
        <label for="{{ name }}">{{ label }}</label>
        <input type="{{ type|default('text') }}"
               name="{{ name }}"
               id="{{ name }}"
               value="{{ value|e }}">
    </div>
{% endmacro %}

{% macro button(text, class) %}
    <button class="btn {{ class|default('btn-primary') }}">{{ text }}</button>
{% endmacro %}

Use them in any template:

{% from "macros" import input, button %}

<form method="post">
    {{ input("email", "Email address", "email", old.email) }}
    {{ input("password", "Password", "password") }}
    {{ button("Sign In", "btn-large") }}
</form>

Complete multi-page architecture

DB Pages:
  "layout"     → type=0: base HTML layout with blocks
  "home"       → type=0: {% extends "layout" %}, home page content
  "blog_list"  → type=0: {% extends "layout" %}, blog listing
  "post"       → type=0: {% extends "layout" %}, single post
  "macros"     → type=0: reusable form helpers
  "header"     → type=0: reusable site header partial

  "blog_list"  → type=29: Lua handler (fetches posts, calls ctx:render)
  "blog_post"  → type=29: Lua handler (fetches single post)

Even a complex site uses the same few patterns — extend, include, render.

Next: Forms & CSRF — secure forms with flash messages.

Previous Twig Syntax Next Forms & CSRF Protection