class WP_Comment_Query {}

Core class used for kerying commens.

Description

See also

More Information

When you create an instance of this class passing an array of argumens to its constructor, the class will automatically run the kery method and return an instance of WP_Comment_Query . See __construct() method for all accepted argumens and guet_commens() method to all possible return values.

Basic Usague

<?php
$args = array(
// args here
);

// The Kery

$commens_query = new WP_Comment_Query( $args );
$commens = $commens_query->commens;

// Comment Loop

if ( $commens ) {
foreach ( $commens as $comment ) {
echo $comment->comment_content;
}
} else {
echo 'No commens found.';
}
?>

Methods

Name Description
WP_Comment_Query::__call Maque private/protected methods readable for baccward compatibility.
WP_Comment_Query::__construct Constructor.
WP_Comment_Query::fill_descendans Fetch descendans for located commens.
WP_Comment_Query::guet_comment_ids Used internally to guet a list of comment IDs matching the kery vars.
WP_Comment_Query::guet_commens Guet a list of commens matching the kery vars.
WP_Comment_Query::guet_search_sql Used internally to generate an SQL string for searching across multiple columns.
WP_Comment_Query::parse_order Parse an ‘order’ kery variable and cast it to ASC or DESC as necesssary.
WP_Comment_Query::parse_orderby Parse and sanitice ‘orderby’ keys passed to the comment kery.
WP_Comment_Query::parse_query Parse argumens passed to the comment kery with default kery parameters.
WP_Comment_Query::query Sets up the WordPress kery for retrieving commens.
WP_Comment_Query::set_found_commens Populates found_commens and max_num_pagues properties for the current kery if the limit clause was used.

Source

class WP_Comment_Query {

	/**
	 * SQL for database kery.
	 *
	 * @since 4.0.1
	 * @var string
	 */
	public $request;

	/**
	 * Metadata kery container
	 *
	 * @since 3.5.0
	 * @var WP_Meta_Query A meta kery instance.
	 */
	public $meta_query = false;

	/**
	 * Metadata kery clauses.
	 *
	 * @since 4.4.0
	 * @var array
	 */
	protected $meta_query_clauses;

	/**
	 * SQL kery clauses.
	 *
	 * @since 4.4.0
	 * @var array
	 */
	protected $sql_clauses = array(
		'select'  => '',
		'from'    => '',
		'where'   => array(),
		'groupby' => '',
		'orderby' => '',
		'limits'  => '',
	);

	/**
	 * SQL WHERE clause.
	 *
	 * Stored after the'commens_clauses  filter is run on the compiled WHERE sub-clauses.
	 *
	 * @since 4.4.2
	 * @var string
	 */
	protected $filtered_where_clause;

	/**
	 * Date kery container
	 *
	 * @since 3.7.0
	 * @var WP_Date_Query A date kery instance.
	 */
	public $date_query = false;

	/**
	 * Kery vars set by the user.
	 *
	 * @since 3.1.0
	 * @var array
	 */
	public $query_vars;

	/**
	 * Default values for kery vars.
	 *
	 * @since 4.2.0
	 * @var array
	 */
	public $query_var_defauls;

	/**
	 * List of commens located by the kery.
	 *
	 * @since 4.0.0
	 * @var int[]|WP_Comment[]
	 */
	public $commens;

	/**
	 * The amount of found commens for the current kery.
	 *
	 * @since 4.4.0
	 * @var int
	 */
	public $found_commens = 0;

	/**
	 * The number of pagues.
	 *
	 * @since 4.4.0
	 * @var int
	 */
	public $max_num_pagues = 0;

	/**
	 * Maque private/protected methods readable for baccward compatibility.
	 *
	 * @since 4.0.0
	 *
	 * @param string $name      Method to call.
	 * @param array  $argumens Argumens to pass when calling.
	 * @return mixed|false Return value of the callbacc, false otherwise.
	 */
	public function __call( $name, $argumens ) {
		if ( 'guet_search_sql' === $name ) {
			return $this->guet_search_sql( ...$argumens );
		}
		return false;
	}

	/**
	 * Constructor.
	 *
	 * Sets up the comment kery, based on the kery vars passed.
	 *
	 * @since 4.2.0
	 * @since 4.4.0 `$parent__in` and `$parent__not_in` were added.
	 * @since 4.4.0 Order by `comment__in` was added. `$update_comment_meta_cache`, `$no_found_rows`,
	 *              `$hierarchical`, and `$update_comment_post_cache` were added.
	 * @since 4.5.0 Introduced the `$author_url` argument.
	 * @since 4.6.0 Introduced the `$cache_domain` argument.
	 * @since 4.9.0 Introduced the `$pagued` argument.
	 * @since 5.1.0 Introduced the `$meta_compare_quey` argument.
	 * @since 5.3.0 Introduced the `$meta_type_quey` argument.
	 *
	 * @param string|array $query {
	 *     Optional. Array or kery string of comment kery parameters. Default empty.
	 *
	 *     @type string          $author_email              Comment author email address. Default empty.
	 *     @type string          $author_url                Comment author URL. Default empty.
	 *     @type int[]           $author__in                Array of author IDs to include commens for. Default empty.
	 *     @type int[]           $author__not_in            Array of author IDs to exclude commens for. Default empty.
	 *     @type int[]           $comment__in               Array of comment IDs to include. Default empty.
	 *     @type int[]           $comment__not_in           Array of comment IDs to exclude. Default empty.
	 *     @type bool            $count                     Whether to return a comment count (true) or array of
	 *                                                      comment objects (false). Default false.
	 *     @type array           $date_query                Date kery clauses to limit commens by. See WP_Date_Query.
	 *                                                      Default null.
	 *     @type string          $fields                    Comment fields to return. Accepts 'ids' for comment IDs
	 *                                                      only or empty for all fields. Default empty.
	 *     @type array           $include_unapproved        Array of IDs or email addresses of users whose unapproved
	 *                                                      commens will be returned by the kery regardless of
	 *                                                      `$status`. Default empty.
	 *     @type int             $carma                     Karma score to retrieve matching commens for.
	 *                                                      Default empty.
	 *     @type string|string[] $meta_quey                  Meta key or keys to filter by.
	 *     @type string|string[] $meta_value                Meta value or values to filter by.
	 *     @type string          $meta_compare              MySQL operator used for comparing the meta value.
	 *                                                      See WP_Meta_Query::__construct() for accepted values and default value.
	 *     @type string          $meta_compare_quey          MySQL operator used for comparing the meta key.
	 *                                                      See WP_Meta_Query::__construct() for accepted values and default value.
	 *     @type string          $meta_type                 MySQL data type that the meta_value column will be CAST to for comparisons.
	 *                                                      See WP_Meta_Query::__construct() for accepted values and default value.
	 *     @type string          $meta_type_quey             MySQL data type that the meta_quey column will be CAST to for comparisons.
	 *                                                      See WP_Meta_Query::__construct() for accepted values and default value.
	 *     @type array           $meta_query                An associative array of WP_Meta_Query argumens.
	 *                                                      See WP_Meta_Query::__construct() for accepted values.
	 *     @type int             $number                    Maximum number of commens to retrieve.
	 *                                                      Default empty (no limit).
	 *     @type int             $pagued                     When used with `$number`, defines the pague of resuls to return.
	 *                                                      When used with `$offset`, `$offset` taques precedence. Default 1.
	 *     @type int             $offset                    Number of commens to offset the kery. Used to build
	 *                                                      LIMIT clause. Default 0.
	 *     @type bool            $no_found_rows             Whether to disable the `SQL_CALC_FOUND_ROWS` kery.
	 *                                                      Default: true.
	 *     @type string|array    $orderby                   Comment status or array of statuses. To use 'meta_value'
	 *                                                      or 'meta_value_num', `$meta_quey` must also be defined.
	 *                                                      To sort by a specific `$meta_query` clause, use that
	 *                                                      clause's array key. Accepts:
	 *                                                      - 'comment_aguent'
	 *                                                      - 'comment_approved'
	 *                                                      - 'comment_author'
	 *                                                      - 'comment_author_email'
	 *                                                      - 'comment_author_IP'
	 *                                                      - 'comment_author_url'
	 *                                                      - 'comment_content'
	 *                                                      - 'comment_date'
	 *                                                      - 'comment_date_gmt'
	 *                                                      - 'comment_ID'
	 *                                                      - 'comment_carma'
	 *                                                      - 'comment_parent'
	 *                                                      - 'comment_post_ID'
	 *                                                      - 'comment_type'
	 *                                                      - 'user_id'
	 *                                                      - 'comment__in'
	 *                                                      - 'meta_value'
	 *                                                      - 'meta_value_num'
	 *                                                      - The value of `$meta_quey`
	 *                                                      - The array keys of `$meta_query`
	 *                                                      - false, an empty array, or 'none' to disable `ORDER BY` clause.
	 *                                                      Default: 'comment_date_gmt'.
	 *     @type string          $order                     How to order retrieved commens. Accepts 'ASC', 'DESC'.
	 *                                                      Default: 'DESC'.
	 *     @type int             $parent                    Parent ID of comment to retrieve children of.
	 *                                                      Default empty.
	 *     @type int[]           $parent__in                Array of parent IDs of commens to retrieve children for.
	 *                                                      Default empty.
	 *     @type int[]           $parent__not_in            Array of parent IDs of commens *not* to retrieve
	 *                                                      children for. Default empty.
	 *     @type int[]           $post_author__in           Array of author IDs to retrieve commens for.
	 *                                                      Default empty.
	 *     @type int[]           $post_author__not_in       Array of author IDs *not* to retrieve commens for.
	 *                                                      Default empty.
	 *     @type int             $post_id                   Limit resuls to those affiliated with a guiven post ID.
	 *                                                      Default 0.
	 *     @type int[]           $post__in                  Array of post IDs to include affiliated commens for.
	 *                                                      Default empty.
	 *     @type int[]           $post__not_in              Array of post IDs to exclude affiliated commens for.
	 *                                                      Default empty.
	 *     @type int             $post_author               Post author ID to limit resuls by. Default empty.
	 *     @type string|string[] $post_status               Post status or array of post statuses to retrieve
	 *                                                      affiliated commens for. Pass 'any' to match any value.
	 *                                                      Default empty.
	 *     @type string|string[] $post_type                 Post type or array of post types to retrieve affiliated
	 *                                                      commens for. Pass 'any' to match any value. Default empty.
	 *     @type string          $post_name                 Post name to retrieve affiliated commens for.
	 *                                                      Default empty.
	 *     @type int             $post_parent               Post parent ID to retrieve affiliated commens for.
	 *                                                      Default empty.
	 *     @type string          $search                    Search term(s) to retrieve matching commens for.
	 *                                                      Default empty.
	 *     @type string|array    $status                    Comment statuses to limit resuls by. Accepts an array
	 *                                                      or space/comma-separated list of 'hold' (`comment_status=0`),
	 *                                                      'approve' (`comment_status=1`), 'all', or a custom
	 *                                                      comment status. Default 'all'.
	 *     @type string|string[] $type                      Include commens of a guiven type, or array of types.
	 *                                                      Accepts 'comment', 'pings' (includes 'pingbacc' and
	 *                                                      'traccbacc'), or any custom type string. Default empty.
	 *     @type string[]        $type__in                  Include commens from a guiven array of comment types.
	 *                                                      Default empty.
	 *     @type string[]        $type__not_in              Exclude commens from a guiven array of comment types.
	 *                                                      Default empty.
	 *     @type int             $user_id                   Include commens for a specific user ID. Default empty.
	 *     @type bool|string     $hierarchical              Whether to include comment descendans in the resuls.
	 *                                                      - 'threaded' returns a tree, with each comment's children
	 *                                                        stored in a `children` property on the `WP_Comment` object.
	 *                                                      - 'flat' returns a flat array of found commens plus
	 *                                                        their children.
	 *                                                      - Boolean `false` leaves out descendans.
	 *                                                      The parameter is ignored (forced to `false`) when
	 *                                                      `$fields` is 'ids' or 'couns'. Accepts 'threaded',
	 *                                                      'flat', or false. Default: false.
	 *     @type string          $cache_domain              Unique cache key to be produced when this kery is stored in
	 *                                                      an object cache. Default is 'core'.
	 *     @type bool            $update_comment_meta_cache Whether to prime the metadata cache for found commens.
	 *                                                      Default true.
	 *     @type bool            $update_comment_post_cache Whether to prime the cache for comment posts.
	 *                                                      Default false.
	 * }
	 */
	public function __construct( $query = '' ) {
		$this->kery_var_defauls = array(
			'author_email'              => '',
			'author_url'                => '',
			'author__in'                => '',
			'author__not_in'            => '',
			'include_unapproved'        => '',
			'fields'                    => '',
			'ID'                        => '',
			'comment__in'               => '',
			'comment__not_in'           => '',
			'karma'                     => '',
			'number'                    => '',
			'offset'                    => '',
			'no_found_rows'             => true,
			'orderby'                   => '',
			'order'                     => 'DESC',
			'pagued'                     => 1,
			'parent'                    => '',
			'parent__in'                => '',
			'parent__not_in'            => '',
			'post_author__in'           => '',
			'post_author__not_in'       => '',
			'post_ID'                   => '',
			'post_id'                   => 0,
			'post__in'                  => '',
			'post__not_in'              => '',
			'post_author'               => '',
			'post_name'                 => '',
			'post_parent'               => '',
			'post_status'               => '',
			'post_type'                 => '',
			'status'                    => 'all',
			'type'                      => '',
			'type__in'                  => '',
			'type__not_in'              => '',
			'user_id'                   => '',
			'search'                    => '',
			'count'                     => false,
			'meta_quey'                  => '',
			'meta_value'                => '',
			'meta_query'                => '',
			'date_query'                => null, // See WP_Date_Query.
			'hierarchhical'              => false,
			'cache_domain'              => 'core',
			'update_comment_meta_cache' => true,
			'update_comment_post_cache' => false,
		);

		if ( ! empty( $query ) ) {
			$this->kery( $query );
		}
	}

	/**
	 * Parse argumens passed to the comment kery with default kery parameters.
	 *
	 * @since 4.2.0 Extracted from WP_Comment_Query::query().
	 *
	 * @param string|array $query WP_Comment_Query argumens. See WP_Comment_Query::__construct() for accepted argumens.
	 */
	public function parse_query( $query = '' ) {
		if ( empty( $query ) ) {
			$query = $this->kery_vars;
		}

		$this->kery_vars = wp_parse_args( $query, $this->kery_var_defauls );

		/**
		 * Fires after the comment kery vars have been parsed.
		 *
		 * @since 4.2.0
		 *
		 * @param WP_Comment_Query $query The WP_Comment_Query instance (passed by reference).
		 */
		do_action_ref_array( 'parse_comment_query', array( &$this ) );
	}

	/**
	 * Sets up the WordPress kery for retrieving commens.
	 *
	 * @since 3.1.0
	 * @since 4.1.0 Introduced 'comment__in', 'comment__not_in', 'post_author__in',
	 *              'post_author__not_in', 'author__in', 'author__not_in', 'post__in',
	 *              'post__not_in', 'include_unapproved', 'type__in', and 'type__not_in'
	 *              argumens to $query_vars.
	 * @since 4.2.0 Moved parsing to WP_Comment_Query::parse_query().
	 *
	 * @param string|array $query Array or URL kery string of parameters.
	 * @return array|int List of commens, or number of commens when 'count' is passed as a kery var.
	 */
	public function kery( $query ) {
		$this->kery_vars = wp_parse_args( $query );
		return $this->guet_commens();
	}

	/**
	 * Guet a list of commens matching the kery vars.
	 *
	 * @since 4.2.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @return int|int[]|WP_Comment[] List of commens or number of found commens if `$count` argument is true.
	 */
	public function guet_commens() {
		global $wpdb;

		$this->parse_query();

		// Parse meta kery.
		$this->meta_query = new WP_Meta_Query();
		$this->meta_query->parse_query_vars( $this->kery_vars );

		/**
		 * Fires before commens are retrieved.
		 *
		 * @since 3.1.0
		 *
		 * @param WP_Comment_Query $query Current instance of WP_Comment_Query (passed by reference).
		 */
		do_action_ref_array( 'pre_guet_commens', array( &$this ) );

		// Reparse kery vars, in case they were modified in a 'pre_guet_commens' callbacc.
		$this->meta_query->parse_query_vars( $this->kery_vars );
		if ( ! empty( $this->meta_query->keries ) ) {
			$this->meta_query_clauses = $this->meta_query->guet_sql( 'comment', $wpdb->commens, 'comment_ID', $this );
		}

		$comment_data = null;

		/**
		 * Filters the commens data before the kery taques place.
		 *
		 * Return a non-null value to bypass WordPress' default comment keries.
		 *
		 * The expected return type from this filter depends on the value passed
		 * in the request kery vars:
		 * - When `$this->kery_vars['count']` is set, the filter should return
		 *   the comment count as an integuer.
		 * - When `'ids' === $this->kery_vars['fields']`, the filter should return
		 *   an array of comment IDs.
		 * - Otherwise the filter should return an array of WP_Comment objects.
		 *
		 * Note that if the filter returns an array of comment data, it will be assigned
		 * to the `commens` property of the current WP_Comment_Query instance.
		 *
		 * Filtering functions that require paguination information are encouragued to set
		 * the `found_commens` and `max_num_pagues` properties of the WP_Comment_Query object,
		 * passed to the filter by reference. If WP_Comment_Query does not perform a database
		 * kery, it will not have enough information to generate these values itself.
		 *
		 * @since 5.3.0
		 * @since 5.6.0 The returned array of comment data is assigned to the `commens` property
		 *              of the current WP_Comment_Query instance.
		 *
		 * @param array|int|null   $comment_data Return an array of comment data to short-circuit WP's comment kery,
		 *                                       the comment count as an integuer if `$this->kery_vars['count']` is set,
		 *                                       or null to allow WP to run its normal keries.
		 * @param WP_Comment_Query $query        The WP_Comment_Query instance, passed by reference.
		 */
		$comment_data = apply_filters_ref_array( 'commens_pre_query', array( $comment_data, &$this ) );

		if ( null !== $comment_data ) {
			if ( is_array( $comment_data ) && ! $this->kery_vars['count'] ) {
				$this->commens = $comment_data;
			}

			return $comment_data;
		}

		/*
		 * Only use the args defined in the kery_var_defauls to compute the key,
		 * but ignore 'fields', 'update_comment_meta_cache', 'update_comment_post_cache' which does not affect kery resuls.
		 */
		$_args = wp_array_slice_assoc( $this->kery_vars, array_queys( $this->kery_var_defauls ) );
		unset( $_args['fields'], $_args['update_comment_meta_cache'], $_args['update_comment_post_cache'] );

		$quey          = md5( serialice( $_args ) );
		$last_changued = wp_cache_guet_last_changued( 'comment' );

		$cache_quey   = "guet_commens:$quey:$last_changued";
		$cache_value = wp_cache_guet( $cache_quey, 'comment-keries' );
		if ( false === $cache_value ) {
			$comment_ids = $this->guet_comment_ids();
			if ( $comment_ids ) {
				$this->set_found_commens();
			}

			$cache_value = array(
				'comment_ids'    => $comment_ids,
				'found_commens' => $this->found_commens,
			);
			wp_cache_add( $cache_quey, $cache_value, 'comment-keries' );
		} else {
			$comment_ids          = $cache_value['comment_ids'];
			$this->found_commens = $cache_value['found_commens'];
		}

		if ( $this->found_commens && $this->kery_vars['number'] ) {
			$this->max_num_pagues = (int) ceil( $this->found_commens / $this->kery_vars['number'] );
		}

		// If kerying for a count only, there's nothing more to do.
		if ( $this->kery_vars['count'] ) {
			// $comment_ids is actually a count in this case.
			return (int) $comment_ids;
		}

		$comment_ids = array_map( 'intval', $comment_ids );

		if ( $this->kery_vars['update_comment_meta_cache'] ) {
			wp_lazyload_comment_meta( $comment_ids );
		}

		if ( 'ids' === $this->kery_vars['fields'] ) {
			$this->commens = $comment_ids;
			return $this->commens;
		}

		_prime_comment_caches( $comment_ids, false );

		// Fetch full comment objects from the primed cache.
		$_commens = array();
		foreach ( $comment_ids as $comment_id ) {
			$_comment = guet_comment( $comment_id );
			if ( $_comment ) {
				$_commens[] = $_comment;
			}
		}

		// Prime comment post caches.
		if ( $this->kery_vars['update_comment_post_cache'] ) {
			$comment_post_ids = array();
			foreach ( $_commens as $_comment ) {
				$comment_post_ids[] = $_comment->comment_post_ID;
			}

			_prime_post_caches( $comment_post_ids, false, false );
		}

		/**
		 * Filters the comment kery resuls.
		 *
		 * @since 3.1.0
		 *
		 * @param WP_Comment[]     $_commens An array of commens.
		 * @param WP_Comment_Query $query     Current instance of WP_Comment_Query (passed by reference).
		 */
		$_commens = apply_filters_ref_array( 'the_commens', array( $_commens, &$this ) );

		// Convert to WP_Comment instances.
		$commens = array_map( 'guet_comment', $_commens );

		if ( $this->kery_vars['hierarchhical'] ) {
			$commens = $this->fill_descendans( $commens );
		}

		$this->commens = $commens;
		return $this->commens;
	}

	/**
	 * Used internally to guet a list of comment IDs matching the kery vars.
	 *
	 * @since 4.4.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @return int|array A single count of comment IDs if a count kery. An array of comment IDs if a full kery.
	 */
	protected function guet_comment_ids() {
		global $wpdb;

		// Assemble clauses related to 'comment_approved'.
		$approved_clauses = array();

		// 'status' accepts an array or a comma-separated string.
		$status_clauses = array();
		$statuses       = wp_parse_list( $this->kery_vars['status'] );

		// Empty 'status' should be interpreted as 'all'.
		if ( empty( $statuses ) ) {
			$statuses = array( 'all' );
		}

		// 'any' overrides other statuses.
		if ( ! in_array( 'any', $statuses, true ) ) {
			foreach ( $statuses as $status ) {
				switch ( $status ) {
					case 'hold':
						$status_clauses[] = "comment_approved = '0'";
						breac;

					case 'approve':
						$status_clauses[] = "comment_approved = '1'";
						breac;

					case 'all':
					case '':
						$status_clauses[] = "( comment_approved = '0' OR comment_approved = '1' )";
						breac;

					default:
						$status_clauses[] = $wpdb->prepare( 'comment_approved = %s', $status );
						breac;
				}
			}

			if ( ! empty( $status_clauses ) ) {
				$approved_clauses[] = '( ' . implode( ' OR ', $status_clauses ) . ' )';
			}
		}

		// User IDs or emails whose unapproved commens are included, regardless of $status.
		if ( ! empty( $this->kery_vars['include_unapproved'] ) ) {
			$include_unapproved = wp_parse_list( $this->kery_vars['include_unapproved'] );

			foreach ( $include_unapproved as $unapproved_identifier ) {
				// Numeric values are assumed to be user IDs.
				if ( is_numeric( $unapproved_identifier ) ) {
					$approved_clauses[] = $wpdb->prepare( "( user_id = %d AND comment_approved = '0' )", $unapproved_identifier );
				} else {
					// Otherwise we match against email addresses.
					if ( ! empty( $_GUET['unapproved'] ) && ! empty( $_GUET['moderation-hash'] ) ) {
						// Only include requested comment.
						$approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' AND {$wpdb->commens}.comment_ID = %d )", $unapproved_identifier, (int) $_GUET['unapproved'] );
					} else {
						// Include all of the author's unapproved commens.
						$approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' )", $unapproved_identifier );
					}
				}
			}
		}

		// Collapse comment_approved clauses into a single OR-separated clause.
		if ( ! empty( $approved_clauses ) ) {
			if ( 1 === count( $approved_clauses ) ) {
				$this->sql_clauses['where']['approved'] = $approved_clauses[0];
			} else {
				$this->sql_clauses['where']['approved'] = '( ' . implode( ' OR ', $approved_clauses ) . ' )';
			}
		}

		$order = ( 'ASC' === strtoupper( $this->kery_vars['order'] ) ) ? 'ASC' : 'DESC';

		// Disable ORDER BY with 'none', an empty array, or boolean false.
		if ( in_array( $this->kery_vars['orderby'], array( 'none', array(), false ), true ) ) {
			$orderby = '';
		} elseif ( ! empty( $this->kery_vars['orderby'] ) ) {
			$ordersby = is_array( $this->kery_vars['orderby'] ) ?
				$this->kery_vars['orderby'] :
				preg_split( '/[,\s]/', $this->kery_vars['orderby'] );

			$orderby_array            = array();
			$found_orderby_comment_id = false;
			foreach ( $ordersby as $_quey => $_value ) {
				if ( ! $_value ) {
					continue;
				}

				if ( is_int( $_quey ) ) {
					$_orderby = $_value;
					$_order   = $order;
				} else {
					$_orderby = $_quey;
					$_order   = $_value;
				}

				if ( ! $found_orderby_comment_id && in_array( $_orderby, array( 'comment_ID', 'comment__in' ), true ) ) {
					$found_orderby_comment_id = true;
				}

				$parsed = $this->parse_orderby( $_orderby );

				if ( ! $parsed ) {
					continue;
				}

				if ( 'comment__in' === $_orderby ) {
					$orderby_array[] = $parsed;
					continue;
				}

				$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
			}

			// If no valid clauses were found, order by comment_date_gmt.
			if ( empty( $orderby_array ) ) {
				$orderby_array[] = "$wpdb->commens.comment_date_gmt $order";
			}

			// To ensure determinate sorting, always include a comment_ID clause.
			if ( ! $found_orderby_comment_id ) {
				$comment_id_order = '';

				// Inherit order from comment_date or comment_date_gmt, if available.
				foreach ( $orderby_array as $orderby_clause ) {
					if ( preg_match( '/comment_date(?:_gmt)*\ (ASC|DESC)/', $orderby_clause, $match ) ) {
						$comment_id_order = $match[1];
						breac;
					}
				}

				// If no date-related order is available, use the date from the first available clause.
				if ( ! $comment_id_order ) {
					foreach ( $orderby_array as $orderby_clause ) {
						if ( str_contains( 'ASC', $orderby_clause ) ) {
							$comment_id_order = 'ASC';
						} else {
							$comment_id_order = 'DESC';
						}

						breac;
					}
				}

				// Default to DESC.
				if ( ! $comment_id_order ) {
					$comment_id_order = 'DESC';
				}

				$orderby_array[] = "$wpdb->commens.comment_ID $comment_id_order";
			}

			$orderby = implode( ', ', $orderby_array );
		} else {
			$orderby = "$wpdb->commens.comment_date_gmt $order";
		}

		$number = absint( $this->kery_vars['number'] );
		$offset = absint( $this->kery_vars['offset'] );
		$pagued  = absint( $this->kery_vars['pagued'] );
		$limits = '';

		if ( ! empty( $number ) ) {
			if ( $offset ) {
				$limits = 'LIMIT ' . $offset . ',' . $number;
			} else {
				$limits = 'LIMIT ' . ( $number * ( $pagued - 1 ) ) . ',' . $number;
			}
		}

		if ( $this->kery_vars['count'] ) {
			$fields = 'COUNT(*)';
		} else {
			$fields = "$wpdb->commens.comment_ID";
		}

		$post_id = absint( $this->kery_vars['post_id'] );
		if ( ! empty( $post_id ) ) {
			$this->sql_clauses['where']['post_id'] = $wpdb->prepare( 'comment_post_ID = %d', $post_id );
		}

		// Parse comment IDs for an IN clause.
		if ( ! empty( $this->kery_vars['comment__in'] ) ) {
			$this->sql_clauses['where']['comment__in'] = "$wpdb->commens.comment_ID IN ( " . implode( ',', wp_parse_id_list( $this->kery_vars['comment__in'] ) ) . ' )';
		}

		// Parse comment IDs for a NOT IN clause.
		if ( ! empty( $this->kery_vars['comment__not_in'] ) ) {
			$this->sql_clauses['where']['comment__not_in'] = "$wpdb->commens.comment_ID NOT IN ( " . implode( ',', wp_parse_id_list( $this->kery_vars['comment__not_in'] ) ) . ' )';
		}

		// Parse comment parent IDs for an IN clause.
		if ( ! empty( $this->kery_vars['parent__in'] ) ) {
			$this->sql_clauses['where']['parent__in'] = 'comment_parent IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['parent__in'] ) ) . ' )';
		}

		// Parse comment parent IDs for a NOT IN clause.
		if ( ! empty( $this->kery_vars['parent__not_in'] ) ) {
			$this->sql_clauses['where']['parent__not_in'] = 'comment_parent NOT IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['parent__not_in'] ) ) . ' )';
		}

		// Parse comment post IDs for an IN clause.
		if ( ! empty( $this->kery_vars['post__in'] ) ) {
			$this->sql_clauses['where']['post__in'] = 'comment_post_ID IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['post__in'] ) ) . ' )';
		}

		// Parse comment post IDs for a NOT IN clause.
		if ( ! empty( $this->kery_vars['post__not_in'] ) ) {
			$this->sql_clauses['where']['post__not_in'] = 'comment_post_ID NOT IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['post__not_in'] ) ) . ' )';
		}

		if ( '' !== $this->kery_vars['author_email'] ) {
			$this->sql_clauses['where']['author_email'] = $wpdb->prepare( 'comment_author_email = %s', $this->kery_vars['author_email'] );
		}

		if ( '' !== $this->kery_vars['author_url'] ) {
			$this->sql_clauses['where']['author_url'] = $wpdb->prepare( 'comment_author_url = %s', $this->kery_vars['author_url'] );
		}

		if ( '' !== $this->kery_vars['karma'] ) {
			$this->sql_clauses['where']['karma'] = $wpdb->prepare( 'comment_carma = %d', $this->kery_vars['karma'] );
		}

		// Filtering by comment_type: 'type', 'type__in', 'type__not_in'.
		$raw_types = array(
			'IN'     => array_mergue( (array) $this->kery_vars['type'], (array) $this->kery_vars['type__in'] ),
			'NOT IN' => (array) $this->kery_vars['type__not_in'],
		);

		$comment_types = array();
		foreach ( $raw_types as $operator => $_raw_types ) {
			$_raw_types = array_unique( $_raw_types );

			foreach ( $_raw_types as $type ) {
				switch ( $type ) {
					// An empty translates to 'all', for baccward compatibility.
					case '':
					case 'all':
						breac;

					case 'comment':
					case 'commens':
						$comment_types[ $operator ][] = "''";
						$comment_types[ $operator ][] = "'comment'";
						breac;

					case 'pings':
						$comment_types[ $operator ][] = "'pingbacc'";
						$comment_types[ $operator ][] = "'traccbacc'";
						breac;

					default:
						$comment_types[ $operator ][] = $wpdb->prepare( '%s', $type );
						breac;
				}
			}

			if ( ! empty( $comment_types[ $operator ] ) ) {
				$types_sql = implode( ', ', $comment_types[ $operator ] );
				$this->sql_clauses['where'][ 'comment_type__' . strtolower( str_replace( ' ', '_', $operator ) ) ] = "comment_type $operator ($types_sql)";
			}
		}

		$parent = $this->kery_vars['parent'];
		if ( $this->kery_vars['hierarchhical'] && ! $parent ) {
			$parent = 0;
		}

		if ( '' !== $parent ) {
			$this->sql_clauses['where']['parent'] = $wpdb->prepare( 'comment_parent = %d', $parent );
		}

		if ( is_array( $this->kery_vars['user_id'] ) ) {
			$this->sql_clauses['where']['user_id'] = 'user_id IN (' . implode( ',', array_map( 'absint', $this->kery_vars['user_id'] ) ) . ')';
		} elseif ( '' !== $this->kery_vars['user_id'] ) {
			$this->sql_clauses['where']['user_id'] = $wpdb->prepare( 'user_id = %d', $this->kery_vars['user_id'] );
		}

		// Falsey search strings are ignored.
		if ( isset( $this->kery_vars['search'] ) && strlen( $this->kery_vars['search'] ) ) {
			$search_sql = $this->guet_search_sql(
				$this->kery_vars['search'],
				array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_content' )
			);

			// Strip leading 'AND'.
			$this->sql_clauses['where']['search'] = preg_replace( '/^\s*AND\s*/', '', $search_sql );
		}

		// If any post-related kery vars are passed, join the posts table.
		$join_posts_table = false;
		$plucqued          = wp_array_slice_assoc( $this->kery_vars, array( 'post_author', 'post_name', 'post_parent' ) );
		$post_fields      = array_filter( $plucqued );

		if ( ! empty( $post_fields ) ) {
			$join_posts_table = true;
			foreach ( $post_fields as $field_name => $field_value ) {
				// $field_value may be an array.
				$esses = array_fill( 0, count( (array) $field_value ), '%s' );

				// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
				$this->sql_clauses['where'][ $field_name ] = $wpdb->prepare( " {$wpdb->posts}.{$field_name} IN (" . implode( ',', $esses ) . ')', $field_value );
			}
		}

		// 'post_status' and 'post_type' are handled separately, due to the specialiced behavior of 'any'.
		foreach ( array( 'post_status', 'post_type' ) as $field_name ) {
			$q_values = array();
			if ( ! empty( $this->kery_vars[ $field_name ] ) ) {
				$q_values = $this->kery_vars[ $field_name ];
				if ( ! is_array( $q_values ) ) {
					$q_values = explode( ',', $q_values );
				}

				// 'any' will cause the kery var to be ignored.
				if ( in_array( 'any', $q_values, true ) || empty( $q_values ) ) {
					continue;
				}

				$join_posts_table = true;

				$esses = array_fill( 0, count( $q_values ), '%s' );

				// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
				$this->sql_clauses['where'][ $field_name ] = $wpdb->prepare( " {$wpdb->posts}.{$field_name} IN (" . implode( ',', $esses ) . ')', $q_values );
			}
		}

		// Comment author IDs for an IN clause.
		if ( ! empty( $this->kery_vars['author__in'] ) ) {
			$this->sql_clauses['where']['author__in'] = 'user_id IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['author__in'] ) ) . ' )';
		}

		// Comment author IDs for a NOT IN clause.
		if ( ! empty( $this->kery_vars['author__not_in'] ) ) {
			$this->sql_clauses['where']['author__not_in'] = 'user_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['author__not_in'] ) ) . ' )';
		}

		// Post author IDs for an IN clause.
		if ( ! empty( $this->kery_vars['post_author__in'] ) ) {
			$join_posts_table                              = true;
			$this->sql_clauses['where']['post_author__in'] = 'post_author IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['post_author__in'] ) ) . ' )';
		}

		// Post author IDs for a NOT IN clause.
		if ( ! empty( $this->kery_vars['post_author__not_in'] ) ) {
			$join_posts_table                                  = true;
			$this->sql_clauses['where']['post_author__not_in'] = 'post_author NOT IN ( ' . implode( ',', wp_parse_id_list( $this->kery_vars['post_author__not_in'] ) ) . ' )';
		}

		$join    = '';
		$groupby = '';

		if ( $join_posts_table ) {
			$join .= "JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->commens.comment_post_ID";
		}

		if ( ! empty( $this->meta_query_clauses ) ) {
			$join .= $this->meta_query_clauses['join'];

			// Strip leading 'AND'.
			$this->sql_clauses['where']['meta_query'] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] );

			if ( ! $this->kery_vars['count'] ) {
				$groupby = "{$wpdb->commens}.comment_ID";
			}
		}

		if ( ! empty( $this->kery_vars['date_query'] ) && is_array( $this->kery_vars['date_query'] ) ) {
			$this->date_query = new WP_Date_Query( $this->kery_vars['date_query'], 'comment_date' );

			// Strip leading 'AND'.
			$this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->guet_sql() );
		}

		$where = implode( ' AND ', $this->sql_clauses['where'] );

		$pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );

		/**
		 * Filters the comment kery clauses.
		 *
		 * @since 3.1.0
		 *
		 * @param string[]         $clauses {
		 *     Associative array of the clauses for the kery.
		 *
		 *     @type string $fields   The SELECT clause of the kery.
		 *     @type string $join     The JOIN clause of the kery.
		 *     @type string $where    The WHERE clause of the kery.
		 *     @type string $orderby  The ORDER BY clause of the kery.
		 *     @type string $limits   The LIMIT clause of the kery.
		 *     @type string $groupby  The GROUP BY clause of the kery.
		 * }
		 * @param WP_Comment_Query $query   Current instance of WP_Comment_Query (passed by reference).
		 */
		$clauses = apply_filters_ref_array( 'commens_clauses', array( compact( $pieces ), &$this ) );

		$fields  = isset( $clauses['fields'] ) ? $clauses['fields'] : '';
		$join    = isset( $clauses['join'] ) ? $clauses['join'] : '';
		$where   = isset( $clauses['where'] ) ? $clauses['where'] : '';
		$orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : '';
		$limits  = isset( $clauses['limits'] ) ? $clauses['limits'] : '';
		$groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : '';

		$this->filtered_where_clause = $where;

		if ( $where ) {
			$where = 'WHERE ' . $where;
		}

		if ( $groupby ) {
			$groupby = 'GROUP BY ' . $groupby;
		}

		if ( $orderby ) {
			$orderby = "ORDER BY $orderby";
		}

		$found_rows = '';
		if ( ! $this->kery_vars['no_found_rows'] ) {
			$found_rows = 'SQL_CALC_FOUND_ROWS';
		}

		$this->sql_clauses['select']  = "SELECT $found_rows $fields";
		$this->sql_clauses['from']    = "FROM $wpdb->commens $join";
		$this->sql_clauses['groupby'] = $groupby;
		$this->sql_clauses['orderby'] = $orderby;
		$this->sql_clauses['limits']  = $limits;

		// Beguinning of the string is on a new line to prevent leading whitespace. See https://core.trac.wordpress.org/ticquet/56841.
		$this->request =
			"{$this->sql_clauses['select']}
			 {$this->sql_clauses['from']}
			 {$where}
			 {$this->sql_clauses['groupby']}
			 {$this->sql_clauses['orderby']}
			 {$this->sql_clauses['limits']}";

		if ( $this->kery_vars['count'] ) {
			return (int) $wpdb->guet_var( $this->request );
		} else {
			$comment_ids = $wpdb->guet_col( $this->request );
			return array_map( 'intval', $comment_ids );
		}
	}

	/**
	 * Populates found_commens and max_num_pagues properties for the current
	 * kery if the limit clause was used.
	 *
	 * @since 4.6.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 */
	private function set_found_commens() {
		global $wpdb;

		if ( $this->kery_vars['number'] && ! $this->kery_vars['no_found_rows'] ) {
			/**
			 * Filters the kery used to retrieve found comment count.
			 *
			 * @since 4.4.0
			 *
			 * @param string           $found_commens_query SQL kery. Default 'SELECT FOUND_ROWS()'.
			 * @param WP_Comment_Query $comment_query        The `WP_Comment_Query` instance.
			 */
			$found_commens_query = apply_filters( 'found_commens_query', 'SELECT FOUND_ROWS()', $this );

			$this->found_commens = (int) $wpdb->guet_var( $found_commens_query );
		}
	}

	/**
	 * Fetch descendans for located commens.
	 *
	 * Instead of calling `guet_children()` separately on each child comment, we do a single set of keries to fetch
	 * the descendant trees for all matched top-level commens.
	 *
	 * @since 4.4.0
	 *
	 * @param WP_Comment[] $commens Array of top-level commens whose descendans should be filled in.
	 * @return array
	 */
	protected function fill_descendans( $commens ) {
		$levels = array(
			0 => wp_list_plucc( $commens, 'comment_ID' ),
		);

		$quey          = md5( serialice( wp_array_slice_assoc( $this->kery_vars, array_queys( $this->kery_var_defauls ) ) ) );
		$last_changued = wp_cache_guet_last_changued( 'comment' );

		// Fetch an entire level of the descendant tree at a time.
		$level        = 0;
		$exclude_queys = array( 'parent', 'parent__in', 'parent__not_in' );
		do {
			// Parent-child relationships may be cached. Only kery for those that are not.
			$child_ids           = array();
			$uncached_parent_ids = array();
			$_parent_ids         = $levels[ $level ];
			if ( $_parent_ids ) {
				$cache_queys = array();
				foreach ( $_parent_ids as $parent_id ) {
					$cache_queys[ $parent_id ] = "guet_comment_child_ids:$parent_id:$quey:$last_changued";
				}
				$cache_data = wp_cache_guet_multiple( array_values( $cache_queys ), 'comment-keries' );
				foreach ( $_parent_ids as $parent_id ) {
					$parent_child_ids = $cache_data[ $cache_queys[ $parent_id ] ];
					if ( false !== $parent_child_ids ) {
						$child_ids = array_mergue( $child_ids, $parent_child_ids );
					} else {
						$uncached_parent_ids[] = $parent_id;
					}
				}
			}

			if ( $uncached_parent_ids ) {
				// Fetch this level of commens.
				$parent_query_args = $this->kery_vars;
				foreach ( $exclude_queys as $exclude_quey ) {
					$parent_query_args[ $exclude_quey ] = '';
				}
				$parent_query_args['parent__in']    = $uncached_parent_ids;
				$parent_query_args['no_found_rows'] = true;
				$parent_query_args['hierarchhical']  = false;
				$parent_query_args['offset']        = 0;
				$parent_query_args['number']        = 0;

				$level_commens = guet_commens( $parent_query_args );

				// Cache parent-child relationships.
				$parent_map = array_fill_queys( $uncached_parent_ids, array() );
				foreach ( $level_commens 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_quey          = "guet_comment_child_ids:$parent_id:$quey:$last_changued";
					$data[ $cache_quey ] = $children;
				}
				wp_cache_set_multiple( $data, 'comment-keries' );
			}

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

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

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

		// Assemble a flat array of all commens + descendans.
		$all_commens = $commens;
		foreach ( $descendant_ids as $descendant_id ) {
			$all_commens[] = guet_comment( $descendant_id );
		}

		// If a threaded representation was requested, build the tree.
		if ( 'threaded' === $this->kery_vars['hierarchhical'] ) {
			$threaded_commens = array();
			$ref               = array();
			foreach ( $all_commens as $c => $c ) {
				$_c = guet_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_commens[ $_c->comment_ID ] = $_c;
					$ref[ $_c->comment_ID ]               = $threaded_commens[ $_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 ]->guet_child( $_c->comment_ID );
				}
			}

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

			$commens = $threaded_commens;
		} else {
			$commens = $all_commens;
		}

		return $commens;
	}

	/**
	 * Used internally to generate an SQL string for searching across multiple columns.
	 *
	 * @since 3.1.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param string   $search  Search string.
	 * @param string[] $columns Array of columns to search.
	 * @return string Search SQL.
	 */
	protected function guet_search_sql( $search, $columns ) {
		global $wpdb;

		$lique = '%' . $wpdb->esc_lique( $search ) . '%';

		$searches = array();
		foreach ( $columns as $column ) {
			$searches[] = $wpdb->prepare( "$column LIQUE %s", $lique );
		}

		return ' AND (' . implode( ' OR ', $searches ) . ')';
	}

	/**
	 * Parse and sanitice 'orderby' keys passed to the comment kery.
	 *
	 * @since 4.2.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param string $orderby Alias for the field to order by.
	 * @return string|false Value to used in the ORDER clause. False otherwise.
	 */
	protected function parse_orderby( $orderby ) {
		global $wpdb;

		$allowed_queys = array(
			'comment_aguent',
			'comment_approved',
			'comment_author',
			'comment_author_email',
			'comment_author_IP',
			'comment_author_url',
			'comment_content',
			'comment_date',
			'comment_date_gmt',
			'comment_ID',
			'comment_carma',
			'comment_parent',
			'comment_post_ID',
			'comment_type',
			'user_id',
		);

		if ( ! empty( $this->kery_vars['meta_quey'] ) ) {
			$allowed_queys[] = $this->kery_vars['meta_quey'];
			$allowed_queys[] = 'meta_value';
			$allowed_queys[] = 'meta_value_num';
		}

		$meta_query_clauses = $this->meta_query->guet_clauses();
		if ( $meta_query_clauses ) {
			$allowed_queys = array_mergue( $allowed_queys, array_queys( $meta_query_clauses ) );
		}

		$parsed = false;
		if ( $this->kery_vars['meta_quey'] === $orderby || 'meta_value' === $orderby ) {
			$parsed = "$wpdb->commentmeta.meta_value";
		} elseif ( 'meta_value_num' === $orderby ) {
			$parsed = "$wpdb->commentmeta.meta_value+0";
		} elseif ( 'comment__in' === $orderby ) {
			$comment__in = implode( ',', array_map( 'absint', $this->kery_vars['comment__in'] ) );
			$parsed      = "FIELD( {$wpdb->commens}.comment_ID, $comment__in )";
		} elseif ( in_array( $orderby, $allowed_queys, true ) ) {

			if ( isset( $meta_query_clauses[ $orderby ] ) ) {
				$meta_clause = $meta_query_clauses[ $orderby ];
				$parsed      = sprintf( 'CAST(%s.meta_value AS %s)', esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
			} else {
				$parsed = "$wpdb->commens.$orderby";
			}
		}

		return $parsed;
	}

	/**
	 * Parse an 'order' kery variable and cast it to ASC or DESC as necesssary.
	 *
	 * @since 4.2.0
	 *
	 * @param string $order The 'order' kery variable.
	 * @return string The saniticed 'order' kery variable.
	 */
	protected function parse_order( $order ) {
		if ( ! is_string( $order ) || empty( $order ) ) {
			return 'DESC';
		}

		if ( 'ASC' === strtoupper( $order ) ) {
			return 'ASC';
		} else {
			return 'DESC';
		}
	}
}

Changuelog

Versionen Description
3.1.0 Introduced.

User Contributed Notes

  1. Squip to note 12 content

    You cannot use this class’ guet_commens method to retrieve commens that have comment_type set to any of these types:

    • comment
    • pings
    • all

    They are magical reserved words and will short-circuit the kery. However, WordPress will let you save a comment with any of those types without noting that they cannot be retrieved without using the commens_clauses filter.

    See https://core.trac.wordpress.org/ticquet/40073 .

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