Getting the balance right: Making the most of WordPress’ block editing experience

WordPress released the Gutenberg block editor in late 2018 and since that time we’ve learned a lot about what does—or doesn’t—work when it comes to building custom blocks.

At The Code Company, we have worked on many new site builds and retrofitting existing sites using the Gutenberg editor. Using this experience we developed our own strategy when it comes to Gutenberg.

This article will predominantly focus on using Gutenberg as an article editor and incorporating the customisations that come up in custom editorial workflows.

Advanced Custom Fields (ACF) Blocks for Gutenberg

Our initial approach was to use ACF Blocks. Rather than building custom Gutenberg blocks with React, etc, ACF blocks allow you to build custom blocks using ACF fields and a relatively simple PHP-based template.

This made a lot of sense for us because:

  • We were already very experienced with ACF as we have been using it for many years for custom theme builds, applications and the like. Using ACF blocks means we can leverage our existing knowledge base for this new technology.
  • It is much more time efficient to work with over building out native Gutenberg blocks in React (etc). We get access to ACF’s huge selection of field types and we can build out templates using familiar PHP/HTML with all the typical ACF APIs, get_field() etc.

So it sounds like a perfect fit right? We get the benefits of using a stable technology that we have a lot of experience with and it is more time and cost effective.

Not quite, unfortunately.

ACF blocks are a great tool for developers, however, we found out rather quickly that there are some user experience issues that come with this approach.

The main problem is that the ACF UI is very different from the native Gutenberg experience. Typically native Gutenberg blocks are edited inline in a ‘what you see is what you get’ (WYSIWYG) fashion. This also includes some additional controls in the sidebar to tweak things like background colours etc. ACF blocks are edited entirely with ACF fields in the sidebar; there is no WYSIWYG editor — only a preview.

This is fine for simple / small blocks, but the bigger and more complex they get the more confusing and convoluted they become. This can get to the point that the user experience is worse than the flexible layouts we were using.

For example:

When ACF blocks are combined with native blocks, it can get even more confusing for users. You end up with two very different UIs when editing content.

A Better Approach to Gutenberg in WordPress

There is a better way, and it involves building some custom Gutenberg blocks (native ones, not with ACF!).

Taking a step back, we realised much of what we were building with ACF blocks was layout-related. We would have one ACF block for each row in a template. For instance, we might have a three column layout for testimonials built as a single block. There are three testimonials, each with a testimonial quote, the person’s name and a link, which means there nine separate fields for this very simple block/row.

A better approach to building this testimonial block would be to decouple the three column layout part from the testimonial part. That way each of the testimonials could be edited individually. It also meant we could easily change it to a four column testimonial row if we wanted to without the need to create an entirely new ACF block for it. Better all around!

How to Build Layouts in Gutenberg using InnerBlocks

Gutenberg actually makes this really easy to implement as it provides a component called `InnerBlocks`. `InnerBlocks` allows us to nest/embed blocks within our blocks, which can be very powerful for building layouts.

For example, to build our testimonials layout, we might do something like this:

<div className={props.className}>
  <InnerBlocks
    templateLock="insert"
    template={[["tcc/testimonial"], ["tcc/testimonial"], ["tcc/testimonial"]]}
  />
</div>

When this block is added to the editor, it will automatically create a three nested tcc/testimonial blocks as per the template we set. It will also be locked to just three columns as we are telling it to prevent inserts / deleted with the templateLock="insert" parameter.

Assuming `tcc/testimonial` is a custom block for a single testimonial, a user could easily edit each of the separate testimonials in this layout. They would only have three fields (at most) to deal with at any given time. So it’s much simpler.

We may even choose to build the `tcc/testimonial` block using ACF. Any UX issues would be isolated to the self contained block and it would likely be much easier, quicker and cheaper to build and maintain over a custom block.

Reusable Layout Gutenberg Blocks

There is a more powerful way to use layouts like these as well, if we generalise a bit. Rather than having the layout restricted to just the `tcc/testimonial` block, we can open this up and allow any kind of block to be embedded. Then we have a reusable three column layout that can be used for anything, not just testimonials.

The way we do this is to have a general “column” block that we use in the template, like so:

<div className={props.className}>
  <InnerBlocks
    allowedBlocks={["tcc/column"]}
    templateLock="insert"
    template={[["tcc/column"], ["tcc/column"], ["tcc/column"]]}
  />
</div>

We would then have a very basic tcc/column block, which looks something like this:

<div className={props.className}>
  <InnerBlocks templateLock={false} allowedBlocks={"*"} />
</div>

If we add a three column layout into the block editor, we get three columns that can host any content. This content could also be more than one block. For example, you could manually build out the testimonials in the editor using this set up. You might add a quote block followed by a paragraph for the person’s name / link into each of the columns.

This is very similar to Gutenberg’s built-in columns block, however, building out custom layout blocks in this way gives us much more flexibility. It’s rare that we just want some columns as set out in the example above as usually there are other requirements. A common example of this might be setting a background video or the like.

Final Thoughts on our Gutenberg Strategy

It’s important to understand that Gutenberg is not a replacement for a page builder. Though we do use it to build out pages, it is designed for, and best suited for, post content.

When it comes to user experience and flexibility, page builders win out over Gutenberg. It is much more time and cost effective for one of our clients to build a landing page using a page builder (which would likely take a couple hours) rather than needing to pay developers to build out custom templates / blocks for everything.

On that note, our preference in the page builder space is Beaver Builder. We find it has the least overheads and is the easiest to work with from both a developer and an end user perspective.

Our philosophy when comes to deciding the best approach for a project is: a page builder is best suited for landing / marketing pages, Gutenberg for everything else.

There are times when we decide Gutenberg is a better fit, but we assess that on a case by case basis. It all comes down to the client’s requirements.

Zac Scott

Zac is the DevOps and Technical Manager at The Code Company. He works with our engineering team heavily to ensure coding standards and best practices are followed. Zac has a history of complex functionality and data heavy projects.