Up/Down voting system for WordPress

Looking in all posts with keywords “voting system, upvote, downvote”, I can’t find a satisfying solution for this issue, except accepting one of the available plugins, spend a lot of time undersanding it and try to modify its functionnalies so that they fit with the requirements. So, I am convinced in writing my own code to create a stack-exchange-like voting system for WordPress. Without your suggestions I cannot find the starting point for the main part of the skeleton of my code.

My actual approach :

  • Create two custom fields: the first stores the number of post
    upvotes, and the second, the number of downvotes. It is possible to display votes state using
    get_post_meta function, and change vote state from front end using update_post_meta.
  • Find a way to store in the database the voted posts by a specific user and the state
    of vote(up, down or nothing). So that logged in users see if they already voted.
If (user is logged in )
{
Show the upvote or downvote state already done by this user;
Allow voting ;
}
else 
{
don't allow voting;
}

My question is:
How to resolve the second issue. Is there a way to achieve it using the customizing features offered by WordPress PHP functions (without using SQL queries, since I don’t know how to use SQL). I observe that all the Up/Down voting plugins use SQL queries in their code which make me really scared. Should I learn SQL to achieve my goal?

Solutions Collecting From Web of "Up/Down voting system for WordPress"

A simple user meta row can handle that for you (the second issue), you can store the post id and the vote (up/down) in an array and that is just the same as post meta ex

/**
 * update user vote per post
 * @param  int $user_id 
 * @param  int $post_id 
 * @param  mixed $vote can be an integer 1 / -1 and can also be a string "up"/"down"
 * @return void
 */
function update_user_vote($user_id,$post_id,$vote){
    //get all saved user data    
    $user_votes = get_user_meta($user_id,'updown_votes',true);
    $user_votes[$post_id] = $vote;
    //update with the new vote
    update_user_meta($user_id,'updown_votes',$user_votes);
}

/**
 * get user vote of post
 * @param  int $user_id 
 * @param  int $post_id 
 * @return if user has voted the his vote will be returned , zero if no vote found for post by this user
 */
function get_user_vote($user_id,$post_id){
    //get all saved user data    
    $user_votes = get_user_meta($user_id,'updown_votes',true);
    return (isset($user_votes[$post_id])) ?  $user_votes[$post_id] : 0;
}

and all done with no SQL 🙂

Yes, you can do this with built in functions. You’ve got a very broad question and a working solution would be a fair bit of work, but there a couple of ways to handle this with core functions that seem workable to me.

Store everything in post meta.

You could do this with only the two fields you are already considering. Instead of saving a counter, save an array of user IDs. To get a count, just count the user IDs. With one “upvoted” array and one “downvoted” array, you have what you need.

To tell a user if they’ve voted just check the array for the user ID.

This is not going to be a good solution if you need to query for votes. That is, it won’t work well if you need to find all the posts that a particular user has voted on. And it won’t work well if you need to find all the votes for all the posts or for some large set of posts.

Use a combination of post meta and user meta

Similar to the above but you will use the *_user_meta functions to save an array of post IDs to the usermeta table in addition to the counters in $wpdb->postmeta.

It means double the database writes and double the reads but this would let you get “all posts voted on by a user” relatively easily. But, as with the other solution, if you need to search that user meta data this isn’t going to work well.

Both options could have performance issues if the arrays get too large. The database column type is longtext, which will hold a lot of data, but the transfer processing time could become a problem.

I think you should probably be able to use comment meta instead of post meta but I think post meta is a better fit.

If I were going to do this with core tables and functions I would lean toward the second option, but if I were seriously considering something like this I would very seriously consider a dedicated table that I could construct and index specifically for this task. That would be the most flexible and efficient way to do it, as far as the kind of queries you could run. if you want the best answer, in my opinion, it involves learning SQL.