WP_Comment_Query::parse_order()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 3
nop 1
dl 11
loc 11
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * Comment API: WP_Comment_Query class
4
 *
5
 * @package WordPress
6
 * @subpackage Comments
7
 * @since 4.4.0
8
 */
9
10
/**
11
 * Core class used for querying comments.
12
 *
13
 * @since 3.1.0
14
 *
15
 * @see WP_Comment_Query::__construct() for accepted arguments.
16
 */
17
class WP_Comment_Query {
18
19
	/**
20
	 * SQL for database query.
21
	 *
22
	 * @since 4.0.1
23
	 * @access public
24
	 * @var string
25
	 */
26
	public $request;
27
28
	/**
29
	 * Metadata query container
30
	 *
31
	 * @since 3.5.0
32
	 * @access public
33
	 * @var object WP_Meta_Query
34
	 */
35
	public $meta_query = false;
36
37
	/**
38
	 * Metadata query clauses.
39
	 *
40
	 * @since 4.4.0
41
	 * @access protected
42
	 * @var array
43
	 */
44
	protected $meta_query_clauses;
45
46
	/**
47
	 * SQL query clauses.
48
	 *
49
	 * @since 4.4.0
50
	 * @access protected
51
	 * @var array
52
	 */
53
	protected $sql_clauses = array(
54
		'select'  => '',
55
		'from'    => '',
56
		'where'   => array(),
57
		'groupby' => '',
58
		'orderby' => '',
59
		'limits'  => '',
60
	);
61
62
	/**
63
	 * SQL WHERE clause.
64
	 *
65
	 * Stored after the {@see 'comments_clauses'} filter is run on the compiled WHERE sub-clauses.
66
	 *
67
	 * @since 4.4.2
68
	 * @access protected
69
	 * @var string
70
	 */
71
	protected $filtered_where_clause;
72
73
	/**
74
	 * Date query container
75
	 *
76
	 * @since 3.7.0
77
	 * @access public
78
	 * @var object WP_Date_Query
79
	 */
80
	public $date_query = false;
81
82
	/**
83
	 * Query vars set by the user.
84
	 *
85
	 * @since 3.1.0
86
	 * @access public
87
	 * @var array
88
	 */
89
	public $query_vars;
90
91
	/**
92
	 * Default values for query vars.
93
	 *
94
	 * @since 4.2.0
95
	 * @access public
96
	 * @var array
97
	 */
98
	public $query_var_defaults;
99
100
	/**
101
	 * List of comments located by the query.
102
	 *
103
	 * @since 4.0.0
104
	 * @access public
105
	 * @var array
106
	 */
107
	public $comments;
108
109
	/**
110
	 * The amount of found comments for the current query.
111
	 *
112
	 * @since 4.4.0
113
	 * @access public
114
	 * @var int
115
	 */
116
	public $found_comments = 0;
117
118
	/**
119
	 * The number of pages.
120
	 *
121
	 * @since 4.4.0
122
	 * @access public
123
	 * @var int
124
	 */
125
	public $max_num_pages = 0;
126
127
	/**
128
	 * Make private/protected methods readable for backward compatibility.
129
	 *
130
	 * @since 4.0.0
131
	 * @access public
132
	 *
133
	 * @param callable $name      Method to call.
134
	 * @param array    $arguments Arguments to pass when calling.
135
	 * @return mixed|false Return value of the callback, false otherwise.
136
	 */
137
	public function __call( $name, $arguments ) {
138
		if ( 'get_search_sql' === $name ) {
139
			return call_user_func_array( array( $this, $name ), $arguments );
140
		}
141
		return false;
142
	}
143
144
	/**
145
	 * @since 4.7.0
146
	 * @access protected
147
	 * @var wpdb
148
	 */
149
	protected $db;
150
151
	/**
152
	 * Constructor.
153
	 *
154
	 * Sets up the comment query, based on the query vars passed.
155
	 *
156
	 * @since 4.2.0
157
	 * @since 4.4.0 `$parent__in` and `$parent__not_in` were added.
158
	 * @since 4.4.0 Order by `comment__in` was added. `$update_comment_meta_cache`, `$no_found_rows`,
159
	 *              `$hierarchical`, and `$update_comment_post_cache` were added.
160
	 * @since 4.5.0 Introduced the `$author_url` argument.
161
	 * @since 4.6.0 Introduced the `$cache_domain` argument.
162
	 * @access public
163
	 *
164
	 * @param string|array $query {
165
	 *     Optional. Array or query string of comment query parameters. Default empty.
166
	 *
167
	 *     @type string       $author_email              Comment author email address. Default empty.
168
	 *     @type string       $author_url                Comment author URL. Default empty.
169
	 *     @type array        $author__in                Array of author IDs to include comments for. Default empty.
170
	 *     @type array        $author__not_in            Array of author IDs to exclude comments for. Default empty.
171
	 *     @type array        $comment__in               Array of comment IDs to include. Default empty.
172
	 *     @type array        $comment__not_in           Array of comment IDs to exclude. Default empty.
173
	 *     @type bool         $count                     Whether to return a comment count (true) or array of
174
	 *                                                   comment objects (false). Default false.
175
	 *     @type array        $date_query                Date query clauses to limit comments by. See WP_Date_Query.
176
	 *                                                   Default null.
177
	 *     @type string       $fields                    Comment fields to return. Accepts 'ids' for comment IDs
178
	 *                                                   only or empty for all fields. Default empty.
179
	 *     @type int          $ID                        Currently unused.
180
	 *     @type array        $include_unapproved        Array of IDs or email addresses of users whose unapproved
181
	 *                                                   comments will be returned by the query regardless of
182
	 *                                                   `$status`. Default empty.
183
	 *     @type int          $karma                     Karma score to retrieve matching comments for.
184
	 *                                                   Default empty.
185
	 *     @type string       $meta_key                  Include comments with a matching comment meta key.
186
	 *                                                   Default empty.
187
	 *     @type string       $meta_value                Include comments with a matching comment meta value.
188
	 *                                                   Requires `$meta_key` to be set. Default empty.
189
	 *     @type array        $meta_query                Meta query clauses to limit retrieved comments by.
190
	 *                                                   See WP_Meta_Query. Default empty.
191
	 *     @type int          $number                    Maximum number of comments to retrieve.
192
	 *                                                   Default null (no limit).
193
	 *     @type int          $offset                    Number of comments to offset the query. Used to build
194
	 *                                                   LIMIT clause. Default 0.
195
	 *     @type bool         $no_found_rows             Whether to disable the `SQL_CALC_FOUND_ROWS` query.
196
	 *                                                   Default: true.
197
	 *     @type string|array $orderby                   Comment status or array of statuses. To use 'meta_value'
198
	 *                                                   or 'meta_value_num', `$meta_key` must also be defined.
199
	 *                                                   To sort by a specific `$meta_query` clause, use that
200
	 *                                                   clause's array key. Accepts 'comment_agent',
201
	 *                                                   'comment_approved', 'comment_author',
202
	 *                                                   'comment_author_email', 'comment_author_IP',
203
	 *                                                   'comment_author_url', 'comment_content', 'comment_date',
204
	 *                                                   'comment_date_gmt', 'comment_ID', 'comment_karma',
205
	 *                                                   'comment_parent', 'comment_post_ID', 'comment_type',
206
	 *                                                   'user_id', 'comment__in', 'meta_value', 'meta_value_num',
207
	 *                                                   the value of $meta_key, and the array keys of
208
	 *                                                   `$meta_query`. Also accepts false, an empty array, or
209
	 *                                                   'none' to disable `ORDER BY` clause.
210
	 *                                                   Default: 'comment_date_gmt'.
211
	 *     @type string       $order                     How to order retrieved comments. Accepts 'ASC', 'DESC'.
212
	 *                                                   Default: 'DESC'.
213
	 *     @type int          $parent                    Parent ID of comment to retrieve children of.
214
	 *                                                   Default empty.
215
	 *     @type array        $parent__in                Array of parent IDs of comments to retrieve children for.
216
	 *                                                   Default empty.
217
	 *     @type array        $parent__not_in            Array of parent IDs of comments *not* to retrieve
218
	 *                                                   children for. Default empty.
219
	 *     @type array        $post_author__in           Array of author IDs to retrieve comments for.
220
	 *                                                   Default empty.
221
	 *     @type array        $post_author__not_in       Array of author IDs *not* to retrieve comments for.
222
	 *                                                   Default empty.
223
	 *     @type int          $post_ID                   Currently unused.
224
	 *     @type int          $post_id                   Limit results to those affiliated with a given post ID.
225
	 *                                                   Default 0.
226
	 *     @type array        $post__in                  Array of post IDs to include affiliated comments for.
227
	 *                                                   Default empty.
228
	 *     @type array        $post__not_in              Array of post IDs to exclude affiliated comments for.
229
	 *                                                   Default empty.
230
	 *     @type int          $post_author               Post author ID to limit results by. Default empty.
231
	 *     @type string|array $post_status               Post status or array of post statuses to retrieve
232
	 *                                                   affiliated comments for. Pass 'any' to match any value.
233
	 *                                                   Default empty.
234
	 *     @type string       $post_type                 Post type or array of post types to retrieve affiliated
235
	 *                                                   comments for. Pass 'any' to match any value. Default empty.
236
	 *     @type string       $post_name                 Post name to retrieve affiliated comments for.
237
	 *                                                   Default empty.
238
	 *     @type int          $post_parent               Post parent ID to retrieve affiliated comments for.
239
	 *                                                   Default empty.
240
	 *     @type string       $search                    Search term(s) to retrieve matching comments for.
241
	 *                                                   Default empty.
242
	 *     @type string       $status                    Comment status to limit results by. Accepts 'hold'
243
	 *                                                   (`comment_status=0`), 'approve' (`comment_status=1`),
244
	 *                                                   'all', or a custom comment status. Default 'all'.
245
	 *     @type string|array $type                      Include comments of a given type, or array of types.
246
	 *                                                   Accepts 'comment', 'pings' (includes 'pingback' and
247
	 *                                                   'trackback'), or anycustom type string. Default empty.
248
	 *     @type array        $type__in                  Include comments from a given array of comment types.
249
	 *                                                   Default empty.
250
	 *     @type array        $type__not_in              Exclude comments from a given array of comment types.
251
	 *                                                   Default empty.
252
	 *     @type int          $user_id                   Include comments for a specific user ID. Default empty.
253
	 *     @type bool|string  $hierarchical              Whether to include comment descendants in the results.
254
	 *                                                   'threaded' returns a tree, with each comment's children
255
	 *                                                   stored in a `children` property on the `WP_Comment`
256
	 *                                                   object. 'flat' returns a flat array of found comments plus
257
	 *                                                   their children. Pass `false` to leave out descendants.
258
	 *                                                   The parameter is ignored (forced to `false`) when
259
	 *                                                   `$fields` is 'ids' or 'counts'. Accepts 'threaded',
260
	 *                                                   'flat', or false. Default: false.
261
 	 *     @type string       $cache_domain              Unique cache key to be produced when this query is stored in
262
	 *                                                   an object cache. Default is 'core'.
263
	 *     @type bool         $update_comment_meta_cache Whether to prime the metadata cache for found comments.
264
	 *                                                   Default true.
265
	 *     @type bool         $update_comment_post_cache Whether to prime the cache for comment posts.
266
	 *                                                   Default false.
267
	 * }
268
	 */
269
	public function __construct( $query = '' ) {
270
		$this->db = $GLOBALS['wpdb'];
271
272
		$this->query_var_defaults = array(
273
			'author_email' => '',
274
			'author_url' => '',
275
			'author__in' => '',
276
			'author__not_in' => '',
277
			'include_unapproved' => '',
278
			'fields' => '',
279
			'ID' => '',
280
			'comment__in' => '',
281
			'comment__not_in' => '',
282
			'karma' => '',
283
			'number' => '',
284
			'offset' => '',
285
			'no_found_rows' => true,
286
			'orderby' => '',
287
			'order' => 'DESC',
288
			'parent' => '',
289
			'parent__in' => '',
290
			'parent__not_in' => '',
291
			'post_author__in' => '',
292
			'post_author__not_in' => '',
293
			'post_ID' => '',
294
			'post_id' => 0,
295
			'post__in' => '',
296
			'post__not_in' => '',
297
			'post_author' => '',
298
			'post_name' => '',
299
			'post_parent' => '',
300
			'post_status' => '',
301
			'post_type' => '',
302
			'status' => 'all',
303
			'type' => '',
304
			'type__in' => '',
305
			'type__not_in' => '',
306
			'user_id' => '',
307
			'search' => '',
308
			'count' => false,
309
			'meta_key' => '',
310
			'meta_value' => '',
311
			'meta_query' => '',
312
			'date_query' => null, // See WP_Date_Query
313
			'hierarchical' => false,
314
			'cache_domain' => 'core',
315
			'update_comment_meta_cache' => true,
316
			'update_comment_post_cache' => false,
317
		);
318
319
		if ( ! empty( $query ) ) {
320
			$this->query( $query );
321
		}
322
	}
323
324
	/**
325
	 * Parse arguments passed to the comment query with default query parameters.
326
	 *
327
	 * @since 4.2.0 Extracted from WP_Comment_Query::query().
328
	 *
329
	 * @access public
330
	 *
331
	 * @param string|array $query WP_Comment_Query arguments. See WP_Comment_Query::__construct()
332
	 */
333 View Code Duplication
	public function parse_query( $query = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
334
		if ( empty( $query ) ) {
335
			$query = $this->query_vars;
336
		}
337
338
		$this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
339
340
		/**
341
		 * Fires after the comment query vars have been parsed.
342
		 *
343
		 * @since 4.2.0
344
		 *
345
		 * @param WP_Comment_Query &$this The WP_Comment_Query instance (passed by reference).
346
		 */
347
		do_action_ref_array( 'parse_comment_query', array( &$this ) );
348
	}
349
350
	/**
351
	 * Sets up the WordPress query for retrieving comments.
352
	 *
353
	 * @since 3.1.0
354
	 * @since 4.1.0 Introduced 'comment__in', 'comment__not_in', 'post_author__in',
355
	 *              'post_author__not_in', 'author__in', 'author__not_in', 'post__in',
356
	 *              'post__not_in', 'include_unapproved', 'type__in', and 'type__not_in'
357
	 *              arguments to $query_vars.
358
	 * @since 4.2.0 Moved parsing to WP_Comment_Query::parse_query().
359
	 * @access public
360
	 *
361
	 * @param string|array $query Array or URL query string of parameters.
362
	 * @return array|int List of comments, or number of comments when 'count' is passed as a query var.
363
	 */
364
	public function query( $query ) {
365
		$this->query_vars = wp_parse_args( $query );
366
		return $this->get_comments();
367
	}
368
369
	/**
370
	 * Get a list of comments matching the query vars.
371
	 *
372
	 * @since 4.2.0
373
	 * @access public
374
	 *
375
	 * @return int|array List of comments or number of found comments if `$count` argument is true.
376
	 */
377
	public function get_comments() {
378
		$this->parse_query();
379
380
		// Parse meta query
381
		$this->meta_query = new WP_Meta_Query();
382
		$this->meta_query->parse_query_vars( $this->query_vars );
383
384
		/**
385
		 * Fires before comments are retrieved.
386
		 *
387
		 * @since 3.1.0
388
		 *
389
		 * @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference.
390
		 */
391
		do_action_ref_array( 'pre_get_comments', array( &$this ) );
392
393
		// Reparse query vars, in case they were modified in a 'pre_get_comments' callback.
394
		$this->meta_query->parse_query_vars( $this->query_vars );
395
		if ( ! empty( $this->meta_query->queries ) ) {
396
			$this->meta_query_clauses = $this->meta_query->get_sql( 'comment', $this->db->comments, 'comment_ID', $this );
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->meta_query->get_s...s, 'comment_ID', $this) can also be of type false. However, the property $meta_query_clauses is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
397
		}
398
399
		// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
400
		$key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
401
		$last_changed = wp_cache_get( 'last_changed', 'comment' );
402
		if ( ! $last_changed ) {
403
			$last_changed = microtime();
404
			wp_cache_set( 'last_changed', $last_changed, 'comment' );
405
		}
406
407
		$cache_key   = "get_comments:$key:$last_changed";
408
		$cache_value = wp_cache_get( $cache_key, 'comment' );
409
		if ( false === $cache_value ) {
410
			$comment_ids = $this->get_comment_ids();
411
			if ( $comment_ids ) {
412
				$this->set_found_comments();
413
			}
414
415
			$cache_value = array(
416
				'comment_ids'    => $comment_ids,
417
				'found_comments' => $this->found_comments,
418
			);
419
			wp_cache_add( $cache_key, $cache_value, 'comment' );
420
		} else {
421
			$comment_ids          = $cache_value['comment_ids'];
422
			$this->found_comments = $cache_value['found_comments'];
423
		}
424
425
		if ( $this->found_comments && $this->query_vars['number'] ) {
426
			$this->max_num_pages = ceil( $this->found_comments / $this->query_vars['number'] );
0 ignored issues
show
Documentation Bug introduced by
The property $max_num_pages was declared of type integer, but ceil($this->found_commen...->query_vars['number']) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
427
		}
428
429
		// If querying for a count only, there's nothing more to do.
430
		if ( $this->query_vars['count'] ) {
431
			// $comment_ids is actually a count in this case.
432
			return intval( $comment_ids );
433
		}
434
435
		$comment_ids = array_map( 'intval', $comment_ids );
436
437
		if ( 'ids' == $this->query_vars['fields'] ) {
438
			$this->comments = $comment_ids;
439
			return $this->comments;
440
		}
441
442
		_prime_comment_caches( $comment_ids, $this->query_vars['update_comment_meta_cache'] );
443
444
		// Fetch full comment objects from the primed cache.
445
		$_comments = array();
446
		foreach ( $comment_ids as $comment_id ) {
447
			if ( $_comment = get_comment( $comment_id ) ) {
448
				$_comments[] = $_comment;
449
			}
450
		}
451
452
		// Prime comment post caches.
453
		if ( $this->query_vars['update_comment_post_cache'] ) {
454
			$comment_post_ids = array();
455
			foreach ( $_comments as $_comment ) {
456
				$comment_post_ids[] = $_comment->comment_post_ID;
457
			}
458
459
			_prime_post_caches( $comment_post_ids, false, false );
460
		}
461
462
		/**
463
		 * Filters the comment query results.
464
		 *
465
		 * @since 3.1.0
466
		 *
467
		 * @param array            $results  An array of comments.
468
		 * @param WP_Comment_Query &$this    Current instance of WP_Comment_Query, passed by reference.
469
		 */
470
		$_comments = apply_filters_ref_array( 'the_comments', array( $_comments, &$this ) );
471
472
		// Convert to WP_Comment instances
473
		$comments = array_map( 'get_comment', $_comments );
474
475
		if ( $this->query_vars['hierarchical'] ) {
476
			$comments = $this->fill_descendants( $comments );
477
		}
478
479
		$this->comments = $comments;
480
		return $this->comments;
481
	}
482
483
	/**
484
	 * Used internally to get a list of comment IDs matching the query vars.
485
	 *
486
	 * @since 4.4.0
487
	 * @access protected
488
	 */
489
	protected function get_comment_ids() {
490
		// Assemble clauses related to 'comment_approved'.
491
		$approved_clauses = array();
492
493
		// 'status' accepts an array or a comma-separated string.
494
		$status_clauses = array();
495
		$statuses = $this->query_vars['status'];
496
		if ( ! is_array( $statuses ) ) {
497
			$statuses = preg_split( '/[\s,]+/', $statuses );
498
		}
499
500
		// 'any' overrides other statuses.
501
		if ( ! in_array( 'any', $statuses ) ) {
502
			foreach ( $statuses as $status ) {
503
				switch ( $status ) {
504
					case 'hold' :
505
						$status_clauses[] = "comment_approved = '0'";
506
						break;
507
508
					case 'approve' :
509
						$status_clauses[] = "comment_approved = '1'";
510
						break;
511
512
					case 'all' :
513
					case '' :
514
						$status_clauses[] = "( comment_approved = '0' OR comment_approved = '1' )";
515
						break;
516
517
					default :
518
						$status_clauses[] = $this->db->prepare( "comment_approved = %s", $status );
519
						break;
520
				}
521
			}
522
523
			if ( ! empty( $status_clauses ) ) {
524
				$approved_clauses[] = '( ' . implode( ' OR ', $status_clauses ) . ' )';
525
			}
526
		}
527
528
		// User IDs or emails whose unapproved comments are included, regardless of $status.
529
		if ( ! empty( $this->query_vars['include_unapproved'] ) ) {
530
			$include_unapproved = $this->query_vars['include_unapproved'];
531
532
			// Accepts arrays or comma-separated strings.
533
			if ( ! is_array( $include_unapproved ) ) {
534
				$include_unapproved = preg_split( '/[\s,]+/', $include_unapproved );
535
			}
536
537
			$unapproved_ids = $unapproved_emails = array();
538
			foreach ( $include_unapproved as $unapproved_identifier ) {
539
				// Numeric values are assumed to be user ids.
540
				if ( is_numeric( $unapproved_identifier ) ) {
541
					$approved_clauses[] = $this->db->prepare( "( user_id = %d AND comment_approved = '0' )", $unapproved_identifier );
542
543
				// Otherwise we match against email addresses.
544
				} else {
545
					$approved_clauses[] = $this->db->prepare( "( comment_author_email = %s AND comment_approved = '0' )", $unapproved_identifier );
546
				}
547
			}
548
		}
549
550
		// Collapse comment_approved clauses into a single OR-separated clause.
551
		if ( ! empty( $approved_clauses ) ) {
552
			if ( 1 === count( $approved_clauses ) ) {
553
				$this->sql_clauses['where']['approved'] = $approved_clauses[0];
554
			} else {
555
				$this->sql_clauses['where']['approved'] = '( ' . implode( ' OR ', $approved_clauses ) . ' )';
556
			}
557
		}
558
559
		$order = ( 'ASC' == strtoupper( $this->query_vars['order'] ) ) ? 'ASC' : 'DESC';
560
561
		// Disable ORDER BY with 'none', an empty array, or boolean false.
562
		if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) {
563
			$orderby = '';
564
		} elseif ( ! empty( $this->query_vars['orderby'] ) ) {
565
			$ordersby = is_array( $this->query_vars['orderby'] ) ?
566
				$this->query_vars['orderby'] :
567
				preg_split( '/[,\s]/', $this->query_vars['orderby'] );
568
569
			$orderby_array = array();
570
			$found_orderby_comment_ID = false;
571
			foreach ( $ordersby as $_key => $_value ) {
572
				if ( ! $_value ) {
573
					continue;
574
				}
575
576
				if ( is_int( $_key ) ) {
577
					$_orderby = $_value;
578
					$_order = $order;
579
				} else {
580
					$_orderby = $_key;
581
					$_order = $_value;
582
				}
583
584
				if ( ! $found_orderby_comment_ID && in_array( $_orderby, array( 'comment_ID', 'comment__in' ) ) ) {
585
					$found_orderby_comment_ID = true;
586
				}
587
588
				$parsed = $this->parse_orderby( $_orderby );
589
590
				if ( ! $parsed ) {
591
					continue;
592
				}
593
594
				if ( 'comment__in' === $_orderby ) {
595
					$orderby_array[] = $parsed;
596
					continue;
597
				}
598
599
				$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
600
			}
601
602
			// If no valid clauses were found, order by comment_date_gmt.
603
			if ( empty( $orderby_array ) ) {
604
				$orderby_array[] = "{$this->db->comments}.comment_date_gmt $order";
605
			}
606
607
			// To ensure determinate sorting, always include a comment_ID clause.
608
			if ( ! $found_orderby_comment_ID ) {
609
				$comment_ID_order = '';
610
611
				// Inherit order from comment_date or comment_date_gmt, if available.
612
				foreach ( $orderby_array as $orderby_clause ) {
613
					if ( preg_match( '/comment_date(?:_gmt)*\ (ASC|DESC)/', $orderby_clause, $match ) ) {
614
						$comment_ID_order = $match[1];
615
						break;
616
					}
617
				}
618
619
				// If no date-related order is available, use the date from the first available clause.
620
				if ( ! $comment_ID_order ) {
621
					foreach ( $orderby_array as $orderby_clause ) {
622
						if ( false !== strpos( 'ASC', $orderby_clause ) ) {
623
							$comment_ID_order = 'ASC';
624
						} else {
625
							$comment_ID_order = 'DESC';
626
						}
627
628
						break;
629
					}
630
				}
631
632
				// Default to DESC.
633
				if ( ! $comment_ID_order ) {
634
					$comment_ID_order = 'DESC';
635
				}
636
637
				$orderby_array[] = "{$this->db->comments}.comment_ID $comment_ID_order";
638
			}
639
640
			$orderby = implode( ', ', $orderby_array );
641
		} else {
642
			$orderby = "{$this->db->comments}.comment_date_gmt $order";
643
		}
644
645
		$number = absint( $this->query_vars['number'] );
646
		$offset = absint( $this->query_vars['offset'] );
647
648 View Code Duplication
		if ( ! empty( $number ) ) {
649
			if ( $offset ) {
650
				$limits = 'LIMIT ' . $offset . ',' . $number;
651
			} else {
652
				$limits = 'LIMIT ' . $number;
653
			}
654
		}
655
656
		if ( $this->query_vars['count'] ) {
657
			$fields = 'COUNT(*)';
658
		} else {
659
			$fields = "{$this->db->comments}.comment_ID";
660
		}
661
662
		$post_id = absint( $this->query_vars['post_id'] );
663 View Code Duplication
		if ( ! empty( $post_id ) ) {
664
			$this->sql_clauses['where']['post_id'] = $this->db->prepare( 'comment_post_ID = %d', $post_id );
665
		}
666
667
		// Parse comment IDs for an IN clause.
668
		if ( ! empty( $this->query_vars['comment__in'] ) ) {
669
			$this->sql_clauses['where']['comment__in'] = "{$this->db->comments}.comment_ID IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['comment__in'] ) ) . ' )';
670
		}
671
672
		// Parse comment IDs for a NOT IN clause.
673
		if ( ! empty( $this->query_vars['comment__not_in'] ) ) {
674
			$this->sql_clauses['where']['comment__not_in'] = "{$this->db->comments}.comment_ID NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['comment__not_in'] ) ) . ' )';
675
		}
676
677
		// Parse comment parent IDs for an IN clause.
678
		if ( ! empty( $this->query_vars['parent__in'] ) ) {
679
			$this->sql_clauses['where']['parent__in'] = 'comment_parent IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['parent__in'] ) ) . ' )';
680
		}
681
682
		// Parse comment parent IDs for a NOT IN clause.
683
		if ( ! empty( $this->query_vars['parent__not_in'] ) ) {
684
			$this->sql_clauses['where']['parent__not_in'] = 'comment_parent NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['parent__not_in'] ) ) . ' )';
685
		}
686
687
		// Parse comment post IDs for an IN clause.
688
		if ( ! empty( $this->query_vars['post__in'] ) ) {
689
			$this->sql_clauses['where']['post__in'] = 'comment_post_ID IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post__in'] ) ) . ' )';
690
		}
691
692
		// Parse comment post IDs for a NOT IN clause.
693
		if ( ! empty( $this->query_vars['post__not_in'] ) ) {
694
			$this->sql_clauses['where']['post__not_in'] = 'comment_post_ID NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post__not_in'] ) ) . ' )';
695
		}
696
697 View Code Duplication
		if ( '' !== $this->query_vars['author_email'] ) {
698
			$this->sql_clauses['where']['author_email'] = $this->db->prepare( 'comment_author_email = %s', $this->query_vars['author_email'] );
699
		}
700
701 View Code Duplication
		if ( '' !== $this->query_vars['author_url'] ) {
702
			$this->sql_clauses['where']['author_url'] = $this->db->prepare( 'comment_author_url = %s', $this->query_vars['author_url'] );
703
		}
704
705 View Code Duplication
		if ( '' !== $this->query_vars['karma'] ) {
706
			$this->sql_clauses['where']['karma'] = $this->db->prepare( 'comment_karma = %d', $this->query_vars['karma'] );
707
		}
708
709
		// Filtering by comment_type: 'type', 'type__in', 'type__not_in'.
710
		$raw_types = array(
711
			'IN' => array_merge( (array) $this->query_vars['type'], (array) $this->query_vars['type__in'] ),
712
			'NOT IN' => (array) $this->query_vars['type__not_in'],
713
		);
714
715
		$comment_types = array();
716
		foreach ( $raw_types as $operator => $_raw_types ) {
717
			$_raw_types = array_unique( $_raw_types );
718
719
			foreach ( $_raw_types as $type ) {
720
				switch ( $type ) {
721
					// An empty translates to 'all', for backward compatibility
722
					case '':
723
					case 'all' :
724
						break;
725
726
					case 'comment':
727
					case 'comments':
728
						$comment_types[ $operator ][] = "''";
729
						break;
730
731
					case 'pings':
732
						$comment_types[ $operator ][] = "'pingback'";
733
						$comment_types[ $operator ][] = "'trackback'";
734
						break;
735
736
					default:
737
						$comment_types[ $operator ][] = $this->db->prepare( '%s', $type );
738
						break;
739
				}
740
			}
741
742
			if ( ! empty( $comment_types[ $operator ] ) ) {
743
				$types_sql = implode( ', ', $comment_types[ $operator ] );
744
				$this->sql_clauses['where']['comment_type__' . strtolower( str_replace( ' ', '_', $operator ) ) ] = "comment_type $operator ($types_sql)";
745
			}
746
		}
747
748
		$parent = $this->query_vars['parent'];
749
		if ( $this->query_vars['hierarchical'] && ! $parent ) {
750
			$parent = 0;
751
		}
752
753
		if ( '' !== $parent ) {
754
			$this->sql_clauses['where']['parent'] = $this->db->prepare( 'comment_parent = %d', $parent );
755
		}
756
757
		if ( is_array( $this->query_vars['user_id'] ) ) {
758
			$this->sql_clauses['where']['user_id'] = 'user_id IN (' . implode( ',', array_map( 'absint', $this->query_vars['user_id'] ) ) . ')';
759 View Code Duplication
		} elseif ( '' !== $this->query_vars['user_id'] ) {
760
			$this->sql_clauses['where']['user_id'] = $this->db->prepare( 'user_id = %d', $this->query_vars['user_id'] );
761
		}
762
763
		// Falsy search strings are ignored.
764
		if ( strlen( $this->query_vars['search'] ) ) {
765
			$search_sql = $this->get_search_sql(
766
				$this->query_vars['search'],
767
				array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_content' )
768
			);
769
770
			// Strip leading 'AND'.
771
			$this->sql_clauses['where']['search'] = preg_replace( '/^\s*AND\s*/', '', $search_sql );
772
		}
773
774
		// If any post-related query vars are passed, join the posts table.
775
		$join_posts_table = false;
776
		$plucked = wp_array_slice_assoc( $this->query_vars, array( 'post_author', 'post_name', 'post_parent' ) );
777
		$post_fields = array_filter( $plucked );
778
779
		if ( ! empty( $post_fields ) ) {
780
			$join_posts_table = true;
781
			foreach ( $post_fields as $field_name => $field_value ) {
782
				// $field_value may be an array.
783
				$esses = array_fill( 0, count( (array) $field_value ), '%s' );
784
				$this->sql_clauses['where'][ $field_name ] = $this->db->prepare( " {$this->db->posts}.{$field_name} IN (" . implode( ',', $esses ) . ')', $field_value );
785
			}
786
		}
787
788
		// 'post_status' and 'post_type' are handled separately, due to the specialized behavior of 'any'.
789
		foreach ( array( 'post_status', 'post_type' ) as $field_name ) {
790
			$q_values = array();
791
			if ( ! empty( $this->query_vars[ $field_name ] ) ) {
792
				$q_values = $this->query_vars[ $field_name ];
793
				if ( ! is_array( $q_values ) ) {
794
					$q_values = explode( ',', $q_values );
795
				}
796
797
				// 'any' will cause the query var to be ignored.
798
				if ( in_array( 'any', $q_values, true ) || empty( $q_values ) ) {
799
					continue;
800
				}
801
802
				$join_posts_table = true;
803
804
				$esses = array_fill( 0, count( $q_values ), '%s' );
805
				$this->sql_clauses['where'][ $field_name ] = $this->db->prepare( " {$this->db->posts}.{$field_name} IN (" . implode( ',', $esses ) . ")", $q_values );
806
			}
807
		}
808
809
		// Comment author IDs for an IN clause.
810
		if ( ! empty( $this->query_vars['author__in'] ) ) {
811
			$this->sql_clauses['where']['author__in'] = 'user_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['author__in'] ) ) . ' )';
812
		}
813
814
		// Comment author IDs for a NOT IN clause.
815
		if ( ! empty( $this->query_vars['author__not_in'] ) ) {
816
			$this->sql_clauses['where']['author__not_in'] = 'user_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['author__not_in'] ) ) . ' )';
817
		}
818
819
		// Post author IDs for an IN clause.
820 View Code Duplication
		if ( ! empty( $this->query_vars['post_author__in'] ) ) {
821
			$join_posts_table = true;
822
			$this->sql_clauses['where']['post_author__in'] = 'post_author IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post_author__in'] ) ) . ' )';
823
		}
824
825
		// Post author IDs for a NOT IN clause.
826 View Code Duplication
		if ( ! empty( $this->query_vars['post_author__not_in'] ) ) {
827
			$join_posts_table = true;
828
			$this->sql_clauses['where']['post_author__not_in'] = 'post_author NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post_author__not_in'] ) ) . ' )';
829
		}
830
831
		$join = '';
832
833
		if ( $join_posts_table ) {
834
			$join .= "JOIN {$this->db->posts} ON {$this->db->posts}.ID = {$this->db->comments}.comment_post_ID";
835
		}
836
837
		if ( ! empty( $this->meta_query_clauses ) ) {
838
			$join .= $this->meta_query_clauses['join'];
839
840
			// Strip leading 'AND'.
841
			$this->sql_clauses['where']['meta_query'] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] );
842
843
			if ( ! $this->query_vars['count'] ) {
844
				$groupby = "{$this->db->comments}.comment_ID";
845
			}
846
		}
847
848
		if ( ! empty( $this->query_vars['date_query'] ) && is_array( $this->query_vars['date_query'] ) ) {
849
			$this->date_query = new WP_Date_Query( $this->query_vars['date_query'], 'comment_date' );
850
			$this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() );
851
		}
852
853
		$where = implode( ' AND ', $this->sql_clauses['where'] );
854
855
		$pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
856
		/**
857
		 * Filters the comment query clauses.
858
		 *
859
		 * @since 3.1.0
860
		 *
861
		 * @param array            $pieces A compacted array of comment query clauses.
862
		 * @param WP_Comment_Query &$this  Current instance of WP_Comment_Query, passed by reference.
863
		 */
864
		$clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );
865
866
		$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
867
		$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
868
		$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
869
		$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
870
		$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
871
		$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
872
873
		$this->filtered_where_clause = $where;
874
875
		if ( $where ) {
876
			$where = 'WHERE ' . $where;
877
		}
878
879
		if ( $groupby ) {
880
			$groupby = 'GROUP BY ' . $groupby;
881
		}
882
883
		if ( $orderby ) {
884
			$orderby = "ORDER BY $orderby";
885
		}
886
887
		$found_rows = '';
888
		if ( ! $this->query_vars['no_found_rows'] ) {
889
			$found_rows = 'SQL_CALC_FOUND_ROWS';
890
		}
891
892
		$this->sql_clauses['select']  = "SELECT $found_rows $fields";
893
		$this->sql_clauses['from']    = "FROM {$this->db->comments} $join";
894
		$this->sql_clauses['groupby'] = $groupby;
895
		$this->sql_clauses['orderby'] = $orderby;
896
		$this->sql_clauses['limits']  = $limits;
897
898
		$this->request = "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} {$this->sql_clauses['orderby']} {$this->sql_clauses['limits']}";
899
900
		if ( $this->query_vars['count'] ) {
901
			return intval( $this->db->get_var( $this->request ) );
902
		} else {
903
			$comment_ids = $this->db->get_col( $this->request );
904
			return array_map( 'intval', $comment_ids );
905
		}
906
	}
907
908
	/**
909
	 * Populates found_comments and max_num_pages properties for the current
910
	 * query if the limit clause was used.
911
	 *
912
	 * @since 4.6.0
913
	 * @access private
914
	 */
915 View Code Duplication
	private function set_found_comments() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
916
		if ( $this->query_vars['number'] && ! $this->query_vars['no_found_rows'] ) {
917
			/**
918
			 * Filters the query used to retrieve found comment count.
919
			 *
920
			 * @since 4.4.0
921
			 *
922
			 * @param string           $found_comments_query SQL query. Default 'SELECT FOUND_ROWS()'.
923
			 * @param WP_Comment_Query $comment_query        The `WP_Comment_Query` instance.
924
			 */
925
			$found_comments_query = apply_filters( 'found_comments_query', 'SELECT FOUND_ROWS()', $this );
926
927
			$this->found_comments = (int) $this->db->get_var( $found_comments_query );
928
		}
929
	}
930
931
	/**
932
	 * Fetch descendants for located comments.
933
	 *
934
	 * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch
935
	 * the descendant trees for all matched top-level comments.
936
	 *
937
	 * @since 4.4.0
938
	 *
939
	 * @param array $comments Array of top-level comments whose descendants should be filled in.
940
	 * @return array
941
	 */
942
	protected function fill_descendants( $comments ) {
943
		$levels = array(
944
			0 => wp_list_pluck( $comments, 'comment_ID' ),
945
		);
946
947
		/*
948
		 * The WHERE clause for the descendant query is the same as for the top-level
949
		 * query, minus the `parent`, `parent__in`, and `parent__not_in` sub-clauses.
950
		 */
951
		$_where = $this->filtered_where_clause;
952
		$exclude_keys = array( 'parent', 'parent__in', 'parent__not_in' );
953
		foreach ( $exclude_keys as $exclude_key ) {
954
			if ( isset( $this->sql_clauses['where'][ $exclude_key ] ) ) {
955
				$clause = $this->sql_clauses['where'][ $exclude_key ];
956
957
				// Strip the clause as well as any adjacent ANDs.
958
				$pattern = '|(?:AND)?\s*' . $clause . '\s*(?:AND)?|';
959
				$_where_parts = preg_split( $pattern, $_where );
960
961
				// Remove empties.
962
				$_where_parts = array_filter( array_map( 'trim', $_where_parts ) );
963
964
				// Reassemble with an AND.
965
				$_where = implode( ' AND ', $_where_parts );
966
			}
967
		}
968
969
		$key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
970
		$last_changed = wp_cache_get( 'last_changed', 'comment' );
971
		if ( ! $last_changed ) {
972
			$last_changed = microtime();
973
			wp_cache_set( 'last_changed', $last_changed, 'comment' );
974
		}
975
976
		// Fetch an entire level of the descendant tree at a time.
977
		$level = 0;
978
		do {
979
			// Parent-child relationships may be cached. Only query for those that are not.
980
			$child_ids = $uncached_parent_ids = array();
981
			$_parent_ids = $levels[ $level ];
982
			foreach ( $_parent_ids as $parent_id ) {
983
				$cache_key = "get_comment_child_ids:$parent_id:$key:$last_changed";
984
				$parent_child_ids = wp_cache_get( $cache_key, 'comment' );
985
				if ( false !== $parent_child_ids ) {
986
					$child_ids = array_merge( $child_ids, $parent_child_ids );
987
				} else {
988
					$uncached_parent_ids[] = $parent_id;
989
				}
990
			}
991
992
			if ( $uncached_parent_ids ) {
993
				$where = 'WHERE ' . $_where . ' AND comment_parent IN (' . implode( ',', array_map( 'intval', $uncached_parent_ids ) ) . ')';
994
				$level_comments = $this->db->get_results( "SELECT {$this->db->comments}.comment_ID, {$this->db->comments}.comment_parent {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} ORDER BY comment_date_gmt ASC, comment_ID ASC" );
995
996
				// Cache parent-child relationships.
997
				$parent_map = array_fill_keys( $uncached_parent_ids, array() );
998
				foreach ( $level_comments as $level_comment ) {
0 ignored issues
show
Bug introduced by
The expression $level_comments of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
999
					$parent_map[ $level_comment->comment_parent ][] = $level_comment->comment_ID;
1000
					$child_ids[] = $level_comment->comment_ID;
1001
				}
1002
1003
				foreach ( $parent_map as $parent_id => $children ) {
1004
					$cache_key = "get_comment_child_ids:$parent_id:$key:$last_changed";
1005
					wp_cache_set( $cache_key, $children, 'comment' );
1006
				}
1007
			}
1008
1009
			$level++;
1010
			$levels[ $level ] = $child_ids;
1011
		} while ( $child_ids );
1012
1013
		// Prime comment caches for non-top-level comments.
1014
		$descendant_ids = array();
1015
		for ( $i = 1, $c = count( $levels ); $i <= $c; $i++ ) {
1016
			if ( empty( $levels[ $i ] ) ) {
1017
				continue;
1018
			}
1019
			$descendant_ids = array_merge( $descendant_ids, $levels[ $i ] );
1020
		}
1021
1022
		_prime_comment_caches( $descendant_ids, $this->query_vars['update_comment_meta_cache'] );
1023
1024
		// Assemble a flat array of all comments + descendants.
1025
		$all_comments = $comments;
1026
		foreach ( $descendant_ids as $descendant_id ) {
1027
			$all_comments[] = get_comment( $descendant_id );
1028
		}
1029
1030
		// If a threaded representation was requested, build the tree.
1031
		if ( 'threaded' === $this->query_vars['hierarchical'] ) {
1032
			$threaded_comments = $ref = array();
1033
			foreach ( $all_comments as $k => $c ) {
1034
				$_c = get_comment( $c->comment_ID );
1035
1036
				// If the comment isn't in the reference array, it goes in the top level of the thread.
1037
				if ( ! isset( $ref[ $c->comment_parent ] ) ) {
1038
					$threaded_comments[ $_c->comment_ID ] = $_c;
1039
					$ref[ $_c->comment_ID ] = $threaded_comments[ $_c->comment_ID ];
1040
1041
				// Otherwise, set it as a child of its parent.
1042
				} else {
1043
1044
					$ref[ $_c->comment_parent ]->add_child( $_c );
1045
					$ref[ $_c->comment_ID ] = $ref[ $_c->comment_parent ]->get_child( $_c->comment_ID );
1046
				}
1047
			}
1048
1049
			// Set the 'populated_children' flag, to ensure additional database queries aren't run.
1050
			foreach ( $ref as $_ref ) {
1051
				$_ref->populated_children( true );
1052
			}
1053
1054
			$comments = $threaded_comments;
1055
		} else {
1056
			$comments = $all_comments;
1057
		}
1058
1059
		return $comments;
1060
	}
1061
1062
	/**
1063
	 * Used internally to generate an SQL string for searching across multiple columns
1064
	 *
1065
	 * @since 3.1.0
1066
	 * @access protected
1067
	 *
1068
	 * @param string $string
1069
	 * @param array $cols
1070
	 * @return string
1071
	 */
1072 View Code Duplication
	protected function get_search_sql( $string, $cols ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1073
		$like = '%' . $this->db->esc_like( $string ) . '%';
1074
1075
		$searches = array();
1076
		foreach ( $cols as $col ) {
1077
			$searches[] = $this->db->prepare( "$col LIKE %s", $like );
1078
		}
1079
1080
		return ' AND (' . implode(' OR ', $searches) . ')';
1081
	}
1082
1083
	/**
1084
	 * Parse and sanitize 'orderby' keys passed to the comment query.
1085
	 *
1086
	 * @since 4.2.0
1087
	 * @access protected
1088
	 *
1089
	 * @param string $orderby Alias for the field to order by.
1090
	 * @return string|false Value to used in the ORDER clause. False otherwise.
1091
	 */
1092
	protected function parse_orderby( $orderby ) {
1093
		$allowed_keys = array(
1094
			'comment_agent',
1095
			'comment_approved',
1096
			'comment_author',
1097
			'comment_author_email',
1098
			'comment_author_IP',
1099
			'comment_author_url',
1100
			'comment_content',
1101
			'comment_date',
1102
			'comment_date_gmt',
1103
			'comment_ID',
1104
			'comment_karma',
1105
			'comment_parent',
1106
			'comment_post_ID',
1107
			'comment_type',
1108
			'user_id',
1109
		);
1110
1111
		if ( ! empty( $this->query_vars['meta_key'] ) ) {
1112
			$allowed_keys[] = $this->query_vars['meta_key'];
1113
			$allowed_keys[] = 'meta_value';
1114
			$allowed_keys[] = 'meta_value_num';
1115
		}
1116
1117
		$meta_query_clauses = $this->meta_query->get_clauses();
1118
		if ( $meta_query_clauses ) {
1119
			$allowed_keys = array_merge( $allowed_keys, array_keys( $meta_query_clauses ) );
1120
		}
1121
1122
		$parsed = false;
1123
		if ( $orderby == $this->query_vars['meta_key'] || $orderby == 'meta_value' ) {
1124
			$parsed = "{$this->db->commentmeta}.meta_value";
1125
		} elseif ( $orderby == 'meta_value_num' ) {
1126
			$parsed = "{$this->db->commentmeta}.meta_value+0";
1127
		} elseif ( $orderby == 'comment__in' ) {
1128
			$comment__in = implode( ',', array_map( 'absint', $this->query_vars['comment__in'] ) );
1129
			$parsed = "FIELD( {$this->db->comments}.comment_ID, $comment__in )";
1130
		} elseif ( in_array( $orderby, $allowed_keys ) ) {
1131
1132
			if ( isset( $meta_query_clauses[ $orderby ] ) ) {
1133
				$meta_clause = $meta_query_clauses[ $orderby ];
1134
				$parsed = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
1135
			} else {
1136
				$parsed = "{$this->db->comments}.$orderby";
1137
			}
1138
		}
1139
1140
		return $parsed;
1141
	}
1142
1143
	/**
1144
	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
1145
	 *
1146
	 * @since 4.2.0
1147
	 * @access protected
1148
	 *
1149
	 * @param string $order The 'order' query variable.
1150
	 * @return string The sanitized 'order' query variable.
1151
	 */
1152 View Code Duplication
	protected function parse_order( $order ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1153
		if ( ! is_string( $order ) || empty( $order ) ) {
1154
			return 'DESC';
1155
		}
1156
1157
		if ( 'ASC' === strtoupper( $order ) ) {
1158
			return 'ASC';
1159
		} else {
1160
			return 'DESC';
1161
		}
1162
	}
1163
}
1164