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 09 · Patterns, live preview and upkeep
Live preview and testing in-place editing
Patterns, live preview and upkeepPage 42 of 45Updated
What turns on in-place editing in live preview, which template calls keep it and which lose it, the three settings that govern it, and a short test to run on representative pages before handover.
Who this is for. Developers handing a site to authors who edit in live preview. After this page you know which of your template calls make an area editable in place, and you can test a site for it before handover.
What turns it on
Live preview renders the record being edited, with the changes not yet saved, through the site's own templates. It runs only for a signed-in backend user (a user of the admin); a site member or a signed-out visitor never gets it. For that request:
The record is filled from the edit form's current values. Nothing is saved.
On a versioned record, the most recently added revision is made active for the request and the form's values are laid over it. The preview therefore shows the newest revision, draft or published, with the edits on top, which is not necessarily the revision visitors see.
When the setting Live preview: instant updates is on, the getters wrap each editable value in a marker, <span class="live-preview-container" contenteditable="true" data-path="…">. The data-path names the place in the record the value was filled from, which is what lets the author type into the value in the preview and lets the preview follow changes made in the form.
The page cache is bypassed, so a cached page never stands in for the preview.
The settings
Setting
Default
Effect
Live preview: instant updates (Globals.admin.insertLivePreviewTags)
On
Adds the markers. With it off, the preview still renders, with nothing editable in place.
Live preview: Allow JavaScript (livePreviewAllowJavascript)
Off
In the setting's own words, “JavaScript embedded with a valid nonce will be executed in the live preview window”. Turning it on keeps the content security policy active for the preview, so that a nonce exists. With it off, do not expect the page's scripts to run in the preview.
Alternative live preview url (livePreviewUrl)
Empty
Points the preview at a separate front end, such as a headless build, with the placeholders {id}, {fullPath} and {revisionId}. Templates on the site itself do not read it.
Which calls keep it
Call
Marked in live preview
The shorthand, {$component->heading} / {{ component.heading }}
Every text area, whatever its editor (a switch's shorthand returns a boolean instead)
getAreaHtml('heading')
Every text area, whatever its editor
getAreaText('heading')
Rich text only; any other editor gives the plain value
So the practical rule: in any area an author edits directly, print the value with the shorthand, or with getAreaHtml() when you need the getter. Keep getAreaText() for the places a marker must not reach: attributes, scripts, JSON and comparisons. How the shorthand resolves is on The shorthand and live preview.
Template code
{* content: the shorthand, editable in place *}
<h2 class="card__title">{$component->heading}</h2>
{* attribute: plain text, never a marker *}
<a class="{$component->getAreaText('cssClasses')}">{$component->linkName}</a>
{* logic: compare the stored value, not the marked one *}
<div class="card{if $component->getAreaText('tone') == 'dark'} card--dark{/if}">
{# content: the shorthand, editable in place #}
<h2 class="card__title">{{ component.heading }}</h2>
{# attribute: plain text, never a marker #}
<a class="{{ component.getAreaText('cssClasses') }}">{{ component.linkName }}</a>
{# logic: compare the stored value, not the marked one #}
<div class="card{% if component.getAreaText('tone') == 'dark' %} card--dark{% endif %}">
What stops an area being editable in place
None of these raises an error. The area cannot be edited in place, or the preview shows markup that the public page does not.
getAreaText() on a plain text area. Text, textarea, select, date, code and colour areas read with getAreaText() carry no marker. That is what you want in an attribute, and a lost edit point anywhere else.
A modifier or function on the marked value.|escape turns the marker into visible text in the preview, strip_tags() removes it, and truncating can cut it in the middle of the tag. This is why a shorthand value is printed as it is, never escaped.
The marked value used as data. In an attribute, a comparison or arithmetic, the marker becomes part of the value: a class that matches nothing, an {if} on a select read through the shorthand that is false only in the preview.
Content drawn by JavaScript or fetched from the API. The marker is added by the server-side getters; values a script builds never pass through them.
Default and placeholder content. A marker needs the place in the record that the value was filled from, and only the content of the record open in the preview has one: its own areas, its local components and their collection elements. Default content belongs to the layout area or the input type, so an area still showing its default is never marked. The author enters a real value through the edit form first; from then on the area is editable in place.
Content from another record. A global component placed on the page, or a record reached through a record area or $_query, is loaded by its id rather than filled from this form. Expect it not to be editable in place from this page, and include it in the test below.
The page cache is not a cause: a live-preview request bypasses it.
A missing marker is not always a fault
A value in an attribute, or one that drives logic, is meant to be read with getAreaText() and is changed in the form. What matters is that every area an author would expect to click on in the preview can be edited there.
Testing in-place editing before handover
Pick a representative page for each page layout, and a page that uses every component layout at least once. A component gallery for authors lists them.
Sign in to the admin as a backend user with the permissions the authors will have, open the page's edit form and its live preview.
For each area, type a change into the value in the preview, and change a value in the form; both should show in the preview straight away.
Save the record. Load the page signed out, in another browser, and confirm that the saved change is there and the markup is intact.
List every area that cannot be edited in place, and decide for each whether that is intended (an attribute, a value used in logic) or a template fault to fix.
If the site relies on scripts in the preview, check them with Live preview: Allow JavaScript set as it will be in production.
The areas most likely to fail
Plain text areas printed through getAreaText() out of habit: headings, labels, button text.
Values passed through a modifier or function: a truncated summary, an escaped title, a label in capitals.
Selects whose value drives an {if} through the shorthand: the branch changes in the preview.
Areas showing default content, and empty image areas showing the placeholder.
Global components, and anything a component reads from another record.
Anything built by JavaScript in the browser: sliders, tabs, accordions.