The WordPress Theme Comments Template

I hate the Comments Template. There, I said it. It can be a confusing mess. In version 2.7, WordPress introduced a simpler way of producing Comments Templates—which was no help if you wanted to separate your comments and trackbacks or have custom comment markup. It’s still confusing.

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 functions.php, and then drop the whole thing on you. Hopefully, it’ll start to make sense. But at they 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. Count the number of comments and trackbacks (or pings)
  4. If there are comments, show the comments—with navigation for paginated comments
  5. If there are trackbacks, show the trackbacks
  6. 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 Trackbacks

Now, with WordPress 2.7 came the function wp_list_comments() that conveniently spits out an ordered list of comments and trackbacks markup for your post (threaded too). Convenient if you want that. And we don’t. We want separated threaded comments and trackbacks, with our own custom markup.

To make the comments template code I’m going to give you work, you’ll need a set of custom callbacks for your list of Comments and Trackbacks. Add the following 2 functions to your theme functions.php file.

  1. // Custom callback to list comments in the your-theme style
  2. function custom_comments($comment, $args, $depth) {
  3.   $GLOBALS['comment'] = $comment;
  4.  $GLOBALS['comment_depth'] = $depth;
  5.   ?>
  6.    <li id="comment-<?php comment_ID() ?>" <?php comment_class() ?>>
  7.     <div class="comment-author vcard"><?php commenter_link() ?></div>
  8.     <div class="comment-meta"><?php printf(__('Posted %1$s at %2$s <span class="meta-sep">|</span> <a href="%3$s" title="Permalink to this comment">Permalink</a>', 'your-theme'),
  9.        get_comment_date(),
  10.        get_comment_time(),
  11.        '#comment-' . get_comment_ID() );
  12.        edit_comment_link(__('Edit', 'your-theme'), ' <span class="meta-sep">|</span> <span class="edit-link">', '</span>'); ?></div>
  13.   <?php if ($comment->comment_approved == '0') _e("\t\t\t\t\t<span class='unapproved'>Your comment is awaiting moderation.</span>\n", 'your-theme') ?>
  14.           <div class="comment-content">
  15.         <?php comment_text() ?>
  16.     </div>
  17.   <?php // echo the comment reply link
  18.    if($args['type'] == 'all' || get_comment_type() == 'comment') :
  19.     comment_reply_link(array_merge($args, array(
  20.      'reply_text' => __('Reply','your-theme'),
  21.      'login_text' => __('Log in to reply.','your-theme'),
  22.      'depth' => $depth,
  23.      'before' => '<div class="comment-reply-link">',
  24.      'after' => '</div>'
  25.     )));
  26.    endif;
  27.   ?>
  28. <?php } // end custom_comments
  1. // Custom callback to list pings
  2. function custom_pings($comment, $args, $depth) {
  3.        $GLOBALS['comment'] = $comment;
  4.         ?>
  5.       <li id="comment-<?php comment_ID() ?>" <?php comment_class() ?>>
  6.        <div class="comment-author"><?php printf(__('By %1$s on %2$s at %3$s', 'your-theme'),
  7.          get_comment_author_link(),
  8.          get_comment_date(),
  9.          get_comment_time() );
  10.          edit_comment_link(__('Edit', 'your-theme'), ' <span class="meta-sep">|</span> <span class="edit-link">', '</span>'); ?></div>
  11.     <?php if ($comment->comment_approved == '0') _e('\t\t\t\t\t<span class="unapproved">Your trackback is awaiting moderation.</span>\n', 'your-theme') ?>
  12.             <div class="comment-content">
  13.        <?php comment_text() ?>
  14.    </div>
  15. <?php } // end custom_pings

Those look kind of hairy don’t they? But you’re better off for it. Now you have access to the comments markup. I think the markup I’ve got in there is pretty sweet and will let you make a lot of changes with just CSS alone, but if you do want to alter the markup, well, there it is.

We’ll also need a special custom function that the custom_comments() is calling. This function will markup the gravatar we’re using so it fits into the microformat schema for hcard.

  1. // Produces an avatar image with the hCard-compliant photo class
  2. function commenter_link() {
  3.  $commenter = get_comment_author_link();
  4.  if ( ereg( '<a[^>]* class=[^>]+>', $commenter ) ) {
  5.   $commenter = ereg_replace( '(<a[^>]* class=[\'"]?)', '\\1url ' , $commenter );
  6.  } else {
  7.   $commenter = ereg_replace( '(<a )/', '\\1class="url "' , $commenter );
  8.  }
  9.  $avatar_email = get_comment_author_email();
  10.  $avatar = str_replace( "class='avatar", "class='photo avatar", get_avatar( $avatar_email, 80 ) );
  11.  echo $avatar . ' <span class="fn n">' . $commenter . '</span>';
  12. } // end commenter_link

If you want to change the default size of your gravatar just change the 80 in get_avatar( $avatar_email, 80 ) ). The 80 is the size in pixels of your gravatar.

The Comments Template

I haven’t scared you away have I? I’ll be honest, it’s not that scary. Here’s the comments template with some helpful PHP comments that should guide you along in understanding what’s happening.

  1. <?php /* The Comments Template — with, er, comments! */ ?>  
  2.    <div id="comments">
  3. <?php /* Run some checks for bots and password protected posts */ ?>
  4. <?php
  5.  $req = get_option('require_name_email'); // Checks if fields are required.
  6.  if ( 'comments.php' == basename($_SERVER['SCRIPT_FILENAME']) )
  7.   die ( 'Please do not load this page directly. Thanks!' );
  8.  if ( ! empty($post->post_password) ) :
  9.   if ( $_COOKIE['wp-postpass_' . COOKIEHASH] != $post->post_password ) :
  10. ?>
  11.     <div class="nopassword"><?php _e('This post is password protected. Enter the password to view any comments.', 'your-theme') ?></div>
  12.    </div><!– .comments –>
  13. <?php
  14.   return;
  15.  endif;
  16. endif;
  17. ?>
  18.  
  19. <?php /* See IF there are comments and do the comments stuff! */ ?>      
  20. <?php if ( have_comments() ) : ?>
  21.  
  22. <?php /* Count the number of comments and trackbacks (or pings) */
  23. $ping_count = $comment_count = 0;
  24. foreach ( $comments as $comment )
  25.  get_comment_type() == "comment" ? ++$comment_count : ++$ping_count;
  26. ?>
  27.  
  28. <?php /* IF there are comments, show the comments */ ?>
  29. <?php if ( ! empty($comments_by_type['comment']) ) : ?>
  30.  
  31.     <div id="comments-list" class="comments">
  32.      <h3><?php printf($comment_count > 1 ? __('<span>%d</span> Comments', 'your-theme') : __('<span>One</span> Comment', 'your-theme'), $comment_count) ?></h3>
  33.  
  34. <?php /* If there are enough comments, build the comment navigation  */ ?>    
  35. <?php $total_pages = get_comment_pages_count(); if ( $total_pages > 1 ) : ?>
  36.      <div id="comments-nav-above" class="comments-navigation">
  37.         <div class="paginated-comments-links"><?php paginate_comments_links(); ?></div>
  38.      </div><!– #comments-nav-above –>    
  39. <?php endif; ?>    
  40.    
  41. <?php /* An ordered list of our custom comments callback, custom_comments(), in functions.php   */ ?>    
  42.      <ol>
  43. <?php wp_list_comments('type=comment&callback=custom_comments'); ?>
  44.      </ol>
  45.  
  46. <?php /* If there are enough comments, build the comment navigation */ ?>
  47. <?php $total_pages = get_comment_pages_count(); if ( $total_pages > 1 ) : ?>    
  48.       <div id="comments-nav-below" class="comments-navigation">
  49.       <div class="paginated-comments-links"><?php paginate_comments_links(); ?></div>
  50.          </div><!– #comments-nav-below –>
  51. <?php endif; ?>    
  52.      
  53.     </div><!– #comments-list .comments –>
  54.  
  55. <?php endif; /* if ( $comment_count ) */ ?>
  56.  
  57. <?php /* If there are trackbacks(pings), show the trackbacks  */ ?>
  58. <?php if ( ! empty($comments_by_type['pings']) ) : ?>
  59.  
  60.     <div id="trackbacks-list" class="comments">
  61.      <h3><?php printf($ping_count > 1 ? __('<span>%d</span> Trackbacks', 'your-theme') : __('<span>One</span> Trackback', 'your-theme'), $ping_count) ?></h3>
  62.  
  63. <?php /* An ordered list of our custom trackbacks callback, custom_pings(), in functions.php   */ ?>    
  64.      <ol>
  65. <?php wp_list_comments('type=pings&callback=custom_pings'); ?>
  66.      </ol>    
  67.      
  68.     </div><!– #trackbacks-list .comments –>  
  69.  
  70.  
  71. <?php endif /* if ( $ping_count ) */ ?>
  72. <?php endif /* if ( $comments ) */ ?>
  73.  
  74. <?php /* If comments are open, build the respond form */ ?>
  75. <?php if ( 'open' == $post->comment_status ) : ?>
  76.     <div id="respond">
  77.         <h3><?php comment_form_title( __('Post a Comment', 'your-theme'), __('Post a Reply to %s', 'your-theme') ); ?></h3>
  78.        
  79.         <div id="cancel-comment-reply"><?php cancel_comment_reply_link() ?></div>
  80.  
  81. <?php if ( get_option('comment_registration') && !$user_ID ) : ?>
  82.      <p id="login-req"><?php printf(__('You must be <a href="%s" title="Log in">logged in</a> to post a comment.', 'your-theme'),
  83.      get_option('siteurl') . '/wp-login.php?redirect_to=' . get_permalink() ) ?></p>
  84.  
  85. <?php else : ?>
  86.      <div class="formcontainer">
  87.      
  88.  
  89.       <form id="commentform" action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post">
  90.  
  91. <?php if ( $user_ID ) : ?>
  92.        <p id="login"><?php printf(__('<span class="loggedin">Logged in as <a href="%1$s" title="Logged in as %2$s">%2$s</a>.</span> <span class="logout"><a href="%3$s" title="Log out of this account">Log out?</a></span>', 'your-theme'),
  93.         get_option('siteurl') . '/wp-admin/profile.php',
  94.         wp_specialchars($user_identity, true),
  95.         wp_logout_url(get_permalink()) ) ?></p>
  96.  
  97. <?php else : ?>
  98.  
  99.        <p id="comment-notes"><?php _e('Your email is <em>never</em> published nor shared.', 'your-theme') ?> <?php if ($req) _e('Required fields are marked <span class="required">*</span>', 'your-theme') ?></p>
  100.  
  101.               <div id="form-section-author" class="form-section">
  102.         <div class="form-label"><label for="author"><?php _e('Name', 'your-theme') ?></label> <?php if ($req) _e('<span class="required">*</span>', 'your-theme') ?></div>
  103.         <div class="form-input"><input id="author" name="author" type="text" value="<?php echo $comment_author ?>" size="30" maxlength="20" tabindex="3" /></div>
  104.               </div><!– #form-section-author .form-section –>
  105.  
  106.               <div id="form-section-email" class="form-section">
  107.         <div class="form-label"><label for="email"><?php _e('Email', 'your-theme') ?></label> <?php if ($req) _e('<span class="required">*</span>', 'your-theme') ?></div>
  108.         <div class="form-input"><input id="email" name="email" type="text" value="<?php echo $comment_author_email ?>" size="30" maxlength="50" tabindex="4" /></div>
  109.               </div><!– #form-section-email .form-section –>
  110.  
  111.               <div id="form-section-url" class="form-section">
  112.         <div class="form-label"><label for="url"><?php _e('Website', 'your-theme') ?></label></div>
  113.         <div class="form-input"><input id="url" name="url" type="text" value="<?php echo $comment_author_url ?>" size="30" maxlength="50" tabindex="5" /></div>
  114.               </div><!– #form-section-url .form-section –>
  115.  
  116. <?php endif /* if ( $user_ID ) */ ?>
  117.  
  118.               <div id="form-section-comment" class="form-section">
  119.         <div class="form-label"><label for="comment"><?php _e('Comment', 'your-theme') ?></label></div>
  120.         <div class="form-textarea"><textarea id="comment" name="comment" cols="45" rows="8" tabindex="6"></textarea></div>
  121.               </div><!– #form-section-comment .form-section –>
  122.              
  123.               <div id="form-allowed-tags" class="form-section">
  124.                <p><span><?php _e('You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes:', 'your-theme') ?></span> <code><?php echo allowed_tags(); ?></code></p>
  125.               </div>
  126.        
  127. <?php do_action('comment_form', $post->ID); ?>
  128.                  
  129.        <div class="form-submit"><input id="submit" name="submit" type="submit" value="<?php _e('Post Comment', 'your-theme') ?>" tabindex="7" /><input type="hidden" name="comment_post_ID" value="<?php echo $id; ?>" /></div>
  130.  
  131. <?php comment_id_fields(); ?>  
  132.  
  133. <?php /* Just … end everything. We're done here. Close it up. */ ?>  
  134.  
  135.       </form><!– #commentform –>          
  136.      </div><!– .formcontainer –>
  137. <?php endif /* if ( get_option('comment_registration') && !$user_ID ) */ ?>
  138.     </div><!– #respond –>
  139. <?php endif /* if ( 'open' == $post->comment_status ) */ ?>
  140.    </div><!– #comments –>

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

How To Create a WordPress Theme

This post is part of a WordPress Themes Tutorial 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. Theme Development Tools
  3. Creating a Theme HTML Structure
  4. Template and Directory Structure
  5. The Header Template
  6. The Index Template
  7. The Single Post, Post Attachment, & 404 Templates
  8. The Comments Template
  9. The Search Template & The Page Template
  10. The Archive, Author, Category & Tags Template
  11. The Sidebar Template
  12. Reset-Rebuild Theme CSS & Define Your Layouts

Don't forget: You should follow me on twitter here.

Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

32 Comments

  1. Posted July 1, 2009 at 9:16 am | Permalink

    These posts keep getting better and better Ian! The comments template has always been a pain to configure. It still is, but I definitely have a better grasp on things after sifting through those PHP comments. This is an excellent resource!

  2. tolmar
    Posted July 1, 2009 at 9:51 am | Permalink

    Great post again.

    Could you please share the entire theme with us? I’d like to see how it all goes in a full installation.
    thx.

    • Posted July 1, 2009 at 10:30 am | Permalink

      i’m with tolmar. it’d be awesome if we could have the theme for download so that we can compare what we’re doing with the finished product to make sure we haven’t screwed up.

      loving this series. i’ll share my personal results when i’m done building mine…. following your articles step by step ;)

      thanks,
      Jon Broom

    • Posted July 1, 2009 at 10:34 am | Permalink

      I’ll eventually get the code up on Google Code so everyone can browse through it. In the meantime, check out the Shape Theme. It’s built on the same code base.

      • tolmar
        Posted July 2, 2009 at 7:16 pm | Permalink

        thx for the reply Ian, appreciated .

      • Posted July 2, 2009 at 10:08 pm | Permalink

        Tolmar, you can now browse and checkout the code on Google Code. Hope that helps!

      • Posted January 24, 2010 at 1:51 pm | Permalink

        Hi Ian,

        I’m looking at the comments.php code and I’m not sure but I think there’s some incorrect nesting here:

        Shouldn’t the above be right before ?

      • Posted January 24, 2010 at 1:52 pm | Permalink

        Ooops, it didn’t show up…

        return;
        endif;
        endif;

      • Posted January 24, 2010 at 2:09 pm | Permalink

        Here’s another one… just don’t know where it is?

        and

        endif; /* if ( $comment_count ) */

  3. Posted July 1, 2009 at 10:57 am | Permalink

    I don’t know if this has been asked before, but I have a question about this ‘your-theme’ parameter
    Each time I create a new theme based on this one,do I need to rename this parameter to reflect the new theme name?

    thanks

  4. João Nunes
    Posted July 1, 2009 at 12:38 pm | Permalink

    Great series. A bit out of my league, but I’m learning stuff each step of the way. Can’t wait to get to css…

    • mathieu Ab
      Posted July 1, 2009 at 1:54 pm | Permalink

      i tried it today but i have problems with the comments template et the functions’ one.

      i can’t see the comments proper on the comments page and it seem i miss a closure “?>” somewhere on the functions template.

  5. mathieu Ab
    Posted July 1, 2009 at 3:21 pm | Permalink

    ok my bad, i fixed it. Forgot something in single.php. All good now.

  6. Posted July 1, 2009 at 5:33 pm | Permalink

    Think I found an error in your code. In the very first function up top on line six you have:
    class=""

    but it really should just be

    because it already prints the class=”….”.

  7. Posted July 1, 2009 at 5:35 pm | Permalink

    Ok, you’re comments don’t like code inputs, lets try it as HTML entities:

    Think I found an error in your code. In the very first function up top on line six you have:
    <code>class="<?php comment_class();?>"</code>

    but it really should just be
    <code><?php comment_class(); ?></code>
    because it already prints the class="….".

    • Posted July 1, 2009 at 9:00 pm | Permalink

      You’re absolutely right, John. Thanks for spotting that and letting me know about it!

  8. tolmarc
    Posted July 9, 2009 at 3:58 pm | Permalink

    Just a quick question, how do I add highlight to author comments? I know that in wp 2.7 it can be done with CSS only. but it doesn’t work with the theme here.

    • tolmarc
      Posted July 9, 2009 at 4:28 pm | Permalink

      Ian,

      You’ve got a small bug on the comments function in functions.php in the shape theme. in the comment class you should omit the “” and leave the wp_comment_class without “.

      It works great on the function.php in the SVN.

    • Posted July 10, 2009 at 7:12 pm | Permalink

      It’s there and it works with the Theme code in this tutorial. You just need to target .bypostauthor.

  9. Posted July 14, 2009 at 2:53 pm | Permalink

    Hi Ian,

    Amazing tutorials, really helped me to put my new site design together quickly.

    This was going to be a “why can’t I work this out!” post, but its turned into a “its important to know…”! Anyway, I was struggling getting the reply to comment link to show, and after playing with the code for about an hour, I realised there was a setting in the admin panel under discussion to turn threaded comments on! Just a point to note if anyone else has the problem! Thanks again.

    • Posted July 23, 2009 at 11:39 pm | Permalink

      Thanks Alex – Didn’t know how to do that, and came back here to find out. Appreciate the help!

  10. paul
    Posted July 29, 2009 at 4:23 pm | Permalink

    my avatars dont show up, but just yesterday everything was good, it even doesnt work with pure shape templates
    i’m confused

  11. Samuel
    Posted October 25, 2009 at 12:24 pm | Permalink

    Is it possible to not show the comment number?

  12. Posted October 29, 2009 at 8:24 am | Permalink

    This tutorial rocks! I can’t stand the wordpress comments template and this post helped me to do things I wanted with comments I’m using a slightly modified version of this tutorial’s code on my personal site, and will shortly be using it on client’s sites. Thanks!

  13. Mark
    Posted November 10, 2009 at 4:53 pm | Permalink

    how do you style the author/admin comments?

  14. Posted November 18, 2009 at 7:30 pm | Permalink

    I get these two errors:

    Warning: Cannot modify header information – headers already sent by (output started at /home/rigidkit/public_html/wp-content/themes/rigidkitchen/functions.php:25) in /home/rigidkit/public_html/wp-content/plugins/subscribe-to-comments.php on line 817

    Warning: Cannot modify header information – headers already sent by (output started at /home/rigidkit/public_html/wp-content/themes/rigidkitchen/functions.php:25) in /home/rigidkit/public_html/wp-includes/pluggable.php on line 865

    Using AJAX commenting and subscribe2comments

  15. Joe
    Posted December 6, 2009 at 1:28 am | Permalink

    Hey Ian,

    Where is that “” coming from at the top of your comments template file above? I don’t see the opening tag. At the very end of the file you close the #comments div so it’s not that.

    Is it just a typo? Thanks!

    • Joe
      Posted December 6, 2009 at 1:31 am | Permalink

      ++++ Let’s try that again +++

      Where is that coming from at the top of your comments template file above? I don’t see the opening tag. At the very end of the file you close the #comments div so it’s not that.

      • Joe
        Posted December 6, 2009 at 1:35 am | Permalink

        ++++ Okay… no code then.

        There’s a closing div.comments tag at the top and I’m just wondering if it is supposed to be there.

  16. Posted January 30, 2010 at 11:58 am | Permalink

    Hey alex; I didn’t know how to do that and came back here to find out. I like free infos so thanks and have a great week end :)

2 Trackbacks

  1. [...] 原文:The WordPress Theme Comments Template [...]

  2. By Comment Templates - WordPress Tavern Forum on July 9, 2009 at 5:23 am

    [...] found these from a quick google search: First one is from theme shaper http://themeshaper.com/wordpress-the…late-tutorial/ Second is a comment system that is free to download [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution. In addition, you may find yourself fitter, happier and more productive. Comment away.

Subscribe without commenting