Creating Select Dropdown with Posts or Terms

Basically in this tutorial I am going to show you how you can create a simple <SelectControl> with posts in Gutenberg like this:

SelectControl with dynamically requested pages

Then we are going to go a little bit further and create a more interesting multi select control <FormTokenField> with post tags.

FormTokenField with dynamically requested tags

Both posts and tags we are going to request dynamically with useSelect and getEntityRecords(). Let’s dive into it right now!

First things first let’s create a custom panel <PluginDocumentSettingPanel> where actually we are going to display the fields. If you don’t know how to do that, please check this tutorial.

Create SelectControl with Dynamically Queried Posts

Using getEntityRecords()

It is actually just a post query but there are a couple things worth keeping in mind. First of all we will have to use useSelect from wp.data.

const { useSelect } = wp.data;

Then, you can query the posts using getEntityRecords() the way like this:

const pagesPosts = useSelect( ( select ) => {
	return select( 'core' ).getEntityRecords( 'postType', 'page' )
} )

As you can see I used postType argument to query pages, but it is also possible to provide more query arguments like this:

const pagesPosts = useSelect( ( select ) => {
	return select( 'core' ).getEntityRecords( 'postType', 'page', { status : 'publish' } );
} )
ArgumentDescription
per_pagehow much posts to get, defaults 10, does not depend on the number of posts set in Settings > Reading. Set to -1 to display all the available posts.
excludeAllows to exclude a post with a certain ID, or multiple posts passed in an array, example 'exclude' : [ 1, 10 ]. Use select('core/editor').getCurrentPostId() to exclude current post ID.
parent_excludeSimilar to exclude, but it excludes only all the direct children of a selected post. Accepts multiple values in an array.
orderbyHow to order posts. Accepts: id, title, date, menu_order, author values. Defaults to date.
orderSort ascending (asc) or descending (desc)? Default to desc
statusPost status, accepts values: publish, draft, future, pending, private, multiple values can be presented as an array or separated by commas.
categoriesCategory ID or an array of IDs
tagsTag ID or an array of IDs.
searchYou can also search for specific posts, uses the default WordPress search algorithm.

Once you query the posts, you will have an array of objects which you can easily explore with console.log( pagesPosts ).

You can easily get an array of IDs for example with map().

let pageIds = pagesPosts.map( page => page.id )

But before using map() method I recommend to check if pagesPosts is not null.

Displaying Posts in SelectControl

Please keep in mind that the code below should be used inside registerPlugin() function either in a panel or a sidebar.

// querying pages
const { pages } = useSelect( ( select ) => {
	const { getEntityRecords } = select( 'core' );

	// Query args
	const query = {
		status: 'publish',
		per_page: 2
	}

	return {
		pages: getEntityRecords( 'postType', 'page', query ),
	}
} )

// populate options for <SelectControl>
let options = [];
if( pages ) {
	options.push( { value: 0, label: 'Select a page' } )
	pages.forEach( ( page ) => {
		options.push( { value : page.id, label : page.title.rendered } )
	})
} else {
	options.push( { value: 0, label: 'Loading...' } )
}

// display select dropdown
return (
	<PluginDocumentSettingPanel
		name="custom-panel"
		title="Misha's custom panel"
		className="some-css-class"
	>
		<SelectControl label="Select a post" options={ options } />
	</PluginDocumentSettingPanel>
)

Here we are:

SelectControl with dynamically requested pages

Create Multiselect with Dynamically Queried Terms

In order to query post tags we are also going to use getEntityRecords() but in this particular case it is going to look like this:

const tags = useSelect( ( select ) => {
    return select( 'core' ).getEntityRecords( 'taxonomy', 'post_tag' );
});

In order to create a multi-select dropdown we have to use <FormTokenField>. Probably it will be useful if I leave a link to official docs of a component.

Do not forget to import useState from wp.element and FormTokenField from wp.components.

const [ selectedTags, setSelectedTags ] = useState( [] )

const { tags } = useSelect( ( select ) => {
	const { getEntityRecords } = select( 'core' )

	return {
		tags: getEntityRecords( 'taxonomy', 'post_tag' ),
	}
} )
	
let options = []
if( tags ) {
	options = tags.map( value => value.name )
}

// display select dropdown
return (
	<PluginDocumentSettingPanel
		name="custom-panel"
		title="Misha's custom panel"
		className="some-css-class"
	>
		<FormTokenField
			value={ selectedTags }
			suggestions={ options }
			onChange={ ( tokens ) => setSelectedTags( tokens ) }
		/>
	</PluginDocumentSettingPanel>
)
FormTokenField with dynamically requested tags
Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X