Change HTML Produced by wp_list_comments()

I am developing a WordPress theme for which I would like each comment’s timestamp wrapped in in a <span> element for the sake of styling it with CSS rules. However, the wp_list_comments() function as I use it in my theme’s comments.php template does not seem to provide options to alter the HTML produced:

<ol class="comment-list">
    <?php
        wp_list_comments( array(
            'style'       => 'ol',
            'format'      => 'html5',
            'short_ping'  => true,
        ) );
    ?>
</ol>

which produces timestamps as such:

<time datetime="2015-12-21T19:09:49+00:00"> december 21st,  2015 on 19:09 </time>

How can I alter the function’s output to include a <span>element around each <time> element without altering core files?

I’ve tried looking at my theme’s functions.php, as well as WordPress wp-includes/comment.php and wp-includes/comment-template.php. None of them deal with the actual tag structure of the comment timestamps generated by wp_list_comments(), so there was nothing there for me to play with.

Solutions Collecting From Web of "Change HTML Produced by wp_list_comments()"

Here are some options on how we can override the native layout for each comment:

Approach #1 – Overriding start_el() with a custom walker

Let’s define our custom wpse comment format:

// Arguments for wp_list_comments() 
$args = [
    'style'       => 'ol',
    'format'      => 'html5',
    'short_ping'  => true,
];

// Use our custom walker if it's available
if( class_exists( 'WPSE_Walker_Comment' ) )
{
    $args['format'] = 'wpse';
    $args['walker'] = new WPSE_Walker_Comment;
}

wp_list_comments( $args );

with a custom comment walker, that handles this new format (PHP 5.4+):

/**
 * Custom comment walker
 *
 * @users Walker_Comment
 */
class WPSE_Walker_Comment extends Walker_Comment
{
    public function start_el( &$output, $comment, $depth = 0, $args = array(), $id = 0 )
    {
       // Our custom 'wpse' comment format
       if ( 'wpse' === $args['format'] )
       {
           $depth++;
           $GLOBALS['comment_depth'] = $depth;
           $GLOBALS['comment'] = $comment;

           // Start output buffering
           ob_start();

           // Let's use the native html5 comment template
           $this->html5_comment( $comment, $depth, $args );

           // Our modifications (wrap <time> with <span>)
           $output .= str_replace( 
               [ '<time ', '</time>' ], 
               ['<span><time ', '</time></span>' ], 
               ob_get_clean() 
           );
       }
       else
       {
           // Fallback for the native comment formats
           parent::start_el( $output, $comment, $depth, $args, $id );
       }    
    }
} // end class

Note how we handle our custom comment format. We also reuse the start_el() method from the parent class for the native formats, by calling parent::start_el().

Also note that we use the output buffering in a similar way as the parent class.

Approach #2 – Overriding html5_comment() with a custom walker

We can also directly override the native Walker_Comment::html5_comment() method, in the following way:

// Arguments for wp_list_comments() 
$args = [
    'style'       => 'ol',
    'format'      => 'html5',
    'short_ping'  => true,
];

// Use our custom walker if it's available
if( class_exists( 'WPSE_Walker_Comment' ) )
{
    $args['walker'] = new WPSE_Walker_Comment;
}

wp_list_comments( $args );

where our custom walker class is defined as:

/**
 * Custom comment walker
 *
 * @users Walker_Comment
 */
class WPSE_Walker_Comment extends Walker_Comment
{
    public function html5_comment( $comment, $depth, $args )
    {
        // Place the modifications of the Walker_Comment::html5_comment() method here
    }
} // end class

Here we can store our modifications to the Walker_Comment::html5_comment() method. It’s rather long, so I didn’t add it here.

Approach #3 – Custom callback

Here we would use the callback attribute:

// Arguments for wp_list_comments() 
$args = [
    'style'       => 'ol',
    'format'      => 'html5',
    'short_ping'  => true,
];

// Use our custom callback if it's available
if( function_exists( 'wpse_comment_callback' ) )
{
    $args['format'] = 'wpse';
    $args['callback'] = 'wpse_comment_callback';
}

wp_list_comments( $args );

where we define the wpse_comment_callback() to our needs.

/**
 * Custom comment callback
 */
function wpse_comment_callback( $comment, $depth, $args )
{
    // Modify the Walker_Comment::html5_comment() method to our needs 
    // and place it here
}

where we could start by simulating the Walker_Comment::html5_comment() method. But we must remember to replace all reference to $this.

There are other approaches avilable, but hopefully you can adjust these to your needs.