Update: For more information, you can download our free ebook, The Ultimate Guide to the WordPress REST API.
Over the last few months I’ve provided a series of tutorials on how to use the WordPress REST API. I’ve covered topics on how to retrieve and create posts, and even how to work with post meta data and how to create a front-end post editor. And, because the term “post” is so broad, it applies to virtually any post type, and therefore covers a large swath of the REST APIs capabilities..
The two major data types I haven’t yet addressed are 1) taxonomies and 2) users. Today, I’m going to tackle taxonomies.
Almost everyone is familiar with the three built-in public taxonomies: category, tag, and post_format. WordPress also has a few internal private taxonomies, such as nav_menus, which is used to store menu settings. Since the REST API does not currently support private taxonomies, we will ignore them for now. Of course, it is important to remember that WordPress allows you to add custom taxonomies, which function like categories and tags.
In this tutorial, I’ll show you how to get a list of taxonomies, the list of terms in a taxonomy, and the list of posts associated with a term — all using PHP. I’ll also be showing you how to query for posts with a given taxonomy term. All of that is helpful knowledge but is of limited use, as WordPress already does that for you. Though if you needed to pull taxonomy data from a remote site, it would be very helpful.
To put it all together in a practical example — and to bring a little jQuery into the discussion — I will demonstrate how to use the REST API to show a list of posts in a specific tag when a user clicks on a tag link.
Understanding the Basics
For this post, I’m going to assume that you understand the basics of working with posts via the WordPress REST API, and that you already have the plugin installed. If you haven’t worked with the REST API, however, I recommend that you read my introductory post on the subject.
In addition, all of the code that I’m showing here is designed to work with tags and categories, since those are taxonomies you have on every site. All of it can be easily abstracted to work with any custom taxonomy. If you’re unfamiliar with custom taxonomies, but want to learn more, I recommend you read my article in Smashing Magazine on WordPress custom taxonomies.
Working with Taxonomies Directly
In WordPress, there are two common ways we work with taxonomies. The first is by listing terms in a taxonomy — for example, the category archives on our site lists all posts in a specific category. The second way is by listing the taxonomy terms associated with a post — for example, listing all of the tags used on the current post.
A less common use is to list all of the taxonomies, or to list all terms in a taxonomy, though the latter is often done by widgets — for example the tag cloud widget, or category list widget. We can do similar things with the WordPress REST API.
The REST API gives us a taxonomies route, with many helpful endpoints for listing taxonomies, information about a taxonomy, or terms in a taxonomy. Listing posts with a specific term is handled via the posts route, which I will discuss in the next section.
The basic endpoints for the taxonomies route are as follows:
- <json-url>/taxonomies: A list of all public taxonomies, which is useful for checking if a taxonomy is registered.
- <json-url>/taxonomies/<taxonomy-slug>: Information about a taxonomy, which is useful for finding information about a taxonomy, such as its labels.
- <json-url>/taxonomies/<taxonomy-slug>/terms: All terms in the taxonomy, which is useful for finding the ID of a term to be used in the next endpoint in this list.
- <json-url>/taxonomies/<taxonomy-slug>/terms/<id>: Get information about a specific term.
In the above examples, you would use “category” in place of <taxonomy-slug>, or post_tag for tags. For a custom taxonomy, use the name you used to register it.
If we wanted to make a list of terms in a taxonomy, in this case categories, we could do it like this:
$response = wp_remote_get( json_url( 'taxonomies/category/terms' ) ); if ( ! is_wp_error( $response ) ) { $terms = json_decode( wp_remote_retrieve_body( $response ) ); $term_list = array(); foreach( $terms as $term ) { $term_list[] = sprintf( '<li><a href="%1s">%2s</a></li>', esc_url( $term->link ),$term->name ); } if ( ! empty( $term_list ) ) { echo sprintf( '<ul>%1s</ul>', implode( $term_list ) ); } }
If you’ve been reading my tutorials, this should be fairly self explanatory. We use wp_remote_get() to make the request, check if it’s an error, and (if there’s no error) convert the body of the response to a PHP object and then loop through it.
Of course we can do the same thing, but more efficiently, by using get_terms() or a similar function. What I demonstrated above would be useful in an AJAX callback, or when getting terms from a taxonomy on another site in a WordPress multisite installation.
To get terms from another site, we would replace the function json_url() with get_json_url(). These two function work the same way, except get_json_url() takes the site ID as its first argument. Here’s the modified code, which will list the categories of every site in a multisite installation:
$sites = wp_get_sites(); $the_list = array(); foreach( $sites as $site ) { $response = wp_remote_get( get_json_url( $site->site_id, 'taxonomies/category/terms' ) ); if ( ! is_wp_error( $response ) ) { $terms = json_decode( wp_remote_retrieve_body( $response ) ); $term_list = array(); foreach( $terms as $term ) { $term_list[] = sprintf( '<li><a href="%1s">%2s</a></li>', esc_url( $term->link ),$term->name ); } if ( ! empty( $term_list ) ) { $site_info = get_blog_details( $site->site_id ); $term_list = sprintf( '<ul>%1s</ul>', implode( $term_list ) ); $the_list[] = sprintf( '<li><a href="%1s">%2s</a><ul>%3s</ul>', $site_info->siteurl, $site_info->blogname, $term_list ); } } } if ( ! empty( $the_list ) ) { echo sprintf( '<ul>%1s</ul>', implode( $the_list ) ); }
This code is much simpler than working with switch_to_blog to run multiple WP_Query objects. I know because, for whatever reason, the first plugin I tried to write did something similar and it was just way too complex.
Do keep in mind, however, that this will only work in multisite. Also, while it may appear quite simple, if you have a lot of sites, it will involve several HTTP requests and lots of database queries. I strongly advise caching the results by using the technique I showed in my article on using the WP-TLC-Transients library or some other caching method.
Getting Posts by Taxonomy
So far, we’ve worked with the taxonomy endpoints. The WordPress REST API, only shows you information about the taxonomy and its terms, not the posts in the terms when working with those endpoints. Post information is retrieved via the post endpoints, which we can use to get posts with a specific taxonomy term.
For example, to get posts with the tag “stargate” we would use the filter tag in our URL string, like this:
json_url( 'posts?filter[tag]=stargate' );
To get posts in the category “sci-fi” we would use the filter category_name, like this:
json_url( 'posts?filter[category_name]=stargate' );
We can combine queries for posts in multiple taxonomies to the URL string for posts with the tag “sith,” like this:
json_url( 'posts?filter[category_name]=force_users&filter[tag]=sith' );
At this point you might be looking to run a complex tax_query, like you can do using WP_Query. It isn’t currently possible, but keep a look out for a future post where I’ll demonstrate how to write a custom route and endpoints for it.
With these URL strings, you could use the same basic pattern as seen above to get the posts via the WordPress HTTP API. But, to show you something different, let’s look at how you could get all posts in a specific tag by using jQuery to make an AJAX request.
The code is very similar to the code that I showed in my post on processing forms with the REST API. Be sure, when enqueuing this code, to localize the vale of json_url() using wp_localize_script(), and place that into the variable rootURL so it can be used to build the URL string for the request. Also, this code uses the standard markup for tags and posts, and is tested using the _s starter theme. You will need to make some adjustments if your theme uses another way of marking a tag.
Here’s the complete code, which I’ll walk you through below:
jQuery(document).ready(function($) { $( '[rel="tag"]' ).click( function( event ) { event.preventDefault(); var href = this.href; if (href.substr(-1) == '/') { href = href.substr( 0, href.length - 1 ); } var slug = href.split('/').pop(); $.ajax({ type: 'GET', cache: true, url: rootURL + '/posts?filter[tag]=' + slug, dataType: 'json', success: function(posts) { var html = '<ul>'; $.each( posts, function(index, post ) { html += '<li><a href="' + post.link + '">' + post.title + '</a></li>'; }); html += '</ul>'; $('article').append( html); } }); }); });
What this does is, whenever someone clicks on a tag link, instead of taking them to that archive, it gets the list of posts with that tag and lists them below the post. You will probably want to put it in a more user-friendly location on your page or in a tooltip or dialog. Whatever you do, the basic concept remains the same.
This code happens inside of a function that runs whenever a tag is clicked. The first part works to get the tag’s slug by chopping down the link’s target to its last segment. Obviously, this only works if you are using standard permalinks. Once that’s done, the slug is used to create a URL string to make an AJAX request. If that request is successful, a simple jQuery each loop is used to build the list, which is then appended to the article.
Again, it’s pretty simple, though you’ll need to do a little tweaking to make it compatible with your theme.
Use Taxonomies Better
Today, on most WordPress sites, taxonomy archives and taxonomy widgets are our main way of interacting with taxonomies. This means that getting to a related post via that taxonomy involves clicking a link, loading a new page, clicking another link, and then loading another page. That’s a bad user experience that is just asking for the end user to abandon the site before they get to the next post.
Using the WordPress REST API, we can make the interaction with taxonomies on our sites more interactive and get users directly to the content they need!
6 Comments