I’ve been working with the WordPress API lately, and while it’s certainly better than admin-ajax
, it still has a way to go. But, there’s enough there to begin integrating more JavaScript-based / headless CMS solutions.
However, one troublesome issue I’ve encountered is the lack of support for Featured Images out the gate.
Take the standard post endpoint for
GET /wp-json/wp/v2/posts
All you get back for Featured Media
is its id
and another endpoint reference for additional info.
[
"featured_media": 68,
"_links": {
"wp:featuredmedia": [
{
"embeddable": true,
"href": "http:\/\/stephenscaff.com\/wp-json\/wp\/v2\/media\/68"
}
],
}
]
Can I get the url?
Not wanting to make an additional request for each image, wouldn’t it be nice to have direct access to the Featured Image url within a single endpoint?
Well, there are 2 ways to do that – by appending _embed
at the end of our request, or by modifying the endpoint response via register_rest_field
hook.
1. _embed
By simply appending ?_embed
to our request:
GET /wp-json/wp/v2/posts?_embed
we now return an _embedded
node, containing a ton of stuff relating to the post’s Featured Image, including urls for the various available sizes.
[
"wp:featuredmedia": [
{
"id": 453,
"alt_text": "Hey Hey Hey",
"media_details": {
"width": 2000,
"height": 1200,
"file": "2017/07/post-nested.jpg",
"sizes": {
"medium": {
"file": "post-nested-1250x750.jpg",
"width": 1250,
"height": 750,
"mime_type": "image/jpeg",
"source_url": "http://stephenscaff.com/wp-content/uploads/2017/07/post-nested-1250x750.jpg"
}
...
}
}
}
]
Cool. We can work with that. But, what if you just need the image url (and would rather avoid all that nesting)?
2. register_rest_field
As it turns out, WP has a handy function called register_rest_field
that “registers a new field on an existing WordPress object.”
It accepts 3 params, $object type
, $attribute
, and $args (get_callback, update_callback, schema)
.
For our purposes, these params would consist of:
- $object type – our target endpoint (ie: ‘post’, ‘custom post type name’, etc).
- $attribute – ‘featured_image’
- array(‘get_callback’) – Callback function that gets a post’s Featured Image.
Here’s simple class to add Featured Images to our posts endpoints, in addition to a custom post type called ‘product’.
/**
* WpApiFeaturedImage
*
* Adds featured images to the products endpoint
* using register_rest_field hook.
*
* @version 1.0
* @author stephen scaff
*/
class WpApiFeaturedImage {
/**
* The endpoints we want to target
*/
public $target_endpoints = '';
/**
* Constructor
* @uses rest_api_init
*/
function __construct() {
$this->target_endpoints = array('product', 'post');
add_action( 'rest_api_init', array( $this, 'add_image' ));
}
/**
* Add Images to json api
*/
function add_image() {
/**
* Add 'featured_image'
*/
register_rest_field( $this->target_endpoints, 'featured_image',
array(
'get_callback' => array( $this, 'get_image_url_full'),
'update_callback' => null,
'schema' => null,
)
);
/**
* Add 'featured_image_thumbnail'
*/
register_rest_field( $this->target_endpoints, 'featured_image_thumbnail',
array(
'get_callback' => array( $this, 'get_image_url_thumb'),
'update_callback' => null,
'schema' => null,
)
);
}
/**
* Get Image: Thumb
*/
function get_image_url_thumb(){
$url = $this->get_image('thumbnail');
return $url;
}
/**
* Get Image: Full
*/
function get_image_url_full(){
$url = $this->get_image('full');
return $url;
}
/**
* Get Image Helpers
*/
function get_image($size) {
$id = get_the_ID();
if ( has_post_thumbnail( $id ) ){
$img_arr = wp_get_attachment_image_src( get_post_thumbnail_id( $id ), $size );
$url = $img_arr[0];
return $url;
} else {
return false;
}
}
}
new WpApiFeaturedImage;
This class will edit our response to now include the direct urls for featured_image
and featured_image_thumbnail
. Fairly painless yeah?
Note the helper method get_image($size)
for adding additional sizes. A smarter play might be to create a featured_image node, and nest the sizes within. But this worked best for my purposes at the time.
Feel free to snag the code from Github