A long, long year ago, it seemed prudent to bring up a few things that worked well in WordPress that were missing in Gatsbyjs. For instance, one-click exchangeable Gatsby js themes.

Some, but not many, of those holes have been filled in various ways, but others remain (and probably will remain). But time has pushed each of these web frameworks down the road a piece, meaning more developers have had more, different experiences with them. A knock-on effect of this is that it’s now clearer what it would be most useful to beg, steal or borrow from WordPress.

WordPress vs Jamstack

To be clear, Gatsby and WordPress are trying to solve somewhat different problems.

Nor is anyone saying there’s something terribly wrong with Gatsby (or Next.js or Remix Run, the new kid on the block). WordPress is monolithic, the Jamstack crowd is looking for the Great Decoupling, plus static pages, plus edge functions, plus GraphQL queries to anything you might once have tackled with a REST API.

Jamstack is aimed squarely at developers, not people who just want to drum up a website with their contact information and a few brochure pages. At the same time, a lot of the world’s websites are running on WordPress, frequently on fairly straight-out-of-the-box WordPress. That is, these are not people (and marketing departments) who are going to fall into the arms of Gatsby, even with a Gatsby template for a blogsite. They’re not going to be pushed into those arms, either, not by the need for blazing-fast speeds and not by their desire to move to a “friendlier” cloud CMS.

As far as speed goes, last year’s “theft” essay got at something of a fundamental truth:

A framework like Gatsby claims to have the upper hand by using static pages, but of course that’s not quite comparing apples to apples. If a JAMstack site needs to personalize pages on a per user basis, it may do so by way of API calls to a third-party services, but make no mistake, this is still just referencing a database on the back end. In the customized-page scenario, there’s no inherent JAMstack speed advantage. And, frankly, this is a fairly common scenario.

Another thing happened in the course of the past year: Google rolled out the Core Web Vitals algorithm update that had us all worried about whether our web pages were as blindingly fast as they needed to be to rank. And it turned out not to make all that much difference. The WordPress sites of the world did not drop off the face of Google Search Engine Results Pages (SERPs).

So if you’re running a website on WordPress and wondering whether you need to high-tail it to Jamstack, the pressure is off, by and large. It’s still nice to have a screamingly fast site, of course, and it’s nice, most folks seem to agree, to work strictly in JavaScript, rather than PHP, as is used for the core of WordPress.

The Headless WordPress CMS Approach

The Jamstack response is to argue that the point of decoupling the front end from the back end is that the back end can still run a WordPress stack. In Gatsbyjs, you’ve got the rather sweet option of using WPGraphQL (with a hat tip to Jason Bahl (@jasonbahl) for putting that great WordPress plugin in motion).

That’s good stuff if you’re a developer, but on the flip side, all sorts of very useful things drop out of play if you abandon the WordPress monolith you’ve been running. And they’re mostly gone even if you keep running WordPress, but use it as a headless CMS.

For one thing, the WordPress theme you’ve been using on the monolithic site is gone, with the design coming from the front-end side of the house.

You can deal with this by getting a theme that behaves and looks more like WordPress—have a look at GatsbyWPThemes for a run at that (and I plan to dig in, try it out, and write about it before long, following on a great conversation the other day with Alexandra Spalato, one of the company’s founders.

In short, you can’t just point your Gatsby front-end at your WordPress theme.

It might seem like this should be doable because, after all, a theme is basically a bunch of CSS in a style.css file.

But it’s not nearly so simple. For one thing, there are also template files that determine what the various repeating sorts of pages (blog entry lists, the blog entries themselves, and so on) should look like. These are written in PHP and HTML, using conventions that are very closely tied to WordPress.

I’ve wondered in the back of my head whether it would be very hard to just write a simple (but would it be?) cross compiler to translate from the PHP files to more Gatsby-native templates. It wouldn’t shock me to see something like this get cooked up before too long.

Jamstack Admin

But even if we get to that point, where WordPress themes are convertible to Jamstack scenarios, you still won’t be able to jump into an admin console, look at a list of themes currently downloaded for use on your site, pick a different one, and hey presto, have a new and different look instantly online at your site.

You can’t do that because, duh, there is no admin console for that Gatsby site of yours.

If you build your site with a CMS and some other, separate services for identity management, database interactions, and localized customization, you have many things to manage and no centralized console.

If you’re a relatively low-code user of WordPress, what you’re going to be missing most of all is that you can’t jump into the WordPress plugin section of the console.

Gatsbyjs Plugins

Now, Gatsby does have plugins. These plugins have some of the same uses as WordPress plugins, but they are designed to be consumed more or less as libraries that the developer has access to. Next.js has plugins, pretty much along the lines of Gatsby, along with some interesting third-party twists. For example, Grouparoo has a system for adding plugins that grab non-static content to add to pages.

All that said, I’m not aware of any way on the Jamstack side of things for a third-party to program some simple little bit of functionality—to take a trivial example, giving you the ability to create pop-up footnotes within your text content1—that you can download and just start using at runtime and without having to work it into the fabric of your own custom application.

During the static site generation process, extensions that acted on the source code or the generator would be called.

Anybody who’s worked in WordPress knows that plugins can be an incredibly powerful way to get a lot done without having to do any real work. Books are always mentioning how many tens of thousands of plugins are out there. The huge number thing is nonsense, because there are all sorts of duds and orphans in the pool. But the decent plugins (and there are certainly a few thousand of these) out there make it possible for you to add nice bits of extra functionality because it’s already coded and it’s available with no fuss.

WordPress plugins are a different animal, and Jamstack needs to steal this version of the plugin thing wholesale.

Gatsby JS Extensions

To keep things straight, I’m going to dub the Jamstack version of plugins “extensions.”

Extensions should snap into a Jamstack framework along the same lines as their WordPress forebears. In other words, they should register callbacks to their functions with named events in the Jamstack process.

As the user browses the site, other, runtime extensions would be called.

So, if we imagine that there’s an event in a Jamstack site where a user logs in, that event might be called “user_login”. In the plugin, we’d include a function called greet_user() that did whatever we’d want to do now that the user was authenticated and we knew who it was. In addition to declaring and defining the function, a separate line of code would “hook” the “user_login” event, along these lines:

register_action( 'user_login', 'greet_user' );

Thus the user lands on the site, which because this is Jamstack is a bunch of basically static pages, there’s a login routine that does whatever it does, calling back to some remote service for authentication. When the user successfully logs in, the Jamstack page currently loaded “fires” the “user-login” event and calls back any functions that were registered for this event.

Since we registered for this event, our greet_user() function will be called, we’ll do whatever we need to do, then the function will return to the overall process of showing pages and interacting with the user.

Jamstack Architecture: Complicating Issues

A bunch of things add some measure of complication to this, compared to the WordPress version of it.

  1. No admin interface. We don’t have the admin interface for adding and activating (and deactivating, and configuring) these extensions. For now, let’s pretend that this is no big deal. (It’s probably actually a big deal, because you probably want to build it so that non-developer admins can use and tweak extensions. That’s kind of the whole point of them, at the end of the day. But where does this thing live? Static pages on the client? But most clients aren’t admins…)
  2. Adding events to static pages. WordPress goes through its whole process for each and every page it serves, meaning there’s a centralized point (the code on the server) from which to execute events. It doesn’t matter where the user first lands—every page does this. With Jamstack, on the other hand, the user could request any page, so every page will need to know whether and how to fire events (or report back to some process that fires them).
  3. Generation time and runtime. WordPress is a simple process, dynamically building the page from header to footer, calling things along the way. Jamstack, on the other hand, has generation time in addition to client runtime, which of course is running on the edge in a browser. So there needs to be mechanisms for extensions that allow functions that do their work as pages are being generated (changing the text content of certain kinds of pages, for instance, with these changed pages thereafter being static) and functions that are shipped out to the client side, to be invoked at the appropriate moment, for instance, changing the content of a page as a React component switches in new content.
  4. Common variables and functions. This is probably the least of the issues, but it will enable extensions to do more work if there is a common environment in which extensions run (particularly on the client side). A WordPress developer has a huge list of functions and globally retrievable variables that describe the current state of the platform, who the current user is, what the URL of the current page is, what the URL of the folder that holds the templates is, what day it is, and so on. If all this sort of stuff is predefined, everybody knows what’s going on. Otherwise, everyone gets to reinvent the wheel for each outing.

Getting back to my example of adding support for pop-up footnotes, the extension version of this would perhaps use a simple character sequence to denote footnotes in normal running content text, maybe something like [fn]comment that makes up the footnote[/fn].

When the content is being rendered at the client, assuming we’re in a Gatsby-like environment where React is going to load in the content for the component on the fly, the content would be retrieved but, just before it was displayed, an event would fire and a callback would be made to the footnote extension.

The Callback Process

In WordPress, the content that goes in the middle of the page is accessible through a function call to, catchily enough, get_the_content(). Let’s assume there’s something similar available to the extension, that the content is scanned for the [fn] marker, and that some spiffy extra stuff is injected.

Now, when the text is rendered onscreen, it includes a numbered footnote that pops up a note when hovered or clicked.

Whoever developed this hypothetical site was not involved in making this happen. One of the site’s content developers (with appropriate administrative clearance) decided it would be great to have footnotes, found a footnote extension that had the right look and feel, installed the extension, and then added the markup to the content.

The Upside of Aggressive Borrowing

I don’t pretend to have worked out all the answers here, but none of the issues I’ve mentioned seems insurmountable.

And there could be some real upsides to having a bunch of capabilities ready to plug in and go, just by checking the activate box.

Menus, for example. WordPress menu configuration is something that could be handled by an interface on the generation side. In WordPress, I can write my own menu code if I want to, but if not, I can configure all sorts of things, beginning with the location on the page where the menu appears (and whether it’s sticky, and so on). All that stuff just happens. Building this as an extension in a Jamstack environment would mean faster deployments and more options for who changes the menus and when.

Other examples: language localization, widgets that display links to related content, vast functionality additions like WooCommerce (a widely used plugin that provides a full range of ecommerce site capabilities), and so on.

On the one hand, Jamstack seems to be slowly reabsorbing dynamic capabilities because, whaddya know, those dynamic things were nice to have. On the other hand, the flip toward static first, backend decoupled seems like the best approach now that there’s enough tools to make this more sophisticated architecture readily available. It’s an opportunity to borrow from time-tested approaches such as those that were gradually built into WordPress over the years. We should be able to benefit from the experience and rebuild these things cleaner and faster than ever.