[WordPress] Get your own markup for nested comments

This blog uses a modified Hemingway Reloaded theme but the theme is old and does not support nested comments and uses a customized way to display list of comments under a post instead of standard wp_list_comments(). Hence, when we decided to display nested comments, I needed to tweak comments.php in the theme for that and to use comment post form for reply too. Below is the experience of tweaking which I am sharing with you.

The wp_list_comments() function uses Walker_Comment class which extends Walker. The walker class has four abstract methods and we need to define them while extending the class. So I decided to extend Walker_Comment itself and override the four abstract methods.

As a first step the all code

CODE:
  1. foreach ... endforeach

in <ol id="comments">...</ol> was replaced with

PHP:
  1. wp_list_comments(array('walker' => new Walker_Sanisoft_Comment));

As you can see there is the custom walker class called Walker_Sanisoft_comment which is passed to wp_list_comments(). Following is the basic stub I used for Walker_Sanisoft_Comment class which I got by reading through the code of Walker_Comment class

PHP:
  1. class Walker_Sanisoft_Comment extends Walker_Comment
  2. {
  3.     function start_lvl(&$output, $depth, $args)
  4.     {
  5.         $GLOBALS['comment_depth'] = $depth + 1;
  6.     }
  7.  
  8.     function end_lvl(&$output, $depth, $args)
  9.     {
  10.         $GLOBALS['comment_depth'] = $depth + 1;
  11.     }
  12.  
  13.     function start_el(&$output, $comment, $depth, $args)
  14.     {
  15.         $depth++;
  16.  
  17.         $GLOBALS['comment_depth'] = $depth;
  18.  
  19.         if (!empty($args['callback']))
  20.         {
  21.             call_user_func($args['callback'], $comment, $args, $depth);
  22.  
  23.             return;
  24.         }
  25.  
  26.         $GLOBALS['comment'] = $comment;
  27.  
  28.         extract($args, EXTR_SKIP);
  29.     }
  30.  
  31.     function end_el(&$output, $comment, $depth, $args)
  32.     {
  33.     }
  34. }

After putting in the comments listing markup, code and adding 'reply' link etc in the new walker class, finally it looked like

PHP:
  1. class Walker_Sanisoft_Comment extends Walker_Comment
  2. {
  3.     var $currentLevel = null;
  4.  
  5.     function start_lvl(&$output, $depth, $args)
  6.     {
  7.         $GLOBALS['comment_depth'] = $depth + 1;
  8. ?>
  9.   <li>
  10.     <cite>&nbsp;</cite>
  11.     <div class="content" style="height: 2em;">&nbsp;</div>
  12.   </li>
  13. <?php
  14.     }
  15.  
  16.     function end_lvl(&$output, $depth, $args)
  17.     {
  18.         $GLOBALS['comment_depth'] = $depth + 1;
  19.     }
  20.  
  21.     function start_el(&$output, $comment, $depth, $args)
  22.     {
  23.         $depth++;
  24.  
  25.         $GLOBALS['comment_depth'] = $depth;
  26.  
  27.         if (!empty($args['callback']))
  28.         {
  29.             call_user_func($args['callback'], $comment, $args, $depth);
  30.  
  31.             return;
  32.         }
  33.  
  34.         $GLOBALS['comment'] = $comment;
  35.  
  36.         extract($args, EXTR_SKIP);
  37.  
  38.         if (!isset($this->currentLevel))
  39.         {
  40.             $this->currentLevel = $depth;
  41.         }
  42.         else
  43.         {
  44.             if (0 <$comment->comment_parent && 1 <$this->currentLevel && $this->currentLevel>= $depth)
  45.             {
  46. ?>
  47.   <li>
  48.     <cite>&nbsp;</cite>
  49.     <div class="content" style="height: 2em;">&nbsp;</div>
  50.   </li>
  51. <?php
  52.             }
  53.  
  54.             $this->currentLevel = $depth;
  55.         }
  56. ?>
  57.   <li id="comment-<?php comment_ID(); ?>">
  58. <?php
  59.         if (0>= $comment->comment_parent)
  60.         {
  61. ?>
  62.     <div class="clear" style="height: 25px;"></div>
  63. <?php
  64.         }
  65. ?>
  66.     <cite>
  67.       <span class="gravatar" style="float: right; padding: 3px;"><?php echo get_avatar($comment, 40); ?></span>
  68.       <span class="author"><?php comment_author_link(); ?></span>
  69.       <span class="date"><?php comment_date('n.j.y'); ?> / <?php comment_date('g:ia'); ?></span>
  70.     </cite>
  71.     <div class="content" id="div-comment-<?php comment_ID() ?>" style="min-height: 46px;">
  72.       <div style="padding-left: <?php echo (2 * ($depth - 1)); ?>%">
  73.         <?php if ($comment->comment_approved == '0') : ?>
  74.         <em>Your comment is awaiting moderation.</em>
  75.         <?php endif; ?>
  76.         <?php comment_text(); ?>
  77.         <?php comment_reply_link(array_merge($args, array('add_below' => 'div-comment', 'depth' => $depth, 'max_depth' => $args['max_depth'], 'respond_id' => 'comment-form'))); ?>
  78.       </div>
  79.     </div>
  80.     <span id="formHeading_<?php comment_ID(); ?>" style="display: none;">Leave a Reply to <a href="#comment-<?php comment_ID(); ?>"><?php echo get_comment_author(); ?></a></span>
  81. <?php
  82.     }
  83.  
  84.     function end_el(&$output, $comment, $depth, $args)
  85.     {
  86. ?>
  87.   </li>
  88. <?php
  89.     }
  90. }

So you can see if you want to use your own markup in the comments making a Walker class is the thing to do.

Next thing was to update comment post form to use for comment reply too with addition of some javascript. So I added id for form title as 'commentFormTitle', also replaced submit button and hidden field section from

PHP:
  1. <div class="formactions"> <a href="#">Preview your comment</a>
  2.   <input type="submit" name="submit" tabindex="5" class="submit" value="Add your comment" />
  3. </div>
  4. <input type="hidden" name="comment_post_ID" value="<?php echo $id; ?>" />

to

PHP:
  1. <input type="submit" name="submit" tabindex="5" class="submit" value="Add your comment" />
  2. <?php cancel_comment_reply_link('Cancel reply'); ?>
  3. <?php comment_id_fields(); ?>

. The default wp-includes/js/comment-reply.js didn't work for our need. Hence, I copied wp-includes/js/comment-reply.dev.js to the theme and modified it slightly. You can download it from here.

and everything works. Oh! it looks more complicated than it really is. You can try this tweak on any theme which doesn't have nested comments OR if you want to have your own markup and it should work.

Happy tweaking ;)

About Amit Badkas

Amit Badkas is Zend certified PHP5 and Zend Framework engineer, and has been working in SANIsoft for past 9 years, his present designation is 'Technical Manager'
No comments yet.

Leave a Reply