I’ve spent the last 8 months telling anybody I talk to about custom WordPress block development that they were way less scary and much easier than I thought they were going to be as somebody with minimal React experience, and that achieving a 1:1 editor experience where you manipulate directly in the content area instead of metaboxes or panels really comes alive when you reuse the same markup and CSS from the front-end and leverage the React components the block editor ships with. Because of that, I think a big game-changer for adoption and shifting thinking would be to find a way to unify templating between the front-end and the editor, essentially swapping the places where you output content with the corresponding editor component.
So what had happened was… I was once again going on and on about this to Mark Jaquith, who blessedly seems to enjoy walls of text from me about programming puzzles, and it turns out he’s been thinking about the same thing as he gets into block development. A weekend later, and:
Here’s the premise: many metaboxes and custom blocks being built for clients represent a particular front-end component for a site where the content management needs are more tightly curated than something like a pattern. The React-based WordPress block editor (sometimes referred to as Gutenberg) is a powerful tool for WYSIWYG editing that continues to prove to be somewhere between a speed bump and a roadblock for long-time WordPress developers who historically have been more PHP-centric.
The developer workflow being targeted by this work is one where front-end outcomes are prioritized, beginning with the “slice and dice”, if you will. By leveraging the familiar parts of PHP-based templating and creating a bridge that demonstrates the power of React when combined with the markup and styling already being done for the front-end, we can de-duplicate code, help demystify the critical role of JavaScript in modernizing WordPress, and serve as an on-ramp for PHP-centric developers to create compelling and delightful 1:1 live preview editing experiences.
In a public blog post, it’s important that I preface this with “these are experiments and there will likely be many failed paths”, and that the focus remains on the problem to be solved during the research and experimentation phase, not on implementation details. All of that said, imagine that we could figure out a way to unify the markup output of a block such that writing this once would produce both a piece of content on a website and the primary editing interface to manage it:
<div class="info">
<h2>{{headline}}</h2>
<p>{{info}}</p>
</div>
I’m using Mustache-style tokens here simply because it’s familiar across many languages and is also used in WordPress, continue to remember that the syntax itself is not the goal, but merely a starting point – a thesis, if you will. It’s an exciting one, at least to me! So let’s get into how I’m thinking about this particular angle.
Why is a 1:1 live preview the ideal?
In a metabox context, you’re probably used to creating a form-centric experience where users need to save to preview their changes, and have probably also struggled at some point with the fact that out of the box WordPress does not have a concept of draft post meta. This is what we call “save and surprise”, and it’s a disruptive and clunky experience that we’ve gotten a little too used to.
This goes beyond the 1:1 visual representation and live-updating preview, though. After all, you could still end up with a form-based experience that is updating a separate preview area. The full ideal is what some might call front-end editing: manipulating content in place, being able to get a sense of your content in context as you work, whether text or image or something more. Computers should be a tool for humans to get things done effectively, not an entity for us to accommodate.
Ready? Here we go.
If you don’t know a single thing about React, or if you just want to know what to focus on for the rest of this post, here’s the super simple version: React is a JavaScript library that makes web (and now native) UI “react” to data changes. As in, you have some data, and whenever it changes, React knows which part of the UI needs to do what because of it. Content editing is fundamentally a thing where you change some data yourself, and the editor is a display that reacts to those data changes. The WordPress block editor uses React to be a dynamic and modern web experience where you can type into place.
Let’s go back to that thesis and take this overly simplified example of a text-based front-end component, ignoring editable data for the moment:
<div class="info">
<h2>Here is my headline</h2>
<p>And here is some more information you need to know</p>
</div>
Blocks have two places where they output: on the front-end, and in the editor. So on the front-end, this would be the block’s output. In the editor, the output can be written using what’s known as JSX, where the X stands for XML and provides a clean and familiar syntax. If we take that front-end component and turn it into JSX, here’s what it looks like:
<div className="info">
<h2>Here is my headline</h2>
<p>And here is some more information you need to know</p>
</div>
There is only one difference: class
becomes className
. That’s it.
So if we include the front-end CSS into our editor stylesheet, scoped with at least the .editor-styles-wrapper
class, this will now be styled just like the front-end of the site. (Well, mostly, there are some nuances around defaults such as block width, but we can add details after we get the basics down. Also yes so far you need a build step.)
Now let’s add some data in. We’re going to use block attributes and make this a dynamically rendered block – that is, rather than storing fully formed HTML into the database, the output relies on block attributes, a bit more like post meta minus the issues with drafts and revisions. Again ignoring the details around how attributes are defined and populated, we get something like this:
<div class="info">
<h2><?php echo $attributes['headline']; ?>></h2>
<p><?php echo $attributes['info']; ?>></p>
</div>
The content within the h2
and p
tags has been replaced with outputting variables from PHP. These variables represent user-editable content, so those are the “fields” we need to surface in the block editor.
The block editor ships with many React components that can essentially be plugged into place within the markup. You know, like a fields API! Once again, we’re going to skip over the details about things like import
you would need in a full file, but your markup output will look something like this:
<div className="info">
<RichText
tagName="h2"
placeholder={__('Enter headline', 'my-namespace')}
value={headline}
onChange={(headline) => {
setAttributes({ headline });
}}
allowedFormats={[]}
/>
<RichText
tagName="p"
placeholder={__('Enter info text', 'my-namespace')}
value={info}
onChange={(info) => {
setAttributes({ info });
}}
allowedFormats={['core/bold', 'core/italic']}
/>
</div>
These things like tagName="h2"
are called props
and we’ve broken them into separate lines for readability and maintenance, but you can see that much like the initial move into JSX maintained that HTML/XML style, these are not entirely dissimilar from HTML attributes. That change from class
to className
? It’s because class
is a JavaScript keyword already, so the prop
is named className
.
If we were to delete all those props
, you’d end up with a neatly self-closing <RichText />
“element”, which is what’s known as a React component. This is an example of a component that the block editor provides out of the box, allowing you to type directly into place within the block itself, instead of relegating the editing experience to a contextless form input.
At this point, you might have noticed something: the basic markup is duplicated between the PHP and the JS(X) sides of the block output. Even if you are familiar with the rest of the things you need to do to make a block work, this is a not-insignificant hurdle, but it’s the magic that makes the editor a true 1:1 experience that reacts to the data as you input it.
When we have duplicated markup, we turn to templates. If you’ve ever used a templating system like Mustache, this version of the markup might look familiar to you:
<div class="info">
<h2>{{headline}}</h2>
<p>{{info}}</p>
</div>
So what if we harnessed something like a templating system where we could just write our markup once and turn that into the PHP version and the React/JSX version? That’s what this little exploration is about and hoping to eventually solve. Is this a potential solution for all blocks? Absolutely not. I’m talking very specifically about custom blocks that represent front-end components on custom developed sites, typically by agencies/consultants for their clients. Within these developer groups there are a lot of very smart people who are feeling left out by the (IMO necessary) shift to JavaScript to drive the UI experience of a PHP-based project. They generally also want great experiences, but aren’t quite sure how to get there and are caught up in an overwhelming amount of information around core blocks and patterns and full site editing when in reality, our specific needs in this area are often currently best served by custom blocks.
It’s unlikely we’ll be able to solve for every complex experience a block might need with a template-based approach, but at the very least it can serve as a place to start transitioning developer thinking from PHP-centric static experiences to ones that also embrace JavaScript to bring that dynamic and, yes, delightful experience to WordPress users.
4 responses to “Exploring custom blocks from a PHP-centric developer UX point of view”
“Is this a potential solution for all blocks? Absolutely not.” Why not? Assume vast ignorance on my part.
Fundamentally we have different priority audiences – WordPress as a project and Gutenberg as a feature within that project prioritizes the UI-centric user, and with that comes building for flexibility and not control/curation. That flexibility is great for a foundation, but for the target audience of the custom developer/agency clientele, it does not serve their needs.
WordPress as a distributed project with distributed themes and plugins doesn’t need to see a proliferation of public custom blocks with their own markup and styling, it just doesn’t scale. Patterns of core blocks make far more sense in the context of distribution. It’s entirely possible and perhaps even likely the the correct long-term solution in core is to introduce concepts around positional and regional locking of blocks and greater control over the markup that is output by things like groups. However, client work needs to work within current constraints and right now that means custom blocks in many places, so we can solve for our own current needs while recognizing that it is a need borne of circumstance, not necessarily the ideal or even suitable for the majority.
Hi Helen! I was inspired by your presentation at WordCamp, and came to your site to find this related post. You’ve convinced me that I can do it, and I’m trying to match up your lesson with the documentation… or a tutorial. Do you have any pointers on how to get started? Thank you SO much!
This idea is great! Would love to see it integrated into Core.