WordPress 2.7 Comments Enhancements

This post has been moved here: http://ottopress.com/2008/wordpress-2-7-comments-enhancements/

WordPress 2.7 includes a lot of new enhancements, but one of the big ones is the new comment functionality. Comments can be threaded, paged, etc. This is all built in, but unfortunately, your theme must support it. So, for theme authors, I’d suggest getting to work on making your themes compatible right away.

Read on if you’re a theme author…

Note: A lot of people seem to miss this key bit: Enhanced Comments are optional and default to off, even after you make these changes. You have to go to the Settings->Discussion panel to turn the features on.

Actually “compatible” is not quite the right term. Old themes will continue to work fine in WordPress 2.7. It’s just the threading and paging and javascript enhancements need the theme to support it. This is much the same as the sidebar widgets, the theme has to support it for the functionality to work. So this article is really not about 2.7 compatibility, it’s about 2.7 capability.

Note that this article will explain some of the changes needed to make themes capable of supporting the new comments functions, however there’s no substitute for the real thing. Install a local copy of WordPress trunk on your home machine (possibly using XAMPP) and test it there.

Also note that this is all based on the current state of WordPress trunk, and is subject to change before WordPress 2.7 is released. However, it’s probably not going to change all that much at this point.

How to create a 2.7 compatible comments.php

2.7 Detection

If you want your theme to be backward compatible as well, then there’s a simple way to do it. Just check for the wp_list_comments function, like so:

if (function_exists('wp_list_comments')) :
// new comments.php stuff
else :
// old comments.php stuff
endif;

While you could check for the version number of WordPress, this method is better because it simply looks for the actual function you’re going to use anyway. Never make assumptions based on version number.

One of the more interesting ways I’ve seen to use this is to have the “old comments” php in a separate file entirely, which is then included. This preserves backwards compatibility for your theme in a simple way. Here’s a quick example code for that approach:

<?php
add_filter('comments_template', 'legacy_comments');
function legacy_comments($file) {
	if ( !function_exists('wp_list_comments') )
		$file = TEMPLATEPATH . '/legacy.comments.php';
	return $file;
}
?>

Adding this code to a theme’s functions.php file will make the theme use the “legacy.comments.php” for older non-2.7 installations. That way, you can simply rename your old comments.php and then make a new one based on the new functionality. Clever.

Password Protection Check

Put this code at the top of your comments.php file. This is what lets it support the post password functionality. Note that this code is quite similar to the previous way that it was done (by checking the cookie directly), but now WordPress has a specific function to do it. You should use this function in case the functionality changes in the future, your code will be forward compatible:

if (!empty($_SERVER['SCRIPT_FILENAME']) && 'comments.php' == basename($_SERVER['SCRIPT_FILENAME']))
	die ('Please do not load this page directly. Thanks!');
if ( post_password_required() ) {
	echo 'This post is password protected. Enter the password to view comments.';
	return;
}
<h4>The Comments Loop</h4>
The Comments Loop used to look similar to this (much simplified from a real one):
[php]if ($comments) :
<?php $comment_count = get_comment_count($post->ID); echo $comment_count['approved']; ?> Comments
<ul class="commentlist">
<?php foreach( $comments as $comment ) :
// stuff to display the comment in an LI here
endforeach;
?></ul>
<?php else :
if ('open' == $post-comment_status) :
	// If comments are open, but there are no comments.
else :
	// comments are closed
endif;
endif;

Basically, it went through the comments manually and output all the necessary pieces. Easy, but very manual. This also had the problem of being very inconsistent and hard to manage for your theme’s users, especially if you heavily customized it.

The new comments loop is much simpler:

<?php if ( have_comments() ) : ?>
<h4 id="comments"><?php comments_number('No Comments', 'One Comment', '% Comments' );?></h4>

<ul class="commentlist">
<?php wp_list_comments(); ?>
</ul>

<div class="navigation">
<div class="alignleft">< ?php previous_comments_link() ?></div>
<div class="alignright">< ?php next_comments_link() ?></div>
</div>
<?php else : // this is displayed if there are no comments so far ?>
	<?php if ('open' == $post->comment_status) :
		// If comments are open, but there are no comments.
	else : // comments are closed
	endif;
endif;
?>

That new one is, in fact, a complete comments loop. No simplification at all. Unless you want something displayed for “no comments” or “comments closed”, of course. I don’t have anything showing there.

There are three important pieces to note here:

  • The have_comments() function replaces the check on the global $comments variable.
  • The wp_list_comments() function now outputs all the comments. It does threading, the classes, everything new.
  • There’s a new navigation section to do comment paging.

The Power of Javascript

To support the new Javascript functionality with comment threading, some minor bits of code are needed:

First, in the header.php, add this line immediately before the call to wp_head():

if ( is_singular() ) wp_enqueue_script( 'comment-reply' );

That code adds the comment-reply javascript to the single post pages, letting the comment reply links work correctly. WordPress specifically does NOT do this itself, for the reason that use of this script requires certain naming conventions and parameters in the comment form, which you’ll have to add.

So, your comment form has a new parameter that you have to add:

<?php comment_id_fields(); ?>

This adds a bit of code to your form which makes it display two hidden inputs: comment_post_ID and comment_parent. Your form probably had the comment_post_ID before, so you need to remove it. The comment_parent is there for the javascript, so that replies to comments get threaded properly.

Also, your comment textarea MUST have an id=”comment”. The javascript expects it for focus purposes. If you used anything else, change it. Note that because of this, no other element on your page can have the “comment” ID.

Finally, the entire comment form MUST be surrounded by a DIV with an id=”respond”. In some previous themes (including the default ones), there would be an anchor tag like this:

<a id="respond"></a>

This was there to allow the link from the front page to go directly to the respond section when there were no comments already. That still happens, but now there’s a double purpose. The javascript moves the comment form to where the reply link is, so instead of it being an anchor, it needs to be a DIV that surrounds the comment form.

So, remove that anchor, and add a DIV with an id=”respond” around the entire comment form. The link from the front page still works this way with all modern browsers, and the javascript can now move the form around on the page as needed.

Next, you can replace the call to your normal “Leave a Comment” text with something like this:

<h3><?php comment_form_title(); ?></h3>

This makes a comment form title of “Leave a Reply” which will change to “Leave a Reply to Whoever” when somebody is replying directly to another person. You can customize this, if you like, with two parameters, like so:

<?php comment_form_title( 'Leave a Reply', 'Leave a Reply to %s' ); ?>

The %s will be replaced with the person’s name. This will only happen when the javascript isn’t working and the reply links have to cause a page refresh. So it’s usually not worth customizing much. Still, not everybody runs javascript and so this is nice to let them know who they are replying to.

Finally, you’ll notice that when somebody clicks “reply” and the comment form appears there, maybe they decide to cancel instead. So, that cancel link needs to be in your respond section. Here’s the code to do that, just put it right below your “leave a message” header in the comment form area:

<div id="cancel-comment-reply">
	<small><?php cancel_comment_reply_link() ?></small></div>

That’s pretty much it for making the AJAX work. With this, the new features on the Settings->Discussion panel will work. Obviously, you can modify this somewhat as needed for your theme, these are just general principles that you’ll need to use.

Styling

Now that you have it working, there’s plenty of new styling you can add to comments. The new comments loop automatically puts every comment into an LI tag, and threads them as well, with embedded UL/LI tags. It also adds a ton of classes on all these LIs which surround every comment in this fashion:

  • comment, trackback, pingback classes get added depending on the type of the comment.
  • byuser gets added if the comment is by a registered user of the site.
  • comment-author-authorname gets added for specific registered users.
  • bypostauthor gets added if the comment is by the author of the post the comment is attached to.
  • odd and even classes are added to odd and even numbered comments
  • alt is added to every other comment
  • thread-odd, thread-even, and thread-alt classes are the same as the odd/even/alt classes, but these only apply to the top level of each set of comments and replies
  • depth-1 is added to the top level comments, depth-2 to the next level, and so on.

What’s more, a comment_class filter is provided to allow you to add your own classes. Here’s an example of that. This example function adds a microid to every comment with the microid for the comment authors given URL and email address. This sort of thing could be done in a plugin or a theme’s functions.php file, whatever.

// add a microid to all the comments
function comment_add_microid($classes) {
	$c_email=get_comment_author_email();
	$c_url=get_comment_author_url();
	if (!empty($c_email) && !empty($c_url)) {
		$microid = 'microid-mailto+http:sha1:' . sha1(sha1('mailto:'.$c_email).sha1($c_url));
		$classes[] = $microid;
	}
	return $classes;
}
add_filter('comment_class','comment_add_microid');

Simple and effective. It just adds the class to the given array of classes and lets the comment display functions take care of the rest.

And there you have it. It’s not hard to support the new functions. And if you need to customize your theme’s comments section even more, wp_list_comments() supports a number of parameters. Most of this is not documented yet, because WordPress 2.7 is not out until November. However, the code is relatively straightforward, and anybody with a good understanding of WordPress should be able to work it out.

Additional: A lot of people keep asking me for a full-fledged example. Really, I recommend that you examine the comments.php file in the default theme in the 2.7 beta versions. However, the actual comments.php file I’m using on this site can be found here: http://ottodestruct.com/comments.phps, if it helps you any. It has the code I’ve described in this article, pretty much verbatim. The only additions to it are a couple of extra options on the wp_list_comments() call, such as avatar_size and reply_text.

403 thoughts on “WordPress 2.7 Comments Enhancements”

  1. Hi, I’m ‘feeling my way’ through making the changes, and seem to have everything working – but it’s driving me slowly mad trying to find out in which file the wordings are located – by which I mean, ‘Reply’ as one example. I want to change that from the default, and can’t find any reference to it in the comments.php file. I know it will be found in another php file somewhere on my server, but which one, please? I’d be grateful for the help as the ‘Reply’ text appears fine, with good spacing, if I’m not logged in but I use a plugin that provides ‘on the page’ editing of the comments, and with the links that provides appearing, the ‘Reply’ link appears somewhat squished, way too close to the other text. So I’d like to insert a line break.

    1. In WordPress, higher level functions like wp_list_comments() tend to pass the arguments they receive down to lower level functions. In this case, the get_comment_reply_link() function is what creates that text, and it has a parameter of “reply_text” that will let you change that. Because of this argument passing, that means that you can send the same argument to wp_list_comments to set the text as well. So, wp_list_comments(‘reply_text=whatever’); will do what you’re looking for.

      1. Hi, thanks for the quick response. I understand your explanation, but tried wp_list_comments(’reply_text=reply to this comment’); and it produced a syntax error? Can I access the get_comment_reply_link function to change the text it places into the comments and, if so, where? Thanks again for your patience.

        1. Well, that is actually the correct way to do it, so all I can say is that you messed up somewhere else. I just changed it on my own site’s theme here, as you can see. It now says “Reply to this Comment” instead of just reply.

          You can also do it via the array method, which I personally find to be cleaner looking. Here’s an example of that which changes the reply text and the avatar size as well:


          wp_list_comments(array(
          'avatar_size'=>48,
          'reply_text'=>'Reply to this Comment'
          ));

  2. Hi!

    I’m probably going to wait for proper release before moving to 2.7, as it isn’t far off.

    This functionality should hopefully massively streamline my maintanence work – at the moment I’m using a plugin to achieve threaded comments, but if the plugin uses compatible headings, I don’t foresee there being major problems with changing things across, and using WordPress Native features.

    However, I have QUESTIONS! Is there going to be native support for having:
    a) E-Mail notification for a commenter when someone replies to their comment?
    b) E-Mail notification for an author when one of their posts specifically is commented on?

    I’ve not been able to find settings for these in my current WordPress version (I’m only on 2.6)

    1. a) No. However, it does have hooks in the right spots to do that sort of thing, so it is possible to write simple plugins which adds that.

      b) Yes. WordPress 2.7 has a function that notifies the post author of a new comment on their posts, after it has been approved by a moderator (if moderation is enabled).

  3. Thanks for the extensive article Otto! I’m modifying a theme on my own.

    Currently, under , I am displaying a alert for moderation to be approved using if ( $comment->comment_approved == '0' ).

    What is the new function to check this?

    1. I’m not sure what exactly you mean here, but the wp_list_comments function displays unapproved comments to the person who writes them, along with the text “Your comment is awaiting moderation”.

  4. awesome, i just upgrade and I’m kind of dislike the reply_links (onclick==obtrusive) and also the comment-reply form behaviour is hard to control and break my theme so I’d to created my own reply_links with thickbox (graybox form). you can check the demo at my blog (running on 2.7b2).

  5. Hello.

    I’m editing my blog theme for new WordPress 2.7 version. However i want to add new “Comment Reply” functionality to my blog theme. But there is a problem. I can’t get comment reply link on comments.

    I created two comments template for old WordPress 2.6.3 and new WordPress 2.7. New comments template (comments.php)’s code is here: http://pastebin.com/m264c16fd

    Also i’m using custom comment styling in functions.php (throught new wp_list_comments‘s callback argument). Codes is here: http://pastebin.com/m43b50f3e

    So how i can add custom reply link to my comments? I can’t. 🙂

    Sorry for bad English.

    1. There’s few other problems with your callback (mainly that it doesn’t do threading properly), but if we ignore that, then all you need to add is something like this:

      <div class="reply">
      <?php comment_reply_link(); ?>
      </div>

  6. I’m very worried that I’ll lose control over the HTML produced by WordPress if I use wp_list_comments() in my theme. Are there individual functions that handle all the new commenting features and I could use to keep control over my comments HTML?

    1. There’s two ways to respond to this, so I’ll cover them both.

      1. Why would you really need to retain that much control over the html for the specific case of comments? What exactly is in the html of a comment that you would want to edit anyway? All comments are basically the same, there’s an avatar (maybe), the user information (name, url, etc), perhaps the time or age of the comment, and then the comment itself. These are usually organized into specific divs with specific classes and such, for styling. What would you add or subtract to this basic layout? Remember, XHTML is supposed to be semantic markup. If you want to change the look of the thing, then you’re not supposed to alter the XHTML itself. That’s what the CSS is for. The XHTML is only there to define the actual elements of data, not to define a layout. The wp_list_comments function outputs either a UL/LI set of comments or a DIV nested set, and those should suffice for all realistic situations. Individual bits are controllable, but there should never really be a need to change the underlying layout.

      2. Still, if you really, really need total control, then look closer at the ‘callback’ argument. It’s in the Walker_Comment class, and it gets passed in from wp_list_comments. Basically, you can make a function to display a comment however you see fit, then call the wp_list_comments function, and pass the name of your own function as the callback argument, thus giving you total control over the comment’s XHTML.

      1. Hmmm I see entirely your point in #1 now, oops :S I’ll see if I can handle it with CSS alone first then. But thanks for clarifying it anyway, I’ll take note of that.

  7. Hiya – would anybody mind taking a look at http://www.medicaladmissions.co.uk/blog/ and telling me why the “Leave a reply” doesn’t change to “Leave a reply to ???” when I click on one of the comment ‘Reply’ buttons?

    I’ve added the code bit-by-bit as defined above, and it did work, right up until I added whatever bit makes the reply form move itself to the comment box – then it just says “Leave a reply” again!

    Thanks in advance.

    1. I probably should clarify that a little bit. That option only works when javascript is disabled. In that case, the page gets reloaded with the users name and focused on the comment form. With javascript enabled, the comment form moves up instantly and the name does not appear or change.

      Disable javascript in your browser then try to reply to somebody. See what happens.

  8. Help Please! I had someone make my theme for me and I can’t get in contact with them anymore, I don’t know what to do with my comment.php =[ Here it is:
    _____________________________________________________________________
    (Basic comments.php file removed by Otto)
    _____________________________________________________________________

    If you could update it for me that would be awesome! I could like pay! Thanks

    1. That comments.php file is pretty basic, you could probably simply replace it with the one from the default theme and it would work fine.

      That said, there’s nothing you really NEED to do. Old comments.php files will still work just fine with WordPress 2.7, you just won’t get the threading and paging features until you modify it.

  9. Has anyone documented the parameters taken by wp_list_comments() other than avatar size and reply text that you mentioned in the comments? I am particularly interested in changing the “[post author] says:” before the comment itself.

  10. And how about date format? I don’t find any way to chance that default “November 18th, 2008 at 6:31 am” – where does it comes from anyway?

    1. You can put a filter function on ‘get_comment_date’ and ‘get_comment_time’ to change the look of those two pieces.


      function change_comment_date($datestring, $dateformat) {
      global $comment;
      return mysql2date('YOUR_DATE_FORMAT_HERE', $comment->comment_date);
      }
      add_filter('get_comment_date','change_comment_date',10,2);

      The get_comment_time filter function also receives a third parameter of whether or not the time should be returned in GMT.

      The “at” piece is currently not editable, except for with the multi-lingual translation system. Here’s the thing, because the wp_list_comments is relatively new, it’s not entirely 100% configurable yet. In time, it will become more so, as work on 2.8 progresses. Some of the 2.7 point releases will probably add enhancements in this regard. Nevertheless, it is a work in progress.

  11. The first part of the post is great until you get to the Javascript part and you get very vague after you mention adding a line to the header.

    Why not show the comments.php with the changes to allow the javascript feature? I think most looking at this post were looking on updating for the new features not being half-working.

    1. There’s really not a whole lot to the javascript functionality. All you have to do is to add that line to the header and then to make sure that the ID of the form is pretty much as I describe it. That’s it, nothing more to it. What the javascript code does is to a) make the “reply to this comment” pieces appear and b) make the comment form move up to those when you click on them. Try it out here: pick a comment, click the reply link underneath it.

      Here’s a link to a complete example comments.php file: http://ottodestruct.com/comments.phps

      That is the actual comments.php I’m using on this site. I modified it as I was writing this article, pretty much, and all I really did was to detail the changes as I made them. Honestly, that file is not all that different from the ones that come with the 2.7 default theme. It’s easier to modify the file than it seems. 🙂

  12. Hi Otto (& all),
    Just to say, when using the “new” comments code with 2.7b3 that autogenerated avatars do not work.

    It’s been fixed now, you just need to get a ‘nightly build’ from the WP site and its all good.

    2.7b1 and 2.7b2 are unaffected!

        1. Thank you Otto, on the first one maybe with CSS / Mootols, on second one i have no idea yet. Best Regards!

  13. Can someone give me a hand here? This might simple CSS, but I’d like to throw out a scenario that would really help me out if I fully understood it. When viewing the source of the comments with the new 2.7 comments.php file I’m seeing this as an li class:

    class=”comment byuser comment-author-admin bypostauthor odd alt thread-odd thread-alt depth-1″

    That’s a big class, or lots of classes, but help me out here. Lets say I want to make every admin’s comment to be the color red. In css, can I simply do this?

    li.comment-author-admin {color: red;}

    I can’t, because I’ve tried that. So how do I go about making good use of all of these classes?

  14. Bleh, it does do that. My apologies. Thanks for this great article. I tweeted it. This is the best resource I’ve found regarding wp_list_comments() in 2.7 thus far. Keep on replying!

  15. Hi Otto.

    Thanks for that great page.

    Only 2 questions:

    1) I’ve tried the function

    function change_comment_date($datestring, $dateformat) {
    global $comment;
    return mysql2date(‘j F Y’, $comment->comment_date);
    }
    add_filter(‘get_comment_date’,’change_comment_date’);

    to change the look of the date and did put it in functions.php but I got the following error:

    Warning: Missing argument 2 for change_comment_date() in /home/…./functions.php on line 7
    (Line 7 is <?php function change_comment_date($datestring, $dateformat) { )

    2) Is it possible to customize the text? I’d like to replace that “Says” by something else.

    Thanks a lot and keep up the good work!

    1. Yes, i too am wondering how to change the “Says” text and also the text link for threaded replies (“Reply to this Comment” on this blog here). Also what about the placement of this new Reply link?

    2. 1. Use add_filter(’get_comment_date’,’change_comment_date’,10,2); instead. You have to specify that it gets 2 parameters. My bad.

      2. The only way to change “Says” currently is to create a callback function that outputs a single comment and pass that into the wp_list_comments as the “callback” parameter. I went into this above a bit. This is, of course, a lot of effort to go to for one word, so I suggest just living with it for now.

      However, if you want to do it with CSS, then you can hide the “Says” entirely, as it is in a span with the class of “says”. You could replace it with :after and such like that as well, but it wouldn’t work in IE.

  16. 2 days ago I registered new wordpress blog at wordpress.com
    I’ve seen the difference backoffice interface of my wordpress 2.6.5

    Is that interface of version 2.7?

    1. If you call the comments_template function like this:

      comments_template(‘/comments.php’, true);

      Then it pre-separates the comments into trackbacks and such, and creates a special place to hold them in the $wp_query object. You can then count them by doing this:

      global $wp_query;
      echo count($wp_query->comments_by_type[‘pings’]); // this is both pingbacks and trackbacks
      echo count($wp_query->comments_by_type[‘trackback’]);
      echo count($wp_query->comments_by_type[‘pingback’]);
      echo count($wp_query->comments_by_type[‘comments’]);

      Like that.

  17. Otto, great post. Since 2.7 came out yesterday I’ve been banging my head against the wall, trying to get a handle on the changes, and this article helps, a huge amount.

    I’ve tried a few other things, and managed to get comments working, and stylized, but not exactly how I want.

    Do you have an example of the CSS you’re using, that works with the code you’ve put together, to work off of? I’m confused as to what the output of your code does, that’s different from what I’ve got already.

    Thanks again.

    1. I’m really not using a whole heck of a lot of comment styling on this site. I put a couple of background colors on the .bypostauthor and .pingback and .trackback classes, and a few margins here and there, but for the most part this is the basic comments layout with no frills.

      Try posting your site URL over on the wordpress.org forums, many of those people are good with styling.

  18. Otto: Could you take a look at my post WordPress Support Forums and let me know if there is a way to control all of the comment’s text itself. As I can see, the only way to do so is by styling the p tags. And with the way the theme I’m using works, it wants to make each p into its own comment box.

    From what I can tell there is no div/span tag to just get a grasp on the text itself of the comment, whereas the date/avatar information each has their own easily styled div tags. Any help would be much appreciated.

Comments are closed.

css.php