Atomic Smash homepage splash

Finding time for REST with the WordPress API – Part 2

Words by Anthony HartnellMay 17, 2017

Build a mock book shop using the Wordpress REST API

In this two part article I will demonstrate how to make use of the WordPress REST API by creating a custom endpoint to display and sort products in a mock book shop. Part 1 will explain the process of registering the endpoint and seeing some returned JSON in the browser. Part 2 will demonstrate how to assemble a dynamic filtering system using AJAX to populate a dropdown and redirect to the correct page.

1

Finding time for REST with the WordPress API – Part 1

In this two part article I will demonstrate how to make use of the WordPress REST API to build a mock book shop website with filtering capability.

2

Finding time for REST with the WordPress API – Part 2

In this final part of the series I will add Ajax and jQuery functionality to fetch data from the REST API route created in part 1 to create a dynamically driven filter.

Before I start working on setting up the Ajax functionality I will need to make sure that I can access the a single category on the url. When I registered the custom taxonomy I added a rewrite option to specify the taxonomy archive url:

'rewrite' => array( 'slug' => 'book-categories' ),

This means to access a single book category I can navigate to /book-categories/development and it will show posts from those custom taxonomies as seen in the image below.

Image of the single taxonomy archive page.

This leverages WordPress’ inbuilt loop to fetch the correct template and provides a really extensible template system. The twenty-seventeen theme uses index.php to display its loop. I want to override that in my plugin so I need to create a custom template for the single taxonomy template. Looking at the WordPress template hierarchy I can see that I need a file named taxonomy-$taxonomy.php:

Screenshot of WordPress Template Hierarchy

I could even create different templates for each term if I wanted using the taxonomy-$taxonomy-$term.php, e.g. taxonomy-book_category-development.php. I just need the overall taxonomy layout so have created a file called taxonomy-book_category.php inside the plugin and attached it to the template_include filter so it gets loaded with the plugin.

add_filter( 'template_include', 'as_add_book_category_archive' );
function as_add_book_category_archive( $template ) {

	if ( is_tax( 'book_category' )  ) {
		$new_template = dirname( __FILE__ ) . '/taxonomy-book_category.php';
		if ( '' != $new_template ) {
			return $new_template ;
		}
	}

	return $template;
}

Now I will copy the contents of the archive-book.php file into taxonomy-book_category.php so that when viewing the single category I can customise it with a back to collection button or similar. The code for these templates have been copied from the twentyseventeen theme.

Writing the filtering HTML

I now need to set about creating the HTML that will output the filtering capability and attach a little bit of functionality with jQuery to display a loading message and hide it once the results have been retrieved. Add the following code under the page header in archive-book.php:

<div class="filter-container">

	<div class="filter-loading">
		<h2>Loading filters...</h2>
	</div>

	<form class="filter-form" action="#" method="post">
		<h2>Filter by category</h2>
		<select class="category-filter" name="">
			<option value="">Choose a category...</option>
		</select>
	</form>
</div>

Here are the steps I need to achieve for the filter:

  • When I browse to /books I will see the loading filters message
  • When the categories data has been retrieved via AJAX (success), hide the filter message and show the filter form

Add these customisations to the css file to style the filters a bit:

.filter-loading,
.filter-container {
    margin: 0 auto 50px;
    max-width: 400px;
}

select.category-filter {
    width: 100%;
}

.filter-form {
    display: none;
}

On the page it will look like this:

Image of the category filter before styling.

I added a display: none to the filter-form which I will reveal using jQuery.

Adding the javascript

I created a folder called js and inside it a new file called as_ajax.js. This contains the code that will request my /book-categories url via AJAX. The value returned from the API is already in JSON format so if the AJAX function succeeds I can iterate over the results to create the HTML option fields I need for the filtering form. This means it is totally dynamic and I can trigger events to happen at certain times. For example, I can hide the loading filters message after I’ve built the HTML so there is no chance for the visitor to see an empty dropdown. Here is what the as_ajax.js file contains:

jQuery(document).ready( function() {
    jQuery.ajax({
        type: 'GET',
        url: '/wp-json/bc/v1/book-categories',
        dataType: 'JSON',
        success: function( response ) {

            var categoryOptions = '';

            // Iterate over each returned category to create the option
            jQuery.each( response, function( i, category ){
                categoryOptions += '<option value="'+ asAjax.book_categories_url + category.slug +'">'+ category.name +'</option>';
            });

            jQuery('.category-filter').append( categoryOptions );


        }
    });
});

Localize your variables

As you can see I have created an option field by concatenating HTML and the data from the categories. The dropdown will eventually redirect to the custom book_category taxonomy url that I mentioned before (/book-categories/) so how do I add that into the option without hard coding the address of the website and what is asAjax??

The answer to this question is localisation- a WordPress function that lets you to pass variables from PHP to javascript. I have localised a variable called asAjax which is essentially an object containing some properties. I have created two, one for the book_category taxonomy url and one for the site url which I’ll be using in the dropdown-redirect code later.

This function contains what you need to localize a script:

// Enqueue and localise the ajax javascript
add_action( 'init', 'as_script_enqueuer' );
function as_script_enqueuer() {

    wp_register_script( "as_ajax_script", plugin_dir_url( __FILE__ ) . '/js/as_ajax.js', array('jquery') );
    wp_localize_script( 'as_ajax_script', 'asAjax', array(
        'book_categories_url' => '/book-categories/',
        'site_url' => get_bloginfo( 'url' )
    ));

    wp_enqueue_script( 'jquery' );
    wp_enqueue_script( 'as_ajax_script' );

}

asAjax is accessible anywhere in the theme and you can see it between the script tags in the browsers View Source in inspector. Now I need to work on step 2. You can console log the success response to check data is coming through. If not there is possibly a typo in the url.

  • When I browse to /books I will see the loading filters message
  • When the categories data has been retrieved via AJAX (success), hide the filter message and show the filter form

Add this code before the end of the as_ajax.js success function:

// Hide the loading message
jQuery('.filter-loading').hide();

// Show the filters form
jQuery('.filter-form').show();

Add the filter redirect code

At the bottom of the as_ajax.js function (inside the jQuery ready function) I have added some javascript to set the window.location based on the dropdown. This is why I coded the options with the book categories url. My as_ajax.js file now contains this code:

jQuery(document).ready( function() {

    // Fetch categories and return html
    jQuery.ajax({
        type: 'GET',
        url: '/wp-json/bc/v1/book-categories',
        dataType: 'JSON',
        success: function( response ) {

            var categoryOptions = '';

            // Iterate over each returned category to create the option
            jQuery.each( response, function( i, category ){
                categoryOptions += '<option value="'+ asAjax.book_categories_url + category.slug +'">'+ category.name +'</option>';
            });

            // Append the new options to the category filter drop down
            jQuery('.category-filter').append( categoryOptions );

            // Hide the loading message
            jQuery('.filter-loading').hide();

            // Show the filters form
            jQuery('.filter-form').show();

        }
    });

    // Redirect the visitor from the filter drop down
	jQuery('.category-filter').on( 'change', function () {

        // Get the selected option value
		var single_taxonomy_url = jQuery(this).val();

        // Require a URL and redirect
		if( single_taxonomy_url ) {
			window.location = asAjax.site_url + single_taxonomy_url; // redirect
		}

		return false;
	});
});

Now I can see that the filter has been populated with data from the AJAX call

Image of the category filter after styling.

When I choose design it will redirect me to the Design single taxonomy. This is what the rendered HTML looks like in Google Chrome’s inspector

Screen shot of Chrome Developer Tools inspector window.

 

Updating the filter after the redirect

When I get redirected to the single taxonomy page, the filter looses its selection and this breaks the flow. This would be especially evident if I had a long list of options. I’ll fix that by comparing the id of the taxonomy in the dropdown with that of the post id of the page I’m on which is returned from WordPress.

 

I have updated taxonomy-book_category.php with this code:

<?php $term_slug = get_query_var( 'term' ); ?>

<form class="filter-form" id="ajax-filter-form" action="#" method="post" data-taxonomy-slug="<?php echo $term_slug; ?>">
    <h2>Filter by category</h2>
    <select class="category-filter">
        <option value="/books">Show all books...</option>
    </select>
</form>

And I have updated the javascript iteration loop with this:

var categoryOptions = '',
    currentTaxonomySlug = jQuery('.filter-form').data('taxonomy-slug');

// Iterate over each returned category to create the option
jQuery.each( response, function( i, category ){

    // Add selected to option if the slug matches the queried element
    if ( currentTaxonomySlug == category.slug ) {
        categoryOptions += '<option value="'+ asAjax.book_categories_url + category.slug +'" selected>'+ category.name +'</option>';
    } else {
        categoryOptions += '<option value="'+ asAjax.book_categories_url + category.slug +'"' + '>'+ category.name +'</option>';
    }
});

This now gives me the selected category as desired:

Summary

I hope this tutorial on the WordPress REST API has been useful and that it gives you some ideas about how you could use this in your website. By using the endpoint to fetch my data I have demonstrated that WordPress can detach itself from the view if necessary. This means that I could write the write an app if needed or just output the entire view in Javascript with Ember, Node, or Angular for example.

Ways I could improve this code:

  • Create a custom field allowing me to set a book as ‘Just in’ or ‘New’ and could append this to the category name returned in the JSON output.
  • The filter current redirects to browser window to the  taxonomy single archive- I could add another AJAX call to load this content in the same window
  • Add better css and loading spinners to streamline the visuals
  • Add some error handling on the plugin and AJAX code.
  • Add an admin interface to set some options

If you would like a copy of this code, please leave a comment below.

Profile picture of Anthony Hartnell

Anthony HartnellDeveloper

Anthony works in the development team and enjoys creating plugins and integrating maps, libraries and other APIs into Wordpress.

Go back to top

Keep up to date with Atomic news