Template helpers
A template’s job is to turn a node into HTML. The helper API is how it does that — and, just as importantly, it’s the only bridge between your markup and the editor. When a template reads a value through a helper, that helper quietly emits the data-* attributes the editor needs to make the value editable. You never write those attributes by hand, and you can’t accidentally leave them out.
That’s the deal in one sentence: speak the helper conventions, and any markup you invent becomes editable for free; ignore them, and the value renders static. You decide what’s editable by choosing which helper to call.
Reading values
get_val('name') // "Fikkie" — raw value, no escaping
the_val('geo.latitude') // echoes the value, HTML-escaped
get_val / the_val give you the bare value (dot-notation walks nested objects). Use them for text that isn’t meant to be edited inline — an alt attribute, a computed class, a microcopy string.
Making values editable
<?php the_value('name', ['tag' => 'h1']) ?>
<?php the_value('description', ['tag' => 'p', 'class' => 'intro']) ?>
get_value / the_value wrap the value in a real element. For a visitor that’s just <h1>Fikkie</h1>. For an editor it’s the same element plus the inline attributes that let them click and type:
<h1 data-inline-name="name" data-inline-type="name"
data-inline-value="Fikkie" data-inline-dirty="false">Fikkie</h1>
When you need the attributes on an element you’re building yourself, use the_prop — it emits just the data-* string (empty for visitors, so it’s always safe to include):
<figure <?php the_prop('image', ['type' => 'image']) ?>>
<img src="<?= get_val('image.url') ?>" alt="<?= get_val('image.name') ?>">
</figure>
Composing blocks
block() renders one node inside another. Data comes first, template second — the data is required, the template optional (a node can name its own via @build):
<?= block($place, 'place-card') ?> // explicit template
<?= block($stop) ?> // uses the node's own @build
block() manages the context stack and stamps the wrapper with node-identity attributes automatically, so a card is editable the moment it’s rendered.
Lists
get_list / the_list turn a nested array into rendered, editable items. the_list() emits the <ol>/<li> scaffold with add/remove/reorder wired up; for a visitor it collapses to plain markup.
<?php foreach (the_list('mainEntity.itemListElement', [
'item-type' => 'Place',
'fields' => [['key' => 'name', 'label' => 'Naam']],
]) as $stop): ?>
<?php the_list_item($stop); ?>
<?= block($stop, 'stop') ?>
<?php end_list_item(); ?>
<?php endforeach; ?>
<?php end_list(); ?>
The three list types (curated, relational, queried) are covered in Lists & relations.
Media
get_media / the_media render media the way the_value renders a value and the_list renders a list: speak the helper, get a correctly-resolved, editable element for free.
<?php the_media('image') ?> // resolves the reference, renders an <img>
<?php the_media('video') ?> // renders a <video>
A page never stores the file itself. When a page uses an image, it stores a small reference to the media node — an @id, a preview url, and the placement-specific overrides:
{
"@id": "ctxr:img42",
"url": "…", // preview
"_focus": { "x": 0.5, "y": 0.3 },
"_decorative": false,
"description": "…" // optional placement alt
}
The shared fields — the file, name, caption, credit — stay on the node, so the same image can appear on many pages, each with its own focus point. the_media does the resolving: it follows the reference to its node, renders the right element per kind, applies the focus point as a CSS object-position, and sets the alt text — empty when the placement is _decorative, otherwise the placement description, otherwise the node’s name / description.
image and video are separate, schema-pure properties — image lives at the Thing level (any node can have one), video at the CreativeWork level — so a node can carry both. That makes the hero fallback a one-liner:
<?= the_media('video') ?? the_media('image') ?> // video hero, image fallback
Use get_media(...) when you want the raw resolved data instead of rendered markup.
Rich text
the_richtext / get_richtext render a formatted-text property — headings, links, emphasis — as sanitised HTML.
<?php the_richtext('articleBody') ?>
In development. The inline prose editor that makes rich text editable in place (the step-2 editing surface) is being built. Today the_richtext renders correctly for visitors and is editable through the structured form; in-place prose editing arrives with the editor’s next layer.
Accessibility & i18n helpers
Small helpers cover the parts of a page that are easy to forget and important to get right:
<?php the_skip_link() ?> // "skip to content" landmark
<?php the_hreflang($data) ?> // alternate-language <link> tags
<button><?= t('add_item', 'Add item') ?></button> // translatable string
t() looks up a UI string for the current locale and falls back to the default you pass. The full translation story — including the four-rung ladder these helpers sit on — is in Internationalisation.
Why helpers instead of raw attributes
You could hand-write data-inline-* attributes. The reason not to: the editor’s contract evolves, and the helpers move with it. A template that reads through helpers stays editable across platform versions; a template that hard-codes attributes is frozen to the day it was written. The helper is the stable surface — the editing experience page explains what it’s stable against.