Create a Voting Plugin for WordPress
Introduction
WordPress, as a platform, has moved from only being a blogging platform, to a platform for a wide variety of websites. One major reason for this, is how easily WordPress can be customized and extended. This enables programmers to create far more functional sites than a normal blog. In the following tutorial we are going to create a plugin which will make wordpress an article voting site and also create a widget to display the top voted posts.
Creating the Plugin
To create a plugin create a file voteme.php in your wp-content/plugins/voteme folder. To create a plugin we have to add the plugin header as follows
<?php
/*
Plugin Name: Vote Me
Plugin URI:
Description: This plugin to add vote in posts
Author: Abbas
Version: 0.1
Author URI:
*/
We will also define some named constants for our plugin base url, and the plugin path as follows:
define('VOTEMESURL', WP_PLUGIN_URL."/".dirname( plugin_basename( __FILE__ ) ) );
define('VOTEMEPATH', WP_PLUGIN_DIR."/".dirname( plugin_basename( __FILE__ ) ) );
Also, create a js folder in your voteme folder, and add a file voteme.js file in it.
The folder structure of the plugin would be as follows.
We will now enqueue the scripts by with ‘wp_enqueue_scripts’ and enqueue our JS file, and localize it to store the WP Ajax url which we will use for our ajax calls.
function voteme_enqueuescripts()
{
wp_enqueue_script('voteme', VOTEMESURL.'/js/voteme.js', array('jquery'));
wp_localize_script( 'voteme', 'votemeajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
}
add_action('wp_enqueue_scripts', voteme_enqueuescripts);</pre>
After this we should be able to see our plugin in the plugin list and we should activate it.
Adding the vote link to posts
Now we will add a link to all the posts displaying the current votes and a link to add the vote by ajax.
Following is the code
function voteme_getvotelink()
{
$votemelink = "";
$post_ID = get_the_ID();
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$link = $votemecount.' <a onclick="votemeaddvote('.$post_ID.');">'.'Vote'.'</a>';
$votemelink = '<div id="voteme-'.$post_ID.'">';
$votemelink .= '<span>'.$link.'</span>';
$votemelink .= '</div>';
return $votemelink;
}
function voteme_printvotelink($content)
{
return $content.voteme_getvotelink();
}
add_filter('the_content', voteme_printvotelink);
Here, we create a function voteme_getvote
link which first gets the current post id and then reads the post meta _votemecount
using get_post_meta
. We use the post meta _votemecount
to store the votes for a particular post. Then we create a link by adding the JavaScript function votemeaddvote
on the click of the link. The function votemeaddvote
we will see shortly.
Next, we use the WordPress filter the_content
to hook our function to add this link after each post. You will be able to see the number of votes and vote link below each post now.
Adding votes using Ajax
As we have added the vote link to every posts its time we make it functional to actually add votes. The JavaScript function which does the AJAX vote posting is below
function votemeaddvote(postId)
{
jQuery.ajax({
type: 'POST',
url: votemeajax.ajaxurl,
data: {
action: 'voteme_addvote',
postid: postId
},
success:function(data, textStatus, XMLHttpRequest){
var linkid = '#voteme-' + postId;
jQuery(linkid).html('');
jQuery(linkid).append(data);
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert(errorThrown);
}
});
}
This sends an AJAX request to WordPress, and sends the action as voteme_addvote
and the post ID. If the AJAX call is successful it just adds the data in the div for that post. If there is an error it will just display the error.
To handle the AJAX request we will have to create a function as follows
function voteme_addvote()
{
$results = '';
global $wpdb;
$post_ID = $_POST['postid'];
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$votemecountNew = $votemecount + 1;
update_post_meta($post_ID, '_votemecount', $votemecountNew);
$results.='<div class="votescore" >'.$votemecountNew.'</div>';
// Return the String
die($results);
}
// creating Ajax call for WordPress
add_action( 'wp_ajax_nopriv_voteme_addvote', 'voteme_addvote' );
add_action( 'wp_ajax_voteme_addvote', 'voteme_addvote' );
In function voteme_addvote we get the post ID from the posted data and then get the current vote count for that post. Then we increment the vote by 1 and update the post meta again. Then we create a div with the new vote details and sent that back by using die($results);
To register this function to handle AJAX request for action: ‘voteme_addvote’ using the following wordpress hooks
// creating Ajax call for WordPress
add_action( 'wp_ajax_nopriv_voteme_addvote', 'voteme_addvote' );
add_action( 'wp_ajax_voteme_addvote', 'voteme_addvote' );</pre>
Now we’ll be able to click the vote link to add the vote on the post with AJAX.
Customizing WordPress admin to show post votes
It would be very convenient for the admin to be able to see the votes on the post edit page. Then from there he would be able to see the post details, and also the vote details on that page.
To add the vote details we need to add a hook on the filter ‘manage_edit-post_columns’ to add the Votes as a column on the post edit page as follows.
add_filter( 'manage_edit-post_columns', 'voteme_extra_post_columns' );
function voteme_extra_post_columns( $columns ) {
$columns[ 'votemecount' ] = __( 'Votes' );
return $columns;
}
Now we need to provide the value to display for this column. To do this we need to hook into the filter manage_posts_custom_column
. When we hook into this filter our function voteme_post_column_row
is called and with the post column name. Here we only process out column votemecount
and give the value for it. We read the value from our custom column _votemecount
and echo it. The complete code for this is as follows.
function voteme_post_column_row( $column ) {
if ( $column != 'votemecount' )
return;
global $post;
$post_id = $post->ID;
$votemecount = get_post_meta($post_id, '_votemecount', true) != '' ? get_post_meta($post_id, '_votemecount', true) : '0';
echo $votemecount;
}
add_action( 'manage_posts_custom_column', 'voteme_post_column_row', 10, 2 );
On the post edit page you should be able to see the vote details column.
Sorting post on basics of votes in WordPress admin
It would be convenient for the admin if we make the vote column sortable. He would be able to see the most voted posts and also the least voted posts. To do this first we must make the Vote column clickable for sorting. To do this we hook into the filter manage_edit-post_sortable_columns
and add the vote column to it as follows.
add_filter( 'manage_edit-post_sortable_columns', 'voteme_post_sortable_columns' );
function voteme_post_sortable_columns( $columns )
{
$columns[ 'votemecount' ] = votemecount;
return $columns;
}
Then we add a hook onto the load-edit.php
hook when we have the order by request for votemecount
we merge the sort parameters with
'meta_key' => '_votemecount',
'orderby' => 'meta_value_num'
So that it sorts on the basics of custom column and considers that column as numeric rather than as a string. The code for it is as follows.
add_action( 'load-edit.php', 'voteme_post_edit' );
function voteme_post_edit()
{
add_filter( 'request', 'voteme_sort_posts' );
}
function voteme_sort_posts( $vars )
{
if ( isset( $vars['post_type'] ) && 'post' == $vars['post_type'] )
{
if ( isset( $vars['orderby'] ) && 'votemecount' == $vars['orderby'] )
{
$vars = array_merge(
$vars,
array(
'meta_key' => '_votemecount',
'orderby' => 'meta_value_num'
)
);
}
}
return $vars;
}
Now in the admin page the vote column will be clickable and clicking on it will sort the post on the basics of votes.
Allowing only Registered users to vote
We might want that not anyone can vote on the post. We might want to check that only users who are registered on our site will be able to vote. We’ll control this via creating a setting page for our plugin as follows
// Settings
add_action('admin_menu', 'voteme_create_menu');
function voteme_create_menu() {
add_submenu_page('options-general.php','Vote Me','Vote Me','manage_options', __FILE__.'voteme_settings_page','voteme_settings_page');
}
function voteme_settings_page() {
?>
<div class="wrap">
<?php
global $blog_id;
if( isset( $_POST['votemeoptionssubmit'] ) )
{
update_option( 'votemelogincompulsory' , $_POST[ 'votemelogincompulsory' ] );
}
?>
<div id="settingsform">
<form id='votemesettingform' method="post" action="">
<h1><?php echo 'Vote Me Settings'; ?></h1>
<Input type = 'Radio' Name ='votemelogincompulsory' value= 'yes' <?php if( get_option('votemelogincompulsory') == 'yes' ) echo 'checked';?> >User Must be logged in for voting
<br/>
<Input type = 'Radio' Name ='votemelogincompulsory' value= 'no' <?php if( get_option('votemelogincompulsory') != 'yes' ) echo 'checked';?> >User might not be logged in for voting
<br/><br/>
<p class="submit">
<input type="submit" id="votemeoptionssubmit" name="votemeoptionssubmit" class="button-primary" value="<?php echo 'Save'; ?>" />
</p>
</form>
</div>
</div>
<?php }
Here we hook onto admin_menu
and create our setting page to show radio buttons for whether to allow voting for registered users only. Then based on the option selected by the admin we update the option votemelogincompulsory
. The settings page will look as follows.
Then, update the voteme_getvotelink
function to read the option votemelogincompulsory
and to show the votelink or the login link depending on the option selected by the user and wthere the user is logged in or no. The code for it is as follows
function voteme_getvotelink()
{
$votemelink = "";
if( get_option('votemelogincompulsory') != 'yes' || is_user_logged_in() )
{
$post_ID = get_the_ID();
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$link = $votemecount.' <a onclick="votemeaddvote('.$post_ID.');">'.'Vote'.'</a>';
$votemelink = '<div id="voteme-'.$post_ID.'">';
$votemelink .= '<span>'.$link.'</span>';
$votemelink .= '</div>';
}
else
{
$register_link = site_url('wp-login.php', 'login') ;
$votemelink = '<div class="votelink" >'." <a href=".$register_link.">"."Vote"."</a>".'</div>';
}
return $votemelink;
}
Creating a widget to display Top voted posts.
Now we will create a widget to display the top voted posts. First we create a function called voteme_get_highest_voted_posts
which takes the number of posts and then displays those many post in order of the highest voted posts. It also displays the number of vote for each post.
function voteme_get_highest_voted_posts($numberofpost)
{
$output = '';
$the_query = new WP_Query( 'meta_key=_votemecount&orderby=meta_value_num&order=DESC&posts_per_page='.$numberofpost );
// The Loop
while ( $the_query->have_posts() ) : $the_query->the_post();
$output .= '<li>';
$output .= '<a href="'.get_permalink(). '" rel="bookmark">'.get_the_title().'('.get_post_meta(get_the_ID(), '_votemecount', true).')'.'</a> ';
$output .= '</li>';
endwhile;
wp_reset_postdata();
return $output;
}
Then we create a widget which takes the number of post and the title from the user and uses the abpve function to display the top voted posts.
class VoteMeTopVotedWidget extends WP_Widget {
function VoteMeTopVotedWidget() {
// widget actual processes
$widget_ops = array('classname' => 'VoteMeTopVotedWidget', 'description' => 'Widget for top voted Posts.' );
$this->WP_Widget('VoteMeTopVotedWidget','VoteMeTopVotedWidget', $widget_ops);
}
function form($instance) {
// outputs the options form on admin
$defaults = array( 'title' => 'Top Voted Posts', 'numberofposts' => '5' );
$instance = wp_parse_args( (array) $instance, $defaults );
?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php echo 'Title:'; ?></label>
<input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>" class="widefat" />
</p>
<p>
<label for="<?php echo $this->get_field_id( 'numberofposts' ); ?>"><?php echo 'Number of Posts'; ?></label>
<input id="<?php echo $this->get_field_id( 'numberofposts' ); ?>" name="<?php echo $this->get_field_name( 'numberofposts' ); ?>" value="<?php echo $instance['numberofposts']; ?>" class="widefat" />
</p>
<?php
}
function update($new_instance, $old_instance) {
// processes widget options to be saved
$instance = $old_instance;
$instance['title'] = strip_tags( $new_instance['title'] );
$instance['numberofposts'] = $new_instance['numberofposts'];
return $instance;
}
function widget($args, $instance) {
// outputs the content of the widget
extract( $args );
$title = apply_filters('widget_title', $instance['title'] );
echo $before_widget;
if ( $title )
echo $before_title . $title . $after_title;
echo '<ul>';
echo voteme_get_highest_voted_posts($instance['numberofposts']);
echo '</ul>';
echo $after_widget;
}
}
function voteme_widget_init() {
// Check for the required API functions
if ( !function_exists('register_widget') )
return;
register_widget('VoteMeTopVotedWidget');
}
add_action('widgets_init', 'voteme_widget_init');</pre>
The widget will look as follows
On the front, the widget will look as follows
Conclusion.
With custom fields, WordPress makes it easy for us to extend it to use for different purposes. WordPress has good support for AJAX as we have seen in this tutorial. So, happy WordPress development!