Manage Custom Taxonomy Terms with REST API

In this tutorial I would like to guide you how you can create WordPress REST API requests in order to manage custom taxonomy terms. And also I’d like to show you some interesting examples along the way.

The idea of this article actually came to my mind when I was developing an add-on for my Simple WordPress Crossposting plugin.

Include your Custom Taxonomy into REST API

That’s the most important step, nothing is going to work without it. But it is super simple, all we need to do is to use one or two parameters – show_in_rest and rest_base when registering a taxonomy with register_taxonomy() function.

	'travelguide', // it is a post typewe are adding a taxonomy to
		'show_in_rest' => true,
		'rest_base' => 'cities', // (Optional)

The interesting thing is that doing so allows not only to work with taxonomy terms in REST API, but also to add those terms to a post when creating it.

REST API endpoints

In the examples below I am about to use /wp/v2/cities endpoint, it is because I have specified it as rest_base, but if you didn’t do so, you have to use the taxonomy name, so it would be just /wp/v2/city.

Worth noting that if you’re working with WordPress default taxonomies in REST, then you have the following endpoints:

  • /wp/v2/categories – for categories,
  • /wp/v2/tags – for tags.

And not because these are their own unique endpoints, but because categories and tags are just their rest_base parameters! So, everything is super logical.

Get One or Multiple Term IDs by Slugs

Whether we about to update an existing term or to delete one – we will need to pass its term ID on a remote website, which could make the things a little bit more complicated.

How do we know the IDs? I mean we have some taxonomy terms on Site 1 and we know their IDs, right? But the IDs on Site 1 and Site 2 don’t match! What matches then? Slugs of course! So we just need to create more REST API requests in order to get all the terms with the specific slugs from Site 2 and so we will know their IDs. The good news here that we can do it in just a single request.

// we don't even need auth headers here
$res = wp_remote_get(
			'slug' => join( ',', $slugs_site_1 ),
// get results
if( 'OK' === wp_remote_retrieve_response_message( $res ) ) {

	$terms = json_decode( wp_remote_retrieve_body( $res ) );
	$terms = wp_list_pluck( $terms, 'id', 'slug' );


wp_list_pluck() is an amazing function and in the example above it allows to convert an array of WP_Term objects into Array( slug => id, slug => id, ... ) which is going to be super convenient for us, I will prove it to you in the next example.

Creating or Updating Terms

Here I decided to use an array of remote term ids we received in the previous example in order to combine both creating and updating terms into a single piece of code. So here we are just using array_key_exist() PHP function in order to check if the term with this specific slug already exists on Site 2 and guess what, its ID is also stored in $remote_terms array, thanks to wp_list_pluck() function.

if( array_key_exist( $slug, $remote_terms ) ) {
	$term_id_to_update = $remote_terms[ $slug ];
	$endpoint = "{$url}/wp/v2/cities/{$term_id_to_update}";
} else {
	$endpoint = "{$url}/wp/v2/cities";

$res = wp_remote_post(
		'headers' => array(
			'Authorization' => 'Basic ' . base64_encode( "{$login}:{$pwd}" )
		'body' => array(
			'name' => 'Kuala Lumpur',
			'slug' => 'kl',
			'parent' => 0,
			'description' => '',
			'meta' => array(),

if( 'Created' === wp_remote_retrieve_response_message( $res ) ) {
	// when a new taxonomy term is added

if( 'OK' === wp_remote_retrieve_response_message( $res ) ) {
	// when an existing taxonomy term is updated	

If case you’re wondering what are $login and $pwd variable here, then you just need to read a little bit about Application Passwords.

How update terms metadata with REST API

Providing custom fields to taxonomies is super easy:

'meta' => array(
	'key1' => 'value1',
	'key2' => 'value2',

But you need to register those keys in REST API on Site 2. Like this:

add_action( 'rest_api_init', function(){

	register_meta( 'term', 'key1', array(
		'type' => 'string',
		'single' => true,
		'show_in_rest' => true
	) );
	// and you need to do the same for key2 and all the other meta keys as well
} );

If you need more information about meta fields, there is a separate tutorial about that.

Deleting Terms

		'method' => 'DELETE',
		'headers' => array(
			'Authorization' => 'Basic ' . base64_encode( "{$login}:{$pwd}" )
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