Why We’re Not Using WordPress’ Gutenberg…Yet
UPDATE:
I wrote this post in 2018 and since then there has been little improvement in attempting to work with Gutenberg via either a JSON REST or GraphQL API.
So we built a CMS of our own that does this and much, much more.
Payload is a headless CMS and application framework that’s built with a JavaScript stack from top to bottom: Node, Express, React, MongoDB. Working with it is so many thousands of times better than any other CMS on the market and works extremely well with a JAMstack.
Features:
- GraphQL, REST, and Local APIs
- Easily customizable ReactJS Admin
- Fully self-hosted
- Extensible Authentication
- Local file storage & upload
- Field-based Localization
- Block-based Layout Builder
- Extensible SlateJS rich text editor
- Array field type
- Field conditional logic
- Extremely granular Access Control
- Document and field-level hooks for every action Payload provides
- Built with Typescript & very Typescript-friendly
- Intensely fast API
- Highly secure thanks to HTTP-only cookies, CSRF protection, and more
Give it a shot!
npx create-payload-app
—
There are a lot of really good things coming out of WordPress’s addition of the Gutenberg editor — and the general direction of the CMS is something that TRBL can agree with. Writing posts with blocks
instead of one archaic WYSIWYG field is a breath of fresh air and a long-awaited addition. In our opinion, the design of the interface is a massive improvement over the stale and aging UI of previous versions. But, we can’t use it, and that’s a bummer.
Why we want to use it
TRBL has been building robust, completely customizable web interfaces for our clients using Advanced Custom Fields’ Flexible Content field type. It’s very, very similar to how Gutenberg Blocks work and this approach has a ton of benefits. Marketers can build not only posts, but their entire site — mega menus, complex footers, pages, and more — all with a layout building tool that’s deliberately designed and customized for the site at hand. This gives content editors the perfect level of customization — everything’s branded, deliberate and controlled, but it’s not to the level of a Visual Composer or similar. Those tools are way too open-ended, provide too much flexibility, and disturbing content combinations arise on the frontend as a result.
We’ve actually been taking this flexible content approach a step further by using WP in a headless role — completely scrapping WP’s PHP template rendering that has absolutely rotted over time and instead writing responsible, maintainable ReactJS interfaces which consume content from WP using its REST API.
See our boilerplate here:
This allows for some pretty neat benefits. We can build React components that map one-to-one with their ACF layout compadres. Let’s take a Slider — it might have a title, a description, a style option that provisions for a few different layouts, and then the slides themselves. The slides could be custom-populated or allowed to be pre-filled by the most recent posts from any given post type. From within WP, we can allow content authors the ability to pick and choose where they want to use this slider and how.
The data can then be consumed by React and used to display a nice, tidy Slider
component filled with props from WP.
Same thing as Gutenberg Blocks, right?
Not today.
So what’s the deal?
Content written and saved by the Gutenberg editor currently is stored in the database as a rendered mess of HTML. I understand why WP did this, because the content
of the post is made up from an arbitrary number of blocks, and there needs to be some sort of standardized way to mash up the content of the article — not to mention what the final, semantic format of the content ends up looking like. This is the way that the classic WP editor has always saved content into the database.
When you retrieve a post from the WP REST API that’s built with Gutenberg, its content might look like this:
<p>Here’s a test Gutenberg post. This is sample content placed into the first little block that pops up.</p> <figure class="wp-block-image"><img src="http://localhost:8080/wp-content/uploads/2018/10/space-1024x576.jpg" alt="Space" class="wp-image-2297" srcset="http://localhost:8080/wp-content/uploads/2018/10/space-1024x576.jpg 1024w, http://localhost:8080/wp-content/uploads/2018/10/space-300x169.jpg 300w, http://localhost:8080/wp-content/uploads/2018/10/space-768x432.jpg 768w, http://localhost:8080/wp-content/uploads/2018/10/space-640x360.jpg 640w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption>Here’s an image with a caption<br></figcaption></figure>
WP generally parses that mess of data using a hierarchy of Gutenberg-specific HTML comments, but when a post is prepared and sent via the REST API, the comments are all stripped out and we’re given a blob of HTML.
I hope I never have to crack into the PHP that parses a content HTML string into its respective blocks via its commented composition. To me, that’s a strange way to do things and I’ve never liked using comments for programmatic purposes. I imagine reverse-engineering that on the frontend to be able to use React components in concert with the data stored in the blocks via manipulating HTML comments, and I’d rather kick the bucket.
What we are used to and actually already have with the ACF to REST API plugin is a nice little JSON array ready for its React-y time to shine:
With this data, we can map
through the blocks
array, dynamically choose which component to grab via the acf_fc_layout
key, and fill the selected component with the props that it expects. Beautiful.
But, if you want to use a React frontend with Gutenberg as of now, you’d have to dangerouslySetInnerHTML
the entirety of the content in a <div>
— unable to make any use of React components at all.
Given the fact that today’s web ecosystem demands media-rich posts and highly dynamic, engaging content, the content of a post is where a component-based infrastructure provides the most value. Without that, there’s not much reason to even bring React into the frontend as it’d just be for the header and the footer of the site at the expense of a lot of added complexity, and that’s a shame.
All hope is not lost, because the WP team is actively evaluating adding an option to consume similarly structured data to its REST API. See here:
That simple addition to the REST API would get TRBL on the Gutenberg bandwagon. For now, we get to dream and hang out in tech-2006.
TRBL’s Suggested Approach
We don’t want WP to simply add an additional, duplicative set of the post’s content, structured by block keys, to API responses. API responses need to remain as tiny as possible which ideally means no duplicative content.
It would be amazing if we were given a query param, like the _embed
parameter — maybe something like _with_blocks
or similar, that replaces the default HTML sent incontent: rendered
with a nicely formatted JSON structure.
There is a plugin that adds this type of formatted block JSON to API responses, but it’s pretty massive:
It adds an entirely new database table, duplicates the response content within content:rendered
, and … it’s another plugin. This should be built into the core and should definitely not add this level of complexity. No shade thrown to royboy769
, because I think we could get a beer and get along, and I think his head is clearly in the right place, but this responsibility lies with WP.
Anyway, what do you think? Any smart ideas out there?
PS — TRBL is about to launch a few separate sites using the code and approach that we’ve alluded to in this post, and we’re extremely pleased with what we’ve been able to pull off. We’ll be talking in-depth about the build process of these projects and will be releasing articles to detail tips, tricks, and lessons learned in the coming months. Stay tuned for that.
In the meantime, maybe we’ll see you in 2006 cyberspace :)