in Tutorials, WordPress

Enhancing the comments list in WordPress

With the introduction of the wp_list_comments() function, WordPress enabled users to easily list comments on the websites without having to manually run a series of loops and queries to get the comments into neat XHTML. This function outputs default code with a selection of options for how this code is structured. Today we’ll be customising how comments are displayed in our WordPress theme, and adding a few extra enhancements to our comments while we’re at it (one of them being the Twitter username we added before). Lets start with the callback, shall we?

“Callback”, you say? Erm… what’s that?

“callback” is one of the arguments we can pass to the wp_list_comments() function. The “callback” argument expects a string which, in this case, is the name of our callback function. Essentially, by using the “callback” argument, we’re saying to WordPress; “okay, that layout looks cool, but use this awesome layout instead”.

So… this function…

Right. The meat of this method is the callback function itself. This is the code that will be used to display each comment in the list. No need to create the list itself, just the items (as is most likely done in your comments.php theme file at this time). The callback function we’ll be creating looks something like this:

<?php
/**
* matty_comment_layout()
* A callback function to be used with the wp_list_comments() function.
*/
function matty_comment_layout ( $comment, $args, $depth ) {
$GLOBALS['comment'] = $comment;
$path_to_default_gravatar = get_bloginfo('stylesheet_directory') . '/assets/images/gravatar.png';
$twitter = '';
$twitter = get_comment_meta( get_comment_ID(), 'twitter', true );
if ( $twitter != '' ) {
$twitter = strtolower($twitter);
$twitter = str_replace(' ', '', $twitter);
$twitter = str_replace('.', '', $twitter);
$twitter = ' <span>(<a href="http://twitter.com/' . $twitter . '" rel="nofollow">' . $twitter . '</a>)</span>';
} // End IF Statement
// Sanitise gravatar and make sure the image has an ALT attribute that isn't empty.
$gravatar = get_avatar($comment,$size='48',$default=$path_to_default_gravatar );
$gravatar = str_replace ("alt=''", 'alt="' . $comment->comment_author . '\'s Gravatar"', $gravatar);
?>
<li <?php comment_class(); ?> id="comment-<?php echo $comment->comment_ID; ?>">
<div><?php echo $gravatar; ?><?php printf( __('<cite>%s</cite>'), get_comment_author_link(), $twitter ); ?></div>
<div><?php printf(__('Posted %1$s at %2$s (%3$s ago)', 'matty'),
get_comment_date(),
get_comment_time(),
human_time_diff(get_comment_date('U'), current_time('timestamp')) ); ?></div>
<?php if ($comment->comment_approved == '0') _e("\t\t\t\t\t<span class='unapproved'>Your comment is awaiting moderation.</span>\n", 'matty') ?>
<div><?php comment_text(); ?></div><!--/.comment-content-->
<div><?php printf(__('<a href="%1$s" rel="bookmark" title="Permalink to ' . $comment->comment_author . '\'s comment">Permalink</a>', 'matty'),
'#comment-' . $comment->comment_ID );
edit_comment_link(__('Edit', 'matty'), '<span>', '</span>'); echo get_comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?></div><!--/.comment-links-->
<?php
} // End matty_comment_layout()
?>

Okay, that’s a long snippet. Lets go through it.

function matty_comment_layout ( $comment, $args, $depth ) {

This is our opening function tag. What’s important to note here is the passing of three arguments: the $comment we’ll be displaying, the $args that go along with that comment and the $depth of the comment in the structure.

$GLOBALS['comment'] = $comment;
$path_to_default_gravatar = get_bloginfo('stylesheet_directory') . '/assets/images/gravatar.png';
$twitter = '';
$twitter = get_comment_meta( get_comment_ID(), 'twitter', true );

if ( $twitter != '' ) {

$twitter = strtolower($twitter);
$twitter = str_replace(' ', '', $twitter);
$twitter = str_replace('.', '', $twitter);
$twitter = ' <span>(<a href="http://twitter.com/' . $twitter . '" rel="nofollow">' . $twitter . '</a>)</span>';

} // End IF Statement

// Sanitise gravatar and make sure the image has an ALT attribute that isn't empty.
$gravatar = get_avatar($comment,$size='48',$default=$path_to_default_gravatar );
$gravatar = str_replace ("alt=''", 'alt="' . $comment->comment_author . '\'s Gravatar"', $gravatar);

I’ve bundled the above together as it’s all extra information that isn’t directly part of the comment itself.

The first line is to ensure we have the correct data for our comment. Below that, $path_to_default_gravatar is where we set the URL of a custom gravatar that we would like to use to replace the default gravatar used. This can be really useful when doing advanced premium WordPress themes. Now, onto the Twitter username.

We create a variable called $twitter, to which we will assign whatever is returned from the native WordPress function, get_comment_meta(). This function takes in the ID of the comment we’re currently processing, the field name (in this case “twitter”) and whether to expect a single value, instead of an array of values (in most cases, this should just be set to true, as we’re only expecting a single value here). If $twitter isn’t empty, we remove and spaces or full-stops from it and create an anchor XHTML tag pointing to the user’s Twitter profile page.

The last two lines get the user’s gravatar and make sure it has alternative text, to keep things neat and tidy. We’ve also told the get_avatar() function that, should it not find a gravatar for the user, it must use $path_to_default_gravatar as the default gravatar to display.

The rest of the comment function looks like this:

<li <?php comment_class(); ?> id="comment-<?php echo $comment->comment_ID; ?>">
<div><?php echo $gravatar; ?><?php printf( __('<cite>%s</cite>'), get_comment_author_link(), $twitter ); ?></div>
<div><?php printf(__('Posted %1$s at %2$s (%3$s ago)', 'matty'),
get_comment_date(),
get_comment_time(),
human_time_diff(get_comment_date('U'), current_time('timestamp')) ); ?></div>
<?php if ($comment->comment_approved == '0') _e("\t\t\t\t\t<span class='unapproved'>Your comment is awaiting moderation.</span>\n", 'matty') ?>
<div><?php comment_text(); ?></div><!--/.comment-content-->
<div><?php printf(__('<a href="%1$s" rel="bookmark" title="Permalink to ' . $comment->comment_author . '\'s comment">Permalink</a>', 'matty'),
'#comment-' . $comment->comment_ID );
edit_comment_link(__('Edit', 'matty'), '<span>', '</span>'); echo get_comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?></div><!--/.comment-links-->

The one very important thing to note here is the lack of a closing </li> tag. WordPress inserts this automatically for us. While this still puzzles me, I’m sure there’s a decently good reason for it.

This code looks a bit random, doesn’t it? Well, it’s not really all that bad. Lets take a look.

We open the <li> tag and call the comment_class() WordPress function. This adds necessary microformats and comment-specific classes to the <li> for this comment. We also give it a unique ID.

Next up, we create a containing <div> tag and echo out our $gravatar image, as well as a prepared statement containing the comment author’s name and a link to their website (via the get_comment_author_link() function) and our $twitter URL, created in the snippet above.

Below the comment author information, we echo out a prepared statement with three values: the comment date, comment time and a human-readable version of how long ago the comment was posted (for example, 3 days ago).
If the comment has not yet been approved, we let the user know this with <?php if ($comment->comment_approved == '0') _e("\t\t\t\t\t<span class='unapproved'>Your comment is awaiting moderation.</span>\n", 'matty') ?>.

Now for the main event. The comment itself. A simple function called comment_text() gets this part of the show done.

Next up we create links that apply to this comment. In the above snippet, we create a permalink to the comment, an edit link for users who are logged in and have access to edit comments and a reply link (if we’re not too deep into the comments thread) that users can use to reply to the comment.

That’s all, folks!

Yep, that’s it. In the above snippet (which is almost a store-and-use-without-thinking snippet, in my opinion), we’ve created a customised layout for the way each comment is displayed, integrated a custom default gravatar, displayed a human-readable version of how long ago the comment was posted and integrated a Twitter username, submitted by the user when the comment was first made.

I’d really appreciate your thoughts on and ideas for this in the comments below.

Pretty cool, hey? 🙂

Leave a Reply

  1. So how would you go about calling this function on the page? Tried running the function “matty_comment_layout ( $comment, $args, $depth )” but don’t know what to put in for those arguments.

    • Hi JoE,
      You’d refer to this function when using wp_list_comments() in your comments.php file.

      For example:

      I’ve specified the name of my comment layout function as the value for the ‘callback’ parameter.

      I hope this helps. 🙂

      Cheers,
      Matty.