DEV Community

Andrew Welch
Andrew Welch

Posted on • Originally published at nystudio107.com on

Headless Preview in Craft CMS

Headless Preview in Craft CMS

Craft CMS 3.2 intro­duced head­less con­tent pre­view. Here’s an explo­ration of how it works, and how you can imple­ment it

Andrew Welch / nystudio107

Headless preview craft cms

Craft CMS has long had a ​“live pre­view” fea­ture that allows con­tent authors to see a pre­view of exact­ly what their con­tent will look like when pub­lished to the web.

With Craft CMS 3.2, one of the major fea­tures added was ​“head­less preview”.

This fea­ture allows devel­op­ers who are ren­der­ing their pages as a Sin­gle Page Appli­ca­tion (SPA) via a fron­tend frame­work like React, Vue.js, Svelte, etc. the abil­i­ty to have Craft CMS con­tent pre­view, too.

Why it required a rewrite

Even though nowhere in ​“con­tent man­age­ment sys­tem” is the promise of a ren­der­ing engine, all tra­di­tion­al CMSs don’t just man­age con­tent, but also ren­der it as web pages as well.

Craft cms headless preview horseman

A CMS ren­der­ing con­tent was prob­a­bly born out of convenience.

When you use a CMS ​“head­less” you are lop­ping off the part that does the ren­der­ing. Essen­tial­ly, your CMS then man­ages your con­tent, but instead of ren­der­ing it, it pro­vides an API so some­thing else can con­sume it.

The rea­son Craft’s ​“live pre­view” fea­ture worked is that the CMS had con­trol over the whole edit­ing ⟷ pre­view­ing loop.

Now with some­thing else doing the ren­der­ing, that’s no longer the case. So they had come up with a clever solution.

Tok­enized Preview

The solu­tion the fine folks at Pix­el & Ton­ic came up with is a com­bi­na­tion of auto-saved entry drafts and a token that’s sent along to the web page that is being previewed.

Nyc Token

When you click on Pre­view , rough­ly the fol­low­ing happens:

  1. A draft of the entry you’re edit­ing is saved
  2. A token is gen­er­at­ed for that draft, and infor­ma­tion about the draft entry ele­ment is saved to the database
  3. The token is sent along to wher­ev­er the web page hap­pens to be as a token URL param
  4. The web page then sends back that same token with any API requests

It looks rough­ly like this:

Craft preview token flowchart

So why all of this token non­sense? Remem­ber, we’re pre­view­ing an auto-saved draft of the entry that’s being edited.

It’s done this way because the con­tent edi­tor and con­tent ren­der­er no longer share any state, so the saved draft is that state.

The token is what Craft uses to link a pre­view web request to the auto-saved entry draft.

When a request comes in to Craft that has a token in the URL params, rough­ly the fol­low­ing happens:

  1. Craft looks up the route infor­ma­tion asso­ci­at­ed with the token in the tokens data­base table
  2. In the case of head­less pre­view, the Preview con­troller’s actionPreview() method is called
  3. The auto-saved draft ele­ment that’s being pre­viewed is then added to a list of placeholder elements
  4. When­ev­er an ele­ment query is done that would match any placeholder ele­ments, they are swapped in

This is what that caus­es it all to ​“just work”. Check out the ElementQuery meth­ods _​placeholderCondition() and _​createElement().

Since the token was passed down to the web page that’s being pre­viewed, if it is passed back up to the API that retrieves data from Craft, the place­hold­er ele­ments get mocked in.

Just like magic.

Make it so

The Live pre­view using Vue.js post details it pret­ty well in terms of what you need to do to add sup­port on your end.

Star trek make it so picard

Essen­tial­ly, it boils down to just extract­ing the token URL param, and send­ing it back to the Craft CMS API end­point, whether that be Ele­ment API, CraftQL plu­g­in, or what­ev­er else you may be using.

Craft cms token lifecycle

Here’s some JavaScript that Bran­don Kel­ly posted:


// Get the preview token from the URL
let m = document.location.href.match(/\btoken=([^&]+)/);
let token = m ? m[1] : '';

// Then forward that on whenever you are sending an API request
let url = `...?token=${token}`;
// ...

That’s real­ly all there is to it. Extract the token URL param, and send it back with your API calls.

The x-craft-preview URL param & request head­er is just a way you can dis­tin­guish the request defin­i­tive­ly as a Craft pre­view, since you might be using the token URL param for oth­er things as well.

There is a token­Param gen­er­al con­fig set­ting if you need to change it to some­thing oth­er than the default of token.

If you’re con­cerned about pre­view not remem­ber­ing the scroll posi­tion cross-domain, check out Clive’s ScrollMemNonEs6.js gist.

Hap­py head­less previewing!

Further Reading

If you want to be notified about new articles, follow nystudio107 on Twitter.

Copyright ©2020 nystudio107. Designed by nystudio107

Top comments (0)