Advertisement
Plugins

How to Write a "Most Popular By Views" WordPress Plugin

by

As you continue writing for WordPress more and more, the level of difficulty and complexity of your plugins will eventually reach far beyond the simple back-end data manipulation, as demonstrated in our beginner's article. In this installment we'll cover in-depth: database interaction, Admin Widgets, and Sidebar Widgets. Today's example will be a custom built "Most Popular by Views" plugin, which creates an admin area widget for us to view, and a sidebar widget for visitors to see.

Tutorial now on Wptuts+

Step 0. What it's Gonna Do?

Before we open our IDE or write any code, you should always write out a list of what features your plugin will and will not have (at least in its initial phase, you can always extend later). For our plugin, "Most Popular By Views," our primary feature is to display a list of the most popular posts (we'll say, top 10). Secondly, we'll also put the list in the admin area as a kind of low-tech analytics. Lastly, we'll give the developers the option to display it anywhere by making it available as a sidebar widget, and via a simple function.

Features:

  • Creates a list of the top ten most popular posts based on views
  • List is displayed in Admin area as a low-tech analytics
  • List is available as both a sidebar widget and function
The finished widgets

Step 1. The Database

Before we can display the most popular posts, we need to gather data about which posts are being viewed and how often, but even before we can do that, we need somewhere to put all that data. Inside of a new plugin file, let's create a new function (ppbv_create_table) that will check to see if our table exists. If it does not, we'll create it. Our method of doing this is rather simple; we'll use $wpdb->get_results to run a SQL statement that checks for a table named "wp_popular_by_views." If it doesn't find the table, get_results will return null. If that's the case, we'll use $wpdb->query to write in the new table. We run this function every time the plugin is activated.

<?php
/**
 * Plugin Name: Popular Posts by Views
 * Plugin URI: http://net.tutsplus.com
 * Description: Create a widget to show your most popular articles based on views.
 * Version: 1.0
 * Author: Jonathan Wolfe
 * Author URI: http://fire-studios.com
 * License: GPL2
 * .
 * This plugin and its accompanying tutorial are written for Nettuts+ at http://net.tutsplus.com
 * .
 */

global $wpdb; // call global so we can get the database prefix
$ppbv_tablename = $wpdb->prefix.'popular_by_views'; // combine the prefix with our tablename

function ppbv_create_table(){
    global $wpdb, $ppbv_tablename; // call global so we can use them within the function
    $ppbv_table = $wpdb->get_results("SHOW TABLES LIKE '{$ppbv_tablename}'" , ARRAY_N); // returns null if no results
    if(is_null($ppbv_table)){ // if we don't have a table
        $create_table_sql = "CREATE TABLE {$ppbv_tablename} (
            id BIGINT(50) NOT NULL AUTO_INCREMENT, 
            post_id VARCHAR(255) NOT NULL, 
            views BIGINT(50) NOT NULL, 
            PRIMARY KEY (id), 
            UNIQUE (id)
        );"; // be careful with SQL syntax, it can be VERY finiky
        $wpdb->query($create_table_sql); // run the SQL statement on the database
    }
}
register_activation_hook(__FILE__,'ppbv_create_table'); // run the function 'ppbv_create_table' at plugin activation
?>

Step 2. Catching the Data

The next thing we need to do, now that we have a table to store our data, is catch our data. We'll create a new function (ppbv_page_viewed) that we'll attach to the wp_head hook so that it'll run on every page load. Inside this function, we're going to do one of two things, after we check to see if the current page is already in the database: increase its views by one or, if it's not in the database, add it to the database. To figure out if the current page is already in the database, we're going to be using the $post object to get the "post_ID." This step is actually really simple, because we aren't collecting any complicated data; the comments in the code provide a detailed step by step in this process.

function ppbv_page_viewed(){
    if(is_single() && !is_page()){ // only run on posts and not pages
        global $wpdb, $post, $ppbv_tablename; // call global for use in funciton
        $wpdb->flush(); // clense the DB interface
        $data = $wpdb->get_row("SELECT * FROM {$ppbv_tablename} WHERE post_id='{$post->ID}'", ARRAY_A); // get the data row that has the matching post ID
        if(!is_null($data)){ // if we have a matching data row
            $new_views = $data['views'] + 1; // increase the views by 1
            $wpdb->query("UPDATE {$ppbv_tablename} SET views='{$new_views}' WHERE post_id='{$post->ID}';"); // update the data row with the new views
            $wpdb->flush(); // clense the DB interface
        }
        else { // if we don't have a matching data row (nobody's viewed the post yet)
            $wpdb->query("INSERT INTO {$ppbv_tablename} (post_id, views) VALUES ('{$post->ID}','1');"); // add a new data row into the DB with the post ID and 1 view
            $wpdb->flush(); // clense the DB interface
        }
    }
}
add_action('wp_head','ppbv_page_viewed'); // attach ppbv_page_viewed to the wp_head hook
Database and views process

Step 3. Creating the Admin Widget

Next up, we're going to use this data we just added to our database to create an ordered list inside of an Admin Area Dashboard Widget. This process involves two functions: the first (ppbv_admin_widget) to generate everything inside the widget, and second, (ppbv_add_admin_widget) to create the widget itself. Let's start with the content function, pppbv_admin_widget. Firstly, since we're making an ordered list, let's echo out the opening tags for that. Then we'll globalize the $wpdb and $ppbv_tablename vars so we can access the database and retrieve the ten most viewed post's IDs. Then we'll run the returned array through a foreach statement, and use each individual ID to build a list-item and create a link to that page while also printing out its views (formatted with number_format to make it easier to read).

function ppbv_admin_widget(){
    echo "<ol id='popular_by_views_admin_list'>"; // create an unordered list
        global $wpdb, $ppbv_tablename; // call global for use in function
        $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
        foreach($popular as $post){ // loop through the returned array of popular posts
            $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
            $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
            $post_url = get_permalink($ID); // get the URL of the current post in the loop
            $title = get_the_title($ID); // get the title of the current post in the loop
            echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
        } // end the loop
    echo "</ol>"; // close out the unordered list
}

Now that we're generating content, let's create the widget. Inside the creation function, ppbv_add_admin_widget, we're going to call another function native to WordPress: wp_add_dashboard_widget. All we need to do is give wp_add_dashboard_widget the following parameters: [id of the container], [title in the container], [content function] (ours fills as such: 'popular_by_views', 'Most Popular Posts by Views', 'ppbv_admin_widget'). The last thing we need to do is attach our creation function to the wp_dashboard_setup hook.

function ppbv_add_admin_widget(){
    wp_add_dashboard_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_admin_widget'); // creates an admin area widget || wp_add_dashboard_widget([id of div],[title in div],[function to run inside of div])
}
add_action('wp_dashboard_setup','ppbv_add_admin_widget'); // attach ppbv_add_admin_widget to wp_dashboard_setup

And now we have a working dashboard widget for administraitors to see.

Admin Dashboard Widget

Step 4. Creating the Sidebar Widget

Creating a sidebar widget is fairly painless; unfortunately, certain parts aren't documented well (like how to make them uniform), but we'll cover that. Let's start by writing a new function (ppbv_display_widget) and, inside of it, we'll carbon copy our content function from the admin widget (I suggest moving the global calls to the top, outside the <ol> echo, of the function for clarity later on). Then the next step is to register our widget in WordPress via wp_register_sidebar_widget (parameters are: [id of the container],[title on the widget page],[content function] || 'popular_by_views', 'Most Popular Posts by Views', 'ppbv_display_widget').

function ppbv_display_widget() {
    global $wpdb, $ppbv_tablename; // call global for use in function
    
    echo "<div id='popular_by_views'>"; // create a container
        echo "<h2>Most Popular by Views</h2>"; // write the title
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N);
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo "</div>"; // close the container
}
wp_register_sidebar_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_display_widget'); // add the widget to the select menu || wp_register_sidebar_widget([id of the option],[title of the option],[function to run from the widget]))

This is actually the bare-minimum you need to do for a sidebar widget, but what 90% of all dynamic sidebars have certain settings applied about how widgets are styled, so let's conform our widget to those settings. The first thing we need to do is add in a parameter to our ppbv_display_widget function, $args. By adding this parameter inside the function, using the extract function on it, we gain access to several variables which will allow our plugin to be styled the same as the rest of the widgets in the sidebar.

"We don't need to provide any input for $args, WordPress will do that for us."

Thanks to $args and extract, we now have access to the following variables that we can echo to style our widget:

  • $before_widget
  • $after_widget
  • $before_title
  • $after_title
function ppbv_display_widget($args){
    global $wpdb, $ppbv_tablename; // call global for use in function
    extract($args); // gives us the default settings of widgets
    
    echo $before_widget; // echos the container for the widget || obtained from $args
        echo $before_title."Most Popular by Views".$after_title; // echos the title of the widget || $before_title/$after_title obtained from $args
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo $after_widget; // close the container || obtained from $args
}
Sidebar Widget

Step 5. The Non-widget Function

Not everybody who uses this plugin is going to want to use the widget, so it's imperative that we provide them with another method of displaying our list. Thankfully, that's as simple as cloning our ppbv_display_widget function and removing the widget parts, replacing them with standard hardcoded HTML.

function ppbv_display() {
    global $wpdb, $ppbv_tablename; // call global for use in function
    
    echo "<div id='popular_by_views'>"; // create a container
        echo "<h2>Most Popular by Views</h2>"; // write the title
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N);
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo "</div>"; // close the container
}

Conclusion

That's it guys, you've successfully made your very own "Most Popular by Views" WordPress plugin. Not too hard, was it?

When you've mastered the art of WordPress plugin development, stop by CodeCanyon.net and begin selling your plugins for profit!

View Final Source Code with Commenting?

<?php
/**
 * Plugin Name: Popular Posts by Views
 * Plugin URI: http://net.tutsplus.com
 * Description: Create a widget to show your most popular articles bassed on views.
 * Version: 1.0
 * Author: Jonathan Wolfe
 * Author URI: http://fire-studios.com
 * License: GPL2
 * .
 * This plugin and it's accompanying tutorial are written for NETTUTS at http://net.tutsplus.com
 * .
 */

global $wpdb; // call global so we can get the database prefix
$ppbv_tablename = $wpdb->prefix.'popular_by_views'; // combine the prefix with our tablename

function ppbv_create_table(){
    global $wpdb, $ppbv_tablename; // call global so we can use them within the function
    $ppbv_table = $wpdb->get_results("SHOW TABLES LIKE '{$ppbv_tablename}'" , ARRAY_N); // returns null if no results
    if(is_null($ppbv_table)){ // if we don't have a table
        $create_table_sql = "CREATE TABLE {$ppbv_tablename} (
            id BIGINT(50) NOT NULL AUTO_INCREMENT, 
            post_id VARCHAR(255) NOT NULL, 
            views BIGINT(50) NOT NULL, 
            PRIMARY KEY (id), 
            UNIQUE (id)
        );"; // be careful with SQL syntax, it can be VERY finiky
        $wpdb->query($create_table_sql); // run the SQL statement on the database
        $wpdb->flush(); // clense the DB interface
    }
}
register_activation_hook(__FILE__,'ppbv_create_table'); // run the function 'ppbv_create_table' at plugin activation

function ppbv_page_viewed(){
    if(is_single() && !is_page()){ // only run on posts and not pages
        global $wpdb, $post, $ppbv_tablename; // call global for use in funciton
        $wpdb->flush(); // clense the DB interface
        $data = $wpdb->get_row("SELECT * FROM {$ppbv_tablename} WHERE post_id='{$post->ID}'", ARRAY_A); // get the data row that has the matching post ID
        if(!is_null($data)){ // if we have a matching data row
            $new_views = $data['views'] + 1; // increase the views by 1
            $wpdb->query("UPDATE {$ppbv_tablename} SET views='{$new_views}' WHERE post_id='{$post->ID}';"); // update the data row with the new views
            $wpdb->flush(); // clense the DB interface
        }
        else { // if we don't have a matching data row (nobody's viewed the post yet)
            $wpdb->query("INSERT INTO {$ppbv_tablename} (post_id, views) VALUES ('{$post->ID}','1');"); // add a new data row into the DB with the post ID and 1 view
            $wpdb->flush(); // clense the DB interface
        }
    }
}
add_action('wp_head','ppbv_page_viewed'); // attach ppbv_page_viewed to the wp_head hook

function ppbv_admin_widget(){
    echo "<ol id='popular_by_views_admin_list'>"; // create an unordered list
        global $wpdb, $ppbv_tablename; // call global for use in function
        $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
        foreach($popular as $post){ // loop through the returned array of popular posts
            $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
            $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
            $post_url = get_permalink($ID); // get the URL of the current post in the loop
            $title = get_the_title($ID); // get the title of the current post in the loop
            echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
        } // end the loop
    echo "</ol>"; // close out the unordered list
}
function ppbv_add_admin_widget(){
    wp_add_dashboard_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_admin_widget'); // creates an admin area widget || wp_add_dashboard_widget([id of div],[title in div],[function to run inside of div])
}
add_action('wp_dashboard_setup','ppbv_add_admin_widget'); // attach ppbv_add_admin_widget to wp_dashboard_setup

function ppbv_display_widget($args){
    global $wpdb, $ppbv_tablename; // call global for use in function
    extract($args); // gives us the default settings of widgets
    
    echo $before_widget; // echos the container for the widget || obtained from $args
        echo $before_title."Most Popular by Views".$after_title; // echos the title of the widget || $before_title/$after_title obtained from $args
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N); // Order our table by largest to smallest views then get the first 10 (i.e. the top 10 most viewed)
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo $after_widget; // close the container || obtained from $args
}
wp_register_sidebar_widget('popular_by_views', 'Most Popular Posts by Views', 'ppbv_display_widget'); // add the widget to the select menu || wp_register_sidebar_widget([id of the option],[title of the option],[function to run from the widget]))

function ppbv_display() {
    global $wpdb, $ppbv_tablename; // call global for use in function
    
    echo "<div id='popular_by_views'>"; // create a container
        echo "<h2>Most Popular by Views</h2>"; // write the title
        echo "<ol id='popular_by_views_list'>"; // create an ordered list
            $popular = $wpdb->get_results("SELECT * FROM {$ppbv_tablename} ORDER BY views DESC LIMIT 0,10",ARRAY_N);
            foreach($popular as $post){ // loop through the returned array of popular posts
                $ID = $post[1]; // store the data in a variable to save a few characters and keep the code cleaner
                $views = number_format($post[2]); // number_format adds the commas in the right spots for numbers (ex: 12543 to 12,543)
                $post_url = get_permalink($ID); // get the URL of the current post in the loop
                $title = get_the_title($ID); // get the title of the current post in the loop
                echo "<li><a href='{$post_url}'>{$title}</a> - {$views} views</li>"; // echo out the information in a list-item
            } // end the loop
        echo "</ol>"; // close the ordered list
    echo "</div>"; // close the container
}
?>
Related Posts
  • Code
    WordPress
    Mastering WordPress Meta Data: Querying Posts and Users by Meta DataMetadata
    So far in this series you've learned how to access WordPress meta data, and work with the arrays in which they are returned. We don't just add custom fields to WordPress posts so we can display this information, but it also so we can sort by it. Now that you know how to retrieve and display meta data, it's time to learn how to customize the WordPress loop to return only posts with specific meta values.Read More…
  • Code
    Creative Coding
    Using WordPress for Web Application Development: Custom Database QueriesApplication foundation 400
    Throughout this series, we've been looking at the various facilities that make it possible to treat WordPress as a foundation for web application development. Thus far, we've covered a lot of ground: We've talked about how WordPress is more of a foundation rather than a framework. We've discussed the nature of the the Event-Driven Design Pattern. There's been a discussion of Email, User Management, Saving Data, Retrieving Data ...and more. In the most recent articles, we've been talking a look at how to handle queries against the WordPress database through the use of WP_Query and WP_User_Query.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Creating Template FilesCreating wordpress theme from html 400
    In the first part of this series, I showed you how to prepare your HTML and CSS files for WordPress, ensuring the structure would work, the code was valid and that the correct classes were being used. In this tutorial you'll learn how to take your index.html file and split it up into a set of template files for use by WordPress.Read More…
  • Code
    Plugins
    A Better Forum List Widget for bbPressBbpress
    When bbPress was still a standalone installation, I had tried it out and wasn't really impressed. Things were clunky and it didn't always work the way it was supposed to. After languishing for a few years, Automattic decided to take bbpress and turn it into a plugin, improving the functionality leaps and bounds and making it a strong contender amongst other forum option for WordPress.Read More…
  • Web Design
    HTML/CSS
    Foundation for Beginners: Joyride, Interchange, Tables and PanelsFoundation thumb retina
    Let's further add to our Foundation arsenal by looking at the Joyride plugin, which helps guide users through your sites. We'll also look at pricing tables, standard tables and interchange; a novel responsive image tool. We'll cover the implementation of these features with a simple template which you can download and play with.Read More…
  • Code
    Plugins
    Integrating Multiple Choice Quizzes in WordPress - Creating the BackendIntegrating multiple choice quizzes in wordpress
    Multiple choice questions are something that most of us have faced at least once in our life. We love them because we can provide correct answers by logically thinking about provided possibilities, even if we don't exactly know the correct answer. Also answering takes less time which makes it so popular. Creating a multiple choice quiz in WordPress can be a very exciting and profitable task. You can use it in your personal blog to attract more visitors, or you can create a premium section with advanced quizzes, or you can create quizzes focusing on popular certification exams. There are numerous possibilities for making it profitable.Read More…