Real World WordPress REST API Usage – YIKES!

By Evan Herman

Say what now?

By now, I’m sure you’ve heard a ton of information about the new WordPress REST API coming to a future releases of WordPress. You may notice others getting excited, or gearing up for a major overhaul of the WordPress infrastructure. It’s all the rage at WordCamps over the past year, and you see articles popping up on sites like Torque and WP Tavern.

When I first heard that a new REST API was coming to WordPress, I too was excited. I didn’t know why, and I couldn’t think of any real world uses for it – mainly because I didn’t understand what it was. But I knew that it was going to be a game changer, and something that developers should at least become familiar with. As the web moves towards web applications, the REST API is going to play an integral part in the way data flows through your site. Further down the road, building out a REST API within WordPress allows WordPress to communicate with other technologies – further widening the “Internet of Things” – transforming your website into a data mine.

In this article I am going to explain what the REST API is (in layperson’s terms), how you or your agency can benefit from it, and provide a real world example or two. My goal is to provide a basic understanding of the REST API and some of its capabilities, as well as provide you with some working code that you can implement, use a starting point or as inspiration.

What is this REST API you speak of?

REST stands for Representational State Transfer and is a web architecture style. REST is essentially a method of communication between one or more web services, allowing you to send or retrieve data between sites that lie on different hosting environments. One of the benefits of REST is its decoupled architecture. This means that each component that makes up a WordPress site is completely independent of one another. This allows you to do some truly custom work – from building out custom admin dashboards to fully functional themes utilizing Angular.js or React.js.

Building out a theme with Angular.js or React.js creates a seamless website – where posts and pages load near instantly and without the need for a full page refresh – providing a much better end user experience.

Ok…But Why?

At this point, you may be asking yourself “Ok…cool…but Why?” You may be thinking, “Why fix something that isn’t broken?” WordPress works perfectly fine now, why reinvent the wheel? And you would be perfectly valid in thinking that. One of the major reasons is building out a REST API guarantees WordPress’ spot as a full fledged application platform. Here are just a few reasons why moving towards a fully RESTful WordPress is the future, and why you should consider embracing it:

  1. Removes any reliance on PHP. WordPress is built using PHP while the REST API removes the reliance of PHP altogether. This is a great thing as it opens the gates to additional developers, from other communities and languages – widening the number of active developers who have the skill and knowledge to work on the WordPress project.
  2. Decoupled Architecture. I briefly touched on this above, but with the full separation of the front end and dashboard of your WordPress sites users now have the ability to fully re-imagine the dashboard for their specific use case. Each project you work on can have a fully customized environment – allowing you to provide the best possible solution to your clients. Additionally, a decoupled front end allows for content to be served from any device or medium.
  3. True Mobile Integration. Having a way to interact with the database via a REST API will allow for a truly mobile experience. This would allow both iOS and Android developers to build out applications that interact with WordPress sites – using native languages such as Swift or Java.

Real World Examples

Now that you have a better understanding of what REST stands for, what the REST API is and why you might use it. Let’s get into some use cases in the real world. Keep in mind that you can use as much or as little of the REST API as you’d like, meaning you can construct an entire theme using it, you can expose your custom post types to the REST API endpoints, or you can use it to retrieve standard post type data for things like widgets or shortcodes.

A few themes built out using the REST API can be found on Github, built out by some popular developers:

  1. Rachel Baker – WCUS Demo Theme
  2. Roy Sivan – Angular WordPress Theme

A beautiful example of a full featured site built on top of the WP REST API, built out by Human Made LTD., can be found at ustwo.com. One thing you will notice about the site is how fast it loads, and how fast it is to switch between pages. Since the REST API is sending JSON (JavaScript Object Notation) data between the server and browser, the DOM is lightning fast to render.

Alongside your REST API compatible themes, there are a number of plugins in the WordPress.org plugin repository that are compatible in one way or another with the REST API. Some of the tools available alter the way the REST API functions (by customizing the endpoints, altering the data returned, altering the key names etc.), while others build in support to their plugins by enabling post types or taxonomies to be retrieved via the REST API. Some helpful plugins/tools to extend the REST API functionality are listed below:

  1. WP REST API Controller – This plugin, built by the YIKES Inc. team, enables a UI in the dashboard, allowing users to toggle visibility of custom post types, customize endpoints and REST API properties.
  2. WP API Menus – Expose menu items to the REST API, so you can query items and build custom menus using the REST API.
  3. WP REST API Log – Plugin which logs WP REST API requests and responses. Helpful for debugging.
  4. WP REST API Cache – Enable caching for WordPress REST API and increase speed of your application.

For a full list of compatible plugins, see WP REST API Compatible Plugins & Tools.

Extending the REST API with Custom Endpoints

We mentioned you could extend the API endpoints to allow your custom post types, registered using register_post_type(), to be accessed by API requests.

First we’re going to setup a demo post type to use as our example. We will also assign a meta field to the post type, so we can demonstrate how easy it is to expose custom meta data to those endpoints as well.

Keep in mind if you are following along with the tutorial here, you will want to copy all code mentioned into the functions.php file of your active theme. If you are unsure of how to edit that file, you can use a third party plugin to add all of this code to your theme safely. One plugin that we highly recommend is ‘My Custom Functions.’

Additionally, it is assumed that you have the WP REST API (version 2) plugin installed on your WordPress site. Without the plugin installed and active, you’re not going to be able to properly access the post type data using the REST API endpoints.

/**
 * Register a sample post type to use as the rest api example
 */
function generate_sample_post_type() {

	$labels = array(
		'name'                  => _x( 'Sample Posts', 'Post Type General Name', 'text_domain' ),
		'singular_name'         => _x( 'Sample Post', 'Post Type Singular Name', 'text_domain' ),
		'menu_name'             => __( 'Sample Posts', 'text_domain' ),
		'name_admin_bar'        => __( 'Sample Post', 'text_domain' ),
		'archives'              => __( 'Item Sample Posts', 'text_domain' ),
		'parent_item_colon'     => __( 'Parent Sample Post:', 'text_domain' ),
		'all_items'             => __( 'All Sample Posts', 'text_domain' ),
		'add_new_item'          => __( 'Add New Sample Post', 'text_domain' ),
		'add_new'               => __( 'Add New Sample Post', 'text_domain' ),
		'new_item'              => __( 'New Sample Post', 'text_domain' ),
		'edit_item'             => __( 'Edit Sample Post', 'text_domain' ),
		'update_item'           => __( 'Update Sample Post', 'text_domain' ),
		'view_item'             => __( 'View Sample Post', 'text_domain' ),
		'search_items'          => __( 'Search Sample Post', 'text_domain' ),
		'not_found'             => __( 'Not found', 'text_domain' ),
		'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
		'featured_image'        => __( 'Sample Post Image', 'text_domain' ),
		'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
		'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
		'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
		'insert_into_item'      => __( 'Insert into sample post', 'text_domain' ),
		'uploaded_to_this_item' => __( 'Uploaded to this sample post', 'text_domain' ),
		'items_list'            => __( 'Sample Posts list', 'text_domain' ),
		'items_list_navigation' => __( 'Sample Posts list navigation', 'text_domain' ),
		'filter_items_list'     => __( 'Filter sample posts list', 'text_domain' ),
	);
	$args = array(
		'label'                 => __( 'Sample Post', 'text_domain' ),
		'description'           => __( 'Sample post type to use as an example for extending the REST API.', 'text_domain' ),
		'labels'                => $labels,
		'supports'              => array( 'title', 'editor', ),
		'hierarchical'          => false,
		'public'                => true,
		'show_ui'               => true,
		'show_in_menu'          => true,
		'menu_position'         => 5,
		'show_in_admin_bar'     => true,
		'show_in_nav_menus'     => true,
		'can_export'            => true,
		'has_archive'           => true,		
		'exclude_from_search'   => false,
		'publicly_queryable'    => true,
		'capability_type'       => 'page',
	);
	register_post_type( 'sample_post_type', $args );

}
add_action( 'init', 'generate_sample_post_type', 0 );

After you add the above code to your themes functions.php file, refresh the admin dashboard, and you will see a new menu item in the left hand side ‘Sample Post Types.’

sample-post-type-menu-item

Screenshot:

Next, we will want to create a new meta box and a new field to assign to our post type. We will use a standard text input field, but this could really be any type of field you want. Copying the following block of code will generate a new metabox

The following block of code will define our new metabox, and assign it to the ‘sample_post_type’, that we created in the previous step. Additionally, we will include a function to include the saving of the metabox data. Again, you will want to copy the entire code block below directly into your active themes functions.php file, or into the ‘My Custom Functions’ plugin.

/**
 * Helper function to get the post meta value
 */
function sample_post_type_metabox_get_meta( $value ) {
	global $post;

	$field = get_post_meta( $post->ID, $value, true );
	if ( ! empty( $field ) ) {
		return is_array( $field ) ? stripslashes_deep( $field ) : stripslashes( wp_kses_decode_entities( $field ) );
	} else {
		return false;
	}
}

/**
 * Generate and render our metabox, assign it to the sample_post_type
 */
function sample_post_type_metabox_add_meta_box() {
	add_meta_box(
		'sample_post_type_metabox-sample-post-type-metabox',
		__( 'Sample Post Type Metabox', 'sample_post_type_metabox' ),
		'sample_post_type_metabox_html',
		'sample_post_type',
		'normal',
		'default'
	);
}
add_action( 'add_meta_boxes', 'sample_post_type_metabox_add_meta_box' );

/**
 * Generate the HTML markup for the input text field in the metbox
 */
function sample_post_type_metabox_html( $post) {
	wp_nonce_field( '_sample_post_type_metabox_nonce', 'sample_post_type_metabox_nonce' ); ?>


sample-post-type-metabox

Now that we have a sample post type setup with a custom meta box and some meta data to work with, we can continue with adding our post type and meta data to the rest api endpoints so we can properly retrieve the data.

Expose the Post Type

Now we will need to hook into the WP REST API plugin, and use the built in action hooks to add our post type the list of available post types. The documentation on the WP REST API site is great for outlining the process, if you want some additional reading.

You can copy and paste the following block of code into your themes functions.php file. If you are using the sample post above, copying & pasting will work just fine. If you have your own custom post types you have defined, you will want to populate the $post_type_array with all the post types you’d like to enable in the REST API.

/**
 * Add REST API support to an already registered post type.
 * Note: Populate the $post_type_array array with the post types you'd like exposed to the REST API.
 */
add_action( 'init', 'enable_post_type_rest_support', 25 );
function enable_post_type_rest_support() {
	global $wp_post_types;

	// Populate with post types you want enabled
	$post_type_array = array(
		'sample_post_type',
	);

	// Loop over our post type array, and enable the post types
	foreach ( $post_type_array as $post_type_name ) {
		if( isset( $wp_post_types[ $post_type_name ] ) ) {
			$wp_post_types[$post_type_name]->show_in_rest = true;
			$wp_post_types[$post_type_name]->rest_base = $post_type_name;
			$wp_post_types[$post_type_name]->rest_controller_class = 'WP_REST_Posts_Controller';
		}
	}
}

Once you’ve added the above code block to your themes functions.php file – you should then be able to access the custom post type via the REST API. If you were using the post type outlined above, your new endpoint would be http://www.example.com/wp-json/wp/v2/sample_post_type but if you were using a different post type, the path at the end of the URL would be different and would end with the post type name. For example, if your post type was ‘jobs’ your end point would be http://www.example.com/wp-json/wp/v2/jobs.

It’s important to note that you can customize the base of the URL in the function above. If you wanted to alter the rest_base, you would just need to change $wp_post_types[$post_type_name]->rest_base = $post_type_name; to something other than $post_type_name.

Viewing the end point for our custom post type, you will notice that our custom metabox/meta data isn’t listed with all of the other data. You will see some of the standard data such as the post ID, date, date_gmt, modified, modified_gmt, slug, type, link, content etc. But our metadata is no where to be found.

In the next step, we will add our metadata to our custom post type end point – so we can access the custom meta data for each individual post.

Expose Custom Metadata

Now we will hook into the WP REST API action rest_api_init, where we can define a new field to add to our API response. In our case, we will add ‘sample_post_meta’ to our response, so we can retreive the data assigned to each post for our custom, sample, metabox we created above. The following code snippet can be copied right into your themes functions.php file, and if using the examples above, will start working. If you are using a different post type, you will want to change “sample_post_type” in the code block below to your respective post type. If you have multiple post types, you will want to use register_api_field multiple times.

The second thing to tweak is “sample_post_meta“, which should be equivalent to the name of your meta field that you created in the steps above. This should be equivilent to the meta name if you were going to use `get_post_meta()` to get the meta data. In the example above, the field name is ‘sample_post_meta’.

/**
 * Register our custom end point to expose our metadata
 */
add_action( 'rest_api_init', function() {
	register_api_field( 'sample_post_type',
		'sample_post_meta',
		array(
			'get_callback'    => 'slug_get_post_meta_cb',
			'update_callback' => 'slug_update_post_meta_cb',
			'schema'          => null,
		)
	);
});

You should now be able to visit the custom endpoint we enabled, http://www.example.com/wp-json/wp/v2/sample_post_type , where you will see the new field ‘sample_post_meta’ and it’s associated data available for us to use. Keep in mind this technique can be used for any post type you have on your site, as well as any associated meta data.

Screenshot:

If you are not familiar with coding, but need to expose custom post types and it’s associated meta to the REST API, you may want to check out our WP REST API Controller plugin, which allows you to toggle on/off the custom post types and each piece of meta data assigned to those post types – without ever touching code or your theme files.

Wrapping Up

While the examples outlined in this article weren’t earth shattering, you should now have a firm grasp on how you too can expose your post types and associated meta data to the REST API. Maybe you have a better idea of how you can integrate the REST API into your projects, or just wanted to learn more about the inner workings of the REST API. Either way, as we move towards a more fully featured REST API, and it gets included in core, you will really start to see things pick up in popularity and begin to see many many more sites integrating with it, for numerous reasons.

Full Code Block

Below you will find a complete listing of all of the blocks of code outline above. The code below can be copied and pasted directly into your themes functions.php file, where things will just work out of the box. You can use the code below as an example or a starting point for your projects.

/**
 * Register a sample post type to use as the rest api example
 */
function generate_sample_post_type() {

	$labels = array(
		'name'                  => _x( 'Sample Posts', 'Post Type General Name', 'text_domain' ),
		'singular_name'         => _x( 'Sample Post', 'Post Type Singular Name', 'text_domain' ),
		'menu_name'             => __( 'Sample Posts', 'text_domain' ),
		'name_admin_bar'        => __( 'Sample Post', 'text_domain' ),
		'archives'              => __( 'Item Sample Posts', 'text_domain' ),
		'parent_item_colon'     => __( 'Parent Sample Post:', 'text_domain' ),
		'all_items'             => __( 'All Sample Posts', 'text_domain' ),
		'add_new_item'          => __( 'Add New Sample Post', 'text_domain' ),
		'add_new'               => __( 'Add New Sample Post', 'text_domain' ),
		'new_item'              => __( 'New Sample Post', 'text_domain' ),
		'edit_item'             => __( 'Edit Sample Post', 'text_domain' ),
		'update_item'           => __( 'Update Sample Post', 'text_domain' ),
		'view_item'             => __( 'View Sample Post', 'text_domain' ),
		'search_items'          => __( 'Search Sample Post', 'text_domain' ),
		'not_found'             => __( 'Not found', 'text_domain' ),
		'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
		'featured_image'        => __( 'Sample Post Image', 'text_domain' ),
		'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
		'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
		'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
		'insert_into_item'      => __( 'Insert into sample post', 'text_domain' ),
		'uploaded_to_this_item' => __( 'Uploaded to this sample post', 'text_domain' ),
		'items_list'            => __( 'Sample Posts list', 'text_domain' ),
		'items_list_navigation' => __( 'Sample Posts list navigation', 'text_domain' ),
		'filter_items_list'     => __( 'Filter sample posts list', 'text_domain' ),
	);
	$args = array(
		'label'                 => __( 'Sample Post', 'text_domain' ),
		'description'           => __( 'Sample post type to use as an example for extending the REST API.', 'text_domain' ),
		'labels'                => $labels,
		'supports'              => array( 'title', 'editor', ),
		'hierarchical'          => false,
		'public'                => true,
		'show_ui'               => true,
		'show_in_menu'          => true,
		'menu_position'         => 5,
		'show_in_admin_bar'     => true,
		'show_in_nav_menus'     => true,
		'can_export'            => true,
		'has_archive'           => true,
		'exclude_from_search'   => false,
		'publicly_queryable'    => true,
		'capability_type'       => 'page',
	);
	register_post_type( 'sample_post_type', $args );

}
add_action( 'init', 'generate_sample_post_type', 0 );

/**
 * Helper function to get the post meta value
 */
function sample_post_type_metabox_get_meta( $value ) {
	global $post;

	$field = get_post_meta( $post->ID, $value, true );
	if ( ! empty( $field ) ) {
		return is_array( $field ) ? stripslashes_deep( $field ) : stripslashes( wp_kses_decode_entities( $field ) );
	} else {
		return false;
	}
}

/**
 * Generate and render our metabox, assign it to the sample_post_type
 */
function sample_post_type_metabox_add_meta_box() {
	add_meta_box(
		'sample_post_type_metabox-sample-post-type-metabox',
		__( 'Sample Post Type Metabox', 'sample_post_type_metabox' ),
		'sample_post_type_metabox_html',
		'sample_post_type',
		'normal',
		'default'
	);
}
add_action( 'add_meta_boxes', 'sample_post_type_metabox_add_meta_box' );

/**
 * Generate the HTML markup for the input text field in the metbox
 */
function sample_post_type_metabox_html( $post) {
	wp_nonce_field( '_sample_post_type_metabox_nonce', 'sample_post_type_metabox_nonce' ); ?>


WP REST API v2 Documentation Site

  • WordPress Plugins Repository
  • Torque Mag | REST API
  • WPMU DEV | WordPress REST API
  • REST API Definition
  • WP Tavern | REST API Powered Example
  • Human Made LTD.
  • Us Two | WP REST API Site Example
  • Leave a Reply

    Your email address will not be published.

    This site uses Akismet to reduce spam. Learn how your comment data is processed.