Custom Field & Meta Box in Gutenberg Editor

How to do this in the “new” way?

From this:

To this:

Creating a custom field using a custom meta box is simple and very straightforward.

Basically we create a meta box using meta box API and add it in post meta data using save_post hook.

Here’s the basic code:

// Add field:
add_action( 'add_meta_boxes', function() {
		'My Meta Box',
		function( $post ) {
			wp_nonce_field( __FILE__, '_my_data_nonce' );
			<p><input type="text" class="large-text" name="my_data" value="<?php echo esc_attr( get_post_meta( $post->ID, '_my_data', true ) ); ?>"></p>
} );
// Save field.
add_action( 'save_post', function( $post_id ) {
	if ( isset( $_POST['my_data'], $_POST['_my_data_nonce'] ) && wp_verify_nonce( $_POST['_my_data_nonce'], __FILE__ ) ) {
		update_post_meta( $post_id, '_my_data', sanitize_text_field( $_POST['my_data'] ) );
} );

But how to do this in the new way?

Note: the “old” way still works, but we need to learn to do this in “new” way to get all the latest and greatest features in WordPress.

#1 Register Field in Rest Endpoint

Gutenberg/block editor is using javascript and REST API, so to make this custom field editable via block editor, we need to register this field and make it available in WordPress REST API:

		'show_in_rest' => true,
		'single'       => true,
		'type'         => 'string',
		'auth_callback' => function() {
			return current_user_can( 'edit_posts' );

You can read more about it here:

#2 Create Field Using JS

So, we need to create a js script, and create/register editor plugin, and create a “meta box” using “PluginDocumentSettingPanel” component.

const MyDataSettings = () => {

	return (
		<PluginDocumentSettingPanel name="my-data" title="My Data">
			<TextControl value='' onChange='' />
if (window.pagenow === 'post') {
	registerPlugin('mydata', {
		render: MyDataSettings,
		icon: null,

And after we add the code above we will see the meta box, but it will do nothing.

To make this field to actually pull the meta data and save the data, we need to use state management functions.

const MyDataSettings = () => {
	const {
		meta: { _my_data },
	} = useSelect((select) => ({
		meta: select('core/editor').getEditedPostAttribute('meta') || {},

	const { editPost } = useDispatch('core/editor');

	const [myData, setMyData] = useState(_my_data);

	useEffect(() => {
			meta: {
				_my_data: myData,
	}, [myData]);

	return (
		<PluginDocumentSettingPanel name="my-data" title="My Data">
			<TextControl value={myData} onChange={setMyData} />

#3 Enqueue Script

I forgot to mention that, we need to enqueue the script. The easiest way is to simply use enqueue_block_editor_assets action hook because this hook will properly enqueue our script to post edit screen.

add_action( 'enqueue_block_editor_assets', function() {
		trailingslashit( plugin_dir_url( __FILE__ ) ) . 'my-data.min.js',
		[ 'wp-element', 'wp-blocks', 'wp-components', 'wp-editor' ],
} );

And not only that, we need to actually compile the script using webpack, etc.

Yup! building something for WordPress is not going to be as easy as it used to be. We’ll need to create a local dev, install node js, npm, etc.


To make it easier, I create an example plugin using the code above, you can download it here:

To use this plugin, you’ll need to run CLI command: npm install
And to compile the script: npm run build .

Let me know if you have question in using/understanding the plugin.


    • David

      awesome. glad that the plugin example is useful.
      i updated my blog post and add more info in how to use it.

      basically use “npm install” to install all dependencies.
      and you can use “npm run build” command to compile the JS.


Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.