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 06 · Rendering areas in templates
The area getters and what each costs
Rendering areas in templatesPage 20 of 45Updated
One set of getters reads areas on every record that has them: pages, book pages, blog posts, product descriptions, custom entity records, global components and components. Every getter, what it returns when an area is filled, empty or missing, and what each call costs.
Who this is for. The template developer reading layout areas in Smarty or Twig. Afterwards you can pick the getter that fits an area, predict what it returns when the author left the area empty, and keep the expensive calls out of loops.
One surface, every container
The area getters are defined once, in a trait shared by every record that holds areas. The same calls work on a page, a book, unit or book page, a blog post, an FAQ question, a product or product category description, a custom entity record, a global component and a component. Learn them once: nothing on this page is specific to one content type.
The containers come in two kinds. Every one in that list except a component is versioned: its content lives in revisions, and a getter called on the record reads the record's active revision. A component has no revisions of its own: its areas sit on the component, which is stored with the revision whose area holds it. So the first two lines below are the same call, and the shorthand on the last line, the normal way to print a value, is the shortest way to it:
Template code
{* on a page, a book page or any other versioned record *}
{$page->getAreaText('intro')}
{* the same call, made on the active revision *}
{$page->getActiveRevision()->getAreaText('intro')}
{* the shorthand, the shortest way to it *}
{$page->intro}
{# on a page, a book page or any other versioned record #}
{{ page.getAreaText('intro') }}
{# the same call, made on the active revision #}
{{ page.getActiveRevision().getAreaText('intro') }}
{# the shorthand, the shortest way to it #}
{{ page.intro }}
There is one exception. getAreaContent() is not passed through to the active revision: on a page, a blog post or any other versioned record, call it on the revision, $page->getActiveRevision()->getAreaContent('name'). On a component, call it directly. getAreaContentOrDefault() is passed through like every other getter.
Every getter
Each getter takes the area's name as the layout defines it. The getters are the explicit form of the shorthand, {$page->intro} in Smarty and {{ page.intro }} in Twig, which is how a template normally prints a value (The area shorthand). Call a getter when you need an argument or a method on the result, when the value goes into an HTML attribute, a script or JSON, or when the area's name is also a getter of the record, such as name or url. The table gives what each returns in a template. It leaves out getAreaWidget(): widgets are deprecated, and a component's template reads records with the query helper $_query instead. Where it says blank, the getter returns a blank object, a stand-in that prints as an empty string and answers true to isBlank(); the same call made in the admin or through the API returns null instead.
Getter
Filled area
Empty area
Name the layout does not have
getAreaType(name)
The input type record
null
null
getAreaCategory(name)
The category, a string
null
null
getAreaEditor(name)
The editor, a string
null
null
getAreaText(name)
The stored value, a string
null
null
getAreaHtml(name)
The rendered value
''
''
getAreaValues(name)
An array of option keys (multiselect only)
[]
[]
getAreaDate(name)
A \DateTime (date and datetime editors)
null
null
getAreaImage(name)
The image
Blank image
Blank image
getAreaFile(name)
The file
null
null
getAreaRecord(name)
The referenced record
null
null
getAreaRecords(name)
A collection of the referenced records
null
null
getAreaComponent(name)
The component
Blank component
Blank component
getAreaCollectionElements(name)
A collection of the elements
An empty collection
An empty collection
getAreaContent(name)
The stored content object (not on a versioned record, above)
Blank content
Blank content
getAreaDefaultContent(name)
The area's default content
Blank content
null
getAreaContentOrDefault(name)
The stored content, or the default when nothing is stored
An array of content objects keyed by attribute name
The same; [] when the area has no attributes
[]
hasAreaWithName(name)
true
true
false
Three things follow from the table.
A missing name is not an error. Every getter answers a name the layout does not have as it answers an empty area, so a misspelt name looks like an empty area. hasAreaWithName() is the one call that tells them apart.
Blank objects only for images, components and raw content. Files, records, text, values and dates give null or [] in a template too; there is no blank file. A collection gives an empty collection, never null, everywhere.
Two getters refuse the wrong kind of area.getAreaText() on an area outside the text category returns the string Error: cannot get text content for area of type …, with the input type's name and category, and the template prints it like any value. getAreaDate() on a filled area whose editor is neither date nor datetime throws: "Could not get date from area … as it is not a date / datetime type".
An area's stored content arrives with the record. Some getters read only that; others load or look up what the area points at. Four tiers, cheapest first:
Reads the area list already in memory; no content is touched.
Cheap
getAreaText(), getAreaValues(), getAreaDate(), getAreaContent(), getAreaDefaultContent(), getAreaContentOrDefault(), the attribute accessors
Reads the stored value from content loaded with the record. getAreaDate() parses a new date object on every call; an attribute accessor makes one such read per attribute.
The first call can load what the area points at. The content keeps it, so a second call on the same content does not load it again.
A query every call
getAreaRecord(), getAreaRecords(), and getAreaHtml() or the shorthand on a record, records, component or collection area
Looks the referenced records up on every call, with nothing kept between calls. getAreaHtml() also renders the record's or component's template.
A reference read inside a loop
Each getAreaRecord() or getAreaRecords() call runs its own query, even on the same content. A list page that reads a related area for every row runs one query per row: the classic query-per-row shape.
The rule: free and cheap calls can go anywhere, loops included. Call a one-load getter once per render and keep the result in a variable. Keep the last tier out of loops: read a value once above the loop when every row needs the same one, and read a reference on every row only when rendering each row's referenced content is what the loop is for.