WordPress
Article

Create a Most Shared Posts Plugin for WordPress

By Narayan Prusty

Displaying a list of posts in a blog with the most number of shares is a good way to improve a site’s user navigation. In the case of WordPress, a widget is the ideal place for this. Users who wouldn’t otherwise know where to go after reading the current post might check out and hopefully participate in your blog’s most shared posts. These are commonly also the ones which have the most page views, and are likely to be of interest to more readers.

In this tutorial we’ll create a basic plugin to display the most shared posts in a widget. Although there are lots of plugins available for this purpose, many of them tend to be overwhelming and also don’t support caching. In this article, the plugin we’ll build will be lightweight and will cache the top ten most shared posts for the past six hours.

Most Shared Posts Plugin

Plugin Directory and Files

To start with the plugin development, in your wp-content/plugins directory create a directory called most-shared-widget, and then create a file called most-shared-widget.php inside it.

In the most-shared-widget.php file, add the following text to make the plugin installable.

<?php
 
/*
Plugin Name: Most Shared Posts Widget
Plugin URI: http://sitepoint.com
Description: Displays most shared posts in an widget
Author: Narayan Prusty
*/

How to Find Total Shares?

For the sake of this plugin we will only retrieve total shares of a post in Twitter and Facebook. Twitter and Facebook provide URLs which we can make a GET request to by passing a URL to find its total shares.

The URL to find total shares on Facebook is:
https://api.facebook.com/method/links.getStats?format=json&urls=http://sitepoint.com

And the URL to find total shares on Twitter is:
http://urls.api.twitter.com/1/urls/count.json?url=http://sitepoint.com

Both of these requests send back data in JSON format. Here is an example of the response to the Facebook request:

[{"url":"http:\/\/sitepoint.com","normalized_url":"http:\/\/www.sitepoint.com\/","share_count":1343,"like_count":1632,"comment_count":207,"total_count":3182,"click_count":138,"comments_fbid":"501562723433","commentsbox_count":0}]

Similarly, Twitter’s response looks like this:

{"count":72,"url":"http:\/\/sitepoint.com\/"}

Retrieving and Storing Total Shares

We can make HTTP requests to the Facebook and Twitter URLs using the WordPress HTTP API. And then store the retrieved post counts as post meta data.

To be friendly with the Facebook and Twitter API servers we won’t be retrieving the total share count of all the posts at a time, rather we will retrieve them as individual posts are viewed by users. We will also make sure that we only retrieve total shares of a post once in a 6 hour period because it’s unlikely that the share count will have changed much in this time.

Here is the code which is responsible for deciding when to retrieve and store total shares count of each post. Place this code in your most-shared-widget.php file.

function msp_is_post()
{
  if(is_single() && !is_attachment())
  {
    global $post;

    $last_update = get_post_meta($post->ID, "msp_last_update", true);

    if($last_update)
    {
      if(time() - 21600 > $last_update)
      {
        msp_update($post->ID);
      }
    }
    else
    {
      msp_update($post->ID);
    }
  }
}

add_action("wp", "msp_is_post");

This is how the above code works:

  • First we registered a callback for the wp action.
  • Then we check if a post is being viewed or not. If yes, then we proceed.
  • Next, we retrieve the total share count of that post. If it’s not present then we simply call the msp_update function which is responsible for retrieving and storing total shares of each post. And if it is present then we check when it was last retrieved; if it was retrieved over 6 hours ago then we update it again, otherwise we simply retain the current value by returning the function.

Here is the implementation of the msp_update function which is responsible for retrieving the total shares count of posts and storing them as post meta data:

function msp_update($id)
{
  $url = get_permalink($id);

  //facebook shares
  $response = wp_remote_get("https://api.facebook.com/method/links.getStats?format=json&urls=" . $url);
  $body = $response["body"]; 
  $body = json_decode($body);

  if($body[0]->share_count)
  {
    $facebook_count = $body[0]->share_count;
  }
  else
  {
    $facebook_count = 0;
  }


  //twitter shares
  $response = wp_remote_get("http://urls.api.twitter.com/1/urls/count.json?url=" . $url);
  $body = $response["body"]; 
  $body = json_decode($body);

  if($body->count)
  {
    $twitter_count = $body->count;
  }
  else
  {
    $twitter_count = 0;
  }

  $total = $facebook_count + $twitter_count;

  update_post_meta($id, "msp_share_count", $total);
  update_post_meta($id, "msp_last_update", time());
}

We first resolved the post ID to post URL using the get_permalink() function provided by WordPress.

We then retrieve and parse the total shares of a post using the WordPress HTTP API. Lastly, we add the total share count of Facebook and Twitter and store them as metadata, along with the current time which represents the last update time.

Creating a Widget

We will use a widget to display the top 10 shared posts. We’ll find the data using the get_posts() function provided by WordPress and then cache the result for six hours using WordPress Transients API.

Here is the code to create a simple widget which just displays the widget title. Place this code in the most-shared-widget.php file.

class Most_Shared_Post_Widget extends WP_Widget 
{
    public function __construct() 
    {
        parent::__construct("Most_Shared_Post_Widget", "Display Most Shared Posts", array("description" => __("This plugin displays ten most shared posts in an widget")));
    }
          
    public function form($instance) 
    {
        if($instance) 
        {
            $title = esc_attr($instance["title"]);
        } 
        else
        {
            $title = "";
        }
        ?>
  
        <p>
            <label for="<?php echo $this->get_field_id('title'); ?>"><?php echo "Title"; ?></label>  
            <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" />
        </p>
  
        <?php
    }
          
    public function update($new_instance, $old_instance) 
    {
        $instance = $old_instance;
        $instance['title'] = strip_tags($new_instance['title']);
        return $instance;
    }
          
    public function widget($args, $instance) 
    {
        extract($args);
        $title = apply_filters('widget_title', $instance['title']);
        echo $before_widget;
 
        if($title) 
        {
            echo $before_title . $title . $after_title;
        }

        msp_display_widget();
        
        echo $after_widget;
    }
}

function msp_register_most_shared_widget() 
{
  register_widget("Most_Shared_Post_Widget");
}
 
add_action("widgets_init", "msp_register_most_shared_widget");

Here we created a widget by extending the class WP_Widget and registered it using the register_widget function.

After displaying the widget title we call the msp_display_widget function which is responsible for retrieving the top 10 posts and displaying them as a list.

Here is the implementation of the msp_display_widget function:

function msp_display_widget()
{
  $posts = get_transient("msp");
  if($posts === false)
  {
    $args = array("posts_per_page" => 10, "meta_key" => "msp_share_count", "orderby" => "meta_value");
    $posts = get_posts($args);
    $json_posts = json_encode($posts);

    echo "<ul>";

    foreach($posts as $post)
    {
      echo "<li><a href='" . get_permalink($post->ID) . "'>" . $post->post_title . "</a></li>";
    }

    echo "</ul>";

    if(count($posts) >= 10)
    {
      set_transient("msp", $json_posts, 21600);
    }
  }
  else
  {
    $posts = json_decode($posts);

    echo "<ul>";

    foreach($posts as $post)
    {
      echo "<li><a href='" . get_permalink($post->ID) . "'>" . $post->post_title . "</a></li>";
    }

    echo "</ul>";
  }
}

The msp_display_widget function first checks to see if the top ten posts are stored as a transient, i.e. it looks in the cache. If it finds the posts in the cache then it simply parses them and displays them as an unordered list. Otherwise it retrieves the top 10 posts using the get_posts function and displays it. After displaying it, it stores the result in the cache by setting an expiration time of 6 hours.

You may be wondering what’s the point of caching the result? Well, get_posts is using the MySQL orderby parameter which sorts the total share count of posts and retrieves the top 10 which is an expensive MySQL operation, therefore for performance reasons it’s better to not perform the operation every time the widget is displayed.

We are only caching the result if there are more than 10 posts with share count meta data. This is done to prevent the widget from displaying nothing for the first 6 hours after installing the plugin as at least 10 posts might not have been requested by users at the time the widget is first displayed.

Here is how the widget looks in the Twenty Fifteen Theme:

Most Shared Posts Plugin

Conclusion

In this article I’ve shown you how to easily build your own Most Shared Posts plugin for WordPress. You can now go ahead and expand on this to display images and add more information.

You can get a complete copy of the plugin here.

Please share your experiences with your own plugins below.

  • Roberto Alicata

    Very interesting article with many ideas and insights

  • http://ChiefAlchemist.com/ Mark Simchock

    Nice!

    Two things:

    1) I’d consider also doing transients on the API calls as well. Or did I read too fast? (Sorry?)

    2) I think it’s important to keep in mind, Most Shared isn’t Best Posts or even Most Popular. I think we’ve all shared a link and added “This is crap…” Perhaps not often but it does happen and should be considered (by perhaps adding a post meta for exclude from most shared.

  • AG

    This isn’t working for me. I have followed the instructions but instead of showing me most shared – the widget just dumps all the posts that have recently been clicked.

  • Cédric

    Hi Narayan Prusty,

    Thanks for that ! It’s very nice !

    I would like to do something similar : I would like to display the 5 most share posts but on a 7 days basis. So if a post X has a total of 700 shares but 600 shares during the 7 last days and a post Z has a total of 8000 shares but only 100 during the last 7 days, I need to display post X, not post Z.

    Do you understand ?
    Thank you in advance for your help !

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Instant Website Review

Use Woorank to analyze and optimize your website to improve your website to improve your ranking!

Run a review to see how your site can improve across 70+ metrics!

Get the latest in WordPress, once a week, for free.