Skip to main content
WordPress made easy with the drag & drop Total WordPress Theme!Learn More

How to Create a Custom Comments Callback in WordPress

Last updated on:

The WordPress comments template (callback) is not only one of the more complicated steps when creating a custom WordPress theme, but the default comments code is also quite complicated to customize. If you are a theme developer and have gotten stuck trying to customize your comments to make them look the way you want, but can’t because you need to add extra div classes or have to remove some, then you need to check out this post. I will show you how to easily create a custom call-back template that WordPress will use for your comment structure so you can have complete control over your comment design.

A note to developers.. When building a WordPress theme for the WordPress.org directory or for redistribution on any other marketplace it’s best to leave the default comment design to make sure there aren’t any possible conflicts with 3rd party plugins. This tutorial is intended primarily for those looking for a custom solution on their active site (by making the modification via a child theme) or for those developing a custom design for their client.

Now on to the actual tutorial and if you have any questions or suggestions on how we can improve the guide please let me know in the comments section below the guide.

Step 1: Create better-comments.php

Make a new php file to your parent or child theme (you can call it anything, but I like to call it better-comments.php) and paste the code below.

<?php
// My custom comments output html
function better_comments( $comment, $args, $depth ) {

	// Get correct tag used for the comments
	if ( 'div' === $args['style'] ) {
		$tag       = 'div';
		$add_below = 'comment';
	} else {
		$tag       = 'li';
		$add_below = 'div-comment';
	} ?>

	<<?php echo $tag; ?> <?php comment_class( empty( $args['has_children'] ) ? '' : 'parent' ); ?> id="comment-<?php comment_ID() ?>">

	<?php
	// Switch between different comment types
	switch ( $comment->comment_type ) :
		case 'pingback' :
		case 'trackback' : ?>
		<div class="pingback-entry"><span class="pingback-heading"><?php esc_html_e( 'Pingback:', 'textdomain' ); ?></span> <?php comment_author_link(); ?></div>
	<?php
		break;
		default :

		if ( 'div' != $args['style'] ) { ?>
			<div id="div-comment-<?php comment_ID() ?>" class="comment-body">
		<?php } ?>
			<div class="comment-author vcard">
				<?php
				// Display avatar unless size is set to 0
				if ( $args['avatar_size'] != 0 ) {
					$avatar_size = ! empty( $args['avatar_size'] ) ? $args['avatar_size'] : 70; // set default avatar size
						echo get_avatar( $comment, $avatar_size );
				}
				// Display author name
				printf( __( '<cite class="fn">%s</cite> <span class="says">says:</span>', 'textdomain' ), get_comment_author_link() ); ?>
			</div><!-- .comment-author -->
			<div class="comment-details">
				<div class="comment-meta commentmetadata">
					<a href="<?php echo htmlspecialchars( get_comment_link( $comment->comment_ID ) ); ?>"><?php
						/* translators: 1: date, 2: time */
						printf(
							__( '%1$s at %2$s', 'textdomain' ),
							get_comment_date(),
							get_comment_time()
						); ?>
					</a><?php
					edit_comment_link( __( '(Edit)', 'textdomain' ), '  ', '' ); ?>
				</div><!-- .comment-meta -->
				<div class="comment-text"><?php comment_text(); ?></div><!-- .comment-text -->
				<?php
				// Display comment moderation text
				if ( $comment->comment_approved == '0' ) { ?>
					<em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'textdomain' ); ?></em><br/><?php
				} ?>
				<div class="reply"><?php
				// Display comment reply link
				comment_reply_link( array_merge( $args, array(
					'add_below' => $add_below,
					'depth'     => $depth,
					'max_depth' => $args['max_depth']
				) ) ); ?>
				</div>
			</div><!-- .comment-details -->
	<?php
		if ( 'div' != $args['style'] ) { ?>
			</div>
		<?php }
	// IMPORTANT: Note that we do NOT close the opening tag, WordPress does this for us
		break;
	endswitch; // End comment_type check.
}

This is a starter template for you to work with, which includes the basic output you’ll want for your comments with some extra divs included for easier styling.

Step 2: Include your new better-comments.php Template

Place the newly created file inside your parent or child theme then go to your functions.php file and use the require_once function to load your file. See the example below (make sure to change the location if you’ve added the better-comments.php file to a different subfolder in your theme – I usually put my custom functions in a functions or inc folder to keep it seperate from the core template files).

Note: The snippet below has 2 examples you’ll want to use the correct line of code depending if you are adding the template into a parent or child theme.

// Include better comments file from a Parent theme
require_once get_parent_theme_file_path( '/functions/better-comments.php' );

// Or include via a child theme
require_once get_stylesheet_directory() . '/functions/better-comments.php';

You can add the code wherever you want in your functions.php file, just make sure to add it within the <?php and ?> tags.

Step 3: Add Better Comments Callback To wp_list_comments

Now we just need to tell WordPress to use our custom output template for the comments. And there are two ways to do this depending on if you are working with a parent or altering the default parent theme function (aka a child theme or plugin).

Parent theme: If you are working with a parent theme you’ll want to locate the comments.php file and you will want to edit the wp_list_comments function to include the callback in the arguments array like such:

<?php
// Display comments
wp_list_comments( array(
    'callback' => 'better_comments'
) ); ?>

Child theme or plugin: If you are working with a child theme or a plugin and want to filter the comment html output than you want to use the wp_list_comments_args filter and pass on your new callback argument like such:

// Filter the comment list arguments
add_filter( 'wp_list_comments_args', function( $args ) {
    $args[ 'callback' ] = 'better_comments';
	return $args;
} );

And of course, in both cases we are referencing the function name we used in step 1 (better_comments).

Step 4: Tweaking The Custom HTML Output

If you did everything correctly WordPress will now use your better_comments function for the comment html output in your theme. As opposed to just using the wp_list_comments function you can now edit all the code that will show up with each comment. Now the “sky is the limit”. Edit your function to make WordPress comments look the way YOU want. Below are some examples of the awesome stuff you can do:

Display Pingbacks & Regular Comments Differently

If you look at the code you can see it has a switch statement which is used to display the pingbacks/trackbacks differently than standard comments. While we normally recommend disabling the pingbacks/trackbacks if you use them on your site or you want them to look good for your end product (if you are a theme developer) then you can use this method to completely alter the output depending on the comment type.

Display a comment user “badge”

If you are running a community style blog where your readers are logged in you could insert a “badge” for each comment that shows the “role” of the person whom left the comment. So you could display a badge for subscriber, contributor, author, administrator…etc.

global $wp_roles;
if ( $wp_roles ) {
	$user_id = $comment->user_id;
	if ( $user_id && $user = new WP_User( $user_id ) ) {
		if ( isset( $user->roles[0] ) ) { ?>
			<div class="comment-user-badge <?php echo esc_attr( $user->roles[0] ); ?>"><?php esc_html( translate_user_role( $wp_roles->roles[ $user->roles[0] ]['name'] ) ); ?></div>'
		<?php }
	} else { ?>
		<div class="comment-user-badge guest"><?php esc_html_e( 'Guest', 'textdomain' ); ?></div>
	<?php }
}

Change Gravatar Size

Another cool thing you can do with the better comments is change the avatar size, we’ll sure, you could have changed it via the wp_list_comments array manually or using the wp_list_comments_args filter but now you can also manually change it, this means you could even use different sizes depending on the comment (maybe you want the author avatar to be larger, that could cool).

Change Default Gravatar or Remove It Completely

You could modify the get_avatar function to add a 3rd parameter for a default gravatar if you want to manually set the URL of your default avatar icon. This means you could add a fun default avatar that matches your website. Alternatively, you could remove the avatar code completely if you rather not use them (this can be a good idea for sites with tons of comments as gravatars can load a bit slow and also bloat up the site).

<?php echo get_avatar( $comment, $avatar_size, 'URL TO CUSTOM DEFAULT AVATAR' ); ?>

Bonus: Highlight Author Comments

Technically this has nothing to do with your custom comment output, but it’s worth a mention since many themes don’t integrate this by default. In the comment_class output if the comment was made by the author of the post the comment will include the bypostauthor classname and this allows you to style your post author comments ddifferently than the other comments so you can make them stand out.

.bypostauthor {background: #ffff99;}
Subscribe to the Newsletter

Get our latest news, tutorials, guides, tips & deals delivered to your inbox.

17 Comments

  1. tommerhaugland

    Hey nice tut. Thanks.

  2. StanleyTips

    Thank you for this tutorial. You are a genius

    • JumpsTv (@JumpsTv)

      Thank you

    • Chandu

      Thank you for this tutorial. You are a genius

  3. Hooman Moeen

    Great tutorial, Thanks.

  4. Davide

    I took a loooot of time to find how to customize comments. This guide is simple but perfect!

  5. Nigel

    Thanks!

    But does this needs to be updated? Will new WordPress updates break it?

    • AJ Clarke

      I am going to update the post right now because the code isn’t rendering nicely. In terms of WordPress you really shouldn’t have to worry much, I don’t believe WordPress would really ever edit the way comments work drastically. Of course I personally do not recommend using this sort of thing anymore. It’s best to use the native comments_list function instead which has many filters you can use to tweak things. Only use this function if you need truly custom comments display.

  6. Hatta

    thanks for the tutorial but it will be more better if u include image of process (the output of the code)

    • Kyla

      Great idea and I’ll make a note for the next time we update this article 🙂

  7. Will

    Are you sure this method works still?
    It brought down my entire site – Error 500.

    • AJ Clarke

      Yes, the code is correct. Most likely the 500 error was caused by an unclosed or double open PHP tag from when you copied the code over to your site. You should never see a 500 error on your server during development. Make sure you’ve enabled WP_Debug so that you can see actual error warnings on your site and know what’s wrong.

  8. Selmane

    Thank You very much for your article. It was just what i was looking for, you saved me a lot of headaches.

  9. shifu

    This is exactly what I was looking for! Thank you so much!

  10. Kingmaico

    Thank you so much for this tutorial!

  11. Tien Dung

    Hello, Not working for me, display is ok but comment content not correct with post ID, Please help me!

  12. Oana Filip

    Hi! I’d love if you could take a look at our article about how we designed a better system to kick-off conversations in WordPress. I think it’s time to switch from comments to conversations to make the most out of a dialogue. I would love to hear your thoughts on this one?

Leave a Reply

Your email address will not be published.

Learn how your comment data is processed by viewing our privacy policy here.