uweschmidt.org

42 / π ≈ 13.37 

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
$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>

9 Responses

  1. toto says:

    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. :)

  2. Uwe says: in reply to toto

    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

  3. Jhay says: in reply to 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. :D

  4. Uwe says: in reply to Jhay

    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?

  5. Jhay says: in reply to Uwe

    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.

  6. Uwe says: in reply to Jhay

    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:

    Change to comments UI to show when a comment is replying to another, and link to the parent comment

    Have you seen these parent comment links on other WordPress sites?

  7. Jhay says: in reply to Uwe

    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. :D

  8. Uwe says: in reply to Jhay

    Hi Jhay,

    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?

    maybe that’s the case. Try asking about this at the WordPress forums.

    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.

    Maybe the WordPress themes have to be modified to support this. Are there WordPress 3.0 themes?

  9. Thanks for this. Like you, I write blog posts documenting my changes because I know that when I visit them later I will have no clue about what changed and why. So the post is more for my future self than anything else :)

Leave a Reply