With WordPress 5.0 a new block-based editing experience will be introduced (a.k.a. Gutenberg). This new editing experience is available via the Gutenberg plugin. By adding this plugin to your (development) WordPress website, you can preview the new editing experience.
At the time of this writing, Gutenberg is still under-development so I recommend only installing it on development websites (not a live site).
Building Your Own Blocks
The new block-based editor (Gutenberg) is built to be extensible, allowing developers to create their own custom blocks.
Do You Need a Custom Block?
Before building your own block, I suggest exploring what you can do with the built-in features of the new block-based editor. Mika Epstein has a great post, You Don’t Need a Block, where she looks at the Shared Block functionality and how it can be used to create your own custom block without any coding.
Clearly, shared blocks won’t be a solution for every need but it is one more tool in your arsenal when bending WordPress to your will.
Custom Block Requirements
In learning about creating WordPress custom Gutenberg blocks, I’ve found most instructions and examples take advantage of features in the newer versions of JavaScript. To support older browsers, a build process is used to to convert this new JavaScript code to the equivalent older, more universal JavaScript (this process is called transpiling and uses a tool like Babel).
While I can see this is a great way to build WordPress custom Gutenberg blocks, I found it wasn’t a great way for me to learn to build custom blocks. There are two factors I don’t like in this setup:
- It requires I learn newer JavaScript syntax and how to build custom blocks at the same time. I prefer to learn one thing at a time.
- It requires a build process using something like npm. I think build processes can be great but I prefer to eliminate them when I’m learning and iterating quickly.
I fully expect I will reach a point where I say, “Wow, I really need to use these newer features of JavaScript. I guess it is time to start using a build process for creating my blocks,” however until that time, I’ll continue working without one.
Example Blocks
The following are blocks I’ve built specifically for learning. In addition to the final product, I’ve done my best to arrange the history so that each commit is informative.
I start each block using the WP CLI scaffold command. e.g. I run something like the following on the command line.
Create the Plugin
$ wp scaffold plugin my-plugin
Create the Block within the Plugin
$ wp scaffold block my-block --plugin=my-plugin
Add code to the plugin file to load the block code
In the root plugin file (e.g. my-plugin.php
), I add
include( plugin_dir_path( __FILE__ ) . 'blocks/my-block.php' );
Resulting Plugin
This results in a plugin like my My Plugin Starter Block. This creates a custom block you can add and remove, however the content in this block can not be modified – it is hardcoded. The following blocks are all built starting from a base like this one.
Blocks I’ve Built
You’ll notice I prefix all of my blocks with “Iron Code” in order to differentiate them from other blocks (and as part of my own branding).
Update: I’m now defining my WordPress block attributes in PHP rather than JavaScript for the reasons I outline in the linked blog post.
Iron Code Basic
Goal: to create an editable block with minimal code changes.
The block has one input field and uses this to render a single paragraph on output. If you view the commits, you can see the steps I took this make this block.
This block will be stored in the post content (along with the other blocks) as the following:
<!-- wp:learn-iron-code-block-basic/iron-code-basic -->
<p class="wp-block-learn-iron-code-block-basic-iron-code-basic">The user typed this in.</p>
<!-- /wp:learn-iron-code-block-basic/iron-code-basic -->
Note: Since this uses an input field only a single line is supported.
Iron Code Two Elements
Goal: create a minimal block with two editable fields
Viewing the commits, you can see I first make it editable with one field (like the Iron Code Basic block) and then add the second field.
This block will be stored in the post content (along with the other blocks) as the following:
<!-- wp:learn-iron-code-block-two-elements/iron-code-two-elements -->
<div class="wp-block-learn-iron-code-block-two-elements-iron-code-two-elements">
<h2 class="learn-iron-code-block-two-elements--heading">User entered heading.</h2>
<p class="learn-iron-code-block-two-elements--content">Body content provided by the user in the Gutenberg editor.</p>
</div>
<!-- /wp:learn-iron-code-block-two-elements/iron-code-two-elements -->
Note: Since we are generating multiple elements for editing, we use nested calls to el()
(i.e. wp.element.createElement()
).
Iron Code Rich Text
Goal: use the Gutenberg RichText component to create a field with a rich contenteditable input area, providing users the option to add emphasis to content or links to content – the RichText component handles multiple line of input
This block will be stored in the post content (along with the other blocks) as the following:
<!-- wp:learn-iron-code-block-rich-text/iron-code-rich-text -->
<p class="wp-block-learn-iron-code-block-rich-text-iron-code-rich-text">My first line<br/>My second line, which has a <strong>bold</strong> word.<br/>My third line</p>
<!-- /wp:learn-iron-code-block-rich-text/iron-code-rich-text -->
Note: By default, the RichText component will generate an html paragraph (<p>
) with line breaks (<br>
) between line.
Iron Code Rich Text List
Goal: create a block using the RichText component to create a ul/li list
This block will be stored in the post content (along with the other blocks) as the following:
<!-- wp:learn-iron-code-block-rich-text-list/iron-code-rich-text-list -->
<ul multiline="li" class="wp-block-learn-iron-code-block-rich-text-list-iron-code-rich-text-list">
<li>One</li>
<li>two</li>
<li>3</li>
<li>rouf</li>
<li>FIVE</li>
</ul>
<!-- /wp:learn-iron-code-block-rich-text-list/iron-code-rich-text-list -->
Note: By default, the RichText component will render the value as a paragraph (<p>
) with line breaks (<br>
). In the final commit, you can see we modify the RichText component to render the value as an unordered list (<ul>
/<li>
).
Iron Code Shortcode
Goal: create a block that renders front-end output on page load using PHP (similar to a shortcode)
This block will be stored as a placeholder only in the post content (along with where the other blocks are stored) as the following:
<!-- wp:learn-iron-code-block-shortcode/iron-code-shortcode /-->
Note: Even if the JavaScript for the block stores actual markup in the post content, that markup will be overridden by the PHP rendering when displayed on the front-end.
Iron Code Basic Focus
Goal: to create an editable block that displays differently in the backend editor depending on whether or not it is in focus
This block is similar to the Iron Code Basic block (found above), in that it has a single input field that renders a paragraph on output. This block goes one step further, using props.isSelected
in the edit function to display this block differently depending on whether or not the block is selected (i.e. in focus).
- When selected, the block displays a single input field (just like the Iron Code Basic block)
- When not selected, the block displays a paragraph (in the same way, it displays on the front-end)
Using this technique we can allow the user to complete a number of fields when the block is selected and once it is no longer selected, we can render the block the way it will appear on the front-end.
Other Notes and Resources
createElement
In my blocks, you’ll notice I create a variable called el
and assign it the wp.element.createElement
. I do this because calling el()
is more tidy than calling wp.element.createElement()
. This raises the question, what is this function? The new WordPress editor is built with React. Calling wp.element.createElement()
(or el()
) is the same as calling React.createElement()
.
Check out this helpful introduction to React.createElement.
Leave a Reply