WP-API V2 tips

Posted by Lloyd Jones
Last updated

WP-API, if you haven’t already heard of it, is an excellent JSON API plugin for WordPress, which (as the name suggests) allows a site’s content to be selectively exposed in handy JSON format, for whichever uses you like.

Recently, BAY.A have been using V2 of this API, which comes with some changes. Here, we’ll outline some common issues and solutions, and keep this post updated for future use.

The API is now integrated into WordPress core, so it’s definitely worth getting to know it!

Without further ado…

Get Custom Post Types using the V2 JSON API

Easy! Using the example of a custom post type called ‘the_event’, you’d just put the following into your functions.php file (or plugin) :

add_action( 'init', 'add_events_to_json_api', 30 );
function add_events_to_json_api(){

    global $wp_post_types;
    $wp_post_types['the_event']->show_in_rest = true;
    $wp_post_types['the_event']->rest_base = 'the_event';
    $wp_post_types['the_event']->rest_controller_class = 'WP_REST_Posts_Controller';

You will now be able to visit “http://yoursite.com/wp-json/wp/v2/the_event/6269/” (if you have a ‘the_event’ post with an ID of 6269) and see the post information, or “http://yoursite.com/wp-json/wp/v2/the_event/” to see all events.

You’re able to get all custom post types dynamically into an array like so:

$types = get_post_types(('public'   => true,'_builtin' => false));

And then loop through them, and for each one, use the code I’ve provided further up above to register them with WP-API.

Get Custom Post Type meta data via WP-API V2

Again, we’re using the ‘the_event’ custom post type, and we’re getting 3 pieces of meta: “_the_event_start”, “_the_event_end”, and “_the_event_location”.
Just use this code below, replacing all instances of ‘the_event’ with your custom post type – including in the filter name (Thanks Nick!) :

add_filter( 'rest_prepare_the_event', 'add_meta_to_json', 10, 3 );
function add_meta_to_json($data, $post, $request){

$response_data = $data->get_data();

if ( $request['context'] !== 'view' || is_wp_error( $data ) ) {
    return $data;

$start = get_post_meta( $post->ID, '_the_event_start', true );
    $start = '';

$end = get_post_meta( $post->ID, '_the_event_end', true );
    $end = '';

$location = get_post_meta( $post->ID, '_the_event_location', true );
    $location = '';

if($post->post_type == 'the_event'){
    $response_data['event_meta'] = array(
        'start' => $start,
        'end' => $end,
        'location' => $location,

$data->set_data( $response_data );

return $data;

Referencing the first example, you will now be able to visit “http://yoursite.com/wp-json/wp/v2/the_event/6269/”, and this time there will be another JSON key called ‘event_meta’, inside which there’ll be your start, end and location meta.

Get custom post types via the WP-API V2 Backbone JS Client

Okay, so using the information above, you may wish to use this information in the javascript client that comes with WP-API. Here’s how:

Firstly, we need to create a Model and Collection for our custom post type:

var TheEvent = wp.api.models.Post.extend({
            urlRoot: WP_API_Settings.root + '/the_event',
            defaults: {
                type: 'the_event'

        var TheEvents = wp.api.collections.Posts.extend({
            url: WP_API_Settings.root + '/the_event',
            model: TheEvent

Next up, we put this into a variable:

        var some_events = new TheEvents;

And finally, we are able to access the custom post type via the ‘done’ function after fetching:

            filter: {
               nopaging: true
        }).done( function() {
            some_events.each( function( myevent ) {
                console.log( myevent.attributes );




For getting the custom meta data, which file does this code go in? I tried putting it in plugin.php and that didn’t seem to work.


Hi Nick,

Thanks for getting in touch.

You can place the example code I’ve given here, as-is, in /wp-content/themes//functions.php (where is the name of your theme).

Or, if you’re using a plugin you’d just go to /wp-content/plugins/ and create a new folder (json-custom-post-types) and in that folder, create a new .PHP file called ‘json-custom-post-types.php’, and in that file, insert the following header:

Plugin Name: JSON CPT
Plugin URI:  http://yoursite.com/
Description: JSON Custom Post Types
Version:     1.0
Author:      You
Author URI:  http://yoursite.com/
Text Domain: json-cpt
Domain Path: /lang

Then the code I provided.

Let me know if that does/doesn’t work for you.



It wooorrrkksss ೕ(˃̵ᴗ˂̵ ๑)

However, I did have to change two things.

The first is that using “empty()” on a function return seems to freak WP out. I changed that to be as follows:

“$post_meta = get_post_meta( $post->ID, ‘custom_field_here’, true );

if(!empty($post_meta)){ …… } ”

The second is that the addFilter( ) call needs to be named after what the custom post type is called. This might be super obvious, but I literally started doing WordPress development yesterday and it took me a bit to figure out.

As an example, I’m using a custom post type named “news_items”, so my addFilter looks like this:

“add_filter( ‘rest_prepare_news_items’, ‘add_meta_to_json’, 10, 3 );”

Thank you very much for your help!


Hey, great! Good to hear!

re: The ‘add_filter’ part, that was actually a typo. I originally (over at Github) was using ‘my_events’ as the example custom post type, but here changed it to ‘the_event’ but forgot to change it. I’ll add a note to the post that it should be the custom post type slug. Thanks!
re: The empty() error: That’s odd! I never knew that! I’ll also update the post to reflect this.

No worries at all – hope the coding goes well!


Hi (tried to find your name), really excellent quick tip to get up and running with WP API v2. I’m amazed how much easier and more powerful it is over v1.

I’m trying to filter based on the meta data attached to my pages. I’ve added it following your tips to the JSON data and can see it attached.

It’s not a custom post type like you have above instead it’s just regular page (I’m sure posts are too different here?). To be honest I never managed to get ?filter to work with meta data in v1, do you know how I can get it to work in v2? Thanks.


Hello! My name’s Lloyd 🙂

The filter functionality, at the time of typing this, seems to be broken. I actually need it for a project of mine, and it won’t work. I’ve got an issue open over at their GitHub repo’, but no news yet..!

Pete Nelson

FYI, you could be able to just add “‘rest_base’ => ‘the_event'” as part of the args to the register_post_type() call rather than having to tap into the global $wp_post_types.


Hi Lloyd,
I was able to get this working if I added your code inside functions.php. However, it doesn’t work if I add it to my plugin. My plugin file is has nothing but the following, I’m not even sure if it executed (not sure how to verify).

Plugin Name: JSON CPT
Plugin URI: http://yoursite.com/
Description: JSON Custom Post Types
Version: 1.0
Author: You
Author URI: http://yoursite.com/
Text Domain: json-cpt
Domain Path: /lang

function add_question_json_api() {
global $wp_post_types;
$wp_post_types[‘question’]->show_in_rest = true;
$wp_post_types[‘question’]->rest_base = ‘question’;
$wp_post_types[‘question’]->rest_controller_class = ‘WP_REST_Posts_Controller’;

add_action( ‘init’, ‘add_question_json_api’, 30 );


Hi Loc,

That’s odd – my guess (without seeing your complete setup) is that perhaps the priority is incorrect? Have you tried changing “add_action( ‘init’, ‘add_question_json_api’, 30 );” to “add_action( ‘init’, ‘add_question_json_api’, 999 );” or even making it smaller? “add_action( ‘init’, ‘add_question_json_api’, 1 );”


Hi Lloyd, yes the priority caused my setup to not work. Changing the name of my plugin to zzzzMyPlugin works. I think they are ordered by its alphabet. Thanks.

Matheus Costa


First of all, thank you for this amazing post. But, I’m having some simple problem… Using your first snippet to display my custom posts as endpoints (example: /products) I recive a JSON with just 10 of them (have more than 100). BUT, if I type a valid ID and not listed, I get the single product normally. Any ideia:

Ex: mysite.com/products = show products from IDs 100 to 110. If I type mysite/com/products/25 (and not listed ID) it shows me the product.

Thank you for your help.


Hi Matheus,

Thank you! Appreciated 🙂

I think you’d need to (somehow) set the post_per_page value to -1? That way you won’t just get the default amount for your site.


Leave a Reply

Your e-mail address will not be published. Required fields are marked *