Reaktiv Blog

Headless WordPress, Static, Cached, Oh My!

Headless man with lightbulb where his head should be writes "Headless CMS" on a whiteboard with code in the background.

So, you want a headless WordPress site. Now what? I mean, when given the choice we all crave speed. Speed means convenience. Convenience means more lead conversion and user engagement.

The big question is: “How do we get there?” Nowadays, we are faced with a paradox of choice. Far from the early workflows of yesteryear, we have an abundance of options. The old adage about competition being good for the consumer is on full display in open source.

There has been quite a bit of interest in “headless” content management in recent years. Modern front-end tooling such as Gatsby has gained more traction, and you probably have been hearing the term JAM stack with increasing frequency.

However, unless you come from a background steeped in the Node JavaScript ecosystem, some of this new dialect might be a little difficult to navigate at first. The good news is that while the lingo may be new, the concepts themselves are not. It is my hope that in this post, we can work through the terminology and frame it in ways that will make sense from a content management standpoint.

Specifically, I am going to cover some of the jargon you may encounter when considering headless WordPress:

Static example: 1996

Before we go forward, first let us go back. Waaay back to the days of Michael Jordan playing semi-pro baseball. SpaceJam.com began in earnest as a marketing site for the 1996 Warner Bros movie, but has since evolved into more of an internet meme. It is an oft cited example amongst front-end developers, showcasing the timelessness and backwards compatibility of browser based technologies.

SpaceJam.com

To get a better idea of the design aesthetic during that era, check out this “1996 Year in Review” site from the Washington Post. It too still remains online to this day, perfectly preserved as a piece of HTML history. It fits conveniently into a 640px width, which was the common denominator for lower resolution CRT computer monitors.

1996 Year in Review

The markup is not great by today’s standards. But all the techniques that went into building that site are still 100% supported by modern browsers. This means as long as the files themselves stay hosted, and the domain name is regularly renewed, the site will continue to display reliably into perpetuity. The same cannot be said of sites that were built on proprietary technologies, such as Flash (RIP).

Though it does not get a lot of credit, HTML itself is static by default. That also means it is fast by default. With the exception of form elements — and some legacy tags like <blink> and <marquee> — once HTML is rendered, that is what you get. You can drop a few *.html files on a server and they just work.

Another blast from the past is this early HTML page from the W3C that explains the concept of the World Wide Web. There is something so self-referentially meta about an HTML page being used to introduce HTML for the first time.

Back then, the W3C had not even broached the subject of adding images to a page or applying any visual styles. There was not yet any “theming.” It was literally all static text, created by scientists (for scientists) to share research with one another. Ah, nostalgia.

NOTE: As an added bonus, HTML is accessible by default when coded correctly.

Statically server-side generated

After the early days of statically authored HTML pages — an era which gave rise to the term “webmaster,” someone tasked with maintaining all those pages — the need to more easily publish (and edit) content became apparent. Dropping a handful of *.html pages on a server is simple enough, but what happens when the scope of a site balloons to hundreds or thousands of unique URLs? That sort of meticulous workflow quickly becomes untenable.

Enter the content management system, aka CMS.

A number of commercial and open source CMSs arose during this era. Too many to enumerate here, for the sake of brevity. One such approach was that of statically generated pages containing malleable content from a database.

Movable Type is often credited as the first CMS which caught on with a wider audience and helped to democratize publishing. Not to oversimplify the process, but it would essentially generate flat HTML whenever new blog content was published.

NOTE: Movable Type now also supports dynamically server-side generated pages.

Dynamically server-side generated

If you are reading this article, you have no doubt heard about WordPress and possibly Drupal or Joomla. Personally, I was fond of Textpattern back in the day. These are all examples of CMSs that dynamically output server-side generated pages.

Unlike a site comprised of flat *.html pages, sites built atop these CMSs could include dynamic aspects in a page. Meaning, portions of a site or page could potentially be subject to change without a recompiling of the content down to flat HTML beforehand.

If you have ever visited a site on January 1st and noticed the previous year’s copyright, chances are that site was not running on something dynamically server-side generated.

Cached dynamic output

While fresh content is obviously a huge upside to the aforementioned approach, the potential downside is that a CMS might hit the database unnecessarily — supposing two or more visits to the same page — when content may not have changed between the intervening visits.

To solve this problem, many dynamic CMSs have a number of caching plugins to choose from. Here is a brief list of popular caching plugins to consider when exploring a WordPress implementation.

WP Rocket and WP Super Cache mostly focus on caching the output that is rendered on the front-end. Meaning, the combination of content and surrounding markup is served for subsequent page requests if nothing has changed in the meantime.

It is worth noting that many managed WordPress hosting companies — such as WordPress VIP and WP Engine — have their own custom speed optimizations built directly into their hosting infrastructure. In such environments, using additional caching plugins is often unnecessary.

This is typically handled by an external server that caches the generated output from WordPress. Varnish or Nginx are typically used as HTTP cache servers in these environments, with Memcached or Redis used for object caching.

Runtime client-side generated

Still with me? Okay, cool.

In terms of front-end architecture, code that runs in a user’s browser is often referred to as the “runtime.” Markup that is created on the fly via browser based JavaScript is considered to be client-side generated.

This category has historically been referred to as a “Single Page Application” architecture, or SPA for short. More recently, it has enjoyed some rebranding as the JAM stack, which stands for Javascript APIs and Markup. Articles about building web apps with React or Vue typically describe this process.

The JAM workflow involves sending statically generated JavaScript to the browser, with a light amount of HTML, then having JS generate the markup necessary to render the page. This often is also done in conjunction with Ajax requests to a server-side API — pulling from a database or intermediary cache — to provide content to the page.

There is a complete decoupling of the UI from the data that hydrates it. In this way, a headless WordPress site can display dynamic content beyond each page load. There can potentially be live updates while the user interacts with the page, as JS continues to talk to the API layer behind the scenes.

Several JS frameworks that work in the browser can also be used on the server to pre-render static content. This can potentially lend itself to a hybrid approach where a fully static (content driven) page can be sent to the browser initially. Then the JS app can kick in and re-render changes atop what would have otherwise been unchanged.

This is where frameworks such as Gatsby shine, handling both statically server-side generated and runtime client-side generated content. This concept is also what enables us to use a CMS in a “headless” way, without sacrificing the SEO benefits of static HTML.

Static Site Generator

Before we dive more into “headless” as a concept, I wanted to pause briefly and provide a list of static site generators. I figured it would potentially be helpful to show that there are a number of viable options in this space.

These all fall into the aforementioned category of statically server-side generated. Additionally, some will also produce JavaScript that runs in the browser. A few of these are more akin to programming frameworks, whereas others fall more into the category of CMS.

NOTE: This list is not exhaustive.

Name URL Language
Eleventy 11ty.dev JavaScript
Gatsby gatsbyjs.org JavaScript
Grav getgrav.org PHP
Gridsome gridsome.org JavaScript
Hexo hexo.io JavaScript
Hugo gohugo.io Golang
Jekyll jekyllrb.com Ruby
Jigsaw jigsaw.tighten.co PHP
Kirby getkirby.com PHP
Middleman middlemanapp.com Ruby
Movable Type movabletype.com Perl, PHP
Netlify CMS netlifycms.org JavaScript
Next.js nextjs.org JavaScript
Nuxt.js nuxtjs.org JavaScript
Pelican docs.getpelican.com Python
Sapper sapper.svelte.dev JavaScript
Statamic statamic.com PHP

Headless WordPress

In the previous list, you may have noticed the conspicuous absence of WordPress. One would be forgiven for wondering what all this talk of static site generators has to do with a CMS that initially rose to prominence by being dynamically server-side generated.

The term “headless” means using a CMS as a source of data, while consuming that content via templates that have been statically server-side generated. Optionally, we can continue to render dynamic content after the page has loaded via runtime client-side generated templates.

As of this writing, that typically means using React to talk to WordPress via an Ajax API layer. To facilitate these types of use cases, WordPress has native REST API functionality available.

However, there is also a more modern approach which involves using the WPGraphQL plugin. If you are unfamiliar with GraphQL, it is Facebook’s query language that resembles a hybrid between JSON and the newer object literal {key:value} shorthand in JavaScript.

I will admit that my first reaction to learning about GraphQL was: “Why another language?”

At its core however, the decision makes sense. Essentially, it is a way to express a data query using a multi-line string. All languages share the ability to express a string, though they may differ on the nuances of how they handle objects and other enumerable data structures.

By allowing the individual language implementations of GraphQL to be handled at an abstracted layer, that keeps the syntax of the multi-line string query to a minimum. As a consumer of data, you need not know (or care) about the nuances of the language the API is written in. You are solely focused on asking for data in a specific format, and receiving a response in that shape.

Headless WordPress benefits

Workflow and speed

As you may have guessed, going headless offers the benefits of having a statically generated site while still affording a familiar authoring experience. Content creators can stick with a publishing workflow that they are used to, while site visitors reap the benefits of static files being served up fast. Those files could also be deployed to a CDN, for closer proximity to the user’s physical location.

UI flexibility

Additionally, because you are free to build your front-end templates however you like, there is no need to work within the confines of the WP theme ecosystem. If it can be built on the front-end — in isolation or as CMS rendered output — it can be a part of your site. This opens the door to a myriad of NPM modules that could potentially be used.

Unit testing

Since all React components are JavaScript functions that receive input and produce output, you can more reliably write unit tests for your site UI. Rather than simply relying on eyeballing to ensure that templates look correct, unit tests can be built to alert you if the expected markup changes. This can make for a “delete key friendly” peace of mind, should you need to do a large site redesign. With good test coverage, finding and fixing regression bugs becomes simpler.

NOTE: If you are looking for a good place to start, I would encourage you to check out Jest. It also pairs well with the “React Testing Library,” which adds handy extensions to Jest. Both of these ship with the latest Create React App starter project scaffolding.

Platform agnostic

This might not be a huge factor, given that a big reason for going headless would be to continue using a familiar CMS. However, should your business need to move to a different back-end in the future, you could take all your front-end templates and point them at another API. As long as that API returns data in a similar format, one would not need to rewrite the site UI. The same could not be said of migrating from one CMS specific templating format to another.

Security through obscurity

One passive benefit of headless WordPress is having a fully static site, for which there is no public facing login. Meaning, nobody is going to be able to snoop around by visiting your site’s “wp-login.php” page. Instead, you can keep the admin side of your CMS somewhat obscure because it need only be known to your content authors and static build system. The WordPress site can be much more locked down than the front-end, thereby enhancing security.

Headless WordPress gotchas

I hesitate to call this section “disadvantages” because this is really just how the JAM stack works, regardless of whether a CMS is involved. Instead, I would simply describe these considerations as “gotchas,” things that perhaps one does not initially think about when getting hyped to go headless.

Buh-bye plugins

Depending on your opinion of keeping up with WordPress plugin updates, this could be a good or bad thing.

Since all our headless templates are front-end exclusively, that means tinkering with a new plugin from within the WordPress admin will have no discernible effect on the public facing site.

That is, unless the plugin also makes its changes known to the front-end via additional REST API data points. If you wanted to drop in some new sidebar widget, you would need to inform a developer of the necessity to build that as a React component. As a JavaScript engineer, that is fine by me. But if you aren’t already a dab hand at JS, then this might be a workflow that sounds a bit less appealing as a content creator or site owner.

Previewing posts

Along those same lines, while writing a post — unless you build a subset of the headless site as a traditional WordPress theme — what you preview within the confines of the currently active theme may not be an exact representation of what users will see on the public facing site.

Meaning, the Twenty Twenty theme is going to look different than your site’s bespoke brand.

To me, this does not feel like a giant drawback. I would favor building a parallel set of layouts, using the same HTML and CSS from the headless site, as a theme for use on the WordPress authoring side. While not a huge showstopper, this is not something you would get automatically with a headless approach. It is not insurmountable, just something to keep in mind.

Potential headless WordPress hybrid workflow

You might be thinking: “Wait, what?”

I was not sure what to call this, but lately I have been thinking about possibly reaping some of the benefits of a proven WordPress authoring workflow while also being able to build atop the rich interactivity afforded by React.

It would not be “headless” in the purest sense. Rather, it would add a React app as an additional feature alongside an otherwise normal WordPress theme. Whether this is a Bad Idea™ remains to be seen, but hear me out.

All that React needs is a point in a page to attach itself. Typically, that looks like this.

const app = <MyReactApp />;
const root = document.getElementById('root');

if (root) {
  ReactDOM.render(app, root);
}

But what if that root was simply the outermost element housing our WordPress theme?

<body>
  <div id="root">
    <!--
      Dynamically server-side generated
      WordPress theme content goes here.
    -->
  </div>

  <!--
    Then our React app loads, and
    essentially takes over "root."
  -->
  <script src="/path/to/minified.js"></script>
</body>

In that scenario, WordPress could still be generating all the potentially cached output — getting us pretty close to flat HTML download speed — and then we would re-render any dynamism using React and GraphQL atop what would otherwise be unchanged.

That would solve the “previewing posts” gotcha. It could also address a need for a phased site rollout. The core site could launch first, and then React could be added later as needed. It would just take a little bit of planning ahead of time, to keep the door open to the possibility.

As for plugins… Perhaps it is too early to call it, because my predictive powers are average at best. I could envision a future in which WordPress plugins could be used either as PHP rendered or alternatively serve data from the REST API (or GraphQL) to be consumed by React.

NOTE: Geoff Taylor, one of the developers on the WPGraphQL team, has built a proof of concept WordPress theme that can render JSX on the server-side.

Conclusion

For our high level overview, that about covers it. Hopefully this write-up was helpful in clarifying some of the concepts around headless WordPress. If you are considering next steps, as with everything related to software development:

“It depends.”

It is easy to read an article heralding measurable speed improvements and immediately want to implement that for your own site. But bear in mind that the problems those sites were solving may not (yet) be issues that your site is facing. As your site scales, you might run into tangential or wholly different factors.

If you are considering making the transition to a headless site, we at Reaktiv Studios would be happy to talk to you about it further. Drop us a line, and we can brainstorm how to eke out more speed together.

Leave a Reply

Written by:

Nathan Smith is a front-end developer residing in the DFW metroplex. Born in Hawaii, he grew up as a military brat, and has lived all over the continental United States. He has a strange affinity for JavaScript unit tests.