Create a Most Shared Posts Plugin for WordPress
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.
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: https://www.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=https://www.sitepoint.com
And the URL to find total shares on Twitter is:
http://urls.api.twitter.com/1/urls/count.json?url=https://www.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:
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.