Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialSteffan Carrington
15,782 PointsWordPress User Comments
Hi all,
I was wondering if anyone knows of any good tutorials discussing customising and styling Comments in WordPress? I've had a look at the Codex and found one or two online, but not ones that go into detail...
Thanks in advance,
Steffan
2 Answers
Ryan Duchene
Courses Plus Student 46,022 PointsOooh, yes. I've had a lot of trouble with WordPress comments myself. They're a bit of a pain to get working, but once you figure out how to do it, it'll be easy.
WordPress has a number of different ways to generate comment HTML, but the generally recommended way to go is using the Walker class. Obviously, this requires that you know something about object-oriented PHP.
The Walker class (and its various subclasses) were created for situations like these. They will "walk" through each element, going through of its descendants one by one. They're at their finest when you use them for comments, but they can also work for WordPress menus, as well as a few other things too, I believe.
So, to start, whenever you want to generate comment HTML, use this template tag:
<?php comments_template(); ?>
Now, create the file comments.php
in the root directory of your theme, if you haven't already. What you're going to want to do is create a new class called MyTheme_Comment
and extend the Walker_Comment
class:
<?php
class MyTheme_Comment extends Walker_Comment
{
// more code here later
} // end MyTheme_Comment
Now, inside of that class, you're going to write three pairs of methods (aka functions) and two properties (aka variables). We'll start with the properties:
<?php
class MyTheme_Comment extends Walker_Comment
{
public $tree_type = 'comment';
public $db_fields = array( 'parent' => 'comment_parent', 'id' => 'comment_ID' );
} // end MyTheme_Comment
The $tree_type
property isn't actually used by WordPress itself, but it's provided because some plugins may make use of it. The $db_fields
property will be used, as its name implies, to fetch variables from the database.
Now the real fun comes. So, in HTML, most elements require two tags: an opening tag and a closing tag. Well, in the Walker class, you'll have one function to open an element and another to close it.
<?php
// inside your class
// opens the comments section
function __construct()
{ ?>
<h2>Comments</h2>
<ul id="comments">
<?php }
// closes the comments section
function __destruct()
{ ?>
</ul>
<?php }
WordPress will call the __construct()
function at the start and the __destruct()
function at the end, leaving you with HTML that looks like this:
<h2>Comments</h2>
<ul id="comments">
</ul>
Now, the next pair of functions will open/close the replies to a specific comment.
<?php
// between the __construct and __destruct functions
// opens a comment thread
public function start_lvl( &$output, $depth = 0, $args = array() )
{
$GLOBALS['comment_depth'] = $depth + 1; ?>
<ul class="comment-replies">
<?php }
// closes a comment thread
public function end_lvl( &$output, $depth = 0, $args = array() )
{
$GLOBALS['comment_depth'] = $depth + 1; ?>
</ul>
<?php }
The start_lvl()
function will open up a thread of comment replies, and the end_lvl()
function will close it. The first line of each function sets a global that keeps track of how far down you are in the replies.
The last pair of functions will open and close tags around single comments.
<?php
// after end_lvl()
// opens a single comment
public function start_el( &$output, $comment, $depth, $args = array(), $id = 0 )
{
$depth++;
$GLOBALS['comment_depth'] = $depth;
$GLOBALS['comment'] = $comment;
$parent_class = ( empty( $args['has_children'] ) ? '' : 'parent' ); ?>
<li <?php comment_class( $parent_class ); ?>>
<!-- this is what will appear inside of the comment -->
<?php }
// closes a single comment
public function end_el( &$output, $comment, $depth, $args = array(), $id = 0 )
{ ?>
</li>
<?php }
The start_el()
function will open up a comment, and the end_el()
function will close it. The first few lines of start_el
set a couple globals to help track depth (much like start_lvl()
and end_lvl()
) and to track the current comment the class is generating.
Anything that you put below the li
in the start_el()
function above will be generated inside of the comment. It works like the Loop, so you can use WordPress functions and template tags like comment_ID()
and comment_author()
.
Last of all, you need to hook into this class to generate comments:
<?php
// below the MyTheme_Comment class
wp_list_comments( array( 'walker' => new MyTheme_Comment(), ) );
Now, let's walk through this whole class, step by step. The __construct()
function will be called, generating the heading and the opening tag of the ul
. Next, the start_el()
function will be called to generate the opening HTML for the first comment.
If this comment has any replies, the start_lvl()
function will be called to open a new ul
for this comment's replies. The reply will be opened by the start_el()
function, the same function that opened the parent comment. But this comment doesn't have any replies, so the end_el()
function will be called immediately to close the li
. There aren't any more comments in this thread, so end_lvl()
is called to close the ul
, and then end_el()
is called again to close the original comment.
When all the comments have finished generating, the __destruct()
function is called to close the main ul
element.
That was a lot; I'm worried it might not have been a clear explanation. I'll try to rework it to improve clarity when I can. Also, the finished code for the copypasta:
<?php
// comments.php
class MyTheme_Comment extends Walker_Comment
{
public $tree_type = 'comment';
public $db_fields = array( 'parent' => 'comment_parent', 'id' => 'comment_ID' );
// opens the comments section
function __construct()
{ ?>
<h2>Comments</h2>
<ul id="comments">
<?php }
// opens a comment thread
public function start_lvl( &$output, $depth = 0, $args = array() )
{
$GLOBALS['comment_depth'] = $depth + 1; ?>
<ul class="comment-replies">
<?php }
// closes a comment thread
public function end_lvl( &$output, $depth = 0, $args = array() )
{
$GLOBALS['comment_depth'] = $depth + 1; ?>
</ul>
<?php }
// opens a single comment
public function start_el( &$output, $comment, $depth, $args = array(), $id = 0 )
{
$depth++;
$GLOBALS['comment_depth'] = $depth;
$GLOBALS['comment'] = $comment;
$parent_class = ( empty( $args['has_children'] ) ? '' : 'parent' ); ?>
<li <?php comment_class( $parent_class ); ?>>
<!-- this is what will appear inside of the comment -->
<?php }
// closes a single comment
public function end_el( &$output, $comment, $depth, $args = array(), $id = 0 )
{ ?>
</li>
<?php }
// closes the comments section
function __destruct()
{ ?>
</ul>
<?php }
} // end MyTheme_Comment
wp_list_comments( array( 'walker' => new MyTheme_Comment(), ) );
Hope this helps! Happy coding!
Steffan Carrington
15,782 PointsThanks for the heads up Ryan, much appreciated!
I had my comments.php file set up and has seen a few articles on people using the walker class in their templates, but didn't go in to much detail. But this made things much clearer.
Oliver Williams
6,278 PointsOliver Williams
6,278 PointsIs there anything wrong with just using a callback function with wp_list_comments() ? It seems a lot easier than using the Walker class!
<?php wp_list_comments('callback=my_comment_format'); ?>