Oct
24
2011

A Better Voting System for WordPress

by   |  Posted in Tutorials  |  21 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.

About the author:

A freelance web developer living in Montreal who spends most of his time writing for this site and building Premium themes for WordPress. You can find him on Twitter @bavotasan.

Site5 Affiliate Link
If you liked this, please share it.

Tags: , , , , ,

Short URL: http://bit.ly/rrp67O

Discussion 21 Comments

  1. Motorräder on October 27, 2011 at 2:24 am

    Voting systems will be much more important. So I will try to put it in my blog I hope it is working…

  2. Rich on November 7, 2011 at 11:08 am

    Great piece of code, will definitely use it on my site. Thanks!

  3. Michelle on November 14, 2011 at 9:43 am

    Thank you for your vote code, i will try it out on my wordpress. Much appreciated :)

  4. Claus on November 17, 2011 at 10:01 am

    Hi c.bavota, as always very helpful! I liked your voting system thereforce thanks for your kind update!

  5. Massagesessel Panasonic on November 21, 2011 at 3:09 pm

    Nice votingsystem, i am interessted in using it for my massagesessel-site.

    Greetings,

    Mike

  6. Philip on November 25, 2011 at 2:55 am

    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,

    $totalvotes = get_the_author_meta( 'author_total_votes', 2 );
    $totalvotes = $totalvotes + 1;
     
    update_user_meta(2, 'author_total_votes', $totalvotes);

    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

  7. Martin on November 25, 2011 at 7:04 am

    Hi Philip,

    Can’t you include the normal the_author_ID(); variable in there?

    Martin

  8. Joshua on November 30, 2011 at 6:53 am

    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

    • c.bavota on December 1, 2011 at 8:50 am

      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.

    • Joshua DeWitt on December 13, 2011 at 11:33 pm

      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

    • c.bavota on December 21, 2011 at 7:57 am

      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.

  9. Joshua on December 2, 2011 at 1:22 am

    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

  10. Jennifer on December 7, 2011 at 7:15 am

    This looks interesting. i bookmark this here, and tell to my webmaster if he can include it to my blog. Don’t delete, thanks!

  11. Caitlin on December 11, 2011 at 11:44 pm

    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!

  12. Beon on December 13, 2011 at 11:18 am

    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?

  13. Patrik on December 14, 2011 at 7:27 am

    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.

  14. Design Inspiration on January 13, 2012 at 1:26 pm

    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!

  15. Raju Krish on January 23, 2012 at 3:10 pm

    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!!!

  16. Spiele spielen on January 24, 2012 at 9:45 am

    Yeah me too, was looking for something like that for a long time now. Thanks so much

  17. Brass Hollow Rods on January 27, 2012 at 6:25 am

    Thanks for the great post, but I would prefer the wp-poll for the wordpress poll system, Its great.

  18. Man Envy on February 19, 2012 at 1:28 am

    Thanks you very much, I want to try it but I don’t see which place to put jQuery?

Leave a Reply

Your email address will not be published. Required fields are marked *

*


To enter code in the comment box, please place it between <pre lang="php"> </pre> tags. You don't have to convert any characters to their hex/HTML code. Just add your code the way you would to any code editor.