Handling the front-end request.
Follow up
This post is a follow up from the previous one.
I had left the work the moment the front-end required the back-end an attachment image HTML code.
The Front to Back plugin will leverage the Theme Customizer to deliver a smooth live editing experience for the user and there is only so much that JavaScript can do.
The request
Copying some JavaScript lines from the afore-mentioned post here is the code requiring the WordPress back-end the HTML markup for an attachment image starting from its source, size and attribute:
var $ = require( './../globals/jQuery.js' ),
Backbone = require( './../globals/Backbone.js' ),
ftbData = require( './../globals/ftbData.js' );
module.exports = Backbone.Model.extend( {
get_attachment_image_from: function ( newSrc, size, attr ) {
var settings = {
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-NONCE', ftbData.nonce );
},
url: ftbData.rest_url_prefix + '/ftb/v1/markup/attachment',
data: {
newSrc: newSrc,
size: size,
attr: attr
},
dataType: 'json'
};
// return the promise to allow for client classes to handle it
return $.get( settings );
}
} );
An example request might be the one below:
GET /wp-json/ftb/v1/markup/attachment?newSrc=http%3A%2F%2Fwp.dev%2Fwp-content%2Fuploads%2F2016%2F03%2F150324154025-14-internet-cats-restricted-super-169.jpeg&size=&attr=class%3Dthumbnail-id HTTP/1.1
Host: wp.dev
The URL will contain the encoded size, attribute and source information.
Setting up the back-end
The Front to Back plugin uses the DI52 dependency injection container to manage its components through service providing classes.
The FTB_ServiceProviders_RestApi
service provider is in charge of setting up the required addition to the REST API infrastructure introduced in WordPress 4.4:
<?php
class FTB_ServiceProviders_RestApi extends tad_DI52_ServiceProvider {
/**
* Binds and sets up implementations.
*/
public function register() {
$this->container->bind( 'FTB_Repositories_AttachmentInterface', 'FTB_Repositories_Attachment' );
$this->container->bind( 'FTB_RestAPI_Markup_AttachmentHandlerInterface', 'FTB_RestAPI_Markup_AttachmentHandler' );
add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) );
}
/**
* Binds and sets up implementations at boot time.
*/
public function boot() {
}
public function register_rest_routes() {
register_rest_route( 'ftb/v1',
'/markup/attachment',
array(
'methods' => 'GET',
'callback' => array( $this->container->make( 'FTB_RestAPI_Markup_AttachmentHandlerInterface' ), 'get_attachment_markup' ),
) );
}
}
The class will bind two concrete class implementations and add the /ftb/v1/markup/attachment
route along with the delegated handler; the route will be a read-only one and the handler will serve GET
requests only.
Serving the request
The method in charge of handling the request is the FTB_RestAPI_Markup_AttachmentHandler::get_attachment_markup
one; the relevant class code below:
<?php
class FTB_RestAPI_Markup_AttachmentHandler implements FTB_RestAPI_Markup_AttachmentHandlerInterface {
/**
* @var FTB_Repositories_AttachmentInterface
*/
protected $attachment_repository;
public function __construct( FTB_Repositories_AttachmentInterface $attachment_repository ) {
$this->attachment_repository = $attachment_repository;
}
public function get_attachment_markup( WP_REST_Request $request ) {
if ( ! current_user_can( 'edit_theme_options' ) ) {
return new WP_REST_Response( array( 'status' => 403, 'message' => 'Current user can\'t edit theme options' ), 403 );
}
$request_size = $request->get_param( 'size' );
$size = $this->get_size( $request_size );
$request_attr = $request->get_param( 'attr' );
$attr = $this->get_attr( $request_attr, $request_size );
$new_src = $request->get_param( 'newSrc' );
$html = $this->get_attachment_html( $new_src, $size, $attr, $request_size, $request_attr );
return $html;
}
/**
* @param $request_size
*
* @return array|mixed|string
*/
protected function get_size( $request_size ) {
if ( empty( $request_size ) ) {
$size = '';
return $size;
} else {
$size = array();
parse_str( $request_size, $size );
$size = count( $size ) === 2 ? $size : reset( $size );
return $size;
}
}
/**
* @param $request_attr
* @param $request_size
*
* @return array
*/
protected function get_attr( $request_attr, $request_size ) {
if ( empty( $request_attr ) ) {
$attr = array();
} else {
$attr = array();
parse_str( $request_attr, $attr );
}
$attr = ftb_merge_query_string_to_array( $attr, array( 'data-ftb-attr' => $request_attr, 'data-ftb-size' => $request_size ) );
return $attr;
}
/**
* @param $new_src
* @param $size
* @param $attr
*
* @return string
*/
protected function get_attachment_html( $new_src, $size, $attr, $request_size, $request_attr ) {
if ( empty( $new_src ) ) {
return ftb_get_the_post_thumbnail( $request_size, $request_attr );
} else {
$attachment_id = $this->attachment_repository->find_by_url( $new_src );
if ( empty( $attachment_id ) ) {
// try again re-fetching
$attachment_id = $this->attachment_repository->find_by_url( $new_src, true );
}
if ( empty( $attachment_id ) ) {
return ftb_get_the_post_thumbnail( $request_size, $request_attr );
}
return wp_get_attachment_image( $attachment_id, $size, false, $attr );
}
}
}
Of note here is the code in charge of verifying a user’s permission to get back some markup in the first place; this check is important as the REST API endpoint handle any request and only internal calls authenticated with the WordPress login cookie should come through.
if ( ! current_user_can( 'edit_theme_options' ) ) {
return new WP_REST_Response( array( 'status' => 403, 'message' => 'Current user can\'t edit theme options' ), 403 );
}
Was the request made by the JavaScript code missing that beforeSend
header set up the WordPress current user would always resolve to 0
: the unauthenticated and powerless visitor not capable of editing the theme options.
With that header set up the code wp_get_current_user
will return instead the real current cookie authenticated user.
To obtain the real markup code the class will rely on the FTB_Repositories_Attachment::find_by_url
method that will, in essence, try to find an attachment
post ID
from its source.
With the attachment ID, size and attribute the ftb_get_the_post_thumbnail
function will produce the required code that will be returned, json_encode
d, to the front-end by the REST API.
Next
Now that this code is in place it’s time to extend the code beyond a draft phase and tackle the planned Theme Customizer UI adjustments.