I've recently moved to WordPress an active community site which is run and moderated by several editors and administrators. Each post gets dozens of comments, and I wanted to highlight those made by staff members.
What not to do
If you've googled a bit for a solution on how to identify authors' or admins' comments, you've probably seen several explanations on how to implement this by comparing emails. Something like:
- <?php
- if( $comment->comment_author_email == 'admin@blog.com' ) {
- $class = 'admin';
- }
- ?>
While this is sort of OK for a single author weblog, it's totally inconvenient and not scalable for a community site run by several editors and administrators: you would need to edit the template file whenever there's a new member in the staff, and nothing prevents an unlogged user from commenting using your well known email address.
So, what to do instead?
First, collect all users and their role
WordPress function get_users_of_blog() returns an array of all users with their user_id and role. We're going to loop through all users and collect their id's and roles in an array.
- $users = get_users_of_blog();
- foreach( $users as $user ) {
- $role = array_pop( array_keys( unserialize($user->meta_value) ) ); // yeah, I know, looks awkward :)
- $user_id = $user->user_id;
- if ( $role != 'subscriber' ) // collect id of anyone whose role is greater than 'subscriber'
- $roles[ $user_id ] = $role;
- }
At this point, the array $roles is populated with something like:
- $roles = array (
- '1' => 'administrator',
- '2' => 'editor',
- '3' => 'editor',
- '4' => 'administrator',
- '5' => 'author',
- );
Now identify for each comment the commenter's role
Typically, your theme has a file named comments.php with a loop that looks like this:
- <ol id="commentlist">
- <?php foreach ($comments as $comment) : ?>
- <li>
- <p>By <?php comment_author_link() ?> - <?php comment_date() ?></p>
- <?php comment_text() ?>
- </li>
- <?php endforeach; ?>
- </ol>
WordPress fetches every comment as an object containing, among others, the following informations:
- stdClass Object (
- [comment_author] => Joe
- [comment_author_email] => joe@email.com
- [comment_author_url] => http://joe.com/
- [comment_author_IP] => 100.101.102.103
- [user_id] => 4
- )
If the user is logged in, $comment->user_id is an integer greater than 0. If the user is not logged in (assuming non logged users can comment), $comment->user_id is zero.
A trivial way to get an user's role would be to issue a call to get_userdata( $user_id ) within the comment loop but that would add an extra query per logged in user, which is an unnecessary burden if you an active community of commenters and a lot of registered users.
Instead we'll simply compare each user_id with what we've collected at the beginning. The comment loop would be something like:
- <ol id="commentlist">
- <?php foreach ($comments as $comment) : ?>
- <?php // The extra stuff to get commenter's role
- $user_id = $comment->user_id;
- $role = ( isset( $roles[$user_id] ) ? $roles[$user_id] : '' );
- ?>
- <li class="<?php echo $role; ?>">
- <p>By <?php comment_author_link() ?> - <?php comment_date() ?></p>
- <?php comment_text() ?>
- </li>
- <?php endforeach; ?>
- </ol>
Now, identifying staff comments is just a matter of CSS:
- #commentlist li { border:2px solid white; } /* not logged or subscriber */
- #commentlist li.administrator { border:2px solid red } /* blog admin */
- #commentlist li.editor { border:2px solid blue } /* editor */
All in all
All in all, this very simple method only adds one extra query to the whole page (issued by get_users_of_blog()). You could even easily get rid of that extra query with caching in a flat .php file the array produced by get_users_of_blog() and refresh it with hooking into 'set_user_role' (see wp-includes/capabilities.php)
Shorter URL
Want to share or tweet this post? Please use this short URL: http://ozh.in/ro
Thanks Ozh.It really helped me.
What happens if you want to use threaded comments? :P
Better wrap it up in a plugin, if there isn't one already.
My .02 $.
Oh, and what the hell? I'm not in Sweden now! LOL.
I like the way you used the cache method here. Good job!
scribu » I don't think threaded comments would change anything
Yes it would, since you have to use wp_list_comments(), instead of a loop.
But I guess you could apply the same principle to the callback method.
Hey Ozh that's exactly what I was looking for. I'm not sure I understand though:
$users = get_users_of_blog(); does this have to be included as a function or something or will it work "out of the box" just as you described at the end of the post?
Simon: just inline in comments.php is fine
Thanks Ozh. It should work sitewide right, not only in comments, or am I still not getting something here?
I tried to add it somewhere else for an avatar class outside the comments loop. And it just give a blank output like this class=" ".
Have a great weekend
Simon » it will work anywhere. Paste your code snippet somewhere and I'll have a look
Merci beaucoup Ozh. Just for argument's sake, let's say I wanted to make the BuddyPress avatars show their role as a class, so I could style them.
I get an empty output. It's probably because I don't really get it ;)
I'm unsure of the scalability of getting and looping over ALL the users of the blog just to get a list of available roles. Could the code instead use the $wp_roles global?
Sensible?
S
Simon Wheatley » I'm not getting a list of available roles. I'm getting a list of *users* and their roles.
great.. nice info.. i was looking for this tutorial and found here..
thanks dude
Hello Ozh, thanks for the source code, it is what i'm looking for, an old source code that very important, thanks for your post Ozh.