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/terms/category
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/terms/category/?search=SLUG
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 wp/v2
.
New argument “per_page” and “filter[posts_per_page]” becomes a little buggy
WP API v2 uses a new argument “per_page
” in posts
route and set it to 10 by default. We can still use filter[posts_per_page]
to change the value of posts_per_page
in 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 posts_per_page
to -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 sanitize_callback
function absint
will turn any negative value to positive.
Luckily we can solve this by simply setting filter[posts_per_page]
to -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 functions.php
:
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 title.rendered
, guid.rendered
, content.rendered
and excerpt.rendered
. And if you’re authenticated, you can also access their raw values with title.raw
, content.raw
etc.
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 “is_image
” property.
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 true
or false
, I have to keep the is_image
property stay in the JSON response, rather than using the newly added media_type
.
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:
wp-json/taxonomies/category/terms
But in WP API v2, the route becomes:
wp-json/wp/v2/terms/category
wp-json/wp/v2/categories
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:
- per_page
- page
- search
- order
- orderby
- parent
I’m glad at least it takes search
parameter so I can still filter the terms by slug with wp-json/wp/v2/terms/category/?search=SLUG
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.
The final project files can be downloaded from the project GitHub repo. Just installing it like any WordPress theme, only you need the latest WP API plugin to get it work.
Talk soon!
Leave a Reply