Note added 2015/12/16: Now this post is updated to be compatible with WP API v2 Beta 9. Note added 15/12/13: With the BREAKING CHANGES in WP API v2 Beta 9, the theme is now broken even if you follow this tutorial. I'll manage to update the post soon so don't get too excited about the plugin updates.
Today in this post, I’ll be showing you how to upgrade the AngularJS WordPress theme that we have been working on for a very long time, to work with the latest WP API v2 (beta 4 at the time of this writing).
To be honest I didn’t expect the WP API v2 would be so much different from the version 1. When I talked about upgrading the theme in some comments of my tutorials, I thought it just about updating the routes and that’s all. It turned out I was wrong and the mistakes I’ve made are pretty worthy of documenting. So here we go.
You can download a copy of my AngularJS WordPress theme from the GitHub repo but it’s ok if you actually aren’t that into AngularJS – you’re just looking forward to knowing what’re the differences between WP API version 1 and 2. You can definitely learn something from this post without knowing what my AngularJS app is about, since I won’t cover too much about AngularJS today.
Changing the routes for all the AngularJS $http services
In our AngularJS WordPress theme, we use the
$http service to make HTTP requests to get the data we need. We ask WP API to send us the latest posts on homepage, all categories to display a category menu, a single post content, etc.
Here’s a full list of all WP API v1 routes we’ve used in our AngularJS app:
wp-json/taxonomies/category/terms– to get all categories.
wp-json/posts?page=PAGE– to get posts from a certain page.
wp-json/posts/?filter[s]=KEYWORD&filter[posts_per_page]=-1– to get all search results.
wp-json/posts/?filter[category_name]=CATEGORY_NAME– to get posts in a certain category.
wp-json/media?filter[post_parent]=POST_ID&filter[posts_per_page]=-1– to get all media from a certain post.
wp-json/taxonomies/category/terms/?filter[slug]=SLUG– to get a certain category by slug.
To work with WP API v2, we need to change the routes to:
wp-json/wp/v2/categories– to get all categories.
wp-json/wp/v2/posts/?page=PAGE&filter[posts_per_page]=1– to get posts from a certain page.
wp-json/wp/v2/posts/?filter[s]=KEYWORD&filter[posts_per_page]=-1– to get all search results.
wp-json/wp/v2/posts/?filter[category_name]=CATEGORY_NAME&filter[posts_per_page]=1– to get posts in a certain category.
wp-json/wp/v2/media?filter[post_parent]=POST_ID&filter[posts_per_page]=-1– to get all media from a certain post.
wp-json/wp/v2/categories/?search=SLUG– to get a certain category by slug.
From the list above, the most significant change that most people can spot right away is the namespace changed. Please note
wp-json is just the base path for the API itself, it is not part of a route. (I still add it to my tutorials in case you forget about it.) Now all built-in WordPress core routes have moved to the
wp/v2 namespace, so the routes all start with
New argument “per_page” and “filter[posts_per_page]” becomes a little buggy
WP API v2 uses a new argument “
posts route and set it to 10 by default. We can still use
filter[posts_per_page] to change the value of
WP_Query, but if we do so, the value of
X-WP-TotalPages in headers won’t get updated (because of how the value gets calculated) and our AngularJs pagination directive will be broken.
So when using
filter[posts_per_page] to set a max post count for an archive page, we need to hook to ‘
rest_post_query‘ to fix the pagination:
We’ll talk more about the function later.
“per_page” can’t be a negative integer so I stick with “filter[posts_per_page]”
A WordPress developer set
-1 to get all posts from a query all the time (though it’s not the best practice). But now we have WP API v2, and to my surprise we can’t do the same thing with the new argument
per_page, because the
absint will turn any negative value to positive.
Luckily we can solve this by simply setting
-1 and get the results we expect.
The not so simple part is, if we force
per_page to a negative integer, the value of
X-WP-TotalPages in headers will be affected and turned to a negative integer too, which doesn’t make any sense at all.
That’s why in the gist above, at line 8 to 14, we need to set the
per_page argument to all post count (
$query_result->found_posts) instead of
-1. Now the
X-WP-TotalPages in headers will return the correct value “
1” when we ask for all posts in a certain query without pagination.
We can’t access the thumbnail url directly in the post JSON response
Back to WP API version 1, the “featured_image” property holds a huge object with very comprehensive information about that image. Now the same property name “featured_image” holds an integer and we can only access the attachment id. Since we display the thumbnail at the list page (
main.html), we need to update our code accordingly.
I’ve talked about this issue in my previous article “Adding Fields To The JSON Response Of The WP REST API” (scenario two), so we can just copy the gist and paste it to our
By hooking to
rest_prepare_post, we add an extra field “
featured_image_thumbnail_url” in our JSON response so we can access it without making extra API calls. After modifying the JSON response, we need to update the
main.html in our theme (at line 6-7, the thumbnail url changed):
“title”, “guid”, “content” and “excerpt” field in post response now return an object
Now when we need to access these values, we need to access their “rendered” property like
excerpt.rendered. And if you’re authenticated, you can also access their raw values with
No “is_image” property in media response but a new “media_type” property added
In this tutorial “Adding Slick Carousel To Your AngularJS WordPress Theme” I showed you how to grab all image attachments from a post to create a Slick carousel. The key point is we can tell if an attachment is an image or not by the “
Unfortunately this property is now gone with WP API v1. I figured out how to bring it back with the gist below:
You don’t really need it if you’re not working with AngularJS. I use
ng-if in my
content.html to show or hide the image div, for
ng-if only takes an
expression which needs to be evaluated to
false, I have to keep the
is_image property stay in the JSON response, rather than using the newly added
Terms route changed and a new parameter “search” introduced
The changes for terms route made me confused most at first. The format in WP API v1 makes more sense to me that it shows the right hierarchy between taxonomy and their terms. For example, we get all categories with such route:
But in WP API v2, the route becomes:
The other significant change is we can’t use the
filter parameter to filter the terms. This was introduced in 1.2.0 but not working with WP API v2 anymore.
Version 2 takes only the following parameters when getting terms:
I’m glad at least it takes
search parameter so I can still filter the terms by slug with
wp-json/wp/v2/categories/?search=SLUG. I need to do so because I set the category route in my AngularJS app to
category/:slug to get (theoretically) better SEO performance.
Final notice: modifying responses is discouraged
The last but not least notice is that modifying responses is discouraged by WP API. From the version 2 documentation, WP API team encourages us to use
register_api_field to add a duplicate field to the JSON response even if we just want to modify an existing one. And removing any field is definitely a no-no and dangerous thing you can ever do to your API response.
I definitely understand that and I’m sorry I don’t use the best practice in this tutorial. But if you only provide the API to third party applications that you know, I’ll say altering the JSON responses with filters like
rest_prepare_post is actually not that bad. Especially if you just want to alter the response for
GET endpoint in the route, but not other endpoints like POST, PUT or DELETE.
Thank you for spending time with me to learn my experience about upgrading the AngularJS theme to work with WP API v2. Any comment or tip you’d like to share is very welcome. I’m also glad to help if you have any question regrading my tutorials.