Working with the Gutenberg Block API

Reading Time: 6 minutes

Now that we’ve covered best practices, enqueueing scripts, and modern JavaScript in Gutenberg block development we’re ready to take a look at the Block API.

Note: Code examples in this post will be using modern JavaScript. For ES5 examples check out the Gutenberg Handbook.

What is the Block API

Blocks are the elements developers can use to extend and create functionality in the WordPress editor within plugins and themes.

The Block API is the functions WordPress exposes for extending the Gutenberg editor with that custom functionality by creating new blocks.

You’ll typically make use of the Block API in the index.js file which should be the main JavaScript for creating your block.

Defining Functions from Dependencies

At the top of your index.js file you’ll likely want to define some of the functions you’ll be using from the JavaScript libraries made available in Gutenberg.

//  Import CSS.
import './style.scss';
import './editor.scss';

// let's us call registerBlockType() directly from the wp.blocks library
const { registerBlockType } = wp.blocks;

// let's us use the RichText component from the wp.editor library
const { RichText } = wp.editor;

// let's us use components such as a Spinner (loading wheel) from the wp.components library
const { Spinner } = wp.components;

// let's us use the withSelect() function from the wp.data library to access the Rest API
const { withSelect } = wp.data;

//let's us use the __() function from the wp.i18n library to translate strings 
const { __ } = wp.i18n;

Doing this allows you to call the functions or components independently. For example, the above let’s us use registerBlockType rather than wp.blocks.registerBlockType.

You may have noticed I didn’t explain the two .scss files being imported at the top of the code. This is a pattern from React that is used in the core Gutenberg development. It allows for scoping styles to particular blocks.

When using webpack to process and spit out our CSS I don’t believe this is necessary (or does anything). I’m still trying to develop a solid answer on this particular item. I’ll update as I learn more and if you can shed light on it let me know in the comments!

Update: The use of these will depend on the way you’re enqueueing your assets and using webpack. If you enqueue each block’s assets individually through PHP you probably don’t need these imports. But if you use Create Guten Block it runs a build process that compiles your SCSS files into a build CSS file that is enqueued on it’s own. Without the import the SCSS styles wouldn’t be compiled into the build file.

Creating a Block

In order to create a block within our index.js file we’re going to want to use the registerBlockType function from the wp.blocks library.

registerBlockType takes two arguments block-name and a block configuration object.

The block-name is the namespace/block-name where the namespace is your plugin name and the block-name is, well, your block’s name.

The block configuration object is an object containing the properties and functionality of your block. The magic really happens within the edit and save functions within the block configuration object.

But First, A Look at the Properties

The attributes passed to the block configuration object will define the block and the data it will be using.

Defining your Block

A lot of the properties passed to the block configuration object help the end user understand and find your block. Some examples:

title – The title of your block.

description – A short description of the block’s functionality.

icon – A dashicon or a custom SVG used to identify the block.

category – A category to help users browse and discover blocks. Core categories include common, formatting, layout, widgets, and embed.

keywords – Sometimes your block needs to use an alias to be discovered. Think an image block using the keyword “photo”. Three additional keywords can be set per block.

registerBlockType('namespace/block-name', {
	title: __('My Block'),
	description: __('A Custom Block'),
	icon: 'shield',
	category: 'common',
	keywords: [
		__('custom-block'),
		__('Custom Block'),
		__('Another Keyword')
	],
});

Diving into Attributes

Attributes are the secret sauce of block properties. Attributes allow the Gutenberg editor to extract the value from a saved post and make it usable in an editable block.

What does that mean? It’s basically how you define the data your block will be able to edit within the JavaScript representation of the block.

Let’s say we’ve got an image and we want to get the src for our url attribute. Our image markup may look like:

<img src=“https://lorempixel.com/1200/800/“ />

First we’ll want to define a url attribute within our attributes property.

attributes: {
    url: {
    
    }
}

We want to define what type of data we’ll be working with using type . In the case of our image src we’re looking for a string.

attributes: {
    url: {
        type: 'string',
    }
}

Next we need to set the source for our attribute. Since src is a HTML attribute of the <img> element. We’ll set our attribute source to 'attribute'.

attributes: {
    url: {
        type: 'string',
        source: 'attribute',
    }
}

The next thing we want to do is identify what element we’re pulling the HTML attribute from. We can do that by setting the selector as our <img> element, a class, or id.

attributes: {
    url: {
        type: 'string',
        source: 'attribute',
        selector: 'img',
    }
}

Cool, cool, cool. Now we have to actually identify the HTML attribute we’re pulling into our url attribute. We do that by setting the attribute as src.

attributes: {
    url: {
        type: 'string',
        source: 'attribute',
        selector: 'img',
        attribute: 'src',
    }
}

https://giphy.com/gifs/community-abed-cool-2HONNTJbRhzKE

So that’s one of the more confusing examples because everything uses the term attribute. Just keep in mind url is one of your block attributes, source says we’re looking for an HTML attribute, and attribute defines the HTML attribute we want.

More Attribute Sources

Attribute is just one of the common sources used for block attributes. Let’s take a look at a few others before we move on.

Text vs HTML

The text attribute let’s you get the inner text from an element. Let’s say we want the text within this <p> element.

<p>Maecenas faucibus <strong>mollis</strong> interdum.</p>

We can get the text with:

attributes: {
    content: {
        type: 'string',
        source: 'text',
        selector: 'p',
    }
}

That will give us:

{ "content": "Maecenas faucibus mollis interdum." }

Notice the <strong> tag is missing. If we want to return the strong tag as well we need to use the HTML source.

attributes: {
    content: {
        type: 'string',
        source: 'html',
        selector: 'p',
    }
}

This will return:

{ "content": "Maecenas faucibus <strong>mollis</strong> interdum." }

Children

One fo the more useful sources is the children source. Which returns an array of the child nodes of a matched element.

You’ll notice above the HTML source returned the strong tag, but we’d not able to independently access it.

We can use the children source on the same <p> element as above.

attributes: {
    content: {
        type: 'array',
        source: 'children',
        selector: 'p',
    }
}

And that will return the following:

{
    "content": [
        "Maecenas faucibus ",
        { "type": "strong", "children": "mollis" },
        " interdum.",
    ]
}

This is super useful when used in combination with the RichText element.

registerBlockType('namespace/block-name', {
    title: __('My Block'),
    description: __('A Custom Block'),
    icon: 'shield',
    category: 'common',
    keywords: [
        __('custom-block'),
        __('Custom Block'),
        __('Another Keyword')
    ],
    attributes: {
        url: {
            source: 'attribute',
            selector: 'img',
            attribute: 'src'
        }
    },
});

Editing and Saving Blocks

The last parts of the block configuration object we’ll take a look at in this post are the edit and save functions.

The edit function

The edit function is used to create a block in the context of the editor. It renders the markup used for the block within the editor as well as takes several properties for use in editing.

attributes

This property gives access to all of the previously defined attributes within the block configuration object.

className

This property returns the class name to be used on the wrapper element. Within the save function the class name is automatically added to the wrapper element. But in the context of the editor the outermost wrapper may not be the main element used. So by surfacing the className you can specify where it goes.

isSelected

The isSelected property let’s you determine if the block is currently selected. In the context of the editor this allows you to display a message or a tooltip when the block is selected in the editor.

setAttributes

This allows the block to update individual attributes as defined in the block configuration object.

A Static Example

To it’s most basic a static block that simply outputs a static message would look like this:

edit: function( { attributes, setAttributes, className, isSelected } ) {
    return (
        <div className={ className }>
            <p>Steve Guttenblock</p>
        </div>
    );
},

In our editor this will give us a <div> with our main wrapper class name with a <p> static paragraph inside.

The save function

The save function defines the final markup output by the block that is then saved into the content and output on the frontend of the site.

attributes

The save function only receives attributes in it’s object argument. This allows for attributes defined in the block configuration object to be combined into the final markup of the block.

save: function( { attributes } ) {
    return (
        <div>
            <p>Steve Guttenblock</p>
        </div>
    );
}

Note: The final markup doesn’t pull in the className anywhere as it is automatically applied to the outermost wrapper.

Tie it altogether and we’ve got the following registerBlockType call.

registerBlockType('namespace/block-name', {
    title: __('My Block'),
    description: __('A Custom Block'),
    icon: 'shield',
    category: 'common',
    keywords: [
        __('custom-block'),
        __('Custom Block'),
        __('Another Keyword')
    ],
    attributes: {
        url: {
            source: 'attribute',
            selector: 'img',
            attribute: 'src'
        }
    },
    edit: function( { attributes, setAttributes, className, isSelected } ) {
        return (
            <div className={ className }>
                <p>Steve Guttenblock</p>
            </div>
        );
    },
    save: function( { attributes } ) {
        return (
            <div>
                <p>Steve Guttenblock</p>
            </div>
        );
    }
});

Note: While I have the defined url attribute in this sample it isn’t used for anything other than to illustrate where attributes are defined.

Where to Now

Now with a solid understanding of the Block API we can delve deeper into Gutenberg block development. Notably taking a look at the RichText component for making editable blocks. And dynamic blocks making use of the REST API and PHP render_callback.

Pin It on Pinterest