Assuming I understood the question, what you need to do is hook into the two hooks related to column headers and columns value for the admin manage pages. They are 'manage_{$type}_columns'
and 'manage_{$type}_custom_column'
where in your use-case {$type}
is users
.
The 'manage_users_columns'
hook
This first one is simple, it lets you specify the column headers and hence the available columns. WordPress hardcodes the value of the "Posts" column so since you want to change it we are simply going to remove it with unset()
and then add a new column with the same title but which instead has the identifier of 'custom_posts'
:
add_action('manage_users_columns','yoursite_manage_users_columns');
function yoursite_manage_users_columns($column_headers) {
unset($column_headers['posts']);
$column_headers['custom_posts'] = 'Posts';
return $column_headers;
}
The 'manage_users_custom_column'
hook
Next you need to use the 'manage_users_custom_column'
hook which only gets called for non-standard columns. We test for $column_name=='custom_posts'
to make our code robust in case we add new user columns in the future and then we grab the user post type counts from the function I wrote _yoursite_get_author_post_type_counts()
which I'll discuss in next. I then played with a few ways to format this but decided an HTML <table>
was most appropriate (since it is a table of data). If a table doesn't work for you I assume you'll be able to generate different markup pretty easily:
add_action('manage_users_custom_column','yoursite_manage_users_custom_column',10,3);
function yoursite_manage_users_custom_column($custom_column,$column_name,$user_id) {
if ($column_name=='custom_posts') {
$counts = _yoursite_get_author_post_type_counts();
$custom_column = array();
if (isset($counts[$user_id]) && is_array($counts[$user_id]))
foreach($counts[$user_id] as $count)
$custom_column[] = "\t<tr><th>{$count['label']}</th>" .
"<td>{$count['count']}</td></tr>";
$custom_column = implode("\n",$custom_column);
}
if (empty($custom_column))
$custom_column = "No Posts!";
else
$custom_column = "<table>\n{$custom_column}\n</table>";
return $custom_column;
}
Getting Posts Counts by Post Type for Each User/Author
Lastly there is the retrieval of post counts by post type by author/user. Generally I try to stick with using WP_Query()
when running queries on posts but this query would have required using so many other hooks it just seemed easier to be "naughty" and do all in one.
I omitted any post of $post->post_type
is 'revision'
or 'nav_menu_item'
but left in 'attachments'
. You might find it better to explicitly include the post types you want instead of excluding the few I did.
I also filtered by $post->post_status
for only 'publish'
and 'pending'
. If you want to also include 'future'
, 'private'
and/or 'draft'
you'll need to make the changes in the code.
For each page load I only call this _yoursite_get_author_post_type_counts()
function once and then store into a static variable rather than call for each user. I store in an array indexed by author/user IDs containing an array with Post Type name in the element 'label'
and of course the count in a same-named element:
function _yoursite_get_author_post_type_counts() {
static $counts;
if (!isset($counts)) {
global $wpdb;
global $wp_post_types;
$sql = <<<SQL
SELECT
post_type,
post_author,
COUNT(*) AS post_count
FROM
{$wpdb->posts}
WHERE 1=1
AND post_type NOT IN ('revision','nav_menu_item')
AND post_status IN ('publish','pending')
GROUP BY
post_type,
post_author
SQL;
$posts = $wpdb->get_results($sql);
foreach($posts as $post) {
$post_type_object = $wp_post_types[$post_type = $post->post_type];
if (!empty($post_type_object->label))
$label = $post_type_object->label;
else if (!empty($post_type_object->labels->name))
$label = $post_type_object->labels->name;
else
$label = ucfirst(str_replace(array('-','_'),' ',$post_type));
if (!isset($counts[$post_author = $post->post_author]))
$counts[$post_author] = array();
$counts[$post_author][] = array(
'label' => $label,
'count' => $post->post_count,
);
}
}
return $counts;
}
The Resultant UI
And this is what it looks like applied to my test install of WordPress 3.0.1:

(source: mikeschinkel.com)
Download the Full Code
You can download the full code from Gist:
You can copy this code into your theme's functions.php
file or store include the file in a plugin, whichever you choose.
Hope this helps!