Built with Chinaski

Blocks in Themes

Block templates live at builder/block_templates/ and are what turns a block’s data into HTML. This page shows you exactly how the builder wires block types into templates, and what your theme or a new block type can expect.

The resolution pipeline

For every block, the builder runs one subroutine that decides the entire output:

  1. Cycles are caught first. A block that re-references itself renders a comment marker instead of an infinite recursion.
  2. Language lookup with fallback: the block is fetched by name in the page’s language; when missing, the default-language version of the same name is used instead. A block found in neither language becomes a “not found” HTML comment; it breaks nothing.
  3. Variables come prepared. The block’s row is passed to its template as-is: all scalar columns become template variables, and its content_json is decoded into content_data (array or hash, depending on the type).
  4. Placement overrides win. Any per-placement override (a stack assignment’s overrides, for example) merges over the block’s stored fields before rendering.
  5. Type-aware glue code runs. Some types get extra context before their template runs:
    • page_list with a parent set publishes a pages array of the children under that parent, with an auto-generated “Also in ” heading when none is set
    • newsletter and form blocks embed the configured form’s fields and route submissions to the forms system
    • document blocks load the referenced document record, with which detail rows to show passed in as booleans (show_thumbnail, show_description, show_size, show_download_count, show_date)
    • faq blocks get a JSON-LD structured-data fragment precomputed and escaped for safety
    • columns and grid blocks resolve {{block:…}} shortcodes inside their cells so nested blocks work there too
  6. Images auto-enrich. If the block’s image URL matches an uploaded media file with responsive derivatives, image_srcset_jpg / image_srcset_webp arrive in the template prebuilt for <img srcset>-style output.
  7. Errors stay trapped. A render error in a block’s own template renders a “render error” comment rather than aborting the entire page.

Where blocks get placed

  • In page and post bodies: via the {{block:name}} shortcode resolved inline at build time; everything your theme’s page.tt / post.tt / blog_index.tt / landing.tt receives has block HTML already rendered.
  • In stacks: stacks compose several blocks into one fragment; the fragment renders with its own container id and its layout id (used by stacks in themes for targeted styling). Stacks can also contain nested stacks, with the same cycle guard.
  • Your templates see printed HTML, not raw block objects: the body var a template gets has shortcodes already replaced.

What a block template looks like

Every block type has exactly one Template Toolkit file: builder/block_templates/<type>.tt (e.g. cta.tt, gallery.tt). These files ship outside your theme; they describe a block’s markup and are the same for every theme, so your theme styles them by class name instead of changing their markup.

  • The template receives the block’s row variables plus content_data (decoded JSON), form field variables when a linked form is configured, and whatever type-specific enrichments above apply.
  • page_list, document, and similar “smart” blocks get their dependent data materialized in the template variables, so a theme only has to print fields.

The CSS contract

Your theme’s _head.tt must style every block type’s wrapper classes the templates emit. The built-in block reference tables document the wrapper and inner class for each type; the default theme’s stylesheet implements them exactly. An unstyled block still renders its HTML; it never breaks the build, it just looks unfinished in the browser.

Adding a new block type

The wiring recipe: three steps, with the Block Types registry as the gatekeeper:

  1. Register the type slug on the Block Types screen. That table decides which types are valid for create_block and block-type switching.
  2. Create builder/block_templates/<type>.tt: the rendering template. Get the variables and enrichment rules above correct and you’re most of the way there.
  3. Create templates/admin/blocks/types/<type>.html.ep: the admin form partial, which fills the flat fields and optionally a content_json row editor.

Escape user-controlled data when writing a template: HTML-escape everything by default; only embed bodies and the body fields inside accordion/columns content data are intended to carry raw HTML.

Putting blocks in custom theme templates

When you author a custom theme, you don’t re-embed blocks or invoke the resolver yourself; the builder resolves shortcodes in the body text before your template runs. Your theme just prints the body, which arrives as already-rendered HTML. If you want blocks-driven layouts everywhere, use stacks: they’re sequences of blocks with overridable content and conditional display rules, and they render as one unit per assignment.

Read this site in