Front to Back – second iteration – 05

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_encoded, 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.

I appreciate your input