I wound up replacing the wp_list_authors() function. It went pretty smoothly. Here's the function I made (sorry, it's long):
function custom_list_authors_2($args = '', $user_levels) {
global $wpdb;
$defaults = array(
'optioncount' => false, 'exclude_admin' => true,
'show_fullname' => false, 'hide_empty' => false,
'feed' => '', 'feed_image' => '', 'feed_type' => '', 'echo' => true,
'style' => 'list', 'html' => true
);
$r = wp_parse_args( $args, $defaults );
extract($r, EXTR_SKIP);
$return = '';
$user_levels = implode(',', $user_levels);
$contributors = $wpdb->get_results("SELECT user_id from $wpdb->usermeta WHERE meta_key = 'wp_user_level' AND meta_value IN ($user_levels)" . ($exclude_admin ? " AND user_login <> 'admin' " : '') );
$contributor_IDs = array();
foreach ( (array) $contributors as $contributor )
{
$contributor_IDs[] = $contributor->user_id;
}
$contributor_IDs = implode(',', $contributor_IDs);
/** @todo Move select to get_authors(). */
$authors = $wpdb->get_results("SELECT ID, user_nicename from $wpdb->users WHERE ID IN ($contributor_IDs)" . ($exclude_admin ? " AND user_login <> 'admin' " : '') . "ORDER BY display_name");
$author_count = array();
foreach ((array) $wpdb->get_results("SELECT DISTINCT post_author, COUNT(ID) AS count FROM $wpdb->posts WHERE post_type = 'post' AND " . get_private_posts_cap_sql( 'post' ) . " GROUP BY post_author") as $row) {
$author_count[$row->post_author] = $row->count;
}
foreach ( (array) $authors as $author ) {
$link = '';
$author = get_userdata( $author->ID );
$posts = (isset($author_count[$author->ID])) ? $author_count[$author->ID] : 0;
$name = $author->display_name;
if ( $show_fullname && ($author->first_name != '' && $author->last_name != '') )
$name = "$author->first_name $author->last_name";
if( !$html ) {
if ( $posts == 0 ) {
if ( ! $hide_empty )
$return .= $name . ', ';
} else
$return .= $name . ', ';
// No need to go further to process HTML.
continue;
}
if ( !($posts == 0 && $hide_empty) && 'list' == $style )
$return .= '<li>';
if ( $posts == 0 ) {
if ( ! $hide_empty )
$link = $name;
} else {
$link = '<a href="' . get_author_posts_url($author->ID, $author->user_nicename) . '" title="' . sprintf(__("Posts by %s"), esc_attr($author->display_name)) . '">' . $name . '</a>';
if ( (! empty($feed_image)) || (! empty($feed)) ) {
$link .= ' ';
if (empty($feed_image))
$link .= '(';
$link .= '<a href="' . get_author_feed_link($author->ID) . '"';
if ( !empty($feed) ) {
$title = ' title="' . $feed . '"';
$alt = ' alt="' . $feed . '"';
$name = $feed;
$link .= $title;
}
$link .= '>';
if ( !empty($feed_image) )
$link .= "<img src=\"$feed_image\" style=\"border: none;\"$alt$title" . ' />';
else
$link .= $name;
$link .= '</a>';
if ( empty($feed_image) )
$link .= ')';
}
if ( $optioncount )
$link .= ' ('. $posts . ')';
}
if ( !($posts == 0 && $hide_empty) && 'list' == $style )
$return .= $link . '</li>';
else if ( ! $hide_empty )
$return .= $link . ', ';
}
$return = trim($return, ', ');
if ( ! $echo )
return $return;
echo $return;
}
Stick this code at the top of your file and call it in place of wp_list_authors(). The added parameter is an array of user levels to select for. 10 = admin, 7 = editor, 2 author, 1 = contributor. The query probably could have been done better, but it saved me lot of time in writing it. Hopefully, somebody will find this useful.