Comments in WordPress

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 (line 684)
$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 (line 684)
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’] ) // line (1007)
//  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'] ) { // line 475
    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'] ) { // line 475
    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; ?> // line 643
    <?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; ?> // line 643
    <?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"> // line 1261
<?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"> // line 1261
<?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>

9 comments