How to Create Custom Sidebars with PluginSidebar in Gutenberg

While working on the WordPress website it’s almost impossible to skip creating meta boxes. The meta box is helpful for storing metadata about your page, post, or custom post types. You can create the meta boxes using the old way but it doesn’t fit well with the Gutenberg. Though you can use it with Gutenberg, it’s recommended to create meta fields with PluginSidebar. This approach is better and works well if you have shifted to Gutenberg.

The PluginSidebar component adds an icon to the Gutenberg Toolbar. When click this icon, it opens a sidebar that will display your fields added to the <PluginSidebar/> component. As an example, in this tutorial, I am going to create a custom sidebar for a custom post type that looks like the below screenshot.

pluginsidebar

Here, I’ll create a post type called ‘team’ and to the team, I’ll add a few fields – Designation, Higher Education, and Social Links. All these values will be stored obviously in the postmeta table. While storing it, for social links, I’ll not create a separate entry per social site instead insert them as a serialized array. Our database entries will be as follows.

postmeta-entries

Register Meta For The Post Type

Now to see how it works practically, let’s register a post type ‘team’ and its meta keys.

Add the following code in your theme functions.php file. You can write this code in your plugin as well but as I’m going to write JSX code into the theme I mentioned about theme file here.

<?php
function setup_post_type() {
    $args = array(
        'public'    => true,
        'label'     => __( 'Team', 'surana' ),
        'menu_icon' => 'dashicons-admin-users',
        'show_in_rest' => true,
		'has_archive' => true,
        'supports' => array('title', 'editor', 'custom-fields'), // here custom-fields is compulsory
		'rewrite' => array('slug' => 'team', 'with_front' => false),
    );
    register_post_type( 'team', $args );

    register_meta( 
		'post', 
		'designation', // meta key
		array(
			'object_subtype' => 'team', // post type name here
 			'type'		=> 'string',
 			'single'	=> true,
 			'show_in_rest'	=> true,
 		)
	);

	register_meta( 
		'post', 
		'degree', 
		array(
			'object_subtype' => 'team',
 			'type'		=> 'string',
 			'single'	=> true,
 			'show_in_rest'	=> true,
 		)
	);

    register_meta( 
		'post', 
		'social_links', 
		array(
			'object_subtype' => 'team',
 			'type'		=> 'array',
 			'single'	=> true,
			'default' => array(),
 			'show_in_rest'	=> array(
				'schema' => array(
					'type'  => 'array', 
					'items' => array( 
						'type' => 'object',
						'properties' => array(
							'facebook' => array( 'type' => 'string' ),
							'linkedin' => array( 'type' => 'string' ),
						),
					)
				)
			),
 		)
	);
}
add_action( 'init', 'setup_post_type' );

If you notice, I’ve passed a little bit of complex schema for the meta key social_links. This is how we defined the schema if metadata is an array. I used facebook and linkedin in the array elements. Obviously, you’ll add/modify these values.

How To Write JSX in WordPress Theme

If you’re writing the JSX first time in your WordPress theme then you’re a little bit scared about how to do this. However, it’s not rocket science altogether. All you need to do is follow a few simple steps and you’ll be ready with the React-supported WordPress theme.

First, make sure you have Node JS with a version higher than 14.0 installed on your system. After this, inside your theme directory run the command:

npm install @wordpress/scripts --save-dev

The @wordpress/scripts is a tool that sets up a development environment for React into the WordPress theme.

Open your package.json and add the below lines to it.

"scripts": {
	"build": "wp-scripts build",
	"start": "wp-scripts start"
}

There are more scripts you can add here but for our tutorial, these 2 scripts are enough. The wp-scripts start watches for the changes inside src directory(we’ll create it in a moment) and compiles it to build folder. The build directory is created automatically when we run the command npm start in the next step. Basically, you’ve to run this npm start command once you start writing the code.

The wp-scripts build compiles the production-ready code and minifies the result in JavaScript. This command should run once you completed your development.

Next, create the src/index.js into your theme. We’re going to write the JSX code into this file. This file will compile to build/index.js so we enqueue build/index.js file in WordPress environment as follows.

<?php
add_action( 'enqueue_block_editor_assets', function() {
    $screen = get_current_screen();
	if( 'team' !== $screen->post_type ) {
		return; // disabled for all except team post type
	}

	wp_enqueue_script(
		'artisansweb-sidebar',
		get_stylesheet_directory_uri() . '/build/index.js',
		array( 'wp-edit-post', 'wp-element', 'wp-components', 'wp-plugins', 'wp-data' ),
		filemtime( get_stylesheet_directory() . '/build/index.js' )
	);
});

As per the name the enqueue_block_editor_assets action loads the assets on the backend editor. Here, I’ve passed a couple of dependencies required while writing a JSX.

You’re done with setting up a development environment for JSX in the WordPress theme. Now in your terminal run the command npm start which keeps watching the code written into the index.js file and compile it.

Create A Custom Sidebar With PluginSidebar

We’re done with registering metadata for the post type ‘team’. To enter the values for these fields let’s create a custom sidebar that will appear on post type edit screen.

I mentioned before we’ll have a total 4 fields out of which the Designation and Education will have a separate entries in postmeta. The social links will be stored as a single row in serialized array format.

To manage these fields in the <pluginSidebar/>, I’ll create 2 components:

  • <ArtisanswebTextControl />: It’ll return textfield for Designation and Education.
  • <ArtisanswebSocialLinksTextControl/>: This component is used for managing social links.

Open your src/index.js and place the below code do it.

( function( wp ) {

	const { registerPlugin } = wp.plugins;
	const { PluginSidebar } = wp.editPost;
    const { PanelBody, TextControl } = wp.components;
    const { useSelect, useDispatch } = wp.data;

	registerPlugin( 'team-meta', {
		render: function(){
			return (
				<PluginSidebar name="team-meta" title="Team Meta">
					<PanelBody title="Profile">
                        <ArtisanswebTextControl label="Designation" metaKey="designation" />
						<ArtisanswebTextControl label="Higher Education" metaKey="degree" />
                    </PanelBody>
                    <PanelBody title="Social Links">
                        <ArtisanswebSocialLinksTextControl metaKey="social_links" />
                    </PanelBody>
				</PluginSidebar>
			)
		}
	} );

	{/*define components here*/}
} )( window.wp );

I’ve called our components inside PanelBody to simplify the code. To the components I’m passing props – label and metaKey. Let’s now define these components.

const ArtisanswebTextControl = (props) => {
		let metaValue = useSelect(
			select => select('core/editor').getEditedPostAttribute( 'meta' )?.[ props.metaKey ],
		)

		const { editPost } = useDispatch( 'core/editor', [ metaValue ] );

		return (
			<TextControl
				type="text"
				label={ props.label }
				value={ metaValue }
				onChange={ ( content ) => { editPost( { meta: { [props.metaKey]: content } } ) } }
			/>
		);
	}

	const ArtisanswebSocialLinksTextControl = ( props ) => {

		let metaValues = useSelect(
			select => select('core/editor').getEditedPostAttribute('meta')?.[props.metaKey]
		);

		const { editPost } = useDispatch( 'core/editor', [ metaValues ] );

		if ( metaValues.length == 0 ) {
			metaValues.push({})
			metaValues = metaValues.splice(0)
			editPost( { meta: { [props.metaKey]: metaValues } } )
		}
		
		return <>
			{ metaValues.map( (row, index) => {
				return (
					<>
						<TextControl
							label="Facebook"
							value={ metaValues[index]['facebook'] }
							onChange={ (value) => {
								metaValues = metaValues.map((row, innerIndex) => {
									return innerIndex === index ? {...row, ['facebook']: value} : row
								});
								editPost( { meta: { [props.metaKey]: metaValues } } )
							} }
						/>

						<TextControl
							label="LinkedIn"
							value={ metaValues[index]['linkedin'] }
							onChange={ (value) => {
								metaValues = metaValues.map((row, innerIndex) => {
									return innerIndex === index ? {...row, ['linkedin']: value} : row
								});
								editPost( { meta: { [props.metaKey]: metaValues } } )
							} }
						/>
					</>
				)
			} ) }
		</>
	}

Each component contains the <TextControl/> and with useSelect and useDispatch hooks we set and get values of the meta field. These hooks are used to interact with wp.data api.

That’s it! Now go ahead and try to submit values and you’ll see you’re successfully created meta fields with the PluginSidebar component. I hope you’re now able to use it in your WordPress projects.

For the sake of tutorial, I have shown you only TextControl to manage meta. However, you’re free to use any type of control like TextareaControl, ToggleControl, etc. The logic will be the same for these controls.

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

Leave a Reply

Your email address will not be published. Required fields are marked *