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!

41 responses

  1. Thanks 🙂 by default WP rest api give 10 post how can we retrieve more post than that like 20 or 30 post

    1. Yoren Chang Avatar
      Yoren Chang

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

  2. Hi Yoren,
    Thanks for a great tutorial,

    I am currently getting an error Error: [ngRepeat:dupes] http://errors.angularjs.org/1.4.3/ngRepeat/dupes?p0=category%20in%20data.categories&p1=string%3A%3C&p2=%3C
    at Error (native) …
    When I changed over to wp rest api v.2 ?

    1. Yoren Chang Avatar
      Yoren Chang

      Hi Rohan, regarding the migration between WP API v1 and v2, please refer to this post: https://1fix.io/blog/2015/09/29/wp-api-v2-angularjs-theme/.

    2. Yoren Chang Avatar
      Yoren Chang

      Hey sorry I didn’t really answer your question from my previous reply. I can’t tell where the error comes from with these messages. If you still need my help, just pack your theme and send it to yoren[at]1fix.io.

    3. Tim Clifford Avatar
      Tim Clifford

      I tried scanning for this error for far too long, turns out after migrating everything to v2 I forgot to re save the permalinks. Hope that helps.

      1. Yoren Chang Avatar
        Yoren Chang

        Hey that’s pretty interesting and I can’t recall if I did that too. Thanks for this tip!

  3. 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!

    1. Yoren Chang Avatar
      Yoren Chang

      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.

  4. 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

    1. Yoren Chang Avatar
      Yoren Chang

      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.

  5. 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 🙁

    1. Yoren Chang Avatar
      Yoren Chang

      Hi Mary, thanks for the notice. I haven’t noticed that a hyphen in the name of a CPT will cause a problem like this. It’s very interesting and actually makes sense because a hyphen is not allowed in a variable name in PHP.

      I found a comment from WPMU https://premium.wpmudev.org/forums/topic/why-is-underscore-permitted-in-the-post-type-but-dash-is-disallowed#post-507002 shows how to set arguments for a CPT more properly. Just fyi.

  6. 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!

    1. Yoren Chang Avatar
      Yoren Chang

      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!

  7. Mohammed Avatar

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

    1. Yoren Chang Avatar
      Yoren Chang

      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.

  8. 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.

    1. Yoren Chang Avatar
      Yoren Chang

      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.

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

  10. 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” ?

    1. Yoren Chang Avatar
      Yoren Chang

      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.

  11. emmanuel joseph Avatar
    emmanuel joseph

    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.

  12. Krishna Kumar Tiwari Avatar
    Krishna Kumar Tiwari

    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

    1. Yoren Chang Avatar
      Yoren Chang

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

  13. 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.

    1. Yoren Chang Avatar
      Yoren Chang

      Hi Igor, please try this solution by Emil: https://1fix.io/angularjs-wp-rest-api/#comment-9070.

  14. Hi YOREN CHANG,
    in WP REST API V2 i am getting issue i am sure you can help.

    http://localhost/wordpress/wp-json/wp/v2/posts?filter%5Bcategory_name%5D=css

    giving all category response. is there any mistake in my route ? or something wrong in plugin.

    i am waiting for your response 🙂

    Thanks

  15. Yoren Chang Avatar
    Yoren Chang

    Hey Mohd,

    Just tested on WP API site and it seems worked fine. See:
    https://demo.wp-api.org/wp-json/wp/v2/posts?categories=7
    and
    https://demo.wp-api.org/wp-json/wp/v2/posts?filter%5Bcategory_name%5D=apple-event

    Both return correct posts in the very category. Need more info from you to help debug.

    1. yes these both giving correct response but not mine.

      on http://url.com/wp-json/wp/v2/posts?categories=id

      giving all post record here is my json response

      http://i.imgur.com/YnrjWtq.png

  16. 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.

    1. Yoren Chang Avatar
      Yoren Chang

      Hi Riju, have you checked Michael Bromley’s https://github.com/michaelbromley/angular-wordpress-seed? I think it would be a good start if you’re looking for building a pure AngularJS application with WP API.

      Such approach is also called “Headless / Decoupled WordPress”. Google for it maybe you’ll find more things of use to you.

  17. Nick Kolev Avatar
    Nick Kolev

    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?

    1. Yoren Chang Avatar
      Yoren Chang

      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.

      1. Nick Kolev Avatar
        Nick Kolev

        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 🙂

  18. kanabi Avatar

    Hello Yoren, I’m not sure if it’s most fitting to ask this here, but could you please consider writing an article on how to establish post translation with angular-translate (https://angular-translate.github.io)? Translating app content defined in translation tables is easy, but dynamic loading different api urls for each language (ex. /{lang}/wp-json/wp/v2/) is currently beyond my ability and I’ve been struggling with this for weeks now. I’m using qTranslate plugin to translate wordpress content. Also changing routes accordingly is necessary.

    Below I’m posting links to some solutions I’ve found at least giving some clues on how to resolve this matter. However a complete solution would be most appreciated – on the web there are only simple tutorials explaining how to translate angular app using angular-translate, but none of them is explicitly telling how to do it in a WP environment. Similar approach could be also used in an Angular2 theme. I really hope you will take a look at this.

    https://github.com/tkssharma/Angular-Common/blob/master/src/controllers/langController.js
    https://github.com/sitepoint-editors/multilingualwithangular/blob/master/js/app.js
    https://github.com/Shelob9/angular-trans-exp/blob/master/app.js

    1. Yoren Chang Avatar
      Yoren Chang

      Hey Kanabi,

      Thanks for your suggestion! Just I don’t really pay attention to AngularJS anymore, thus I’ve stopped updating this series.

      Maybe you can check with Josh and see what’s his take on this?

  19. Adriano Monecchi Avatar
    Adriano Monecchi

    Hi there. Thanks for the Tutorial.

    I’ve managed to display the featured image url within the WP API response, but WP debug keeps complaining about b>Warning: Missing argument 2 for `my_rest_prepare_post()`

    What am I suppose to pass as the second parameter?

    Regards,

    1. Yoren Chang Avatar
      Yoren Chang

      Hi Adriano,

      `my_rest_prepare_post ` hooks to `rest_prepare_post` which takes 3 arguments. So maybe check if you pass all of them?

Leave a Reply

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