Updating Plugins for Gutenberg, WordCamp Miami 2019 – Video, Notes and Code

This presentation is built around the frustrations and payoffs of updating RSVPMaker and the WordPress for Toastmasters extension to RSVPMaker, as well as starting to create new functionality around Gutenberg, such as the My Marginalia plugin I created to help a client with the “show notes” she posts with recorded videos. Download PPT.

Whether you’re creating a plugin for the repository of a hack for your own website, Gutenberg may be able to help you make it better.

(For anyone not grokking the terminology, Gutenberg refers to the new editor that comes standard with WordPress 5+ and the more JavaScript-centric programming model that comes with it).


Gutenberg Handbook


Gutenberg Hub

Create Guten Block
Tutorials: CSS Tricks and Tuts+

HTML in My JavaScript

Here’s something I found confusing at first. Does this look like legal JavaScript to you?

JSX example from Create Guten Block

In fact, this is NOT legal JavaScript in the sense of being code that your browser would understand. This is the JSX template language, which originated as part of the React JavaScript framework created by Facebook. The idea is to allow you to specify a user interface in an HTML-like syntax that can also include functional components such as <RichText> to specify that an editable rich text field should be displayed at that spot within your application. For example, this is equivalent to instantiating a JavaScript class that will render the RichText component:

 setAttributes({ content })}

As part of the development process, we run this source code through a “compilation” step. You don’t compile your JavaScript down to a binary executable, but you feed it through a series of preprocessing steps that translate it into code that is intended to be understandable by all modern browsers and also optimizes / minifies it to download and run faster.

In the process, code like <div>my content here</div> turns into something like:

wp.element.createElement("div","my content here")

Using the Create Guten Block utility, you can create the skeleton of an application and then begin customizing it to meet your needs. You define your editor user interface within the block of code for the “edit” function and the code to be saved to the post in the “save” function.

You can use JSX in both the edit and save functions. Specifically, you use it within the return clause, after you have applied whatever processing might be required to decide what should be output in the editor.

The saved content that will be recorded to the WordPress database looks like this:

Source code for an image, as saved by the Gutenberg editor.

In most cases, what you are saving is legal HTML code wrapped in comments that define instructions to the editor for how this content should be displayed the next time it is edited. Within the opening HTML content, you will often see variables expressed in JSON format within the {curly brackets}.

Gutenberg blocks can also be used like shortcodes, in which case those JSON-encoded attributes will be passed to a PHP function that uses server-side logic to determine what should be output to the user. On the other hand, one reason for adopting Gutenberg is that it allows less server side processing, particularly when your goal is simply to format content in a custom way. You can do that with your save function and regular HTML/CSS.

Demo Code

Here’s simple example showing Gutenberg edit and save functions, plus an “inspector” component for the sidebar.

All this does is create a block in the editor and a save mechanism on the front end, with a custom headline and a line of text you can change using the sidebar component.


import './style.scss';
import './editor.scss';
const { __ } = wp.i18n; 
const { registerBlockType } = wp.blocks; 
const { Component } = wp.element;
const { InspectorControls } = wp.editor;
const { PanelBody, TextControl } = wp.components;

class DemoInspector extends Component {
render() {
	const { attributes, setAttributes, className } = this.props;
	return (
		 setAttributes( { message } ) }
}//end render


registerBlockType( 'wcmia/demo', {
	title: __( 'WordCamp Demo' ), 
	icon: 'shield', 
	category: 'common', 
	keywords: [__( 'Demo' )],
	attributes: {
	message: {
		type: 'string',
		default: '',
	edit: function( props ) { // UI for editor
	const { attributes, setAttributes, className } = props;
		return (

My custom block (editor)


); }, save: function( props ) { // format for storage / retrieval const { attributes, setAttributes, className } = props; return (

My custom block (editor)


); }, } );

We can give it formatting that will be applied both in the editor and on the front end with a style.scss file like this:

.wp-block-wcmia-demo  {
border: medium solid red;
padding: 5px;

Practical examples:

  • A custom format you define for product descriptions, executive bios, recipes or other content employed frequently in the context of your specific uses for WordPress. For example, I created a Floating Callout plugin for a callout / sidebar format used as an accent within a post or page. I had essentially been doing the same thing for years with snippets of custom HTML / CSS — but the plugin makes it easier.
  • A block of content that will exhibit custom behavior when viewed on your site, in combination with either front end JavaScript or server-side processing in PHP (more on that below).

Fussy Code

One important thing to understand is that the “save” function doesn’t merely save content to the HTML content of the post, as it will be stored in the WordPress database. When you retrieve the content, Gutenberg expects it to be organized the same way. If not, you will see an error.

Here’s an example that popped up while I was writing this post.

The unexpected or invalid code warning.

This apparently happened because I was having trouble with the display of my JavaScript code examples, which I recorded here using the Gutenberg component for displaying code. Ironically, Gutenberg seemed to be confused by the JSX examples. All the < symbols in HTML or component tags were being displayed as entity codes (<).

To get the code to display properly, I had to do a search-and-replace in Windows Notepad. That worked in terms of front-end display, except that Gutenberg would no longer allow me to edit those blocks as blocks in the editor.

Wrapping a Block Around Other Blocks

When you define Edit and Save functions using the InnerBlocks component, you can define a block that wraps around other content blocks (paragraphs, images, etc.). The code below is from My Marginalia, which applies special fomatting to the wrapped content. The Floating Callout plugin I mentioned does the same thing.

There’s also a “Limited Time” block in RSVPMaker that uses an InnerBlocks component in combination with server-side rendering to suppress the display of content that is past its expiration date.

    edit: function( props ) {	
	const { attributes, className, setAttributes, isSelected } = props;
	const marginstyle = {width: attributes.width + 'em'};
	const innerstyle = {marginLeft: (attributes.width + 2) + 'em'};

	return (
Nested inside another Marginalia block
setAttributes({ content })} />
); }, save: function( { attributes, className } ) { const marginstyle = {}; const innerstyle = {}; if(attributes.position == 'left') { marginstyle['float'] = 'left;' marginstyle['width'] = attributes.width + 'em'; innerstyle['marginLeft'] = (attributes.width + 2) + 'em'; } else { marginstyle['float'] = 'right;' marginstyle['width'] = attributes.width + 'em'; innerstyle['marginRight'] = (attributes.width + 2) + 'em'; } return
; } });

Displaying a Notification

Displaying a notification in the WordPress admin following an event like a post being saved used to be fairly easy in PHP.

add_action('admin_notices', 'rsvpmaker_template_notice');

function rsvpmaker_template_notice () {
	global $post;
	if(isset($_POST['rsvpmaker_template_data'])) //detect some trigger
	echo '

'.__('After updating this template, click','rsvpmaker').' '.__('create / update events','rsvpmaker').'

'; }

It took me months of research to figure out how to do essentially the same thing in Gutenberg because those PHP-generated notifications aren’t shown on the editor screen when Gutenberg is active. The following code is based on a tip from a collaborator on Github and my own study of internal WordPress code to figure out how it detects such events (the example I found was related to saving the content of metaboxes on post save).

Blocks versus Shortcodes

Here are some shortcode examples, one where the output is based on the attributes added to the shortcode and another that wraps around a piece of content (the [caption] shortcode used in the Classic Editor to format image captions and allow them to be treated as a unit with the accompanying image).

The PHP code to process your shortcode can then be something like this:


function my_shortcode_function($atts = array()) {
	$title = $atts['title'];
	$size = $atts['size'];
	$content = sprintf('


',$size,$content); return $content; } function my_shortcode_wrapper($atts = array(), $content = '') { //apply some extra formatting or logic to $content return $content; }

You can register a Gutenberg block to get run through a server-side routine in much the same way:

function wpt_server_block_render(){
	register_block_type('wp4toastmasters/role', ['render_callback' => 'toastmaster_short']);


function toastmasters_short($atts) {
	global $post;
	$role = $atts['role'];
	$count = (int) $atts['count'];
	$content = '';
	for($i =1; $i <= $count; $i++) {
		$slug = $role+$i;
		$assigned = get_post_meta($post->ID,$slug,true);
			$content .= get_agenda_content($slug,$assigned);
			$content .= get_signup_button($slug,$assigned);
	return $content;

Escape from Gutenberg

Although I like many aspects of Gutenberg, I wasn’t prepared to refactor every bit of PHP into JavaScript. In particularly, I had a lot of functionality built into metaboxes displayed beneath the classic editor, and metaboxes are discouraged in the Gutenberg framework. Mine included some JQuery interactivity that seemed to clash with the Gutenberg code.

The coping mechanism I devised for RSVPMaker was to make a few basic options like setting the date and turning RSVP registrations on or off available within the sidebar to the editor. The more elaborate functionality like setting event pricing and customizing the registration form moved to a separate screen.

Here’s how you can do that, in pseudocode simplified from the actual code used in RSVPMaker.

add_action( 'admin_bar_menu', 'my_rsvpmaker', 99 );

function my_toolbar($wp_admin_bar) {
	global $post;
	if(isset($post->post_type) && ($post->post_type == 'rsvpmaker') )
	//a new menu
	$args = array(
		'id'    => 'rsvpmaker_options',
		'title' => 'RSVP / Event Options',
		'href'  => admin_url('edit.php?post_type=rsvpmaker&page=rsvpmaker_details&post_id='.$post->ID),
		'meta'  => array( 'class' => 'edit-rsvpmaker-options')
	$wp_admin_bar->add_node( $args );
	//a subnew menu, parent set to id of item above
	$args = array(
		'parent'    => 'rsvpmaker_options',
		'id' => 'my_form',
		'title' => 'My Form Page',
		'href'  => admin_url('edit.php?post_type=rsvpmaker&page=my_form_page&post_id='.$post->ID),
		'meta'  => array( 'class' => 'my_form')
	$wp_admin_bar->add_node( $args );

add_action('admin_menu', 'rsvpmaker_admin_menu');

function rsvpmaker_admin_menu() {
//submenu menu under post type
add_submenu_page('edit.php?post_type=rsvpmaker', __("Event Options",'rsvpmaker'), __("Event Options",'rsvpmaker'), 'edit_rsvpmakers', "my_form_page", "my_form_page" );
//standalone menu
add_menu_page(__("Event Options",'rsvpmaker'), __("Event Options",'rsvpmaker'), 'edit_rsvpmakers', "my_form_page", "my_form_page" );

function my_form_page() {
	$post_id = (isset($_REQUEST['post_id'])) ? (int) $_REQUEST['post_id'] : false;
		echo '

Updated my variable

'; } printf('
',admin_url('edit.php?post_type=rsvpmaker&page=rsvpmaker_details&post_id='.$post_id)); printf('',get_post_meta($post_id,'my_variable',true)); submit_button(); echo '
'; } else { $o = ''; $future = get_future_events(); foreach($future as $event) { $o .= sprintf('',$event->ID,$event->post_title,$event->date); } printf('
',admin_url('edit.php'),$o); } }

This shows hooking into the action for display of the admin bar, getting access to the $wp_admin_bar object, and calling add_node methods that add our custom menu and submenu.

We register a custom admin page and define a function for displaying it. If the user clicks through from the admin bar (while viewing a post on the website or in the editor), that link will have the post id added to the URL query.

If the post ID is set, we display a form with options specific to that post (an RSVPMaker event in this case). Otherwise, we retrieve a list of posts and give the user a form they can fill out to display the options for the post they are interested in.

Check back on Sunday or Monday for updates to this post.