Upgrading Your AngularJS Theme To Work With WP API V2

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!

Share the post:Tweet about this on TwitterShare on Google+0Share on Facebook0Share on LinkedIn6
I'm a senior web developer helping clients build their websites to grow businesses. Currently I'm based in Taipei, Taiwan. I write things about WordPress, AngularJS and life. Whenever you'd like to find someone to talk about these topics, just get in touch!

37 Comments

Submit a comment
  • Thanks 🙂 by default WP rest api give 10 post how can we retrieve more post than that like 20 or 30 post

    • Hi, the solution should be in this paragraph above: “New argument “per_page” and “filter[posts_per_page]” becomes a little buggy”.

  • I am integrating AngularJS and the WP API. I started with version 1.23, but because I need to get all terms for a post, and that doesn’t seem at all possible with v1, I am trying V2. Everything works fine with V1, but getting a “Dupes” error in V2. Any ideas on that?

    Do you know a way to duplicate the WP function, get_the_terms(ID) in the API, or do I have to create a custom route?

    Thanks so much for any help. I have really made use of your tutorials to find my way with this project!

    • Hey Mary, I’m not sure where the “Dupes” error comes from, maybe Tim’s comment can be of use to you?

      You can get the terms for a certain post with route like http://demo.wp-api.org/wp-json/wp/v2/posts/178/terms/category, just change the taxonomy at the end of the route.

      Glad I can help. Contact me if you need further assistance. Thanks.

  • Thanks for your help! The dupes error was because no data was being returned – I needed to toggle my permalinks, from switching to v2.

    I got A LOT working, but now I am unable to load the featured image using your function – for a custom post type. It seems to only work for regular posts. I’ve looked all over for docs on these functions (rest_prepare_post , etc). Any ideas on adapting this to work with a CPT?

    Thanks so much for your help.

    Mary

    • Hey Mary, you can use the same function but change the filter from rest_prepare_post to rest_prepare_job if the CPT is “job”. The filter is actually in this format: 'rest_prepare_' + CPT.

  • OK. I got it figured out. You have to append the function with the post type, a la “rest_prepare_portfolio’ – but it won’t work with a hyphenated post type, fyi. Seems we should be passing the post type to this function, so we’ll see if they work that out. I just changed my post type and removed the hyphen 🙁

  • Thank you so much Yoren, You did an amazing job here. Looking forward to see more posts about WordPress Rest API and Angular. Take care!

    • Hey Miguel, Thanks for your kind words. Your website looks really promising and I’m pretty sure you can target the right audience! Happy New Year!

  • Is there’s a way to automatically get the results of the next and previous posts in a specific order?

    • For a general WordPress theme you can. But with WP API, we don’t have a built-in route to do so. Need to build a custom route on our own.

  • Thank you very much for your tutorial. By following your series on AngularJS and WP-API I was able to get my self started on experimenting with AngularJS and WordPress.

    I am trying to build a site that displays a list of posts on the front end using AngularJS and WP API v2. So far I was able to display the posts (all posts, no pagination) and was able to list the categories each post is assigned to.

    Now, I want to be able to filter the posts by selecting from checkboxes. I need to be able to select one or multiple categories and show only the posts assigned to those categories that have been selected.

    What is the best way to implement this? I am thinking of implementing Masonry to display the posts as tiles and a filter would be really nice.

    By the way, since I am using a virtual host for my dev site (using angularpress.dev as domain), using fixed that nobase error.

    • Hey Aaron, Glad you have a very good idea to integrate AngularJS with WP API. You might need to create custom routes to make the multiple categories filter (tax query) work with WP API, or maybe just hook to the right filters can do the trick.

      But regarding the AngularJS part, I’m afraid I can’t be helpful at this moment.

      P.s. the last paragraph of your comments are keeping eaten by the comment form… sorry about that.

  • By the way, since I am using a virtual host for my dev site (using angularpress.dev as domain), using fixed that nobase error.

  • Hello,
    Thank you for your article !
    Even if that’s not best practice with V2 I decided to go with rest_prepare_post to remove fields in the JSON response (it is just for displaying posts). I managed to get rid of many things but not of the “_links” field (with all its subfields) that I totally don’t need. I remove the other fields with “unset($_data[‘modified_gmt’]);” for example.
    Any idea how to unset this as this is unnecessary for me and a pretty “heavy field” ?

    • Hey Fab, it’s pretty understandable because “_links” is not part of the response data, so we can’t use the filter to unset this very field.

      I believe the _links field is like an universal field for any standard API. So we can’t modify it.

  • Hi,

    Nice article.
    I do have a question, there’s a white space in the beginning of the result. {{post.content.rendered}}, how can i remove this space??

    Thanks.

  • Hi Yoren,
    I’m using wp-rest api plugin in wordpress. I’ve show all data through rest api, but i want to show 5 post per page (pagination). Pls help me. If you have some example it’s realy help to me.

    Thanks,
    Krishna Kumar Tiwari

    • Hi, you can use “filter[posts_per_page]=5” to get only 5 posts per page.

  • Hi,

    Is there a way to use “Month and name” as Permalink and make it work with wp-api-v2? I followed your slug example but it only works when I use “Post name” for permalinks. Thanks in advance.

  • Hi Yoren, Impressive post.Have you ever considered Angular standalone front end with wordpress backend.I have a scenario where i have a wordpress admin and it manages content of side. But i want to add new apps which are basically angular js apps which could possibly talk to WP rest api once they are authenticated.These angular apps will basically do crud operations of different post types which are solely used by admins and will not get reflected on the sites.However these post types should show up in wordpress admin so that admin could take some action by looking at the data.The angular app is a web client and used on tablet by the user to fill information.Does this scenario make any sense and what would be the best way you think to implement this architecture wise.

  • Hi Yoren,

    Excellent reference tutorials of tying up AngularJS with WordPress! I am working on importing my AngularJS SPA into WordPress but have slightly different approach with the routing. I am using UIRouter rather than ngRoute. This has a number of benefits but might be a bit tricky when it comes to displaying images for example. No PHP script works within the partials as they are pure HTML. How do you go about solving this kind of problem? The whole idea is to let the user update content, insert plugins within the code (i.e. Google maps) but this does not work for some reason. The partial get inserted into the index.php but still the scripts are not usable. Any ideas how to solve this problem?

    • Hi Nick, not sure if your question is about plugin compatibility? To me, when building such theme it almost guarantees tons of plugins won’t work with it. Although you can hack around it – with tons of efforts.

      • Thank you very much Yoren. Unfortunately that seems to be the case after a few days of efforts on my side to make it work. I handled the images but the plugin shortcodes are sitll not working. It was worth a try though. Learned something new 🙂

Submit a comment

Your email address will not be published. Required fields are marked *