If you have some experience with Gutenberg development, It’s easy enough to create a simple control that lets a user select one or more options, like this:
<RadioControl
label="Align"
help="The type of the current user"
selected={ postMeta._my_selection }
options={ [
{ label: 'Left', value: 'left' },
{ label: 'Center', value: 'center' },
{ label: 'Right', value: 'right' },
] }
onChange={ ( value ) => setPostMeta( { _my_selection: value } ) }
/>
In this example we save the selected option to and load it from post meta. We use withSelect
and withDispatch
for this:
withSelect( ( select ) => {
return {
postMeta: select( 'core/editor' ).getEditedPostAttribute( 'meta' ),
};
} ),
withDispatch( ( dispatch ) => {
return {
setPostMeta( newMeta ) {
dispatch( 'core/editor' ).editPost( { meta: newMeta } );
}
};
} )
and we also need to register the meta fields in PHP with register_post_meta
.
If you want to learn more about this part, I recommend you to check out this tutorial.
Load options from the wp.data store
But what if you need to to get the possible options from a database? For example, you want to create a select field that allows your user to pick a related post type (for whatever reason)?
While slightly more tricky, it’s still easy enough to achieve by getting the required info from wp.data
:
Add this to your main JS function:
<RadioControl
label="Align"
help="The type of the current user"
selected={ postMeta._my_selection }
options={ options={ ( postTypes ?? []).map( pt => (
{ label: pt.name, value: pt.slug }
) ) } }
onChange={ ( value ) => setPostMeta( { _my_selection: value } ) }
/>
Add this to your withSelect
:
postTypes: select('core').getPostTypes()
Don’t forget to add postTypes
to your main function parameters:
const My_Main_Function = ( { postType, postMeta, setPostMeta, postTypes } ) => {
Load options from PHP array
All well and good, but what if you have some kind of dataset that you can access only via PHP?
For example, an array like this:
<?php
$my_options = [
['label' => 'Option one', 'value' => 'o1'],
['label' => 'Option two', 'value' => 'o2'],
['label' => 'Option three', 'value' => 'o3'],
];
If we want to show these options in the block editor, we can create our own custom REST endpoint first:
<?php
add_action('rest_api_init', function() {
register_rest_route('xyz/v1', '/my-options', [
'method' => 'GET',
'callback' => function(){
$my_options = [
['label' => 'Option one', 'value' => 'o1'],
['label' => 'Option two', 'value' => 'o2'],
['label' => 'Option three', 'value' => 'o3'],
];
return rest_ensure_response($my_options);
},
'permission_callback' => function() {
return current_user_can( 'edit_posts' );
},
]);
});
Then on the javascript side, we can add this rest route to the wp.data store, like so:
dispatch( 'core' ).addEntities( [
{
name: 'my-options', // route name
kind: 'xyz/v1', // namespace
baseURL: '/xyz/v1/my-options', // API path without /wp-json
}
]);
Now we can add this to the object that withSelect
returns:
myOptions: select( 'core' ).getEntityRecords( 'xyz/v1', 'my-options' )
And after adding myOptions
to the main function parameters, we can simply do:
<RadioControl
label="My options"
selected={ postMeta._my_selected_option }
options={ options={ ( myOptions ?? []).map( o => (
{ label: o.label, value: o.value }
) ) } }
onChange={ ( value ) => setPostMeta( { _my_selected_option: value } ) }
/>
Note that you will also need to register _my_selected_option
as post meta to remember which option was actually selected.
Instead of a RadioControl, you could use a SelectControl or CheckboxControl.