The Ultimate WordPress Theme Tutorial (8)

The WordPress Theme Comments Template

Posted on  by Ian Stewart

 

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.

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

01
02
03
04
05
06
07
08
09
10
11
12
// Produces an avatar image with the hCard-compliant photo class
function commenter_link() {
    $commenter = get_comment_author_link();
    if ( ereg( '<a[^>]* class=[^>]+>', $commenter ) ) {
        $commenter = ereg_replace( '(<a[^>]* class=['"]?)', '1url ' , $commenter );
    } else {
        $commenter = ereg_replace( '(<a )/', '1class="url "' , $commenter );
    }
    $avatar_email = get_comment_author_email();
    $avatar = str_replace( "class='avatar", "class='photo avatar", get_avatar( $avatar_email, 80 ) );
    echo $avatar . ' <span>' . $commenter . '</span>';
} // 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.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?php /* The Comments Template — with, er, comments! */ ?>
            <div id="comments">
<?php /* Run some checks for bots and password protected posts */ ?>
<?php
    $req = get_option('require_name_email'); // Checks if fields are required.
    if ( 'comments.php' == basename($_SERVER['SCRIPT_FILENAME']) )
        die ( 'Please do not load this page directly. Thanks!' );
    if ( ! empty($post->post_password) ) :
        if ( $_COOKIE['wp-postpass_' . COOKIEHASH] != $post->post_password ) :
?>
                <div class="nopassword"><?php _e('This post is password protected. Enter the password to view any comments.', 'your-theme') ?></div>
            </div><!-- .comments -->
<?php
        return;
    endif;
endif;
?>
<?php /* See IF there are comments and do the comments stuff! */ ?>
<?php if ( have_comments() ) : ?>
<?php /* Count the number of comments and trackbacks (or pings) */
$ping_count = $comment_count = 0;
foreach ( $comments as $comment )
    get_comment_type() == "comment" ? ++$comment_count : ++$ping_count;
?>
<?php /* IF there are comments, show the comments */ ?>
<?php if ( ! empty($comments_by_type['comment']) ) : ?>
                <div id="comments-list" class="comments">
                    <h3><?php printf($comment_count > 1 ? __('<span>%d</span> Comments', 'your-theme') : __('<span>One</span> Comment', 'your-theme'), $comment_count) ?></h3>
<?php /* If there are enough comments, build the comment navigation  */ ?>
<?php $total_pages = get_comment_pages_count(); if ( $total_pages > 1 ) : ?>
                    <div id="comments-nav-above" class="comments-navigation">
                                <div class="paginated-comments-links"><?php paginate_comments_links(); ?></div>
                    </div><!-- #comments-nav-above -->
<?php endif; ?>                  
<?php /* An ordered list of our custom comments callback, custom_comments(), in functions.php   */ ?>
                    <ol>
<?php wp_list_comments('type=comment&callback=custom_comments'); ?>
                    </ol>
<?php /* If there are enough comments, build the comment navigation */ ?>
<?php $total_pages = get_comment_pages_count(); if ( $total_pages > 1 ) : ?>
                <div id="comments-nav-below" class="comments-navigation">
                        <div class="paginated-comments-links"><?php paginate_comments_links(); ?></div>
            </div><!-- #comments-nav-below -->
<?php endif; ?>                  
                </div><!-- #comments-list .comments -->
<?php endif; /* if ( $comment_count ) */ ?>
<?php /* If there are trackbacks(pings), show the trackbacks  */ ?>
<?php if ( ! empty($comments_by_type['pings']) ) : ?>
                <div id="trackbacks-list" class="comments">
                    <h3><?php printf($ping_count > 1 ? __('<span>%d</span> Trackbacks', 'your-theme') : __('<span>One</span> Trackback', 'your-theme'), $ping_count) ?></h3>
<?php /* An ordered list of our custom trackbacks callback, custom_pings(), in functions.php   */ ?>
                    <ol>
<?php wp_list_comments('type=pings&callback=custom_pings'); ?>
                    </ol>            
                </div><!-- #trackbacks-list .comments -->          
<?php endif /* if ( $ping_count ) */ ?>
<?php endif /* if ( $comments ) */ ?>
<?php /* If comments are open, build the respond form */ ?>
<?php if ( 'open' == $post->comment_status ) : ?>
                <div id="respond">
                    <h3><?php comment_form_title( __('Post a Comment', 'your-theme'), __('Post a Reply to %s', 'your-theme') ); ?></h3>
                    <div id="cancel-comment-reply"><?php cancel_comment_reply_link() ?></div>
<?php if ( get_option('comment_registration') && !$user_ID ) : ?>
                    <p id="login-req"><?php printf(__('You must be <a href="%s" title="Log in">logged in</a> to post a comment.', 'your-theme'),
                    get_option('siteurl') . '/wp-login.php?redirect_to=' . get_permalink() ) ?></p>
<?php else : ?>
                    <div class="formcontainer">  
                        <form id="commentform" action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post">
<?php if ( $user_ID ) : ?>
                            <p id="login"><?php printf(__('<span>Logged in as <a href="%1$s" title="Logged in as %2$s">%2$s</a>.</span> <span><a href="%3$s" title="Log out of this account">Log out?</a></span>', 'your-theme'),
                                get_option('siteurl') . '/wp-admin/profile.php',
                                wp_specialchars($user_identity, true),
                                wp_logout_url(get_permalink()) ) ?></p>
<?php else : ?>
                            <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>*</span>', 'your-theme') ?></p>
              <div id="form-section-author" class="form-section">
                                <div class="form-label"><label for="author"><?php _e('Name', 'your-theme') ?></label> <?php if ($req) _e('<span>*</span>', 'your-theme') ?></div>
                                <div class="form-input"><input id="author" name="author" type="text" value="<?php echo $comment_author ?>" size="30" maxlength="20" tabindex="3" /></div>
              </div><!-- #form-section-author .form-section -->
              <div id="form-section-email" class="form-section">
                                <div class="form-label"><label for="email"><?php _e('Email', 'your-theme') ?></label> <?php if ($req) _e('<span>*</span>', 'your-theme') ?></div>
                                <div class="form-input"><input id="email" name="email" type="text" value="<?php echo $comment_author_email ?>" size="30" maxlength="50" tabindex="4" /></div>
              </div><!-- #form-section-email .form-section -->
              <div id="form-section-url" class="form-section">
                                <div class="form-label"><label for="url"><?php _e('Website', 'your-theme') ?></label></div>
                                <div class="form-input"><input id="url" name="url" type="text" value="<?php echo $comment_author_url ?>" size="30" maxlength="50" tabindex="5" /></div>
              </div><!-- #form-section-url .form-section -->
<?php endif /* if ( $user_ID ) */ ?>
              <div id="form-section-comment" class="form-section">
                                <div class="form-label"><label for="comment"><?php _e('Comment', 'your-theme') ?></label></div>
                                <div class="form-textarea"><textarea id="comment" name="comment" cols="45" rows="8" tabindex="6"></textarea></div>
              </div><!-- #form-section-comment .form-section -->
              <div id="form-allowed-tags" class="form-section">
                  <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>
              </div>
<?php do_action('comment_form', $post->ID); ?>
                            <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>
<?php comment_id_fields(); ?> 
<?php /* Just … end everything. We're done here. Close it up. */ ?> 
                        </form><!-- #commentform -->
                    </div><!-- .formcontainer -->
<?php endif /* if ( get_option('comment_registration') && !$user_ID ) */ ?>
                </div><!-- #respond -->
<?php endif /* if ( 'open' == $post->comment_status ) */ ?>
            </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.