HOW TO: Extend the WordPress REST API (with block support)

January 3, 2021

What is this for?

WordPress has native REST API support that includes a response for default data (ie. Posts, Pages, Tags, etc.). In order to support a more personalised and granular set of values to an external app, we're going to add additional fields in the Gutenberg editor using Advanced Custom Fields and make them available over the REST API (ie. /wp-json/wp/v2/).

For the purposes of this guide, we will be adding a New Customer Notice field and an associated block. We will first include the New Customer Notice field data in a response from /wp-json/wp/v2/ (without displaying it on the frontend rendered HTML). The idea behind the New Customer Notice field is that the external app will only display this content to users who are new customers.

Secondly, we will modify WordPress to expose the new field to the REST API for all posts. With this method we can make it easy to provide additional content not contained in the post body to an external application - where display logic can be configured to show/hide relevant information to various segments of site visitors, using structured JSON instead of HTML.

Configure the Custom Field in WordPress

  • In Advanced Custom Fields, add a new Field Group.
  • Name the Field Group and click Add Field.
  • Enter a unique Field Label (the Field Name will auto-populate), and click Publish.
  • The field will now appear when creating/editing posts.

Extend the REST API to include the field data

Now that the field is setup and will appear when creating/editing posts, we need to expose the field data to the REST API.

Add this snippet to a new plugin/mu-plugin, or simply add it to your /wp-content/themes/[YOUR_THEME]/functions.php file:

// Add new_customer_notice field to rest
function register_new_customer_notice_api_field(){
 register_rest_field('post', 'new_customer_notice',
 array(
 'get_callback' => 'get_new_customer_notice_api_field',
 'schema' => null,
 ));
}
add_action('rest_api_init', 'register_new_customer_notice_api_field');

// Add the call back for the REST API
function get_new_customer_notice_api_field($post){
 return get_field('new_customer_notice', $post['id']);
}

Check the API response

After saving a new post with some data in the New Customer Notice field you should be able to see it return in a standard post response (ie. https://YOUR_DOMAIN.COM/wp-json/wp/v2/posts) to be handled by
any external app as needed.

BONUS ROUND: Add Gutenberg Block support

This method requires Advanced Custom Fields PRO

Instead of having the custom fields show up at the bottom of the Gutenberg editor, outside the body - we can actually create a block instead.

To create the block, add this snippet to a new plugin/mu-plugin, or add it to your /wp-content/themes/[YOUR_THEME]/functions.php file:

// Add a block for new_customer_notice
// The render_template value in the array is optional (for rendering in page HTML)
add_action('acf/init', 'new_customer_notice_acf_init_block_types');
function new_customer_notice_acf_init_block_types() {
 // Check function exists.
 if( function_exists('acf_register_block_type') ) {
 // register a customer block.
 acf_register_block_type(array(
 'name' => 'new_customer_notice',
 'title' => __('New customer notice'),
 'description' => __('Only displays to new visitors.'),
 'render_template' => 'template-parts/blocks/new_customer_notice.php',
 'category' => 'formatting',
 'icon' => 'admin-comments',
 'keywords' => array( 'new customer', 'new' ),
 ));}
}

Modify the New Customer Notice custom field so it’s associated with the new block (instead of a field below the Gutenberg editor body):

The field will no longer be exposed over the REST API now that it's registered as a block - so replace the original snippet if present (from the Extend the REST API to include the field data section) and add this instead to expose blocks over REST:

add_action(
 'rest_api_init',
 function () {
 if ( ! function_exists( 'use_block_editor_for_post_type' ) ) {
 require ABSPATH . 'wp-admin/includes/post.php'; }
 
// Expose Gutenberg blocks in the WordPress REST API
 $post_types = get_post_types_by_support( [ 'editor' ] );
 foreach ( $post_types as $post_type ) {
 if ( use_block_editor_for_post_type( $post_type ) ) {
 register_rest_field(
 $post_type,
 'blocks',
 ['get_callback' => function ( array $post ) {
 return parse_blocks( $post['content']['raw'] );},]
 );}}}
);

OPTIONAL: Render the block on the WordPress frontend

If you want to render the block in the WordPress frontend, rather than relying on an external app you can add this file - which you declared earlier when registering the block - /wp-content/themes/[THEME]/template-parts/blocks/new_customer_notice.php and add this snippet:

<?php
// Render the block in the page (and REST) HTML
$text = get_field('new_customer_notice', $post['id']);
echo '<div class="new_customer_notice">';
 if( !empty( $text ) )
 echo $text;
echo '</div>';