Front to Back – second iteration – 04

Retrieving markup from the REST API infrastructure, the JavaScript code.

Quick recap

In my last post I’ve tackled the issue of allowing for the live edit of the post thumbnail within the Front to Back plugin.
The live editing happens in the Theme Customizer and implementing it requires some front end and backend communication.

The template

The Front to Back plugin is meant to be a developer tool.
As such it does not work as a theme builder delegating layout and page components to anyone with administration rights but produces page specific template files in the current theme root folder.
The starting template I’ve used to test the featured image live editing is this one, it’s the ftb-templates/about-us.php file in the theme root folder

<?php
get_header(); ?>

<div id="primary" class="content-area" xmlns="http://www.w3.org/1999/html">
    <main id="main" class="site-main" role="main">
        <?php while ( have_posts() ) : the_post(); ?>

            <article>
                <header class="entry-header">
                    <h1 class="entry-title">
                        <ftb-title element=".entry-title">About us</ftb-title>
                    </h1>
                </header><!-- .entry-header -->

                <div class="featured-image">
                    <ftb-featured-image attr="class=thumbnail-id" size="full"></ftb-featured-image>
                </div>

            </article><!-- #post-## -->

        <?php endwhile; ?>

    </main><!-- .site-main -->

    <?php get_sidebar( 'content-bottom' ); ?>

</div><!-- .content-area -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Using the ftb-* markup tags I’m telling WordPress I want the user to be able to edit the page title and featured image in the Theme Customizer. The generated page template is the page-about-us.php file, located in the theme root folder, and has the following code:

<?php get_header(); ?><div xmlns="http://www.w3.org/1999/html" id="primary" class="content-area">
    <main id="main" class="site-main" role="main">
        <?php while ( have_posts() ) : the_post(); ?>

            <article>
                <header class="entry-header">
                    <h1 class="entry-title">
                        <?php the_title(); ?>
                    </h1>
                </header><!-- .entry-header -->

                <div class="featured-image">
                    <?php ftb_the_post_thumbnail( 'full', array( 'class' => 'thumbnail-id' ) ); ?>
                </div>

            </article><!-- #post-## -->

        <?php endwhile; ?>

    </main><!-- .site-main -->

    <?php get_sidebar( 'content-bottom' ); ?>

</div><!-- .content-area -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>

Not different from many WordPress templates then but for the use of the ftb_the_post_thumbnail template tag: this will take care of returning either the post thumbnail markup or an empty img tag should the post thumbnail not be set.
The Theme Customizer editing section looks like this: Page title and thumbnail edit

Live editing, the JavaScript side

To “live edit” the post thumbnail, or any attachment for the matter, I’m triggering a request to the WordPress backend to obtain the attachment HTML code; the Kirky library control I’m using for the featured image is the image one and when a user edits the featured image in the Theme Customizer the JavaScript callback will be passed two arguments:

  • the jQuery selector identifying the changing element
  • the new image src or none if the image is removed

I’ve set up the Kirky library to use the FTB.Attachments.replace JavaScript callback when editing the featured image and here it is in its webpack context

var $ = require( './../globals/jQuery.js' ),
    Backbone = require( './../globals/Backbone.js' ),
    Events = require( './Events.js' ),
    Backend = require( './Backend.js' );

module.exports = Backbone.Model.extend( {

    events: Events,

    backend: new Backend(),

    replace: function ( element, newSrc ) {
        var $element = $( element ), size, attr, html, self = this;

        $element.each( function () {
            $this = $( this );

            // tell anything listening we are going to replace an image
            self.events.trigger( 'ftb.attachment.replace_src.before', element, newSrc );

            // the `ftb_the_post_thumbnail` template tag will add these two data attributes to the markup
            size = $this.data( 'ftb-size' );
            attr = $this.data( 'ftb-attr' );

            // require the new HTML from the backend...
            html = self.backend.get_attachment_image_from( newSrc, size, attr ).success( function ( html ) {

                // something went wrong, abort
                if ( html === false ) {
                    return;
                }

                //... and on success replace it
                $this.replaceWith( html );

                // tell anything listening we have replaced the attachment HTML 
                self.events.trigger( 'ftb.attachment.replace_src.after', element, newSrc, html );

        } );
    }
} );

The Backend object abstracts backend communications for other classes:

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 classe to handle it
        return $.get( settings );
    }

} );

The beforeSend function sets the X-WP-NONCE header to a nonce that’s localized in the ftbData object; such nonce is generated with a wp_create_nonce( 'wp_rest' ) call.
The dataType is set to json and not html due to the fact that the REST API infrastructure will json_encode anything before it’s returned and setting the dataType to json grants the response will be properly decoded upon arrival.

Next

I will dive into the backend side of things to have the featured image live editing fully working.