WP_REST_Terms_Controller

Core class used to manage terms associated with a taxonomy via the REST API.

Class Synopsis

php
class WP_REST_Terms_Controller extends WP_REST_Controller {
    protected $taxonomy;
    protected $meta;
    protected $sort_column;
    protected $total_terms;
    protected $allow_batch = array( 'v1' => true );
    
    public function __construct( string $taxonomy );
    public function register_routes();
    
    // Permission Checks
    public function get_items_permissions_check( $request );
    public function get_item_permissions_check( $request );
    public function create_item_permissions_check( $request );
    public function update_item_permissions_check( $request );
    public function delete_item_permissions_check( $request );
    public function check_read_terms_permission_for_post( $post, $request );
    
    // CRUD Operations
    public function get_items( $request );
    public function get_item( $request );
    public function create_item( $request );
    public function update_item( $request );
    public function delete_item( $request );
    
    // Data Preparation
    public function prepare_item_for_database( $request );
    public function prepare_item_for_response( $item, $request );
    protected function prepare_links( $term );
    
    // Schema & Parameters
    public function get_item_schema();
    public function get_collection_params();
    
    // Utilities
    protected function get_term( $id );
    protected function check_is_taxonomy_allowed( $taxonomy );
}

Endpoints

The endpoint path depends on the taxonomy’s rest_base:

TaxonomyEndpoint
category/wp/v2/categories
post_tag/wp/v2/tags
Custom/wp/v2/{rest_base}
MethodEndpointDescription
GET/wp/v2/categoriesList categories
POST/wp/v2/categoriesCreate a category
GET/wp/v2/categories/{id}Get a single category
POST/PUT/PATCH/wp/v2/categories/{id}Update a category
DELETE/wp/v2/categories/{id}Delete a category

Constructor

php
public function __construct( string $taxonomy )

Parameters:

  • $taxonomy – Taxonomy key (e.g., 'category', 'post_tag')

Behavior:

  • Sets $this->taxonomy to the provided taxonomy
  • Gets rest_base and rest_namespace from taxonomy object
  • Creates WP_REST_Term_Meta_Fields instance

Collection Parameters

ParameterTypeDefaultDescription
contextstring‘view’Scope under which request is made
pageinteger1Current page
per_pageinteger10Items per page (max 100)
searchstringSearch string
excludearray[]Exclude specific IDs
includearray[]Include specific IDs
offsetintegerOffset (non-hierarchical only)
orderstring‘asc’Sort order (asc/desc)
orderbystring‘name’Sort field
hide_emptybooleanfalseHide terms with no posts
parentintegerFilter by parent ID (hierarchical only)
postintegerFilter by post ID
slugarrayFilter by slugs

Orderby Options

  • id – Term ID
  • include – Order by include parameter
  • name – Term name
  • slug – Term slug
  • include_slugs – Order by slug include
  • term_group – Term group
  • description – Term description
  • count – Post count

Schema Properties

PropertyTypeContextRequiredDescription
idintegerview, embed, editTerm ID (readonly)
countintegerview, editPost count (readonly)
descriptionstringview, editHTML description
linkstring (uri)view, embed, editTerm archive URL (readonly)
namestringview, embed, editcreateTerm name
slugstringview, embed, editTerm slug
taxonomystringview, embed, editTaxonomy key (readonly)
parentintegerview, editParent term ID (hierarchical only)
metaobjectview, editTerm meta

Permission Checks

get_items_permissions_check()

  • Returns false if taxonomy doesn’t exist or isn’t allowed in REST
  • Requires edit_terms capability for edit context
  • If filtering by post, validates post read permission

get_item_permissions_check()

  • Validates term exists and belongs to this taxonomy
  • Requires edit_term capability for edit context

create_item_permissions_check()

  • For hierarchical taxonomies: requires edit_terms capability
  • For non-hierarchical taxonomies: requires assign_terms capability

update_item_permissions_check()

  • Requires edit_term capability

delete_item_permissions_check()

  • Requires delete_term capability

check_read_terms_permission_for_post()

php
public function check_read_terms_permission_for_post( WP_Post $post, WP_REST_Request $request ): bool

Checks if terms for a post can be read:

  • Post must be associated with this taxonomy
  • Post is publicly viewable, or
  • User can read_post

Key Methods

get_term()

php
protected function get_term( int $id ): WP_Term|WP_Error

Gets the term if:

  • ID is valid (> 0)
  • Term exists
  • Term belongs to this taxonomy
  • Taxonomy is allowed in REST

check_is_taxonomy_allowed()

php
protected function check_is_taxonomy_allowed( string $taxonomy ): bool

Checks if taxonomy has show_in_rest enabled.

prepare_item_for_database()

php
public function prepare_item_for_database( WP_REST_Request $request ): object

Maps request fields to term properties:

  • namename
  • slugslug
  • descriptiondescription
  • parentparent (validates parent term exists)

prepare_item_for_response()

php
public function prepare_item_for_response( WP_Term $item, WP_REST_Request $request ): WP_REST_Response

Prepares term data for API response including links.

RelationDescription
selfLink to this term
collectionLink to terms collection
aboutLink to taxonomy info
upLink to parent term (hierarchical, embeddable)
wp:post_typeLinks to posts with this term

Deletion Behavior

DELETE /wp/v2/categories/{id}

Required Parameter:

  • force – Must be true (terms don’t support trashing)

Response:

json
{
    "deleted": true,
    "previous": {
        "id": 123,
        "name": "Category Name",
        "slug": "category-name",
        ...
    }
}

Hierarchical vs Non-Hierarchical

The controller behavior varies based on taxonomy type:

Hierarchical (e.g., categories)

  • parent schema property included
  • parent collection parameter available
  • offset parameter not available
  • Requires edit_terms to create

Non-Hierarchical (e.g., tags)

  • No parent property
  • offset parameter available
  • Requires assign_terms to create

Usage Example

php
// List categories
$request = new WP_REST_Request( 'GET', '/wp/v2/categories' );
$request->set_param( 'per_page', 100 );
$request->set_param( 'hide_empty', false );
$request->set_param( 'orderby', 'name' );

$controller = new WP_REST_Terms_Controller( 'category' );
$response = $controller->get_items( $request );

// Create a category
$request = new WP_REST_Request( 'POST', '/wp/v2/categories' );
$request->set_param( 'name', 'New Category' );
$request->set_param( 'description', 'Category description' );
$request->set_param( 'parent', 5 ); // Parent category ID

$response = $controller->create_item( $request );

// Get terms for a specific post
$request = new WP_REST_Request( 'GET', '/wp/v2/tags' );
$request->set_param( 'post', 123 );

$controller = new WP_REST_Terms_Controller( 'post_tag' );
$response = $controller->get_items( $request );

// Update a term
$request = new WP_REST_Request( 'POST', '/wp/v2/categories/5' );
$request->set_param( 'name', 'Updated Name' );
$request->set_param( 'slug', 'updated-slug' );

$response = $controller->update_item( $request );

// Delete a term
$request = new WP_REST_Request( 'DELETE', '/wp/v2/categories/5' );
$request->set_param( 'force', true );

$response = $controller->delete_item( $request );

Custom Taxonomies

Register custom taxonomies with REST support:

php
register_taxonomy( 'genre', 'post', array(
    'public'       => true,
    'show_in_rest' => true,
    'rest_base'    => 'genres',
    'hierarchical' => true,
    'labels'       => array(
        'name' => 'Genres',
        'singular_name' => 'Genre',
    ),
));

// Endpoint automatically available at /wp/v2/genres

Term Existence Handling

When creating a term that already exists, the API returns an error with the existing term ID:

json
{
    "code": "term_exists",
    "message": "A term with the name provided already exists with this parent.",
    "data": {
        "status": 400,
        "term_id": 123
    }
}

Taxonomy Default Args

Since WordPress 6.8.0, taxonomies can define default query arguments that are respected:

php
register_taxonomy( 'custom_tax', 'post', array(
    'show_in_rest' => true,
    'args'         => array(
        'orderby' => 'term_order',
    ),
));

Source

wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php

Since

WordPress 4.7.0

Changelog

VersionDescription
4.7.0Introduced
5.0.0Added rest_after_insert_{$taxonomy} action
5.9.0Added batching support
6.0.3Added check_read_terms_permission_for_post()
6.8.0Respects taxonomy default query arguments