The primary purpose of this post is to document the changes I made to core WordPress code in order to get comments working they way I want. Since all of this is a hack, I have to re-do those changes when I upgrade WordPress to a newer version. It would probably be best to write a plugin instead, so I wouldn’t have to change the code each time I upgrade.
Maybe someone is reading this and knows a better way to do all of this. I’m a WordPress novice and just figured those things out by browsing the code, I never read the documentation.
Btw, all of the following applies to WordPress 2.9.1, so things might be different in other versions…
Threaded comments
In Discussion Settings, it’s problematic to first enable threaded (nested) comments X levels deep, then later decrease the maximum comment depth, or even disable nested comments altogether. Comment pagination will break if you have comment threads with a depth that is greather than the one currently set. I experienced this problem because I imported my comments from Drupal, and some comment threads were 10 levels deep. I think WordPress should at least warn about this on the Discussion Settings page…
Also other plugins, like Quote Comments, add thread information to the database even if nested comments are turned off.
I wanted to restore the behavior I had in Drupal, which is a flat comment list, but the user could reply to each comment individually and the comment parent relation is stored in the database. I disabled threaded comments and made the following changes.
Changes in wp-includes/comment.php
This is needed for the function get_page_of_comment to work correctly, if threaded comments are turned off (args['max_depth'] ≤ 1), but (some) comments in the DB have a thread structure (comment_parent ≠ 0).
Original
// Count comments older than this one $oldercoms = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = 0 AND comment_approved = '1' AND comment_date_gmt < '%s'" . $comtypewhere, $comment->comment_post_ID, $comment->comment_date_gmt ) );
Replacement
// Count comments older than this one if ( $args['max_depth'] > 1 ) $oldercoms = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = 0 AND comment_approved = '1' AND comment_date_gmt < '%s'" . $comtypewhere, $comment->comment_post_ID, $comment->comment_date_gmt ) ); else $oldercoms = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1' AND comment_date_gmt < '%s'" . $comtypewhere, $comment->comment_post_ID, $comment->comment_date_gmt ) );
Changes in wp-includes/comment-template.php
Although threaded comments are disabled, I still want to show the Reply-button for each individual comment, which requires changing the function get_comment_reply_link.
Commented code
// if ( 0 == $args[‘depth’] || $args[‘max_depth’] <= $args[‘depth’] ) // return;
Incorrect comment links
When the HTML code for comments on a page is generated, the variable $in_comment_loop will be set so that the function get_page_of_comment won’t be called each time inside the function get_comment_link (the comments are all on the same page anyway). This is a problem in case one actually wants to get the link to a comment that is on a different page — one example would be the default Recent Comments widget. I also ran into this problem with my in reply to-links (see below).
Changes in wp-includes/comment-template.php
Original
if ( $args['per_page'] ) {
if ( '' == $args['page'] )
$args['page'] = ( !empty($in_comment_loop) ) ? get_query_var('cpage') : get_page_of_comment( $comment->comment_ID, $args );
if ( $wp_rewrite->using_permalinks() )
$link = user_trailingslashit( trailingslashit( get_permalink( $comment->comment_post_ID ) ) . 'comment-page-' . $args['page'], 'comment' );
else
$link = add_query_arg( 'cpage', $args['page'], get_permalink( $comment->comment_post_ID ) );
} else {
$link = get_permalink( $comment->comment_post_ID );
}
Replacement
Now checking for get_page_of_comment argument that can be set to force page computation.
if ( $args['per_page'] ) {
if ( '' == $args['page'] )
$args['page'] = ( !empty($in_comment_loop) && empty($args['get_page_of_comment']) ) ? get_query_var('cpage') : get_page_of_comment( $comment->comment_ID, $args );
if ( $wp_rewrite->using_permalinks() )
$link = user_trailingslashit( trailingslashit( get_permalink( $comment->comment_post_ID ) ) . 'comment-page-' . $args['page'], 'comment' );
else
$link = add_query_arg( 'cpage', $args['page'], get_permalink( $comment->comment_post_ID ) );
} else {
$link = get_permalink( $comment->comment_post_ID );
}
Changes in wp-includes/default-widgets.php
Fixing the Recent Comments widget.
Original
<?php echo $before_widget; ?>
<?php if ( $title ) echo $before_title . $title . $after_title; ?>
<ul id="recentcomments"><?php
if ( $comments ) : foreach ( (array) $comments as $comment) :
echo '<li class="recentcomments">' . /* translators: comments widget: 1: comment author, 2: post link */ sprintf(_x('%1$s on %2$s', 'widgets'), get_comment_author_link(), '<a href="' . esc_url( get_comment_link($comment->comment_ID) ) . '">' . get_the_title($comment->comment_post_ID) . '</a>') . '</li>';
endforeach; endif;?></ul>
<?php echo $after_widget; ?>
Replacement
Setting argument get_page_of_comment because the recent comments can all be on different pages.
<?php echo $before_widget; ?>
<?php if ( $title ) echo $before_title . $title . $after_title; ?>
<ul id="recentcomments"><?php
if ( $comments ) : foreach ( (array) $comments as $comment) :
echo '<li class="recentcomments">' . /* translators: comments widget: 1: comment author, 2: post link */ sprintf(_x('%1$s on %2$s', 'widgets'), get_comment_author_link(), '<a href="' . esc_url( get_comment_link($comment->comment_ID, array('get_page_of_comment' => true)) ) . '">' . get_the_title($comment->comment_post_ID) . '</a>') . '</li>';
endforeach; endif;?></ul>
<?php echo $after_widget; ?>
Keeping track of replies
I have a lot of comments on my Wiimote Whiteboard page and it’s sometimes hard to figure to which previous comments someone has replied to. That’s the reason I made a small change to show the comment’s parent.
Changes in wp-includes/comment-template.php
Original
<div class="comment-author vcard">
<?php if ($args['avatar_size'] != 0) echo get_avatar( $comment, $args['avatar_size'] ); ?>
<?php printf(__('<cite class="fn">%s</cite> <span class="says">says:</span>'), get_comment_author_link()) ?>
</div>
Replacement
Setting argument get_page_of_comment, in case the the comment parent is on another comment page.
<div class="comment-author vcard">
<?php if ($args['avatar_size'] != 0) echo get_avatar( $comment, $args['avatar_size'] ); ?>
<?php printf(__('<cite class="fn">%s</cite> <span class="says">says:</span>'), get_comment_author_link()) ?>
<?php
if ($comment->comment_parent) {
$parent_comment = get_comment($comment->comment_parent);
print 'in reply to <a href="'.(htmlspecialchars(get_comment_link($parent_comment->comment_ID, array('get_page_of_comment' => true)))).'">'.$parent_comment->comment_author.'</a>';
}
?>
</div>
Subscribe
Thanks for sharing, Uwe.
The identical “no link to a comment page” problem has WP-RecentComments widget. To tell the truth, it would be nice to hear a miracle cure from You.
Hi toto,
I took a brief look at WP-RecentComments and guess you mean the incorrect comment links.
I glanced over the code and found the culprit in core.php (starting at line 119). The plugin simply assumes that all comments are on the same page — it doesn’t even use WordPress’ get_comment_link function. This should be rather easy to fix; I suggest you contact the author of that plugin about this and send him or her a link to this page.
if ($comment->comment_type == 'pingback') { $result .= '<li id="rc_item_' . ++$count . '" class="rc_item rc_pingback">' . sprintf('<div class="rc_info"><span class="rc_label">' . __('Pingback:') . '</span> %1$s</div>', get_comment_author_link()) . '</li>'; } else if ($comment->comment_type == 'trackback') { $result .= '<li id="rc_item_' . ++$count . '" class="rc_item rc_trackback">' . sprintf('<div class="rc_info"><span class="rc_label">' . __('Trackback:') . '</span> %1$s</div>', get_comment_author_link()) . '</li>'; } else if ($args['post'] == 'true') { $result .= '<li id="rc_item_' . ++$count . '" class="rc_item">' . $element_avatar . sprintf('<div class="rc_info"><span class="author_name">%1$s</span> ' . __('on', 'wp-recentcomments') . ' <span class="post_title">%2$s</span></div>', get_comment_author_link(), '<a href="'. get_permalink($comment->comment_post_ID) . '#comment-' . $comment->comment_ID . '">' . get_the_title($comment->comment_post_ID) . '</a>') . '<div class="rc_excerpt">' . $comment_excerpt . '</div></li>'; } else { $result .= '<li id="rc_item_' . ++$count . '" class="rc_item">' . $element_avatar . sprintf('<div class="rc_info"><span class="author_name">%1$s</span>' . rc_get_author_info() . '</div>', '<a href="'. get_permalink($comment->comment_post_ID) . '#comment-' . $comment->comment_ID . '">' . $comment->comment_author . '</a>') . '<div class="rc_excerpt">' . $comment_excerpt . '</div></li>'; }Uwe
Hi, I was wondering how to display just “in reply to [comment author of parent comment]” on the comments section of my blog?
I tried doing a hack based on your code but I can’t get it done. Any help would be greatly appreciated.
Hi Jhay,
this should work by making the changes as described above in wp-includes/comment-template.php at lines 477 and 1264–1269. Did you do that?
Hi, are you using WordPress 3.0.1? It’s the version of WP I am running and I can’t implement the changes to the core code because they are different from what is in my WP core files.
Hi Jhay,
I have to admit that I’m still running WordPress 2.9.1. Hence, the line numbers are probably different in your case, but it should be possible to find the place in the code where the relevant parts have been relocated.
The more important question is whether WordPress has changed its behavior in this regard. This may be the case, according to this:
Have you seen these parent comment links on other WordPress sites?
I see. Now that you’ve mentioned that changed behavior in WP 3.0, does it mean that the hacks you’ve shown in this post are no longer necessary because they’re ‘built into’ WP 3.0?
This is puzzling because if it were so, how come most WordPress sites don’t display the “in reply to” info in the threaded comments. This is why I searched for code that does that and I landed here in your blog.
Hi Jhay,
maybe that’s the case. Try asking about this at the WordPress forums.
Maybe the WordPress themes have to be modified to support this. Are there WordPress 3.0 themes?