A quick run down about extending the API (see notes inside, there aren’t many right now, I need to add more, that’s my bad).
This covers several scenarios and items that you may encounter yourself.
- Next Post
- Previous Post
- Getting the Featured Image
- Title
- Link
- ID
- Get the posts first image
- Get Next/Previous posts first image
- Getting custom fields
<?php
if( class_exists( 'WP_REST_Posts_Controller' ) ){
Class WP_REST_DT_Posts_Controller extends WP_REST_Posts_Controller {
/**
* WP_REST_DT_Posts_Controller constructor.
*/
public function __construct() {
parent::__construct( 'post' );
$this->namespace = 'deep-thoughts/v2';
}
/**
* Register our custom route
*
* We
*/
public function register_routes() {
register_rest_route( $this->namespace, '/posts', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
}
/**
* Get items to return in API call
*
* This method is used to override the parent get_items method so we can format,
* add custom fields, and return the data the way we want.
*
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
*/
public function get_items( $request ) {
/**
* Use parent get_items to pull all post data and retain support
* for all arguments
*/
$posts = parent::get_items( $request );
/**
* As long as data is returned, we can now loop through it and customize the output,
* add custom fields, etc.
*/
if ( $posts instanceof WP_REST_Response && isset( $posts->data ) && ! empty( $posts->data ) ) {
$new_post_data = [];
foreach ( $posts->data as $post_index => $post_data ) {
$new_post = [
'id' => $this->extract_post_data( 'id', $post_data ),
'title' => $this->extract_post_data( 'title', $post_data ),
'link' => $this->extract_post_data( 'link', $post_data ),
];
$featured_image = wp_get_attachment_url( $this->extract_post_data( 'featured_media', $post_data ) );
if ( $featured_image ) {
$new_post['featured_image'] = $featured_image;
}
// Current post image
$image_src = catch_post_image( $this->extract_post_data( 'content', $post_data ) );
if ( $image_src ) {
$new_post['image_src'] = $image_src;
}
// Next post image
if ( isset( $posts->data[ $post_index + 1 ] ) ) {
$next_post_data = $posts->data[ $post_index + 1 ];
$image_src = catch_post_image( $this->extract_post_data( 'content', $next_post_data ) );
if ( $image_src ) {
$new_post['Next_Post_Obj']['next_image_src'] = $image_src;
}
}
// Prev post image
if ( isset( $posts->data[ $post_index - 1 ] ) ) {
$prev_post_data = $posts->data[ $post_index - 1 ];
$image_src = catch_post_image( $this->extract_post_data( 'content', $prev_post_data ) );
if ( $image_src ) {
$new_post['Prev_Post_Obj']['prev_image_src'] = $image_src;
}
}
$new_post_data[ $post_index ] = $new_post;
$next_post = $posts->data[$post_index + 1];
$prev_post = $posts->data[$post_index - 1];
if ( ! empty( $next_post ) ) {
$new_post_data[ $post_index ]['Next_Post_Obj']['Next_ID'] = $next_post['id'];
$new_post_data[ $post_index ]['Next_Post_Obj']['Next_Title'] = $next_post['title'];
$new_post_data[ $post_index ]['Next_Post_Obj']['Next_Link'] = $next_post['link'];
}
if ( ! empty( $prev_post ) ) {
$new_post_data[ $post_index ]['Prev_Post_Obj']['Prev_ID'] = $prev_post['id'];
}
if ( function_exists( 'get_fields' ) ) {
/**
* Get specific ACF field
* Last argument in get_field set to FALSE to return unformatted value
*
* @see https://www.advancedcustomfields.com/resources/get_field/
*/
$new_post_data[ $post_index ]['_edit_lock'] = get_field( '_edit_lock', $post_data['id'], false );
/**
* Get all ACF custom fields and add to post data
*
* @see https://www.advancedcustomfields.com/resources/get_fields/
*/
$custom_fields = get_fields( $post_data['id'] );
// As long as there are custom fields, loop through each adding it to the new data to return
if ( ! empty( $custom_fields ) ) {
foreach ( $custom_fields as $custom_field_key => $custom_field_value ) {
$new_post_data[ $post_index ][ $custom_field_key ] = $custom_field_value;
}
}
}
/**
* You can also add any custom fields you want by using the core WordPress function.
* We surround the get_post_meta() function with maybe_unserialize() in case the value is a serialized array
*/
$new_post_data[ $post_index ]['_edit_lock_core'] = maybe_unserialize( get_post_meta( $post_data['id'], '_edit_lock', true ) );
}
$posts->data = $new_post_data;
}
return $posts;
}
/**
* Return value for specific key from passed data
*
* This method is used to return a value (if found in post data), or return
* an empty string if not found.
*
* @param $key
* @param $data
*
* @return mixed|string
*/
public function extract_post_data( $key, $data ) {
// If passed data is not an array, it's empty, or the requested key does not exist, return empty string
if ( ! is_array( $data ) || empty( $data ) || ! isset( $data[ $key ] ) ) return '';
// If value is not an array, go ahead and return the value
if ( ! is_array( $data[ $key ] ) ) {
return $data[ $key ];
} elseif ( array_key_exists( 'rendered', $data[ $key ] ) ) {
// If value is an array, chances are the value is under the 'rendered' key, if so return that value
return $data[ $key ][ 'rendered' ];
}
// All else fails, return empty string.
return '';
}
}
function catch_post_image( $post_content ) {
preg_match_all( '/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post_content, $matches );
$first_img = $matches [1] [0];
// no image found, return false
if ( empty( $first_img ) ) {
return false;
}
return $first_img;
}
/**
* Since we're extending the existing post API class, we need to initialize our
* class on the rest_api_init action
*/
add_action( 'rest_api_init', 'init_deep_thoughts');
/**
* Custom function to initialize our extending class. Used a function to make sure
* code is compatible with older versions of PHP (instead of using anonymous function)
*/
function init_deep_thoughts(){
$deep_thoughts = new WP_REST_DT_Posts_Controller();
$deep_thoughts->register_routes();
}
}