Chapter 11. Project Gutenberg, Blocks, and Custom Block Types

When the new WordPress editor was proposed in January 2017, Matt Mullenweg wrote:

The editor will endeavor to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Less than two years later, the block editor (aka the Gutenberg editor) was included in WordPress version 5.0, bringing with it a new way to edit posts and a new way to develop experiences with WordPress.

Note

The original project to build the block editor was codenamed “Gutenberg.” We now prefer the term block editor or simply WordPress editor, but many people and posts you run across will refer to the editor itself as Gutenberg.

The Gutenberg team has put together the Block Editor Handbook to help both users and developers get up to speed with using Gutenberg. The Block Editor Handbook is a tight, well-written, and evolving piece of documentation that you should read. Like, right now go read it, and then come back here. We will reference specific sections of this handbook later on.

In this chapter, we briefly cover the general features of the block editor, build a minimal block as a starting point, and then dive a bit deeper into the features most relevant to application development.

The block editor is built primarily in JavaScript (using the UI), and managed as a Node.js project. Though the Gutenberg handbook will help you code a block, it can be hard to tell what parts of the example code are JavaScript, React, or Gutenberg. Understanding how the various technologies work together will help you as you work to extend WordPress. We have tried our best to make it clear in our examples where the code comes from.

The WordPress Editor

The current WordPress editor is built around the unit of blocks. These blocks, representing paragraphs, headings, lists, images, and more complex components, are placed in a series. Some blocks, like the group and column blocks, can have other blocks nested inside them. You can drag and drop blocks within the editor to reorder them (see Figure 11-1).

images/bwwp_1101.png
Figure 11-1. The WordPress Block Editor

Blocks can be added by clicking the + in the UI or by typing / followed by the block name within the empty space of the editor. Pressing the enter key within a paragraph block creates a new paragraph block. Some blocks will automagically appear when you type certain Markdown-based characters into an empty block. The * character will start an unordered list. The ## characters will start a secondary heading.1

One block can be edited at a time. You click on a block to bring it into focus and switch into its editor view. While in focus, the Block tab in the right sidebar contains settings specific to that block. Clicking another block or in the empty area of the editor will put the focus block into the frontend view.

The WordPress editor mirrors the frontend as much as possible. Some blocks will use placeholders or have slightly different styling to make things easier to edit, but developers are instructed to have the editor views of their blocks resemble the frontend view of their blocks as much as possible.

The Classic Editor Plugin

If you have a site with plugins or features that require the classic editor, or you are just a big fan of the old TinyMCE-based editor, you can install the Classic Editor plugin on that site. This plugin allows you to selectively or globally use the classic editor to edit any post or page. According to the README file, “Classic Editor is an official WordPress plugin, and will be fully supported and maintained until at least 2022, or as long as is necessary.”

We suggest using the Classic Editor plugin as a last resort. While the plan is for that plugin to be supported through 2022, the block editor will become an increasingly integral part of the WordPress dashboard and other plugins and themes built on top of it.

Creating Your Own Blocks

Using blocks is fun. Creating your own blocks is even funner…more fun…sometimes fun. It can be difficult, but let’s start with the smallest possible block and build up from there.

Minimal Block Example

The bare minimum required to add a block to the editor is to make a call to wp.blocks.registerBlockType() in some JavaScript run on the editor page:

wp.blocks.registerBlockType( 'bwawwp/minimal', {
  title: 'Minimal Block Example',
  category: 'common',
  edit() {
    return 'Minimal block editor content.';
  },
  save() {
    return 'Minimal block frontend content.';
  },
} );

The full docs and list of options can be found in the Block Registration section of the Block Editor Handbook.

Our minimal block passes in the name of the block and an array of arguments. Names must be unique and should be prefixed with the namespace or slug of the plugin loading the block. Names must start with a letter and can contain only lowercase letters, numbers, and dashes.

Our minimal block also passes in a title and category. The title can be any descriptive string, to help users find it in the block list. Later, we will cover how to add a new category to group related blocks. The categories included in core WordPress are common, formatting, layout, widgets, and embed.

The workhorses of the registerBlockType attributes are the edit and save attributes, for which we pass in functions to compute and return the structure of your block. You’ll use the edit function when the block is rendered in the editor (see Figure 11-2). The save function is used when the post is saved, before blocks are serialized into the post_content.

In the minimal block example, we just return a simple string. Note that any HTML included in these strings is going to be sanitized and converted into HTML entities. To generate markup with your blocks, you are going to have to use the wp.element.createElement() function.

images/bwwp_1102.png
Figure 11-2. Minimal block in the editor

We can build a plugin with just one folder, and two files to load our block:

  • block.js

  • minimal-block-example.php

Here is code for minimal-block-example.php that will enqueue this block.js file:

/**
 * Plugin Name: Minimal Block Example
 */
function enqueue_min_block() {
	wp_enqueue_script(
		'minimal-block',
		plugins_url( 'block.js', __FILE__ ),
		array( 'wp-blocks' )
	);
}
add_action( 'enqueue_block_editor_assets', 'enqueue_min_block' );

This is similar to how we enqueued other JavaScript in Chapter 9. In this case, we are hooking into the enqueue_block_editor_assets action instead of the regular wp_enqueue_scripts action. Note also that our block JavaScript has wp-blocks as a dependency. As we add functionality to our blocks, we will need to include other Gutenberg-related packages here.

Note

This example demonstrates the minimum requirements for a plugin as well. The only value you need in your header is the “Plugin Name.” The rest are optional. Some are highly recommended, as we cover in Chapter 3.

From here, return to the docs at WordPress.org and go through the “Writing Your First Block Type” tutorial. This covers adding styles, using editable fields, adding toolbars and settings, and creating dynamic blocks that update on the fly.

Using Custom Blocks to Build App Experiences

Imagine our SchoolPress teachers want to be able to create new homework assignments. They could use Microsoft Word or Adobe Acrobat, or just type things up in a regular WordPress post. But we want something that integrates with the rest of the app we are building and will store assignment responses into a database for reporting and other functionality.

We could build a form with custom PHP. We could build something more dynamic in React that stores data into WordPress through the WordPress REST API. We could use the Advanced Custom Fields plugin along with your homework CPT to lay out the data needed. As with many tasks in WordPress development, or development in general, there are many reasonable options.

One option that makes some sense is to create a homework CPT and custom blocks and block templates. By building on the block editor, we start with a UI that is already familiar to our users. We can code our custom blocks and block templates so that homework assignments will always include data in the structured format our WordPress-based app will need.

The Homework Blocks

To support our homework app, we add a couple of blocks. The homework/instructions block will go at the top of our homework and include a due date set via block settings. Multiple homework/question blocks will go below. Each question block has a RichText field to enter the question and a question type set via the block settings. The question types could be true/false, multiple choice, or essay.

The full code for these blocks can be found in the Chapter 11 folder of this book’s GitHub repository.

Saving Block Data to Post Meta

By default, attributes on blocks are stored inside of specially formatted HTML comments in the post_content body. The instructions block looks something like this before being converted for the frontend:

<!-- wp:homework/instructions -->
<p class="wp-block-homework-instructions-content">Email me your answers.</p>
<p class="wp-block-homework-instructions-due_date">Due Date: 2020-11-01</p>
<!-- /wp:homework/instructions -->

If our block is configured correctly, the content and due date are editable from the block editor and settings panel for those blocks. And things will then show up on the frontend of the website.

However, we might want to be able to sort homework assignments by due date or develop other reports around data set in our blocks. This is the kind of thing that would be possible if that data were stored in post meta.

To link block attributes to post meta, we need to register our post meta fields. We don’t always register post meta. You can just call the update_post_meta() function directly and add any data you want. However, when manipulating post meta through the REST API, we need to register it:

register_post_meta( 'homework', '_homework_due_date', array(
    'show_in_rest' => true,
    'single' => true,
    'type' => 'string',
    'auth_callback' => function() {
        return current_user_can( 'edit_posts' );
    }
) );

Now we can simply set the source in the block attribute to link to our post meta:

wp.blocks.registerBlockType( 'homework/instructions', {
	// ...

	attributes: {
	    content: {
	        type: 'array',
	        source: 'children',
	        selector: 'p',
	    },
	    due_date: {
	        type: 'string',
	        meta: '_homework_due_date',
	        source: 'meta',
	        default: '',
	    }
	},

	// ...
}

You can find more details on how to edit post meta through blocks in the “Store Post Meta with a Block” tutorial in the Block Editor Handbook.

Tips

Gutenberg development is complicated, fast-changing, and worthy of a book of its own. We have covered the basics here and a few techniques that should be useful to app developers working with Gutenberg. Here are some general tips that will help and some areas for further reading.

More Tips

Zac Gordon’s “31 Tips for Gutenberg Development” includes some great tips and also direction into advanced topics in block development.

Learn JavaScript, Node.js, and React More Deeply

Learning vanilla JavaScript, Node.js, and React more deeply will help you with your WordPress block development. At the very least, take some time to read up on, experiment with, and gain a general understanding of how each of these technologies works. You’ll find that debugging issues with Gutenberg development is much easier if you can better tell which layer of your stack the issue is coming from:

JavaScript

We cover JavaScript and its history with WordPress in Chapter 9. The stronger your JavaScript skills, the easier you will find it to develop blocks. JavaScript: The Definitive Guide, by David Flanagan, and JavaScript: The Good Parts, by Douglas Crockford, are two great books for learning JavaScript. You can browse them to pick up the basics and use them for reference or dive into them to “learn JavaScript deeply.”

Node.js*

Node.js is a JavaScript runtime that will run in your server environment. Several Node.js-based tools are used in the typical Gutenberg build setup, including webpack, Babel, and the Node Package Manager (npm). Webpack is used to compile all your JavaScript into a single bundle to be deployed to the browser. Babel is used to convert ESNext and JSX code into JavaScript that will run across the widest range of browsers. The npm is used to install JavaScript packages and manage the dependencies between them. Both webpack and Babel are typically installed as node modules. You may also want to use additional node libraries in the JavaScript code for your blocks. You can install and manage those via npm. The “JavaScript Build Setup” section of the Block Editor Handbook will walk you through installing node and npm, then installing the @wordpress/scripts package, which includes the recommended default configurations for webpack and Babel.

React

We give a full description of React in Chapter 9. In summary, React is a JavaScript library for building interactive UIs that is used extensively in the block editor screens. A WordPress block can be viewed as a collection of React UI components designed to serve a common editor or content style use case. WordPress has its own library of React components specific for building blocks. These can be combined with other React components or custom developed components. Experimenting with React outside the context of building a Gutenberg block will help you to get familiar with React in general. When you run into issues building WordPress blocks, you will be better equipped to know if those issues are React issues or WordPress issues, which will help you to know where to go for help. If you’d like to dive deep into React, check out the book Learning React, by Alex Banks and Eve Porcello. Just going through the official tutorial on the React website or one of the other examples there will be very useful as well.

1 A full list of formatting shortcuts and other useful shortcut keys can be found on the WordPress site.