Bye-bye Meta Boxes, Hello Gutenberg Sidebars

Wait… what? ? Are meta boxes deprecated now? Technically not, but it is not a clickbait title – for those post types that have Gutenberg editor we should use something else instead.

/2 comments

By the way, the tutorial about WordPress Meta Boxes is my first tutorial on this blog, but now time of Meta Boxes is over…

Below is the correct tutorial about creating Gutenberg sidebar panel settings. I say correct, because when I learned this I found some tutorials which suggest you to work directly with WordPress REST API and use wp.apiRequest etc. Please skip such tutorials, because those implementations will cause bugs.

Let’s begin! πŸš€

I personally don’t work with Yoast plugin, not because I do not like it, I just think that it is too heavy, so I store my posts SEO settings in post meta. And here is what we will create in this tutorial:

Creating Gutenberg Sidebars for custom post settings
Much better than meta boxes, huh? πŸ™ƒ

The cool thing here is that you can create as much these sidebar “tabs” as you want and each of them can contain a lot of fields. You can deactivate a certain sidebar tab if you click on the star icon.

One more thing – if you do not want deal with all of the code below, I recommend you an alternate way to create Gutenberg sidebars – just with small PHP code snippets for the functions.php file.

Step 1. Register Meta Keys in REST API

I am going to use these 3 meta keys – misha_plugin_seo_title, misha_plugin_seo_description and misha_plugin_seo_robots.

Nothing super especial right now, you just have to register all of the keys in REST API. Code for your functions.php / custom plugin:

// you have to use it within the "init" hook
add_action( 'init', function(){
 
	register_meta( 'post', 'misha_plugin_seo_title', array(
 		'type'		=> 'string',
 		'single'	=> true,
 		'show_in_rest'	=> true,
 	) );
 
	register_meta( 'post', 'misha_plugin_seo_description', array(
 		'type'		=> 'string',
 		'single'	=> true,
 		'show_in_rest'	=> true,
 	) );
 
	register_meta( 'post', 'misha_plugin_seo_robots', array(
 		'type'		=> 'boolean', // because it is a checkbox
 		'single'	=> true,
 		'show_in_rest'	=> true,
 	) );
 
});

Of course, you can check the documentation of the register_meta() function, but I will describe the parameters we used here shortly.

Why I used boolean type for robots meta key? Because I do not use anything except noindex/follow, so, the checkbox above will add only this value once checked.

Step 2. Enqueue Scripts

I want to highlight this step too, because I think you have to pay attention to dependencies:

add_action( 'enqueue_block_editor_assets', function(){
 
	wp_enqueue_script(
		'misha-sidebar',
		get_stylesheet_directory_uri() . '/sidebar.js',
		array( 'wp-i18n', 'wp-blocks', 'wp-edit-post', 'wp-element', 'wp-editor', 'wp-components', 'wp-data', 'wp-plugins', 'wp-edit-post' ),
		filemtime( dirname( __FILE__ ) . '/sidebar.js' )
	);
 
});

At you can see, comparing to registering a regular Gutenberg block, here are a lot of dependencies. The above code can be placed in your theme / child theme functions.php or in a custom plugin, but please be careful with the path on line 7.

And I already know that I have to mention that too – at this moment sidebar.js is just an empty file 😁

In case you want to allow / disable your sidebar depending on a custom post type, you can use get_current_screen()-based condition at the beginning of the action hook:

add_action( 'enqueue_block_editor_assets', function(){
 
	$screen = get_current_screen();
	if( $screen->post_type === 'page' ) return; // disabled for Pages
 
	wp_enqueue_script(
 
		...

Step 3. Components

In this step let’s decide which React components we will need.

( function( plugins, editPost, element, components, data, compose ) {
 
	const el = element.createElement;
 
	const { Fragment } = element;
	const { registerPlugin } = plugins;
	const { PluginSidebar, PluginSidebarMoreMenuItem } = editPost;
	const { PanelBody, TextControl, TextareaControl, CheckboxControl } = components;
	const { withSelect, withDispatch } = data;
 
 
	const MetaTextControl = ...
	const MetaTextareaControl = ...
	const MetaCheckboxControl = ...
 
	registerPlugin( 
		...
	);
 
} )(
	window.wp.plugins,
	window.wp.editPost,
	window.wp.element,
	window.wp.components,
	window.wp.data,
	window.wp.compose
);

Here is just a skeleton, how your sidebar.js file will look like. You can copy the above code to the file right away.

Probably you see here some familiar components, like PanelBody, TextControl etc on line 7, which were explained in details in my previous tutorial. All the new components I will describe below.

Step 4. registerPlugin

Ok, here is a lot of code but everything is explained after it.

registerPlugin( 'misha-seo', {
	render: function() {
		return el( Fragment, {},
			el( PluginSidebarMoreMenuItem,
				{
					target: 'misha-seo',
					icon: mishaIcon,
				},
				'SEO'
			),
			el( PluginSidebar,
				{
					name: 'misha-seo',
					icon: mishaIcon,
					title: 'SEO',
				},
				el( PanelBody, {},
					// Field 1
					el( MetaTextControl,
						{
							metaKey: 'misha_plugin_seo_title',
							title : 'Title',
						}
					),
					// Field 2
					el( MetaTextareaControl,
						{
							metaKey: 'misha_plugin_seo_description',
							title : 'Description',
						}
					),
					// Field 3
					el( MetaCheckboxControl,
						{
							metaKey: 'misha_plugin_seo_robots',
							title : 'Hide from search engines',
						}
					),
				)
			)
		);
	}
} );
PluginSidebarMoreMenuItem component allows to add your sidebar panel to Plugins section in settings
If you do not add your sidebar plugin here, once you close your settings panel – it will be closed forever 😁

Step 5. withDispatch, withSelect

The long story short – using regular Gutenberg control components like TextControl or ToggleControl etc is not enough, because they don’t allow us go get or set values in post meta.

That’s why we compose them into a HOC (Higher Order Component):

var MetaTextControl = compose.compose(
	withDispatch( function( dispatch, props ) {
		return {
			setMetaValue: function( metaValue ) {
				dispatch( 'core/editor' ).editPost(
					{ meta: { [ props.metaKey ]: metaValue } }
				);
			}
		}
	} ),
	withSelect( function( select, props ) {
		return {
			metaValue: select( 'core/editor' ).getEditedPostAttribute( 'meta' )[ props.metaKey ],
		}
	} ) )( function( props ) {
		return el( TextControl, {
			label: props.title,
			value: props.metaValue,
			onChange: function( content ) {
				props.setMetaValue( content );
			},
		});
	}
);

According to the step 4 I created higher order components for each inspector control – MetaTextControl, MetaTextareaControl and MetaCheckboxControl, but the components code is very similar, so for some situations it would be better to create just one component, let’s say MetaControl and pass control type in it.

And a small bonus for you – just in case your would like to hide certain controls in your sidebar depending on a custom post type:

withSelect( function( select, props ) {
	return {
		metaValue: select( 'core/editor' ).getEditedPostAttribute( 'meta' )[ props.metaKey ],
		postType: select("core/editor").getCurrentPostType(),
	}
} ) )( function( props ) {
	if ( props.postType == 'page' ) {
		return null;
	}
	return el( TextControl, {
 
	...

See also

Misha Rudrastyh

Misha Rudrastyh

I love WordPress, WooCommerce and Gutenberg so much. 10 yrs of experience.

Need some custom developer help? Let me know

Follow Misha

Need some help with Gutenberg?

If you need some professional developer help, I will be happy to assist you.

Contact me Who I am?

Comments — 2

Leave a comment

php js HTML CSS Code