How I Learned to Create a Gutenberg Sidebar for Editing Post Metadata (Tips for WordPress Plugin Developers)

More than a year after releasing the first version of RSVPMaker with support for Gutenberg (the WordPress “block editor” introduced with 5.0), I now have an editor sidebar implementation I’m pretty happy with.

In the process, I learned more than I ever wanted to know about the WordPress Data API for JavaScript — and frankly more than I needed to know for the relatively simple thing I wanted to accomplish. I just wanted to update my old PHP-based UI for getting and setting post metadata to work in Gutenberg. The problem is not just insufficient documentation, but overwhelming documentation that can lead you in a wrong direction.

What you see below is a composite image of 2 screenshots.

What you see on the left are the most basic RSVPMaker settings (when does the event start and end? and are we collecting RSVPs?) as they’ve been added to the Document tab of the standard Gutenberg sidebar. I do that to make these basic elements of editing an event date as accessible as possible.

The insert on the right shows an additional sidebar, specific to RSVPMaker, that I can get to by clicking the calendar icon at the top of the screen. This additional sidebar provides access to a longer list of RSVPMaker settings: not just date and time, but also the email address to send registration notifications to, whether there is a maximum number of registrations to be accepted, and so on.

There are still a few more complex settings, such as those for event pricing online payments, where I direct users to a separate RSVP / Event Options screen. But I want them to be able to accomplish most tasks without delivering the editor.

The designers and developers behind the Gutenberg UI recommend providing a “distraction free” editing environment that minimizes the use of the old “metaboxes” at the bottom of the content editing window, which used to be a standard for WordPress plugin design. I also found that the JavaScript functions in my old metabox code seemed to clash with Gutenberg, so I got rid of metaboxes some time ago. But making those same capabilities available in a Gutenberg sidebar, rather than a metabox has proven challenging.

Gutenberg represents a steep learning curve for those developers who learned plugin programming in PHP and are now asked to master at least the basics of the React JavaScript framework and the Gutenberg component library. I hope that we will eventually be provided with some easier ways of handling common needs like setting the metadata of a post from within the Gutenberg UI.

Meanwhile, here are my tips on how to cope with the current state of things.

For Developers Learning Gutenberg

As a way of documenting what I had learned (and making sure I really understood it), I created a demo plugin you can find on Github at https://github.com/davidfcarr/meta-sidebar-demo

You can also browse the somewhat more elaborate Gutenberg code used in RSVPMaker at https://github.com/davidfcarr/rsvpmaker/tree/master/gutenberg/src

I use Create Guten Block by Ahmad Awais to bootstrap my Gutenberg projects. I recommend it as a starting point, and the Github repo provides good instructions on how to use it to generate working code with NodeJS and the NPM package manager.

One of my big frustrations has been that most of the Gutenberg tutorials available focus on the creation of blocks, mentioning sidebar components only in the context of providing a sidebar associated with your block which can display additional settings. Much of this advice does not apply to adding UI components for settings that apply to the entire document, rather than a block.

I studied several other tutorials, that still left me with gaps in my understanding of how to allow users to manipulate post metadata. Often, they assumed more knowledge of JavaScript frameworks than I possessed, or pointed to documentation I found cryptic.

The tutorial that got me closest was Bye-bye Meta Boxes, Hello Gutenberg Sidebars by Misha Rudrastyh, although it still left me with a few mysteries to solve on my own.

Here’s what I’ve figured out.

Step 1: Make Meta Data Available in REST API

Here is an excerpt from the init.php file used in the demo plugin. Create Guten Block Provides a default init.php setup, and this is the code I added specific to making the sidebar work.

This demo meta data does not serve any function. In RSVPMaker, I use metadata fields to track settings like whether RSVPs (event registrations) should be collected and what email to send notifications to.

Key points:

  • Your JavaScript components will not be able to update metadata in WordPress unless the data fields are specifically made available in this way.
  • If your metadata fields begin with an underscore (Example: ‘_rsvp_on’), WordPress treats them as private data and will not allow you to edit them via the API. You must use the auth_callback field to confirm that the user is authorized to edit that field.
  • Update: The auth_callback solution I originally used (based on someone else’s message board answer) was auth_callback=’__return true’ — which works but isn’t a real test. Adding the anonymous function call to current_user_can(‘edit_posts’) tells you the user has at least author level privileges.
  • The solution I tried but couldn’t get to work, to test editing rights for the specific post, is:

Maybe for some reason the $post global isn’t available in this context?

Step 2: Define Components to Select Data, Dispatch Updates

Gutenberg provides a (relatively) well-documented mechanism for accessing the data associated with a block, both reading it and updating it. In that case, the “props” or properties are written to the HTML text stored in a Gutenberg post. Attempting to follow those instructions outside the block context will lead you to heartbreak.

When working with UI components that will exist out of a block context, you can expect to get treated to long explanations about the inner workings of ReactJS as it is implemented in Gutenberg and higher order components.

Short version: the withSelect and withDispatch higher order components allow you to create an alternative context around your UI components that defines how the ‘props’ will work — what data and functions they will make available. You use wp.compose to add withSelect and withDispatch to your UI component and return an enhanced component with additional superpowers — the ability to get and set metadata values.

This file shows this wrappering applied to both standard Gutenberg UI components and a couple of custom ones from RSVPMaker.

Key points:

  • You must specify the components you want to use, including withSelect and withDispatch, at the top of the file.
  • To make the components available to import into our application (as defined in another file), we must export them at the end.
  • If you stick to the model of one component per file, you can export with the format “export default ComponentName”
  • Because I’ve chosen to define multiple components in one file, I must export them individually, using this format: export {MetaEndDateControl, MetaDateControl, MetaTextControl, MetaSelectControl, MetaRadioControl};
  • This is only one possible solution, but it’s the simplest I’ve found. Other tutorials advise creating the withState higher order component and defining your own state management rules and functions. IMHO, that’s overkill if all you want to do is update metadata fields.

The basic pattern for setting up a withSelect wrapper (taken from Misha Rudrastyh’s tutorial) looks like this:

The withDispatch function returns a setMetaValue function I can use with the onChange attribute of my UI component by calling props.metaValue(newvalue)

After some experimentation, I found it was possible to filter or modify the data before passing it to or from a UI component. For example, for RSVPMaker, I wanted to split the end time for an event into two dropdown lists, for the hours and minutes, then combine them again when updating. The metadata representation is ’12:00′ for 12 pm, so we do this with a split function and return the resulting array. First, we test to make sure I’ve retrieved a valid value (a string that includes the ‘:’ character).

That looks like this:

The onChange property for the UI component wrapped by withSelect and withDispatch calls a function that looks up the values for both select fields and combines them into a new time field string before calling the withDispatch setMetaValue function.

Following this same pattern should allow you to define Select/Dispatch wrappers around other standard Gutenberg controls, such as the TextareaControl, the ToggleControl, the RangeControl, or the ColorPicker.

Step 3: Create (or Modify) a Sidebar

The example below covers how the components are used in a sidebar. This covers 2 cases: first, adding a couple of extra fields to the Document tab of the standard Gutenberg sidebar and, second, creating an additional sidebar to be displayed next to the standard Gutenberg sidebar and on the menu.

As part of the section up top where I’m defining which components will be used, this line imports the Select/Dispatch components defined in the previous step that I need for my application.

In my RSVPMaker, I pull in the date components as well, but the idea is you only want to import the components you need for your project.

For the separate sidebar, you specify an icon. You can provide your own custom icons in SVG, or you can use WordPress dashicons.

You can then include the components in your sidebar using the HTML-like JSX syntax, where the component setup parameters are specified as if they were HTML attributes. Because of the way I’ve defined the components, instead of specifying a field value, I set the metaKey attribute to the metadata key used in my application (and specified on the PHP side using register_meta).

<MetaTextControl label=”Demo Text Control ” metaKey=”_demo_text_field”/>

The wrapper component defined above uses withSelect to get the current metadata value and plug it in as the current value for the underlying TextControl UI component.

You also provide a label and, in the case of a radio or select field, a list of available options.

One Other Thing No One Tells You

One detail I haven’t seen explained adequately in other tutorials. If you use the Create Guten Block starter plugin tool, you will wind up with a project directory structure that looks like this:

project-directory/
project-directory/dist/
project-directory/node-modules/
project-directory/src/

When you publish your plugin, or upload it to a web server, it is not necessary to include the node-modules subdirectory, which is part of the “scaffolding” for compiling your project.

Since the most elaborate JavaScript I had written previously involved JQuery, this notion of compiling JavaScript was foreign to me when I first started working with Gutenberg. Although you’re not really to binary, like you would with C code, the output is a minified / optimized / compact rendition of your code with all the required binaries bundled in. This means you don’t have to enqueue the supporting libraries the way you do with JQuery.

In any case, my point is you really only need to publish the JavaScript that gets generated into the dist folder — although, in the spirit of open source, I also publish the uncompiled code from the src directory. By default, Create Guten Block also puts the init.php file, which includes the code necessary to enqueue your scripts and CSS. However, if you’re adding Gutenberg code to another plugin, you could move that functionality into another file.

For RSVPMaker, I copy all my Gutenberg project files with the exception of the node-modules stuff, into a gutenberg subdirectory of the rsvpmaker plugin folder. In my main, rsvpmaker.php file, I include the init.php file. To make sure it’s only loaded if I see that Gutenberg is active on the website, I test for the existence of the register_block_type PHP function.

Was This Helpful?

If you found this helpful, or have questions for me, drop me a note. I’m not claiming to be a Gutenberg or React expert; just sharing a few things I learned the hard way.

Related posts:

Updating Plugins for Gutenberg, WordCamp Miami 2019 – Video, Notes and Code – walk through of an earlier version of my code. Covers my “Escape from Gutenberg” technique (hack) for moving some metadata-setting functions to a separate screen if you don’t want them as metaboxes and haven’t yet figured out how to add those features to a sidebar or otherwise integrate them with the editor.

My Gutenberg Breakthrough: Adding a Custom Notification – another feature for which documentation is scarce, how to make notification messages occur within the Gutenberg editor (notifications created with older PHP methods are NOT displayed in the Gutenberg editor)

Leave a Reply