The Block API of Gutenberg supports post meta as a attribute source. But what if you want to use post meta in say a plugin sidebar?
With the help of the @wordpress/data package and so called “higher-order components” it’s as easy as for blocks. 🙌
First we import all the required dependencies. This assumes that you’re using webpack and define your externals like this. If you’re looking for an ES5 example take a look at the block editor handbook.
/**
* WordPress dependencies
*/
import {
withSelect,
withDispatch,
} from '@wordpress/data';
import {
PluginSidebar,
PluginSidebarMoreMenuItem,
} from '@wordpress/edit-post';
import {
PanelColor,
} from '@wordpress/editor';
import {
Component,
Fragment,
compose,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
To render the UI we extend Component
and implement the render()
method. For this example I used a PanelColor
component which allows a user to select a color. We’ll save the hex value in the post meta my_color_one
:
/**
* Custom component with a simple color panel.
*/
class MyPlugin extends Component {
render() {
// Nested object destructuring.
const {
meta: {
my_color_one: colorOne,
} = {},
updateMeta,
} = this.props;
return (
<Fragment>
<PluginSidebarMoreMenuItem
name="my-plugin-sidebar"
type="sidebar"
target="my-plugin-sidebar"
>
{ __( 'Color it!', 'my-plugin' ) }
</PluginSidebarMoreMenuItem>
<PluginSidebar
name="my-plugin-sidebar"
title={ __( 'Color it!', 'my-plugin' ) }
>
<PanelColor
colorValue={ colorOne}
initialOpen={ false }
title={ __( 'Color 1', 'my-plugin' ) }
onChange={ ( value ) => {
// value is undefined if color is cleared.
updateMeta( { my_color_one: value || '' } );
} }
/>
</PluginSidebar>
</Fragment>
);
}
}
(Please ignore the incorrect syntax highlighting.)
Now we need a higher-order component which is used to fetch the data, in this case our post meta.
// Fetch the post meta.
const applyWithSelect = withSelect( ( select ) => {
const { getEditedPostAttribute } = select( 'core/editor' );
return {
meta: getEditedPostAttribute( 'meta' ),
};
} );
The second higher-order component is used to update the data.
// Provide method to update post meta.
const applyWithDispatch = withDispatch( ( dispatch, { meta } ) => {
const { editPost } = dispatch( 'core/editor' );
return {
updateMeta( newMeta ) {
editPost( { meta: { ...meta, ...newMeta } } ); // Important: Old and new meta need to be merged in a non-mutating way!
},
};
} );
Since we now have two higher-order components we have to combine them with compose
:
// Combine the higher-order components.
const render = compose( [
applyWithSelect,
applyWithDispatch
] )( MyPlugin );
Having a fully renderable component we can finally register our custom plugin:
registerPlugin( 'my-plugin', {
icon: 'art',
render,
} );
And that’s it! 🚢
PS: Make sure to register the post meta properly with 'show_in_rest' => true
.
Photo by Kimberly Farmer.