Building a terms list block for WordPress

I wrote a terms list block for WordPress. Here’s what I learned.

Building a terms list block for WordPress

WordPress has evolved so much over the years. The new editor runs using blocks, which are pieces of JavaScript, CSS, and PHP/HTML combined into a single unit to add a feature to a page or site template. I enjoy learning by doing, and found an opportunity to create a new WordPress block to brush up on my block building skills.

Over the holiday season, I took some time to migrate an old site I ran from a Postnuke database into WordPress. This included migrating a photo gallery into a custom post type. I found myself needing to list out the sub-terms for a taxonomy I created for photo albums, starting with a list of the top-level albums, and then showing a list of the sub-albums when viewing an album archive page. After looking around for an appropriate block, I didn’t find one, so I set out to build my own. Here are some observations from lessons I learned along the way.

Here’s the “Terms List Block” on GitHub. Patches and feedback welcome.

Finding a similar block

When looking for something similar to meet my needs, I looked at the “Categories List” block. Surely the block supports selecting a custom taxonomy? It doesn’t. This block is elegant and does one thing really well- show a list of categories from the “category” taxonomy.

I found several existing blocks to show posts from a taxonomy, though none which allowed me to list terms of a given taxonomy. Even if such a block already exists, I saw this opportunity to build my own as a learning exercise.

How to approach this new block

I could have copied the “Categories List” block and changed the taxonomy to my own. That would be a simple solution to meet the needs for my pet project. However, this wouldn’t offer the flexibility to change taxonomy.

I opted to use the create-block NPM package, and to add my code to the generated plugin, with the “Category List” block as inspiration and as a reference. The “Category List” block is bundled into WordPress, so doesn’t have all of the build tools, etc, contained within itself (these tools are bundled with WordPress itself).

create-block is a fantastic package. It creates all the necessary scaffolding for your block, and for the plugin which will register the block. I found this a huge time-saver, and a way to benefit from a “thousand hour head start”. There are several packages available to WordPress developers which enable this major head start. It has never been easier to start building with WordPress.

Building a custom control to select taxonomies

The area I most wrestled with is how to build a select box for custom taxonomies. In hindsight, this was actually really straightforward. It must’ve been “holiday brain” or something else which got in the way.

Nevertheless, what I was attempting to do was to pull an array of taxonomy slugs and names, and to send that array to the options parameter of a SelectControl. I ended up doing this, though wrapping the logic inside a new TaxonomyControl. This approach made it easier to contain the logic to get the taxonomies list in the same place as the SelectControl without polluting the return markup for my block settings.

Here’s what I ended up with as the TaxonomyControl:

/**
 * Creates a control object for selecting a taxonomy.
 * @return {Object[]} A formatted SelectControl.
 */
const TaxonomySelectControl = withSelect((select) => {
const taxonomies = select('core').getTaxonomies();

return {
	taxonomies,
};
})(({ taxonomies, onChange, value }) => {
const taxonomyOptions = taxonomies.map((taxonomy) => ({
	label: taxonomy.labels.singular_name + ' (' + taxonomy.slug + ')',
	value: taxonomy.slug,
}));

return (
	<SelectControl
		__nextHasNoMarginBottom
		label={__('Select Taxonomy')}
		options={taxonomyOptions}
		value={value}
		onChange={onChange}
	/>
);
});

Note that I added the taxonomy slug in parenthesis next to the name, in case several plugins register taxonomies with the same labels. In my case, I registered photo-category with the label Categories.

Of course, import withSelect from @wordpress/data at the top of your edit.js file.

import { withSelect } from '@wordpress/data';

To output the TaxonomyControl in my block settings, I used the following command:

<TaxonomySelectControl
	value={ selectedTaxonomy }
	onChange={ toggleAttribute( 'selectedTaxonomy' ) }
/>
<p>
	{ __(
		'The selected taxonomy will be overridden when viewing a term archive or a single post.'
	) }
</p>

selectedTaxonomy here is a block attribute to store the selected taxonomy. toggleAttribute is a method in the block to switch an attribute to a new value.

Lessons learned

One block, one purpose

On the approach, I could have made two blocks- one for a categories list, and the other similar to the “Categories” block to show terms from a selected taxonomy as if on a single entry page. Currently, the block I shipped does both use cases in a single block. I should expand this to a second block in future, to have each block perform in a single context.

Static vs Dynamic blocks

For this project, I opted for a dynamic block. The block can later benefit from server-side rendering, and the frontend rendering itself is done in PHP, which I’m more comfortable working with. I wanted to see immediate progress, so I took the path of least resistance to see results, which then enabled me to dive in deeper and explore the block settings, and the rest of the project.

Get familiar with the WordPress data model

Through my journey I learned that I need to be more familiar with WordPress’ data model as it pertains to blocks. I’m very familiar with how data is structured, though wasn’t familiar with how to pull the specific type of data I wanted (a list of registered taxonomies) from WordPress’ data object, within JavaScript.

In addition to the data model, it’s important to have a concept of what properties are provided. One such example is isResolving, which is used to indicate whether or not a block is done resolving it’s operation. This is used when switching taxonomies in my block, as an example. While the terms list is being loaded, isResolving remains true, and is false when the terms list is available.

This is not only PHP. Think different

Switching between JavaScript and PHP contexts has a mental switching cost. The structures and approaches one would take in PHP are fundamentally different in JavaScript. One example is working with arrays and objects. In PHP, I would be inclined to pull data from an array, loop through that array, and assign <option> tags to a select box in that loop. In Javascript, using the SelectControl in WordPress, it’s a matter of assigning an array to the options parameter for the control. One can also loop, though that’s unnecessary here. This is a primitive example, though is a good reminder that PHP and JavaScript can be treated differently by engineers. The same approach could also be taken in PHP in this example, for what it’s worth.

Exploring block variations

WordPress’ documentation on blocks is excellent. I wanted to dive in and create, so I opted for creating a new block. As a next step, I’ll likely explore if a block variation will achieve a similar result to what I desire from this block. This would (in theory) require less code to achieve a similar result, and ensure this block keeps up with developments in the main “Category List” block.

Onwards to more blocks

I learned many lessons while building this block. I learned more about how to interact with the WordPress data model in JavaScript, how to build a custom control for showing my taxonomy selector, and how to structure a block as a plugin using the create-block package. While I’m sure there are several lessons here which seem obvious to anyone building blocks every day, I don’t build blocks daily so had some catching up to do in order to learn more about the data model, etc. Blocks can seem intimidating at first, though WordPress and it’s provided packages, as always, make this really easy to create and to learn from.

Being open source, all WordPress code is available to view and learn from. Being able to study, reference, and understand the underlying code of an existing block is an excellent companion to the documentation provided when learning how to create blocks.

I’m excited to build more blocks for WordPress, and learned a lot along the way to building the Terms List Block. Needless to say, I find it now that much easier to build blocks into any plugin I build in the future.

Enjoyed this article?

Get more insights on technical leadership, teams, and software development delivered to your inbox.