Timberdocs

Developers

Extending Timber

Timber has no plugin API. You extend it by editing the code, which is small and readable on purpose. Here are the common extension points.

Add an admin screen#

  1. Create padmin/views/yourthing.php:
<?php
if ($action === 'save' && admin_is_post()) {
    save_settings('mything', ['name' => input('name')]);
    notify('Saved');        // toast via HX-Trigger
    exit;
}
admin_page('Your thing', function () { ?>
    <form hx-post="<?= admin_url('yourthing/save') ?>" hx-swap="none" class="stack">
        <?php admin_field('name', 'Name', settings('mything.name')) ?>
        <button class="btn btn-primary btn-save">Save</button>
    </form>
<?php }, ['section' => 'yourthing']);
  1. Register it in $routes in padmin/index.php.
  2. Add a nav entry to $nav in padmin/views/_layout.php.

Helpers include admin_field, admin_toggle, media_field, editor_field, code_field, admin_go, notify, save_settings, unique_slug, seo_panel, status_badge and admin_icon.

Add a collection#

Pick a name and use collection() / save_record() / delete_record(). Register it in DATA_LISTS (or DATA_OBJECTS) in padmin/views/data.php so the data browser and export understand it.

Add a public route#

Add a case above the page-slug fallback in index.php, and add the first segment to the reserved slug lists (unique_slug() in padmin/lib.php, REDIRECT_RESERVED in views/redirects.php).

Add an integration#

Each integration is one small file in inc/integrations/{id}.php returning a definition: a name, the module it serves (analytics, email, notifications, support), an icon, a docs link, the fields to collect (text or secret), and an optional verify callable. See brevo.php and google-analytics.php for examples. Non-secret values go to settings; secret ones to data/secrets.json.

Add a theme#

See Building themes.

Add a content converter#

The WordPress migrator is source-agnostic after parsing: any parser that writes the same items.ndjson records can reuse the import, menu, redirect, media and undo pipeline — a good starting point for Ghost, Squarespace or Jekyll importers.

Conventions#

  • Escape output with e(); JSON inside <script> uses json_encode(..., JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT).
  • Prefix new admin helpers with admin_ — shared hosts sometimes define short global function names like go().
  • Build URLs with url(), href(), asset(), media_url(), abs_url().
  • Never bypass CSRF. Plain forms need a hidden _csrf field.
  • Keep the three principles: no build step, no required service, settings over code.
Timber is open source. Built by indies, for indies. © 2026