4 min read

Get The Most Popular Posts From The WordPress API

Get The Most Popular Posts From The WordPress API

As of right now the WordPress plugin directory holds 40,367 plugins. Finding the one you need is typically pretty easy with the hardest part choosing which one suits your needs the best.

In my particular use case, I am building a new section on a site that will be completely outside of WordPress. Even though it’s outside WordPress, I still wanted to pull in a list of the most popular posts.

Searching for most popular in the plugin directory returned 614 different plugins, but I couldn’t find any that would work in this context. A lot of them do their calculations by literally storing views for each visit. I see no reason to fill up my database with this data when an external system is already logging it. That is when I remembered WordPress has it’s own API and can be utilized directly from the Stats package.

I went on a mission to implement this and wanted to share how to do it. Before we get to the code you should create a new app which is used to generate an OAuth token. This OAuth token is required because it is used to authenticate requests to the API. Once your app is setup, it’s time to create a token.

Create an Authentication Token

The WordPress OAuth2 docs outline all the instructions for generating tokens with a client/server. We can bypass this by creating a token as the client owner.

The docs say, “As the client owner, you can authenticate with the password grant_type, allowing you to skip the authorization step of authenticating, instead logging in with your WordPress.com username and password. Note that if you are using 2-step authentication (highly recommended), you will need to create an application password to be able to use the password grant_type.”

Create a new PHP file and insert their sample code:

$curl = curl_init( 'https://public-api.wordpress.com/oauth2/token' );
curl_setopt( $curl, CURLOPT_POST, true );
curl_setopt( $curl, CURLOPT_POSTFIELDS, array(
    'client_id' => your_client_id,
    'client_secret' => your_client_secret_key,
    'grant_type' => 'password',
    'username' => your_wpcom_username,
    'password' => your_wpcom_password,
) );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1);
$auth = curl_exec( $curl );
$auth = json_decode($auth);
$access_key = $auth->access_token;
var_dump($access_key);

Be sure and replace out the CURLOPT_POSTFIELDS array with your credentials.

Now when you run this in the browser, it will spit out an auth token that we can utilize in our script.

Creating the API Class

Now that we have a token it’s time to start building a new class to handle the API request, but first how do we want to call it?

I decided on this as a good way of pulling in the popular posts:

$popular = (new WordPressApi())->popular();

Now it’s time to create our WordPressApi class. To start let’s just implement the basic structure:

<?php

class WordPressApi
{
    public function popular()
    {
        //..   
    }
}

That will satisfy the desired code, but as you guessed, it doesn’t do anything useful. Let’s dig in and figure out what needs to be done to pull these out.

Building the API Call

The top-posts page in the documentation outlines everything needed and even a sample CURL request.

From that page the required features we need are:

  • URL: https://public-api.wordpress.com/rest/v1.1/sites/$site/stats/top-posts
  • $site: The site’s id or domain
  • period: day, week, month, year
  • max: The maximum number of results to return Default: 10.

Then the example CURL is:

$options  = array (
  'http' => 
  array (
    'ignore_errors' => true,
    'header' => 
    array (
      0 => 'authorization: Bearer YOUR_API_TOKEN',
    ),
  ),
);

$context  = stream_context_create( $options );
$response = file_get_contents(
    'https://public-api.wordpress.com/rest/v1.1/sites/82974409/stats/top-posts',
    false,
    $context
);
$response = json_decode( $response );

Now it’s just a matter of implementing this into our class and returning the results.

Adjusting the API Class

For our final piece we need to setup the API URL, implement the CURL call, and finally return the results. Here is an updated class:

<?php

class WordPressApi
{
    private $site_id = 'your_site_id'; // The site's id or domain
    private $token = 'your_api_token';
    private $baseUrl;

    public function __construct()
    {
        $this->baseUrl = 'https://public-api.wordpress.com/rest/v1.1/sites/'.$this->site_id.'/';
    }

    public function popular($period = 'month', $max = 8)
    {
        return $this->getJson($this->baseUrl.'stats/top-posts?period='.$period.'&max='.$max);
    }

    public function getJson($url)
    {
        $options = [
            'http' => [
                'ignore_errors' => true,
                'header' => [
                    0 => 'authorization: Bearer '. $this->token,
                ]
            ]
        ];
        $context  = stream_context_create($options);
        $response = file_get_contents($url, false, $context);
        return json_decode( $response );
    }
}

If we now call this with our original code:

$popular = (new WordPressApi())->popular();
var_dump($popular);die;

It returns an object like this:

WordPress Popular Posts Results

That isn’t something that is easy to loop through in our view so ideally it should be cleaned up. Let’s adjust our popular method and return just the list of postviews:

public function popular($period = 'month', $max = 8)
{
    $data = $this->getJson($this->baseUrl.'stats/top-posts?period='.$period.'&max='.$max);
    foreach ($data->days as $key => $value) {
        return $value->postviews;
    }
}

Now we have a list of the most popular, however, there is another problem. These results include both pages and posts. If your site is anything like mine, then the home page gets a lot of visits and is always toward the top of the list. Let’s adjust this method one more time to filter out any pages by utilizing array_filter:

public function popular($period = 'month', $max = 8)
{
    $data = $this->getJson($this->baseUrl.'stats/top-posts?period='.$period.'&max='.$max);
    foreach ($data->days as $key => $value) {
        $posts = array_filter($value->postviews, function($post){
            return $post->type == 'post';
        });
    }
}

Showing the posts on the site

One final step is to now show these on your site. Here is how it would be done in straight PHP:

<?php $popular = (new WordPressApi())->popular(); ?>
<ul>
<?php foreach ($popular as $post): ?>
    <li><a href=“<?php echo $post->href; ?>”><?php echo $post->title; ?></li>
<?php endforeach; ?>

If you have any questions please feel free to comment below or contact me on Twitter. Photo credits Pixabay.