Live preview mode¶
Statamic has a live preview mode, which is also available in the Brekz Templating project.
It's however not exactly a run-of-the-mill variant of Statamic's live preview mode, because of the architecture of Brekz Templating having multiple services, all responsible for their own thing.
This document will highlight how it works and why it is the way it is.
Why the semi-custom implementation?¶
Brekz Templating consists of multiple services, each one is responsible for its own tasks. This allows us to better separate what each service needs to do, and allows us to also replace parts of it in the future if needed.
For this document, the most relevant services are Brekz CMS and Brekz Website. All the components and rendering logic is inside Brekz Website, not in Brekz CMS.
If we wanted to use the default live preview implementation of Statamic, we would have to implement each template and component in Website and CMS, which is a lot of extra overhead and mistake prone.
An alternative solution would be to not have actual components in CMS and instead replace them with dummy blocks, which would then show the layout. This however would kind of limit how useful the live preview mode would be.
In the end we settled on using a custom preview_target, which allows us to tell to Statamic that we want to use a custom endpoint for the live preview mode.
In this case we point it to a specific endpoint in Brekz Website, which will perform the actual render for Statamic.
Since this is done inside the real Brekz Website instance, the resulting preview should be very accurate to how the page will look and feel when it's published.
Architecture¶
TL;DR¶
Statamic's live preview mode is provided by Brekz Website's /live-preview endpoint.
This is configured on a per-collection basis by setting the preview target.
preview_targets:
-
label: Entry
url: "https://{{ config['services']['brekz-website']['domain'] }}/live-preview"
This causes Statamic to embed Brekz Website inside the Statamic UI where normally the live preview would go.
Brekz Website receives a special token from Brekz CMS that gives it access to the entry data we are currently editing. This entry data is then given to the same render system as what normal pages would go through.
Because of that, the live preview should look and feel exactly the same as what the real page will look like. All the components and tooling is available, and certain caches are also automatically disabled to give the most accurate preview.
Flowchart¶
sequenceDiagram
actor Editor as Editor (Browser)
participant CP as Brekz CMS (Statamic CP)
participant Website as Brekz Website
participant CMSAPI as Brekz CMS (Internal API)
Editor->>CP: Opens entry & activates Live Preview
CP->>CP: Creates preview token & stores unsaved entry data
CP->>Editor: Renders CP UI with embedded iframe pointing to /live-preview?token=
Editor->>Website: GET /live-preview?token= (iframe load)
Website->>Website: Validate request (token required)
Website->>Website: Disable caches (accuracy over speed)
Website->>CMSAPI: GET /api/internal/live-preview/{token}/data
Note over Website,CMSAPI: Authenticated via IsInternalServiceApiCallMiddleware
CMSAPI->>CMSAPI: Resolve token → live preview entry
CMSAPI->>CMSAPI: Merge saved data + supplemental (unsaved edits) + blueprint contents
CMSAPI-->>Website: JSON response with full entry data
Website->>Website: Parse response into LivePreviewDataStruct
Website->>Website: Set locale from entry data
Website->>Website: Resolve sections from entry data & blueprint (SectionHelper)
alt Generic CMS blueprint (contentpage)
Website->>Website: Iterate sections[] from entry data
else Custom blueprint (section_mapping)
Website->>Website: Iterate sections_mapping[] from blueprint
end
Website->>Website: Render static sections via Blade templates
Website->>Website: Render dynamic sections via DynamicContentHandlers
Website->>Website: Combine all sections to HTML
Website-->>Editor: Rendered page HTML (LivePreview.rendered-page view)
Note over Editor: Page preview shown inside Statamic CP iframe