A Better Voting System for WordPress
by c.bavota | Posted in Tutorials | 23 comments
I published a tutorial quite a while back called Simple Voting for WordPress with PHP and jQuery. It was not without its problems, and recently I needed to improve on it for a client, so I thought it would be a good idea to finally release an updated version.
The original tutorial relied on an outside PHP file to process the votes but now I use the built-in Ajax function in WordPress. That way it’s more secure and efficient. To get everything started, let’s take a look at the jQuery required:
<script type="text/javascript">
/* <![CDATA[ */
(function($) {
$("#vote").not(".disabled").click(function() {
var el = $(this);
var nonce = $("input#voting_nonce").val();
var data = {
action: 'add_votes_options',
nonce: nonce,
postid: '<?php echo $post->ID; ?>',
ip: '<?php echo $_SERVER['REMOTE_ADDR']; ?>'
};
$.post('<?php echo admin_url('admin-ajax.php'); ?>', data,
function(response){
if(response!="-1") {
el.html("VOTED").unbind("click");
if(response=="null") {
alert("A vote has already been registered to this IP address.");
} else {
$("#votecounter").html(response);
alert("Thanks for your vote.");
}
} else {
alert("There was a problem registering your vote. Please try again later.");
}
});
return false;
});
})(jQuery);
/* ]]> */
</script>
If the vote button is clicked, it will send the Ajax request and process it accordingly, depending on a few things. The only thing missing, is the code to register a cookie once the vote has been calculated so that voters can only vote once. Let’s include two cookie functions originally created by Peter-Paul Koch and add a block of code to our original script:
<script type="text/javascript">
/* <![CDATA[ */
(function($) {
function setCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
$("#vote").not(".disabled").click(function() {
var el = $(this);
el.html('<span id="loader"></span>');
var nonce = $("input#voting_nonce").val();
var data = {
action: 'add_votes_options',
nonce: nonce,
postid: '<?php echo $post->ID; ?>',
ip: '<?php echo $_SERVER['REMOTE_ADDR']; ?>'
};
$.post('<?php echo admin_url('admin-ajax.php'); ?>', data,
function(response){
if(response!="-1") {
el.html("VOTED").unbind("click");
if(response=="null") {
alert("A vote has already been registered to this IP address.");
} else {
$("#votecounter").html(response);
alert("Thanks for your vote.");
}
var cookie = getCookie("better_votes");
if(!cookie) {
var newcookie = "<?php echo $post->ID; ?>";
} else {
var newcookie = cookie + ",<?php echo $post->ID; ?>";
}
setCookie("better_votes", newcookie, 365);
} else {
alert("There was a problem registering your vote. Please try again later.");
}
});
return false;
});
})(jQuery);
/* ]]> */
</script>
Now a cookie will be registered once the vote has been tallied. This is all the jQuery we need to make our voting system work. If jQuery is not already loaded in your WordPress theme, you may also need to add this into your header.php file before the wp_head() code:
<?php wp_enqueue_script( 'jquery' ) ?>
The following is the PHP code that we need to process the vote on the server side. This will need to be placed in your theme’s functions.php file. If the file doesn’t exist, just create it and make sure this code is placed between the PHP tags:
add_action("wp_ajax_add_votes_options", "add_votes_options");
add_action("wp_ajax_nopriv_add_votes_options", "add_votes_options");
function add_votes_options() {
if (!wp_verify_nonce($_POST['nonce'], 'voting_nonce'))
return;
$postid = $_POST['postid'];
$ip = $_POST['ip'];
$voter_ips = get_post_meta($postid, "voter_ips", true);
if(!empty($voter_ips) && in_array($ip, $voter_ips)) {
echo "null";
die(0);
} else {
$voter_ips[] = $ip;
update_post_meta($postid, "voter_ips", $voter_ips);
}
$current_votes = get_post_meta($postid, "votes", true);
$new_votes = intval($current_votes) + 1;
update_post_meta($postid, "votes", $new_votes);
$return = $new_votes>1 ? $new_votes." votes" : $new_votes." vote";
echo $return;
die(0);
}
The two action calls at the beginning hook into the Ajax function from the jQuery. We need both since one is for logged-in users and the other is for guests. Next we check for the security nonce, and end the process if it is not set correctly. This is a huge improvement over my old code that had absolutely no security whatsoever. If all is good, we start processing the vote by checking if the voters IP address has already been registered. If so, the process stops and returns a “null” value. Otherwise we registered the vote and IP address and echo out the total votes.
If you take a look at the jQuery above, you can see how the different responses will be processed. A “null” response will alert the voter that their IP address has already been registered so their new vote will not count. A response of “-1″ means something went wrong and we alert the voter. If everything goes well, the vote is registered, the voter is thanked and the total number of votes increases on the page.
There you have all the jQuery and PHP required to get it working on the backend, but you still need some PHP/HTML in order for things to work on the front end.
<?php
// This will display "0 votes" and increase as votes are added
$votes = get_post_meta($post->ID, "votes", true);
$votes = !empty($votes) ? $votes : "0";
if($votes == 1) $plural = ""; else $plural = "s";
echo '<div id="votecounter">'.$votes.' vote'.$plural.'</div>';
?>
<?php
// This will display the vote button and disable it if a cookie has already
// been set. We also add the security nonce here.
$hasvoted = $_COOKIE['better_votes'];
$hasvoted = explode(",", $hasvoted);
if(in_array($post->ID, $hasvoted)) {
$vtext = "VOTED";
$class = ' class="disabled"';
} else {
$vtext = "VOTE";
$class = "";
}
?>
<a href="javascript:void(0)" id="vote"<?php echo $class; ?>><?php echo $vtext; ?></a>
<?php if(function_exists('wp_nonce_field')) wp_nonce_field('voting_nonce', 'voting_nonce'); ?>
So there you have it, a more efficient voting system for WordPress that is secure and will hopefully double guard you against fraudulent voting. You can see this working live on the new Bloodshots website. It will only be active between Oct 24th and Oct 28th while people can vote for the films.



Voting systems will be much more important. So I will try to put it in my blog I hope it is working…
Great piece of code, will definitely use it on my site. Thanks!
Thank you for your vote code, i will try it out on my wordpress. Much appreciated
Hi c.bavota, as always very helpful! I liked your voting system thereforce thanks for your kind update!
Nice votingsystem, i am interessted in using it for my massagesessel-site.
Greetings,
Mike
Thanks a lot for this update,
is it possible to pass the author id also?
i try to write in the post author meta, the total number of votes from his posts,
in the code i use user id “2″ and it works fine,
if i try to pass the author_id, i get nothing…
what i’m missing here?
thanks a lot,
Philip
Hi Philip,
Can’t you include the normal
the_author_ID();variable in there?Martin
Thanks so much for this code!
Can you please tell us where that last front end code needs to be placed?
Also, I need to sort the posts so that the most popular with the most votes are listed first. Can you help with this as well?
Thanks again.
Newbie,
Josh
That last bit of code needs to go where you want the voting button to appear. To gather all the vote info you would have to do a direct call to the db using
$wpdb. You can read about it here: http://codex.wordpress.org/Class_Reference/wpdb.I might have some time this weekend to play around and figure out the code for you.
Hi,
My apology for the novice questions. New territory for me here.
Can you please confirm that the code at the beginning of this article (with cookie code) should be placed in the theme’s header.php file.
Also, I’m trying to paste the front end code into the page to show the button but it is only showing the code and not the button. Thoughts? I am able to paste this code into the footer.php (as a test) and see the button but it doesn’t seem to work on a blog page, for example. When I hover over or click on the vote button in the footer section, I see a javascript:void error.
Again, my apology for the simple questions. Any assistance would be appreciated.
Thanks.
Josh
Your JavaScript should always appear in your footer so you should place that code in the footer.php. The endqueue script code should go in your header.php. The
javascript:void(0)code you see is not an error. It is so the button doesn’t actually click through to anything.Thanks so much. I’ll explore this further and your recommended coding approach this weekend and will keep you posted on my progress.
If this additional work is outside of your reach for pro bono work, let me know and we can discuss payment for your time, etc.
Thanks again. It’s really appreciated.
Josh
This looks interesting. i bookmark this here, and tell to my webmaster if he can include it to my blog. Don’t delete, thanks!
Thanks for this piece of coding! I am always on the lookout for some good new plugins to add to my site, and this one looks like a great option!
When i have the voting system in multiple posts in the same page, i can only vote to one, if a go to the single post in each post it works great in all posts.
Any chance to make work with multiple posts in same page?
hello mr. bavota. it is a shame that jquery plugin database is mostly down, and no newer backup is there. i grab your voting system here, thanks for it. i wish you happy christmas days to you and your family.
Its so good to see the value you’re providing. Even a programmer can instantly notice there is lot of hard work you’ve put in to it.
Hope you get rewards for creating such a helpful blog. Love the voting system totally!
wow!!! I think this voting system code will suite my site.
Thank you so much for your code, i will try it out on my wordpress. Really appreciated!!!
Yeah me too, was looking for something like that for a long time now. Thanks so much
Thanks for the great post, but I would prefer the wp-poll for the wordpress poll system, Its great.
Thanks you very much, I want to try it but I don’t see which place to put jQuery?
hi,are there any seo benefits using this voting system?
Hi, do you have any idea if this code still works for the latest version of WordPress (currently using 3.3.1)? I’m pretty sure that I have set everything up correctly but clicking vote appears to do nothing at all.
Just to check I’m on the right track, I have the second block of js in my js folder (votescript.js) and have linked to this from my header.php.
I already have jquery included in the header for a gallery so that’s present.
I have included the PHP processing code in my functions.php between the php tags.
I have pasted the vote count and vote link code into my theme (I tried this for both single and archive pages).
I have pasted all code as is from this tutorial, so do I need to change any parameters, or am I missing something obvious?
Any guidance would be much appreciated, regards, Rob.