The WordPress Theme Comments Template

I hate the Comments Template. There, I said it. It can be a confusing mess.

Luckily for you, I’ve sorted it out. Confusing still, yes. But sorted out. For this tutorial on the Comments Template, I’m basically going to walk you through what’s going to happen, show you some custom code snippets you’ll need to add to your inc/template-tags.php file, and then drop the whole thing on you. Hopefully, it’ll start to make sense. But at the very least you’ll have a wicked comments template.

Let’s take a look at a quick list of what’s going on in this Template.

  1. Prevent loading for bots and on password protected posts
  2. Check if there are comments
  3. Distinguish between comments and trackbacks / pingbacks) so that we can display trackbacks with simpler mock-up. From this point on, I’ll refer to both trackbacks and pingbacks as “Pingbacks”.
  4. If there are comments, show the comments—with navigation for paginated comments
  5. If comments are open, show the comments “respond” form

That’s a lot of stuff going on for one template. But written out like that, it’s pretty straightforward.

Custom Callbacks for Comments and Pingbacks

We’re going to use the function wp_list_comments() that conveniently spits out an ordered list of comments and pingbacks markup for your post (threaded too).

To make our comments template code work, you’ll use a custom callback function that controls the layout of the actual comments and pingbacks. Open inc/template-tags.php and paste the following function at the very bottom of the file.

if ( ! function_exists( 'shape_comment' ) ) :
 * Template for comments and pingbacks.
 * Used as a callback by wp_list_comments() for displaying the comments.
 * @since Shape 1.0
function shape_comment( $comment, $args, $depth ) {
	$GLOBALS['comment'] = $comment;
	switch ( $comment->comment_type ) :
		case 'pingback' :
		case 'trackback' :
	<li class="post pingback">
		<p><?php _e( 'Pingback:', 'shape' ); ?> <?php comment_author_link(); ?><?php edit_comment_link( __( '(Edit)', 'shape' ), ' ' ); ?></p>
		default :
	<li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
		<article id="comment-<?php comment_ID(); ?>" class="comment">
				<div class="comment-author vcard">
					<?php echo get_avatar( $comment, 40 ); ?>
					<?php printf( __( '%s <span class="says">says:</span>', 'shape' ), sprintf( '<cite class="fn">%s</cite>', get_comment_author_link() ) ); ?>
				</div><!-- .comment-author .vcard -->
				<?php if ( $comment->comment_approved == '0' ) : ?>
					<em><?php _e( 'Your comment is awaiting moderation.', 'shape' ); ?></em>
					<br />
				<?php endif; ?>

				<div class="comment-meta commentmetadata">
					<a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>"><time pubdate datetime="<?php comment_time( 'c' ); ?>">
						/* translators: 1: date, 2: time */
						printf( __( '%1$s at %2$s', 'shape' ), get_comment_date(), get_comment_time() ); ?>
					<?php edit_comment_link( __( '(Edit)', 'shape' ), ' ' );
				</div><!-- .comment-meta .commentmetadata -->

			<div class="comment-content"><?php comment_text(); ?></div>

			<div class="reply">
				<?php comment_reply_link( array_merge( $args, array( 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
			</div><!-- .reply -->
		</article><!-- #comment-## -->

endif; // ends check for shape_comment()

Let’s explain what’s happening here in more detail. First, this code repeats for each comment or trackback we have. On lines 11-14, we use a PHP “switch statement“, which is a type of conditional similar to IF .. ELSE statements. In simplest terms, switch statements let you first determine the value of a variable, and display different code depending on the value of that variable.

In English, our comments switch statement says: “in the case that this particular comment is a pingback or a trackback, format it with the markup on on lines 15-16.” Here’s how our pingbacks look:

Example Pingback
Example Pingback

It’s pretty sweet. It’s also pretty bare, but you can pretty it up with just CSS alone. We’ll talk about CSS in a later lesson.

Notice how we don’t have any closing <li> tag on line 17. wp_list_comments() adds this part in automatically.

Now, on line 18, the “break” statement means we’re done with pingbacks and trackbacks. The “default” statement on line 19 says, in English, “in the case that the current comment is not any of the other cases above, format it with the default markup on lines 21-41.” Since the only other cases above are pingbacks and trackbacks, this markup will be applied to all regular comments.

Example Comment
Example Comment

Again, bare, but we’ll color it in later.

It’s important that each individual comment li has comment_class() added (see line 21), because, like body_class() and post_class(), comment_class() adds useful classes to comments that you can target with CSS. For example, comments made by the post’s author get a class of “bypostauthor”, so you can distinguish the author’s comments from the rest.

To change the default size of your gravatar, just change the 40 in echo get_avatar( $comment, 40 ); on line 25 above. The 40 is the size in pixels of your gravatar. In fact, if you want to alter the layout of the individual comment, you’d modify the code on lines 21-41 (or 15-16 for pingbacks).

Just as with pingbacks, we don’t need a <li> tag to correspond with the opening li> on line 21, because WordPress will add it later.

All righty, we end our “default” case with the “break” on line 52, and we end the switch statement on line 53 with “endswitch”.

The Comments Template (comments.php)

I haven’t scared you away have I? I’ll be honest, it’s not that scary. We have to put our shape_comment() function that we walked through above to use inside the comments template.

There are helpful PHP comments that should guide you along in understanding what’s happening. Paste this code in the comments.php file.

 * The template for displaying Comments.
 * The area of the page that contains both current comments
 * and the comment form. The actual display of comments is
 * handled by a callback to shape_comment() which is
 * located in the inc/template-tags.php file.
 * @package Shape
 * @since Shape 1.0

	 * If the current post is protected by a password and
	 * the visitor has not yet entered the password we will
	 * return early without loading the comments.
	if ( post_password_required() )

	<div id="comments" class="comments-area">

	<?php // You can start editing here -- including this comment! ?>

	<?php if ( have_comments() ) : ?>
		<h2 class="comments-title">
				printf( _n( 'One thought on &ldquo;%2$s&rdquo;', '%1$s thoughts on &ldquo;%2$s&rdquo;', get_comments_number(), 'shape' ),
					number_format_i18n( get_comments_number() ), '<span>' . get_the_title() . '</span>' );

		<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through? If so, show navigation ?>
		<nav role="navigation" id="comment-nav-above" class="site-navigation comment-navigation">
			<h1 class="assistive-text"><?php _e( 'Comment navigation', 'shape' ); ?></h1>
			<div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'shape' ) ); ?></div>
			<div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'shape' ) ); ?></div>
		</nav><!-- #comment-nav-before .site-navigation .comment-navigation -->
		<?php endif; // check for comment navigation ?>

		<ol class="commentlist">
				/* Loop through and list the comments. Tell wp_list_comments()
				 * to use shape_comment() to format the comments.
				 * If you want to overload this in a child theme then you can
				 * define shape_comment() and that will be used instead.
				 * See shape_comment() in inc/template-tags.php for more.
				wp_list_comments( array( 'callback' => 'shape_comment' ) );
		</ol><!-- .commentlist -->

		<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through? If so, show navigation ?>
		<nav role="navigation" id="comment-nav-below" class="site-navigation comment-navigation">
			<h1 class="assistive-text"><?php _e( 'Comment navigation', 'shape' ); ?></h1>
			<div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'shape' ) ); ?></div>
			<div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'shape' ) ); ?></div>
		</nav><!-- #comment-nav-below .site-navigation .comment-navigation -->
		<?php endif; // check for comment navigation ?>

	<?php endif; // have_comments() ?>

		// If comments are closed and there are comments, let's leave a little note, shall we?
		if ( ! comments_open() && '0' != get_comments_number() && post_type_supports( get_post_type(), 'comments' ) ) :
		<p class="nocomments"><?php _e( 'Comments are closed.', 'shape' ); ?></p>
	<?php endif; ?>

	<?php comment_form(); ?>

</div><!-- #comments .comments-area -->

The comment_form() function (line 74), is responsible for producing the complete comment form. Here’s what it produces, in its default form (which is how we’re using it). No styling, yet, of course:

Logged Out View
Comment Form, Logged Out View
Comment Form, Logged In
Comment Form, Logged In View

If you would like to change elements in the comment form, you can do so by passing different parameters to the comment_form() function. See the Codex for a full list of parameters.

And that’s it. You’ve got a pretty sweet Comments Template to call your very own.

How To Create a WordPress Theme

This post is part of the The ThemeShaper WordPress Theme Tutorial: 2nd Edition that will show you how to create a powerful WordPress Theme from scratch. Read it from the beginning and code yourself up something awesome.

  1. WordPress Theme Tutorial Introduction
  2. Developing Theme Sense
  3. Theme Development Tools
  4. Creating a Theme HTML Structure
  5. Template and Directory Structure
  6. Setting Up Your Theme Functions
  7. Secure Your WordPress Theme
  8. The Header Template
  9. The Index Template
  10. The Single Post, Post Attachment, & 404 Templates
  11. The Comments Template
  12. The Search Template & The Page Template
  13. The Archive Template
  14. The Sidebar Template & The Footer Template
  15. Reset-Rebuild Theme CSS & Define Your Layouts
  16. Custom Background & Custom Header
  17. Distributing Your WordPress Theme

18 thoughts on “The WordPress Theme Comments Template”

  1. I set it up exactly the way you explained in your post, but it doesn’t seem to display the comments. The form is showing up correctly, but none of the actual comments

    1. So I actually figured it out. I wasn’t including the inc/template-tags.php into the functions file. Here’s the code I used:

      require( dirname( __FILE__ ) . '/inc/template-tags.php' );

      I am new to WordPress, so I had no clue that I needed to do that. May want to include that in your tutorial. Just a thought. Otherwise, this is a great set of tutorials! Thanks!

  2. Any idea why the plural part of the string on line 32 in comments.php is not showing up as translateable in PoEdit? It only gathers the first part.

    1. So I found out what was going on. I had to make PoEdit check for plural translations and voila it was there.

  3. After this step, and double checking it, no form appeared in my preview. The sample comments are all there.

    Where does pull the form from?

    What am I missing here?

  4. hello I am brand new to wordpress and want to make custom themes and what i want to customize is the comments (lol hardest part of a theme/template) This is what I want: a widget or plugin to allow anyone to comment by using facebook or twitter… I’ve heard there is a way to do this and I’m not sure if I understood it correctly but a way the comments can show up on your facebook page and twitter page as well

  5. In the first paragraph after the discussion of regular comments it says:
    “It’s important that each individual comment li has comments_class()
    Shouldn’t that be comment_class()?

    Thanks for the tutorials. I’ve found them extremely helpful.

  6. I don’t want comments to be any where on my site, ever. Do you I have to include this file and what else do I need to do to exclude them from my site? Thanks!

    1. You could do a multi-file search to remove all calls to the comments template. If you search for the term comments_template you should find them all. For example, in single.php – you can remove or comment out these lines:

      // If comments are open or we have at least one comment, load up the comment template
      if ( comments_open() || '0' != get_comments_number() )
      comments_template( '', true );

      Be sure to also remove or comment out the opening and closing PHP tags just before and after the above code too.

Comments are closed.