WP REST API Query 00

Exploring the idea of a REST API powered WordPress query.

A use case

The WordPress REST API is all the rage now for very good reasons.
The main one being the possibility to serve content created using WordPress excellent back-end to any consuming application; WordPress themes and plugin being just one of the possible applications consuming that data.
But my ball park really is WordPress and I ask myself “How could this amazing piece of software benefit me while developing a WordPress theme?”.
Say I have to implement an archive loop and have set with a dumbed down version of TwentySixteen theme one:

<?php
get_header(); ?>

    <div id="primary" class="content-area">
        <main id="main" class="site-main" role="main">

        <?php if ( have_posts() ) : ?>

            <header class="page-header">
                <?php
                    the_archive_title( '<h1 class="page-title">', '</h1>' );
                    the_archive_description( '<div class="taxonomy-description">', '</div>' );
                ?>

                // This is relevant!
                <?php get_template_part( 'template-parts/archive-search' );

            </header><!-- .page-header -->

            <div id="content-area">
                <?php
                while ( have_posts() ) : the_post();

                    get_template_part( 'template-parts/content' );

                endwhile;

                the_posts_pagination( array(
                    'prev_text'          => __( 'Previous page', 'twentysixteen' ),
                    'next_text'          => __( 'Next page', 'twentysixteen' ),
                    'before_page_number' => '<span class="meta-nav screen-reader-text">' . __( 'Page', 'twentysixteen' ) . ' </span>',
                ) );

                else :
                    get_template_part( 'template-parts/content', 'none' );

                endif;
                ?>
            </div><!-- #content-area -->

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

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

This is pretty classic WordPress theme code but the site header has a search form; see this call in the loop header:

<?php get_template_part( 'template-parts/archive-search' );

Classic as it goes the search form user flow would be:

  • user enters search string
  • user hits search submit button
  • WordPress submits the search form
  • user sees page reloading while…
  • WordPress processes the search string
  • WordPress finds the corresponding posts
  • WordPress returns the found posts
  • WordPress re-renders the page with search results
  • user sees the page refreshed

But we do not want to reload the entire page when searching an archive and would like to tap into the amazing (no puns here) powers of the WordPress REST API to have a flow like this one instead:

  • user enters search string
  • user hits search submit button
  • WordPress submits the search form with an AJAX request to a RESTful address
  • user sees the content fade out and a spinner coming up while…
  • WordPress REST API processes the search string
  • WordPress REST API finds the corresponding posts
  • WordPress REST API returns the found posts
  • the JS callback function receives the data for the search results
  • JS re-renders the content ares
  • user sees the content area refreshed

Now this is Web 2.0.

Templates

If I know a thing about JavaScript (and I know two so I have an easy game here) is that the following points:

  • the JS callback function receives the data for the search results
  • JS re-renders the content ares

will roll out like this in more detail

  • the JS callback (JS) evaluates the response status
  • if successful (have at least one post) take hold of the content template string
  • else take hold of the empty content template string
  • spin up the JS template engine of choice (Handlebars, Mustache, BackBone…)
  • feed the template engine the template and the data
  • get the output from the template engine
  • print the output in the content area (inside #content-area)

So I have two version of each template here for a total of 4 templates:

  • template-parts/content.php to render the loop with PHP when there is some content
  • template-parts/content-none.php to render the loop with PHP when there is no content
  • a JavaScript template to render the loop with JS when there is some content
  • a JavaScript template to render the loop with JS when there is no content

Using a simple conditional in the template would but reduce that number to 2:

  • template-parts/content.php to render the loop with PHP
  • a JavaScript template to render the loop with JS

Ways out

Where the flow above cringes is in scale and maintenance.
Keeping the two templates versions in sync is a chore and the template logic in PHP and JS might differ greatly.
A first way to do it would be to simply go through the double maintenance and buckle up in an epic exercise of repetition.
A second option is to stick with one technology only and since I’m trying to move away from PHP that would be JavaScript: I will leave the #content-area initially empty and fill it with JavaScript triggering a first REST API request as soon as the document is ready and filling the gap.
Appealing, easy but not accessible and gracefully degrading as flying car.

Leveraging template engines

What if I did use Handlebars?
It comes in JS and PHP fashion and being logic-less I will take care of keeping data manipulation out of it.
I can come up with a simple template like this one:

{{#if posts}}
    <ul>
    {{#each posts}}
        <li>{{post.title}}</li>
    {{/each}}
    </ul>
{{else}}
    <p>Nothing found!</p>
{{/if}}

The template would be fed the posts array both in PHP and JS and do its job.
The problem lies in data format:

  • in PHP each object in a posts result array is an instance of WP_Post and the title of the post is accessible, in Handlebars, using {{post.post_title}}
  • in JS each object in a REST API result array is a JSON object and the title of the post is accessible, in Handlebars, using {{post.title.rendered}}

Adding conditionals here would make it:

{{#if posts}}
    <ul>
    {{#each posts}}
        <li>
            {{#if post.post_title}}
                {{post.post_title}}
            {{/else}}
                {{post.title.rendered}} 
            {{/if}}
        </li>
    {{/each}}
    </ul>
{{else}}
    <p>Nothing found!</p>
{{/if}}

But this approach kinda defeats the purpose of “uncomplicating” maintenance and lends itself, when thought in scale, to the frantic creation of helpers that have to be maintained on both languages.

Data and data format

While the data is the same the format is different and those differences make the latter less appealing.
Since the JavaScript side cannot be fed anything but the REST API Json format response would it not be nice to have PHP return the data in exactly the same format?
It does. Partially.
The REST API is, in its “find me some posts” function, a wrapping around WP_Query and the returned data is modified after a classic WP_Query instance found the requested posts.
On the PHP side of things:

  • prepare the query
  • execute the query
  • return an array of WP_Post objects

While on the REST API side:

  • prepare the query
  • execute the query
  • return an json_encoded version of an array of post objects (plus some data)

Conclusion (or rather “my next crappy idea”)

What if a vanilla WP_Query could be told to return data, in PHP, in the same format as the REST API would?
I will, of course, explore the possibility with code and crash-land or fly free in the process.