Advanced WordPress Comment Styles

Comments are gold. There’s little a blogger loves more than to see a whole list of comments posted on his/her article. It’s great to know people want to engage with you, and they can add a lot to an article.

However, if comments are not done well, they can be difficult to read and follow, or even just downright boring.

What we’re going to do first is create a custom comment callback that allows us to specify the way the comments are output, then lay out the structure for the comment list and reply form, add extra functionality such as author-only styles, implement comment subscription options and spam protection, and, finally, we’ll add nice CSS styling to everything we’ve done.

We will be working with the default WordPress theme in order to make everything easy to follow, and to ensure everyone can follow along. We will also be ignoring all styling elements until the very end, so if it looks bad, just be patient!

An important note to remember is that anytime I refer to line numbers, I’m referring to the line numbers of the code I posted, not the line numbers in your files.

1 – Create Custom Comment Callback

The comment callback is just a way of telling WordPress what HTML to spit out for your comments.

Rather than trying to modify the default theme’s existing comment callback, we’re going to create our own, by adding this to functions.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php //this function will be called in the next section
function advanced_comment($comment, $args, $depth) {
   $GLOBALS['comment'] = $comment; ?>
 
<li <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>">
   <div class="comment-author vcard">
     <?php echo get_avatar($comment,$size='48',$default='<path_to_url>' ); ?>
       <div class="comment-meta"<a href="<?php the_author_meta( 'user_url'); ?>"><?php printf(__('%s'), get_comment_author_link()) ?></a></div>
       <small><?php printf(__('%1$s at %2$s'), get_comment_date(),  get_comment_time()) ?><?php edit_comment_link(__('(Edit)'),'  ','') ?></small>
     </div>
     <div class="clear"></div>
 
     <?php if ($comment->comment_approved == '0') : ?>
       <em><?php _e('Your comment is awaiting moderation.') ?></em>
       <br />
     <?php endif; ?>
 
     <div class="comment-text">	
         <?php comment_text() ?>
     </div>
 
   <div class="reply">
      <?php comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?>
   </div>
   <div class="clear"></div>
<?php } ?>

What this code does is specify exactly how we want each, individual comment to be displayed. This allows us to define custom class/id settings for each element as well, rather than being bound to the default theme’s settings.

2 – Lay Out Your Template File

The code in the previous section created the structure for individual comments, now we need to lay out the structure for the actual comments page, on which all of the comments will be displayed (Including the comment form).

If your comments.php has anything in it already, replace it with the code below. I have included comments throughout the code to explain a few important details.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<?php
/**
 * @package WordPress
 * @subpackage Default_Theme
 */
 
// Do not delete these lines
	if (!empty($_SERVER['SCRIPT_FILENAME']) && 'comments.php' == basename($_SERVER['SCRIPT_FILENAME']))
		die ('Please do not load this page directly. Thanks!');
 
	if ( post_password_required() ) { ?>
		<p class="nocomments">This post is password protected. Enter the password to view comments.</p>
	<?php
		return;
	}
?>
 
<!-- You can start editing here. -->
 
<?php if ( have_comments() ) : ?>
	<h3 id="comments"><?php comments_number('No Responses', 'One Response', '% Responses' );?> to &#8220;<?php the_title(); ?>&#8221;</h3>
 
	<ol class="commentlist">
		<?php wp_list_comments('type=comment&callback=advanced_comment'); //this is the important part that ensures we call our custom comment layout defined above 
                ?>
	</ol>
	<div class="clear"></div>
	<div class="comment-navigation">
		<div class="older"><?php previous_comments_link() ?></div>
		<div class="newer"><?php next_comments_link() ?></div>
	</div>
 <?php else : // this is displayed if there are no comments so far ?>
 
	<?php if ( comments_open() ) : ?>
		<!-- 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; ?>
 
 
<?php if ( comments_open() ) : ?>
 
<div id="respond">
 
<h3><?php comment_form_title( 'Leave a Reply', 'Leave a Reply to %s' ); ?></h3>
 
<div class="cancel-comment-reply">
	<small><?php cancel_comment_reply_link(); ?></small>
</div>
 
<?php if ( get_option('comment_registration') && !is_user_logged_in() ) : ?>
<p>You must be <a href="<?php echo wp_login_url( get_permalink() ); ?>">logged in</a> to post a comment.</p>
<?php else : ?>
 
<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">
 
<?php if ( is_user_logged_in() ) : ?>
 
<p>Logged in as <a href="<?php echo get_option('siteurl'); ?>/wp-admin/profile.php"><?php echo $user_identity; ?></a>. <a href="<?php echo wp_logout_url(get_permalink()); ?>" title="Log out of this account">Log out &raquo;</a></p>
 
<?php else : //this is where we setup the comment input forums ?>
 
<p><input type="text" name="author" id="author" value="<?php echo esc_attr($comment_author); ?>" size="22" tabindex="1" <?php if ($req) echo "aria-required='true'"; ?> />
<label for="author"><small>Name <?php if ($req) echo "(required)"; ?></small></label></p>
 
<p><input type="text" name="email" id="email" value="<?php echo esc_attr($comment_author_email); ?>" size="22" tabindex="2" <?php if ($req) echo "aria-required='true'"; ?> />
<label for="email"><small>Mail (will not be published) <?php if ($req) echo "(required)"; ?></small></label></p>
 
<p><input type="text" name="url" id="url" value="<?php echo esc_attr($comment_author_url); ?>" size="22" tabindex="3" />
<label for="url"><small>Website</small></label></p>
 
<?php endif; ?>
 
<!--<p><small><strong>XHTML:</strong> You can use these tags: <code><?php echo allowed_tags(); ?></code></small></p>-->
 
<p><textarea name="comment" id="comment" cols="100%" rows="10" tabindex="4"></textarea></p>
 
<p><input name="submit" type="submit" id="submit" tabindex="5" value="Post" />
<?php comment_id_fields(); ?>
</p>
<?php do_action('comment_form', $post->ID); ?>
 
</form>
 
<?php endif; // If registration required and not logged in ?>
</div>
 
<?php endif; // if you delete this the sky will fall on your head ?>

If you need help understanding the purpose of anything in comments.php, check out the article on Net Tuts about unraveling comments.php.

3 – Enable Nested Comments

People have mixed feelings about threaded comments, but they can be quite useful in organizing the discussion flow. This step is entirely optional and won’t break anything if you choose not to enable nested comments.

Assuming you do wish to enable them, you need to go to your WordPress Dashboard and click on Settings > Discussion > Enable threaded (nested) comments # levels deep (i.e. how many times can you reply to a reply).

4 – Make the Author Stand Out

Particularly useful for people who write tutorials and need to answer questions from their readers, this bit of code will make any comment left by the author of the article stand out from the community’s comments.

Newer WordPress versions make this very easy. They will automatically add certain CSS classes to comments (Assuming that you used the <php comment_class(); ?> tag that we mentioned in step 1).

To style the comments, just add CSS rules for the following classes:

  • byuser - For comments left by any registered user on the site.
  • bypostauthor – For comments left by the author of the current post (Very useful for styling comments by guest authors on their own posts, but not on any other posts)
  • comment-author-name – Where “name” is the user’s name. This can be good for styling comments from an individual user, e.g. comment-author-admin

For an older method of doing this manually (Allowing you to style comments based on specific emails being used), check out this post.

5 – Disable Comments on Old Posts

This can be done through the WordPress settings, under Discussion, but in case you’d like to do this automatically from within the theme, place this code in your functions.php:

1
2
3
4
5
6
7
8
9
10
11
<?php 
function close_comments( $posts ) {
	if ( !is_single() ) { return $posts; }
	if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( 30 * 24 * 60 * 60 ) ) {
		$posts[0]->comment_status = 'closed';
		$posts[0]->ping_status    = 'closed';
	}
	return $posts;
}
add_filter( 'the_posts', 'close_comments' ); 
?>

This snippet was originally posted by Jeff Star at Perishable Press.

The important part is the “30 * 24 * 60 * 60.” That means 60 seconds, time 60 minutes, times 24 hours, times 30 days. So if you wanted to make it happen after 3 months, you could change the first 30 to a 90.

This could be useful for theme developers who would like to make “Commenting on Old Posts Disabled” a feature of their theme.

6 – Subscribe to Comments

Often times a reader will ask a support question via post comments. Receiving an email whenever another comment is posted is a much easier way for that reader to know an answer has been posted than manually checking every now and then (if they even remember to do that).

Subscribe to Comments by Mark Jaquith is a great plugin that adds a link to subscribe to further comments just below the message box of the comments page. It also includes a subscription manager that is placed under Tools in your WordPress Dashboard, allowing users to unsubscribe from posts at any time.

We will style this button in the last section.

7 – Add Extra Moderation Links

Even with anti-spam protection, you will occasionally have comments that you need to mark as spam or delete entirely, so lets add links that allow us to do so. This will allow us to moderate comments from the website itself, not just the dashboard.

First add this to your functions.php

1
2
3
4
5
6
7
<?php function delete_comment_link($id) {
  if (current_user_can('edit_post')) {
    echo '<a href="'.admin_url("comment.php?action=cdc&c=$id").'">del</a> ';
    echo '<a href="'.admin_url("comment.php?action=cdc&dt=spam&c=$id").'">spam</a>';
  }
}
?>

Next, put this code in functions.php after line 24 of the custom callback function we created in section 1.

1
 <?php delete_comment_link(get_comment_ID()); ?>

like so:

1
2
3
4
<div class="reply">
  <?php comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?>
  <?php delete_comment_link(get_comment_ID()); ?>
</div>

Your outcome should look something like this:

extra mod links

Thanks goes to Joost de Valk for this great snippet.

8 – Add an Extra Layer of Spam Protection

Spammers are always a problem, even though there are a whole slew of plugins to protect against them. This piece of code will add an extra barrier that they have to break through. Essentially what it does is block any comment that does not have a referrer (i.e. where the user came from previously) in the posting request, which is usually indicative of bots.

Paste this into your functions.php

1
2
3
4
5
6
7
8
<?php function check_referrer() {
    if (!isset($_SERVER['HTTP_REFERER']) || $_SERVER['HTTP_REFERER'] == “”) {
        wp_die( __('Please enable referrers in your browser, or, if you\'re a spammer, get out of here!') );
    }
}
 
add_action('check_comment_flood', 'check_referrer');
 ?>

This snipped was also from From Joost de Valk. There is a chance you could block some legitimate users though, but if spam is becoming a major issue, it’s worth considering.

9 – Add Comment Feed Link

To display a link to your comments RSS feed, paste this somewhere in your comments.php file:

1
<?php comments_rss_link('Subscribe to Comments via RSS'); ?>

One of the best places would be immediately after the comment input forums.

1
2
3
4
5
6
7
8
9
10
<p><textarea name="comment" id="comment" cols="100%" rows="10" tabindex="4"></textarea></p>
<small>Allowed tags: <?php echo allowed_tags(); ?></small> 
<p><input name="submit" type="submit" id="submit" tabindex="5" value="Post" />
<?php comment_id_fields(); ?>
</p>
<?php do_action('comment_form', $post->ID); ?>
 
</form>
 
<div class="comment-rss"><?php comments_rss_link('Subscribe to Comments via RSS'); ?></div>

10 – Display Allowed Tags

Bold text can really help people’s points stand out in their comments, just as italics can be great for things like addresses and error messages (404: Not Found). Letting your readers know they are allowed to use certain HTML tags in their messages can be a real help.

Paste this:

1
Allowed tags: <?php echo allowed_tags(); ?>

in your comments.php. I have put it just above the textarea and placed “small” tags around it.

1
2
3
<p><textarea name="comment" id="comment" cols="100%" rows="10" tabindex="4"></textarea></p>
   <small>Allowed tags: <?php echo allowed_tags(); ?></small> 
<p><input name="submit" type="submit" id="submit" tabindex="5" value="Post" />

It should come out looking something like this:

allowed tags

This snippet comes from Net Tuts.

11 – Show Total Number of Comments

If you’d like to display the total number of comments posted sitewide, put this snippet anywhere in your theme’s template files, such as header.php

1
2
<?php $numcomms = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_approved = '1'"); 
  if (0 < $numcomms) $numcomms = number_format($numcomms); echo "There's <span>".$numcomms."</span> total comments on "; bloginfo('name'); ?>

It will be displayed as something like There’s 1534 total comments on your website name. The “span” tags around “.$numcomms.” are there so we can emphasize the number of comments with CSS later. I have also wrapped the code in div tags like so:

1
2
3
4
<div class="comment-total">
   <?php $numcomms = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_approved = '1'"); 
       if (0 < $numcomms) $numcomms = number_format($numcomms); echo "There's <span>".$numcomms."</span> total comments on "; bloginfo('name');?>
</div>

This snippet comes from Hiroshi at PHP Magic Book

12 – Add Some CSS

After everything we have done, your result should look pretty similar to the default theme here.

Obviously this is no good, so we want to get a little happy with the CSS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/****************
advanced comment styles
****************/
 
h3#comments,.comment-navigation,.comment-navigation:after,#respond:after,.comment-rss{display:block} 
ol.commentlist{width:100%} 
h3#comments,#respond h3{height:25px;text-align:left;background:#4c7faa;color:#fff;padding:5px 0 0 5px} 
ol.commentlist,li.authorcomment,li.comment,#respond h3,form#commentform,input#submit{margin:0}
ol.commentlist,ol.commentlist ul,form#commentform{padding:0}  
ol.commentlist{border-bottom:1px solid #ccc} 
ol.commentlist ul{margin:0 0 0 20px} 
li.authorcomment,li.comment,form#commentform textarea,form#commentform input{border:1px solid #ccc}
li.authorcomment,li.comment{padding:10px 0 0 10px;list-style:none;border-bottom:none} 
li.even{background:#fff} 
li.odd{background:#efefef} 
.authorcomment{background:#deebf9} 
ul.children ul{margin-left:20px} 
ul.children li{border-right:none} 
.vcard img{float:left;background:#c4c4c4} 
.vcard img,.comment-navigation .newer a,.comment-navigation .older a{padding:5px} 
.comment-meta,ol.commentlist li small,p.subscribe-to-comments label{position:relative} 
.comment-meta,ol.commentlist li small{top:10px;left:10px} 
.comment-text{margin:0 10px 0 0} 
.reply,.comment-navigation .newer,input#submit{float:right} 
.reply,.comment-navigation .newer a,.comment-navigation .older a,input#submit{background:#4c7faa} 
.reply{margin:0 10px 10px 0} 
a.comment-reply-link,.reply a:link,
.comment-navigation .newer a,.comment-navigation .older a,input#submit{display:inline-block;text-align:center;cursor:pointer;color:#fff} 
a.comment-reply-link,.reply a:link{padding:5px 0} a.comment-reply-link,.reply a:link,input#submit{width:70px} 
a.comment-reply-link:hover,.reply a:hover,.comment-navigation .newer a:hover,
.comment-navigation .older a:hover,input#submit:hover{background:#e7e7e7;text-decoration:none;color:#4c7faa;font-weight:bold} 
a.comment-reply-link:hover,.reply a:hover,input#submit:hover{width:68px} 
a.comment-reply-link:hover,.reply a:hover{padding:4px 0} 
a.comment-reply-link:hover,.reply a:hover,.comment-navigation .newer a:hover,.comment-navigation .older a:hover{border:1px solid #4c7faa} 
.comment-navigation{margin:10px 0 10px 0} .comment-navigation:after,#respond:after{content:".";height:0;visibility:hidden} 
.clear{clear:both} 
.comment-navigation .newer a:hover,.comment-navigation .older a:hover{padding:4px} 
form#commentform textarea,form#commentform input{padding:2px 3px} 
form#commentform textarea{width:442px} 
input#submit{padding:5px 0 !important;border:0 !important} 
input#submit,p.subscribe-to-comments input{outline:0} 
input#submit:hover{padding:4px 0 !important;border:1px solid #4c7faa !important} 
p.subscribe-to-comments{background:url('images/email_32.png') no-repeat} 
p.subscribe-to-comments,.comment-rss{height:32px;text-indent:42px;padding:5px 0 0 0} 
p.subscribe-to-comments input{margin:5px 3px 3px 3px !important;border:0} 
p.subscribe-to-comments label{top:-2px;color:#666} 
.comment-rss{background:url('images/rss_32.png') no-repeat} 
 
/*comment total stlying*/
 
.comment-total{text-align: center;font-size: 1.5em;color: #fff;}
.comment-total span{font-size: 2em;color: #800000;}

You can see my finished modification of the default theme comments page here.

Because there are a few things only visible to the site admin, here’s a screenshot of the logged-in admin view:

admin view of finished default theme mod

The CSS above is written such that this could all be incorporated into almost any, if not all, themes without more than a few small modifications, so don’t feel like you’re stuck with the default theme!

To make it easier on you, feel free to download all the files for my modified default theme here.

13 – Going Further

We’ve covered a lot of ground here, but if you’d like to go even further with your site’s comments, here are some links for further reading:

Enjoy this post? You should follow me on Twitter!