How To Store Post Meta By Creating Sidebar For Your Plugin

This post assumes you already have a plugin installed and ready to add PHP and JavaScript code To Store Post Meta By Creating Sidebar For Your Plugin. For an introduction to WordPress plugins and how to use JavaScript to expand the block editor, Click to see the Gutenberg block.

In the next sections, you’ll develop a custom sidebar for a plugin that includes a TextControl

which allows the user to edit a value in the post_meta table.

Get a Sidebar up and Running to Store Post Meta

The first step is to inform the editor that a new plugin with its own sidebar has been installed. To do so, go to the

@wordpress/plugins, @wordpress/edit-post, and @wordpress/element packages and use the registerPlugin, PluginSidebar, and createElement functions supplied by WordPress.

Save the following code in a JavaScript file called plugin-sidebar.js in the plugin’s directory:

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
 
    registerPlugin( 'my-plugin-sidebar', {
        render: function () {
            return el(
                PluginSidebar,
                {
                    name: 'my-plugin-sidebar',
                    icon: 'admin-post',
                    title: 'My plugin sidebar',
                },
                'Meta field'
            );
        },
    } );
} )( window.wp );

Because those utilities must be available in the browser for this code to operate, you instruct WordPress to enqueue the packages that include them by declaring wp-plugins, wp-edit-post, and wp-element as script dependents.

Copy and paste the following code into a PHP file in your plugin’s directory:

<?php
 
/*
Plugin Name: Sidebar plugin
*/
 
function sidebar_plugin_register() {
    wp_register_script(
        'plugin-sidebar-js',
        plugins_url( 'plugin-sidebar.js', __FILE__ ),
        array( 'wp-plugins', 'wp-edit-post', 'wp-element' )
    );
}
add_action( 'init', 'sidebar_plugin_register' );
 
function sidebar_plugin_script_enqueue() {
    wp_enqueue_script( 'plugin-sidebar-js' );
}
add_action( 'enqueue_block_editor_assets', 'sidebar_plugin_script_enqueue' );

After you’ve installed and activated this plugin, you’ll see a new icon in the top-right corner of the editor that looks like a tack. The plugin’s sidebar will open when you click it:

sidebar-up-and-running

Tweak the sidebar style and add controls

After the sidebar is up and running, add the essential components and basic style.

To visualize and edit the meta field value you’ll use an input component. The @wordpress/components package includes a number of components that you may reuse, and, specifically, the TextControl is aimed at creating an input field:

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
    var Text = wp.components.TextControl;
 
    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( Text, {
                        label: 'Meta Block Field',
                        value: 'Initial value',
                        onChange: function ( content ) {
                            console.log( 'content changed to ', content );
                        },
                    } )
                )
            );
        },
    } );
} )( window.wp );

Add this new code to plugin-sidebar.js. It’s worth noting that it makes use of the @wordpress/components package’s new wp.components functionality. Include it in the PHP dependencies array as wp-components.

It makes the following modifications to the preceding section:

  • To be able to add some styles, I added the CSS class plugin-sidebar-content to the div element.
  • Substituted the raw Meta field text with a TextControl component wrapped within the div element.

With the new CSS class, you can now give the sidebar some breathing room. Create a new file in your plugin directory called plugin-sidebar.css with the following contents:

.plugin-sidebar-content {
    padding: 16px;
}

You must instruct WordPress to enqueue this stylesheet in the editor and front-end by using the enqueue_block_editor_assets action hook.

Following those modifications, the PHP code should look like this:

<?php
 
/*
Plugin Name: Sidebar example
*/
 
function sidebar_plugin_register() {
    wp_register_script(
        'plugin-sidebar-js',
        plugins_url( 'plugin-sidebar.js', __FILE__ ),
        array(
            'wp-plugins',
            'wp-edit-post',
            'wp-element',
            'wp-components'
        )
    );
    wp_register_style(
        'plugin-sidebar-css',
        plugins_url( 'plugin-sidebar.css', __FILE__ )
    );
}
add_action( 'init', 'sidebar_plugin_register' );
 
function sidebar_plugin_script_enqueue() {
    wp_enqueue_script( 'plugin-sidebar-js' );
}
add_action( 'enqueue_block_editor_assets', 'sidebar_plugin_script_enqueue' );
 
function sidebar_plugin_style_enqueue() {
    wp_enqueue_style( 'plugin-sidebar-css' );
}
add_action( 'enqueue_block_assets', 'sidebar_plugin_style_enqueue' );

Open the sidebar and reload the editor:

sidebar-style-and-controls

Register the Meta Field to Store Post Meta

WordPress includes a register_post_meta method for working with fields in the post_meta table. You’re going to utilize it to register a new field named sidebar_plugin_meta_block_field, which will be a single string. This field must be accessible via the REST API since the block editor uses the REST API to retrieve data.

Within the init callback function, add the following to the PHP code:

register_post_meta( 'post', 'sidebar_plugin_meta_block_field', array(
    'show_in_rest' => true,
    'single' => true,
    'type' => 'string',
) );

Query the block editor’s internal data structures, commonly known as stores, to ensure the field has been loaded. Open the console in your browser and type the following code:

wp.data.select( 'core/editor' ).getCurrentPost().meta;

Because WordPress hasn’t been told to load any meta fields yet, this code returns a void array before adding the register_post_meta function to the plugin. The same code will return an object containing the registered meta field you registered once you register it.

Make sure your post type allows custom-fields if the code returns undefined. Either during registering the post or using the add_post_type_support_function.

Initialize the Input Control to Store Post Meta

The field can now be surfaced to the UI because it’s in the editor store. The first step will be to separate the input control into its own function, allowing you to expand its functionality while keeping the code clean.

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
    var Text = wp.components.TextControl;
 
    var MetaBlockField = function () {
        return el( Text, {
            label: 'Meta Block Field',
            value: 'Initial value',
            onChange: function ( content ) {
                console.log( 'content changed to ', 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 )
                )
            );
        },
    } );
} )( window.wp );

You may now concentrate entirely on the MetaBlockField component. The objective is to set it up using the value of sidebar_plugin_meta_block_field and maintain it up to current when that value changes.

WordPress offers a few tools for working with store data. UseSelect is the first command you’ll use.

The useSelect method is used to retrieve data for the current component and to update it when the original data changes. To use it, we’ll need to edit the code:

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
    var Text = wp.components.TextControl;
    var useSelect = wp.data.useSelect;
 
    var MetaBlockField = function () {
        var metaFieldValue = useSelect( function ( select ) {
            return select( 'core/editor' ).getEditedPostAttribute( 'meta' )[ 'sidebar_plugin_meta_block_field' ];
        }, [] );
 
        return el( Text, {
            label: 'Meta Block Field',
            value: metaFieldValue,
            onChange: function ( content ) {
                console.log( 'content has changed to ', 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 )
                )
            );
        },
    } );
} )( window.wp );

This code should be pasted into the JavaScript file. It’s worth noting that it now uses the wp.data.useSelect utility to be found in the @wordpress/data package. Include wp-data as a dependency in your PHP script.

The following is how the code from the previous section differs:

  • Every time the original data changes, the MetaBlockField component will be updated.
  • Instead of using getCurrentPost, getEditedPostAttribute is utilizes to obtain data since it returns the most current values of the post, including user editions that haven’t been saves yet.

Open the sidebar and update the code. The content of the input is now a void string rather than an Initial value. Users can’t yet type values, but if the value in the store changes, make sure the component is update. Open the console in your browser and run the code.

wp.data
    .dispatch( 'core/editor' )
    .editPost( { meta: { sidebar_plugin_meta_block_field: 'hello world!' } } );

and see how the input component’s contents change!

Update the Meta Field When the Input’s Content Changes

When the input content changes, the final step in the trip is to update the meta field. To do so, you’ll utilise useDispatch, a tool from the @wordpress/data package. Hooks are another name for these utilities.

The useDispatch function accepts only one parameter, the store name, and returns methods for updating the store.

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
    var Text = 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( Text, {
            label: 'Meta Block Field',
            value: metaFieldValue,
            onChange: function ( content ) {
                editPost( {
                    meta: { sidebar_plugin_meta_block_field: 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 )
                )
            );
        },
    } );
} )( window.wp );

The following is how it differed from the preceding section:

  • The editPost method returned by the useDispatch hook is now used by the component. Actions are another name for these functions.
  • We effectively update the editor store on each key stroke by calling editPost every time the user writes something within the input control.

Copy and paste this new code into the JavaScript file, then load the sidebar to see how the input value changes as you enter. It’s also a good idea to double-check that the internal data structures have been updated. Fill in the blanks in the input control, then run the following command in your browser’s console:

wp.data.select( 'core/editor' ).getEditedPostAttribute( 'meta' )[
    'sidebar_plugin_meta_block_field'
];

The message that appears should be the same as what you placed into the input box.

After you’ve made your adjustments, press the “Save draught” or “Publish” button to save your work. Reload the editor page after that. The browser now includes new material, which has been pulled directly from the database. You want to make sure that everything you entered was saved correctly in the database and that it was reloaded into the current post data structure. Open the sidebar and double-check that the input control is fix to the last value you entered.

One last double-check. Because you haven’t yet updated the input, the current post and the edited characteristics should be identical at this time. Confirm this by running the following code in the console of your browser:

wp.data.select( 'core/editor' ).getCurrentPost()[ 'meta' ][
    'sidebar_plugin_meta_block_field'
];
wp.data.select( 'core/editor' ).getEditedPostAttribute( 'meta' )[
    'sidebar_plugin_meta_block_field'
];

That’s it! you have done it.

Finishing Touches for Store Post Meta

Now that your JavaScript code is working as intended, there are a few things you can do to make it simpler and easier to update in the future.

The first step is to turn mapSelectToProps and mapDispatchToProps into anonymous methods that can be given straight to withSelect and withData:

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
    var Text = wp.components.TextControl;
    var withSelect = wp.data.withSelect;
    var withDispatch = wp.data.withDispatch;
 
    var MetaBlockField = function ( props ) {
        return el( Text, {
            label: 'Meta Block Field',
            value: props.metaFieldValue,
            onChange: function ( content ) {
                props.setMetaFieldValue( content );
            },
        } );
    };
 
    var MetaBlockFieldWithData = withSelect( function ( select ) {
        return {
            metaFieldValue: select( 'core/editor' ).getEditedPostAttribute(
                'meta'
            )[ 'sidebar_plugin_meta_block_field' ],
        };
    } )( MetaBlockField );
 
    var MetaBlockFieldWithDataAndActions = withDispatch( function ( dispatch ) {
        return {
            setMetaFieldValue: function ( value ) {
                dispatch( 'core/editor' ).editPost( {
                    meta: { sidebar_plugin_meta_block_field: value },
                } );
            },
        };
    } )( MetaBlockFieldWithData );
 
    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( MetaBlockFieldWithDataAndActions )
                )
            );
        },
    } );
} )( window.wp );

After that, combine MetaBlockField, MetaBlockFieldWithData, and MetaBlockFieldWithDataAndActions into one MetaBlockField function that is provided to the div element. Compose is a tool provided by the @wordpress/compose package for concatenating functions. Don’t forget to include wp-compose in the PHP script’s dependencies array.

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
    var Text = wp.components.TextControl;
    var withSelect = wp.data.withSelect;
    var withDispatch = wp.data.withDispatch;
    var compose = wp.compose.compose;
 
    var MetaBlockField = compose(
        withDispatch( function ( dispatch ) {
            return {
                setMetaFieldValue: function ( value ) {
                    dispatch( 'core/editor' ).editPost( {
                        meta: { sidebar_plugin_meta_block_field: value },
                    } );
                },
            };
        } ),
        withSelect( function ( select ) {
            return {
                metaFieldValue: select( 'core/editor' ).getEditedPostAttribute(
                    'meta'
                )[ 'sidebar_plugin_meta_block_field' ],
            };
        } )
    )( function ( props ) {
        return el( Text, {
            label: 'Meta Block Field',
            value: props.metaFieldValue,
            onChange: function ( content ) {
                props.setMetaFieldValue( 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 )
                )
            );
        },
    } );
} )( window.wp );

Finally, collect the meta field name (sidebar_plugin_meta_block_field) from the withSelect and withDispatch methods in one place to make future changes easy. You may take use of the fact that the initial methods withSelect and withDispatch can accept the props of the UI component they encapsulate as a second parameter. Consider the following scenario:

// ...
var MetaBlockFieldWithData = withSelect( function ( select, props ) {
    console.log( props.metaFieldName );
} )( MetaBlockField );
 
// ...
el( MetaBlockFieldWithData, {
    metaFieldName: 'sidebar_plugin_meta_block_field',
} );
// ...

Take note of how withSelect may access the metaFieldName. To take use of this, let’s update the code as follows:

( function ( wp ) {
    var registerPlugin = wp.plugins.registerPlugin;
    var PluginSidebar = wp.editPost.PluginSidebar;
    var el = wp.element.createElement;
    var Text = wp.components.TextControl;
    var withSelect = wp.data.withSelect;
    var withDispatch = wp.data.withDispatch;
    var compose = wp.compose.compose;
 
    var MetaBlockField = compose(
        withDispatch( function ( dispatch, props ) {
            return {
                setMetaFieldValue: function ( value ) {
                    dispatch( 'core/editor' ).editPost( {
                        meta: { [ props.fieldName ]: value },
                    } );
                },
            };
        } ),
        withSelect( function ( select, props ) {
            return {
                metaFieldValue: select( 'core/editor' ).getEditedPostAttribute(
                    'meta'
                )[ props.fieldName ],
            };
        } )
    )( function ( props ) {
        return el( Text, {
            label: 'Meta Block Field',
            value: props.metaFieldValue,
            onChange: function ( content ) {
                props.setMetaFieldValue( 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, {
                        fieldName: 'sidebar_plugin_meta_block_field',
                    } )
                )
            );
        },
    } );
} )( window.wp );

That is all there is to it. You now have a slimmed-down version of the original code. Add extra features to your plugin if you want to.

That’s all for this article if you have any queries please contact us through our website or email us at [email protected]

Leave a Comment