{ Rest API Custom Endpoints }

WordPress’s API allows us to create a JSON endpoint for pretty much anything we want. So many of the tutorials online show how to use REST in a plugin context, but it can be incredibly useful for custom themes as well.

Here’s an example of a class I use to get started:

Starting with the constructor, we use it to hook into the rest_api_init action. Any route customizations need to be done through this hook.

public function __construct() {
   add_action( 'rest_api_init', function() {
      $this->registerRoutes();
      $this->disableUserRoutes();
   } );
}

The disableUserRoutes method is specifically for WP 4.7+ where the WP API is baked into the core. It exposes some public routes that we may not want to, especially /wp/v2/users. This allows anyone to get a list of the users on your site, including the admin user! If you’ve followed the usual security considerations and given your admin user a name other than “admin” (which you’ve done right?), this route gives ammo to potential brute force attacks, so we shut it off until the WP team patches it or adds an authorization requirement.

getTestimonial assumes we have a testimonial custom post type, and want to return specific fields from one of them based on its ID.

$queryArgs = [
   'p' => $pId,
   'post_type' => 'testimonial'
];

The “p” arg is simply referring to the post ID, which makes the request simple as we just want to return one post.

$rawMeta = get_post_custom( $post->ID );
$rawMetaKeys = array_keys( $rawMeta );

$metaKeys = array_filter( $rawMetaKeys, function( $item ) {
   return strpos( $item, '_', 0 );
});

foreach ( $metaKeys as $metaKey ) {
   $data[$metaKey] = get_post_meta( $post->ID, $metaKey, true );
}

Since I’m going to use all of the fields (including custom meta fields), I’m looping through all of them here and filtering out the WP internal fields (ones that start with _, which we don’t want here). Then we return the resulting $data using rest_ensure_response() which encodes it as JSON for us. No need for a WP_AJAX wp_die() or exit at the end here.

At this point, we can call the new route

http://ourdomain.com/wp-json/theme-api/v1/selectedTestimonial/X

with a front end tool of our choice where X is the ID and we will receive the testimonial post as XHR data. In my case I used React and Axios. It’s a promise-based API that is pretty simple to use, and abstracts away the need to write all of the low-level AJAX routines. Jason Arnold on Medium wrote a great article on the differences.

If using React, we can add a “mount point” for the component in the PHP/HTML template:

<div class="js-mount-point" id="testimonialMount"></div>

Then we need a data store of sorts, this is an excerpt of one using Axios:

RestData.js

themeRestApi is a global passed in with WP’s wp_localize_script(). I use it to find the post information I need and inject it into the script. This can be done with something as simple as the functions.php file in a wp_enqueue_assets() action.

Here’s the (simplified) testimonial container component:

testimonial-container.js

.. and then our “dumb” or stateless component:

testimonial.js

Together they are a simple example of displaying a custom post with React. We don’t actually need the Testimonial.propTypes object literal, as we are relying solely on state in this instance. However, in case I did want to extend the components to support passing props in, it’s in place.

More details on how these are implemented to come, with detailed documentation.