Paulund

Create Your Own WordPress Rest Endpoints

As the REST API is still relatively new there might be some endpoints that don't currently exist such as getting the post archives where you would normally use the function wp_get_archives. This function will return a list of months with the post count next to that month. In this tutorial we're going to create our own WordPress endpoint that returns a list of months along with the post count with that month.

First Create A WordPress Plugin

To create a WordPress plugin you just need to create a file inside the plugins folder and add the following comments to the top of the file.

/**
 * Plugin Name:       Paulund REST Post Archives
 * Plugin URI:        https://paulund.co.uk
 * Description:       Plugin to create a new restful endpoint to get month post archives
 * Version:           1.0
 * Author:            Paulund
 * Author URI:        https://paulund.co.uk
 * Text Domain:       paulund
 */

Create The PHP Class

All the plugins I create use PHP OOP this is because I find it easier to organise and handle the code. The first thing we need to create is the PHP class and the run method to start the plugin.

/**
 * Rest API Post Archives list
 */
class Rest_Post_Archives
{
    /**
     * Run WordPress filters
     */
    public function run()
    {
        
    }
}

$restPostArchives = new Rest_Post_Archives();
$restPostArchives->run();

The run() method is where we'll add any WordPress actions or filters we need to use. In this plugin we need to use the WordPress action rest_api_init which runs at the start of the REST API.

Register The Endpoint

To create a new Endpoint on your WordPress REST API you need to use the function register_rest_route. This accepts 4 parameters namespace, route, args and override. We're going to create a new endpoint with the route of posts/archives to return a list of months with the post count.


add_action( 'rest_api_init', function () {
    register_rest_route( 'wp/v2', '/posts/archives', array(
        'methods' => 'GET',
        'callback' => array($this, 'get_rest_post_archives'),
    ) );
} );

We now have a new endpoint that we can access with the URL http://example.com/wp-json/wp/v2/posts/archives.

Get The Rest Post Archives

Inside the registered route function we're using a callback of get_rest_post_archives this is the function we use to get the months and the post type within these months.


    /**
     * Get the post archives from rest api
     *
     * @param $request
     *
     * @return mixed|\WP_REST_Response
     */
    public function get_rest_post_archives( $request )
    {
        global $wpdb;

        $defaults = array(
            'type' => 'monthly', 'limit' => '',
            'format' => 'html', 'before' => '',
            'after' => '', 'show_post_count' => false,
            'echo' => 1, 'order' => 'DESC',
            'post_type' => 'post'
        );

        $r = wp_parse_args( $request, $defaults );

        $post_type_object = get_post_type_object( $r['post_type'] );
        if ( ! is_post_type_viewable( $post_type_object ) ) {
            return;
        }
        $r['post_type'] = $post_type_object->name;

        if ( '' == $r['type'] ) {
            $r['type'] = 'monthly';
        }

        if ( ! empty( $r['limit'] ) ) {
            $r['limit'] = absint( $r['limit'] );
            $r['limit'] = ' LIMIT ' . $r['limit'];
        }

        $order = strtoupper( $r['order'] );
        if ( $order !== 'ASC' ) {
            $order = 'DESC';
        }

        $sql_where = $wpdb->prepare( "WHERE post_type = %s AND post_status = 'publish'", $r['post_type'] );

        /**
         * Filters the SQL WHERE clause for retrieving archives.
         *
         * @since 2.2.0
         *
         * @param string $sql_where Portion of SQL query containing the WHERE clause.
         * @param array  $r         An array of default arguments.
         */
        $where = apply_filters( 'getarchives_where', $sql_where, $r );

        /**
         * Filters the SQL JOIN clause for retrieving archives.
         *
         * @since 2.2.0
         *
         * @param string $sql_join Portion of SQL query containing JOIN clause.
         * @param array  $r        An array of default arguments.
         */
        $join = apply_filters( 'getarchives_join', '', $r );

        $last_changed = wp_cache_get_last_changed( 'posts' );

        $limit = $r['limit'];

        $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date $order $limit";
        $key = md5( $query );
        $key = "wp_get_archives:$key:$last_changed";
        if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
            $results = $wpdb->get_results( $query );
            wp_cache_set( $key, $results, 'posts' );
        }

        return rest_ensure_response( $results );
    }

This code was taken from the function wp_get_archives and I've taken out the bits that we don't need like changing the type as we only want to work with months post count. ## Results

When the plugin is installed you'll have the new endpoint registered which you can access by navigating to /wp-json/wp/v2/posts/archives this will return a JSON of the months and post count.

[{
	"year": "2016",
	"month": "9",
	"posts": "10"
}, {
	"year": "2016",
	"month": "8",
	"posts": "3"
}, {
	"year": "2016",
	"month": "7",
	"posts": "6"
}, {
	"year": "2016",
	"month": "6",
	"posts": "2"
}, {
	"year": "2016",
	"month": "5",
	"posts": "12"
}, {
	"year": "2016",
	"month": "4",
	"posts": "7"
}, {
	"year": "2016",
	"month": "3",
	"posts": "6"
}, {
	"year": "2016",
	"month": "2",
	"posts": "5"
}, {
	"year": "2016",
	"month": "1",
	"posts": "4"
}]