This is the second part of a WordPress Gutenberg Blocks series.  To follow this I’m assuming you understand part 1.  The repo for part 1 is located here  if you want to pick up where we left off.  The completed source code here is available in that repo in the branch ‘article2/richtext‘

Outline:

We left off last time with a very boring block.  We did the minimum to get something to show up in the editor (and that was enough for one article), but it didn’t show us why Gutenberg is going to be so fantastic at bringing true WYSIWYG to the WordPress editing experience.  Our goals now are:

  1. Import a RichText component users can directly edit
  2. Hook in this component using Gutenberg’s “attributes”
  3. Deal with common errors in developing blocks

But before we start let’s make a minor adjustment that will save time.  Before, we had to run “npm run build” every time we made changes to our javascript.  Let’s create a command that will watch our files and automatically run our build when it notices file changes.  Head over to our package.json and add the following:

...
"scripts": {
  "build": "webpack",
  "watch": "webpack --watch",
  "test": "echo \"Error: no test specified\" && exit 1"
},
...

We’re going to enter “npm run watch” and I’ll have it running for the rest of this article.

Importing the RichText Gutenberg component

Let’s change a few things in our index.js file:

const { registerBlockType } = wp.blocks;

registerBlockType('firstgutyblocks/hello-world', {
    title: "My First RichText Block!",
    icon: 'welcome-write-blog',
    category: 'common',

    edit() {
        return (
            <div>Only the editor will show this</div>
        );
    },

    save() {
        return (
            <div>Only the front end will show this</div>
        );
    }
})

So we’re changing the title, the icon, and the edit and save methods.  If you were to run this in the editor, you would again have static text.  One thing to point out- edit() will only be run in the editor.  This is the living, breathing, react block that can have user interaction built in.  When you hit “publish” or “update”, the editor will then run save() and spit out only what’s in that method.  It won’t be a living react component, but simple html.

So edit() is used to create the block and modify it.  save() spits out simple html to the post.

Let’s import the RichText component form wp.editor.

const { 
    registerBlockType,
} = wp.blocks;

const {
    RichText
} = wp.editor;

Again, this is using object destructuring.  We are taking registerBlockType and RichText from wp.blocks and wp-editor respectively and assigning them to their own variable so we don’t have to type out wp.editor.RichText every time we need it.

So what is the wp.blocks?  Remember back in our php file?


function firstgutyblocks_hello_world_editor_assets() {
    wp_enqueue_script(
        'firstgutyblocks/hello-world',
        plugins_url( 'build/index.build.js', __FILE__ ),
        array( 'wp-blocks', 'wp-element')
    );
};

In wp_enqueue_script we pass in an array.  That array declares the javascript dependencies that we need to do our block, and wp.blocks is thusly added to the page for us to use!

RichText is a pre-built component for Gutenberg blocks.  It’s generally the way that you’ll create a field that the user can change the text in.  Here is the RichText component documentation. You should check it out, because the prebuilt stuff for Gutenberg normally has a readme.md file outlining the intended uses of that thing.

So enough with the background.  Let’s call this component in our edit() method :

const { 
    registerBlockType,
} = wp.blocks;

const {
    RichText
} = wp.editor;

registerBlockType('firstgutyblocks/hello-world', {
    title: "My First RichText Block!",
    icon: 'welcome-write-blog',
    category: 'common',

    edit() {
        return (
            <RichText
                value='The stuff inside the input'
                />
        );
    },

    save() {
        return (
            <div>Only the front end will show this</div>
        );
    }
})

Make sure that you’ve saved and webpack built your file with no errors.  Now load that block up in the editor!

When you do, you’ll notice that the value attribute is what shows up inside of the text box.  You’ll also notice that if you try editing the component, you definitely can, but you’ll get errors in the console.

Lovely.

Right now, RichText is an uncontrolled input.  This means, we haven’t hooked our input up to update react’s state.  This should be familiar to you if you’ve built some react apps.  If not, take a look at what it means to be controlled.

So RichText right now is complaining that it needs to know what to do when someone changes the input.  We need to give RichText a function that instructs it on how to update the “state” whenever there’s a change.  Gutenberg block doesn’t really have state the way a normal react app would, but instead has something called block “attributes.”

Setting up and updating attributes

We are going to add an attribute called “textString” to the block:

const { 
    registerBlockType,
} = wp.blocks;

const {
    RichText
} = wp.editor;

registerBlockType('firstgutyblocks/hello-world', {
    title: "My First RichText Block!",
    icon: 'welcome-write-blog',
    category: 'common',

    attributes: {
        textString: {
            type: 'array',
            source: 'children',
            selector: 'h2',
        }
    },

    edit() {
        return (
            <RichText
                value='The stuff inside the input'
                />
        );
    },

    save() {
        return (
            <div>Only the front end will show this</div>
        );
    }
})
  • “attributes” is similar to setting initial state in a normal React component. To change something, you set attributes and the block will react to those changes.
  • Attributes are encoded into the markup when you save.   This way, when you load the page back up in the editor, the editor remembers what values each attribute had when you last saved the page.  This is the reason for things like “selectors”.  It’s giving Gutenberg information about where the actual data lies inside of the markup.  In this case, it’s saying that “all the data for this attribute will be children of the h2 tag.”
  • Why is it an array?  Well, with RichText, technically you’re not just going to have a string there.  You might add bolded text, italics, and line breaks, which might have dom elements like span tags or strong tags.  React doesn’t think of this as a string anymore, but an array of elements.  We have to let Guty know that the children of the h2 tag might be a bunch of dom elements.
  • You can assign a type to the attributes, and also some other options like default values.  See more here…
  • To change attributes you use the setAttributes method, very much like setState in react.

TL;DR?  You need to declare attributes that will store your field information from a block.  This is like state from React.

We’re going to add a function “onTextChange” that takes the new RichText changes, and sets them in the attributes.  There are a lot of changes we’re going to make in the edit() method:

    // props are passed to edit by default
    // props contains things like setAttributes and attributes
    edit(props) {

        // we are peeling off the things we need
        const { setAttributes, attributes } = props;

        // This function is called when RichText changes
        // By default the new string is passed to the function
        // not an event object like react normally would do
        function onTextChange(changes) {
            // works very much like setState
            setAttributes({
                textString: changes
            });
        }

        return (
            <RichText
                tagName="h2"
                value={attributes.textString}
                onChange={onTextChange}
                placeholder="Enter your text here!"
                />
        );
    },

I’ve added tagName here so that the text field will appear as an <h2> element.  I’ve also added a placeholder because it’s a nice thing to do 🙂

If you refresh your editor, you should be able to add “My First RichText Block!” to your post or page.  You should be able to edit it, and notice that the text should be showing like an h2 element.

Dealing with editor errors

We’re not quite done yet.

If we hit “update” or “publish” and view the page, you will see the words “Only the front end will show this”.  This is because we never updated the save() method, and this method determines what’s actually saved to the page.  Let’s change that.

// again, props are automatically passed to save and edit
save(props) {

    const { attributes } = props;

    // We want the text to be an h2 element
    // and we place the textString value just
    // like we would in a normal react app
    return (
        <h2>{attributes.textString}</h2>
    );
}

Once that’s saved, reload the editor.  You will get an error that is very common while developing Guty blocks:

If you check the console you may get a message like:

You’ll notice that the “Actual” in this message was the old markup.  We saved our block previously with this markup and that’s what’s stored in the database currently.  But our block has been recently changed, and Gutenberg is expecting the block to include h2 tags now.  If the actual markup structure and the expected don’t match, the block explodes and you will have to remove this instance of the block and add a new instance back in.

This process is probably the most irritating part of Guty blocks.  I hope that they find a good solution to this.

After you’ve removed your old block, added the block back in, and saved, you should now see your block show up on viewing the page with the correct h2 tags.

Review

We have edited our block to include a prebuilt WordPress component, and hooked that component into the attributes of the block.  We also looked at how to handle markup differences when you load a saved block.

Hopefully, you could start playing around with this now and add your own fields that users could edit.  You could try adding multiple fields with different element tags, or maybe play around with some of the options in the documentation.  There’s also a simpler text editing field called PlainText you could try.

So now what?

These fields are going to be a huge part of making gutenberg blocks, but there are some essentials that we still need to go over:

  • What ways can we add styles?
  • How do we add images?
  • How do we create those fancy tool bars above the blocks and in the advanced settings panel?
  • How do we manage multiple blocks?

More to come!

Prerequisites:

Gutenberg Blocks may seem overwhelming, but I’m hoping to clear away just enough details so that we can see what’s going on at the heart of this new editor.  I’m assuming that:

  • You’re familiar with some build processes with babel
  • You’ve done enough React to be familiar with JSX
  • You’re primarily Javascript/html/css focused.

Outline:

Here are the steps we’ll take to get a block loaded in the Gutenberg editor.  We plan on making a single block with pre-rendered text.  (No interactivity, CSS, fancy stuff yet)

  1. Set up WordPress and a folder structure
  2. Create a build process with webpack
  3. Call the block’s javascript into the editor with php
  4. Register a block with javascript

To see the finished product, you can see the repo here

WordPress Gutenberg and folder structure:

Make sure that you have installed and activated the Gutenberg plugin.

I use local by flywheel to quickly spin up instances of WordPress. Whichever way you choose to set up your WordPress, you’ll need a folder inside of your plugins folder with your plugin title.

Inside this firstgutyblocks folder we will have a php file that I’ve named “firstgutyblocks.php”.  This will contain the plugin information.  You’ll need to include these comments so WordPress knows what to do with this file:

<?php
/**
 * Plugin Name: First Guty Blocks
 * Description: Our first Gutenberg Blocks!
 * Version: 1.0.0
 * Author: Jim Schofield
 *
 * @package firstgutyblocks
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

Before moving on, go into wp-admin and activate our plugin!

Set up the Gutenberg build process

Time to set up Webpack

Webpack’s role is to transpile our JSX into friendly javascript.  If this is unfamiliar to you, take a look here and check out babel.  There are ways to write code in vanilla javascript instead, but I don’t recommend it.  JSX is the bread and butter of React applications, and if you look at the source code of Gutenberg, that’s about all you’ll see.  So it’s best to get comfy with it 🙂  It’ll save you time in the long run.

In the terminal, go to your firstgutyblocks folder and init npm.

npm init

It will ask you to fill in information like project names, etc., but you can just go with defaults (just keep pressing enter).  Then, install some dependencies:

npm install --save-dev webpack webpack-cli babel-core babel-loader babel-preset-env babel-preset-react

That’s a lot… so here’s the what and why for all of those things:

  • webpack – our asset bundler/task runner of choice today
  • webpack-cli – allows us to use some commands in the command line that are useful
  • babel-core – the thing that will transform our bleeding edge javascript into plain ol javascript
  • babel-loader –  allows us to use babel inside of webpack
  • babel-preset-env and babel-preset-react – basically the rules babel follows to transform our javascript

So now that we have all of those dependencies, let’s start making webpack work…

We’ll need to create a webpack.config.js file in the firstgutyblocks folder and configure it to build what we want, where we want, how we want:

// node module that let's us do file system stuffs...
const path = require('path');

// Webpack expects an exported object with all the configurations, so we export an object here
module.exports = {
    entry: './src/index.js', // Where to find our main js
    output: {
        // where we want our built file to go to and be named
        // I name it index.build.js so I keep index files separate
        filename: 'index.build.js',
        // we're going to put our built file in a './build/' folder
        path: path.resolve(__dirname, 'build')
    }, 
    module: {
        rules: [
            { 
                // basically tells webpack to use babel with the correct presets
                test: /\.js$/,
                loader: 'babel-loader',
                query: {
                    presets: ['babel-preset-env', 'babel-preset-react']
                }
            }
        ]
    },
    // Webpack yells at you if you don't choose a mode...
    mode: 'development'
}

Now… we’re about to actually run webpack.

First, let’s go to our package.json and add the following to our “scripts” key:

...
"scripts": {
    "build": "webpack"
    "test": "echo \"Error: no test specified\" && exit 1"
}
...

This is a convenience thing- to run a build we type “npm run build”.  If you do it right now, you will see an error because we don’t have a javascript file yet…

So let’s make a “src” folder and create an “index.js” in that.  I’m going to add this code to said index file:

const message = <h1>Test JSX!</h1>;
console.log("Hello World!");

And now if you do “npm run build” again you should have a nice, pleasant, build message!

So what’s with the javascript that I added?  Well, first, I want a console log that’s run when the script is loaded letting me know when the javascript is loaded and working correctly in the editor.  Second, I want to make sure that the transpiling is taking place when I run webpack.  So if I try to use jsx as I am on the first line, it will fail when I try to run webpack if something’s not configured or installed.

So far, we have webpack building our javascript into a file in the build folder, and our plugin folder should look like this:

Calling the javascript in php

Now, we actually want WordPress to take that javascript and load it when we open up the shiny new Gutenberg editor.  So we go back to the plugin file and add a function that’s called in a new shiny WordPress hook ‘enqueue_block_editor_assets’.  Basically, we want WordPress to know about our new Gutenberg block and where the javascript file is located.  Let’s add to our ‘firstgutyblocks.php’ file…

/* this function name I believe is arbitrary, but I 
* generally see  people follow 
* {namespace}_{blockname}_editor_assets as a 
* naming convention
*/
function firstgutyblocks_hello_world_editor_assets() {
    wp_enqueue_script(
        // the name - also generally {namespace/blockname}
        'firstgutyblocks/hello-world',
        // where the javscript is located
        plugins_url( 'build/index.build.js', __FILE__ ),
        // and dependencies WordPress needs to serve up for us
        // you must have these two for the most basic block
        array( 'wp-blocks', 'wp-element' )
    );
};

// and then, we actually have the function run when the editor loads...
add_action( 'enqueue_block_editor_assets', 'firstgutyblocks_hello_world_editor_assets' );

OKAY.  NOW we can actually log in to WordPress and open a page or a post.  If all goes well, you will now be rewarded with a “A Guty Block is Present!” console log when the editor starts up.  You’ll need to reload the editor if it’s already open.

So we haven’t actually made a block or added it to the editor yet.  Most of the battle has been fought, we’re almost there…

Register our block in javascript

We have a process to get Javascript building.  We have our one javascript file loading when the editor loads.  Now it’s actually time to create the block in javascript!

Let’s go back to the index.js file and remove the work before.  First, let’s get what we need to register a block:

const { registerBlockType} = wp.blocks;
// using destructuring to basically do:
// const registerBlockType = wp.blocks.registerBlockType

wp.blocks is provided for us on the window already.  We need to retrieve this function to register our block:

const { registerBlockType} = wp.blocks;

registerBlockType('firstgutyblocks/hello-world', { 
        // We put the Guty config stuff here
    }
);

The method registerBlockType takes two arguments.  The first is the block is the block’s unique name.  The second a config object.  This config object is where the React part takes over.  Let’s fill in that object now.

const { registerBlockType} = wp.blocks;

registerBlockType('firstgutyblocks/hello-world',{ 
        // We put the Guty config stuff here
        title: 'My First Guty Block!', //Title seen in the editor for the block
        icon: 'smiley', //using WordPress' dashboard icons
        category: 'common',

        // edit is basically the 'render' function for your block.  
        // It can be a live react app inside the editor.
        edit() {
            return <h1>Hello Editor!</h1>;
        },

        // save is the 'render' function, but it's used to generate a static html 
        // string, and it is not a live react app.
        save() {
            return <h1>Hello World!</h1>;
        }
    }
);`

When you load the editor, you should be able to select “My First Guty Block!”  You should then see a static h1 element saying “Hello Editor!”  If you publish, you would see a static h1 element on the page saying “Hello World!”

Review

We’ve set up a WordPress plugin to register a Gutenberg block and load this block in the editor.  We’ve set up a webpack build process to build all the files we need.

Although this static example is not so impressive to look at, I promise that there are some exciting things possible in this new editor.  I plan to write some more articles on how to make make interactive and truly WYSIWYG blocks, adding CSS, and doing advanced things like API calls and rendering react applications on the front end.

In the meantime, I have a repo of some general blocks I’ve been playing around with if you’re interested.

Check out part 2: Creating an editable field