Skip to content

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