Custom fields provide a way to assign extra information to website content. These bits of information are usually known as metadata.

Metadata is information about information. In the case of WordPress, it’s information associated with posts, users, comments and terms.

Given the many-to-one relationship of metadata in WordPress, your options are fairly limitless. You can have as many meta options as you wish, and you can store just about anything in there.

Plugin Handbook

Here are some examples of metadata you can attach to a post using custom fields:

  • The geographic coordinates of a place or real estate
  • The date of an event
  • The ISBN or author of a book
  • The mood of the day of the author of the post

And there are plenty more.

Out of the box, WordPress does not provide an easy way to add and manage custom fields. In the Classic Editor, custom fields are displayed in a box placed at the bottom of the page, below the post editor.

Custom fields in the Classic Editor
Custom fields in the Classic Editor.

In Gutenberg, custom fields are disabled by default, but you can display them by selecting the corresponding item in post settings.

Adding the custom fields panel to the block editor
Adding the custom fields panel to the block editor.

Unfortunately, there is no way to display metadata on the frontend without using a plugin or getting your hands dirty with code.

If you’re a user, you’ll find several excellent plugins doing the job for you out there. But if you’re a developer and want to get more out of WordPress custom fields, integrate them seamlessly into the block editor, and display them on the frontend of your WordPress website using a custom Gutenberg block, then you’re in the right place.

So, if you’re wondering what is the best way to use WordPress custom fields both in Gutenberg and the Classic Editor for WordPress developers, the quick answer is “creating a plugin that works for both the Classic Editor and Gutenberg”.

But don’t worry too much. If creating a plugin to manage custom fields in both editors could be a little tricky, we’ll try to make the process as straightforward as possible. Once you understand the concepts we’ll discuss in this article, you’ll gain the skills needed to manage custom meta fields in Gutenberg and build all kinds of websites.

Note: Before doing anything, make sure you have an up-to-date version of Node.js on your computer

That having been said, here is our rundown:

Create a Block Plugin With the Official create-block Tool

The first step is to create a new plugin with all the files and dependencies needed to register a new block type. The block plugin will allow you to easily build a custom block type for managing and displaying custom metadata.

To create a new block type, we’ll use the official create-block tool. For a detailed overview of how to use the create-block tool, check out our previous article about Gutenberg block development.

Open your command line tool, navigate to the plugins directory of your WordPress development website and run the following command:

npx @wordpress/create-block

When prompted, add the following details:

  • The template variant to use for this block: dynamic
  • The block slug used for identification (also the output folder name): metadata-block
  • The internal namespace for the block name (something unique for your products): meta-fields
  • The display title for your block: Meta Fields
  • The short description for your block (optional): Block description
  • The dashicon to make it easier to identify your block (optional): book
  • The category name to help users browse and discover your block: widgets
  • Do you want to customize the WordPress plugin? Yes/No

Let’s take a moment to review those details and try to understand where they are used.

  • The block slug used for identification defines the plugin’s folder name and textdomain
  • The internal namespace for the block name defines the block internal namespace and function prefix used throughout the plugin’s code.
  • The display title for your block defines the plugin name and the block name used in the editor interface.

The setup may take a couple of minutes. When the process is completed, you’ll get a list of the available commands.

Block plugin successfully installed
Block plugin successfully installed.

Before moving on to the next section, in your command line tool, navigate to your plugin’s folder and run the following commands:

cd metadata-block
npm start

You are ready to build your code. The next step is to edit the main PHP file of the plugin to build a meta box for the Classic Editor.

So, before moving on to the next section, install and activate the Classic Editor plugin.

Then, open the Plugins screen and activate the new Meta Fields plugin.

Activate plugins
Activate plugins.

Add a Meta Box to the Classic Editor

In the context of the Classic Editor, a meta box is a container holding form elements to type in specific bits of information, such as the post author, tags, categories, etc.

In addition to the built-in meta boxes, plugin developers can add any number of custom meta boxes to include HTML form elements (or any HTML content) where plugin users can enter plugin-specific data.

The WordPress API provides useful functions to easily register custom meta boxes to include all the HTML elements your plugin needs to work.

To get started, append the following code to the PHP file of the plugin you’ve just created:

// register meta box
function meta_fields_add_meta_box(){
	add_meta_box(
		'meta_fields_meta_box', 
		__( 'Book details' ), 
		'meta_fields_build_meta_box_callback', 
		'post',
		'side',
		'default'
	 );
}

// build meta box
function meta_fields_build_meta_box_callback( $post ){
	  wp_nonce_field( 'meta_fields_save_meta_box_data', 'meta_fields_meta_box_nonce' );
	  $title = get_post_meta( $post->ID, '_meta_fields_book_title', true );
	  $author = get_post_meta( $post->ID, '_meta_fields_book_author', true );
	  ?>
	  <div class="inside">
	  	  <p><strong>Title</strong></p>
		  <p><input type="text" id="meta_fields_book_title" name="meta_fields_book_title" value="<?php echo esc_attr( $title ); ?>" /></p>	
		  <p><strong>Author</strong></p>
		  <p><input type="text" id="meta_fields_book_author" name="meta_fields_book_author" value="<?php echo esc_attr( $author ); ?>" /></p>
	  </div>
	  <?php
}
add_action( 'add_meta_boxes', 'meta_fields_add_meta_box' );

The add_meta_box function registers a new meta box, while the callback function builds the HTML to be injected into the meta box. We won’t dive deeper into this topic because it’s beyond the scope of our article, but you’ll find all the details you need here, here and here.

The next step is to create a function that saves the data entered by the post author anytime the save_post hook is triggered (see Developer Resources):

// save metadata
function meta_fields_save_meta_box_data( $post_id ) {
	if ( ! isset( $_POST['meta_fields_meta_box_nonce'] ) )
		return;
	if ( ! wp_verify_nonce( $_POST['meta_fields_meta_box_nonce'], 'meta_fields_save_meta_box_data' ) )
		return;
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
		return;
	if ( ! current_user_can( 'edit_post', $post_id ) )
		return;

	if ( ! isset( $_POST['meta_fields_book_title'] ) )
		return;
	if ( ! isset( $_POST['meta_fields_book_author'] ) )
		return;

	$title = sanitize_text_field( $_POST['meta_fields_book_title'] );
	$author = sanitize_text_field( $_POST['meta_fields_book_author'] );

	update_post_meta( $post_id, '_meta_fields_book_title', $title );
	update_post_meta( $post_id, '_meta_fields_book_author', $author );
}
add_action( 'save_post', 'meta_fields_save_meta_box_data' );

Again, check out the online documentation for details. Here we’ll just point out the underscore character (_) preceding the meta key. This tells WordPress to hide the keys of these custom fields from the list of custom fields available by default and makes your custom fields visible only in your custom meta box.

The image below shows what the custom meta box looks like in the Classic Editor:

A custom Meta Box in the Classic Editor
A custom Meta Box in the Classic Editor.

Now, if you disable the Classic Editor plugin and check what happens in the block editor, you’ll see that the meta box still appears and works, but not exactly in the way you might expect.

Our goal is to create a system for managing metadata attached to blog posts or custom post types that integrates seamlessly within the block editor. For this reason, the code shown so far will only be needed to ensure backward compatibility with the Classic Editor.

So, before moving on, we’ll tell WordPress to remove the custom meta box from the block editor by adding the __back_compat_meta_box flag to the add_meta_box function (see also Meta Box Compatibility Flags and Backward Compatibility).

Let’s get back to the callback function that registers the meta box and change it as follows:

// register meta box
function meta_fields_add_meta_box(){
	add_meta_box(
		'meta_fields_meta_box', 
		__( 'Book details' ), 
		'meta_fields_build_meta_box_callback', 
		'post', 
		'side',
		'default',
		// hide the meta box in Gutenberg
		array('__back_compat_meta_box' => true)
	 );
}

Save the plugin file and go back to your WordPress admin. Now, you shouldn’t see the custom meta box in the block editor anymore. If you reactivate the Classic Editor instead, your custom meta box will show up again.

Add Custom Meta Fields to the Gutenberg Block Editor (Three Options)

In our previous articles about Gutenberg block development, we provided detailed overviews of the editor, its parts, and how to develop static blocks and dynamic blocks.

As we mentioned, in this article we’ll take it a step further and discuss how to add custom meta fields to blog posts.

There are several ways to store and use post metadata in Gutenberg. Here we’ll cover the following:

Create a Custom Block To Store and Display Custom Meta Fields

In this section, we’ll show you how to create and manage custom meta fields from within a dynamic block. According to the Block Editor Handbook, a post meta field “is a WordPress object used to store extra data about a post” and we need to first register a new meta field before we can use it.

Register Custom Meta Fields

Before registering a custom meta field, you need to make sure that the post type that will use it supports custom fields. In addition, when you register a custom meta field, you should set the show_in_rest parameter to true.

Now, back to the plugin file. Add the following code:

/**
 * Register the custom meta fields
 */
function meta_fields_register_meta() {

    $metafields = [ '_meta_fields_book_title', '_meta_fields_book_author' ];

    foreach( $metafields as $metafield ){
        // Pass an empty string to register the meta key across all existing post types.
        register_post_meta( '', $metafield, array(
            'show_in_rest' => true,
            'type' => 'string',
            'single' => true,
            'sanitize_callback' => 'sanitize_text_field',
            'auth_callback' => function() { 
                return current_user_can( 'edit_posts' );
            }
        ));
    }  
}
add_action( 'init', 'meta_fields_register_meta' );

register_post_meta registers a meta key for the specified post types. In the code above, we have registered two custom meta fields for all post types registered on your website that support custom fields. For more information, see the function reference.

Once done, open the src/index.js file of your block plugin.

Register the Block Type on the Client

Now navigate to the wp-content/plugins/metadata-block/src folder and open the index.js file:

import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import Edit from './edit';
import metadata from './block.json';

registerBlockType( metadata.name, {
	edit: Edit,
} );

With static blocks we would also have seen a save function. In this case, the save function is missing because we installed a dynamic block. The content shown on the frontend will be generated dynamically via PHP.

Build the Block Type

Navigate to the wp-content/plugins/metadata-block/src folder and open the edit.js file. You should see the following code (comments removed):

import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.scss';

export default function Edit() {
	return (
		<p { ...useBlockProps() }>
			{ __( 'Meta Fields – hello from the editor!', 'metadata-block' ) }
		</p>
	);
}

Here you’ll add the code to generate the block to be rendered in the editor.

The first step is to import the components and functions needed to build the block. Here is the complete list of dependencies:

import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls, RichText } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
import { useEntityProp } from '@wordpress/core-data';
import { TextControl, PanelBody, PanelRow } from '@wordpress/components';
import './editor.scss';

If you’ve read our previous articles, you should be familiar with many of these import declarations. Here we’ll point out just a couple of them:

import { useSelect } from '@wordpress/data';
import { useEntityProp } from '@wordpress/core-data';

Once you’ve imported these dependencies, here is how you’ll useSelect and useEntityProp in the Edit() function:

const postType = useSelect(
		( select ) => select( 'core/editor' ).getCurrentPostType(),
		[]
	);
const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );

This code provides the current postType, an object of meta fields (meta), and a setter function to update them (setMeta).

Now replace the current code for the Edit() function with the following:

export default function Edit() {
	const blockProps = useBlockProps();
	const postType = useSelect(
		( select ) => select( 'core/editor' ).getCurrentPostType(),
		[]
	);
	const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
	const bookTitle = meta[ '_meta_fields_book_title' ];
	const bookAuthor = meta[ '_meta_fields_book_author' ];
	const updateBookTitleMetaValue = ( newValue ) => {
		setMeta( { ...meta, _meta_fields_book_title: newValue } );
    };
	const updateBookAuthorMetaValue = ( newValue ) => {
		setMeta( { ...meta, _meta_fields_book_author: newValue } );
	};
return ( ... );
}

Again:

  • We used useSelect to get the current post type.
  • useEntityProp returns an array of meta fields and a setter function to set new meta values.
  • updateBookTitleMetaValue and updateBookAuthorMetaValue are two event handlers to save meta field values.

The next step is to build the JSX (JavaScript XML) code returned by the Edit() function:

export default function Edit() {
	...
	return (
		<>
			<InspectorControls>
				<PanelBody 
					title={ __( 'Book Details' )}
					initialOpen={true}
				>
					<PanelRow>
						<fieldset>
							<TextControl
								label={__( 'Book title' )}
								value={ bookTitle }
								onChange={ updateBookTitleMetaValue }
							/>
						</fieldset>
					</PanelRow>
					<PanelRow>
						<fieldset>
							<TextControl
								label={ __( 'Book author' ) }
								value={ bookAuthor }
								onChange={ updateBookAuthorMetaValue }
							/>
						</fieldset>
					</PanelRow>
				</PanelBody>
			</InspectorControls>
			<div { ...blockProps }>
				<RichText 
					tagName="h3"
					onChange={ updateBookTitleMetaValue }
					allowedFormats={ [ 'core/bold', 'core/italic' ] }
					value={ bookTitle }
					placeholder={ __( 'Write your text...' ) }
				/>
				<TextControl
					label="Book Author"
					value={ bookAuthor }
					onChange={ updateBookAuthorMetaValue }
				/>
			</div>
		</>
	);
}

The RichText component provides a contenteditable input, while TextControl provides simple text fields.

We also created a sidebar panel containing two input fields to use instead of the two form controls included in the block.

Save the file and go back to the editor. Add the Meta Fields block from the block inserter and fill in the book title and author.

A custom block including two custom meta fields
A custom block including two custom meta fields.

You will notice that whenever you change the value of the field in the block, the value in the corresponding text field in the sidebar will also change.

Next, we have to create the PHP code that generates the HTML to be rendered on the frontend.

Display the Block on the Frontend

Open the main PHP file again in your code editor and rewrite the callback function that generates the output of the block as follows:

function meta_fields_metadata_block_block_init() {
	register_block_type(
		__DIR__ . '/build',
		array(
			'render_callback' => 'meta_fields_metadata_block_render_callback',
		)
	);
}
add_action( 'init', 'meta_fields_metadata_block_block_init' );

function meta_fields_metadata_block_render_callback( $attributes, $content, $block ) {
	
	$book_title = get_post_meta( get_the_ID(), '_meta_fields_book_title', true );
	$book_author = get_post_meta( get_the_ID(), '_meta_fields_book_author', true );
    
	$output = "";

	if( ! empty( $book_title ) ){
		$output .= '<h3>' . esc_html( $book_title ) . '</h3>';
	}
	if( ! empty( $book_author ) ){
		$output .= '<p>' . __( 'Book author: ' ) . esc_html( $book_author ) . '</p>';
	}
	if( strlen( $output ) > 0 ){
		return '<div ' . get_block_wrapper_attributes() . '>' . $output . '</div>';
	} else {
		return '<div ' . get_block_wrapper_attributes() . '>' . '<strong>' . __( 'Sorry. No fields available here!' ) . '</strong>' . '</div>';
	}
}

This code is quite self-explanatory. First, we use get_post_meta to retrieve the values of the custom meta fields. Then we use those values to build the block content. Finally, the callback function returns the HTML of the block.

The block is ready to be used. We intentionally kept the code in this example as simple as possible but using Gutenberg’s native components you can build more advanced blocks and get the most from WordPress custom meta fields.

A custom block including several meta fields
A custom block including several meta fields.

In our example, we used h3 and p elements to build the block for the frontend.

But you can display the data in many ways. The following image shows a simple unordered list of meta fields.

An example block on the frontend
An example block on the frontend.

You’ll find the complete code of this example in this public gist.

Adding a Custom Meta Box to the Document Sidebar

The second option is to attach custom meta fields to posts using a plugin that generates a settings panel in the Document Sidebar.

The process is pretty similar to the previous example, except that in this case, we won’t need a block to manage metadata. We will create a component to generate a panel including a set of controls in the Document sidebar following these steps:

  1. Create a new block plugin with create-block
  2. Register a custom meta box for the Classic Editor
  3. Register the custom meta fields in the main plugin file via the register_post_meta() function
  4. Register a plugin in the index.js file
  5. Build the component using built-in Gutenberg components

Create a New Block Plugin With the create-block Tool

To create a new block plugin, follow the steps in the previous section. You can create a new plugin or edit the scripts we built in the previous example.

Register a Custom Meta Box for the Classic Editor

Next, you need to register a custom meta box to ensure backward compatibility for WordPress websites still using the Classic Editor. The process is the same as described in the previous section.

Register the Custom Meta Fields in the Main Plugin File

The next step is to register the custom meta fields in the main plugin file via the register_post_meta() function. Again, you can follow the previous example.

Register a Plugin in the index.js File

Once you’ve completed the previous steps, it is time to register a plugin in the index.js file to render a custom component.

Before registering the plugin, create a components folder inside the plugin’s src folder. Inside the components folder, create a new MetaBox.js file. You can choose whatever name you think is good for your component. Just make sure to follow the best practice for naming in React.

Before moving on, install the @wordpress/plugins module from your command line tool.

Stop the process (mac), install the module and start the process again:

^C
npm install @wordpress/plugins --save
npm start

Once done, open the index.js file of your plugin and add the following code.

/**
 * Registers a plugin for adding items to the Gutenberg Toolbar
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/slotfills/plugin-sidebar/
 */
import { registerPlugin } from '@wordpress/plugins';

import MetaBox from './components/MetaBox';

This code is fairly self-explanatory. However, we want to take a moment to dwell on the two import statements for those readers who do not have advanced React skills.

With the first import statement, we enclosed the name of the function in curly brackets. With the second import statement, the name of the component is not enclosed in curly brackets.

Next, register your plugin:

registerPlugin( 'metadata-plugin', {
	render: MetaBox
} );

registerPlugin simply registers a plugin. The function accepts two parameters:

  • A unique string that identifies the plugin
  • An object of plugin settings. Note that the render property must be specified and must be a valid function.

Build the Component Using Built-in Gutenberg Components

It’s time to build our React component. Open the MetaBox.js file (or whatever you called it) and add the following import statements:

import { __ } from '@wordpress/i18n';
import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { PanelRow, TextControl, DateTimePicker } from '@wordpress/components';
  • The compose function performs function composition, meaning that the result of a function is passed on to another function.Before you can use compose, you may need to install the corresponding module:
    npm install @wordpress/compose --save

    We’ll see the compose function in action in a moment.

  • withSelect and withDispatch are two higher order components that allow you to fetch or dispatch data from or to a WordPress store. withSelect is used to inject state-derived props using registered selectors, withDispatch is used to dispatch props using registered action creators.
  • PluginDocumentSettingPanel renders items in the Document Sidebar (see the source code on Github).

Next, you’ll create the component to display the meta box panel in the Document sidebar. In your MetaBox.js file, add the following code:

const MetaBox = ( { postType, metaFields, setMetaFields } ) => {

	if ( 'post' !== postType ) return null;

	return(
		<PluginDocumentSettingPanel 
			title={ __( 'Book details' ) } 
			icon="book"
			initialOpen={ false }
		>
			<PanelRow>
				<TextControl 
					value={ metaFields._meta_fields_book_title }
					label={ __( "Title" ) }
					onChange={ (value) => setMetaFields( { _meta_fields_book_title: value } ) }
				/>
			</PanelRow>
			<PanelRow>
				<TextControl 
					value={ metaFields._meta_fields_book_author }
					label={ __( "Author" ) }
					onChange={ (value) => setMetaFields( { _meta_fields_book_author: value } ) }
				/>
			</PanelRow>
			<PanelRow>
				<TextControl 
					value={ metaFields._meta_fields_book_publisher }
					label={ __( "Publisher" ) }
					onChange={ (value) => setMetaFields( { _meta_fields_book_publisher: value } ) }
				/>
			</PanelRow>
			<PanelRow>
				<DateTimePicker
					currentDate={ metaFields._meta_fields_book_date }
					onChange={ ( newDate ) => setMetaFields( { _meta_fields_book_date: newDate } ) }
					__nextRemoveHelpButton
					__nextRemoveResetButton
				/>
			</PanelRow>
		</PluginDocumentSettingPanel>
	);
}

const applyWithSelect = withSelect( ( select ) => {
	return {
		metaFields: select( 'core/editor' ).getEditedPostAttribute( 'meta' ),
		postType: select( 'core/editor' ).getCurrentPostType()
	};
} );

const applyWithDispatch = withDispatch( ( dispatch ) => {
	return {
		setMetaFields ( newValue ) {
			dispatch('core/editor').editPost( { meta: newValue } )
		}
	}
} );

export default compose([
	applyWithSelect,
	applyWithDispatch
])(MetaBox);

Let’s break down this code.

  • The PluginDocumentSettingPanel element renders a new panel in the Document sidebar. We set the title (“Book details”) and icon, and set initialOpen to false, which means that initially the panel is closed.
  • Within the PluginDocumentSettingPanel we have three text fields and a DateTimePicker element that allows the user to set the publication date.
  • withSelect provides access to the select function that we are using to retrieve metaFields and postType. withDispatch provides access to the dispatch function, which allows to update the metadata values.
  • Finally, the compose function allows us to compose our component with withSelect and withDispatch higher-order components. This gives the component access to the metaFields and postType properties and the setMetaFields function.

Save your MetaBox.js file and create a new post in your WordPress development website and take a look at the Document Sidebar. You should see the new Book details panel.

A custom meta box panel in Gutenberg
A custom meta box panel in Gutenberg.

Now run your tests. Set the values of your custom meta fields and save the post. Then reload the page and check if the values you entered are in place.

Add the block we have built in the previous section and check if everything is working properly.

Adding a Custom Sidebar To Manage Post Meta Data

If you have a large number of custom meta fields to add to your posts or custom post types, you could also create a Custom Settings Sidebar specifically for your plugin.

The process is very similar to the previous example, so if you’ve understood the steps discussed in the previous section, you won’t have any difficulty with building a Custom Sidebar for Gutenberg.

Again:

  1. Create a new block plugin with create-block
  2. Register a custom meta box for the Classic Editor
  3. Register the custom meta fields in the main plugin file via the register_post_meta() function
  4. Register a plugin in the index.js file
  5. Build the component using built-in Gutenberg components

Create a New Block Plugin With the create-block Tool

Again, to create a new block plugin, follow the steps discussed above. You can create a new plugin or edit the scripts built in the previous examples.

Register a Custom Meta Box for the Classic Editor

Now register a custom meta box to ensure backward compatibility for WordPress websites still using the Classic Editor. The process is the same as described in the previous section.

Register the Custom Meta Fields in the Main Plugin File

Register the custom meta fields in the main plugin file via the register_post_meta() function.

Register a Plugin in the index.js File

Now create an empty CustomSidebar.js file in your components folder.

Once done, change your index.js file as follows:

/**
 * Registers a plugin for adding items to the Gutenberg Toolbar
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/slotfills/plugin-sidebar/
 */
import { registerPlugin } from '@wordpress/plugins';

import CustomSidebar from './components/CustomSidebar';
// import MetaBox from './components/MetaBox';

registerPlugin( 'metadata-block', {
    render: CustomSidebar
} );

With the code above we first import the CustomSidebar component, then we tell the registerPlugin function to render the new component.

Build the Component Using Built-in Gutenberg Components

Next, open the CustomSidebar.js file and add the following dependencies:

import { __ } from '@wordpress/i18n';
import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/edit-post';
import { PanelBody, PanelRow, TextControl, DateTimePicker } from '@wordpress/components';

You should notice that we are importing two new components:

  • PluginSidebar adds an icon into the Gutenberg Toolbar that, when clicked, displays a sidebar including the content wrapped in the <PluginSidebar /> element (The component is also documented on GitHub).
  • PluginSidebarMoreMenuItem renders a menu item under Plugins in More Menu dropdown and can be used to activate the corresponding PluginSidebar component (see also on GitHub).

Now you can build your custom component:

const CustomSidebar = ( { postType, metaFields, setMetaFields } ) => {
        
    if ( 'post' !== postType ) return null;

    return (
        <>
            <PluginSidebarMoreMenuItem 
                target="metadata-sidebar" 
                icon="book"
            >
                Metadata Sidebar
            </PluginSidebarMoreMenuItem>
            <PluginSidebar 
                name="metadata-sidebar" 
                icon="book" 
                title="My Sidebar"
            >
                <PanelBody title="Book details" initialOpen={ true }>
                    <PanelRow>
                        <TextControl 
                            value={ metaFields._meta_fields_book_title }
                            label={ __( "Title" ) }
                            onChange={ (value) => setMetaFields( { _meta_fields_book_title: value } ) }
                        />
                    </PanelRow>
                    <PanelRow>
                        <TextControl 
                            value={ metaFields._meta_fields_book_author }
                            label={ __("Author", "textdomain") }
                            onChange={ (value) => setMetaFields( { _meta_fields_book_author: value } ) }
                        />
                    </PanelRow>
                    <PanelRow>
                        <TextControl 
                            value={ metaFields._meta_fields_book_publisher }
                            label={ __("Publisher", "textdomain") }
                            onChange={ (value) => setMetaFields( { _meta_fields_book_publisher: value } ) }
                        />
                    </PanelRow>
                    <PanelRow>
                        <DateTimePicker
                            currentDate={ metaFields._meta_fields_book_date }
                            onChange={ ( newDate ) => setMetaFields( { _meta_fields_book_date: newDate } ) }
                            __nextRemoveHelpButton
                            __nextRemoveResetButton
                        />
                    </PanelRow>
                </PanelBody>
            </PluginSidebar>
        </>
    )
}

The final step is the component composition with withSelect and withDispatch higher-order components:

const applyWithSelect = withSelect( ( select ) => {
    return {
        metaFields: select( 'core/editor' ).getEditedPostAttribute( 'meta' ),
        postType: select( 'core/editor' ).getCurrentPostType()
    };
} );

const applyWithDispatch = withDispatch( ( dispatch ) => {
    return {
        setMetaFields ( newValue ) {
            dispatch('core/editor').editPost( { meta: newValue } )
        }
    }
} );

export default compose([
    applyWithSelect,
    applyWithDispatch
])(CustomSidebar);

Save your changes, then check the editor interface. If you open the Options dropdown, you’ll see a new Metadata Sidebar item under the Plugins section. Clicking on the new item will activate your brand-new custom sidebar.

The PluginSidebarMoreMenuItem component adds a menu item under Options - Plugins
The PluginSidebarMoreMenuItem component adds a menu item under Options – Plugins.

The same happens when you click on the book icon in the upper right corner.

The Plugin Settings Sidebar
The Plugin Settings Sidebar.

Now go back to your development website, and create a new blog post. Fill in your meta fields, then add the block to the editor’s canvas. It should include the same meta values you entered in your custom sidebar.

Save the post and preview the page on the frontend. You should see your card including the book title, author, publisher, and publication date.

You’ll find the full code of this article in this public gist.

Further Readings

In this article, we covered multiple topics, from selectors to higher-order components and much more. We’ve linked the top resources we used for reference throughout the article as well.

But if you wish to dive deeper into those topics, you may also want to check the following additional resources:

Gutenberg Documentation and Official WordPress Resources

More Official Resources

Additional Resources From the Community

Useful Readings From the Kinsta Website

Summary

In this third article in our series on Gutenberg block development, we covered new advanced topics that should make the picture outlined in previous articles on static and dynamic block development more complete.

You should now be able to take advantage of the potential of custom fields in Gutenberg and create more advanced and functional WordPress websites.

But there’s more. With the skills you’ve gained from our articles on block development, you should also have a good idea of how to develop React components outside of WordPress. After all, Gutenberg is a React-based SPA.

And now it’s down to you! Have you already created Gutenberg blocks that use custom meta fields? Share your creations with us in the comments below.

Carlo Daniele Kinsta

Carlo is a passionate lover of webdesign and front-end development. He has been playing with WordPress for more than 20 years, also in collaboration with Italian and European universities and educational institutions. He has written hundreds of articles and guides about WordPress, published both on Italian and international websites, as well as on printed magazines. You can find him on LinkedIn.