Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get wordpress authors in order by the number of custom posts published

Tags:

php

wordpress

In my WordPress v5.8.1, I have a list of authors who post in custom posts song and poem. With the below code I am getting the list of authors who posted in the both or either in one custom post.

 $authors = get_users(array(
        'who' => 'authors',
        'has_published_posts' => array('song','poem'),
        'orderby' => 'post_count',
        'order' => 'DESC',
        'number' => '15'
 ));

Below code is listing all the authors with their post counts:

foreach ($authors as $user) {
   $name = $user->first_name . ' ' . $user->last_name;
   $songs = count_user_posts($user->ID, $post_type = "song");
   $poems = count_user_posts($user->ID, $post_type = "poem");
   echo $name.' has '. $songs .' songs, and '. $poems .' poems;
}

With 'orderby' => 'post_count' in the arguments, I expected the authors list with highest combined custom posts count displayed first, however it is showing randomly with no order, neither by post_counts nor ID.

How can I order the authors with most combined total posts?

like image 230
theKing Avatar asked Nov 05 '20 14:11

theKing


2 Answers

Try below code.

$authors = get_users(array(
    'who' => 'authors',
    'has_published_posts' => array('song','poem'),
    'orderby' => 'post_count',
    'order' => 'DESC',
    'number' => '15'
));

Create one array and count total poem + songs

$author_posts = array();

foreach ($authors as $user) {
    $name = $user->first_name . ' ' . $user->last_name;
    $songs = count_user_posts($user->ID, $post_type = "song");
    $poems = count_user_posts($user->ID, $post_type = "poem");
    $author_posts[] = array(
        'total' => $songs+$poems,
        'label' => $name.' has '. $songs .' songs, and '. $poems .' poems'
    );
}

now use `usort to sort an array by total.

usort($author_posts, function($a, $b) {
    if($a['total']==$b['total']) return 0;
    return $a['total'] < $b['total']?1:-1;
}); 

print the output.

foreach ( $author_posts as $key => $author_post ) {
    echo $author_post['label']."</br>";
}

Complete code.

$authors = get_users(array(
    'who' => 'authors',
    'has_published_posts' => array('song','poem'),
    'orderby' => 'post_count',
    'order' => 'DESC',
    'number' => '15'
));

$author_posts = array();

foreach ($authors as $user) {
    $name = $user->first_name . ' ' . $user->last_name;
    $songs = count_user_posts($user->ID, $post_type = "song");
    $poems = count_user_posts($user->ID, $post_type = "poem");
    $author_posts[] = array(
        'total' => $songs+$poems,
        'label' => $name.' has '. $songs .' songs, and '. $poems .' poems'
    );
}

usort($author_posts, function($a, $b) {
    if($a['total']==$b['total']) return 0;
    return $a['total'] < $b['total']?1:-1;
}); 

foreach ( $author_posts as $key => $author_post ) {
    echo $author_post['label']."</br>";
}

Tested and works.

like image 99
Bhautik Avatar answered Nov 10 '22 11:11

Bhautik


First, the orderby argument of function get_users() works with post_count but counts all post types (here, it is counting poem, song and the others types like post or page).

If you want to order your results by specific custom post types, I would recommend to use the wpdb class to design your own request. This allows you to get the exact desired results with one single request and no need to use a foreach to sort your results after.

I tried this way and it worked:

$authors = $wpdb->get_results(
    "SELECT
        $wpdb->users.ID AS author_id,
        $wpdb->users.display_name AS author_name,
        COUNT($wpdb->posts.ID) AS published_songs_and_poems,
        COUNT(CASE WHEN $wpdb->posts.post_type = 'song' THEN $wpdb->posts.ID ELSE NULL END) as published_songs,
        COUNT(CASE WHEN $wpdb->posts.post_type = 'poem' THEN $wpdb->posts.ID ELSE NULL END) as published_poems
    FROM $wpdb->users
    JOIN $wpdb->posts
        ON $wpdb->posts.post_author = $wpdb->users.ID
        AND $wpdb->posts.post_type IN('song', 'poem') AND $wpdb->posts.post_status = 'publish'
    GROUP BY author_id
    ORDER BY published_songs_and_poems DESC"
);

This request return an object with results grouped by author and order by total amount of published songs and poems.

You can use this object as you already did. Something like this :

array_walk($authors, function($author) {
    echo $author->author_name." has published ".$author->published_songs." song(s) and ".$author->published_poems." poem(s).<br/>";
});

I edited this answer because the first version focused on how to return the results order by total post_count. This was clarified when commented by @theKing.

like image 28
Lagaart Avatar answered Nov 10 '22 12:11

Lagaart