The Publishing Project

WordPress CMS CRUD (part 4): Creating custom post types and adding them to the REST API

One of the things I’ve always liked about WordPress is its flexibility. We can extend WordPress and create pretty much any type of content that we need for specific projects.

We can choose whether to build it inside a theme or a plugin. For the most part I would recommend building it in a plugin so that we will retain the capability even if we switch themes.

Like all plugins we first declare a preamble that looks like this. This is the block that makes it a plugin that we can load and use.

<?php
   /*
   Plugin Name: Awesomeness Creator
   Plugin URI: https://example.com
   description: a plugin to create awesomeness and spread joy
   Version: 1.0
   Author: Mr. Awesome
   Author URI: https://site.com
   License: GPL2
   */
?>

The actual meat of the plugin is the custom post type registration. As with all WordPress related code, it has two parts: a callback function and a hook that tells WordPress what to do with the callback.

<?php
function rivendellweb_custom_book_type() {
    $args = array(
      'public'       => true,
      'show_in_rest' => true,
      'rest_base'    => 'books',
      'label'        => 'Books'
    );
    register_post_type( 'book', $args );
}
add_action( 'init', 'rivendellweb_custom_book_type' );
?>

There are two arguments that are important when working with REST API routes.

show_in_rest tells WordPress that we want this custom post type to show in the REST API. When I activate the plugin it adds 4 additional books-related routes to the list of APIs available

rest_base allows us to rewrite the name of the route in the REST API. The default is the same name as the custom type but there may be cases where we want a different name. In our example I chose books instead of book (singular) for the name of the route.

We can also create one or more taxonomies for our custom post types and, with the show_in_rest attribute, we can use it from the REST API.

Because we’ve used a custom name in the route with base_rest we have to rewrite the taxonomy to match using the rewrite attribute in the custom taxonomy arguments.

The custom taxonomy declaration looks like this

<?php
function rivendellweb_custom_book_genre_taxonomy() {
  $labels => array(
    'name'          => __x('Genres'),
    'singular_name' => __x('Genre', 'taxonomy singular name'),
    'search_items'  => __('Search Genres'),
    'edit_item'     => __('Edit Genre'),
    'add_new_item'  => __('Add New Genre')
  );

  $args = array(
    'labels'       => $labels,
    'show_in_rest' => true,
    'hierarchical' => true,
    'query_var'    => true,
    'rewrite'      => array(
      'slug' => 'books/genre',
      'with_front' => false
    )
  );
  register_taxonomy( 'genre', 'book', $args );
}
add_action( 'init',
  'rivendellweb_custom_book_genre_taxonomy', 0 );

With this functionality plugin installed we’ve created a new custom post type, added an interface to it on the admin UI, and made sure we can access it through the REST API.