My current personal project is to build a block plugin, and as a basic foundation I started with the Block Editor Handbook’s Create a Block Tutorial. In terms of adding new features, one aim was to create (meta) text inputs where I could input information, unique to each block being added to the page. If I add multiple blocks from my block plugin to the same post or page, the text fields for each block would be unique.
Initial searching led me to the plugin sidebar. Without knowing too much about it, it seemed like a good solution. This how-to guide is fantastic if you want to add your plugin sidebar using ES5. I converted mine to ESNext (the latest ES standard).
Before going further, here’s a heads up – if you just want to add controls / inputs to the sidebar unique to each specific instance of your block on a post / page, you want the settings sidebar. Anything added to the plugin sidebar for your block plugin will display on any post / page by default, even if the block isn’t present there.
Adding a plugin sidebar
My main intention at this stage was to add two text fields to the sidebar (plugin sidebar). Below is how I approached this in ES5, followed by a later ESNext re-write.
ES5
Much of this is covered in the Plugin Sidebar documentation here. The only differences are the addition of a second meta block field function in plugin-sidebar.js
, the return of the additional meta field element in the registerPlugin
function, and making sure to register the second meta field in the main PHP file for the block.
plugin-sidebar.js
:
( function ( wp ) {
var registerPlugin = wp.plugins.registerPlugin;
var PluginSidebar = wp.editPost.PluginSidebar;
var el = wp.element.createElement;
var TextControl = wp.components.TextControl;
var useSelect = wp.data.useSelect;
var useDispatch = wp.data.useDispatch;
var MetaBlockField = function ( props ) {
var metaFieldValue = useSelect( function ( select ) {
return select( 'core/editor' ).getEditedPostAttribute(
'meta'
)[ 'sidebar_plugin_meta_block_field' ];
}, [] );
var editPost = useDispatch( 'core/editor' ).editPost;
return el( TextControl,
{
label: 'First Meta Block Field',
value: metaFieldValue,
onChange: function ( content ) {
editPost( {
meta: { sidebar_plugin_meta_block_field: content },
} );
},
} );
};
var SecondMetaBlockField = function ( props ) {
var secondMetaFieldValue = useSelect( function ( select ) {
return select( 'core/editor' ).getEditedPostAttribute(
'meta'
)['sidebar_plugin_meta_block_field_2'];
}, [] );
var editPost = useDispatch( 'core/editor' ).editPost;
return el( TextControl,
{
label: 'Second Meta Block Field',
value: secondMetaFieldValue,
onChange: function ( content ) {
editPost( {
meta: { sidebar_plugin_meta_block_field_2: content },
} );
},
} );
};
registerPlugin( 'my-plugin-sidebar', {
render: function () {
return el(
PluginSidebar,
{
name: 'my-plugin-sidebar',
icon: 'admin-post',
title: 'My plugin sidebar',
},
el(
'div',
{ className: 'plugin-sidebar-content' },
el( MetaBlockField )
),
el(
'div',
{ className: 'plugin-sidebar-content2' },
el( SecondMetaBlockField )
)
);
},
} );
} )( window.wp );
main-plugin-file.php
:
function my_demo_block_plugin_init() {
register_block_type( __DIR__ . '/build' );
register_post_meta( 'post', 'sidebar_plugin_meta_block_field', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
register_post_meta( 'post', 'sidebar_plugin_meta_block_field_2', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
}
add_action( 'init', 'my_demo_block_plugin_init' );
ESNext
To re-write this in ESNext, I removed the plugin-sidebar.js
script from being registered and enqueued via my main PHP file as the information within it is now imported / exported.
My approach was to basically break up the functionality so that the initial registerPlugin
function is now in index.js
(which is where both the edit and save files were called). This returns a MetaFields
component which has been imported from plugin-sidebar.js
, and within that component the PluginSidebar
component is returned, enclosing the two TextControl
components.
As a result, my index.js
file now includes the following import along with the existing imports:
import MetaFields from './plugin-sidebar.js';
I also added the registerPlugin
function after the imports:
registerPlugin( 'my-plugin-sidebar', {
render: function(){
return (
<>
<MetaFields/>
</>
);
}
} );
The contents of plugin-sidebar.js
now includes the following:
import { PluginSidebar} from '@wordpress/edit-post';
import { TextControl } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
const MetaFields = (props) => {
return (
<PluginSidebar name="my-plugin-sidebar" title="My plugin sidebar">
<MetaBlockField/>
<SecondMetaBlockField/>
</PluginSidebar>
);
};
const MetaBlockField = (props) => {
const metaFieldValue = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute(
'meta'
)['sidebar_plugin_meta_block_field'];
}, []);
const editPost = useDispatch('core/editor').editPost;
return (
<TextControl
label="First Meta Block Field"
value={metaFieldValue}
onChange={(content) => editPost({
meta: { sidebar_plugin_meta_block_field: content },
} )
}
/>
);
};
const SecondMetaBlockField = (props) => {
const secondMetaFieldValue = useSelect( function ( select ) {
return select( 'core/editor' ).getEditedPostAttribute(
'meta'
)[ 'sidebar_plugin_meta_block_field_2' ];
}, [] );
const editPost = useDispatch( 'core/editor' ).editPost;
return (
<TextControl
label="Second Meta Block Field"
value={secondMetaFieldValue}
onChange={ ( content ) =>
editPost( {
meta: { sidebar_plugin_meta_block_field_2: content },
} )
}
/>
);
};
export default MetaFields;
In the end, this is what the sidebar looks like here:

Adding fields to the settings sidebar
This functionality is what I’d originally been looking for, as I only needed the settings to display when the block itself is selected.
This is fairly well covered in the how-to guides. In short, it’s the InspectorControls
component that will allow controls to show in the settings sidebar. Adding two text inputs instead of one involved a few changes, which I’ll show here (this is all in ESNext).
Within the Edit
function in edit.js
, I moved the contents of InspectorControls
to it’s own component (MyInspectorControls
). In there, the InspectorControls
component encloses two TextControl
components. Each of these two TextControl
components value’s are individual attributes. The || ''
is added to make sure these are controlled components, which also means the value can be passed to other UI elements too via props, or can notify changes through callbacks. In this case we’re saying ‘this component is controlled, but currently (may be ) empty‘.
export default function Edit( { attributes, setAttributes } ) {
const MyInspectorControls = (
<InspectorControls key="setting">
<div id="block-plugin-controls">
<TextControl
label="Additional Something first"
value={attributes.first_settings_input || ''}
onChange={ ( val ) => setAttributes( { first_settings_input: val } ) }
/>
<TextControl
label="Additional Something else"
value={attributes.second_settings_input || ''}
onChange={ ( val ) => setAttributes( { second_settings_input: val } ) }
/>
</div>
</InspectorControls>
);
return (
<div>
{ MyInspectorControls}
</div>
);
}
Moving back over to the main plugin file, we still need to make sure the meta fields are registered there too. Note the first parameter passed to register_post_meta
is an empty string as in this case the attribute should be available on both posts and pages:
register_post_meta( '', 'first_settings_input', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
register_post_meta( '', 'second_settings_input', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
Lastly, in index.js
, the meta fields should be added as attributes within the registerBlockType
function. This makes sure they are saved, as attributes:
attributes: {
first_settings_input: {
type: 'string',
},
second_settings_input: {
type: 'string',
},
},
After adding the block to a post or page, the is what the settings sidebar now looks like:

Hopefully this is a helpful introduction to adding text inputs to either the plugin sidebar or the settings sidebar, and will save you doing what I did and picking the wrong sidebar initially.