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.
I have an issue with a theme that is really perplexing. In WP 2.7, the redirect_to URL from the “Login to reply” button and also the “You must be logged in to comment” end up 404’ing. If I add urlencode to the “You must be…” link, it works fine, but I shouldn’t need to do this. It doesn’t matter what permalinks are set to, it still 404’s. I’ve added FollowSymLinks to the htaccess and that didn’t solve it. The redirect_to URL is the full URL including the http://www… If I strip out the http://www.domain.com part it redirects to the login screen as it should. What would be causing this to happen? I’ve tried the disable canonical links plugin and no change.
I’ve the div id=”div-comment-xxx”, got the JavaScript code in the head tag, reply link done as well, id=”respond” also there and the comment_id_field is there as well. But the form simply does not move up the page when I click on reply to comment. It just refreshes the page and the form stays at the bottom of the post.
Any idea what could be wrong? I have tried to find the problem many times but couldn’t find out what’s wrong. 🙁
Please help. Thanks 🙂
Looking at the source of your site, it appears to me that you’ve customized your comment’s html using a callback (probably), and something is wrong with your call to comment_reply_link();
That function call in your callback should look like this:
comment_reply_link(array_merge( $args, array(‘add_below’ => ‘div-comment’, ‘depth’ => $depth, ‘max_depth’ => $args[‘max_depth’])))
The “add_below” link is the important bit here.
Yup, I did used the callback function for my comments.
You got it right. My ‘div-comment’ in this comment_reply_link was incorrect. I didn’t specify which div id.
Thank you so much for your help. I have manage to get it working correctly on my site already. 🙂
This was exactly what I needed to edit my theme for threaded comments, and stylized author comments. Thankyou, it was easy to read, and figure out, A++ for you my friend.
Hi,
currently I’m working on some modifications on a blog. The blog is based on WP2.7 and has a custom theme, made by somebody else.
Now I’m trying to get the threaded comments feature working, and I’ve used your tutorial but it isn’t working. I’ve added the line to the header.php file and the lines in the comments.php file, but it’s still not working.
An example can be found here: http://www.software-innovators.nl/2009/03/29/het-nut-van-pauzes/
Could you take a look at the source code of that page, please? Maybe you can find what is wrong with the structure or something? The blog’s content is Dutch, but the HTML page structure is English.
Kind regards,
Something is wrong with your reply links. It’s using the wrong kind of quotes. Instead of single quotes in the A link, it’s using double quotes, which it should not be doing.
What does the actual PHP code in your comments.php look like? Post a copy on http://wordpress.pastebin.com and give me a link to it, so I can examine it.
I coudn’t manage to make it work… I can’t get even a “reply” link for each comment. What could be wrong?
Same here 🙁 No “reply to comment” and no threading using your comments.php(s) 🙁
Are you sure that you enabled threaded comments in the admin screens? If it’s not turned on, then obviously you won’t see any changes.
I have installed Brian’s Threaded Comments and replaced his comments.php with your file. THAT works. Very weird. WordPress’ threaded comments was already enabled. Weird weird. Thanks anyways.
I use your comments.php but I don`t see a “Reply to this Comment” link for each comment. What could be wrong?
Did you turn on threaded comments in the Settings->Discussion area?
What I must do in the Settings->Discussion area?
thank you for reply my problem
You’d have to turn on the threaded comments for there to be a reply link.
?? Where can I have the threaded comments?
From Cristina I know this link and If I follow your tutorial, dat would be the Reply to this Comment show.
And I use comments.php, so I think more easer for me? But this Reply to this Comment not show
I don’t understand your response.
If you’ve made the changes to your theme as I describe in the article, and the Reply link doesn’t show, then you still need to enable the Threaded Comments option on the Settings->Discussion screen.
The reply link will not show unless threaded comments are turned on.
That’s all there is to it. I cannot explain it any better than that.
I see now the “Reply to this Comment” but when I click on it, the comment box does not open below like this
Please help me?
It`s work Yay! Thank you 😀
but the comments form open little bit long and little bit difficult.
Not direct open 🙁
Would you help me please?
Did you add the code to your theme’s header.php file, like I describe in the article above? Read the part about “The Power of Javascript” closer.
Thanks. I have been searching google for hours on how to style and enhance wordpress 2.7 comments.
🙂
Hello & thanks for this great Post…! Just testing out the comment functionality.
thx otto!
this really helped in converting my old theme over to threaded comments! i was even able to style my author comments…
one question which i don’t know if you can help with – i was displaying the commenters url after their name, like so:
elana @ elanaspantry.com says:
or
heidi @ 101cookbooks.com says:
before i implemented the new comment code
was wondering where i would change that code now?
here’s my code:
if(get_comment_author_url())
{
echo '' . get_comment_author() . ' @ ' . get_comment_author_url_link() . '';
}
else { comment_author(); }
nevermind – i think i found it here: http://c.hadcoleman.com/2009/01/comment-design-for-wordpress-27/
How do I style the comments? My old code was:
commented on <a href="#comment-" title="">
How do I implement that style to the new wp_list_comment thing?
My code did not show, wait here it is:
commented on <a href=”#comment-” title=””>
How do I show codes here?
Thanks for the tutorial !
We will sure use it as soon as the need comes along !
____________________
Saguenay-IT, (IT Outsourcing, SOA, PHP, ASP, Flex, ActionScript, JavaScript…)
Reading about how the thing doesn’t work with IE6, I still can’t understand why some people stick to IE6 considering much better browsers available. IE6 is not even compatible with CSS!
Steve, editor of westhost review
I’m trying this on my own site, as well as yours, and it seems that the “Reply to %s” isn’t working 100%. Both my own site, and yours are still saying “Leave a Reply” when I reply to any of the previous comments. Any ideas?
The “Reply to Person” only works when Javascript is disabled on the client. That’s the purpose of it. If the javascript is working, then you don’t need to see the Reply to X thing, since the reply box itself moves to where the reply will be. However, without the javascript, the page has to reload to get the reply-to info, and the name thing there is a visual indicator of who you’re replying to, since the reply box will be at the bottom and not in the right place.
Why does the threaded comments doesnt appear on its respective parent comment?
I already enabled the threaded feature in the SETTINGS>DISCUSSION
Help is really appreciated. Thanks
Thank you thank you thank you Otto.
All the hours I wasted with IntenseDebate can now be redeemed by WordPress’ genius integration of these new comment enhancements. Not only is it completely functional, but I can make it look cool too.
Good rundown on changes. Very helpful.
not sure if this is a good place to ask this, but I’m having a big problem with the comment permalinks. Old permalinks (from pre WP2.7) no longer work with paged comments (since they are missing a /comment-page-N/ segment, so that is a pain. But more importantly, the new permalinks aren’t in fact permalinks at all. They are completely dependent on how many comments there are per page – which can change at a blog-owners whim. Does anyone have a solution to fixing the old comment links? (which in fact would solve the permalink problem in it’s entirety since the new permalink form could be scrapped completely).
It’s not actually possible to fix old comment links (other than turning off paging), because the links don’t contain enough information to do that. Everything after the # is not sent to the server, so WP has no idea that you’re wanting to see a specific comment there.
As for the other thing, hey, the blog owner can change anything on a whim, so they’re as “permanent” as anything else.
ok, fair point about ‘permanance’ – but the old comment link issue is a real problem. We need paging to reduce our page size, but we have 5 years worth of comments that include hundreds of links to previous comments – most of which are now broken.
Is there perhaps a way to use a .haccess rule to morph a /#comment-NNN to a form which could be recognised by the server and the correct page calculation made within a plugin?
Unfortunately, it’s not that simple.
Everything after a hash mark in a URL literally doesn’t get sent to the server. Hash marks indicate “in-page” links. When you have a URL that looks like example.com/link/morelink#hashtag then the only bit the server gets is “GET /link/morelink”. The browser then finds the hashtag in the page and auto-scrolls to it.
So WordPress never knows that you want to see comment-NNN, it just sees that you want the post. With links like that, it’s impossible for WordPress to know you want a comment, because the browser never tells it that fact. And you can’t even fix this with .htaccess, because the webserver itself (Apache) doesn’t get the hashtag bit either.
So, the only solution for leaving those old links working is to not have paging.
what about a more robust permalink structure for comments? i.e. that uses something like /2009/07/post-name/comment/123456/#comment-123456 and so is independent of any paging choices? That could get processed to always go to the correct page and the browser would still be able to find the name reference. I could go through the database making a change to the older links relatively automatically to allow for this. For reference, we have some 450 such links in our database and this would be more tractable than working out by hand what page of comments each of the old links are on.
Hmm. Should be possible to do with a plugin.
Essentially, the plugin would need to recognize the new URL, pull the comment ID value out of it there, then use the get_page_of_comment() function to find the page number to use. From there, you can do set_query_var(‘cpage’, NNNN) to set the comments page to whatever the result it.
This would all have to happen before the query runs, meaning that you’re not going to get nice bits like is_single() and so forth.
My suggestion would be to alter your links to look like /link/?comment=NNN instead. This avoids complexity, and you can just do something like $commment_id = (int) $_GET[‘comment’] to safely get the comment id, without opening a security hole.
Thanks, that last suggestion sounds sensible – and in effect gives a non-paging-dependent permalink for each comment. Where would such code go though? I’ve not had much experience hacking WP at this kind of level, so I may need to see if there is anyone out there that could be motivated to help out.
Can anyone tell me how to get my blog’s comment system to work like this blog’s?
I’ve tried IntenseDebate but it required Javascript which I don’t want. It’s also messy, where this blog’s comment system is simple in it’s layout.
My blog can’t even get threaded comments. Any suggestions would be much appreciated.
Why does the threaded comments doesnt appear on its respective parent comment?