Find popular posts with the WordPress REST API

Don’t use a plugin if you don’t have to. Especially for something so simple (and fun).

A frequent request we receive from clients is to include a “Most Viewed” or “Trending” posts list. WordPress itself doesn’t count page views and thus doesn’t offer an out-of-the-box method for finding popular posts. So what to do?

While Jetpack and other plugins offer this functionality we aim to limit the use of plugins to those truly essential so as to avoid unnecessary conflicts and performance issues. We want simple, effective solutions. So in this case I built one, and I opted to use the WP REST API to do so.

Since all I needed was a way to count each time a post was viewed, I used register_rest_route() to create a new endpoint. When a GET request is made to this endpoint a callback function is run, which does the following:

  1. Accepts the post ID that was passed as part of the GET request URL
  2. Gets the value of that post’s “views” post meta field
  3. Adds 1 to the current value and then saves the new value

Here’s the actual code (add to functions.php or a plugin) to accomplish this:

add_action( 'rest_api_init', function () {
  register_rest_route( 'base', '/views/(?P<id>\d+)', array(
    'methods' => 'GET',
    'callback' => 'post_view_counter_function',
  ));
});function post_view_counter_function( WP_REST_Request $request ) {
  $post_id = $request['id'];if ( FALSE === get_post_status( $post_id ) ) {
    return new WP_Error( 'error_no_post', 'Not a post id', array( 'status' => 404 ) );
  } else {
    $current_views = get_post_meta( $post_id, 'views', true );
    $views = $current_views + 1;
    update_post_meta( $post_id, 'views', $views );
    return $views;
  }
}

To make the GET request I added this jQuery snippet in the single post template (this assumes you have added the post ID as a data-attribute on an element with the post-article class):

$( document ).ready(function() {var postid = $( ".post-article" ).attr( "data-postid" );$.get( "https://websiteurl.com/wp-json/base/views/" + postid);
});

That’s all there is to it! The GET request doesn’t need to actually return any data to the requester (though for the sake of testing, the code above returns the current number of views). It’s simply a way to ping the website and tell it to +1 the current post’s views.

Benefits of this approach include:

  1. Unlike a POST request, no authentication is required.
  2. Using jQuery for the GET request ensures that it runs every time a post is viewed, even if the viewer is seeing the cached page (which would not be true if using PHP).
  3. It’s a fun use case for the REST API!
  4. Now it’s easy to make a query for the most popular posts by including ‘meta_key’ => ‘views’ and ‘orderby’ => ‘meta_value_num’ as query arguments.

An easy-to-implement, lightweight solution for the win!