WP_User_Query to exclude users with no posts

The question:

I see that it is possible to sort a user query by the number of posts each user has, but is it possible to exclude users with zero posts from the result? In the Wp_User_Query class there is a pre_user_query action, but query strings are a huge weak point, so I’m not sure what sort of filter action I’d want to use here.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Well I have come up with 2 solutions.

Solution 1 – foreach loop and verify each user

This one is based off of @GhostToast’s solution, but with updated WordPress functions

//new query with default args
$author_query = new WP_User_Query();

// Get the results
$authors = $author_query->get_results();

if( $authors ) {

    foreach( $authors as $author ) {

     if ( count_user_posts( $author->id ) >= 1 ) {

        echo $author->display_name . '</br>';
} else { 
    echo "no users found"; 

Solution 2 – fancy pants pre_user_query action

This is what I was thinking of when I posted my question once I found the pre_user_query action in the WP_User_Query class. If you pass in post_count as your orderby parameter then some fancy SQL querying that I never would’ve figured out on my own happens to join the proper tables together. So what I did was copy that join statement and add it on to my own. This would be better if I could check for its presence first before adding it… perhaps I will use a string match in the future. But for now since I am the one setting up the query I know it isn’t there and I just won’t worry about it yet. So the code turned out like so:

function authors_with_posts( $query ) {

    if ( isset( $query->query_vars['query_id'] ) && 'authors_with_posts' == $query->query_vars['query_id'] ) {  
        $query->query_from = $query->query_from . ' LEFT OUTER JOIN (
                SELECT post_author, COUNT(*) as post_count
                FROM wp_posts
                WHERE post_type = "post" AND (post_status = "publish" OR post_status = "private")
                GROUP BY post_author
            ) p ON (wp_users.ID = p.post_author)';
        $query->query_where = $query->query_where . ' AND post_count  > 0 ';  

and then to use it

$args = ( array( 'query_id' => 'authors_with_posts' ) );  
$author_query = new WP_User_Query( $args );

The idea for a query_id parameter is from An Introduction to WP_User_Class

Which is also just a very good reference on WP_User_Query

Method 2

Since 4.4, you can simply use the `has_published_posts’ parameter.


$authors = get_transient('mytheme_all_authors');
if (empty($authors)){

    $user_args = array(
    'role__in'    => array('Author', 'Administrator', 'Contributor'),
    'orderby' => 'post_count',
    'order'   => 'DESC',
    'count_total'  => true,
    'has_published_posts' => array('post'),

    $authors = new WP_User_Query( $user_args );
    set_transient('mytheme_all_authors', $authors, 1 * HOUR_IN_SECONDS );

$total= $authors->get_total();
$authors = $authors->results;
foreach ( $authors as $user) {
    // loop through your users....

has_published_postscan be either true/false (or null), or an array of post types (like in this example).

Note: I’m using transients here because this specific query can get pretty heavy depending on the system so it makes sense to store it for future uses.

Method 3

Submitting as answer for closure:

   $all_members = get_users();
      foreach($all_members as $member){
        $post_count = count_user_posts($member->ID);
        if(empty($post_count)) {
            $bad_writers[] = $member->ID;
        } else {
            // do something;

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment