wp_list_comments( string|array $args = array(), WP_Comment[] $comments = null ): void|string

Displays a list of comments.

Description

Used in the comments.php template to list comments for a particular post.

See also

  • WP_Query::$comments

Parameters

$argsstring|arrayoptional
Formatting options.
  • walker object
    Instance of a Walker class to list comments. Default null.
  • max_depth int
    The maximum comments depth.
  • style string
    The style of list ordering. Accepts 'ul', 'ol', or 'div'.
    'div' will result in no additional list markup. Default 'ul'.
  • callback callable
    Callback function to use. Default null.
  • end-callback callable
    Callback function to use at the end. Default null.
  • type string
    Type of comments to list. Accepts 'all', 'comment', 'pingback', 'trackback', 'pings'. Default 'all'.
  • page int
    Page ID to list comments for.
  • per_page int
    Number of comments to list per page.
  • avatar_size int
    Height and width dimensions of the avatar size. Default 32.
  • reverse_top_level bool
    Ordering of the listed comments. If true, will display newest comments first. Default null.
  • reverse_children bool
    Whether to reverse child comments in the list. Default null.
  • format string
    How to format the comments list. Accepts 'html5', 'xhtml'.
    Default 'html5' if the theme supports it.
  • short_ping bool
    Whether to output short pings. Default false.
  • echo bool
    Whether to echo the output or return it. Default true.

Default:array()

$commentsWP_Comment[]optional
Array of WP_Comment objects.

Default:null

Return

void|string Void if 'echo' argument is true, or no comments to list.
Otherwise, HTML list of comments.

More Information

Default options for $args

$args = array(
'walker'            => null,
'max_depth'         => '',
'style'             => 'ul',
'callback'          => null,
'end-callback'      => null,
'type'              => 'all',
'page'              => '',
'per_page'          => '',
'avatar_size'       => 32,
'reverse_top_level' => null,
'reverse_children'  => '',
'format'            => 'html5', // or 'xhtml' if no 'HTML5' theme support
'short_ping'        => false,   // @since 3.6
'echo'              => true     // boolean, default is true
);

The ‘max_depth‘, ‘per_page‘, and ‘reverse_top_level‘ parameters can be more easily controlled through the Discussion Settings Administration Panel but a theme can override those settings.

Source

function wp_list_comments( $args = array(), $comments = null ) {
	global $wp_query, $comment_alt, $comment_depth, $comment_thread_alt, $overridden_cpage, $in_comment_loop;

	$in_comment_loop = true;

	$comment_alt        = 0;
	$comment_thread_alt = 0;
	$comment_depth      = 1;

	$defaults = array(
		'walker'            => null,
		'max_depth'         => '',
		'style'             => 'ul',
		'callback'          => null,
		'end-callback'      => null,
		'type'              => 'all',
		'page'              => '',
		'per_page'          => '',
		'avatar_size'       => 32,
		'reverse_top_level' => null,
		'reverse_children'  => '',
		'format'            => current_theme_supports( 'html5', 'comment-list' ) ? 'html5' : 'xhtml',
		'short_ping'        => false,
		'echo'              => true,
	);

	$parsed_args = wp_parse_args( $args, $defaults );

	/**
	 * Filters the arguments used in retrieving the comment list.
	 *
	 * @since 4.0.0
	 *
	 * @see wp_list_comments()
	 *
	 * @param array $parsed_args An array of arguments for displaying comments.
	 */
	$parsed_args = apply_filters( 'wp_list_comments_args', $parsed_args );

	// Figure out what comments we'll be looping through ($_comments).
	if ( null !== $comments ) {
		$comments = (array) $comments;
		if ( empty( $comments ) ) {
			return;
		}
		if ( 'all' !== $parsed_args['type'] ) {
			$comments_by_type = separate_comments( $comments );
			if ( empty( $comments_by_type[ $parsed_args['type'] ] ) ) {
				return;
			}
			$_comments = $comments_by_type[ $parsed_args['type'] ];
		} else {
			$_comments = $comments;
		}
	} else {
		/*
		 * If 'page' or 'per_page' has been passed, and does not match what's in $wp_query,
		 * perform a separate comment query and allow Walker_Comment to paginate.
		 */
		if ( $parsed_args['page'] || $parsed_args['per_page'] ) {
			$current_cpage = get_query_var( 'cpage' );
			if ( ! $current_cpage ) {
				$current_cpage = 'newest' === get_option( 'default_comments_page' ) ? 1 : $wp_query->max_num_comment_pages;
			}

			$current_per_page = get_query_var( 'comments_per_page' );
			if ( $parsed_args['page'] != $current_cpage || $parsed_args['per_page'] != $current_per_page ) {
				$comment_args = array(
					'post_id' => get_the_ID(),
					'orderby' => 'comment_date_gmt',
					'order'   => 'ASC',
					'status'  => 'approve',
				);

				if ( is_user_logged_in() ) {
					$comment_args['include_unapproved'] = array( get_current_user_id() );
				} else {
					$unapproved_email = wp_get_unapproved_comment_author_email();

					if ( $unapproved_email ) {
						$comment_args['include_unapproved'] = array( $unapproved_email );
					}
				}

				$comments = get_comments( $comment_args );

				if ( 'all' !== $parsed_args['type'] ) {
					$comments_by_type = separate_comments( $comments );
					if ( empty( $comments_by_type[ $parsed_args['type'] ] ) ) {
						return;
					}

					$_comments = $comments_by_type[ $parsed_args['type'] ];
				} else {
					$_comments = $comments;
				}
			}

			// Otherwise, fall back on the comments from `$wp_query->comments`.
		} else {
			if ( empty( $wp_query->comments ) ) {
				return;
			}
			if ( 'all' !== $parsed_args['type'] ) {
				if ( empty( $wp_query->comments_by_type ) ) {
					$wp_query->comments_by_type = separate_comments( $wp_query->comments );
				}
				if ( empty( $wp_query->comments_by_type[ $parsed_args['type'] ] ) ) {
					return;
				}
				$_comments = $wp_query->comments_by_type[ $parsed_args['type'] ];
			} else {
				$_comments = $wp_query->comments;
			}

			if ( $wp_query->max_num_comment_pages ) {
				$default_comments_page = get_option( 'default_comments_page' );
				$cpage                 = get_query_var( 'cpage' );
				if ( 'newest' === $default_comments_page ) {
					$parsed_args['cpage'] = $cpage;

					/*
					* When first page shows oldest comments, post permalink is the same as
					* the comment permalink.
					*/
				} elseif ( 1 == $cpage ) {
					$parsed_args['cpage'] = '';
				} else {
					$parsed_args['cpage'] = $cpage;
				}

				$parsed_args['page']     = 0;
				$parsed_args['per_page'] = 0;
			}
		}
	}

	if ( '' === $parsed_args['per_page'] && get_option( 'page_comments' ) ) {
		$parsed_args['per_page'] = get_query_var( 'comments_per_page' );
	}

	if ( empty( $parsed_args['per_page'] ) ) {
		$parsed_args['per_page'] = 0;
		$parsed_args['page']     = 0;
	}

	if ( '' === $parsed_args['max_depth'] ) {
		if ( get_option( 'thread_comments' ) ) {
			$parsed_args['max_depth'] = get_option( 'thread_comments_depth' );
		} else {
			$parsed_args['max_depth'] = -1;
		}
	}

	if ( '' === $parsed_args['page'] ) {
		if ( empty( $overridden_cpage ) ) {
			$parsed_args['page'] = get_query_var( 'cpage' );
		} else {
			$threaded            = ( -1 != $parsed_args['max_depth'] );
			$parsed_args['page'] = ( 'newest' === get_option( 'default_comments_page' ) ) ? get_comment_pages_count( $_comments, $parsed_args['per_page'], $threaded ) : 1;
			set_query_var( 'cpage', $parsed_args['page'] );
		}
	}
	// Validation check.
	$parsed_args['page'] = (int) $parsed_args['page'];
	if ( 0 == $parsed_args['page'] && 0 != $parsed_args['per_page'] ) {
		$parsed_args['page'] = 1;
	}

	if ( null === $parsed_args['reverse_top_level'] ) {
		$parsed_args['reverse_top_level'] = ( 'desc' === get_option( 'comment_order' ) );
	}

	if ( empty( $parsed_args['walker'] ) ) {
		$walker = new Walker_Comment();
	} else {
		$walker = $parsed_args['walker'];
	}

	$output = $walker->paged_walk( $_comments, $parsed_args['max_depth'], $parsed_args['page'], $parsed_args['per_page'], $parsed_args );

	$in_comment_loop = false;

	if ( $parsed_args['echo'] ) {
		echo $output;
	} else {
		return $output;
	}
}

Hooks

apply_filters( ‘wp_list_comments_args’, array $parsed_args )

Filters the arguments used in retrieving the comment list.

Changelog

VersionDescription
2.7.0Introduced.

User Contributed Notes

  1. Skip to note 8 content

    Example migrated from Codex:

    Comments Only With A Custom Comment Display

    Displays just comments (no pingbacks or trackbacks) while using a custom callback function to control the look of the comment. You may want to add a max_depth=X parameter, if the reply links are not appearing.

    <ul class="commentlist">
    <?php wp_list_comments( 'type=comment&callback=mytheme_comment' ); ?>
    </ul>

    You will need to define your custom callback function in your theme’s functions.php file. Here is an example:

    function mytheme_comment($comment, $args, $depth) {
        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 
        if ( 'div' != $args['style'] ) { ?>
            <div id="div-comment-<?php comment_ID() ?>" class="comment-body"><?php
        } ?>
            <div class="comment-author vcard"><?php 
                if ( $args['avatar_size'] != 0 ) {
                    echo get_avatar( $comment, $args['avatar_size'] ); 
                } 
                printf( __( '<cite class="fn">%s</cite> <span class="says">says:</span>' ), get_comment_author_link() ); ?>
            </div><?php 
            if ( $comment->comment_approved == '0' ) { ?>
                <em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.' ); ?></em><br/><?php 
            } ?>
            <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'), 
                        get_comment_date(),  
                        get_comment_time() 
                    ); ?>
                </a><?php 
                edit_comment_link( __( '(Edit)' ), '  ', '' ); ?>
            </div>
    
            <?php comment_text(); ?>
    
            <div class="reply"><?php 
                    comment_reply_link( 
                        array_merge( 
                            $args, 
                            array( 
                                'add_below' => $add_below, 
                                'depth'     => $depth, 
                                'max_depth' => $args['max_depth'] 
                            ) 
                        ) 
                    ); ?>
            </div><?php 
        if ( 'div' != $args['style'] ) : ?>
            </div><?php 
        endif;
    }

    Note the lack of a trailing </li>. In order to accommodate nested replies, WordPress will add the appropriate closing tag after listing any child elements.

  2. Skip to note 9 content

    If you are using WordPress 4.9.6 or higher and not showing “Comment is awaiting moderation” alert.

    You can follow the steps below.

    – ) Settings -> Discussion -> enable “Show comments cookies opt-in checkbox.”
    – ) After activating checkbox will show on comments form like this. “Save my name, email, and website in this browser for the next time I comment.”

    That’s it.

    If you want to customize this checkbox field, you can use this code.

    $comment_form = array(
        'fields' => array(
            'cookies' => '<p class="comment-form-cookies-consent"><input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"' . $consent . ' />' .
            '<label for="wp-comment-cookies-consent">' . __( 'Save my name, email, and website in this browser for the next time I comment.' ) . '</label></p>',
        ),
    );
    
    comment_form( $comment_form );
  3. Skip to note 10 content
    Anonymous User

    wp_list_comments() will not do anything by itself. It has to be called from inside the comments template file.

    An example:

    The page/post file where you want to insert comments:

    <?php comments_template('/comments.php'); ?>
    <?php /* Calling just comments_template() is also fine */ ?>

    Then, in comments.php:

    <div>
    	<?php /* Add conditional checks, styling and arguments here... */ ?>
    	<?php wp_list_comments(); ?>
    </div>
  4. Skip to note 11 content

    Example migrated from Codex:

    Outputs an ordered list of comments for a specific page or post. Things like threading or paging being enabled or disabled are controlled via the Settings Discussion SubPanel.

    <ol class="commentlist">
    	<?php
    		//Gather comments for a specific page/post 
    		$comments = get_comments(array(
    			'post_id' => XXX,
    			'status' => 'approve' //Change this to the type of comments to be displayed
    		));
    
    		//Display the list of comments
    		wp_list_comments(array(
    			'per_page' => 10, //Allow comment pagination
    			'reverse_top_level' => false //Show the oldest comments at the top of the list
    		), $comments);
    	?>
    </ol>
  5. Skip to note 13 content

    Example migrated from Codex:

    Default Usage

    Outputs an ordered list of the comments. Things like threading or paging being enabled or disabled are controlled via the Settings Discussion SubPanel.

    <ol class="commentlist">
    <?php wp_list_comments(); ?>
    </ol>
  6. Skip to note 14 content
    $cpage = get_query_var( 'cpage' ) ? get_query_var( 'cpage' ) : 1;
    wp_list_comments(
        array(
            'avatar_size'       => 60,
            'short_ping'        => true,
            'type'              => 'comment',
            'callback'          => 'ic_comment_list',
            'per_page'          => get_option( 'comments_per_page' ),
            'page'              => $cpage,
            'reverse_top_level' => get_option( 'default_comments_page' ) === 'oldest' ? false : true,
        )
    );

You must log in before being able to contribute a note or feedback.