0

I'm using a plugin that allows users to vote on posts, I'd like to add each vote that's cast to the authors user_meta so I can rank users the same way I rank posts.

There's a couple of different functions in the plugin that update and save the post_meta.

add_action( 'wp_ajax_nopriv_epicred_vote', 'epicred_vote' );
add_action( 'wp_ajax_epicred_vote', 'epicred_vote' );
    function epicred_vote(){
        global $wpdb, $current_user;

        get_currentuserinfo();

        $wpdb->myo_ip   = $wpdb->prefix . 'epicred';

        $option = (int)$_POST['option'];
        $current = (int)$_POST['current'];

        //if we are locked via IP set the fid variable to be the IP address, otherwise log the member ID
        if(get_option('epicred_ip') == 'yes'){
            $ipAddr = isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) ? $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] : $_SERVER['REMOTE_ADDR'];
            $fid = "'" . $ipAddr . "'"; 
        }else{
            $fid = $current_user->ID;
        }


        $postid = (int)$_POST['poll'];  

        $query = "SELECT epicred_option FROM $wpdb->myo_ip WHERE epicred_ip = $fid AND epicred_id = $postid";

        $al = $wpdb->get_var($query);


        if($al == NULL){
            $query = "INSERT INTO $wpdb->myo_ip ( epicred_id , epicred_ip, epicred_option) VALUES ( $postid, $fid, $option)";
            $wpdb->query($query);
        }else{
            $query = "UPDATE $wpdb->myo_ip SET epicred_option = $option WHERE epicred_ip = $fid AND epicred_id = $postid";
            $wpdb->query($query);
        }

        $vote = get_post_meta($postid,'epicredvote',true);

            if($option == 1){
                if($al != 1){
                    if($al == -1){
                    $vote = $vote+2;    
                    }else{
                    $vote = $vote+1;
                    }
                }
            }


            if($option == -1){

                if($al != -1){
                    if($al == 1){
                        $vote = $vote-2;
                    }else{
                    $vote = $vote-1;
                    }   
                }   
            }
            update_post_meta($postid,'epicredvote',$vote);


            $response['poll'] = $postid;
            $response['vote'] = $vote;

        echo json_encode($response);

        // IMPORTANT: don't forget to "exit"
        exit;
    }

And

function wpt_save_wpeddit() {

     global $wp, $wpdb, $post;  


    // unhook this function so it doesn't loop infinitely
    remove_action('save_post', 'wpt_save_wpeddit');


    // Is the user allowed to edit the post or page?
    if ( !current_user_can( 'edit_post', $post->ID ))
    return $post->ID;
    // OK, we're authenticated: we need to find and save the data. Make sure we don't add an image every time the post is
    // saved as a draft - so keep track of the external URL in a custom field.


        $vote = get_post_meta($post->ID,'epicredvote',true);
        $rank = get_post_meta($post->ID,'epicredrank',true);

        if($vote == ""){
            $vote = 0;
        }
        if($rank == ""){
            $rank = 0;
        }

        update_post_meta($post->ID, 'epicredvote', $vote );
        update_post_meta($post->ID,'epicredrank',$rank);


    add_action('save_post', 'wpt_save_wpeddit');

}

Then my goal would be to use something like this in order to rank the users:-

EDIT:- loop I'm using to output users/scores.

 <?php


                        $args = array(
                            'meta_key' => 'epicredvote',
                            'orderby'  => 'meta_value',
                            'order'    => 'DESC',
                            'number' => 10,

                        );

                        add_action( 'pre_user_query', 'wpse_149342_pre_user_query' );

                        $user_query = new WP_User_Query(  $args );

                        // User Loop
                        if ( ! empty( $user_query->results ) ) {
                            foreach ( $user_query->results as $user ) {
                                echo '<p>' . $user->display_name . '</p>';
                               echo '<span>' . $user->epicredvote . '</span>'; 
                            }
                        } else {
                            echo 'No users found.';
                        }
                    ?>

So one vote on a post = one vote for that user essentially.

Possible, or am I completely off track here?

2
  • Does the plugin have any filters that you can hook into? If so, then that's definitely possible. If not, you could try using jquery to detect when someone votes on a post and then update the user meta via ajax.
    – gdaniel
    Jul 23, 2014 at 14:35
  • No filters that I can see. It does use Ajax however to register the votes. Made a small edit to the first code block (at the top). I'm sure it's possible to update the user meta with ajax when someone votes on the post, the problem is 1. update_user_meta is a WP function I've never worked with before and 2. Ajax is finicky as heck when I try to get it to work with WP.
    – andy
    Jul 23, 2014 at 15:51

1 Answer 1

1
+50

It looks like the plugin is using the update_post_meta function, which in turn uses the update_metadata function which includes the action hooks update_postmeta and updated_postmeta which fire immediately before and after the post meta is stored to the database. You could hook into one of these to update the user meta of the author of the post. Pseudo code:

add_action( 'update_postmeta', 'wpse155265_update_user_vote', 10, 4 );
function wpse155265_update_user_vote( $meta_id, $object_id, $meta_key, $meta_value ) {
  $post = get_post( $object_id );
  $user_id = $post->post_author;
  $votes = (int) get_user_meta( $user_id, 'epicredvote', true );
  $votes++;
  update_user_meta( $user_id, 'epicredvote', $votes );
}

Edit:

As noted, the above does not take into consideration whether the post meta update is a vote up or down. Revised code below; we'll compare the value of the post meta, old versus new, to determine if the user's meta should be increased or decreased.

add_action( 'update_postmeta', 'wpse155265_update_user_vote', 10, 4 );
function wpse155265_update_user_vote( $meta_id, $object_id, $meta_key, $meta_value ) {
  $post = get_post( $object_id );
  $user_id = $post->post_author;
  $meta_value_old = get_post_meta( $object_id, 'epicredvote', true );
  $votes = (int) get_user_meta( $user_id, 'epicredvote', true );
  ( $meta_value > $meta_value_old ) ? $votes++ : $votes--;
  update_user_meta( $user_id, 'epicredvote', $votes );
}

Another approach that occurred to me just now would be to only calculate the user's votes when ranking users, rather than storing their votes in a meta. Loop through all users from get_users and for each one, calculate their total votes, storing each user into an array with their total as the key, sort the array by vote totals using ksort and then loop through the array to output your ranked list. Running WP_Query for every user might be a bit intense, though. Perhaps there's a single SQL statement that can be put together that will actually return all users sorted by their vote total - but I'd have to fiddle with it to see if that's possible.

Edit:

Here's a single SQL that will calculate and rank your users. Plug this into $wpdb as needed:

global $wpdb;
$results = $wpdb->get_results(
  "
    SELECT u.display_name as name,
    ( SELECT SUM(pm.meta_value)
      FROM wp_posts p, wp_postmeta pm
      WHERE p.post_author = u.ID
      AND p.post_status LIKE 'publish'
      AND pm.meta_key = 'epicredvote'
      AND p.ID = pm.post_id ) as votes
    FROM wp_users u
    ORDER BY votes DESC
  "
);
foreach ( $results as $result ) {
  echo "{$result->name}: {$result->votes} votes<br>";
}
11
  • Doing some testing now. Will report back soon.
    – andy
    Jul 24, 2014 at 12:10
  • Ok after some testing I can say this sort of works. The problem is that every time a post is voted on it increments the epicredvote meta field of that user by 1, so a post can be voted up/down/up/down/up/down/ and that users meta value will increase by 8. Obviously it should be the sum of the votes and not how many times the users posts have been voted on.
    – andy
    Jul 24, 2014 at 12:55
  • Mobile at the moment but can update coffee later today. Jul 24, 2014 at 13:33
  • Edited. For performance reasons, I would highly recommend the single SQL statement approach, but I've left all the other code for reference. Jul 25, 2014 at 0:23
  • 1
    The SQL query is inefficient; instead of FROM wp_posts p, wp_postmeta pm WHERE [...] p.ID = pm.post_id, use FROM wp_posts p JOIN wp_postmeta pm ON p.ID = pm.post_id WHERE [...].
    – Schism
    Jul 29, 2014 at 14:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.