WP_Comment_Query::fill_descendants( WP_Comment[] $comments ): array

Fetch descendants for located comments.

Description

Instead of calling get_children() separately on each child comment, we do a single set of queries to fetch the descendant trees for all matched top-level comments.

Parameters

$commentsWP_Comment[]required
Array of top-level comments whose descendants should be filled in.

Return

array

Source

protected function fill_descendants( $comments ) {
	$levels = array(
		0 => wp_list_pluck( $comments, 'comment_ID' ),
	);

	$key          = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
	$last_changed = wp_cache_get_last_changed( 'comment' );

	// Fetch an entire level of the descendant tree at a time.
	$level        = 0;
	$exclude_keys = array( 'parent', 'parent__in', 'parent__not_in' );
	do {
		// Parent-child relationships may be cached. Only query for those that are not.
		$child_ids           = array();
		$uncached_parent_ids = array();
		$_parent_ids         = $levels[ $level ];
		if ( $_parent_ids ) {
			$cache_keys = array();
			foreach ( $_parent_ids as $parent_id ) {
				$cache_keys[ $parent_id ] = "get_comment_child_ids:$parent_id:$key:$last_changed";
			}
			$cache_data = wp_cache_get_multiple( array_values( $cache_keys ), 'comment-queries' );
			foreach ( $_parent_ids as $parent_id ) {
				$parent_child_ids = $cache_data[ $cache_keys[ $parent_id ] ];
				if ( false !== $parent_child_ids ) {
					$child_ids = array_merge( $child_ids, $parent_child_ids );
				} else {
					$uncached_parent_ids[] = $parent_id;
				}
			}
		}

		if ( $uncached_parent_ids ) {
			// Fetch this level of comments.
			$parent_query_args = $this->query_vars;
			foreach ( $exclude_keys as $exclude_key ) {
				$parent_query_args[ $exclude_key ] = '';
			}
			$parent_query_args['parent__in']    = $uncached_parent_ids;
			$parent_query_args['no_found_rows'] = true;
			$parent_query_args['hierarchical']  = false;
			$parent_query_args['offset']        = 0;
			$parent_query_args['number']        = 0;

			$level_comments = get_comments( $parent_query_args );

			// Cache parent-child relationships.
			$parent_map = array_fill_keys( $uncached_parent_ids, array() );
			foreach ( $level_comments as $level_comment ) {
				$parent_map[ $level_comment->comment_parent ][] = $level_comment->comment_ID;
				$child_ids[]                                    = $level_comment->comment_ID;
			}

			$data = array();
			foreach ( $parent_map as $parent_id => $children ) {
				$cache_key          = "get_comment_child_ids:$parent_id:$key:$last_changed";
				$data[ $cache_key ] = $children;
			}
			wp_cache_set_multiple( $data, 'comment-queries' );
		}

		++$level;
		$levels[ $level ] = $child_ids;
	} while ( $child_ids );

	// Prime comment caches for non-top-level comments.
	$descendant_ids = array();
	for ( $i = 1, $c = count( $levels ); $i < $c; $i++ ) {
		$descendant_ids = array_merge( $descendant_ids, $levels[ $i ] );
	}

	_prime_comment_caches( $descendant_ids, $this->query_vars['update_comment_meta_cache'] );

	// Assemble a flat array of all comments + descendants.
	$all_comments = $comments;
	foreach ( $descendant_ids as $descendant_id ) {
		$all_comments[] = get_comment( $descendant_id );
	}

	// If a threaded representation was requested, build the tree.
	if ( 'threaded' === $this->query_vars['hierarchical'] ) {
		$threaded_comments = array();
		$ref               = array();
		foreach ( $all_comments as $k => $c ) {
			$_c = get_comment( $c->comment_ID );

			// If the comment isn't in the reference array, it goes in the top level of the thread.
			if ( ! isset( $ref[ $c->comment_parent ] ) ) {
				$threaded_comments[ $_c->comment_ID ] = $_c;
				$ref[ $_c->comment_ID ]               = $threaded_comments[ $_c->comment_ID ];

				// Otherwise, set it as a child of its parent.
			} else {

				$ref[ $_c->comment_parent ]->add_child( $_c );
				$ref[ $_c->comment_ID ] = $ref[ $_c->comment_parent ]->get_child( $_c->comment_ID );
			}
		}

		// Set the 'populated_children' flag, to ensure additional database queries aren't run.
		foreach ( $ref as $_ref ) {
			$_ref->populated_children( true );
		}

		$comments = $threaded_comments;
	} else {
		$comments = $all_comments;
	}

	return $comments;
}

Changelog

VersionDescription
4.4.0Introduced.

User Contributed Notes

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