3

I want to display Y number of authors' info randomly. These authors have to have at least X numbers of posts published.

Please keep in mind that this would be for a blog with thousands of users where most of them have published 0 posts.

I have looked at functions like wp_list_authors() and WP_User_Query() but I cant seem to be able to set the minimum number of posts each author needs to have.

I have tried to get the authors with those functions and then, with a loop, test for each author id and see if they have posted X number of posts or more. (I want to avoid this because it seems too tedious and might be too poor performance wise.

I could order them in descending order, shuffle the array and display the users' info, but I do not want this because I prefer to showcase users with low number of posts.

If I order them in ascending order, I would get hundrends or thousands of users with 0 posts. However, here I can use wp_list_authors() as indicated by @s_ha_dum in: Total number of authors with more than one post that excludes authors with 0 posts but what if I want to get users that have at least 2 or more posts?

Finally, I could use a pre_user_query filter as explained by @helgatheviking in: WP_User_Query to exclude users with no posts

Is this the best solution?What about performance? Is there a better solution? If so, what would you recommend me do?

2

You can get rid of most of your code above. WP_User_Query has an include parameter (introduced in Wordpress 3.9)

include (array) - List of users to be included.

So we need to get a random array of author ID's. I have modified your count_users_with_posts() a bit here to extend it to make it more dynamic and to get a set amount of authors randomly. I also had to repair a few bugs (some SQL errors, specially this line: WHERE post_count > %s ORDER BY count DESC. You should enable debugging when developing :-))

CAVEAT: This works on my local install with 4 users.

function get_author_posts_count( $min_posts = 1, $max_posts = 10, $limit = 10, $post_type = 'post' )
{
    global $wpdb;

    $authors = $wpdb->get_col(
        $wpdb->prepare(
            "SELECT post_author FROM (
                SELECT post_author, COUNT(*) AS count 
                FROM $wpdb->posts
                WHERE post_type = %s 
                AND post_status='publish' 
                GROUP BY post_author
            ) AS stats
            WHERE stats.count BETWEEN %d AND %d
            ORDER BY RAND()
            LIMIT 0,%d",
            $post_type,
            $min_posts,
            $max_posts,
            $limit
        )
    );

    return $authors;
}

As you can see, I have included 4 parameters here.

  • $min_posts -> Minimum amount of published posts an author must have. Default 1

  • $max_posts -> As you would like to get authors with low post count, I have included a maximum post count. You can remove that if you wish, just remember to change the SQL accordingly then Default 10

  • $limit -> The amount of post authors to get. Default 10

  • $post_type -> The post type to get use. Default post

You can then use the function above in your WP_User_query as follow

$args = [
    'include' => get_author_posts_count( 5, 20, 5, 'my_post_type' )
];

$authors = new WP_User_Query( $args );

EDIT

From comments (thanks @birgire), there are a few issues that you should take note of

  • Before passing the result of get_author_posts_count() to the include parameter of WP_User_Query, you should check whether or not if any values are available. If the result of get_author_posts_count() is empty or invalid, the include parameter will be ignored and all users will be returned. The query will not return an empty array of users

  • There is a limit on the lenght of an SQL query, so very big author queries might crash. As I already stated, my test site is really small, so I cannot test my code to the max. You should also check out this post on SQL query lentghs

I would appreciate any feedback on tests on large sites with many posts and plenty authors

  • +1 also a good reminder of the newly include attribute. I was wondering about the case when the query returns an empty array (no results found) Then it looks like WP_User_Query ignores include? We should also notice that there might be a limit to the length of the SQL query, if we want to include many user ID's. – birgire May 5 '15 at 14:29
  • @birgire thanks for your input. My code does need a bit of clean up. I quickly modified everything before work and quickly tested it. I need to look at this again a bit later. My SQL is still really bad, so there might still be a snitch here and there :-) – Pieter Goosen May 5 '15 at 15:39
  • Thanks for pointing out the include parameter, i was totally unaware of it. On another note, I was thinking that for my case, I could even get rid of WP_User_query because I could use a custom query (in this case with the function get_author_posts_count()) to fetch authors' ids randomly, or would I still have any advantages using WP_User_query? I do not understand your second point about the length of an SQL query, the post you mentioned talks about the length of the query itself and not the amount of data that it needs to retrieve from the dabatase, right? I only need to retrieve a few ids. – Gixty May 5 '15 at 20:04
  • It all depends on what data you need to get. get_author_posts_count() just gets an random amount of author ID's. WP_User_Query gets all the data related to an author, so passing the resultant array of author ID's to WP_User_Query will get you all that authors data. You will need to look at your situation and according to that decide the best route. If you only need a few id's, you should be fine. I'm still learning SQL, so I might have understood that part aswell :-) – Pieter Goosen May 6 '15 at 4:31
  • Wordpress also always discourage custom SQL queries as you loose filters and you always have the disadvantage that custom SQL needs to be updated manually should table structures change where as with native functions this is done by core developers. Your is a unique case, so I would probably go with custom SQL here. – Pieter Goosen May 6 '15 at 4:37
1

This is a rough draft of what I have so far. Please feel free to update it and improve it.

First of all, we use the pre_user_action to choose the minimum number of posts a user needs to have in order to get their info and display it. It was taken from WP_User_Query to exclude users with no posts (by @helgatheviking). I just made some minor changes to fit my needs.

add_action( 'pre_user_query', 'users_with_posts',10, 1 );

function users_with_posts( &$query) {
    global $wpdb;
    $min_posts = 5; 
    if ( isset( $query->query_vars['query_id'] ) && 'wps_last_name' == $query->query_vars['query_id'] )
         $query->query_from = $query->query_from . " LEFT OUTER JOIN (
                      SELECT post_author, COUNT(*) as post_count
                      FROM $wpdb->posts
                      WHERE post_type = post AND post_status = publish
                      GROUP BY post_author
                    ) p ON ({$wpdb->users}.ID = p.post_author)
                    ";

        $query->query_where = $query->query_where . " AND post_count  > {$min_posts} ";  
}

Then, we need the total number of users who have posted more than X number of posts.

function count_users_with_posts($min_posts) {
        global $wpdb;
        $author_ids = $wpdb->get_col($wpdb->prepare("SELECT post_author FROM
            (SELECT post_author, COUNT(*) AS post_count FROM {$wpdb->posts}
                WHERE post_type = 'post' AND post_status='publish' GROUP BY post_author) AS stats
            WHERE post_count > %s ORDER BY count DESC;",$min_posts));
        return count($author_ids);
}

Now we are ready to proceed and use the WP_User_query() function to get our "random" users. They are not 100% randomly chosen but it is as close as I can get it.

These are the args for our function:

$args = array (
    'query_id' => 'users_with_posts',
    'orderby' => 'post_count',
    'order' => 'ASC', //default
    'number' => $total_number,
    'offset' => $offset,

); 

You can see we are missing two variables, well here is where get to play a little. We will generate a random offset to get the "random" effect.

$total_number = 12; //number of users we want to display
$total_authors = count_users_with_posts(5); //total number of users with more than 5 posts
$offset = mt_rand(0,$total_authors - $total_number); //randomly generated offset.

$users = new WP_User_Query( $args );

There is plenty of room for improvement, I hope someone takes it from here, or if there is a different and better way, you are more than welcome to share it.

  • Check my answer and the answer by @birgire to this question. This might help you a bit. It is at least the route that I'm thinking of :-) – Pieter Goosen May 4 '15 at 8:38
  • Thanks @PieterGoosen I see what @birgire did. I could as well ORDER BY RAND() in the pre_user_query action. I will try that later and see how it works. I need to get some sleep now. Do you say in your post with how many users you did your test on? – Gixty May 4 '15 at 8:51
  • My test was on 4 or 5 authors. Unfortunately my test site is small, it will be very interesting how this will do on a large site with many authors. Have a good rest, will see what I can do tonight as well. Enjoy :-) – Pieter Goosen May 4 '15 at 8:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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