Atomic Smash homepage splash

Finding time for REST with the WordPress API – Part 1

Words by Anthony HartnellApril 7, 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.

WordPress has shown the community that it is moving towards becoming a fully-fledged application framework since its release of version 4.7 by incorporating a REST API in its core. REST stands for Representational State Transfer and is a model that makes certain site data like posts, categories and search functions available as JSON through web requests known as HTTP endpoints.

Prior versions could only achieve this through plugins and now we will expect to see the API mature and evolve to provide powerful and flexible functionality, further cementing WordPress as an industry standard Website CMS Framework.

Setting up shop

In this mock scenario I will build an imaginary book catalogue website with the ability to view a collection of books and provide a way to filter by category. To begin with I’ve set up a basic WordPress site using the default twentyseventeen theme and have registered a custom post type called book with an assigned custom taxonomy called book_categories. I have wrapped the following code inside a plugin to allow me to integrate it easily into the theme and as such I can update it easily if it’s shared across multiple sites.

// Create 'book' custom post type
add_action( 'init', 'as_book_custom_init' );
function as_book_custom_init() {
    $args = array(
        'public' => true,
        'label'  => 'Books',
        'has_archive' =>  true,
        'rewrite' => array( 'slug' => 'books' ),
    );
    register_post_type( 'book', $args );
}

// Create 'book category' custom taxonomy
add_action( 'init', 'as_create_book_tax' );
function as_create_book_tax() {
	register_taxonomy(
		'book_category',
		'book',
		array(
			'label' => __( 'Book Category' ),
			'rewrite' => array( 'slug' => 'book-categories' ),
			'hierarchical' => true,
		)
	);
}

This has created our required menu:

Custom Post Type Registration

To display the archive of books i’ll first take a look at the WordPress Template Hierarchy which visually demonstrates how WordPress templates are interpreted and constructed. Orange parts of the template show the filename structure needed to override standard WordPress templates.

The archive template I need is shown here so I will need to create archive-book.php:

I will now create some new book posts and categories and assign each one as demonstrated here:

Displaying a collection of books

I next need to create the archive to render the posts in this post type. As this is included in a plugin, I need to let WordPress know about it by attaching it to the archive template filter:

// Hook into the archive template filter
add_filter( 'archive_template', 'as_add_book_archive' );
function as_add_book_archive() {

    global $post;

    if ( is_post_type_archive ( 'book' ) ) {
        $archive_template = dirname( __FILE__ ) . '/archive-book.php';
    }

    return $archive_template;
}

I then added the following code to archive-book.php to render the template:

<?php get_header(); ?>

<div class="wrap">

	<?php if ( have_posts() ) : ?>
		<header class="page-header">
            <h1 class="page-title">Our Collection</h1>
		</header>
	<?php endif; ?>

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

		<div id="books-container">

			<?php
			/* Start the Loop */
			while ( have_posts() ) : the_post(); ?>

			<div class="book">
				<h2><?php echo the_title(); ?></h2>
				<?php
				$terms = get_the_terms( get_the_id(), 'book_category' );

				foreach ($terms as $term) {
					echo '<p>' . $term->name . '</p>';
				}
			 	?>
			</div>

			<?php endwhile; ?>

		</div>

	<?php endif; ?>
</div>
<?php get_footer();

I also enqueued some css to apply some basic styling. Here is the css:

.book {
    border: 1px solid black;
    width: 42%;
    float: left;
    margin: 20px;
    padding: 20px;
}

.book:nth-child(odd) {
    margin-left: 0;
}

.book:nth-child(even){
    margin-right: 0;
}

The result is a collection of books each with their assigned categories underneath:

Build your own simple WordPress admin plugin

Get started

Setting up the endpoint

Firstly it may be best to remove the default endpoints that come with the WordPress REST API. This is more for peace of mind that you can start with a clean slate and to keep the code as separate as possible. You can do this with:


remove_action( 'rest_api_init', 'create_initial_rest_routes', 0 );

Next i’ll create an action that uses a callback to register new REST routes:

add_action( 'rest_api_init', function() {

    register_rest_route( 'bc/v1', '/book-categories', array(
        'methods' => array('GET'),
        'callback' => 'api_book_categories'
    ));

});

The register_rest_route function takes 3 arguments, the namespace, the route and the options. Namespaces are used for vendor/package prefixes to avoid clashes between custom routes. Namespaces generally follow the pattern of vendor/v1 – in this example I use bc/v1 to denote bookcatalogue and version 1 of the api. The next argument is the route which will be any name of your choosing. It’s best practise to use hyphens on the route name so the web crawler in the search engine knows to index individual word; an underscore translates to a word character meaning it would be considered part of a word.

Finally the options are passed in as an array – the callback option relates to a function that I will create below:

// Build the api endpoint to get the categories
function api_book_categories( WP_REST_Request $request ) {

    $terms = get_terms(
        array(
            'taxonomy' => 'book_category',
            'hide_empty' => true
        )
    );

	if ( empty( $terms ) ) {
		return new WP_Error( 'bookcatalogue_no_categories', 'Invalid category', array( 'status' => 404 ) );
	}
    
	return $terms;
}

Now to visit the endpoint I append wp-json to the url followed by the route url. This will be wp-json/bc/v1/book-categories

Unless there is an error you will get back some formatted json like this:

I am using a free chrome extension called JSON Formatter which makes it more readable in browser. Install it here: https://github.com/callumlocke/json-formatter 

 

 

 

 

 

 

 

 

What's covered in Part 2

In the next and final part I will create a WordPress AJAX request to retrieve the available book categories to build the dynamic filter.

Continue reading
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