The Taming of the Block - Part II: The practical part

Estimated Reading Time: 15min

This is the second of two posts accompanying the talk I gave at WordCamp Vienna 2020 about how to configure, restrict and lock down the Gutenberg Block Editor. If you have not read part one I highly recommend doing so and come back here afterwards.

After the whole COVID mess hit, this post had been sitting in draft status 99% done for a couple of months. I’ve checked the main facts but some takes, especially the ones concerning future developments, might not be as hot-off-the-press as in February, although still factually correct as of today.

In this post we’ll finally start the taming. 😉 But I think the first post was essential to understand where we’re coming from and why everything that follows from here is important and valuable.

Anyway, let’s get our hands dirty with practicalities then!

The rest of this post will basically be split up in 4 parts as you can see looking at the table of contents.

Difficulty
👶
🔧
🏗️
Risk
🛋️
👷
💀
Stability
🚧
🧪

I’ve also added a couple of emojis to each section that represent various aspects from

  • how easy those things are to change, as in click in UI or write plenty of code
  • to how risky they are, as in problems you can cause
  • to how stable, as in how likely this is to change in the future, these solutions are.

In any case I’ve also added lots of links to documentation, plugins that help you solve particular issues and Github issues where applicable.

So, let’s get started.

Decluttering the block editor

The Gutenberg block editor gives unprecedented powers and possibilities to users and editors. But with great power comes great responsibility. While having all these freedoms is great for most people there also is another side to it: Out of the box the editing interface has become way more complex.

Disabling blocks

At the time of writing this there are (depending on how you count) more than 70 different core blocks. One question that immediately comes to ones mind when reading that number is:

Do you really need all those 70+ blocks?

And I guess most of the time the answer will be: No. But you always have this full list of blocks visible in the editor potentially confusing you and your clients. Let’s try to improve on that.

Hide Blocks with Block Manager

Difficulty: 👶 | Risk: 🛋️ | Stability:

The first and easiest way to do this is by using the Block Manager. The Block Manager actually is a default feature of the block editor that is available via the Editor options at the top right of the editor.

The block manager allows you to hide single blocks as well as entire categories of blocks such as all embed blocks with the click of a button.

One caveat to keep in mind though is that this only hides blocks but doesn’t actually disable them. Also this is only a per-user setting. So you can use it to simplify the interface for yourself but it won’t keep other users from using those blocks.

Disable Blocks with Plugin

Difficulty: 👶 | Risk: 👷 | Stability: 🚧

If you want to actually disable a block you have two possibilities. The first one is to use one of many plugins that let you completely disable certain blocks. One example for this is the plugin Disable Gutenberg Blocks – Block Manager. (I have quickly tried this one and it seems to do its job but I didn’t do a real review so I can’t vow for it.)

Please be sure you don’t disable blocks that have already been used in existing content since otherwise that might break on the next edit. Ideally you’d think about disabling blocks when creating a new website, because doing so later might be tricky.

Disable Blocks with Code

Difficulty: 🏗️ | Risk: 👷 | Stability: 🚧

The other option to disable blocks is writing some code. This has the advantage of being more flexible. Here is a basic example of how to do this in a plugin.

First you need to enqueue a JS file for the block editor:

<?php
add_action( 'enqueue_block_editor_assets', function(){

    wp_enqueue_script(
        'my-block-script',
        plugins_url( 'my-block-script.js', __FILE__ ),
        array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' )
    );

} );

Then you can filter the allowed blocks:

// my-block-script.js
wp.domReady( function() {

    // Denylist approach - the "core/verse" block isn't allowed.
    wp.blocks.unregisterBlockType( 'core/verse' );

    // Allowlist approach - only listed blocks are allowed.
    var allowedBlocks = [ 'core/paragraph', 'core/image'  ];
    wp.blocks.getBlockTypes().forEach( function( blockType ) {

        if ( allowedBlocks.indexOf( blockType.name ) === -1 ) {
            wp.blocks.unregisterBlockType( blockType.name );
        }

    } );

} );

Alternatively you can also filter the available blocks on the server where you can also add more logic, like e.g. only limiting blocks for a certain post type:

<?php
 add_filter(
    'allowed_block_types',
    function ( $allowed_block_types, $post ) {

        if ( $post->post_type !== 'post' ) {
            return $allowed_block_types;
        }
        return [ 'core/paragraph' ];
}, 10, 2 );

Reducing / Changing block configurability

Now that we’ve gotten rid of unnecessary blocks we might notice that the remaining blocks still offer a wide range of configuration options. If we look at e.g. the paragraph block we’ll see plenty of them: Multiple Text and Color Settings:

And again we can ask ourselves the same question:

Do you really need them all?

And again most of the time the answer will be: No.

So let’s see what we can do about that.

Colors and gradients

Difficulty: 🔧 | Risk: 👷 | Stability: 🚧

Colors and gradients actually are the features that are the easiest to configure. If you’ve ever used the add_theme_support() function before you’re all set.

<?php
add_action( 'after_setup_theme', function(){

   // Disable Custom Colors
   // (Color Picker for arbitrary colors)
   add_theme_support( 'disable-custom-colors' );

   // Change Editor Colors
   // (Default colors easily selectable from colored circles)
   add_theme_support( 'editor-color-palette', [
       [
           'name' => 'strong magenta',
           'slug' => 'strong-magenta',
           'color' => '#a156b4'
       ],
   ] );

   // Completely disable any kind of color selection
   add_theme_support( 'editor-color-palette', [] );

   //////////////////////////////////////////

   // Disable Custom Gradients
   // (Color Picker for arbitrary colors)
   add_theme_support( 'disable-custom-gradients' );

   // Change Editor Gradient Palette
   // (Default gradients easily selectable from colored circles)
   add_theme_support( 'editor-gradient-presets', [
       [
           'name'  => 'Red to blue',
           'gradient' => 'linear-gradient(red,blue)',
           'slug' => 'red-to-blue'
       ]
   ] );

} );

Font Sizes

Difficulty: 🔧 | Risk: 👷 | Stability: 🚧

Font sizes actually work just like colors:

<?php
add_action( 'after_setup_theme', function(){

   // Disable Custom Font Sizes
   // (Input for arbitrary sizes)
   add_theme_support('disable-custom-font-sizes');

   // Change Editor Font Sizes
   add_theme_support( 'editor-font-sizes', [
        [
            'name' => 'Small',
            'size' => 12,
            'slug' => 'small'
        ],
   ] );

} );

Style Variations

Difficulty: 🏗️ | Risk: 👷 | Stability: 🚧

Another configuration option for blocks are “Style Variations” a lot of blocks come with. E.g. the Button block has a fill and an outline style.

If you don’t need them you can remove them, although this usually needs a bit of JavaScript. Also you can add your own styles, since block styles basically just are a CSS class that is added to the HTML output of the block for later styling it with CSS.

Just like with disabling blocks we first need to enqueue a JS file which then does the actual changes:

// my-block-script.js
wp.domReady( function() {

  // Unregister a style variation from a core block.
  wp.blocks.registerBlockStyle( 'core/quote', {
          name: 'fancy-quote',
          label: 'Fancy Quote'
      } );
  
  // Add a custom style variation.
  wp.blocks.unregisterBlockStyle( 'core/quote', 'fancy-quote' );

} );

Alternatively there also is a server-side registration helper that needs way less boilerplate code if all you want to do is register a block style.

<?php
register_block_style(
    'core/quote',
    [
        'name'         => 'fancy-quote',
        'label'        => 'Fancy Quote',
    ]
);

unregister_block_style( 'core/quote', 'fancy-quote' );

Please be aware that unregistering styles on the server only works for ones that were registered on the server using register_block_style().

Other Settings

Difficulty: 🏗️ | Risk: 💀 | Stability: 🧪

And finally there are multiple other things one might want to change, like disabling the Drop Cap feature or changing the number of columns a columns block can have. Unfortunately the mechanism to do that is still under discussion and hence there currently is no proper way of doing that, just some really ugly hacks. In case you want to keep an eye on that have a look at this issue.

Consistency & Maintainability

Okay, great, we’ve now gotten rid of everything we don’t need. Which brings us to the next topic:

Sometimes you need to ensure that things are consistent over the whole site and it is easy to make global changes.

Global content with Reusable Blocks

Difficulty: 👶 | Risk: 🛋️ | Stability:

Often you have pieces that should be the same all over your site. For example imagine a call to action for contacting you. This includes your name and a phone number. But when any of that changes you’d normally need to go through all pages with this call to action and manually change them one by one.

But there is a smarter way: Reusable Blocks

You can turn any block into a reusable block. This reusable block can then be used all over your site, but any changes to it are immediately applied to all occurrences of it. This is great to keep things consistent as well as make global changes easily – as long as you plan for it from the beginning.

You can also later turn a reusable block back into a normal one. After that you can again edit this block independently from the reusable block.

This can even be “hacked” into a template system by building a couple of more complex pre-configured pieces of content as reusable blocks. If you’re curious about this have a look at this blog post by Justin Tadlock.

Post Processing with render filters

Difficulty: 🔧 | Risk: 👷 | Stability:

This is all great if you plan for the changes from the get-go. But what if you want to make global changes after the fact?

Well, that’s what the render filters pre_render_block and render_block are for. WordPress runs each block through these filters before them being output so you can alter or completely replace the output of a block.

<?php
// Replace all paragraph blocks with a Ghost
add_filter('render_block', function ($blockContent, $block) {

    if ($block['blockName'] === 'core/paragraph') {
        $blockContent = '<p>👻</p>';
    }

    return $blockContent;

}, 10, 2);

The great thing about this is that it is non-destructive and happens on the fly. No changes are being done to the database but changes get applied immediately and globally.

This is in huge contrast to changing the template in the block definition itself: If there are any changes to it they only get applied after each post using this kind of block has been edited and saved.

Dynamic blocks

Difficulty: 🏗️ | Risk: 🛋️ | Stability:

Related to the render filters, if you’re creating your own blocks you can opt in to implementing them as dynamic blocks. These separate the data storage from the output which is generated on the fly.

A dynamic block is a block that gets it output via render filters as default behaviour.

This is especially useful for blocks that render dynamic content, like the “Latest Posts” core block.

As a kind of bonus this also moves the templating from JS to PHP, just in case you prefer that. 😉

Block Templates

Difficulty: 🔧 | Risk: 🛋️ | Stability:

The next feature we’ll have a look at are block templates.

If you open a new post it will be empty by default. But with block templates you can define a set of blocks that is initially added to each new post. These can either be a template, as in, a standardized base to start from, or a locked down structure that can’t be changed, but only filled with your content.

<?php
add_action( 'init', function () {

    // Set template for posts
    $post_type_object = get_post_type_object( 'post' );
    $post_type_object->template = [
        [ 'core/image' ],
    ];
    // ...and lock it down so blocks can't be changed.
    $post_type_object->template_lock = 'all';

    // Set template for Custom Post Type on registration
    register_post_type(
        'book',
        [
            'public' => true,
            'label'  => 'Books',
            'show_in_rest' => true,
            'template' => [
                [ 'core/image',     [ 'align'       => 'left'               ] ],
                [ 'core/heading',   [ 'placeholder' => 'Add Author...'      ] ],
                [ 'core/paragraph', [ 'placeholder' => 'Add Description...' ] ],
            ],
        ]
    );

} );

For some use cases this might even be able to replace the custom fields based approach a lot of us have been using up until today for enforcing a certain structure for a post.

Regaining full control of CSS

Difficulty: 🏗️ | Risk: 👷 | Stability: 🧪

This brings us to the last topic I’d like to have a look at today. This is also something I had to skip for the talk.

Currently a website built with Gutenberg usually contains multiple CSS files on the front end:

All together with e.g. the TwentyNineteen theme these weigh around 250kb over 3 files containing plenty of code for blocks you might never use and quite some redundant, overwritten styling.

Also it forces one to work with the basic layout approaches WP core deems reasonable. If you take completely different approaches (e.g. using CSS grid instead of Flexbox for Columns or Galleries) this might and probably will collide.

The Gutenberg team is aware that this area is in need for improvement and is currently working on a Global Style System.

But since this is still in very early stages until then one approach you can already use today is to totally remove all CSS styles from core and roll your own. Like this you can load CSS that only contains what you really need, especially considering that you might have disabled some blocks entirely anyway.

I’m not going to go into the details here since this could probably fill an entire blog post on its own, but this are the basics I’ve taken from the exhale theme by Justin Tadlock:

<?php
add_action('wp_enqueue_scripts', function () {

    // Disable core block styles.
    wp_dequeue_style('wp-block-library');

});

add_action( 'enqueue_block_assets', function() {

    // Unregister core block and theme styles.
    wp_deregister_style( 'wp-block-library' );
    wp_deregister_style( 'wp-block-library-theme' );

    // Re-register core block and theme styles with an empty
    // string. This is necessary to get styles set up correctly.
    wp_register_style( 'wp-block-library', '' );
    wp_register_style( 'wp-block-library-theme', '' );

} );

With this code you’ll end up with completely unstyled blocks in the front- as well as in the backend. Especially if you’ve also limited the blocks that are available on your site you can probably slim down your CSS quite significantly.

But if you want to go down this route be very well aware of what you’re doing here since you’re shifting a lot of burden WP core usually handles onto your own shoulders. You’ll constantly play a game of catch up with core styles from now on. Only do this if you really need it and are very well aware of the consequences, especially concerning the maintenance of this approach in the future.

Talking about the future…

The future

As we have seen by now there are a lot of things you can already configure today, even if some of it is still lacking. In any case the development of Gutenberg is dashing forward like a steamroller, so beyond the things I’ve already covered there is plenty of new stuff coming up soon.

What’s coming up next?

With almost 2000 open issues on Github and being a sole freelancer just watching along I can obviously not give you a complete overview of what is currently cooking in Gutenberg, even less so a prognosis on where it is heading. But there is one thing I personally believe is the most dramatic upcoming change:

Full site editing

Currently the editor is still limited to the post content, merely replacing the old editor without structurally changing anything about the way you manage the rest of the site like menus, sidebars and even the whole site layout. This is about to change and there are multiple parts to it.

Basically the idea is that not only the post content but everything else too is becoming a block.

Menus - Blocks, Widgets - Blocks. Even things like “Site Title” or “Post Content” will become (a special kind of) blocks, so called “theme blocks”. A theme itself will then be block-based instead of consisting of the current PHP set of templates.

This approach offers many interesting opportunities, for example you could enable users to alter templates using the familiar block editor interface instead of needing to work with PHP template files. This will probably also change the current theme landscape quite a bit.

But how all of this will work is still under heavy discussion. The details will definitely still change. Maybe even the overall concept will still be changed before things actually get released. If you are curious though head over to Github for more details on what’s currently brewing.

Conclusion

Wow, I guess you’re heads are steaming right now. I know that all of this is a lot and quite hard to handle, especially for us in the WordPress community who historically haven’t been used to such fast and drastic changes. I also have to admit that I currently often struggle with Gutenberg, technically as well as conceptually. A lot of its features still are simply incomplete, inconsistent or not customizable enough.

But I think, or let’s say hope, that as long as we get more and better options to configure, restrict and lock down all those new possibilities according to the specific needs of us and our clients Gutenberg has the potential to be great for everyone. But I guess only future will tell how things will turn out in the end…

Power to the users - by default and with the possibility to limit it.

P.S.: If you have any thoughts, corrections or additions to this post please feel free to reach out to me.