Guide 04 · Developer docs

Input types, layouts, components and images

The platform's central abstraction, in one line: an input type defines what an editor can enter, a layout area binds one input type to a named slot, a layout groups areas and points at a template, a record or component holds the content for each area, and the template reads it back. Read this book straight after the template languages.

L1–L3
Unit 07 · The shorthand, and working with each input type

Limits of the shorthand, and the rule

The shorthand resolves areas only on the frontend, loses to a real getter of the same name, throws on an unknown name in Smarty, takes no arguments and is harder to search for. Each limit, its symptom and guard, and the rule reviewers apply.

Who this is for. Developers and reviewers choosing, line by line, between the shorthand and an explicit getter. After this page you can recognise each failure by its symptom and apply one rule to every template.

Frontend only

The area step of the resolution runs only for a model of the frontend abstraction, the models the platform builds to render the site's pages. A model of the backend or API abstraction never reaches it, so the same expression there finds no area and throws Property heading does not exist, the same message as a typo.

What decides it is the model's abstraction, not where the template file lives: a site template rendered by backend code with a backend model behaves as backend. Code that may receive models from either side reads areas with the explicit getters, which work in every abstraction.

A real getter wins

If the model has a getter matching the name, the getter's result is returned and the area is never read. There is no error: the symptom is a plausible but wrong value. An area called name on a component prints the component's own name, not the author's text.

Names that collide: name and id on records and components alike; url, slug, fullPath, created and modified on records that have them, such as pages, posts and book pages. A plain component has no URL, so url does not collide on one.

The habit that avoids it: name areas for what they hold, such as heading, ctaUrl or personName, never after a generic property. An area that already has a colliding name is still readable with a getter: getAreaHtml('name') to print it, getAreaText('name') for plain text. Renaming it touches every template that reads it; see Where content is stored, and what a change does to it.

An unknown name throws in Smarty

A mistyped or missing area name behaves differently in each engine:

  • Smarty throws, and the page fails with a server error: Property heding does not exist in, followed by the model's class name.
  • Twig prints nothing and reports nothing. Core dna runs Twig without strict variables, so the failed lookup becomes null, an empty string on the page.

Neither suits an area that is genuinely optional: one present on a newer version of a layout and not on an older one, or one read by a partial shared between layouts. Test for the area first with hasAreaWithName(), which works the same in both engines:

Template code
{if $component->hasAreaWithName('subtitle')}
    <p class="sub">{$component->subtitle}</p>
{/if}
{% if component.hasAreaWithName('subtitle') %}
    <p class="sub">{{ component.subtitle }}</p>
{% endif %}
Not is defined

In Twig, is defined is true for every name on a record or component, including names that are neither a getter nor an area, so it guards nothing. In Smarty, isset($component->subtitle) does reflect whether the area exists, but hasAreaWithName() reads the same in both engines. Whether an existing area is empty is a different test: Testing whether an area is empty.

No raw text, no arguments

The shorthand is a property read: it takes a name and nothing else, so there is no way to pass it an argument. On a text area it returns what getAreaHtml() returns, wrapped in live preview, never the plain stored text. Anything that needs either uses an explicit call: plain text for an attribute or a comparison (getAreaText()), the keys of a multiselect (getAreaValues()), the possible values of a select (getAreaType()).

Harder to search for

getAreaText('heading') names the area as a quoted string; $component->heading looks like any other property. Before renaming an area or auditing where it is used, search for both forms: the quoted name, and the name after -> and after a dot.

The rule

Use the shorthand to print an area's value as element content in a page or component template. Use an explicit getter when the value:

  • goes into an HTML attribute (href, class, src, style, data-), a script or JSON: getAreaText();
  • is compared, tested or calculated with, unless the area is a switch or a date, whose shorthand is a boolean or a date object and never wrapped;
  • needs an argument, or the raw stored value;
  • may not exist, as in a partial shared between layouts: guard with hasAreaWithName() first;
  • has a name a getter already takes, such as name or url;
  • is read from a model that may not be a frontend model.

A reviewer can apply it mechanically: flag a text-area shorthand inside quotes or next to an operator before it reaches live preview, and turn a getter that prints element content with no argument into the shorthand.

Go deeper

Was this page helpful?

Your answer goes to the docs team.