Grouping Your WordPress Blog Comments By Type: Comments, Trackbacks And Pingbacks

First, my apologies for the extended period of time off I took from this blog. There’s no great scandal behind the break I took; my health and humor are just fine. As Technorati notes, somewhere around 95 percent of blogs haven’t been updated in three months; I just kind of fell into that groove. But I’m back on task now, and hope to post something every day again.

Part of the benefit of blogging is getting comments and other sorts of feedback. Quality feedback is a huge help to bloggers; I want to know that what I have said actually resonates — or, failing that, at least whether what I wrote actually works for most people.

I also like having clear links within my posts that interrelate various posts on a topic: Not only links to earlier postings, but especially links to later posts, that may build on a theme.

WordPress, thankfully, is built around a fairly robust commenting system. In addition to now supporting threaded comments (that is, you can see a “ladder” of comments and replies to comments), WordPress can also handle pingback and trackback links.

Out of the box, WordPress commingles comments, trackbacks and pingbacks, by order of most recent to least recent. That’s fine, but I like the idea of grouping post feedback by type: Namely, I want to give precedence to comments left specifically on the blog, with external and internal hyperlinks grouped together, after the comments.

With a little hacking of the comments.php script in your theme, you can easily break your trackback / pingback links out from your comments, and place them either before or after your comments.

An Aside On Trackbacks vs. Pingbacks

In WordPress, trackbacks and pingbacks are essentially the same thing. They both pass links from one Web site to another. From the end-user perspective, the biggest difference is that trackbacks have to be managed by hand, while pingbacks are automated.

For example, suppose I find a post on John Doe’s blog and decide I want to blog about it, too. Suppose Doe is using a blogging platform that supports both trackback and pingback.

If I use trackback to notify Doe of the link to my post, I need to specifically scroll down, in the WordPress post editor, to the Send Trackbacks section, then provide the URL to John Doe’s original post. Doe will likely see my link as a comment to his post, but he needs to confirm the link to my post is legitimate.

the send trackbacks menu in WordPress

Alternatively, so long as I have hyperlinked to Doe’s post somewhere in my post, pingback takes care of everything. It automatically reaches out to Doe’s Web server, and Doe’s Web server, in turn, confirms that the link to my post actually works.

Most WordPress-to-WordPress linkbacks are pingbacks; most free blogging systems support pingbacks; trackbacks remain a legitimate linking option, but one few people use.

Option 1: Using wp_list_comments() Only

In WordPress, the wp_list_comments() template tag allows you to filter comments by type: ‘comment’ means comments specifically submitted through your comment form; ‘pings’ constitutes pingbacks and trackbacks.

Suppose your comments.php page uses wp_list_comments for output. It probably looks like this:

<?php if ( have_comments() ) : ?>
	<h3><?php comments_number('No Comments', 'One Comment', '% Comments' );?> </h3>
	<ol class="commentlist">
	<?php wp_list_comments('avatar_size=48&reply_text=Reply to this comment'); ?>
	</ol>
	<div class="navigation" style="clear:both">
		<div class="alignleft"><?php previous_comments_link() ?></div>
		<div class="alignright"><?php next_comments_link() ?></div>
	</div>
	<div style="clear:both"></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. -->

	 <?php else : // comments are closed ?>
		<!-- If comments are closed. -->
		<p class="nocomments">Comments are closed.</p>

	<?php endif; ?>
<?php endif; ?>

We can quickly hack this to show comments and links, broken into two parts, like this:

<?php if ( have_comments() ) : ?>
	<h3>Comments</h3>
	<ol class="commentlist">
	<?php wp_list_comments('avatar_size=48&reply_text=Reply to this comment&type=comment'); ?>
	</ol>
	<h3>Linkbacks</h3>
	<ol class="commentlist">
	<?php wp_list_comments('avatar_size=48&reply_text=Reply to this comment&type=pings'); ?>
	</ol>
	<div class="navigation" style="clear:both">
		<div class="alignleft"><?php previous_comments_link() ?></div>
		<div class="alignright"><?php next_comments_link() ?></div>
	</div>
	<div style="clear:both"></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. -->

	 <?php else : // comments are closed ?>
		<!-- If comments are closed. -->
		<p class="nocomments">Comments are closed.</p>

	<?php endif; ?>
<?php endif; ?>

This works pretty well and requires very little coding. My concern is that it’s not very flexible, however, especially because it still doesn’t really differentiate between comments and linkbacks; and if you have a comment but not a linkback, or vice-versa, the display is awkward still.

I prefer a slightly more code-intensive solution, which ensures I get the results I seek.

Option 2: True Separation Of Comments And Linkbacks

Hacking how comments appear on your blog requires a bit of tinkering with PHP code, but it shouldn’t be too hard for anyone who has a general familiarity with HTML.

First, you need to open your comments.php file in your Web editor. Generally speaking, the path to that file is /wp-content/themes/your-themes-name/comments.php, where your-themes-name is, of course, the name of your theme.

Each comments.php file is a bit different, depending on theme. But you can identify where to begin your hack by looking for this PHP block:

<?php if ( have_comments() ) : ?>
//some HTML and PHP code here for laying out comments
<?php endif; ?>

You’ll want to copy, exactly, the code that outputs your comments. We’re going to need it. Set that code aside.

Add this block of code immediately after <?php if( have_comments() ) : ?>:

<?php
$ccount = 0;
$pcount = 0;
foreach ($comments as $comment) :
	$tmp = get_comment_type();
	switch($tmp) {
		case 'comment':
			$carray[$ccount] = $comment;
			$ccount++;
			break;
		default:
			$parray[$pcount] = $comment;
			$pcount++;
	}
endforeach; /* end for each comment */ ?>

What the block above does is break all your comments into two arrays: One for comments themselves, the other for pingbacks and trackbacks. We’ll next use these two arrays to actually output our grouped feedback.

We’re now going to add another code block, right after the one we just pasted. This one is going to determine if we output the comments part of our feedback.

<?php if ($ccount) : ?>
// HTML and PHP code to display comments
<?php endif; ?>

We need to amend the comments display code you copied a bit earlier. We’re both going to provide a count of comments / links, and we’re going to have to add a foreach loop to the display code.

First, I want to render a headline with a comment count, and prepare an ordered list that will hold the comments as list items:

<h3>Comments (<?php _e($ccount); ?>)</h3>
        <ol class="commentlist">

Now, I want to go ahead with my foreach loop, outputting each comment:

<?php foreach( $carray as $comment) : ?>
	<li <?php _e( $oddcomment ) ?>id="comment-<?php comment_ID() ?>"><div>
	<?php // Gravatar code
	if(function_exists('get_avatar')) echo get_avatar( $comment, 48 );
	?>
	<h4><?php comment_author_link() ?>:</h4>
	<?php comment_text() ?>
	<?php if ($comment->comment_approved == '0') : ?>
	<em>(<?php _e('Comment awaits moderation') ?>)</em>
	<?php endif; ?>
	<small class="commentmetadata"><a href="#comment-<?php comment_ID() ?>" title=""><?php comment_date(get_option('date_format')) ?>, <?php comment_time(get_option('time_format')) ?></a></small>
	<?php edit_comment_link(__('Edit'),'&nbsp;|&nbsp;&nbsp;',''); ?></div>
	</li>
	<?php /* Changes every other comment to a different class */
	if ('alt' == $oddcomment) $oddcomment = '';
	else $oddcomment = 'class="alt" ';
	?>
<?php endforeach; ?>
</ol>

So, altogether, the code block that will output comments only is:

<?php if ($ccount) : ?>
	<h3>Comments (<?php _e($ccount); ?>)</h3>
	<ol class="commentlist">

	<?php foreach( $carray as $comment) : ?>
		<li <?php _e( $oddcomment ) ?>id="comment-<?php comment_ID() ?>"><div>
		<?php // Gravatar code
		if(function_exists('get_avatar')) echo get_avatar( $comment, 48 );
		?>
		<h4><?php comment_author_link() ?>:</h4>
		<?php comment_text() ?>
		<?php if ($comment->comment_approved == '0') : ?>
		<em>(<?php _e('Comment awaits moderation') ?>)</em>
		<?php endif; ?>
		<small class="commentmetadata"><a href="#comment-<?php comment_ID() ?>" title=""><?php comment_date(get_option('date_format')) ?>, <?php comment_time(get_option('time_format')) ?></a></small>
		<?php edit_comment_link(__('Edit'),'&nbsp;|&nbsp;&nbsp;',''); ?></div>
		</li>
		<?php /* Changes every other comment to a different class */
		if ('alt' == $oddcomment) $oddcomment = '';
		else $oddcomment = 'class="alt" ';
		?>
	<?php endforeach; ?>

	</ol>
<?php endif; ?>

To output the links only, I simply copy and paste the code block above; change the headline to indicate linkbacks; and change the array name used from $carray to $parray.

<?php if ($pcount) : ?>
	<h3>Linkbacks (<?php _e($pcount); ?>)</h3>
	<ol class="commentlist">

	<?php foreach( $parray as $comment) : ?>
		<li <?php _e( $oddcomment ) ?>id="comment-<?php comment_ID() ?>"><div>
		<?php // Gravatar code
		if(function_exists('get_avatar')) echo get_avatar( $comment, 48 );
		?>
		<h4><?php comment_author_link() ?>:</h4>
		<?php comment_text() ?>
		<?php if ($comment->comment_approved == '0') : ?>
		<em>(<?php _e('Comment awaits moderation') ?>)</em>
		<?php endif; ?>
		<small class="commentmetadata"><a href="#comment-<?php comment_ID() ?>" title=""><?php comment_date(get_option('date_format')) ?>, <?php comment_time(get_option('time_format')) ?></a></small>
		<?php edit_comment_link(__('Edit'),'&nbsp;|&nbsp;&nbsp;',''); ?></div>
		</li>
		<?php /* Changes every other comment to a different class */
		if ('alt' == $oddcomment) $oddcomment = '';
		else $oddcomment = 'class="alt" ';
		?>
	<?php endforeach; ?>

	</ol>
<?php endif; ?>

So, in 100 percent finished form, the code I use to group comments and linkbacks into distinct parts, and show them as such, is:

<?php if ($comments) : ?>
    <?php
	$ccount = 0;
    	$pcount = 0;

		foreach ($comments as $comment) :
			$tmp = get_comment_type();
			switch($tmp) {
				case 'comment':
					$carray[$ccount] = $comment;
					$ccount++;
					break;
				default:
					$parray[$pcount] = $comment;
					$pcount++;
			}
		endforeach; /* end for each comment */
	?>

	<?php if ($ccount) : ?>
        <h3>Comments (<?php _e($ccount); ?>)</h3>
        <ol class="commentlist">

        <?php foreach( $carray as $comment) : ?>
            <li <?php _e( $oddcomment ) ?>id="comment-<?php comment_ID() ?>"><div>
            <?php // Gravatar code
            if(function_exists('get_avatar')) echo get_avatar( $comment, 48 );
            ?>
            <h4><?php comment_author_link() ?>:</h4>
            <?php comment_text() ?>
            <?php if ($comment->comment_approved == '0') : ?>
            <em>(<?php _e('Comment awaits moderation') ?>)</em>
            <?php endif; ?>
            <small class="commentmetadata"><a href="#comment-<?php comment_ID() ?>" title=""><?php comment_date(get_option('date_format')) ?>, <?php comment_time(get_option('time_format')) ?></a></small>
            <?php edit_comment_link(__('Edit'),'&nbsp;|&nbsp;&nbsp;',''); ?></div>
            </li>
            <?php /* Changes every other comment to a different class */
            if ('alt' == $oddcomment) $oddcomment = '';
            else $oddcomment = 'class="alt" ';
            ?>
        <?php endforeach; ?>

        </ol>
    <?php endif; ?>

    <?php if ($pcount) : ?>
    	<h3>Linkbacks (<?php _e($pcount); ?>)</h3>
        <ol class="commentlist">

        <?php foreach($parray as $comment) : ?>
            <li <?php _e( $oddcomment ) ?>id="comment-<?php comment_ID() ?>"><div>
            <?php // Gravatar code
            if(function_exists('get_avatar')) echo get_avatar( $comment, 48 );
            ?>
            <h4><?php comment_author_link() ?>:</h4>
            <?php comment_text() ?>
            <?php if ($comment->comment_approved == '0') : ?>
            <em>(<?php _e('Comment awaits moderation') ?>)</em>
            <?php endif; ?>
            <small class="commentmetadata"><a href="#comment-<?php comment_ID() ?>" title=""><?php comment_date(get_option('date_format')) ?>, <?php comment_time(get_option('time_format')) ?></a></small>
            <?php edit_comment_link(__('Edit'),'&nbsp;|&nbsp;&nbsp;',''); ?></div>
            </li>
            <?php /* Changes every other comment to a different class */
            if ('alt' == $oddcomment) $oddcomment = '';
            else $oddcomment = 'class="alt" ';
            ?>
		<?php endforeach; ?>

        </ol>
    <?php endif; ?>

 <?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. -->

	 <?php else : // comments are closed ?>
		<!-- If comments are closed. -->

	<?php endif; ?>
<?php endif; ?>

I distribute code under the GNU GPL.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  • Check out the Commenting Guidelines before commenting, please!
  • Want to share code? Please put it into a GitHub Gist, CodePen or pastebin and link to that in your comment.
  • Just have a line or two of markup? Wrap them in an appropriate SyntaxHighlighter Evolved shortcode for your programming language, please!