In order to access posts by a taxonomy query via the v2 WP REST API, you’ll need to do a little set-up first. Let’s say we’re starting a beer blog, and we’re attaching two custom taxonomies to our posts: “styles” and “breweries”.

Creating the Taxonomies

When you register the taxonomy using register_taxonomy, you have to make sure you set it to be available via the API. To do this, make sure you have 'show_in_rest' => true to make it accessible in the API and provide thename you want to access it with in the URL with 'rest_base' => 'beers'. Here’s sample code for registering our taxonomies called “styles” and “breweries” that’s accessible via the API:


register_taxonomy(
    'styles',
    [ 'posts' ],
    [
        'labels' => [
            'name'              => 'Styles',
            'singular_name'     => 'Style',
        ],
        'show_in_rest' => true,
        'rest_base' => 'styles'
    ]
);

register_taxonomy(
    'breweries',
    [ 'posts' ],
    [
        'labels' => [
            'name'              => 'Breweries',
            'singular_name'     => 'Brewery',
        ],
        'show_in_rest' => true,
        'rest_base' => 'breweries'
    ]
);

Now you can find all terms in the Breweries taxonomy with /wp-json/wp/v2/breweries and all the Styles with /wp-json/wp/v2/styles

WP REST API Taxonomy Query

In order to get posts attached to a specific beer style in the styles taxonomy, you can query it by style term ID in the URL by appending ?style=[term_id].

For example, let’s say IPAs have a term_id of 25. To find all posts with the term IPA, you can do: /wp-json/wp/v2/posts/?styles=25

For multiple terms, add more comma separated IDs, like: /wp-json/wp/v2/posts/?styles=25,26,27

This is equivalent to the WP_Query:


$args = [
    'post_type' => 'post',
    'tax_query' => [
        'relation' => 'AND',
        [
            'taxonomy'         => 'styles',
            'field'            => 'term_id',
            'terms'            => [25,26,27],
            'include_children' => false
        ]
    ]
];
$query = new WP_Query($args);

Note, this will not find all posts that include ALL of the styles (25, 26, and 27) but find posts that have at least one of the terms (25, 26, or 27).

Multiple Taxonomy Queries

If we want to find posts by both beer style and brewery, we simply add more parameters to the URL. If we want all posts with the term IPAs (term_id 25) from Boulevard Brewery (term_id 33), we’d do: /wp-json/wp/v2/posts/?styles=25&breweries=33

This is the WP_Query equivalent of:


$args = [
    'post_type' => 'post',
    'tax_query' => [
        'relation' => 'AND',
        [
            'taxonomy'         => 'styles',
            'field'            => 'term_id',
            'terms'            => [25],
            'include_children' => false
        ],
        [
            'taxonomy'         => 'breweries',
            'field'            => 'term_id',
            'terms'            => [33],
            'include_children' => false
        ]
    ]
];
$query = new WP_Query($args);

Complexity Tradeoff for Simple URLs

Because the structure is so simple, ?[rest_base]=[comma_separated_term_ids], it doesn’t allow you to have all the power of WP_Query(). From looking at the WP core code, it looks like the following are NOT supported out of the box:

  • Relationship "OR" queries
  • Querying by slug instead of term_id
  • Setting include_children to true.
  • Using the operator argument to set if you want it to find posts that are in all the terms you passed (using operator=>'AND') or finding posts that are NOT IN the term(s) you passed.

As of this writing in WordPress v4.9.4, to do any of those more complicated queries, you’d have to add custom filters to the API to make them accessible.