WP_User_Query to exclude users with no posts

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.

Related posts

Leave a Reply

3 comments

  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 ';  
        } 
    }
    add_action('pre_user_query','authors_with_posts');
    

    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

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

    Example:

    $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.

  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;
                continue;
            } else {
                // do something;
            }
        }