Working with Custom Post Types in WP-API v2

If you worked with the first version of the WP-API, you know that getting custom post types was really easy.

To get all posts, I could send a GET request to http://scottbolinger.com/wp-json/posts. To get a specific type, I could send my request to http://scottbolinger.com/wp-json/posts?type=event.

There have been some pretty big changes in version 2, which is now in WordPress core.

Custom post types are now hidden from the API by default. I can see why they did this, many themes and plugins added post types that they never intended to be public. Making those public would cause more problems than it would solve.

However, that now means we can’t just add the ‘type’ flag to our request, and expect to get post types back.

How to get custom post types in the WP-API v2

Any custom post type that you want to be available to the WP-API needs to have the show_in_rest = true argument. You can do this in your registration function, or after the post is already registered.

Find available post types

The WP-API lists all available post types at https://YOURSITE.com/wp-json/wp/v2/types

The Register Function

You can add your custom post type to the API when you register it.

Using the ‘book’ post type example from the codex, we just add the show_in_rest argument.

/**
 * Register a book post type, with REST API support
 *
 * Based on example at: https://codex.wordpress.org/Function_Reference/register_post_type
 */
add_action( 'init', 'my_event_cpt' );
function my_event_cpt() {
    $args = array(
      'public'       => true,
      'show_in_rest' => true,
      'label'        => 'Events'
    );
    register_post_type( 'event', $args );
}

The important part is ‘show_in_rest’ => true, that’s what exposes our CPT to the API.

Method 2: Add support after the post is already registered

If you are exposing a CPT that is not in your own plugin, or you need to do it in a different place, you have a couple of options. The first is to use the init action, which is recommend in the official documentation.

add_action( 'init', 'my_custom_post_type_rest_support', 25 );
function my_custom_post_type_rest_support() {
    global $wp_post_types;
    //be sure to set this to the name of your post type!
    $post_type_name = 'book';
    if( isset( $wp_post_types[ $post_type_name ] ) ) {
        $wp_post_types[$post_type_name]->show_in_rest = true;
        // Optionally customize the rest_base or controller class
        $wp_post_types[$post_type_name]->rest_base = $post_type_name;
        $wp_post_types[$post_type_name]->rest_controller_class = 'WP_REST_Posts_Controller';
    }
}

The second option is to use the register_post_type_args filter.

function sb_add_cpts_to_api( $args, $post_type ) {
    if ( 'book' === $post_type ) {
        $args['show_in_rest'] = true;
    }
    return $args;
}
add_filter( 'register_post_type_args', 'sb_add_cpts_to_api', 10, 2 );

This works 99% of the time, but I’ve seen an occasion where this did not work for some strange reason. If you have any trouble use the init hook instead.

Getting Your Posts

Your CPT will be available at your site like this: http://scottbolinger.com/wp-json/wp/v2/book

For more information, please consult the REST API Handbook.

*Updated June 2021


Posted

in

,

by

Tags:

Comments

21 responses to “Working with Custom Post Types in WP-API v2”

  1. Pascal Birchler Avatar

    Tip: Method 2 can be simplified now with the new `register_post_type_args` hook in trunk, see https://core.trac.wordpress.org/ticket/17447

    1. Scott Avatar
      Scott

      Good tip, thanks Pascal!

  2. Matheus Costa Avatar

    So, I’ve tried both mothods but the returned JSON just contain 10 posts (in both methods). Can u tell me why?
    Btw, thank you for the post. Saved my a lot of work.

    1. Matheus Costa Avatar

      Just to be clear…
      When I use the “produto” endpoint and search (Ctrl+F) for the “id” it returns 10 itens (here’s a print: http://prntscr.com/8lc712). BUT, if I type after the “produto” endpoint and random and valid ID (that no appears in this JSON) it works (print:http://prntscr.com/8lc7gt)

    2. Scott Avatar
      Scott

      Hi Matheus, the API returns 10 posts at a time by default. You have to use the page parameter to get more. For example, …wp-json/wp/v2/posts?page=2

      1. Raihan Avatar
        Raihan

        Hi Scott,
        How do we overwrite this default value and make the api return all items?

  3. Ryan Hale Avatar

    Scott, have you tried adding this support and creating a new post with the custom post type? I’ve been trying this and can get it to work fine when posting to /posts. It creates the post without a problem. But then I added support for a ‘course’ custom post type but the post is added without accepting the title, excerpt, or content that I am sending. Nothing is different between the two javascript calls except the /course vs. /posts endpoint.
    Do you think that *should* be working? Or do you think I need to write my own custom route to handle that?

    1. Ryan Hale Avatar

      Ugh…please disregard. I found that the CPT didn’t support what I was trying to add through the API. Once I added support, everything started working.

  4. Evan Mullins Avatar

    Thanks for this! Helped me out when I updated my site to v2 and all my cpt calls didn’t work anymore!

  5. Raj Avatar

    Scott, i am little confused here.
    I have a custom post type as part of a plugin, so I used method 2, first 2 blocks of codes.
    I am able to get custom type posts in following link,
    http://totest-cscom.rhcloud.com/wp-json/wp/v2/posts
    but when trying to fetch individual post which belong to that custom type, i get a 404 error. any idea on this?
    http://totest-cscom.rhcloud.com/wp-json/wp/v2/posts/4609
    Please help me here to resolve this

    1. Raj Avatar

      Sorry this works,
      its normal post type i.e. post
      http://totest-cscom.rhcloud.com/wp-json/wp/v2/posts/4609
      Below won’t, its post type = recipe
      http://totest-cscom.rhcloud.com/wp-json/wp/v2/posts/4934

  6. Abdallah Nofal Avatar

    Thanks alot for this, It’s great.

  7. Muhammad Abdu Avatar
    Muhammad Abdu

    I don’t follow why I have to explicitly allow access to post types if my client is authenticated at the same level as a WordPress administrator.
    A pain!

  8. Grace Avatar
    Grace

    hi, i am completely new to wordpress in the way of rummaging in the php.files. so with that said where to i find the register_post_type in which file?

  9. Andy Avatar
    Andy

    Something odd with mine. A bunch of my custom post types working properly, except for 1. Continues to 404 with no rest route, despite having the same code as the rest.
    Any idea what would cause that?

  10. Deon Avatar

    Thank you for this. I really battled to add existing post types. Lots of hours of frustrations sorted out in two min. If only I found your post earlier! :):)

  11. Fachrul Hasan Avatar
    Fachrul Hasan

    Hello,
    Is there any code example for call the custom post type?
    Thank you!

  12. Iliyan Avatar
    Iliyan

    Thank you , that worked !

  13. Travis Avatar
    Travis

    Holy thread resurrection Batman!
    But, is there a way to include all the postmeta data attached to the custom post type?

  14. wikitechgo Avatar
    wikitechgo

    Thanks for this! Helped me out when I updated my site to v2 and all my cpt calls didn’t work anymore!