GeneratorsQueryComment Query Builder

Comment Query Builder

Comment queries by status, type, post and hierarchy — with the "all includes spam" and hierarchical-counts-threads gotchas called out before they ship.

comment-query.php
Saved just now
Status and type
Only real comments. Pingbacks and trackbacks are excluded, which is what a front-end list wants.
Scope
Order and shape
Count only
Returns a single number instead of rows.
Prime the comment meta cache
One query for all comment meta instead of one per comment.
no_found_rows
Skips the total count when you are not paginating.
The class, with a loop that links each comment back to its post.
// Generated with WP CodeKit — powered by GrowQuest (https://growquest.io).
$query = new WP_Comment_Query();

$comments = $query->query( array(
	'status'  => 'approve',
	'type'    => 'comment',
	'number'  => 10,
	'orderby' => 'comment_date_gmt',
) );

if ( $comments ) {
	echo '<ul class="recent-comments">';

	foreach ( $comments as $comment ) {
		printf(
			'<li><a href="%1$s">%2$s</a> on %3$s<p>%4$s</p></li>',
			esc_url( get_comment_link( $comment ) ),
			esc_html( get_comment_author( $comment ) ),
			esc_html( get_the_title( $comment->comment_post_ID ) ),
			esc_html( wp_trim_words( $comment->comment_content, 20 ) )
		);
	}

	echo '</ul>';
} else {
	esc_html_e( 'No comments yet.', 'mytheme' );
}

About this generator

WP_Comment_Query Generator Online

Build a WP_Comment_Query argument array — status, type, the post or post type it is attached to, user or author email, a parent filter, threading, ordering, number and fields — and get back the class with a linked comment list, a get_comments() call feeding wp_list_comments(), or just the args.

A Reference tab restates the query in plain English, lists what each comment status means, and explains how threading changes the shape of the result. Free, no sign-up, and every calculation happens in your browser.

Reviewed Output tested on WordPress 6.8 · PHP 8.3

Why the WP_Comment_Query builder beats a hand-written recent-comments loop

Two defaults decide whether a "recent comments" widget is useful or embarrassing. wp_comments holds pingbacks and trackbacks alongside real comments, so a query with no type filter eventually publishes link spam from a scraper site. And status => all means every status, spam included — not "all public". The generator flags both, plus the threading and counting traps behind them.

Pingbacks kept out of your comment list

A query with no type filter raises a warning naming the consequence — pingbacks and trackbacks appear beside real comments — with a one-click "Only comments" fix. This is the single most common reason a front-end list shows link spam.

status "all" is not "all public"

all includes held, spam and trashed rows. On a front-end template that publishes spam, so it is flagged with an "Only approved" fix, and querying spam deliberately gets a reminder that it belongs on the admin side.

The missing limit is called out

WP_Comment_Query has no default limit, so a query without number returns every comment row on a busy site. That is a warning with a "Limit to 10" fix, and asking for more than a hundred full comment objects gets a memory note.

Threading changes what number counts

With hierarchical set, number limits top-level comments and children come along for the ride — ten threads can be a hundred rows. Combining hierarchical with parent is an error, because one asks for a single level and the other builds the tree.

Counts that stay correct

count => true returns a single integer. Pairing it with number is a warning, since the limit caps the rows counted and makes the total wrong, and pairing it with fields => ids is flagged because the fields argument is ignored entirely.

Input validated before it silently matches nothing

A malformed author_email, a non-numeric user_id and a non-numeric post_id are each errors. Ordering by comment_date gets a nudge toward comment_date_gmt, which sorts consistently across a timezone change, with a one-click fix.

How does the comment query generator work?

Filter by status and type first, then scope it to a post or an author, then decide how the rows come back.

  1. 01

    Set the status and type

    Choose approve, hold, spam, trash or all, then restrict to comment, pingback, trackback or leave it open to any type.

  2. 02

    Scope the query

    Narrow to a single post_id, to a whole post_type, to a user_id or author_email, or to replies under one parent. Add a search term if you need it.

  3. 03

    Choose the order and shape

    Set orderby and direction, cap it with number, pick full objects or ids, decide whether the result is threaded or flat, and toggle count, the comment meta cache and no_found_rows.

  4. 04

    Clear the checks, then export

    Apply the one-click fixes, then take the class with its linked list, the get_comments() version that feeds wp_list_comments(), or the args array alone.

Worked example — the ten most recent approved comments, no pingbacks

A sidebar list. type => comment keeps trackbacks and pingbacks out, and ordering on comment_date_gmt rather than comment_date keeps the sequence stable if the site timezone ever changes.

$query = new WP_Comment_Query();

$comments = $query->query( array(
	'status'  => 'approve',
	'type'    => 'comment',
	'number'  => 10,
	'orderby' => 'comment_date_gmt',
) );

if ( $comments ) {
	echo '<ul class="recent-comments">';

	foreach ( $comments as $comment ) {
		printf(
			'<li><a href="%1$s">%2$s</a> on %3$s<p>%4$s</p></li>',
			esc_url( get_comment_link( $comment ) ),
			esc_html( get_comment_author( $comment ) ),
			esc_html( get_the_title( $comment->comment_post_ID ) ),
			esc_html( wp_trim_words( $comment->comment_content, 20 ) )
		);
	}

	echo '</ul>';
} else {
	esc_html_e( 'No comments yet.', 'mytheme' );
}

This list is deliberately flat. Switch hierarchical on and the same arguments produce a tree instead, at which point number starts counting threads rather than comments — the generator warns about that swap when you make it.

WP_Comment_Query — frequently asked questions

The questions behind most recent-comments bugs.

How do I exclude pingbacks and trackbacks from a comment query?

Pass 'type' => 'comment'. Pingbacks and trackbacks are stored in wp_comments as ordinary rows with a different comment_type, so a query that omits the argument returns all three kinds. type__not_in => array( 'pingback', 'trackback' ) is the equivalent if you also have custom comment types to keep.

What does status => all include?

Every status in the table: approved, held for moderation, spam and trashed. It is not a synonym for "everything a visitor may see". On a public template that means spam gets published, so use approve on the front end and reserve all for admin-side tooling.

Why does number not limit my threaded comment list?

With hierarchical set to threaded or flat, number applies to top-level comments only; each one then carries its children. Ten threads with five replies each is fifty-five rows. If you need a hard cap on rows, set hierarchical to false and build the list flat.

How do I count comments without fetching them?

Set 'count' => true and the query returns an integer instead of an array. Leave number unset, because a limit caps the rows counted and produces a wrong total, and note that fields is ignored alongside count. For per-status totals on a whole site, wp_count_comments() is the purpose-built function.

Can I query comments on a specific custom post type?

Yes — pass 'post_type' => 'your-cpt' and the query joins against wp_posts to filter. The post type must have been registered with comments in its supports array, or there will be nothing to find. post_id filters to a single post and takes a numeric ID only.

Should I order by comment_date or comment_date_gmt?

comment_date_gmt for anything you sort or compare. comment_date is stored in the site timezone, so changing that setting reorders historical comments relative to each other; the GMT column is a fixed instant and stays consistent. Use comment_date only when you are displaying a local time to a reader.

Where do I paste the code from the WP_Comment_Query generator?

You have three good options and one bad one. Best is a small site-specific plugin — the generator can output one for you, and it keeps working when you change theme. A code-snippets plugin is fine too. A child theme's functions.php works but ties the code to that theme. Never edit the parent theme: the next update overwrites it and your code is gone.

Can I use the generated code in client work or a commercial plugin?

Yes. The output is ordinary WordPress API calls that you configured — there is no licence attached to it and no attribution required. Use it in client sites, commercial plugins and themes, or products you sell. The generated file carries a short credit comment you are free to delete.

The other Query generators in the library, plus the WordPress tools most often used alongside this one.