Adding Fields To The JSON Response Of The WP REST API

The WP-API team got the documentation updated, so be sure to check this post out before you modifying the JSON response. (Thanks PDuran for this.)

Since I started the series about building themes with AngularJS and WP REST API, I got asked lots of questions that sometimes they were involved more with AngularJS, and sometimes they were more concerned with WP REST API.

To be honest, I prefer WP REST API related questions because they usually take less time for me to solve. After all, I’m quite new to AngularJS so before answering each question I’ll do some research to make sure my answer will be backed up.

Most questions related to WP REST API can be solved by manipulating data in the JSON response. Yes, though the post title might imply the “adding” part, we can also “update” or “remove” fields (data) with the same approach. Let’s get started.

Scenario one: get the categories and their posts in a single API request

David asked this question that he wanted to build an accordion menu with categories as the first level links, which when being clicked, the posts would be collapsed as the second level links.

When we call the WP REST API with a route like “wp-json/taxonomies/category/terms/1“, we’ll get the JSON response with all information about the term (category) object.

We can also get the posts in a single category by calling “wp-json/posts/?filter[category_name]=uncategorized“, but that would be very inefficiency that if we have five categories, we’ll have five extra API calls.

The ideal solution for me is we should include the latest 3 or 5 posts to the JSON response, that can save us from those extra calls. Here’s the gist for such task, you’ll need to insert it to the functions.php:

Please note at line 5-8 is for preventing the posts being added every time the term route is called. For example, when calling terms or even posts routes, they’ll call for a single term too, and the latest five posts will also be added to the JSON response, which might be useless in those cases. But if that’s exactly what you want, just comment out these lines.

After that, when calling the “wp-json/taxonomies/category/terms/1” route, you’ll get an advanced JSON response like the image below. You can see the latest posts in the category are included.

Term JSON response with latest posts

Scenario two: add featured image thumbnail URL to wp-json/wp/v2/posts route

The other question is asked by Dominic, that he’s interested in how to get featured image thumbnail URL, that in the next version (v2.0) of WP API, the route “wp-json/wp/v2/posts” will return only the featured image ID, but not the image URLs.

In this scenario, we know that we could access the feature image object with an route like “wp-json/wp/v2/media/45“, but as the previous example, doing so will cost us more API calls so it would be great that we just add the the thumbnail URL back to the JSON response. Here’s a gist does the trick:

From the gist above you can see that we use the filter “rest_prepare_post” to manipulate the JSON data. It’s really simple and straight forward that I add a new key “featured_image_thumbnail_url” to the $data->data array, and set it to the thumbnail url.

With such a simple tweak, extra API calls are saved and we can use “{{post.featured_image_thumbnail_url}}” in our AngularJS template for the post thumbnail.

Scenario three: removing fields we don’t need from the JSON response

Let’s say from the scenario two, we think the “featured_image” only contents an ID so it’s useless to us. We can remove it with a PHP unset function (at line 11):

And of course, the better solution in this case should be, just resetting the value of $_data['featured_image'] (at line 9):

Be sure to check out the WP API develop branch

The WP API repository on GitHub now set the default branch to the develop branch, which is the version 2.0. Be sure to spend some time with it if you’re serious about building a WordPress app in the near future.

I’ll also update all the tutorials in the building themes with AngularJS and WP REST API series when the v2.0 comes out. (The AngularJS 2.0 will aslo be out this summer. What a coincidence.) See you in my next post!

Share the post:Tweet about this on TwitterShare on Google+1Share on Facebook9Share on LinkedIn4
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!

64 Comments

Submit a comment
  • Hey Yoren, looking at this convinced me to abandoned v1 and run with v2!

    Sorry to bother you again, but if you have the time,
    I’m trying to filter based on the meta data attached to my pages. I’ve added it to the JSON data and can see it attached.

    It’s just a regular page type (I’m sure posts are not too different here?). To be honest I never managed to get ?filter to work with meta data in v1. Any chances you could show how to use filter with custom meta value in v2? And if you have even more time you can always show v1 also 🙂

    • Hey David,

      Can you check this post by Josh to see if his method can work? http://torquemag.io/working-meta-data-using-json-rest-api/

      As he wrote the post in last September, he should be using version 1.

      The version 2 should work pretty much the same way, just the filter name has been changed to “rest_query_vars”.

      I’d love to write a short post to demonstrate it this weekend, for the future readers. Thanks for bringing me new post ideas, as always!

      • Thanks for the excellent resource. I’ve gone back to v1 also. As much as I like how it works, as Dominic below mentions, there’s just no docs out there for it.

        Well I’ve figured out how to filter by custom posts. I first add it anything I need to JSON object:

        //I’m using Advance Custom Fields
        add_filter(‘json_prepare_page’, ‘wp_api_encode_acf’, 10, 3);
        function wp_api_encode_acf($data, $post, $context)
        {
        $custom_fields_exist = get_fields($post[‘ID’]);
        if ($custom_fields_exist) {
        // This would merge the fields instead of overwriting it
        // $data[‘meta’] = array_merge($data[‘meta’], get_fields($post[‘ID’]));
        $data[‘meta’] = get_fields($post[‘ID’]);
        }
        return $data;
        }

        …then make them filterable with:

        add_filter(‘json_query_vars’, ‘slug_allow_meta’);
        function slug_allow_meta($valid_vars)
        {
        $valid_vars = array_merge($valid_vars, array(‘meta_key’, ‘meta_value’));
        return $valid_vars;
        }

        and finally filter them with:

        /wp-json/pages?filter[meta_key]=META_KEY&filter[meta_value]=META_VALUE

        Of course replace META_KEY and META_VALUE for what you’re after.

        I understand this could expose your site to potential security issues as it makes all meta data filterable.

        My question is by overwriting the meta as I did above with my own custom meta data would that reduce the risk of these security issues?

        • The secure issue only happens if the meta values are “confidential”. If not, it should be fine.

          I’ll suggest to add something like “$allowed_fields” to your “wp_api_encode_acf” function, that only allows certain metas to be exposed to the WP API. That should reduce the security risk and better protect your data.

  • After spending about a week with v2 of the WP API and struggling to find the same level of ease I went back to v1. That was about a month ago now. v2 is intended for core inclusion into WordPress but that keeps getting delayed. Originally scheduled for WordPress 4.1 it might make it into 4.3 – target date August 18th (https://make.wordpress.org/core/features-as-plugins/).

    Angular 2 should be interesting, can’t wait!

    Btw, the link to my comment within your post is broken. The event tracking and the href urls.

    • Thanks, the link should be correct now.

      WP API version 2 is much more complicated than version 1 and the documentation is still an issue. Though as a developer who loves to read the code, it is quite fun. 😉

      • Yes! The docs were very lacking. I did however think the code was well organized. I’m definitely going to re-visit v2 soon.

  • Great post Yoren! I was into the same problem as DAVID with the added request by a Custom Post Type (working with v2). It’s true that the documentation is poor but in this case the answer is there Modifying Responses and the example is clear enough.
    Thanks.

    • Hi, Pduran, Thanks for the link. I’m not sure but it seemed the official documentation didn’t exist yet when I wrote this post. I’m glad the API docs are getting better and better.

  • Hello, Yoren Chang! Great snippets. BTW, any way to add pagination with endpoint over the category term? (post_per_page)

  • Hi Yoren! Great article and very useful.
    Correct me if I’m wrong but when you add the filter to alter the json response for example by removing objects from the response (unset($_data[‘id’]);) all api calls are affected.

    So how can I remove json response objects from one api call and remove completely others for another api call?

    • Hi Ciprian,

      Yes you’re totally right so the WP-API team has warned us don’t alter the response even if we can.

      Regarding to your question, I think the easiest way is to required an additional params to detect if it’s the call you allow to alter the JSON response. Or you may do so by detecting the call from it’s header/ip/oath token.

      Let me know if any of the methods works. Thanks!

        • Hi Ahmad,

          You can take a look at: https://gist.github.com/yoren/95cd7779de9cc6e4c189#file-functions-php (a gist from the demos above), at line 7 I use a preg_match to see if it’s the route to get terms (in WP API v1).

          So you can add a special param to a normal route like:

          http://URL/wp-json/posts?my-unique-param=VERY-UNIQUE

          then check if the param matches when you prepare the response:

          if ( isset( $_GET[‘my-unique-param’] ) && ‘VERY-UNIQUE’ == $_GET[‘my-unique-param’] ) {
          // modify the response
          }

          It’s should just work (in theory), but please note I haven’t used such code in any production project and can’t be responsible for any security issue it may cause…

          Let me know if you have any further question. Cheers!

  • Hi Yoren,

    Thank you for your post. I’m trying to get the featured_image back with the post meta, I added your function in functions.php under rest-api > core > wp-includes folder, but it doesn’t seem to work. (Still show id but not link in the post meta.)

    I’m really new to WordPress, could you please give me a hint?

    Thanks.

    • Hey Alan, when we say functions.php in the WordPress world, we usually mean the functions.php in your theme – any theme you’ve activated.

      Just fyi that don’t modify any code in your WordPress core or plugins or even themes (you should create a child theme if you need to do so). So you can get all the benefits from the future upgrades.

      Cheers!

  • First of all, great tutorial.
    I have a question if you dont mind. Ive followed most of your parts in this tutorial series, and I think everything is great. Got a simpel theme up and running which have posts, pages and a menu, using the WP API Menu plugin to extend the rest API to fetch menus aswell. But now I have run in to trouble. Seems that you cant get widgets out of the API. Didnt think about it that much with the menus since there was a plugin to solve that, but I cant find any info on the web about how to get widgets with the rest API, and this makes me wonder – is the API really ment for theme building, and if so – how to get stuff like menus and widgets. The more I think about it, it feels like the REST API is for reading out like a list of post in an external app, not building a whole theme. I hope Im wrong though, since this feels much better than to mix angular with WordPress original theme structure with all PHP and stuff like that.

    Best Regards

    • Hey Samuel,

      Quoting your words that “it feels like the REST API is for reading out like a list of post in an external app, not building a whole theme.” I can’t say if this statement is totally true or false, but you’re right to some extent.

      But we should also be aware of that the WP API is still at very early stage. There’s no default route for widgets now doesn’t mean it won’t be available in the future. And I have a firm belief that we’ll have it eventually, as long as the Widgets API stays in core.

      I might mislead you or the lovely readers in some way that, we “can” build a WP theme with AngularJS and WP API doesn’t mean it’s “the best practice” to build an web application with AngularJS and WP API. To be honest it’s not the best practice for the performance sake if we compare to a pure JS application (with WP API).

      Anyway I’m glad to have you here, and feel free to ask me anything I’d love to share my thoughts with you.

  • Thank you for your answer Yoren!

    Off course, you are totally right about the early stages of this. I found a issue about this after I wrote to you, where they are practically saying it would be implemented as soon as the widget API itself is more robust. https://github.com/WP-API/WP-API/issues/19 (see kwights commit from september 2015).

    As I cant wait for that I asked a friend to write a plugin like the WP MENU API plugin but for widgets, where you just basically get a list of sidebars with wp-json/wp/v2/sidebars, or a sidebar with the widget output via wp-json/wp/v2/sidebars/{sidebar_id}.

    The plugin is in early development but its working as I want it to already and I have it fully functional set up on me test theme. It will soon be on the WP plugin repo to.

    https://github.com/martin-pettersson/wp-rest-api-sidebars

    Hope this is helpful for someone else in the meantime as well.

    Best Regards

    • Hey Samuel,

      Thumbs up to you and Martin! Keep working on it and I’d love to share on my social accounts when it’s live on WP.org.

  • I saw it. We where just discussing whats the best thing to do, and Im leaning towards your idea, so I guess we are two to one 😉

    • Martin just namespaced the plugin! Also I’ve tweeted the repo on WP.org, hope it helps to promote this cool plugin.

  • Hi,Yoren. Great thanks for your helpful tutorial.

    My circumstance is wordpress 4.4 and REST API V2.
    I try to work the Scenario one, and I pasted your script to functions.php.
    and check JSON data for example “/wp-json/wp/v2/categories/15/”.
    but I cannot see the posts being set in functions.php.

    I hope I can attach some posts (or other data) when I access the category JSON data.

    Sorry to bother you but I am glad if you help me.

  • how to get all catagories wp/v2/catagories route? in defalut 10 catagories

  • Hello Yoren,

    Can you please help me with that:
    I have Custom Field called “Views” which get updated when user visit any link.

    Now Iam trying to get the last 10 posts with most views through rest api v1, how can I do that ?
    Iam using that but not working
    &filter[posts_per_page]=10&filter[orderby]=Views&filter[order]=Desc

    I have “Add Advance Custom Fields to JSON API” installed.

    Could you please help !

  • Hi YOREN CHANG.
    Thank you so much for this, you are the only one to have this solution.
    I’m using wp-api v1.2.5 and I tried the first scenario, I placed the code exactly as it is in my functions.php but i’m still not getting the posts within the categories in the json response, could it have anything to do with the latest version of WordPress? unfortunately i have to use v1 because v2 will not work in my meteor application.
    Thank you again

    • Hi, sorry but I don’t use v1 anymore, can’t be helpful with your question.

      • No problem. Thank you for responding. Is it possible to embed a featured image in the “get the categories and their posts in a single API request” for v2?? something like foreach ( $posts as $p ) {
        $posts_arr[] = array(
        ‘ID’ => $p->ID,
        ‘title’ => $p->post_title,
        ‘content’ => $p->post_content,
        ‘featured_image_thumbnail_url’ => $p ->featured_image_thumbnail_url,
        );

  • Hello, Good work with this post.

    I came here because I am trying to understand how to do something in the WP API. Maybe you could give me some quick advice and point me to the right direction.

    We need to add custom fields internally to the “Shop Orders” and they must be updated and retrieved using the RestFul API. I have been debugging and reading the code but haven’t been able to understand how this works. I don’t want to take you too much of your time but I would really appreciate a couple words.

    Regards

  • Hello Yoren,

    First thanks a lot for all your precious advise and works. I’m creating my wordpress theme with angular. Everything works perfect but i’m using ACF custom field. Do you mind explaining how to handle the repeater field in angular context ? I’m kind of stuck in ressources out there and new to angular.
    Thanks

    • Hey i’ve manage to display the content of my repeater field with post controller and acf-to-rest-api. One more question that i’ve seen earlier in another post still about wordpress with angular. When i’m on one post, if i reload the page i have a blank page, i always have to go back to homepage. I have set the url as http://www.home.dev/slug/ in my post controller and in my permalink. What should i do ?

      • Hi lea, Have you set the right routes in your JS file? They must be corresponding to your permalink settings.

  • // Add custom fields to json response
    function slug_register_featured() {
    register_api_field( ‘post’,
    ‘featured’,
    array(
    ‘get_callback’ => ‘get_meta_to_response’,
    ‘update_callback’ => null,
    ‘schema’ => null,
    )
    );
    }
    add_action( ‘rest_api_init’, ‘slug_register_featured’ );

    function get_meta_to_response( $object, $field_name, $request ) {
    return get_post_meta( $object[ ‘id’ ], $field_name, true );
    }

  • Hello, here is my problem and I would love a lot if you can help me, I have two site http: // localhost / site1 and http: // localhost / site2, I have a post_type = project found in site1 With post_meta ( “amount”) and I would like to recover this post_meta amount and display it in site2 with WP-JSON wordpress API both site are in wordpress.
    Here is my script on site two

    array (
    ‘Ignore_errors’ => true,
    ),
    );
    $ Context = stream_context_create ($ options);
    $ Response = file_get_contents (
    ‘Http: // localhost / site1 / wp-json / posts? Type = project,
    false,
    $ context
    );
    $ Response = json_decode ($ response);
    Var_dump ($ response);
    ?>
    I get to retrieve all the post_type = project but to get get_post_meta ( “amount”) I can not display it
    Thank you for your reply

    • Hi, Marana,

      Have you added the “amount” meta into your JSON response? If you’ve done so, you should be seeing it when you dump $response. And since it’s a meta value on site1, you cannot use get_post_meta to access it on site2.

  • Hello, that I do var_dump of $ response it displays all the post_type product but not the post_meta

  • Rest API work for me for this combination – domain.com/wp-json/wp/v2/custom-post, but my app read only standard wp/v2/posts.

    How i can add custom post to standard WordPress category and REST API?

    • Hey Damian,

      Sorry for the late reply. You need to set `show_in_rest ` => true when registering the CPT to get it work.

  • Great post, Yoren.

    The code in “Scenario two” worked perfectly for me. =)

    But now I would like to take the other way. In other words, I would like to GET fields from a JSON REQUEST.

    Do you know some good tutorial for that?

Submit a comment

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