Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I originally was going to post a question on how I would go about ranking a list of authors by the amount of post views from all of their posts combined. But I luckily found a solution here: List users with the most total posts view

This is the code I'm using from that page, except I tweaked it a little to fetch post views from a plugin I use:

<?php global $wpdb;
$topuser = array();

// query all posts by each user
$users = $wpdb->get_results("SELECT ID FROM $wpdb->users ORDER BY ID"); 
foreach ( $users as $user ) {       
    $query = get_posts( array('author' => $user->ID,  'posts_per_page' => '10000000000'));
    $counter = 0;

    // get each post of a user
    foreach ( $query as $post ){
        $views = absint( get_post_views('normal') );
        $counter += $views;
    }
    $topuser[] = array( 'id' => $user->ID, 'views' => $counter);
    wp_reset_query();
}

// function to sort array based on views count
function sortViews($a, $b) {
    return $b['views'] - $a['views'];
}
usort($topuser, 'sortViews'); // sort the array
$output = array_slice($topuser, 0, 10); // slice the array by limit 3

// output the result: user, total postview count, latest post
foreach ($output as $user){
    $profile = get_userdata($user['id']);
    $query = get_posts( array('author' => $user['id'], 'numberposts' => 1 ));

    echo '<p>' . $profile->user_nicename .' ('. $user['views'] .')</p>';            
    foreach ( $query as $post ){
        echo '<a href="' . $post->post_name . '">' . $post->post_title . '</a>';
        echo get_post_meta($post->ID, get_post_views('normal'), true);
    }
} ?>

Now I would like to take this solution a step further towards my vision when first coming up with the idea.

I want to show the specific rank (position in the list) of each user on their buddypress profile page. I would paste this code in member-header.php

Example: It would say something like "User Rank: 15", meaning that this user shows up as the 15th result when executing the above query (of course I would change the number from 10 to more which is why that would be possible).

Hope you guys can help out. Thanks in advance :)

share|improve this question
add comment

1 Answer

up vote 2 down vote accepted

First you can replace

'posts_per_page' => '10000000000'

with

'posts_per_page' => -1

to remove the limit.

If you want to show the user rank, you can add a $rank counter in the foreach loop:

$rank=0;
// output the result: user, total postview count, latest post
foreach ($output as $user){
    $rank++;
    $profile = get_userdata($user['id']);
    $query = get_posts( array('author' => $user['id'], 'numberposts' => 1 ));

    // update the rank for each user
    update_user_meta( $user['id'], 'user_rank', $rank );

    echo '<div class="user-item">';
    echo '<p>' . $profile->user_nicename .' ('. $user['views'] .') [User Rank: '.$rank.']</p>';            
    foreach ( $query as $post ){
        echo '<a href="' . $post->post_name . '">' . $post->post_title . '</a>';
        echo get_post_meta($post->ID, get_post_views('normal'), true);
    }
    echo '</div>';
}

Update:

Calculating the rank for all the users might be a job for a cron service, for example:

  1. wp-cron,
  2. linux cron,
  3. external cron service
  4. custom cron.

Here is just one idea for part 2 and 3:

  1. Create a file called mycron.php
  2. Add the two code lines at the top of the file from here: http://codex.wordpress.org/Integrating_WordPress_with_Your_Website
  3. Add your code to mycron.php
  4. Increase the array_slice limit (it's currently set to only 10)
  5. Run mycron.php to test it
  6. Add the mycron.php to a cron service (eg. daily)
  7. Add time/memory measurements to mycron.php
  8. If this gets too heavy, try to divide it to other cronjobs (maybe 500 users per cronjob)
  9. Have a large cup of coffee ;-)

ps: remember to have a backup of your database.

Update 2:

Here is an exmple of your mycron.php file, if you want to try it out in your Wordpress root folder:

<?php 

define('WP_USE_THEMES', false);
require('./wp-blog-header.php');

global $wpdb;
$topuser = array();
$html = "";

// query all posts by each user
$users = $wpdb->get_results("SELECT ID FROM $wpdb->users ORDER BY ID"); 
foreach ( $users as $user ) {       
    $query = get_posts( array('author' => $user->ID,  'posts_per_page' => -1));
    $counter = 0;

    // get each post of a user
    foreach ( $query as $post ){
        $views = absint( get_post_views('normal') );
        $counter += $views;
    }
    $topuser[] = array( 'id' => $user->ID, 'views' => $counter);
    wp_reset_query();
}

// function to sort array based on views count
function sortViews($a, $b) {
    return $b['views'] - $a['views'];
}
usort($topuser, 'sortViews'); // sort the array

// output the result: user, total postview count, latest post
foreach ($topuser as $user){
    $rank++;
    $profile = get_userdata($user['id']);
    $query = get_posts( array('author' => $user['id'], 'numberposts' => 1 ));

// update the rank for each user
update_user_meta( $user['id'], 'user_rank', $rank );

$html .= '<div class="user-item">';
$html .= '<p>' . $profile->user_nicename .' ('. $user['views'] .') [User Rank: '.$rank.']</p>';            
foreach ( $query as $post ){
    $html .=  '<a href="' . $post->post_name . '">' . $post->post_title . '</a>';
    $html .=  get_post_meta($post->ID, get_post_views('normal'), true);
}
$html .= '</div>';
} 

echo $html;

printf(" Perfomance: %s queries in %s seconds ", get_num_queries(), timer_stop(0));

echo (file_put_contents("/path/to/ranks.html", $html)>0)? "Success!":"Problem writing to file!";
share|improve this answer
    
I updated the code, so you can test to save the $rank for each user (take db backup before testing). Use <?php echo get_user_meta( $user_id, 'user_rank', true ); ?> to retrieve the user rank for user with $user_id. –  birgire Apr 8 '13 at 13:52
    
Ok, I tried implementing your code on buddypress profiles and it works like a charm! You've been more helpful to me than the last 10 people I've went to combined. Thank you so much. I've wanted this feature for so long but never could figure it out until now. Now that the proper code is working in the ranking system, I've been trying to add div elements to the page inside 'foreach ($output as $user){' However I get an error when trying to do so. Is there an easy solution to this? Because I rather be able to style up the rankings page since right now its only a list. Thanksfor everything –  jspecs Apr 8 '13 at 20:38
    
Also one more thing (I promise this is my last question lol) you mentioned earlier the idea of running the loop only one or two times a day to avoid it bogging down the site. Is this feature already implemented in the code you gave me? –  jspecs Apr 8 '13 at 20:41
    
thanks ;-) I updated the answer, assuming you want to use linux cron or external cron services. –  birgire Apr 9 '13 at 14:48
1  
Since the moderator is angry(lol), I'll keep this short. It has taken a week of hours of searching but I finally got a working command line for a cron job in my site's cpanel: lynx -dump "http://yoursite.com/path/to/cronfile.php" Thank you for everything @birgire, I never would have been able to make my vision reality without you :-) –  jspecs Apr 28 '13 at 0:30
show 21 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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