WordPress 2.7 introduced a simplified way of listing comments with a new function called wp_list_comments() for use in a theme’s comments.php. This automatically takes care of the display of the author, date, avatar, comment text etc, rather than the more complex way used for older versions of WordPress. This is all fine and dandy, but actually makes customising the output of the comments – ie what exactly is displayed – slightly more complex.
wp_list_comments()
I’m not going to repeat all that can be found on the Codex, see wp_list_comments() for details, but essentially the function has a fairly limited set of arguments, none of which relate to some of the elements mentioned above. For example, it isn’t possible to exclude the comment date, or avatar, by playing directly with the function’s arguments.
Custom callback
Luckily, the WP developers saw fit to include the the use of a callback function within wp_list_comments(). The callback function is called like this:
wp_list_comments('type=comment&callback=mytheme_comment');
What this means is that wp_list_comments() will return the output of the callback function rather than it’s default output. So, to create our own customised output, we simply need to define a suitable callback function, in this example a function called mytheme_comment, in our theme’s functions.php.
And this is exactly what I have done on www.studiograsshopper.ch, where I use a custom callback function to display Trackbacks and Pingbacks differently from normal comments. You can see an example here.
If you look at the Trackbacks on the post linked above you will see that the display is simplified: there is no Reply button, and I’ve changed the default “Says” text to “Wrote”. There are some CSS tweaks too, but let’s ignore those for the moment.
A “default” custom callback function
Here’s the example custom callback function shown in the Codex:
function mytheme_comment($comment, $args, $depth) { $GLOBALS['comment'] = $comment; ?> <li <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>"> <div id="comment-<?php comment_ID(); ?>"> <div class="comment-author vcard"> <?php echo get_avatar($comment,$size='48',$default='<path_to_url>' ); ?> <?php printf(__('<cite class="fn">%s</cite> <span class="says">says:</span>'), get_comment_author_link()) ?> </div> <?php if ($comment->comment_approved == '0') : ?> <em><?php _e('Your comment is awaiting moderation.') ?></em> <br /> <?php endif; ?> <div class="comment-meta commentmetadata"><a href="<?php echo htmlspecialchars( get_comment_link( $comment->comment_ID ) ) ?>"><?php printf(__('%1$s at %2$s'), get_comment_date(), get_comment_time()) ?></a><?php edit_comment_link(__('(Edit)'),' ','') ?></div> <?php comment_text() ?> <div class="reply"> <?php comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?> </div> </div> <?php }
Basically, if we were to run this function and view its output, we would see exactly the same result as the normal comments on this site. In other words, this function will produce the same output as the following code in a typical theme’s comments.php file:
<?php wp_list_comments('type=comment'); ?>
Now we have a base to work from, it’s not too difficult to edit this function to give us the output we want. In my case, I wanted to display Trackbacks and Pingbacks differently from normal comments.
Customising Trackbacks and Pingbacks
Let’s look at how I customised the theme on my site to achieve this.
First, I opened up my theme’s comments.php and found the wp_list_comments() used to display trackbacks and pingbacks:
<?php wp_list_comments('type=pings'); ?>
Note that type=pings covers both trackbacks and pingbacks.
I then added the call to my custom callback function to the existing code:
<?php wp_list_comments('type=pings&callback=custom_pings'); ?>
Then, in functions.php, I added the Codex example callback function, renamed it to custom_pings, then edited this function to remove the elements I didn’t want, in my case:
1. Removed the line for the avatar:
<?php echo get_avatar($comment,$size='48',$default='<path_to_url>' ); ?>
2. Removed the code for the Reply button:
<div class="reply"> <?php comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?> </div>
Here’s the final version of the callback function as used in my functions.php:
/* Custom callback function for Trackbacks/Pings, see comments.php */ function custom_pings($comment, $args, $depth) { $GLOBALS['comment'] = $comment; ?> <li <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>"> <div id="comment-<?php comment_ID(); ?>"> <div class="comment-author vcard"> <?php printf(__('<cite class="fn">%s</cite> <span class="says">wrote:</span>'), get_comment_author_link()) ?> </div> <?php if ($comment->comment_approved == '0') : ?> <em><?php _e('Your comment is awaiting moderation.') ?></em> <br /> <?php endif; ?> <div class="comment-meta commentmetadata"><a href="<?php echo htmlspecialchars( get_comment_link( $comment->comment_ID ) ) ?>"><?php printf(__('%1$s at %2$s'), get_comment_date(), get_comment_time()) ?></a><?php edit_comment_link(__('(Edit)'),' ','') ?></div> <?php comment_text() ?> </div> <?php }
To recap
There’s a lot of code on this page, so let’s simplify the steps so that you can do something similar on your own site.
- Look at your comments.php file and find the call to wp_list_comments()
- Within wp_list_comments(), add the call to the custom callback function
- Take the Codex example custom callback function, and paste this code into your theme’s functions.php
- Make sure the function name is the same in both the wp_list_comments() function in comments.php, and the theme’s functions.php
- Edit the callback function in functions.php as required. Note: don’t include a closing li tag – WordPress adds this automatically depending on the comment output.
- Add new styles to your style.css file, or edit existing comment related styles in style.css, as necessary.
A final word – the Codex actually advises against using callback functions with wp_list_comments(), which seems odd given that the developers added this capability in the first place. I’ve been running this code for a while now, without problems, and have no hesitation in recommending the use of a callback function if you need maximum flexibility to control the output of wp_list_comments().
Very nice and helpful article. I appreciate you taking the time to put it together.
A quick question for you:
Where at in the functions.php file would you paste this code? The beginning, end, etc…?
Thanks.
JAB
@Josh,
It doesn’t really matter where you place it in functions.php, unless your functions.php has include_once or require_once calls, and the included files need to be included before your new code.
I would place it at the bottom of the file, to be on the safe side.
Nice article Josh,
yes – always drop in these kind of additional callabacks at the bottom of your functions file just to be on the safe side.
Thanks for the help, guys.
I’m still having a little bit of trouble. This is the code I pasted in the bottom of my functions.php file:
/* Custom callback function for Trackbacks/Pings, see comments.php */
function custom_pings($comment, $args, $depth) {
$GLOBALS[‘comment’] = $comment; ?>
<li id="li-comment-“>
<?php printf(__('%s spake thusly on’), get_comment_author_link()) ?>comment_ID ) ) ?>”>:
comment_approved == ‘0’) : ?>
<?php
}
I don't think WP likes something in there, because when I upload the revised comments.php and functions.php, and then click on my website, nothing happens. I made sure that the callback in my comments.php file matches that in my functions.php file. The callback is:
The general effect I’m going for is this:
Josh Bales spake thusly on December 16th, 2009 at 2:12 pm:
I am a man of many mysteries.
Again, any insight you can offer would be greatly appreciated.
JAB
I completely buggered up the above message with the code I included, so I just uploaded the message and relevant code to my site. It’s at http://joshbales.net/callbackcode.txt if you care to take a look.
Thanks.
JAB
Josh,
Your code seems OK to me. You did add the callback reference to wp_list_comments in comments.php?
What errors do you get?
when I tried to add this:
/* Custom callback function for Trackbacks/Pings, see comments.php */
function custom_pings($comment, $args, $depth) {
$GLOBALS[‘comment’] = $comment; ?>
<li id=”li-comment-“>
<div id="comment-“>
<?php printf(__('%s wrote:’), get_comment_author_link()) ?>
comment_approved == ‘0’) : ?>
<a href="comment_ID ) ) ?>”>
<?php
}
on the functions.php I got this error message:
Parse error: syntax error, unexpected '}' in /home4/popsicl2/public_html/wp-content/themes/magadine12/functions.php on line 26
I’m not sure your code pasted properly here. Re-post your code and wrap it in code tags (as shown above the comment reply box).
Which line is line 26?
Did you find a solution for this by any chance? I am having the same issue. I posted it separately but wanted to ask you as well. Any help would be much appreciated. Thanks!
Thanks for the details.
I could follow your advice and i am seeing that in your site when i press Reply, Javascript os workng, but when i our website page is getting reloaded.
any idea?
for your ref, our page is http://www.dealsway.net/demo1/bookstore/product/?prid=6
Do you have this in your header.php?
It should be just above the call to wp_head().
yes, i have this.
i am seeing that as a result of this following is getting added to the header
http://www.dealsway.net/demo1/bookstore/wp-includes/js/comment-reply.js?ver=20090102
i could solve the issue.
basically, following was missing insie my older form,
div class=”cancel-comment-reply”>
once i add that, javascript works fine.
can you take care of ur post for this as well.
This article assumes that your theme uses a post-WP 2.7 comments form.
Glad you fixed it. 🙂
This is a beautifully clear tutorial – thanks!
The issue I’m having is that it feels a little heavy-handed for what I want to achieve. Essentially, I want to add a custom class to each comment IF the user is a logged-in administrator (which will act as a hook for some AJAXy fun to do with moderating comment karma). So I only want to add a class, rather than entirely replace the output of wp_list_comments().
Is there a better way to achieve this? Or do I just have to accept that I’ll need to write it all out again?
Hi,
You can do it through CSS. WordPress adds the class “comment-author-admin” to Admin’s comments. This doesn’t deal with is/isn’t logged in though.
Hi. Thanks for the tutorial.
I understand it, but somehow I’m having problems.
I basically copied and pasted ‘type=comment&callback=mytheme_comment’ to create wp_list_comments(‘type=comment&callback=mytheme_comment’); in my comments.php file and copied and pasted the exact sample code from the Codex into my function.php file (which currently does not have any other code).
However I keep receiving this error message:
Parse error: syntax error, unexpected ‘}’ in /home4/popsicl2/public_html/wp-content/themes/magadine12/functions.php on line 26
I believe it was mentioned above by someone else, but I’m not sure the issue was resolved. Would anyone have any advice? Is there any other code from other files that may be affecting the code on functions.php?
Thanks.
this is great! thanks
That’s odd – the Twenty Ten theme (ie the new default theme in WordPress 3.0) use a callback. So obviously it can’t be a problem!
Indeed, the callback works fine. The Codex is a Wiki, so anyone can put what they like in there. Perhaps, when wp_list_comments was first introduced, the callback function was a bit flaky, hence the Codex author’s comments. Works fine for me though.
Actually, I just edited the documentation at http://codex.wordpress.org/Template_Tags/wp_list_comments#Parameters to change the “Not recommended” to “Use with caution”, which I think is more appropriate.
Cool! Thanks for posting this. 🙂
Hi Grasshopper,
Thanks for the article.
I’m using the callback and it’s all good except for one thing:
I can’t seem to find the css entity that controls “.postbyauthor”, “.by user”, “.comment-author-admin”, etc.
I like to set different background colours depending on who the comment author is.
Help?
Look at your Page Source. You should see that WP automatically automatically adds various classes to each comment. You can then add appropriate styles referencing these classes in your style.css.
Hi, thanks for answering..
When I arrived at this page, I had already been using the custom call back “successfully” ( aside from the li classes) but I was using the callback as it appears on wordpress.org, and in source, the comment “li”s had NO classes.
It finally occurred to me to switch to the callback code included with this article and all the comment “li” classes “came back”. This article was a huge help – thanks.
P.S. You should get your code to replace the code on the wordpress.org site.
This is an brilliant example of a proper work-through. It has a simple intro, a well-explained work-through and, most importantly, an excellent summary. I just wish other bloggers could write like this! Bookmarked for future reference. Thank you.
Thanks, Jamie. Glad you found it useful. 🙂
One kind HELP! request:
I’d like to use this plugin http://wordpress.org/extend/plugins/add-local-avatar/
They say to put some code in this way
* Inside the comment loop of comments.php use to show the comment author’s avatar.
Sorry, but I’m not enough strong to understand where that loop is :-))
as a matter of fact, inside the comments.php file, I find only the following code that should be such loop, but my knowledge is not enough to understand where to insert
thank you if you tip me 🙂
Robert
'twentyten_comment' ) );
?>
Sorry, the code doesn’t show.
How to show the code in this blog?
Thank you
Robert
Use <pre>tags around your code</pre> like this:
thanks very much!
This is the best solution that I found on web!
have a nice day! 🙂
You’re welcome! 🙂
Glad you found it useful.
Thanks! Just wondering, it is possible to change the position of the comments? Let’s say i want to sort the highest rated comment to display as the first comment.
I guess you are using a comments rating plugin. What did the plugin author say?
He told me to do it myself… I used your code up there to create two functions, one to output the one with highest rating and highlight it. The other to output all other comments. Guess I will put in the sorting later but it’s working fine.
Cool! 🙂
Thank you so much for this, i’ve been following all sorts of guides that just screw up my code. I actually know kind of what i’m doing now!
However I do have one question. To style the comments, you obviously need css, and in the css you need to call each of the id’s or classes. But when you have this:
<div id="comment-“>
or
How are you supposed to call that in CSS? Im learning btw, so its a question not a comment about the code :p
Glad you found it useful. 🙂
The short answer is that you don’t. That ID is unique to each individual comment. You need to target the wrapper div which has an id of “comments” (note the plural), which is created by the main wp_list_comments() function.
More importantly, if you want to style author commnets differently to other users, is to look at the classes automatically added to the <li> tag of each comment. (Remember, the comment list is a “list”). Look at your Page Source and you’ll see what I mean.
Great! Cool! Thanks for posting this. 🙂
So, if I have this:
, I must just to comment it and replace with
(see the source)
Yes. Try it and see. 🙂
Sorry, my previous message is a question. Any suggestions? Please help!
How To Add Reply {Comment Threading} Fungction Manualy ?
Ade,
Absolutely Fantastic! Was just about to throw in the towel with respect to gaining added control over wp_list_comments() and then found your post. It took a little bit to fully understand what was going on, but you hit the nail on the head. Thank You!
FYI, deploying this on WP 3.1.2 with a theme manager plug-in and the ‘custom comment’ plug-in because I want to gather — and thanks to you — report additional field-level data associated with Comments.
Again, Thank You.
– Mark
Thanks for posting, Mark!
Glad you found the article useful. 🙂
Very nice “wp_list_comments()”
Will try to use it in my works.
But not at all understand callback of functions.php.
Good article! Tnx, Mark!))
A “callback” is a function which is passed as an argument to another function.
In our example, the function custom_pings() is the “callback”. This needs to be placed in your functions.php.
To make it do something useful, this callback then has to be passed to the wp_list_comments() function (which probably appears in your theme template files), like this:
wp_list_comments('type=pings&callback=custom_pings');
Hi,
What do I do if I don’t have a comments.php file? I had a custom WP theme made for me but they never made a comment section, so I’m attempting to make one on my own. However, I’m not sure: Should I just make my own comments.php file or should I download another theme and try and take it from there? Any help would be appreciated, thanks!
Hi,
I’m having trouble with this. I have a custom theme, and it only displays this:
'div')); ?>
in the comments.php – what do you suggest I do? I just want to remove the URL field.
Regards,
For some reason it got rid of it. I meant this:
'div'));
?>