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