Building a Gutenberg Block

After completing Zac Gordon’s wonderful Gutenberg Development Course, I wanted to try building my own block. It was more difficult than I expected, but a great learning experience. For comparison, see my article on building custom blocks with Advanced Custom Fields.

I added a “List Subpages” block to my BE Subpages Widget plugin (code here). This lets you select a page and dynamically lists all its subpages.

The biggest hurdle is my lack of knowledge of modern JavaScript development. I’m a theme and plugin developer, so I’m comfortable with PHP and frontend markup. I use a bit of jQuery in theme development, but nothing special.

There was a lot of copy/pasting pieces from existing blocks while I tried to figure out the proper syntax to implement what I want. I’m sure this code could be written better if I knew what I was doing.

Getting Started

I followed the example code from the Gutenberg Development Course to setup the plugin initially. You could also use the create-guten-block tool or the wp cli command wp scaffold block.

In terminal, run npm install in the plugin’s directory. Then run npm run dev, which will monitor the files for changes and recompile the resulting CSS/JS into the assets directory.

In the main plugin file I’m enqueuing the editor-specific Javascript using the enqueue_block_editor_assets hook. If my block required its own styling or JS, I’d also enqueue block-specific CSS and JS using enqueue_block_assets hook, which applies to both the editor and frontend, ensuring the block looks the same in both places.

Starting the block

In the block’s index.js file, use registerBlockType() to create a block (example). You specify a unique name, some basic parameters, and two functions: edit and save.

The edit function is what’s rendered in the Gutenberg editor. When the block is in focus, I’m displaying a dropdown menu, and when the block is out of focus I’m displaying the actual subpages list.

The save function is saved into the post content and is shown on the frontend. Since my block is outputting dynamic content, my save function is empty and I created a PHP callback function to handle the output, similar to a shortcode.

This is one complaint I have about Gutenberg.  All dynamic elements need to be implemented twice: once in JS for the edit() function so it’s visible in editor, and again in PHP for frontend render. You’ll need to be careful to keep your WP_Query returning the same results as your JavaScript REST API Query.

Gutenberg is readable and reusable

Gutenberg’s code is very clean and logical. Everything is broken down into small, single-purpose files. Reusable components are accessible from global variables.

In my plugin I wanted a dropdown menu with a hierarchical page listing.  I found an existing area of Gutenberg that already did this – the “page parent” dropdown in the Page Attributes section.

In the parent.js file in /packages/editor/src/components/page-attributes, they’re using <TreeSelect> to create this hierarchical select menu (see here). At the top of the file you’ll see they are importing that component from another file:

import { TreeSelect } from '@wordpress/components';

You can’t copy this line directly, but you can use something similar:

const { TreeSelect } = wp.components;

I used this approach to find all the pieces I needed and import them all. I also kept my code simple and readable by breaking my functionality into separate files.

Querying Posts

You can use withAPIData() to query for data using the REST API. The examples I found in Gutenberg used a constant like applyWithAPIData to build the query, then applies it to your component on export. You can then access the JSON result of that query by using whatever variable you returned in the constant (in this case, pages).

See the REST API Handbook for more information on querying.

Lots to learn

It truly is time to “Learn Javascript Deeply” to keep up with future WordPress development. To that end, I’m:

  • Reading Eloquent Javascript
  • Taking Wes Bos’ courses Javascript30 (free), ES6 for Everyone, and React for Beginners.
  • Keeping up with Gutenberg development. I’m reading all the issues and pull requests to follow what’s changing and improve my understanding of the underlying code.
  • Contribute where I can. Here’s my first bug report and patch.
  • While building client sites, find elements to build as Gutenberg blocks in my free time. Implementing these real-world examples will help prepare me for when I’m actually building client sites with Gutenberg.

We’re still many months away from Gutenberg merging into core. But if you’re like me, it’s going to take that long to become technically competent in modern JavaScript and comfortable building websites using Gutenberg.

Now is the perfect time to start learning.

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson


  1. Rob Mehew says

    Awesome post, I feel I am in a very similar position to yourself. I have built a couple of plugins, many WordPress sites, but my knowledge of modern Javascript is limited and I rely heavily on jQuery.

    I have just started a recent blog post series about learning React, but I think I’ll checkout some of your links and look into Modern Javascript as well, thanks for the resources!

  2. 3200 Creative says

    Hi Bill,

    Good choice on the Gutenberg course! its a nice overview w/ some good example blocks to reference.

    I saw your educational task list at the end of this article. Since I’m learning from the 4 resources you mentioned I thought I’d contribute one:

    I followed the React track at Treehouse early last year. For the cost it was a good 5 hour introduction with plenty of JSX practice.

  3. Valentin says

    withAPIData HOC not displaying data in editor after post edit page reload if window width > 782px. How can i solve this issue?

  4. Spacema says

    After using several “builders” and theme bundles, such as WPBakeryBuilder, Elementor, Beaver Builder, SiteOrigin,PageBuilder and others, I still feel Divi is the easiest and best as far as themes and builders are concerned. Some of these builders require going back and forth from frontend to backend, and some just don’t have all the features.

    Personally, I think there will be many updates coming for the new WordPress format, and those companies who have created great themes and builders, like Divi, will make WordPress think twice about changing the system. Maybe WordPress should consider keeping the current format of WordPress and introduce the new platform separately? I just don’t see WordPress catching up to Divi or some of the other builders to make it “standard”. Especially if WordPress still has outdated plugins and themes in their repository. I am not thrilled about the change in WordPress’ format.