Issues (4967)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/wp-includes/class-wp-query.php (19 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Query API: WP_Query class
4
 *
5
 * @package WordPress
6
 * @subpackage Query
7
 * @since 4.7.0
8
 */
9
10
/**
11
 * The WordPress Query class.
12
 *
13
 * @link https://codex.wordpress.org/Function_Reference/WP_Query Codex page.
14
 *
15
 * @since 1.5.0
16
 * @since 4.5.0 Removed the `$comments_popup` property.
17
 */
18
class WP_Query {
19
20
	/**
21
	 * Query vars set by the user
22
	 *
23
	 * @since 1.5.0
24
	 * @access public
25
	 * @var array
26
	 */
27
	public $query;
28
29
	/**
30
	 * Query vars, after parsing
31
	 *
32
	 * @since 1.5.0
33
	 * @access public
34
	 * @var array
35
	 */
36
	public $query_vars = array();
37
38
	/**
39
	 * Taxonomy query, as passed to get_tax_sql()
40
	 *
41
	 * @since 3.1.0
42
	 * @access public
43
	 * @var object WP_Tax_Query
44
	 */
45
	public $tax_query;
46
47
	/**
48
	 * Metadata query container
49
	 *
50
	 * @since 3.2.0
51
	 * @access public
52
	 * @var object WP_Meta_Query
53
	 */
54
	public $meta_query = false;
55
56
	/**
57
	 * Date query container
58
	 *
59
	 * @since 3.7.0
60
	 * @access public
61
	 * @var object WP_Date_Query
62
	 */
63
	public $date_query = false;
64
65
	/**
66
	 * Holds the data for a single object that is queried.
67
	 *
68
	 * Holds the contents of a post, page, category, attachment.
69
	 *
70
	 * @since 1.5.0
71
	 * @access public
72
	 * @var object|array
73
	 */
74
	public $queried_object;
75
76
	/**
77
	 * The ID of the queried object.
78
	 *
79
	 * @since 1.5.0
80
	 * @access public
81
	 * @var int
82
	 */
83
	public $queried_object_id;
84
85
	/**
86
	 * Get post database query.
87
	 *
88
	 * @since 2.0.1
89
	 * @access public
90
	 * @var string
91
	 */
92
	public $request;
93
94
	/**
95
	 * List of posts.
96
	 *
97
	 * @since 1.5.0
98
	 * @access public
99
	 * @var array
100
	 */
101
	public $posts;
102
103
	/**
104
	 * The amount of posts for the current query.
105
	 *
106
	 * @since 1.5.0
107
	 * @access public
108
	 * @var int
109
	 */
110
	public $post_count = 0;
111
112
	/**
113
	 * Index of the current item in the loop.
114
	 *
115
	 * @since 1.5.0
116
	 * @access public
117
	 * @var int
118
	 */
119
	public $current_post = -1;
120
121
	/**
122
	 * Whether the loop has started and the caller is in the loop.
123
	 *
124
	 * @since 2.0.0
125
	 * @access public
126
	 * @var bool
127
	 */
128
	public $in_the_loop = false;
129
130
	/**
131
	 * The current post.
132
	 *
133
	 * @since 1.5.0
134
	 * @access public
135
	 * @var WP_Post
136
	 */
137
	public $post;
138
139
	/**
140
	 * The list of comments for current post.
141
	 *
142
	 * @since 2.2.0
143
	 * @access public
144
	 * @var array
145
	 */
146
	public $comments;
147
148
	/**
149
	 * The amount of comments for the posts.
150
	 *
151
	 * @since 2.2.0
152
	 * @access public
153
	 * @var int
154
	 */
155
	public $comment_count = 0;
156
157
	/**
158
	 * The index of the comment in the comment loop.
159
	 *
160
	 * @since 2.2.0
161
	 * @access public
162
	 * @var int
163
	 */
164
	public $current_comment = -1;
165
166
	/**
167
	 * Current comment ID.
168
	 *
169
	 * @since 2.2.0
170
	 * @access public
171
	 * @var int
172
	 */
173
	public $comment;
174
175
	/**
176
	 * The amount of found posts for the current query.
177
	 *
178
	 * If limit clause was not used, equals $post_count.
179
	 *
180
	 * @since 2.1.0
181
	 * @access public
182
	 * @var int
183
	 */
184
	public $found_posts = 0;
185
186
	/**
187
	 * The amount of pages.
188
	 *
189
	 * @since 2.1.0
190
	 * @access public
191
	 * @var int
192
	 */
193
	public $max_num_pages = 0;
194
195
	/**
196
	 * The amount of comment pages.
197
	 *
198
	 * @since 2.7.0
199
	 * @access public
200
	 * @var int
201
	 */
202
	public $max_num_comment_pages = 0;
203
204
	/**
205
	 * Set if query is single post.
206
	 *
207
	 * @since 1.5.0
208
	 * @access public
209
	 * @var bool
210
	 */
211
	public $is_single = false;
212
213
	/**
214
	 * Set if query is preview of blog.
215
	 *
216
	 * @since 2.0.0
217
	 * @access public
218
	 * @var bool
219
	 */
220
	public $is_preview = false;
221
222
	/**
223
	 * Set if query returns a page.
224
	 *
225
	 * @since 1.5.0
226
	 * @access public
227
	 * @var bool
228
	 */
229
	public $is_page = false;
230
231
	/**
232
	 * Set if query is an archive list.
233
	 *
234
	 * @since 1.5.0
235
	 * @access public
236
	 * @var bool
237
	 */
238
	public $is_archive = false;
239
240
	/**
241
	 * Set if query is part of a date.
242
	 *
243
	 * @since 1.5.0
244
	 * @access public
245
	 * @var bool
246
	 */
247
	public $is_date = false;
248
249
	/**
250
	 * Set if query contains a year.
251
	 *
252
	 * @since 1.5.0
253
	 * @access public
254
	 * @var bool
255
	 */
256
	public $is_year = false;
257
258
	/**
259
	 * Set if query contains a month.
260
	 *
261
	 * @since 1.5.0
262
	 * @access public
263
	 * @var bool
264
	 */
265
	public $is_month = false;
266
267
	/**
268
	 * Set if query contains a day.
269
	 *
270
	 * @since 1.5.0
271
	 * @access public
272
	 * @var bool
273
	 */
274
	public $is_day = false;
275
276
	/**
277
	 * Set if query contains time.
278
	 *
279
	 * @since 1.5.0
280
	 * @access public
281
	 * @var bool
282
	 */
283
	public $is_time = false;
284
285
	/**
286
	 * Set if query contains an author.
287
	 *
288
	 * @since 1.5.0
289
	 * @access public
290
	 * @var bool
291
	 */
292
	public $is_author = false;
293
294
	/**
295
	 * Set if query contains category.
296
	 *
297
	 * @since 1.5.0
298
	 * @access public
299
	 * @var bool
300
	 */
301
	public $is_category = false;
302
303
	/**
304
	 * Set if query contains tag.
305
	 *
306
	 * @since 2.3.0
307
	 * @access public
308
	 * @var bool
309
	 */
310
	public $is_tag = false;
311
312
	/**
313
	 * Set if query contains taxonomy.
314
	 *
315
	 * @since 2.5.0
316
	 * @access public
317
	 * @var bool
318
	 */
319
	public $is_tax = false;
320
321
	/**
322
	 * Set if query was part of a search result.
323
	 *
324
	 * @since 1.5.0
325
	 * @access public
326
	 * @var bool
327
	 */
328
	public $is_search = false;
329
330
	/**
331
	 * Set if query is feed display.
332
	 *
333
	 * @since 1.5.0
334
	 * @access public
335
	 * @var bool
336
	 */
337
	public $is_feed = false;
338
339
	/**
340
	 * Set if query is comment feed display.
341
	 *
342
	 * @since 2.2.0
343
	 * @access public
344
	 * @var bool
345
	 */
346
	public $is_comment_feed = false;
347
348
	/**
349
	 * Set if query is trackback.
350
	 *
351
	 * @since 1.5.0
352
	 * @access public
353
	 * @var bool
354
	 */
355
	public $is_trackback = false;
356
357
	/**
358
	 * Set if query is blog homepage.
359
	 *
360
	 * @since 1.5.0
361
	 * @access public
362
	 * @var bool
363
	 */
364
	public $is_home = false;
365
366
	/**
367
	 * Set if query couldn't found anything.
368
	 *
369
	 * @since 1.5.0
370
	 * @access public
371
	 * @var bool
372
	 */
373
	public $is_404 = false;
374
375
	/**
376
	 * Set if query is embed.
377
	 *
378
	 * @since 4.4.0
379
	 * @access public
380
	 * @var bool
381
	 */
382
	public $is_embed = false;
383
384
	/**
385
	 * Set if query is paged
386
	 *
387
	 * @since 1.5.0
388
	 * @access public
389
	 * @var bool
390
	 */
391
	public $is_paged = false;
392
393
	/**
394
	 * Set if query is part of administration page.
395
	 *
396
	 * @since 1.5.0
397
	 * @access public
398
	 * @var bool
399
	 */
400
	public $is_admin = false;
401
402
	/**
403
	 * Set if query is an attachment.
404
	 *
405
	 * @since 2.0.0
406
	 * @access public
407
	 * @var bool
408
	 */
409
	public $is_attachment = false;
410
411
	/**
412
	 * Set if is single, is a page, or is an attachment.
413
	 *
414
	 * @since 2.1.0
415
	 * @access public
416
	 * @var bool
417
	 */
418
	public $is_singular = false;
419
420
	/**
421
	 * Set if query is for robots.
422
	 *
423
	 * @since 2.1.0
424
	 * @access public
425
	 * @var bool
426
	 */
427
	public $is_robots = false;
428
429
	/**
430
	 * Set if query contains posts.
431
	 *
432
	 * Basically, the homepage if the option isn't set for the static homepage.
433
	 *
434
	 * @since 2.1.0
435
	 * @access public
436
	 * @var bool
437
	 */
438
	public $is_posts_page = false;
439
440
	/**
441
	 * Set if query is for a post type archive.
442
	 *
443
	 * @since 3.1.0
444
	 * @access public
445
	 * @var bool
446
	 */
447
	public $is_post_type_archive = false;
448
449
	/**
450
	 * Stores the ->query_vars state like md5(serialize( $this->query_vars ) ) so we know
451
	 * whether we have to re-parse because something has changed
452
	 *
453
	 * @since 3.1.0
454
	 * @access private
455
	 * @var bool|string
456
	 */
457
	private $query_vars_hash = false;
458
459
	/**
460
	 * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
461
	 * via pre_get_posts hooks.
462
	 *
463
	 * @since 3.1.1
464
	 * @access private
465
	 */
466
	private $query_vars_changed = true;
467
468
	/**
469
	 * Set if post thumbnails are cached
470
	 *
471
	 * @since 3.2.0
472
	 * @access public
473
	 * @var bool
474
	 */
475
	 public $thumbnails_cached = false;
476
477
	/**
478
	 * Cached list of search stopwords.
479
	 *
480
	 * @since 3.7.0
481
	 * @var array
482
	 */
483
	private $stopwords;
484
485
	private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );
486
487
	private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
488
489
	/**
490
	 * Resets query flags to false.
491
	 *
492
	 * The query flags are what page info WordPress was able to figure out.
493
	 *
494
	 * @since 2.0.0
495
	 * @access private
496
	 */
497
	private function init_query_flags() {
498
		$this->is_single = false;
499
		$this->is_preview = false;
500
		$this->is_page = false;
501
		$this->is_archive = false;
502
		$this->is_date = false;
503
		$this->is_year = false;
504
		$this->is_month = false;
505
		$this->is_day = false;
506
		$this->is_time = false;
507
		$this->is_author = false;
508
		$this->is_category = false;
509
		$this->is_tag = false;
510
		$this->is_tax = false;
511
		$this->is_search = false;
512
		$this->is_feed = false;
513
		$this->is_comment_feed = false;
514
		$this->is_trackback = false;
515
		$this->is_home = false;
516
		$this->is_404 = false;
517
		$this->is_paged = false;
518
		$this->is_admin = false;
519
		$this->is_attachment = false;
520
		$this->is_singular = false;
521
		$this->is_robots = false;
522
		$this->is_posts_page = false;
523
		$this->is_post_type_archive = false;
524
	}
525
526
	/**
527
	 * Initiates object properties and sets default values.
528
	 *
529
	 * @since 1.5.0
530
	 * @access public
531
	 */
532
	public function init() {
533
		unset($this->posts);
534
		unset($this->query);
535
		$this->query_vars = array();
536
		unset($this->queried_object);
537
		unset($this->queried_object_id);
538
		$this->post_count = 0;
539
		$this->current_post = -1;
540
		$this->in_the_loop = false;
541
		unset( $this->request );
542
		unset( $this->post );
543
		unset( $this->comments );
544
		unset( $this->comment );
545
		$this->comment_count = 0;
546
		$this->current_comment = -1;
547
		$this->found_posts = 0;
548
		$this->max_num_pages = 0;
549
		$this->max_num_comment_pages = 0;
550
551
		$this->init_query_flags();
552
	}
553
554
	/**
555
	 * Reparse the query vars.
556
	 *
557
	 * @since 1.5.0
558
	 * @access public
559
	 */
560
	public function parse_query_vars() {
561
		$this->parse_query();
562
	}
563
564
	/**
565
	 * Fills in the query variables, which do not exist within the parameter.
566
	 *
567
	 * @since 2.1.0
568
	 * @since 4.4.0 Removed the `comments_popup` public query variable.
569
	 * @access public
570
	 *
571
	 * @param array $array Defined query variables.
572
	 * @return array Complete query variables with undefined ones filled in empty.
573
	 */
574
	public function fill_query_vars($array) {
575
		$keys = array(
576
			'error'
577
			, 'm'
578
			, 'p'
579
			, 'post_parent'
580
			, 'subpost'
581
			, 'subpost_id'
582
			, 'attachment'
583
			, 'attachment_id'
584
			, 'name'
585
			, 'static'
586
			, 'pagename'
587
			, 'page_id'
588
			, 'second'
589
			, 'minute'
590
			, 'hour'
591
			, 'day'
592
			, 'monthnum'
593
			, 'year'
594
			, 'w'
595
			, 'category_name'
596
			, 'tag'
597
			, 'cat'
598
			, 'tag_id'
599
			, 'author'
600
			, 'author_name'
601
			, 'feed'
602
			, 'tb'
603
			, 'paged'
604
			, 'meta_key'
605
			, 'meta_value'
606
			, 'preview'
607
			, 's'
608
			, 'sentence'
609
			, 'title'
610
			, 'fields'
611
			, 'menu_order'
612
			, 'embed'
613
		);
614
615
		foreach ( $keys as $key ) {
616
			if ( !isset($array[$key]) )
617
				$array[$key] = '';
618
		}
619
620
		$array_keys = array( 'category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in', 'post_name__in',
621
			'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'post_parent__in', 'post_parent__not_in',
622
			'author__in', 'author__not_in' );
623
624
		foreach ( $array_keys as $key ) {
625
			if ( !isset($array[$key]) )
626
				$array[$key] = array();
627
		}
628
		return $array;
629
	}
630
631
	/**
632
	 * Parse a query string and set query type booleans.
633
	 *
634
	 * @since 1.5.0
635
	 * @since 4.2.0 Introduced the ability to order by specific clauses of a `$meta_query`, by passing the clause's
636
	 *              array key to `$orderby`.
637
	 * @since 4.4.0 Introduced `$post_name__in` and `$title` parameters. `$s` was updated to support excluded
638
	 *              search terms, by prepending a hyphen.
639
	 * @since 4.5.0 Removed the `$comments_popup` parameter.
640
	 *              Introduced the `$comment_status` and `$ping_status` parameters.
641
	 *              Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts.
642
	 * @since 4.6.0 Added 'post_name__in' support for `$orderby`. Introduced the `$lazy_load_term_meta` argument.
643
	 * @access public
644
	 *
645
	 * @param string|array $query {
646
	 *     Optional. Array or string of Query parameters.
647
	 *
648
	 *     @type int          $attachment_id           Attachment post ID. Used for 'attachment' post_type.
649
	 *     @type int|string   $author                  Author ID, or comma-separated list of IDs.
650
	 *     @type string       $author_name             User 'user_nicename'.
651
	 *     @type array        $author__in              An array of author IDs to query from.
652
	 *     @type array        $author__not_in          An array of author IDs not to query from.
653
	 *     @type bool         $cache_results           Whether to cache post information. Default true.
654
	 *     @type int|string   $cat                     Category ID or comma-separated list of IDs (this or any children).
655
	 *     @type array        $category__and           An array of category IDs (AND in).
656
	 *     @type array        $category__in            An array of category IDs (OR in, no children).
657
	 *     @type array        $category__not_in        An array of category IDs (NOT in).
658
	 *     @type string       $category_name           Use category slug (not name, this or any children).
659
	 *     @type string       $comment_status          Comment status.
660
	 *     @type int          $comments_per_page       The number of comments to return per page.
661
	 *                                                 Default 'comments_per_page' option.
662
	 *     @type array        $date_query              An associative array of WP_Date_Query arguments.
663
	 *                                                 See WP_Date_Query::__construct().
664
	 *     @type int          $day                     Day of the month. Default empty. Accepts numbers 1-31.
665
	 *     @type bool         $exact                   Whether to search by exact keyword. Default false.
666
	 *     @type string|array $fields                  Which fields to return. Single field or all fields (string),
667
	 *                                                 or array of fields. 'id=>parent' uses 'id' and 'post_parent'.
668
	 *                                                 Default all fields. Accepts 'ids', 'id=>parent'.
669
	 *     @type int          $hour                    Hour of the day. Default empty. Accepts numbers 0-23.
670
	 *     @type int|bool     $ignore_sticky_posts     Whether to ignore sticky posts or not. Setting this to false
671
	 *                                                 excludes stickies from 'post__in'. Accepts 1|true, 0|false.
672
	 *                                                 Default 0|false.
673
	 *     @type int          $m                       Combination YearMonth. Accepts any four-digit year and month
674
	 *                                                 numbers 1-12. Default empty.
675
	 *     @type string       $meta_compare            Comparison operator to test the 'meta_value'.
676
	 *     @type string       $meta_key                Custom field key.
677
	 *     @type array        $meta_query              An associative array of WP_Meta_Query arguments. See WP_Meta_Query.
678
	 *     @type string       $meta_value              Custom field value.
679
	 *     @type int          $meta_value_num          Custom field value number.
680
	 *     @type int          $menu_order              The menu order of the posts.
681
	 *     @type int          $monthnum                The two-digit month. Default empty. Accepts numbers 1-12.
682
	 *     @type string       $name                    Post slug.
683
	 *     @type bool         $nopaging                Show all posts (true) or paginate (false). Default false.
684
	 *     @type bool         $no_found_rows           Whether to skip counting the total rows found. Enabling can improve
685
	 *                                                 performance. Default false.
686
	 *     @type int          $offset                  The number of posts to offset before retrieval.
687
	 *     @type string       $order                   Designates ascending or descending order of posts. Default 'DESC'.
688
	 *                                                 Accepts 'ASC', 'DESC'.
689
	 *     @type string|array $orderby                 Sort retrieved posts by parameter. One or more options may be
690
	 *                                                 passed. To use 'meta_value', or 'meta_value_num',
691
	 *                                                 'meta_key=keyname' must be also be defined. To sort by a
692
	 *                                                 specific `$meta_query` clause, use that clause's array key.
693
	 *                                                 Accepts 'none', 'name', 'author', 'date', 'title',
694
	 *                                                 'modified', 'menu_order', 'parent', 'ID', 'rand',
695
	 *                                                 'relevance', 'RAND(x)' (where 'x' is an integer seed value),
696
	 *                                                 'comment_count', 'meta_value', 'meta_value_num', 'post__in',
697
	 *                                                 'post_name__in', 'post_parent__in', and the array keys
698
	 *                                                 of `$meta_query`. Default is 'date', except when a search
699
	 *                                                 is being performed, when the default is 'relevance'.
700
	 *
701
	 *     @type int          $p                       Post ID.
702
	 *     @type int          $page                    Show the number of posts that would show up on page X of a
703
	 *                                                 static front page.
704
	 *     @type int          $paged                   The number of the current page.
705
	 *     @type int          $page_id                 Page ID.
706
	 *     @type string       $pagename                Page slug.
707
	 *     @type string       $perm                    Show posts if user has the appropriate capability.
708
	 *     @type string       $ping_status             Ping status.
709
	 *     @type array        $post__in                An array of post IDs to retrieve, sticky posts will be included
710
	 *     @type string       $post_mime_type          The mime type of the post. Used for 'attachment' post_type.
711
	 *     @type array        $post__not_in            An array of post IDs not to retrieve. Note: a string of comma-
712
	 *                                                 separated IDs will NOT work.
713
	 *     @type int          $post_parent             Page ID to retrieve child pages for. Use 0 to only retrieve
714
	 *                                                 top-level pages.
715
	 *     @type array        $post_parent__in         An array containing parent page IDs to query child pages from.
716
	 *     @type array        $post_parent__not_in     An array containing parent page IDs not to query child pages from.
717
	 *     @type string|array $post_type               A post type slug (string) or array of post type slugs.
718
	 *                                                 Default 'any' if using 'tax_query'.
719
	 *     @type string|array $post_status             A post status (string) or array of post statuses.
720
	 *     @type int          $posts_per_page          The number of posts to query for. Use -1 to request all posts.
721
	 *     @type int          $posts_per_archive_page  The number of posts to query for by archive page. Overrides
722
	 *                                                 'posts_per_page' when is_archive(), or is_search() are true.
723
	 *     @type array        $post_name__in           An array of post slugs that results must match.
724
	 *     @type string       $s                       Search keyword(s). Prepending a term with a hyphen will
725
	 *                                                 exclude posts matching that term. Eg, 'pillow -sofa' will
726
	 *                                                 return posts containing 'pillow' but not 'sofa'. The
727
	 *                                                 character used for exclusion can be modified using the
728
	 *                                                 the 'wp_query_search_exclusion_prefix' filter.
729
	 *     @type int          $second                  Second of the minute. Default empty. Accepts numbers 0-60.
730
	 *     @type bool         $sentence                Whether to search by phrase. Default false.
731
	 *     @type bool         $suppress_filters        Whether to suppress filters. Default false.
732
	 *     @type string       $tag                     Tag slug. Comma-separated (either), Plus-separated (all).
733
	 *     @type array        $tag__and                An array of tag ids (AND in).
734
	 *     @type array        $tag__in                 An array of tag ids (OR in).
735
	 *     @type array        $tag__not_in             An array of tag ids (NOT in).
736
	 *     @type int          $tag_id                  Tag id or comma-separated list of IDs.
737
	 *     @type array        $tag_slug__and           An array of tag slugs (AND in).
738
	 *     @type array        $tag_slug__in            An array of tag slugs (OR in). unless 'ignore_sticky_posts' is
739
	 *                                                 true. Note: a string of comma-separated IDs will NOT work.
740
	 *     @type array        $tax_query               An associative array of WP_Tax_Query arguments.
741
	 *                                                 See WP_Tax_Query->queries.
742
	 *     @type string       $title                   Post title.
743
	 *     @type bool         $update_post_meta_cache  Whether to update the post meta cache. Default true.
744
	 *     @type bool         $update_post_term_cache  Whether to update the post term cache. Default true.
745
	 *     @type bool         $lazy_load_term_meta     Whether to lazy-load term meta. Setting to false will
746
	 *                                                 disable cache priming for term meta, so that each
747
	 *                                                 get_term_meta() call will hit the database.
748
	 *                                                 Defaults to the value of `$update_post_term_cache`.
749
	 *     @type int          $w                       The week number of the year. Default empty. Accepts numbers 0-53.
750
	 *     @type int          $year                    The four-digit year. Default empty. Accepts any four-digit year.
751
	 * }
752
	 */
753
	public function parse_query( $query =  '' ) {
754
		if ( ! empty( $query ) ) {
755
			$this->init();
756
			$this->query = $this->query_vars = wp_parse_args( $query );
757
		} elseif ( ! isset( $this->query ) ) {
758
			$this->query = $this->query_vars;
759
		}
760
761
		$this->query_vars = $this->fill_query_vars($this->query_vars);
762
		$qv = &$this->query_vars;
763
		$this->query_vars_changed = true;
764
765
		if ( ! empty($qv['robots']) )
766
			$this->is_robots = true;
767
768
		if ( ! is_scalar( $qv['p'] ) || $qv['p'] < 0 ) {
769
			$qv['p'] = 0;
770
			$qv['error'] = '404';
771
		} else {
772
			$qv['p'] = intval( $qv['p'] );
773
		}
774
775
		$qv['page_id'] =  absint($qv['page_id']);
776
		$qv['year'] = absint($qv['year']);
777
		$qv['monthnum'] = absint($qv['monthnum']);
778
		$qv['day'] = absint($qv['day']);
779
		$qv['w'] = absint($qv['w']);
780
		$qv['m'] = is_scalar( $qv['m'] ) ? preg_replace( '|[^0-9]|', '', $qv['m'] ) : '';
781
		$qv['paged'] = absint($qv['paged']);
782
		$qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers
783
		$qv['author'] = preg_replace( '|[^0-9,-]|', '', $qv['author'] ); // comma separated list of positive or negative integers
784
		$qv['pagename'] = trim( $qv['pagename'] );
785
		$qv['name'] = trim( $qv['name'] );
786
		$qv['title'] = trim( $qv['title'] );
787
		if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']);
788
		if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']);
789
		if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']);
790
		if ( '' !== $qv['menu_order'] ) $qv['menu_order'] = absint($qv['menu_order']);
791
792
		// Fairly insane upper bound for search string lengths.
793
		if ( ! is_scalar( $qv['s'] ) || ( ! empty( $qv['s'] ) && strlen( $qv['s'] ) > 1600 ) ) {
794
			$qv['s'] = '';
795
		}
796
797
		// Compat. Map subpost to attachment.
798
		if ( '' != $qv['subpost'] )
799
			$qv['attachment'] = $qv['subpost'];
800
		if ( '' != $qv['subpost_id'] )
801
			$qv['attachment_id'] = $qv['subpost_id'];
802
803
		$qv['attachment_id'] = absint($qv['attachment_id']);
804
805
		if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
806
			$this->is_single = true;
807
			$this->is_attachment = true;
808
		} elseif ( '' != $qv['name'] ) {
809
			$this->is_single = true;
810
		} elseif ( $qv['p'] ) {
811
			$this->is_single = true;
812
		} elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) {
813
			// If year, month, day, hour, minute, and second are set, a single
814
			// post is being queried.
815
			$this->is_single = true;
816
		} elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) {
817
			$this->is_page = true;
818
			$this->is_single = false;
819
		} else {
820
			// Look for archive queries. Dates, categories, authors, search, post type archives.
821
822
			if ( isset( $this->query['s'] ) ) {
823
				$this->is_search = true;
824
			}
825
826
			if ( '' !== $qv['second'] ) {
827
				$this->is_time = true;
828
				$this->is_date = true;
829
			}
830
831 View Code Duplication
			if ( '' !== $qv['minute'] ) {
832
				$this->is_time = true;
833
				$this->is_date = true;
834
			}
835
836 View Code Duplication
			if ( '' !== $qv['hour'] ) {
837
				$this->is_time = true;
838
				$this->is_date = true;
839
			}
840
841
			if ( $qv['day'] ) {
842
				if ( ! $this->is_date ) {
843
					$date = sprintf( '%04d-%02d-%02d', $qv['year'], $qv['monthnum'], $qv['day'] );
844
					if ( $qv['monthnum'] && $qv['year'] && ! wp_checkdate( $qv['monthnum'], $qv['day'], $qv['year'], $date ) ) {
845
						$qv['error'] = '404';
846
					} else {
847
						$this->is_day = true;
848
						$this->is_date = true;
849
					}
850
				}
851
			}
852
853
			if ( $qv['monthnum'] ) {
854
				if ( ! $this->is_date ) {
855
					if ( 12 < $qv['monthnum'] ) {
856
						$qv['error'] = '404';
857
					} else {
858
						$this->is_month = true;
859
						$this->is_date = true;
860
					}
861
				}
862
			}
863
864
			if ( $qv['year'] ) {
865
				if ( ! $this->is_date ) {
866
					$this->is_year = true;
867
					$this->is_date = true;
868
				}
869
			}
870
871
			if ( $qv['m'] ) {
872
				$this->is_date = true;
873
				if ( strlen($qv['m']) > 9 ) {
874
					$this->is_time = true;
875
				} elseif ( strlen( $qv['m'] ) > 7 ) {
876
					$this->is_day = true;
877
				} elseif ( strlen( $qv['m'] ) > 5 ) {
878
					$this->is_month = true;
879
				} else {
880
					$this->is_year = true;
881
				}
882
			}
883
884
			if ( '' != $qv['w'] ) {
885
				$this->is_date = true;
886
			}
887
888
			$this->query_vars_hash = false;
889
			$this->parse_tax_query( $qv );
890
891
			foreach ( $this->tax_query->queries as $tax_query ) {
892
				if ( ! is_array( $tax_query ) ) {
893
					continue;
894
				}
895
896
				if ( isset( $tax_query['operator'] ) && 'NOT IN' != $tax_query['operator'] ) {
897
					switch ( $tax_query['taxonomy'] ) {
898
						case 'category':
899
							$this->is_category = true;
900
							break;
901
						case 'post_tag':
902
							$this->is_tag = true;
903
							break;
904
						default:
905
							$this->is_tax = true;
906
					}
907
				}
908
			}
909
			unset( $tax_query );
910
911
			if ( empty($qv['author']) || ($qv['author'] == '0') ) {
912
				$this->is_author = false;
913
			} else {
914
				$this->is_author = true;
915
			}
916
917
			if ( '' != $qv['author_name'] )
918
				$this->is_author = true;
919
920
			if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) {
921
				$post_type_obj = get_post_type_object( $qv['post_type'] );
922
				if ( ! empty( $post_type_obj->has_archive ) )
923
					$this->is_post_type_archive = true;
924
			}
925
926
			if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
927
				$this->is_archive = true;
928
		}
929
930
		if ( '' != $qv['feed'] )
931
			$this->is_feed = true;
932
933
		if ( '' != $qv['embed'] ) {
934
			$this->is_embed = true;
935
		}
936
937
		if ( '' != $qv['tb'] )
938
			$this->is_trackback = true;
939
940
		if ( '' != $qv['paged'] && ( intval($qv['paged']) > 1 ) )
941
			$this->is_paged = true;
942
943
		// if we're previewing inside the write screen
944
		if ( '' != $qv['preview'] )
945
			$this->is_preview = true;
946
947
		if ( is_admin() )
948
			$this->is_admin = true;
949
950
		if ( false !== strpos($qv['feed'], 'comments-') ) {
951
			$qv['feed'] = str_replace('comments-', '', $qv['feed']);
952
			$qv['withcomments'] = 1;
953
		}
954
955
		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
956
957
		if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
958
			$this->is_comment_feed = true;
959
960
		if ( !( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots ) )
961
			$this->is_home = true;
962
963
		// Correct is_* for page_on_front and page_for_posts
964
		if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
965
			$_query = wp_parse_args($this->query);
966
			// pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
967
			if ( isset($_query['pagename']) && '' == $_query['pagename'] )
968
				unset($_query['pagename']);
969
970
			unset( $_query['embed'] );
971
972
			if ( empty($_query) || !array_diff( array_keys($_query), array('preview', 'page', 'paged', 'cpage') ) ) {
973
				$this->is_page = true;
974
				$this->is_home = false;
975
				$qv['page_id'] = get_option('page_on_front');
976
				// Correct <!--nextpage--> for page_on_front
977
				if ( !empty($qv['paged']) ) {
978
					$qv['page'] = $qv['paged'];
979
					unset($qv['paged']);
980
				}
981
			}
982
		}
983
984
		if ( '' != $qv['pagename'] ) {
985
			$this->queried_object = get_page_by_path( $qv['pagename'] );
986
987
			if ( $this->queried_object && 'attachment' == $this->queried_object->post_type ) {
988
				if ( preg_match( "/^[^%]*%(?:postname)%/", get_option( 'permalink_structure' ) ) ) {
989
					// See if we also have a post with the same slug
990
					$post = get_page_by_path( $qv['pagename'], OBJECT, 'post' );
991
					if ( $post ) {
992
						$this->queried_object = $post;
993
						$this->is_page = false;
994
						$this->is_single = true;
995
					}
996
				}
997
			}
998
999
			if ( ! empty( $this->queried_object ) ) {
1000
				$this->queried_object_id = (int) $this->queried_object->ID;
1001
			} else {
1002
				unset( $this->queried_object );
1003
			}
1004
1005
			if  ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) {
1006
				$this->is_page = false;
1007
				$this->is_home = true;
1008
				$this->is_posts_page = true;
1009
			}
1010
		}
1011
1012
		if ( $qv['page_id'] ) {
1013
			if  ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
1014
				$this->is_page = false;
1015
				$this->is_home = true;
1016
				$this->is_posts_page = true;
1017
			}
1018
		}
1019
1020
		if ( !empty($qv['post_type']) ) {
1021
			if ( is_array($qv['post_type']) )
1022
				$qv['post_type'] = array_map('sanitize_key', $qv['post_type']);
1023
			else
1024
				$qv['post_type'] = sanitize_key($qv['post_type']);
1025
		}
1026
1027 View Code Duplication
		if ( ! empty( $qv['post_status'] ) ) {
1028
			if ( is_array( $qv['post_status'] ) )
1029
				$qv['post_status'] = array_map('sanitize_key', $qv['post_status']);
1030
			else
1031
				$qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']);
1032
		}
1033
1034
		if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) )
1035
			$this->is_comment_feed = false;
1036
1037
		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
1038
		// Done correcting is_* for page_on_front and page_for_posts
1039
1040
		if ( '404' == $qv['error'] )
1041
			$this->set_404();
1042
1043
		$this->is_embed = $this->is_embed && ( $this->is_singular || $this->is_404 );
1044
1045
		$this->query_vars_hash = md5( serialize( $this->query_vars ) );
1046
		$this->query_vars_changed = false;
1047
1048
		/**
1049
		 * Fires after the main query vars have been parsed.
1050
		 *
1051
		 * @since 1.5.0
1052
		 *
1053
		 * @param WP_Query &$this The WP_Query instance (passed by reference).
1054
		 */
1055
		do_action_ref_array( 'parse_query', array( &$this ) );
1056
	}
1057
1058
	/**
1059
	 * Parses various taxonomy related query vars.
1060
	 *
1061
	 * For BC, this method is not marked as protected. See [28987].
1062
	 *
1063
	 * @access protected
1064
	 * @since 3.1.0
1065
	 *
1066
	 * @param array $q The query variables. Passed by reference.
1067
	 */
1068
	public function parse_tax_query( &$q ) {
1069
		if ( ! empty( $q['tax_query'] ) && is_array( $q['tax_query'] ) ) {
1070
			$tax_query = $q['tax_query'];
1071
		} else {
1072
			$tax_query = array();
1073
		}
1074
1075
		if ( !empty($q['taxonomy']) && !empty($q['term']) ) {
1076
			$tax_query[] = array(
1077
				'taxonomy' => $q['taxonomy'],
1078
				'terms' => array( $q['term'] ),
1079
				'field' => 'slug',
1080
			);
1081
		}
1082
1083
		foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) {
1084
			if ( 'post_tag' == $taxonomy )
1085
				continue;	// Handled further down in the $q['tag'] block
1086
1087
			if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
1088
				$tax_query_defaults = array(
1089
					'taxonomy' => $taxonomy,
1090
					'field' => 'slug',
1091
				);
1092
1093
 				if ( isset( $t->rewrite['hierarchical'] ) && $t->rewrite['hierarchical'] ) {
1094
					$q[$t->query_var] = wp_basename( $q[$t->query_var] );
1095
				}
1096
1097
				$term = $q[$t->query_var];
1098
1099
				if ( is_array( $term ) ) {
1100
					$term = implode( ',', $term );
1101
				}
1102
1103
				if ( strpos($term, '+') !== false ) {
1104
					$terms = preg_split( '/[+]+/', $term );
1105
					foreach ( $terms as $term ) {
1106
						$tax_query[] = array_merge( $tax_query_defaults, array(
1107
							'terms' => array( $term )
1108
						) );
1109
					}
1110
				} else {
1111
					$tax_query[] = array_merge( $tax_query_defaults, array(
1112
						'terms' => preg_split( '/[,]+/', $term )
1113
					) );
1114
				}
1115
			}
1116
		}
1117
1118
		// If querystring 'cat' is an array, implode it.
1119 View Code Duplication
		if ( is_array( $q['cat'] ) ) {
1120
			$q['cat'] = implode( ',', $q['cat'] );
1121
		}
1122
1123
		// Category stuff
1124
		if ( ! empty( $q['cat'] ) && ! $this->is_singular ) {
1125
			$cat_in = $cat_not_in = array();
1126
1127
			$cat_array = preg_split( '/[,\s]+/', urldecode( $q['cat'] ) );
1128
			$cat_array = array_map( 'intval', $cat_array );
1129
			$q['cat'] = implode( ',', $cat_array );
1130
1131
			foreach ( $cat_array as $cat ) {
1132
				if ( $cat > 0 )
1133
					$cat_in[] = $cat;
1134
				elseif ( $cat < 0 )
1135
					$cat_not_in[] = abs( $cat );
1136
			}
1137
1138 View Code Duplication
			if ( ! empty( $cat_in ) ) {
1139
				$tax_query[] = array(
1140
					'taxonomy' => 'category',
1141
					'terms' => $cat_in,
1142
					'field' => 'term_id',
1143
					'include_children' => true
1144
				);
1145
			}
1146
1147 View Code Duplication
			if ( ! empty( $cat_not_in ) ) {
1148
				$tax_query[] = array(
1149
					'taxonomy' => 'category',
1150
					'terms' => $cat_not_in,
1151
					'field' => 'term_id',
1152
					'operator' => 'NOT IN',
1153
					'include_children' => true
1154
				);
1155
			}
1156
			unset( $cat_array, $cat_in, $cat_not_in );
1157
		}
1158
1159
		if ( ! empty( $q['category__and'] ) && 1 === count( (array) $q['category__and'] ) ) {
1160
			$q['category__and'] = (array) $q['category__and'];
1161
			if ( ! isset( $q['category__in'] ) )
1162
				$q['category__in'] = array();
1163
			$q['category__in'][] = absint( reset( $q['category__and'] ) );
1164
			unset( $q['category__and'] );
1165
		}
1166
1167
		if ( ! empty( $q['category__in'] ) ) {
1168
			$q['category__in'] = array_map( 'absint', array_unique( (array) $q['category__in'] ) );
1169
			$tax_query[] = array(
1170
				'taxonomy' => 'category',
1171
				'terms' => $q['category__in'],
1172
				'field' => 'term_id',
1173
				'include_children' => false
1174
			);
1175
		}
1176
1177
		if ( ! empty($q['category__not_in']) ) {
1178
			$q['category__not_in'] = array_map( 'absint', array_unique( (array) $q['category__not_in'] ) );
1179
			$tax_query[] = array(
1180
				'taxonomy' => 'category',
1181
				'terms' => $q['category__not_in'],
1182
				'operator' => 'NOT IN',
1183
				'include_children' => false
1184
			);
1185
		}
1186
1187
		if ( ! empty($q['category__and']) ) {
1188
			$q['category__and'] = array_map( 'absint', array_unique( (array) $q['category__and'] ) );
1189
			$tax_query[] = array(
1190
				'taxonomy' => 'category',
1191
				'terms' => $q['category__and'],
1192
				'field' => 'term_id',
1193
				'operator' => 'AND',
1194
				'include_children' => false
1195
			);
1196
		}
1197
1198
		// If querystring 'tag' is array, implode it.
1199 View Code Duplication
		if ( is_array( $q['tag'] ) ) {
1200
			$q['tag'] = implode( ',', $q['tag'] );
1201
		}
1202
1203
		// Tag stuff
1204
		if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) {
1205
			if ( strpos($q['tag'], ',') !== false ) {
1206
				$tags = preg_split('/[,\r\n\t ]+/', $q['tag']);
1207 View Code Duplication
				foreach ( (array) $tags as $tag ) {
1208
					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
1209
					$q['tag_slug__in'][] = $tag;
1210
				}
1211
			} elseif ( preg_match('/[+\r\n\t ]+/', $q['tag'] ) || ! empty( $q['cat'] ) ) {
1212
				$tags = preg_split('/[+\r\n\t ]+/', $q['tag']);
1213 View Code Duplication
				foreach ( (array) $tags as $tag ) {
1214
					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
1215
					$q['tag_slug__and'][] = $tag;
1216
				}
1217
			} else {
1218
				$q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
1219
				$q['tag_slug__in'][] = $q['tag'];
1220
			}
1221
		}
1222
1223
		if ( !empty($q['tag_id']) ) {
1224
			$q['tag_id'] = absint( $q['tag_id'] );
1225
			$tax_query[] = array(
1226
				'taxonomy' => 'post_tag',
1227
				'terms' => $q['tag_id']
1228
			);
1229
		}
1230
1231 View Code Duplication
		if ( !empty($q['tag__in']) ) {
1232
			$q['tag__in'] = array_map('absint', array_unique( (array) $q['tag__in'] ) );
1233
			$tax_query[] = array(
1234
				'taxonomy' => 'post_tag',
1235
				'terms' => $q['tag__in']
1236
			);
1237
		}
1238
1239 View Code Duplication
		if ( !empty($q['tag__not_in']) ) {
1240
			$q['tag__not_in'] = array_map('absint', array_unique( (array) $q['tag__not_in'] ) );
1241
			$tax_query[] = array(
1242
				'taxonomy' => 'post_tag',
1243
				'terms' => $q['tag__not_in'],
1244
				'operator' => 'NOT IN'
1245
			);
1246
		}
1247
1248 View Code Duplication
		if ( !empty($q['tag__and']) ) {
1249
			$q['tag__and'] = array_map('absint', array_unique( (array) $q['tag__and'] ) );
1250
			$tax_query[] = array(
1251
				'taxonomy' => 'post_tag',
1252
				'terms' => $q['tag__and'],
1253
				'operator' => 'AND'
1254
			);
1255
		}
1256
1257 View Code Duplication
		if ( !empty($q['tag_slug__in']) ) {
1258
			$q['tag_slug__in'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
1259
			$tax_query[] = array(
1260
				'taxonomy' => 'post_tag',
1261
				'terms' => $q['tag_slug__in'],
1262
				'field' => 'slug'
1263
			);
1264
		}
1265
1266
		if ( !empty($q['tag_slug__and']) ) {
1267
			$q['tag_slug__and'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
1268
			$tax_query[] = array(
1269
				'taxonomy' => 'post_tag',
1270
				'terms' => $q['tag_slug__and'],
1271
				'field' => 'slug',
1272
				'operator' => 'AND'
1273
			);
1274
		}
1275
1276
		$this->tax_query = new WP_Tax_Query( $tax_query );
1277
1278
		/**
1279
		 * Fires after taxonomy-related query vars have been parsed.
1280
		 *
1281
		 * @since 3.7.0
1282
		 *
1283
		 * @param WP_Query $this The WP_Query instance.
1284
		 */
1285
		do_action( 'parse_tax_query', $this );
1286
	}
1287
1288
	/**
1289
	 * Generate SQL for the WHERE clause based on passed search terms.
1290
	 *
1291
	 * @since 3.7.0
1292
	 *
1293
	 * @param array $q Query variables.
1294
	 * @return string WHERE clause.
1295
	 */
1296
	protected function parse_search( &$q ) {
1297
		global $wpdb;
1298
1299
		$search = '';
1300
1301
		// added slashes screw with quote grouping when done early, so done later
1302
		$q['s'] = stripslashes( $q['s'] );
1303
		if ( empty( $_GET['s'] ) && $this->is_main_query() )
1304
			$q['s'] = urldecode( $q['s'] );
1305
		// there are no line breaks in <input /> fields
1306
		$q['s'] = str_replace( array( "\r", "\n" ), '', $q['s'] );
1307
		$q['search_terms_count'] = 1;
1308
		if ( ! empty( $q['sentence'] ) ) {
1309
			$q['search_terms'] = array( $q['s'] );
1310
		} else {
1311
			if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $q['s'], $matches ) ) {
1312
				$q['search_terms_count'] = count( $matches[0] );
1313
				$q['search_terms'] = $this->parse_search_terms( $matches[0] );
1314
				// if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence
1315
				if ( empty( $q['search_terms'] ) || count( $q['search_terms'] ) > 9 )
1316
					$q['search_terms'] = array( $q['s'] );
1317
			} else {
1318
				$q['search_terms'] = array( $q['s'] );
1319
			}
1320
		}
1321
1322
		$n = ! empty( $q['exact'] ) ? '' : '%';
1323
		$searchand = '';
1324
		$q['search_orderby_title'] = array();
1325
1326
		/**
1327
		 * Filters the prefix that indicates that a search term should be excluded from results.
1328
		 *
1329
		 * @since 4.7.0
1330
		 *
1331
		 * @param string $exclusion_prefix The prefix. Default '-'. Returning
1332
		 *                                 an empty value disables exclusions.
1333
		 */
1334
		$exclusion_prefix = apply_filters( 'wp_query_search_exclusion_prefix', '-' );
1335
1336
		foreach ( $q['search_terms'] as $term ) {
1337
			// If there is an $exclusion_prefix, terms prefixed with it should be excluded.
1338
			$exclude = $exclusion_prefix && ( $exclusion_prefix === substr( $term, 0, 1 ) );
1339
			if ( $exclude ) {
1340
				$like_op  = 'NOT LIKE';
1341
				$andor_op = 'AND';
1342
				$term     = substr( $term, 1 );
1343
			} else {
1344
				$like_op  = 'LIKE';
1345
				$andor_op = 'OR';
1346
			}
1347
1348
			if ( $n && ! $exclude ) {
1349
				$like = '%' . $wpdb->esc_like( $term ) . '%';
1350
				$q['search_orderby_title'][] = $wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", $like );
1351
			}
1352
1353
			$like = $n . $wpdb->esc_like( $term ) . $n;
1354
			$search .= $wpdb->prepare( "{$searchand}(({$wpdb->posts}.post_title $like_op %s) $andor_op ({$wpdb->posts}.post_excerpt $like_op %s) $andor_op ({$wpdb->posts}.post_content $like_op %s))", $like, $like, $like );
1355
			$searchand = ' AND ';
1356
		}
1357
1358
		if ( ! empty( $search ) ) {
1359
			$search = " AND ({$search}) ";
1360
			if ( ! is_user_logged_in() ) {
1361
				$search .= " AND ({$wpdb->posts}.post_password = '') ";
1362
			}
1363
		}
1364
1365
		return $search;
1366
	}
1367
1368
	/**
1369
	 * Check if the terms are suitable for searching.
1370
	 *
1371
	 * Uses an array of stopwords (terms) that are excluded from the separate
1372
	 * term matching when searching for posts. The list of English stopwords is
1373
	 * the approximate search engines list, and is translatable.
1374
	 *
1375
	 * @since 3.7.0
1376
	 *
1377
	 * @param array $terms Terms to check.
1378
	 * @return array Terms that are not stopwords.
1379
	 */
1380
	protected function parse_search_terms( $terms ) {
1381
		$strtolower = function_exists( 'mb_strtolower' ) ? 'mb_strtolower' : 'strtolower';
1382
		$checked = array();
1383
1384
		$stopwords = $this->get_search_stopwords();
1385
1386
		foreach ( $terms as $term ) {
1387
			// keep before/after spaces when term is for exact match
1388
			if ( preg_match( '/^".+"$/', $term ) )
1389
				$term = trim( $term, "\"'" );
1390
			else
1391
				$term = trim( $term, "\"' " );
1392
1393
			// Avoid single A-Z and single dashes.
1394
			if ( ! $term || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) )
1395
				continue;
1396
1397
			if ( in_array( call_user_func( $strtolower, $term ), $stopwords, true ) )
1398
				continue;
1399
1400
			$checked[] = $term;
1401
		}
1402
1403
		return $checked;
1404
	}
1405
1406
	/**
1407
	 * Retrieve stopwords used when parsing search terms.
1408
	 *
1409
	 * @since 3.7.0
1410
	 *
1411
	 * @return array Stopwords.
1412
	 */
1413
	protected function get_search_stopwords() {
1414
		if ( isset( $this->stopwords ) )
1415
			return $this->stopwords;
1416
1417
		/* translators: This is a comma-separated list of very common words that should be excluded from a search,
1418
		 * like a, an, and the. These are usually called "stopwords". You should not simply translate these individual
1419
		 * words into your language. Instead, look for and provide commonly accepted stopwords in your language.
1420
		 */
1421
		$words = explode( ',', _x( 'about,an,are,as,at,be,by,com,for,from,how,in,is,it,of,on,or,that,the,this,to,was,what,when,where,who,will,with,www',
1422
			'Comma-separated list of search stopwords in your language' ) );
1423
1424
		$stopwords = array();
1425
		foreach ( $words as $word ) {
1426
			$word = trim( $word, "\r\n\t " );
1427
			if ( $word )
1428
				$stopwords[] = $word;
1429
		}
1430
1431
		/**
1432
		 * Filters stopwords used when parsing search terms.
1433
		 *
1434
		 * @since 3.7.0
1435
		 *
1436
		 * @param array $stopwords Stopwords.
1437
		 */
1438
		$this->stopwords = apply_filters( 'wp_search_stopwords', $stopwords );
0 ignored issues
show
Documentation Bug introduced by
It seems like apply_filters('wp_search_stopwords', $stopwords) of type * is incompatible with the declared type array of property $stopwords.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1439
		return $this->stopwords;
1440
	}
1441
1442
	/**
1443
	 * Generate SQL for the ORDER BY condition based on passed search terms.
1444
	 *
1445
	 * @param array $q Query variables.
1446
	 * @return string ORDER BY clause.
1447
	 */
1448
	protected function parse_search_order( &$q ) {
1449
		global $wpdb;
1450
1451
		if ( $q['search_terms_count'] > 1 ) {
1452
			$num_terms = count( $q['search_orderby_title'] );
1453
1454
			// If the search terms contain negative queries, don't bother ordering by sentence matches.
1455
			$like = '';
1456
			if ( ! preg_match( '/(?:\s|^)\-/', $q['s'] ) ) {
1457
				$like = '%' . $wpdb->esc_like( $q['s'] ) . '%';
1458
			}
1459
1460
			$search_orderby = '';
1461
1462
			// sentence match in 'post_title'
1463
			if ( $like ) {
1464
				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_title LIKE %s THEN 1 ", $like );
1465
			}
1466
1467
			// sanity limit, sort as sentence when more than 6 terms
1468
			// (few searches are longer than 6 terms and most titles are not)
1469
			if ( $num_terms < 7 ) {
1470
				// all words in title
1471
				$search_orderby .= 'WHEN ' . implode( ' AND ', $q['search_orderby_title'] ) . ' THEN 2 ';
1472
				// any word in title, not needed when $num_terms == 1
1473
				if ( $num_terms > 1 )
1474
					$search_orderby .= 'WHEN ' . implode( ' OR ', $q['search_orderby_title'] ) . ' THEN 3 ';
1475
			}
1476
1477
			// Sentence match in 'post_content' and 'post_excerpt'.
1478
			if ( $like ) {
1479
				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_excerpt LIKE %s THEN 4 ", $like );
1480
				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_content LIKE %s THEN 5 ", $like );
1481
			}
1482
1483
			if ( $search_orderby ) {
1484
				$search_orderby = '(CASE ' . $search_orderby . 'ELSE 6 END)';
1485
			}
1486
		} else {
1487
			// single word or sentence search
1488
			$search_orderby = reset( $q['search_orderby_title'] ) . ' DESC';
1489
		}
1490
1491
		return $search_orderby;
1492
	}
1493
1494
	/**
1495
	 * If the passed orderby value is allowed, convert the alias to a
1496
	 * properly-prefixed orderby value.
1497
	 *
1498
	 * @since 4.0.0
1499
	 * @access protected
1500
	 *
1501
	 * @param string $orderby Alias for the field to order by.
1502
	 * @return string|false Table-prefixed value to used in the ORDER clause. False otherwise.
1503
	 */
1504
	protected function parse_orderby( $orderby ) {
1505
		global $wpdb;
1506
1507
		// Used to filter values.
1508
		$allowed_keys = array(
1509
			'post_name', 'post_author', 'post_date', 'post_title', 'post_modified',
1510
			'post_parent', 'post_type', 'name', 'author', 'date', 'title', 'modified',
1511
			'parent', 'type', 'ID', 'menu_order', 'comment_count', 'rand',
1512
		);
1513
1514
		$primary_meta_key = '';
1515
		$primary_meta_query = false;
1516
		$meta_clauses = $this->meta_query->get_clauses();
1517
		if ( ! empty( $meta_clauses ) ) {
1518
			$primary_meta_query = reset( $meta_clauses );
1519
1520
			if ( ! empty( $primary_meta_query['key'] ) ) {
1521
				$primary_meta_key = $primary_meta_query['key'];
1522
				$allowed_keys[] = $primary_meta_key;
1523
			}
1524
1525
			$allowed_keys[] = 'meta_value';
1526
			$allowed_keys[] = 'meta_value_num';
1527
			$allowed_keys   = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
1528
		}
1529
1530
		// If RAND() contains a seed value, sanitize and add to allowed keys.
1531
		$rand_with_seed = false;
1532
		if ( preg_match( '/RAND\(([0-9]+)\)/i', $orderby, $matches ) ) {
1533
			$orderby = sprintf( 'RAND(%s)', intval( $matches[1] ) );
1534
			$allowed_keys[] = $orderby;
1535
			$rand_with_seed = true;
1536
		}
1537
1538
		if ( ! in_array( $orderby, $allowed_keys, true ) ) {
1539
			return false;
1540
		}
1541
1542
		switch ( $orderby ) {
1543
			case 'post_name':
1544
			case 'post_author':
1545
			case 'post_date':
1546
			case 'post_title':
1547
			case 'post_modified':
1548
			case 'post_parent':
1549
			case 'post_type':
1550
			case 'ID':
1551
			case 'menu_order':
1552
			case 'comment_count':
1553
				$orderby_clause = "{$wpdb->posts}.{$orderby}";
1554
				break;
1555
			case 'rand':
1556
				$orderby_clause = 'RAND()';
1557
				break;
1558
			case $primary_meta_key:
1559 View Code Duplication
			case 'meta_value':
1560
				if ( ! empty( $primary_meta_query['type'] ) ) {
1561
					$orderby_clause = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
1562
				} else {
1563
					$orderby_clause = "{$primary_meta_query['alias']}.meta_value";
1564
				}
1565
				break;
1566
			case 'meta_value_num':
1567
				$orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
1568
				break;
1569
			default:
1570
				if ( array_key_exists( $orderby, $meta_clauses ) ) {
1571
					// $orderby corresponds to a meta_query clause.
1572
					$meta_clause = $meta_clauses[ $orderby ];
1573
					$orderby_clause = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
1574
				} elseif ( $rand_with_seed ) {
1575
					$orderby_clause = $orderby;
1576
				} else {
1577
					// Default: order by post field.
1578
					$orderby_clause = "{$wpdb->posts}.post_" . sanitize_key( $orderby );
1579
				}
1580
1581
				break;
1582
		}
1583
1584
		return $orderby_clause;
1585
	}
1586
1587
	/**
1588
	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
1589
	 *
1590
	 * @since 4.0.0
1591
	 * @access protected
1592
	 *
1593
	 * @param string $order The 'order' query variable.
1594
	 * @return string The sanitized 'order' query variable.
1595
	 */
1596 View Code Duplication
	protected function parse_order( $order ) {
1597
		if ( ! is_string( $order ) || empty( $order ) ) {
1598
			return 'DESC';
1599
		}
1600
1601
		if ( 'ASC' === strtoupper( $order ) ) {
1602
			return 'ASC';
1603
		} else {
1604
			return 'DESC';
1605
		}
1606
	}
1607
1608
	/**
1609
	 * Sets the 404 property and saves whether query is feed.
1610
	 *
1611
	 * @since 2.0.0
1612
	 * @access public
1613
	 */
1614
	public function set_404() {
1615
		$is_feed = $this->is_feed;
1616
1617
		$this->init_query_flags();
1618
		$this->is_404 = true;
1619
1620
		$this->is_feed = $is_feed;
1621
	}
1622
1623
	/**
1624
	 * Retrieve query variable.
1625
	 *
1626
	 * @since 1.5.0
1627
	 * @since 3.9.0 The `$default` argument was introduced.
1628
	 *
1629
	 * @access public
1630
	 *
1631
	 * @param string $query_var Query variable key.
1632
	 * @param mixed  $default   Optional. Value to return if the query variable is not set. Default empty.
1633
	 * @return mixed Contents of the query variable.
1634
	 */
1635
	public function get( $query_var, $default = '' ) {
1636
		if ( isset( $this->query_vars[ $query_var ] ) ) {
1637
			return $this->query_vars[ $query_var ];
1638
		}
1639
1640
		return $default;
1641
	}
1642
1643
	/**
1644
	 * Set query variable.
1645
	 *
1646
	 * @since 1.5.0
1647
	 * @access public
1648
	 *
1649
	 * @param string $query_var Query variable key.
1650
	 * @param mixed  $value     Query variable value.
1651
	 */
1652
	public function set($query_var, $value) {
1653
		$this->query_vars[$query_var] = $value;
1654
	}
1655
1656
	/**
1657
	 * Retrieve the posts based on query variables.
1658
	 *
1659
	 * There are a few filters and actions that can be used to modify the post
1660
	 * database query.
1661
	 *
1662
	 * @since 1.5.0
1663
	 * @access public
1664
	 *
1665
	 * @return array List of posts.
1666
	 */
1667
	public function get_posts() {
1668
		global $wpdb;
1669
1670
		$this->parse_query();
1671
1672
		/**
1673
		 * Fires after the query variable object is created, but before the actual query is run.
1674
		 *
1675
		 * Note: If using conditional tags, use the method versions within the passed instance
1676
		 * (e.g. $this->is_main_query() instead of is_main_query()). This is because the functions
1677
		 * like is_main_query() test against the global $wp_query instance, not the passed one.
1678
		 *
1679
		 * @since 2.0.0
1680
		 *
1681
		 * @param WP_Query &$this The WP_Query instance (passed by reference).
1682
		 */
1683
		do_action_ref_array( 'pre_get_posts', array( &$this ) );
1684
1685
		// Shorthand.
1686
		$q = &$this->query_vars;
1687
1688
		// Fill again in case pre_get_posts unset some vars.
1689
		$q = $this->fill_query_vars($q);
1690
1691
		// Parse meta query
1692
		$this->meta_query = new WP_Meta_Query();
1693
		$this->meta_query->parse_query_vars( $q );
1694
1695
		// Set a flag if a pre_get_posts hook changed the query vars.
1696
		$hash = md5( serialize( $this->query_vars ) );
1697
		if ( $hash != $this->query_vars_hash ) {
1698
			$this->query_vars_changed = true;
1699
			$this->query_vars_hash = $hash;
1700
		}
1701
		unset($hash);
1702
1703
		// First let's clear some variables
1704
		$distinct = '';
1705
		$whichauthor = '';
1706
		$whichmimetype = '';
1707
		$where = '';
1708
		$limits = '';
1709
		$join = '';
1710
		$search = '';
1711
		$groupby = '';
1712
		$post_status_join = false;
1713
		$page = 1;
1714
1715
		if ( isset( $q['caller_get_posts'] ) ) {
1716
			_deprecated_argument( 'WP_Query', '3.1.0',
1717
				/* translators: 1: caller_get_posts, 2: ignore_sticky_posts */
1718
				sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
1719
					'<code>caller_get_posts</code>',
1720
					'<code>ignore_sticky_posts</code>'
1721
				)
1722
			);
1723
1724
			if ( ! isset( $q['ignore_sticky_posts'] ) ) {
1725
				$q['ignore_sticky_posts'] = $q['caller_get_posts'];
1726
			}
1727
		}
1728
1729
		if ( !isset( $q['ignore_sticky_posts'] ) )
1730
			$q['ignore_sticky_posts'] = false;
1731
1732
		if ( !isset($q['suppress_filters']) )
1733
			$q['suppress_filters'] = false;
1734
1735
		if ( !isset($q['cache_results']) ) {
1736
			if ( wp_using_ext_object_cache() )
1737
				$q['cache_results'] = false;
1738
			else
1739
				$q['cache_results'] = true;
1740
		}
1741
1742
		if ( !isset($q['update_post_term_cache']) )
1743
			$q['update_post_term_cache'] = true;
1744
1745
		if ( ! isset( $q['lazy_load_term_meta'] ) ) {
1746
			$q['lazy_load_term_meta'] = $q['update_post_term_cache'];
1747
		}
1748
1749
		if ( !isset($q['update_post_meta_cache']) )
1750
			$q['update_post_meta_cache'] = true;
1751
1752
		if ( !isset($q['post_type']) ) {
1753
			if ( $this->is_search )
1754
				$q['post_type'] = 'any';
1755
			else
1756
				$q['post_type'] = '';
1757
		}
1758
		$post_type = $q['post_type'];
1759
		if ( empty( $q['posts_per_page'] ) ) {
1760
			$q['posts_per_page'] = get_option( 'posts_per_page' );
1761
		}
1762
		if ( isset($q['showposts']) && $q['showposts'] ) {
1763
			$q['showposts'] = (int) $q['showposts'];
1764
			$q['posts_per_page'] = $q['showposts'];
1765
		}
1766
		if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
1767
			$q['posts_per_page'] = $q['posts_per_archive_page'];
1768
		if ( !isset($q['nopaging']) ) {
1769
			if ( $q['posts_per_page'] == -1 ) {
1770
				$q['nopaging'] = true;
1771
			} else {
1772
				$q['nopaging'] = false;
1773
			}
1774
		}
1775
1776
		if ( $this->is_feed ) {
1777
			// This overrides posts_per_page.
1778
			if ( ! empty( $q['posts_per_rss'] ) ) {
1779
				$q['posts_per_page'] = $q['posts_per_rss'];
1780
			} else {
1781
				$q['posts_per_page'] = get_option( 'posts_per_rss' );
1782
			}
1783
			$q['nopaging'] = false;
1784
		}
1785
		$q['posts_per_page'] = (int) $q['posts_per_page'];
1786
		if ( $q['posts_per_page'] < -1 )
1787
			$q['posts_per_page'] = abs($q['posts_per_page']);
1788
		elseif ( $q['posts_per_page'] == 0 )
1789
			$q['posts_per_page'] = 1;
1790
1791
		if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
1792
			$q['comments_per_page'] = get_option('comments_per_page');
1793
1794
		if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
1795
			$this->is_page = true;
1796
			$this->is_home = false;
1797
			$q['page_id'] = get_option('page_on_front');
1798
		}
1799
1800
		if ( isset($q['page']) ) {
1801
			$q['page'] = trim($q['page'], '/');
1802
			$q['page'] = absint($q['page']);
1803
		}
1804
1805
		// If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
1806
		if ( isset($q['no_found_rows']) )
1807
			$q['no_found_rows'] = (bool) $q['no_found_rows'];
1808
		else
1809
			$q['no_found_rows'] = false;
1810
1811
		switch ( $q['fields'] ) {
1812
			case 'ids':
1813
				$fields = "{$wpdb->posts}.ID";
1814
				break;
1815
			case 'id=>parent':
1816
				$fields = "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent";
1817
				break;
1818
			default:
1819
				$fields = "{$wpdb->posts}.*";
1820
		}
1821
1822
		if ( '' !== $q['menu_order'] ) {
1823
			$where .= " AND {$wpdb->posts}.menu_order = " . $q['menu_order'];
1824
		}
1825
		// The "m" parameter is meant for months but accepts datetimes of varying specificity
1826
		if ( $q['m'] ) {
1827
			$where .= " AND YEAR({$wpdb->posts}.post_date)=" . substr($q['m'], 0, 4);
1828 View Code Duplication
			if ( strlen($q['m']) > 5 ) {
1829
				$where .= " AND MONTH({$wpdb->posts}.post_date)=" . substr($q['m'], 4, 2);
1830
			}
1831 View Code Duplication
			if ( strlen($q['m']) > 7 ) {
1832
				$where .= " AND DAYOFMONTH({$wpdb->posts}.post_date)=" . substr($q['m'], 6, 2);
1833
			}
1834 View Code Duplication
			if ( strlen($q['m']) > 9 ) {
1835
				$where .= " AND HOUR({$wpdb->posts}.post_date)=" . substr($q['m'], 8, 2);
1836
			}
1837 View Code Duplication
			if ( strlen($q['m']) > 11 ) {
1838
				$where .= " AND MINUTE({$wpdb->posts}.post_date)=" . substr($q['m'], 10, 2);
1839
			}
1840 View Code Duplication
			if ( strlen($q['m']) > 13 ) {
1841
				$where .= " AND SECOND({$wpdb->posts}.post_date)=" . substr($q['m'], 12, 2);
1842
			}
1843
		}
1844
1845
		// Handle the other individual date parameters
1846
		$date_parameters = array();
1847
1848
		if ( '' !== $q['hour'] )
1849
			$date_parameters['hour'] = $q['hour'];
1850
1851
		if ( '' !== $q['minute'] )
1852
			$date_parameters['minute'] = $q['minute'];
1853
1854
		if ( '' !== $q['second'] )
1855
			$date_parameters['second'] = $q['second'];
1856
1857
		if ( $q['year'] )
1858
			$date_parameters['year'] = $q['year'];
1859
1860
		if ( $q['monthnum'] )
1861
			$date_parameters['monthnum'] = $q['monthnum'];
1862
1863
		if ( $q['w'] )
1864
			$date_parameters['week'] = $q['w'];
1865
1866
		if ( $q['day'] )
1867
			$date_parameters['day'] = $q['day'];
1868
1869
		if ( $date_parameters ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $date_parameters of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1870
			$date_query = new WP_Date_Query( array( $date_parameters ) );
1871
			$where .= $date_query->get_sql();
1872
		}
1873
		unset( $date_parameters, $date_query );
1874
1875
		// Handle complex date queries
1876
		if ( ! empty( $q['date_query'] ) ) {
1877
			$this->date_query = new WP_Date_Query( $q['date_query'] );
1878
			$where .= $this->date_query->get_sql();
1879
		}
1880
1881
1882
		// If we've got a post_type AND it's not "any" post_type.
1883
		if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
1884
			foreach ( (array)$q['post_type'] as $_post_type ) {
1885
				$ptype_obj = get_post_type_object($_post_type);
1886
				if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
1887
					continue;
1888
1889
				if ( ! $ptype_obj->hierarchical ) {
1890
					// Non-hierarchical post types can directly use 'name'.
1891
					$q['name'] = $q[ $ptype_obj->query_var ];
1892
				} else {
1893
					// Hierarchical post types will operate through 'pagename'.
1894
					$q['pagename'] = $q[ $ptype_obj->query_var ];
1895
					$q['name'] = '';
1896
				}
1897
1898
				// Only one request for a slug is possible, this is why name & pagename are overwritten above.
1899
				break;
1900
			} //end foreach
1901
			unset($ptype_obj);
1902
		}
1903
1904
		if ( '' !== $q['title'] ) {
1905
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title = %s", stripslashes( $q['title'] ) );
1906
		}
1907
1908
		// Parameters related to 'post_name'.
1909
		if ( '' != $q['name'] ) {
1910
			$q['name'] = sanitize_title_for_query( $q['name'] );
1911
			$where .= " AND {$wpdb->posts}.post_name = '" . $q['name'] . "'";
1912
		} elseif ( '' != $q['pagename'] ) {
1913
			if ( isset($this->queried_object_id) ) {
1914
				$reqpage = $this->queried_object_id;
1915
			} else {
1916
				if ( 'page' != $q['post_type'] ) {
1917
					foreach ( (array)$q['post_type'] as $_post_type ) {
1918
						$ptype_obj = get_post_type_object($_post_type);
1919
						if ( !$ptype_obj || !$ptype_obj->hierarchical )
1920
							continue;
1921
1922
						$reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
1923
						if ( $reqpage )
1924
							break;
1925
					}
1926
					unset($ptype_obj);
1927
				} else {
1928
					$reqpage = get_page_by_path($q['pagename']);
1929
				}
1930
				if ( !empty($reqpage) )
1931
					$reqpage = $reqpage->ID;
1932
				else
1933
					$reqpage = 0;
1934
			}
1935
1936
			$page_for_posts = get_option('page_for_posts');
1937
			if  ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
1938
				$q['pagename'] = sanitize_title_for_query( wp_basename( $q['pagename'] ) );
1939
				$q['name'] = $q['pagename'];
1940
				$where .= " AND ({$wpdb->posts}.ID = '$reqpage')";
1941
				$reqpage_obj = get_post( $reqpage );
1942
				if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
1943
					$this->is_attachment = true;
1944
					$post_type = $q['post_type'] = 'attachment';
1945
					$this->is_page = true;
1946
					$q['attachment_id'] = $reqpage;
1947
				}
1948
			}
1949
		} elseif ( '' != $q['attachment'] ) {
1950
			$q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
1951
			$q['name'] = $q['attachment'];
1952
			$where .= " AND {$wpdb->posts}.post_name = '" . $q['attachment'] . "'";
1953
		} elseif ( is_array( $q['post_name__in'] ) && ! empty( $q['post_name__in'] ) ) {
1954
			$q['post_name__in'] = array_map( 'sanitize_title_for_query', $q['post_name__in'] );
1955
			$post_name__in = "'" . implode( "','", $q['post_name__in'] ) . "'";
1956
			$where .= " AND {$wpdb->posts}.post_name IN ($post_name__in)";
1957
		}
1958
1959
		// If an attachment is requested by number, let it supersede any post number.
1960
		if ( $q['attachment_id'] )
1961
			$q['p'] = absint($q['attachment_id']);
1962
1963
		// If a post number is specified, load that post
1964 View Code Duplication
		if ( $q['p'] ) {
1965
			$where .= " AND {$wpdb->posts}.ID = " . $q['p'];
1966
		} elseif ( $q['post__in'] ) {
1967
			$post__in = implode(',', array_map( 'absint', $q['post__in'] ));
1968
			$where .= " AND {$wpdb->posts}.ID IN ($post__in)";
1969
		} elseif ( $q['post__not_in'] ) {
1970
			$post__not_in = implode(',',  array_map( 'absint', $q['post__not_in'] ));
1971
			$where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
1972
		}
1973
1974 View Code Duplication
		if ( is_numeric( $q['post_parent'] ) ) {
1975
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_parent = %d ", $q['post_parent'] );
1976
		} elseif ( $q['post_parent__in'] ) {
1977
			$post_parent__in = implode( ',', array_map( 'absint', $q['post_parent__in'] ) );
1978
			$where .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
1979
		} elseif ( $q['post_parent__not_in'] ) {
1980
			$post_parent__not_in = implode( ',',  array_map( 'absint', $q['post_parent__not_in'] ) );
1981
			$where .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
1982
		}
1983
1984
		if ( $q['page_id'] ) {
1985
			if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
1986
				$q['p'] = $q['page_id'];
1987
				$where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
1988
			}
1989
		}
1990
1991
		// If a search pattern is specified, load the posts that match.
1992
		if ( strlen( $q['s'] ) ) {
1993
			$search = $this->parse_search( $q );
1994
		}
1995
1996
		if ( ! $q['suppress_filters'] ) {
1997
			/**
1998
			 * Filters the search SQL that is used in the WHERE clause of WP_Query.
1999
			 *
2000
			 * @since 3.0.0
2001
			 *
2002
			 * @param string   $search Search SQL for WHERE clause.
2003
			 * @param WP_Query $this   The current WP_Query object.
2004
			 */
2005
			$search = apply_filters_ref_array( 'posts_search', array( $search, &$this ) );
2006
		}
2007
2008
		// Taxonomies
2009
		if ( !$this->is_singular ) {
2010
			$this->parse_tax_query( $q );
2011
2012
			$clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );
2013
2014
			$join .= $clauses['join'];
2015
			$where .= $clauses['where'];
2016
		}
2017
2018
		if ( $this->is_tax ) {
2019
			if ( empty($post_type) ) {
2020
				// Do a fully inclusive search for currently registered post types of queried taxonomies
2021
				$post_type = array();
2022
				$taxonomies = array_keys( $this->tax_query->queried_terms );
2023
				foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
2024
					$object_taxonomies = $pt === 'attachment' ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
2025
					if ( array_intersect( $taxonomies, $object_taxonomies ) )
2026
						$post_type[] = $pt;
2027
				}
2028
				if ( ! $post_type )
0 ignored issues
show
Bug Best Practice introduced by
The expression $post_type of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2029
					$post_type = 'any';
2030
				elseif ( count( $post_type ) == 1 )
2031
					$post_type = $post_type[0];
2032
2033
				$post_status_join = true;
2034
			} elseif ( in_array('attachment', (array) $post_type) ) {
2035
				$post_status_join = true;
2036
			}
2037
		}
2038
2039
		/*
2040
		 * Ensure that 'taxonomy', 'term', 'term_id', 'cat', and
2041
		 * 'category_name' vars are set for backward compatibility.
2042
		 */
2043
		if ( ! empty( $this->tax_query->queried_terms ) ) {
2044
2045
			/*
2046
			 * Set 'taxonomy', 'term', and 'term_id' to the
2047
			 * first taxonomy other than 'post_tag' or 'category'.
2048
			 */
2049
			if ( ! isset( $q['taxonomy'] ) ) {
2050
				foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
2051
					if ( empty( $queried_items['terms'][0] ) ) {
2052
						continue;
2053
					}
2054
2055
					if ( ! in_array( $queried_taxonomy, array( 'category', 'post_tag' ) ) ) {
2056
						$q['taxonomy'] = $queried_taxonomy;
2057
2058
						if ( 'slug' === $queried_items['field'] ) {
2059
							$q['term'] = $queried_items['terms'][0];
2060
						} else {
2061
							$q['term_id'] = $queried_items['terms'][0];
2062
						}
2063
2064
						// Take the first one we find.
2065
						break;
2066
					}
2067
				}
2068
			}
2069
2070
			// 'cat', 'category_name', 'tag_id'
2071
			foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
2072
				if ( empty( $queried_items['terms'][0] ) ) {
2073
					continue;
2074
				}
2075
2076 View Code Duplication
				if ( 'category' === $queried_taxonomy ) {
2077
					$the_cat = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'category' );
2078
					if ( $the_cat ) {
2079
						$this->set( 'cat', $the_cat->term_id );
2080
						$this->set( 'category_name', $the_cat->slug );
2081
					}
2082
					unset( $the_cat );
2083
				}
2084
2085 View Code Duplication
				if ( 'post_tag' === $queried_taxonomy ) {
2086
					$the_tag = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'post_tag' );
2087
					if ( $the_tag ) {
2088
						$this->set( 'tag_id', $the_tag->term_id );
2089
					}
2090
					unset( $the_tag );
2091
				}
2092
			}
2093
		}
2094
2095
		if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) {
2096
			$groupby = "{$wpdb->posts}.ID";
2097
		}
2098
2099
		// Author/user stuff
2100
2101
		if ( ! empty( $q['author'] ) && $q['author'] != '0' ) {
2102
			$q['author'] = addslashes_gpc( '' . urldecode( $q['author'] ) );
2103
			$authors = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $q['author'] ) ) );
2104
			foreach ( $authors as $author ) {
2105
				$key = $author > 0 ? 'author__in' : 'author__not_in';
2106
				$q[$key][] = abs( $author );
2107
			}
2108
			$q['author'] = implode( ',', $authors );
2109
		}
2110
2111
		if ( ! empty( $q['author__not_in'] ) ) {
2112
			$author__not_in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__not_in'] ) ) );
2113
			$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
2114
		} elseif ( ! empty( $q['author__in'] ) ) {
2115
			$author__in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__in'] ) ) );
2116
			$where .= " AND {$wpdb->posts}.post_author IN ($author__in) ";
2117
		}
2118
2119
		// Author stuff for nice URLs
2120
2121
		if ( '' != $q['author_name'] ) {
2122
			if ( strpos($q['author_name'], '/') !== false ) {
2123
				$q['author_name'] = explode('/', $q['author_name']);
2124
				if ( $q['author_name'][ count($q['author_name'])-1 ] ) {
2125
					$q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash
2126
				} else {
2127
					$q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash
2128
				}
2129
			}
2130
			$q['author_name'] = sanitize_title_for_query( $q['author_name'] );
2131
			$q['author'] = get_user_by('slug', $q['author_name']);
2132
			if ( $q['author'] )
2133
				$q['author'] = $q['author']->ID;
2134
			$whichauthor .= " AND ({$wpdb->posts}.post_author = " . absint($q['author']) . ')';
2135
		}
2136
2137
		// MIME-Type stuff for attachment browsing
2138
2139
		if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] ) {
2140
			$whichmimetype = wp_post_mime_type_where( $q['post_mime_type'], $wpdb->posts );
2141
		}
2142
		$where .= $search . $whichauthor . $whichmimetype;
2143
2144
		if ( ! empty( $this->meta_query->queries ) ) {
2145
			$clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
2146
			$join   .= $clauses['join'];
2147
			$where  .= $clauses['where'];
2148
		}
2149
2150
		$rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
2151
		if ( ! isset( $q['order'] ) ) {
2152
			$q['order'] = $rand ? '' : 'DESC';
2153
		} else {
2154
			$q['order'] = $rand ? '' : $this->parse_order( $q['order'] );
2155
		}
2156
2157
		// Order by.
2158
		if ( empty( $q['orderby'] ) ) {
2159
			/*
2160
			 * Boolean false or empty array blanks out ORDER BY,
2161
			 * while leaving the value unset or otherwise empty sets the default.
2162
			 */
2163
			if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
2164
				$orderby = '';
2165
			} else {
2166
				$orderby = "{$wpdb->posts}.post_date " . $q['order'];
2167
			}
2168
		} elseif ( 'none' == $q['orderby'] ) {
2169
			$orderby = '';
2170
		} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
2171
			$orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
2172
		} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
2173
			$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
2174
		} elseif ( $q['orderby'] == 'post_name__in' && ! empty( $post_name__in ) ) {
2175
			$orderby = "FIELD( {$wpdb->posts}.post_name, $post_name__in )";
2176
		} else {
2177
			$orderby_array = array();
2178
			if ( is_array( $q['orderby'] ) ) {
2179
				foreach ( $q['orderby'] as $_orderby => $order ) {
2180
					$orderby = addslashes_gpc( urldecode( $_orderby ) );
2181
					$parsed  = $this->parse_orderby( $orderby );
2182
2183
					if ( ! $parsed ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsed of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2184
						continue;
2185
					}
2186
2187
					$orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
2188
				}
2189
				$orderby = implode( ', ', $orderby_array );
2190
2191
			} else {
2192
				$q['orderby'] = urldecode( $q['orderby'] );
2193
				$q['orderby'] = addslashes_gpc( $q['orderby'] );
2194
2195
				foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
2196
					$parsed = $this->parse_orderby( $orderby );
2197
					// Only allow certain values for safety.
2198
					if ( ! $parsed ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsed of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2199
						continue;
2200
					}
2201
2202
					$orderby_array[] = $parsed;
2203
				}
2204
				$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
2205
2206
				if ( empty( $orderby ) ) {
2207
					$orderby = "{$wpdb->posts}.post_date " . $q['order'];
2208
				} elseif ( ! empty( $q['order'] ) ) {
2209
					$orderby .= " {$q['order']}";
2210
				}
2211
			}
2212
		}
2213
2214
		// Order search results by relevance only when another "orderby" is not specified in the query.
2215
		if ( ! empty( $q['s'] ) ) {
2216
			$search_orderby = '';
2217
			if ( ! empty( $q['search_orderby_title'] ) && ( empty( $q['orderby'] ) && ! $this->is_feed ) || ( isset( $q['orderby'] ) && 'relevance' === $q['orderby'] ) )
2218
				$search_orderby = $this->parse_search_order( $q );
2219
2220
			if ( ! $q['suppress_filters'] ) {
2221
				/**
2222
				 * Filters the ORDER BY used when ordering search results.
2223
				 *
2224
				 * @since 3.7.0
2225
				 *
2226
				 * @param string   $search_orderby The ORDER BY clause.
2227
				 * @param WP_Query $this           The current WP_Query instance.
2228
				 */
2229
				$search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );
2230
			}
2231
2232
			if ( $search_orderby )
2233
				$orderby = $orderby ? $search_orderby . ', ' . $orderby : $search_orderby;
2234
		}
2235
2236
		if ( is_array( $post_type ) && count( $post_type ) > 1 ) {
2237
			$post_type_cap = 'multiple_post_type';
2238
		} else {
2239
			if ( is_array( $post_type ) )
2240
				$post_type = reset( $post_type );
2241
			$post_type_object = get_post_type_object( $post_type );
2242
			if ( empty( $post_type_object ) )
2243
				$post_type_cap = $post_type;
2244
		}
2245
2246
		if ( isset( $q['post_password'] ) ) {
2247
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_password = %s", $q['post_password'] );
2248
			if ( empty( $q['perm'] ) ) {
2249
				$q['perm'] = 'readable';
2250
			}
2251
		} elseif ( isset( $q['has_password'] ) ) {
2252
			$where .= sprintf( " AND {$wpdb->posts}.post_password %s ''", $q['has_password'] ? '!=' : '=' );
2253
		}
2254
2255 View Code Duplication
		if ( ! empty( $q['comment_status'] ) ) {
2256
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_status = %s ", $q['comment_status'] );
2257
		}
2258
2259 View Code Duplication
		if ( ! empty( $q['ping_status'] ) )  {
2260
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.ping_status = %s ", $q['ping_status'] );
2261
		}
2262
2263
		if ( 'any' == $post_type ) {
2264
			$in_search_post_types = get_post_types( array('exclude_from_search' => false) );
2265
			if ( empty( $in_search_post_types ) ) {
2266
				$where .= ' AND 1=0 ';
2267
			} else {
2268
				$where .= " AND {$wpdb->posts}.post_type IN ('" . join( "', '", array_map( 'esc_sql', $in_search_post_types ) ) . "')";
2269
			}
2270
		} elseif ( !empty( $post_type ) && is_array( $post_type ) ) {
2271
			$where .= " AND {$wpdb->posts}.post_type IN ('" . join("', '", esc_sql( $post_type ) ) . "')";
2272
		} elseif ( ! empty( $post_type ) ) {
2273
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", $post_type );
2274
			$post_type_object = get_post_type_object ( $post_type );
2275
		} elseif ( $this->is_attachment ) {
2276
			$where .= " AND {$wpdb->posts}.post_type = 'attachment'";
2277
			$post_type_object = get_post_type_object ( 'attachment' );
2278
		} elseif ( $this->is_page ) {
2279
			$where .= " AND {$wpdb->posts}.post_type = 'page'";
2280
			$post_type_object = get_post_type_object ( 'page' );
2281
		} else {
2282
			$where .= " AND {$wpdb->posts}.post_type = 'post'";
2283
			$post_type_object = get_post_type_object ( 'post' );
2284
		}
2285
2286
		$edit_cap = 'edit_post';
2287
		$read_cap = 'read_post';
2288
2289
		if ( ! empty( $post_type_object ) ) {
2290
			$edit_others_cap = $post_type_object->cap->edit_others_posts;
2291
			$read_private_cap = $post_type_object->cap->read_private_posts;
2292
		} else {
2293
			$edit_others_cap = 'edit_others_' . $post_type_cap . 's';
0 ignored issues
show
The variable $post_type_cap does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2294
			$read_private_cap = 'read_private_' . $post_type_cap . 's';
2295
		}
2296
2297
		$user_id = get_current_user_id();
2298
2299
		$q_status = array();
2300
		if ( ! empty( $q['post_status'] ) ) {
2301
			$statuswheres = array();
2302
			$q_status = $q['post_status'];
2303
			if ( ! is_array( $q_status ) )
2304
				$q_status = explode(',', $q_status);
2305
			$r_status = array();
2306
			$p_status = array();
2307
			$e_status = array();
2308
			if ( in_array( 'any', $q_status ) ) {
2309
				foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
2310
					if ( ! in_array( $status, $q_status ) ) {
2311
						$e_status[] = "{$wpdb->posts}.post_status <> '$status'";
2312
					}
2313
				}
2314
			} else {
2315
				foreach ( get_post_stati() as $status ) {
2316
					if ( in_array( $status, $q_status ) ) {
2317
						if ( 'private' == $status ) {
2318
							$p_status[] = "{$wpdb->posts}.post_status = '$status'";
2319
						} else {
2320
							$r_status[] = "{$wpdb->posts}.post_status = '$status'";
2321
						}
2322
					}
2323
				}
2324
			}
2325
2326
			if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
2327
				$r_status = array_merge($r_status, $p_status);
2328
				unset($p_status);
2329
			}
2330
2331
			if ( !empty($e_status) ) {
2332
				$statuswheres[] = "(" . join( ' AND ', $e_status ) . ")";
2333
			}
2334 View Code Duplication
			if ( !empty($r_status) ) {
2335
				if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) ) {
2336
					$statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $r_status ) . "))";
2337
				} else {
2338
					$statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
2339
				}
2340
			}
2341 View Code Duplication
			if ( !empty($p_status) ) {
2342
				if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) ) {
2343
					$statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $p_status ) . "))";
2344
				} else {
2345
					$statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
2346
				}
2347
			}
2348
			if ( $post_status_join ) {
2349
				$join .= " LEFT JOIN {$wpdb->posts} AS p2 ON ({$wpdb->posts}.post_parent = p2.ID) ";
2350
				foreach ( $statuswheres as $index => $statuswhere ) {
2351
					$statuswheres[$index] = "($statuswhere OR ({$wpdb->posts}.post_status = 'inherit' AND " . str_replace( $wpdb->posts, 'p2', $statuswhere ) . "))";
2352
				}
2353
			}
2354
			$where_status = implode( ' OR ', $statuswheres );
2355
			if ( ! empty( $where_status ) ) {
2356
				$where .= " AND ($where_status)";
2357
			}
2358
		} elseif ( !$this->is_singular ) {
2359
			$where .= " AND ({$wpdb->posts}.post_status = 'publish'";
2360
2361
			// Add public states.
2362
			$public_states = get_post_stati( array('public' => true) );
2363
			foreach ( (array) $public_states as $state ) {
2364
				if ( 'publish' == $state ) // Publish is hard-coded above.
2365
					continue;
2366
				$where .= " OR {$wpdb->posts}.post_status = '$state'";
2367
			}
2368
2369
			if ( $this->is_admin ) {
2370
				// Add protected states that should show in the admin all list.
2371
				$admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
2372
				foreach ( (array) $admin_all_states as $state ) {
2373
					$where .= " OR {$wpdb->posts}.post_status = '$state'";
2374
				}
2375
			}
2376
2377
			if ( is_user_logged_in() ) {
2378
				// Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
2379
				$private_states = get_post_stati( array('private' => true) );
2380
				foreach ( (array) $private_states as $state ) {
2381
					$where .= current_user_can( $read_private_cap ) ? " OR {$wpdb->posts}.post_status = '$state'" : " OR {$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status = '$state'";
2382
				}
2383
			}
2384
2385
			$where .= ')';
2386
		}
2387
2388
		/*
2389
		 * Apply filters on where and join prior to paging so that any
2390
		 * manipulations to them are reflected in the paging by day queries.
2391
		 */
2392
		if ( !$q['suppress_filters'] ) {
2393
			/**
2394
			 * Filters the WHERE clause of the query.
2395
			 *
2396
			 * @since 1.5.0
2397
			 *
2398
			 * @param string   $where The WHERE clause of the query.
2399
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
2400
			 */
2401
			$where = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
2402
2403
			/**
2404
			 * Filters the JOIN clause of the query.
2405
			 *
2406
			 * @since 1.5.0
2407
			 *
2408
			 * @param string   $join  The JOIN clause of the query.
2409
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
2410
			 */
2411
			$join = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
2412
		}
2413
2414
		// Paging
2415
		if ( empty($q['nopaging']) && !$this->is_singular ) {
2416
			$page = absint($q['paged']);
2417
			if ( !$page )
2418
				$page = 1;
2419
2420
			// If 'offset' is provided, it takes precedence over 'paged'.
2421
			if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
2422
				$q['offset'] = absint( $q['offset'] );
2423
				$pgstrt = $q['offset'] . ', ';
2424
			} else {
2425
				$pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
2426
			}
2427
			$limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
2428
		}
2429
2430
		// Comments feeds
2431
		if ( $this->is_comment_feed && ! $this->is_singular ) {
2432
			if ( $this->is_archive || $this->is_search ) {
2433
				$cjoin = "JOIN {$wpdb->posts} ON ({$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID) $join ";
2434
				$cwhere = "WHERE comment_approved = '1' $where";
2435
				$cgroupby = "{$wpdb->comments}.comment_id";
2436
			} else { // Other non singular e.g. front
2437
				$cjoin = "JOIN {$wpdb->posts} ON ( {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID )";
2438
				$cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' AND post_type = 'attachment' ) ) AND comment_approved = '1'";
2439
				$cgroupby = '';
2440
			}
2441
2442
			if ( !$q['suppress_filters'] ) {
2443
				/**
2444
				 * Filters the JOIN clause of the comments feed query before sending.
2445
				 *
2446
				 * @since 2.2.0
2447
				 *
2448
				 * @param string   $cjoin The JOIN clause of the query.
2449
				 * @param WP_Query &$this The WP_Query instance (passed by reference).
2450
				 */
2451
				$cjoin = apply_filters_ref_array( 'comment_feed_join', array( $cjoin, &$this ) );
2452
2453
				/**
2454
				 * Filters the WHERE clause of the comments feed query before sending.
2455
				 *
2456
				 * @since 2.2.0
2457
				 *
2458
				 * @param string   $cwhere The WHERE clause of the query.
2459
				 * @param WP_Query &$this  The WP_Query instance (passed by reference).
2460
				 */
2461
				$cwhere = apply_filters_ref_array( 'comment_feed_where', array( $cwhere, &$this ) );
2462
2463
				/**
2464
				 * Filters the GROUP BY clause of the comments feed query before sending.
2465
				 *
2466
				 * @since 2.2.0
2467
				 *
2468
				 * @param string   $cgroupby The GROUP BY clause of the query.
2469
				 * @param WP_Query &$this    The WP_Query instance (passed by reference).
2470
				 */
2471
				$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( $cgroupby, &$this ) );
2472
2473
				/**
2474
				 * Filters the ORDER BY clause of the comments feed query before sending.
2475
				 *
2476
				 * @since 2.8.0
2477
				 *
2478
				 * @param string   $corderby The ORDER BY clause of the query.
2479
				 * @param WP_Query &$this    The WP_Query instance (passed by reference).
2480
				 */
2481
				$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
2482
2483
				/**
2484
				 * Filters the LIMIT clause of the comments feed query before sending.
2485
				 *
2486
				 * @since 2.8.0
2487
				 *
2488
				 * @param string   $climits The JOIN clause of the query.
2489
				 * @param WP_Query &$this   The WP_Query instance (passed by reference).
2490
				 */
2491
				$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
2492
			}
2493
			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
2494
			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
2495
2496
			$comments = (array) $wpdb->get_results("SELECT $distinct {$wpdb->comments}.* FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits");
0 ignored issues
show
The variable $climits does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2497
			// Convert to WP_Comment
2498
			$this->comments = array_map( 'get_comment', $comments );
2499
			$this->comment_count = count($this->comments);
2500
2501
			$post_ids = array();
2502
2503
			foreach ( $this->comments as $comment )
2504
				$post_ids[] = (int) $comment->comment_post_ID;
2505
2506
			$post_ids = join(',', $post_ids);
2507
			$join = '';
2508
			if ( $post_ids ) {
2509
				$where = "AND {$wpdb->posts}.ID IN ($post_ids) ";
2510
			} else {
2511
				$where = "AND 0";
2512
			}
2513
		}
2514
2515
		$pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );
2516
2517
		/*
2518
		 * Apply post-paging filters on where and join. Only plugins that
2519
		 * manipulate paging queries should use these hooks.
2520
		 */
2521 View Code Duplication
		if ( !$q['suppress_filters'] ) {
2522
			/**
2523
			 * Filters the WHERE clause of the query.
2524
			 *
2525
			 * Specifically for manipulating paging queries.
2526
			 *
2527
			 * @since 1.5.0
2528
			 *
2529
			 * @param string   $where The WHERE clause of the query.
2530
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
2531
			 */
2532
			$where = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
2533
2534
			/**
2535
			 * Filters the GROUP BY clause of the query.
2536
			 *
2537
			 * @since 2.0.0
2538
			 *
2539
			 * @param string   $groupby The GROUP BY clause of the query.
2540
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
2541
			 */
2542
			$groupby = apply_filters_ref_array( 'posts_groupby', array( $groupby, &$this ) );
2543
2544
			/**
2545
			 * Filters the JOIN clause of the query.
2546
			 *
2547
			 * Specifically for manipulating paging queries.
2548
			 *
2549
			 * @since 1.5.0
2550
			 *
2551
			 * @param string   $join  The JOIN clause of the query.
2552
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
2553
			 */
2554
			$join = apply_filters_ref_array( 'posts_join_paged', array( $join, &$this ) );
2555
2556
			/**
2557
			 * Filters the ORDER BY clause of the query.
2558
			 *
2559
			 * @since 1.5.1
2560
			 *
2561
			 * @param string   $orderby The ORDER BY clause of the query.
2562
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
2563
			 */
2564
			$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
2565
2566
			/**
2567
			 * Filters the DISTINCT clause of the query.
2568
			 *
2569
			 * @since 2.1.0
2570
			 *
2571
			 * @param string   $distinct The DISTINCT clause of the query.
2572
			 * @param WP_Query &$this    The WP_Query instance (passed by reference).
2573
			 */
2574
			$distinct = apply_filters_ref_array( 'posts_distinct', array( $distinct, &$this ) );
2575
2576
			/**
2577
			 * Filters the LIMIT clause of the query.
2578
			 *
2579
			 * @since 2.1.0
2580
			 *
2581
			 * @param string   $limits The LIMIT clause of the query.
2582
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
2583
			 */
2584
			$limits = apply_filters_ref_array( 'post_limits', array( $limits, &$this ) );
2585
2586
			/**
2587
			 * Filters the SELECT clause of the query.
2588
			 *
2589
			 * @since 2.1.0
2590
			 *
2591
			 * @param string   $fields The SELECT clause of the query.
2592
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
2593
			 */
2594
			$fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );
2595
2596
			/**
2597
			 * Filters all query clauses at once, for convenience.
2598
			 *
2599
			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
2600
			 * fields (SELECT), and LIMITS clauses.
2601
			 *
2602
			 * @since 3.1.0
2603
			 *
2604
			 * @param array    $clauses The list of clauses for the query.
2605
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
2606
			 */
2607
			$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
2608
2609
			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
2610
			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
2611
			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
2612
			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
2613
			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
2614
			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
2615
			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
2616
		}
2617
2618
		/**
2619
		 * Fires to announce the query's current selection parameters.
2620
		 *
2621
		 * For use by caching plugins.
2622
		 *
2623
		 * @since 2.3.0
2624
		 *
2625
		 * @param string $selection The assembled selection query.
2626
		 */
2627
		do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
2628
2629
		/*
2630
		 * Filters again for the benefit of caching plugins.
2631
		 * Regular plugins should use the hooks above.
2632
		 */
2633 View Code Duplication
		if ( !$q['suppress_filters'] ) {
2634
			/**
2635
			 * Filters the WHERE clause of the query.
2636
			 *
2637
			 * For use by caching plugins.
2638
			 *
2639
			 * @since 2.5.0
2640
			 *
2641
			 * @param string   $where The WHERE clause of the query.
2642
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
2643
			 */
2644
			$where = apply_filters_ref_array( 'posts_where_request', array( $where, &$this ) );
2645
2646
			/**
2647
			 * Filters the GROUP BY clause of the query.
2648
			 *
2649
			 * For use by caching plugins.
2650
			 *
2651
			 * @since 2.5.0
2652
			 *
2653
			 * @param string   $groupby The GROUP BY clause of the query.
2654
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
2655
			 */
2656
			$groupby = apply_filters_ref_array( 'posts_groupby_request', array( $groupby, &$this ) );
2657
2658
			/**
2659
			 * Filters the JOIN clause of the query.
2660
			 *
2661
			 * For use by caching plugins.
2662
			 *
2663
			 * @since 2.5.0
2664
			 *
2665
			 * @param string   $join  The JOIN clause of the query.
2666
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
2667
			 */
2668
			$join = apply_filters_ref_array( 'posts_join_request', array( $join, &$this ) );
2669
2670
			/**
2671
			 * Filters the ORDER BY clause of the query.
2672
			 *
2673
			 * For use by caching plugins.
2674
			 *
2675
			 * @since 2.5.0
2676
			 *
2677
			 * @param string   $orderby The ORDER BY clause of the query.
2678
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
2679
			 */
2680
			$orderby = apply_filters_ref_array( 'posts_orderby_request', array( $orderby, &$this ) );
2681
2682
			/**
2683
			 * Filters the DISTINCT clause of the query.
2684
			 *
2685
			 * For use by caching plugins.
2686
			 *
2687
			 * @since 2.5.0
2688
			 *
2689
			 * @param string   $distinct The DISTINCT clause of the query.
2690
			 * @param WP_Query &$this    The WP_Query instance (passed by reference).
2691
			 */
2692
			$distinct = apply_filters_ref_array( 'posts_distinct_request', array( $distinct, &$this ) );
2693
2694
			/**
2695
			 * Filters the SELECT clause of the query.
2696
			 *
2697
			 * For use by caching plugins.
2698
			 *
2699
			 * @since 2.5.0
2700
			 *
2701
			 * @param string   $fields The SELECT clause of the query.
2702
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
2703
			 */
2704
			$fields = apply_filters_ref_array( 'posts_fields_request', array( $fields, &$this ) );
2705
2706
			/**
2707
			 * Filters the LIMIT clause of the query.
2708
			 *
2709
			 * For use by caching plugins.
2710
			 *
2711
			 * @since 2.5.0
2712
			 *
2713
			 * @param string   $limits The LIMIT clause of the query.
2714
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
2715
			 */
2716
			$limits = apply_filters_ref_array( 'post_limits_request', array( $limits, &$this ) );
2717
2718
			/**
2719
			 * Filters all query clauses at once, for convenience.
2720
			 *
2721
			 * For use by caching plugins.
2722
			 *
2723
			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
2724
			 * fields (SELECT), and LIMITS clauses.
2725
			 *
2726
			 * @since 3.1.0
2727
			 *
2728
			 * @param array    $pieces The pieces of the query.
2729
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
2730
			 */
2731
			$clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
2732
2733
			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
2734
			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
2735
			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
2736
			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
2737
			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
2738
			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
2739
			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
2740
		}
2741
2742
		if ( ! empty($groupby) )
2743
			$groupby = 'GROUP BY ' . $groupby;
2744
		if ( !empty( $orderby ) )
2745
			$orderby = 'ORDER BY ' . $orderby;
2746
2747
		$found_rows = '';
2748
		if ( !$q['no_found_rows'] && !empty($limits) )
2749
			$found_rows = 'SQL_CALC_FOUND_ROWS';
2750
2751
		$this->request = $old_request = "SELECT $found_rows $distinct $fields FROM {$wpdb->posts} $join WHERE 1=1 $where $groupby $orderby $limits";
2752
2753
		if ( !$q['suppress_filters'] ) {
2754
			/**
2755
			 * Filters the completed SQL query before sending.
2756
			 *
2757
			 * @since 2.0.0
2758
			 *
2759
			 * @param string   $request The complete SQL query.
2760
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
2761
			 */
2762
			$this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
2763
		}
2764
2765
		/**
2766
		 * Filters the posts array before the query takes place.
2767
		 *
2768
		 * Return a non-null value to bypass WordPress's default post queries.
2769
		 *
2770
		 * Filtering functions that require pagination information are encouraged to set
2771
		 * the `found_posts` and `max_num_pages` properties of the WP_Query object,
2772
		 * passed to the filter by reference. If WP_Query does not perform a database
2773
		 * query, it will not have enough information to generate these values itself.
2774
		 *
2775
		 * @since 4.6.0
2776
		 *
2777
		 * @param array|null $posts Return an array of post data to short-circuit WP's query,
2778
		 *                          or null to allow WP to run its normal queries.
2779
		 * @param WP_Query   $this  The WP_Query instance, passed by reference.
2780
		 */
2781
		$this->posts = apply_filters_ref_array( 'posts_pre_query', array( null, &$this ) );
0 ignored issues
show
Documentation Bug introduced by
It seems like apply_filters_ref_array(...', array(null, &$this)) of type * is incompatible with the declared type array of property $posts.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
2782
2783
		if ( 'ids' == $q['fields'] ) {
2784
			if ( null === $this->posts ) {
2785
				$this->posts = $wpdb->get_col( $this->request );
2786
			}
2787
2788
			$this->posts = array_map( 'intval', $this->posts );
2789
			$this->post_count = count( $this->posts );
2790
			$this->set_found_posts( $q, $limits );
2791
2792
			return $this->posts;
2793
		}
2794
2795
		if ( 'id=>parent' == $q['fields'] ) {
2796
			if ( null === $this->posts ) {
2797
				$this->posts = $wpdb->get_results( $this->request );
2798
			}
2799
2800
			$this->post_count = count( $this->posts );
2801
			$this->set_found_posts( $q, $limits );
2802
2803
			$r = array();
2804
			foreach ( $this->posts as $key => $post ) {
2805
				$this->posts[ $key ]->ID = (int) $post->ID;
2806
				$this->posts[ $key ]->post_parent = (int) $post->post_parent;
2807
2808
				$r[ (int) $post->ID ] = (int) $post->post_parent;
2809
			}
2810
2811
			return $r;
2812
		}
2813
2814
		if ( null === $this->posts ) {
2815
			$split_the_query = ( $old_request == $this->request && "{$wpdb->posts}.*" == $fields && !empty( $limits ) && $q['posts_per_page'] < 500 );
2816
2817
			/**
2818
			 * Filters whether to split the query.
2819
			 *
2820
			 * Splitting the query will cause it to fetch just the IDs of the found posts
2821
			 * (and then individually fetch each post by ID), rather than fetching every
2822
			 * complete row at once. One massive result vs. many small results.
2823
			 *
2824
			 * @since 3.4.0
2825
			 *
2826
			 * @param bool     $split_the_query Whether or not to split the query.
2827
			 * @param WP_Query $this            The WP_Query instance.
2828
			 */
2829
			$split_the_query = apply_filters( 'split_the_query', $split_the_query, $this );
2830
2831
			if ( $split_the_query ) {
2832
				// First get the IDs and then fill in the objects
2833
2834
				$this->request = "SELECT $found_rows $distinct {$wpdb->posts}.ID FROM {$wpdb->posts} $join WHERE 1=1 $where $groupby $orderby $limits";
2835
2836
				/**
2837
				 * Filters the Post IDs SQL request before sending.
2838
				 *
2839
				 * @since 3.4.0
2840
				 *
2841
				 * @param string   $request The post ID request.
2842
				 * @param WP_Query $this    The WP_Query instance.
2843
				 */
2844
				$this->request = apply_filters( 'posts_request_ids', $this->request, $this );
2845
2846
				$ids = $wpdb->get_col( $this->request );
2847
2848
				if ( $ids ) {
2849
					$this->posts = $ids;
2850
					$this->set_found_posts( $q, $limits );
2851
					_prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
2852
				} else {
2853
					$this->posts = array();
2854
				}
2855
			} else {
2856
				$this->posts = $wpdb->get_results( $this->request );
2857
				$this->set_found_posts( $q, $limits );
2858
			}
2859
		}
2860
2861
		// Convert to WP_Post objects.
2862
		if ( $this->posts ) {
2863
			$this->posts = array_map( 'get_post', $this->posts );
2864
		}
2865
2866 View Code Duplication
		if ( ! $q['suppress_filters'] ) {
2867
			/**
2868
			 * Filters the raw post results array, prior to status checks.
2869
			 *
2870
			 * @since 2.3.0
2871
			 *
2872
			 * @param array    $posts The post results array.
2873
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
2874
			 */
2875
			$this->posts = apply_filters_ref_array( 'posts_results', array( $this->posts, &$this ) );
0 ignored issues
show
Documentation Bug introduced by
It seems like apply_filters_ref_array(...($this->posts, &$this)) of type * is incompatible with the declared type array of property $posts.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
2876
		}
2877
2878
		if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
2879
			/** This filter is documented in wp-includes/query.php */
2880
			$cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
2881
2882
			/** This filter is documented in wp-includes/query.php */
2883
			$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
2884
2885
			/** This filter is documented in wp-includes/query.php */
2886
			$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
2887
			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
2888
2889
			/** This filter is documented in wp-includes/query.php */
2890
			$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
2891
			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
2892
2893
			/** This filter is documented in wp-includes/query.php */
2894
			$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
2895
2896
			$comments_request = "SELECT {$wpdb->comments}.* FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";
2897
			$comments = $wpdb->get_results($comments_request);
2898
			// Convert to WP_Comment
2899
			$this->comments = array_map( 'get_comment', $comments );
2900
			$this->comment_count = count($this->comments);
2901
		}
2902
2903
		// Check post status to determine if post should be displayed.
2904
		if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
2905
			$status = get_post_status($this->posts[0]);
2906
			if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) {
2907
				$this->is_page = false;
2908
				$this->is_single = true;
2909
				$this->is_attachment = true;
2910
			}
2911
			$post_status_obj = get_post_status_object($status);
0 ignored issues
show
It seems like $status defined by get_post_status($this->posts[0]) on line 2905 can also be of type false; however, get_post_status_object() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
2912
2913
			// If the post_status was specifically requested, let it pass through.
2914
			if ( !$post_status_obj->public && ! in_array( $status, $q_status ) ) {
2915
2916
				if ( ! is_user_logged_in() ) {
2917
					// User must be logged in to view unpublished posts.
2918
					$this->posts = array();
2919
				} else {
2920
					if  ( $post_status_obj->protected ) {
2921
						// User must have edit permissions on the draft to preview.
2922
						if ( ! current_user_can($edit_cap, $this->posts[0]->ID) ) {
2923
							$this->posts = array();
2924
						} else {
2925
							$this->is_preview = true;
2926
							if ( 'future' != $status )
2927
								$this->posts[0]->post_date = current_time('mysql');
2928
						}
2929
					} elseif ( $post_status_obj->private ) {
2930
						if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
2931
							$this->posts = array();
2932
					} else {
2933
						$this->posts = array();
2934
					}
2935
				}
2936
			}
2937
2938
			if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
2939
				/**
2940
				 * Filters the single post for preview mode.
2941
				 *
2942
				 * @since 2.7.0
2943
				 *
2944
				 * @param WP_Post  $post_preview  The Post object.
2945
				 * @param WP_Query &$this         The WP_Query instance (passed by reference).
2946
				 */
2947
				$this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
2948
			}
2949
		}
2950
2951
		// Put sticky posts at the top of the posts array
2952
		$sticky_posts = get_option('sticky_posts');
2953
		if ( $this->is_home && $page <= 1 && is_array($sticky_posts) && !empty($sticky_posts) && !$q['ignore_sticky_posts'] ) {
2954
			$num_posts = count($this->posts);
2955
			$sticky_offset = 0;
2956
			// Loop over posts and relocate stickies to the front.
2957
			for ( $i = 0; $i < $num_posts; $i++ ) {
2958
				if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
2959
					$sticky_post = $this->posts[$i];
2960
					// Remove sticky from current position
2961
					array_splice($this->posts, $i, 1);
2962
					// Move to front, after other stickies
2963
					array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
2964
					// Increment the sticky offset. The next sticky will be placed at this offset.
2965
					$sticky_offset++;
2966
					// Remove post from sticky posts array
2967
					$offset = array_search($sticky_post->ID, $sticky_posts);
2968
					unset( $sticky_posts[$offset] );
2969
				}
2970
			}
2971
2972
			// If any posts have been excluded specifically, Ignore those that are sticky.
2973
			if ( !empty($sticky_posts) && !empty($q['post__not_in']) )
2974
				$sticky_posts = array_diff($sticky_posts, $q['post__not_in']);
2975
2976
			// Fetch sticky posts that weren't in the query results
2977
			if ( !empty($sticky_posts) ) {
2978
				$stickies = get_posts( array(
2979
					'post__in' => $sticky_posts,
2980
					'post_type' => $post_type,
2981
					'post_status' => 'publish',
2982
					'nopaging' => true
2983
				) );
2984
2985
				foreach ( $stickies as $sticky_post ) {
2986
					array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
2987
					$sticky_offset++;
2988
				}
2989
			}
2990
		}
2991
2992
		// If comments have been fetched as part of the query, make sure comment meta lazy-loading is set up.
2993
		if ( ! empty( $this->comments ) ) {
2994
			wp_queue_comments_for_comment_meta_lazyload( $this->comments );
2995
		}
2996
2997 View Code Duplication
		if ( ! $q['suppress_filters'] ) {
2998
			/**
2999
			 * Filters the array of retrieved posts after they've been fetched and
3000
			 * internally processed.
3001
			 *
3002
			 * @since 1.5.0
3003
			 *
3004
			 * @param array    $posts The array of retrieved posts.
3005
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3006
			 */
3007
			$this->posts = apply_filters_ref_array( 'the_posts', array( $this->posts, &$this ) );
0 ignored issues
show
Documentation Bug introduced by
It seems like apply_filters_ref_array(...($this->posts, &$this)) of type * is incompatible with the declared type array of property $posts.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
3008
		}
3009
3010
		// Ensure that any posts added/modified via one of the filters above are
3011
		// of the type WP_Post and are filtered.
3012
		if ( $this->posts ) {
3013
			$this->post_count = count( $this->posts );
3014
3015
			$this->posts = array_map( 'get_post', $this->posts );
3016
3017
			if ( $q['cache_results'] )
3018
				update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
3019
3020
			$this->post = reset( $this->posts );
3021
		} else {
3022
			$this->post_count = 0;
3023
			$this->posts = array();
3024
		}
3025
3026
		if ( $q['lazy_load_term_meta'] ) {
3027
			wp_queue_posts_for_term_meta_lazyload( $this->posts );
3028
		}
3029
3030
		return $this->posts;
3031
	}
3032
3033
	/**
3034
	 * Set up the amount of found posts and the number of pages (if limit clause was used)
3035
	 * for the current query.
3036
	 *
3037
	 * @since 3.5.0
3038
	 * @access private
3039
	 *
3040
	 * @param array  $q      Query variables.
3041
	 * @param string $limits LIMIT clauses of the query.
3042
	 */
3043
	private function set_found_posts( $q, $limits ) {
3044
		global $wpdb;
3045
		// Bail if posts is an empty array. Continue if posts is an empty string,
3046
		// null, or false to accommodate caching plugins that fill posts later.
3047
		if ( $q['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) )
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->posts of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
3048
			return;
3049
3050
		if ( ! empty( $limits ) ) {
3051
			/**
3052
			 * Filters the query to run for retrieving the found posts.
3053
			 *
3054
			 * @since 2.1.0
3055
			 *
3056
			 * @param string   $found_posts The query to run to find the found posts.
3057
			 * @param WP_Query &$this       The WP_Query instance (passed by reference).
3058
			 */
3059
			$this->found_posts = $wpdb->get_var( apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ) );
3060
		} else {
3061
			$this->found_posts = count( $this->posts );
3062
		}
3063
3064
		/**
3065
		 * Filters the number of found posts for the query.
3066
		 *
3067
		 * @since 2.1.0
3068
		 *
3069
		 * @param int      $found_posts The number of posts found.
3070
		 * @param WP_Query &$this       The WP_Query instance (passed by reference).
3071
		 */
3072
		$this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
3073
3074
		if ( ! empty( $limits ) )
3075
			$this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] );
0 ignored issues
show
Documentation Bug introduced by
The property $max_num_pages was declared of type integer, but ceil($this->found_posts / $q['posts_per_page']) 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...
3076
	}
3077
3078
	/**
3079
	 * Set up the next post and iterate current post index.
3080
	 *
3081
	 * @since 1.5.0
3082
	 * @access public
3083
	 *
3084
	 * @return WP_Post Next post.
3085
	 */
3086
	public function next_post() {
3087
3088
		$this->current_post++;
3089
3090
		$this->post = $this->posts[$this->current_post];
3091
		return $this->post;
3092
	}
3093
3094
	/**
3095
	 * Sets up the current post.
3096
	 *
3097
	 * Retrieves the next post, sets up the post, sets the 'in the loop'
3098
	 * property to true.
3099
	 *
3100
	 * @since 1.5.0
3101
	 * @access public
3102
	 *
3103
	 * @global WP_Post $post
3104
	 */
3105
	public function the_post() {
3106
		global $post;
3107
		$this->in_the_loop = true;
3108
3109
		if ( $this->current_post == -1 ) // loop has just started
3110
			/**
3111
			 * Fires once the loop is started.
3112
			 *
3113
			 * @since 2.0.0
3114
			 *
3115
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3116
			 */
3117
			do_action_ref_array( 'loop_start', array( &$this ) );
3118
3119
		$post = $this->next_post();
3120
		$this->setup_postdata( $post );
3121
	}
3122
3123
	/**
3124
	 * Determines whether there are more posts available in the loop.
3125
	 *
3126
	 * Calls the {@see 'loop_end'} action when the loop is complete.
3127
	 *
3128
	 * @since 1.5.0
3129
	 * @access public
3130
	 *
3131
	 * @return bool True if posts are available, false if end of loop.
3132
	 */
3133
	public function have_posts() {
3134
		if ( $this->current_post + 1 < $this->post_count ) {
3135
			return true;
3136
		} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
3137
			/**
3138
			 * Fires once the loop has ended.
3139
			 *
3140
			 * @since 2.0.0
3141
			 *
3142
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3143
			 */
3144
			do_action_ref_array( 'loop_end', array( &$this ) );
3145
			// Do some cleaning up after the loop
3146
			$this->rewind_posts();
3147
		}
3148
3149
		$this->in_the_loop = false;
3150
		return false;
3151
	}
3152
3153
	/**
3154
	 * Rewind the posts and reset post index.
3155
	 *
3156
	 * @since 1.5.0
3157
	 * @access public
3158
	 */
3159
	public function rewind_posts() {
3160
		$this->current_post = -1;
3161
		if ( $this->post_count > 0 ) {
3162
			$this->post = $this->posts[0];
3163
		}
3164
	}
3165
3166
	/**
3167
	 * Iterate current comment index and return WP_Comment object.
3168
	 *
3169
	 * @since 2.2.0
3170
	 * @access public
3171
	 *
3172
	 * @return WP_Comment Comment object.
3173
	 */
3174
	public function next_comment() {
3175
		$this->current_comment++;
3176
3177
		$this->comment = $this->comments[$this->current_comment];
3178
		return $this->comment;
3179
	}
3180
3181
	/**
3182
	 * Sets up the current comment.
3183
	 *
3184
	 * @since 2.2.0
3185
	 * @access public
3186
	 * @global WP_Comment $comment Current comment.
3187
	 */
3188
	public function the_comment() {
3189
		global $comment;
3190
3191
		$comment = $this->next_comment();
3192
3193
		if ( $this->current_comment == 0 ) {
3194
			/**
3195
			 * Fires once the comment loop is started.
3196
			 *
3197
			 * @since 2.2.0
3198
			 */
3199
			do_action( 'comment_loop_start' );
3200
		}
3201
	}
3202
3203
	/**
3204
	 * Whether there are more comments available.
3205
	 *
3206
	 * Automatically rewinds comments when finished.
3207
	 *
3208
	 * @since 2.2.0
3209
	 * @access public
3210
	 *
3211
	 * @return bool True, if more comments. False, if no more posts.
3212
	 */
3213
	public function have_comments() {
3214
		if ( $this->current_comment + 1 < $this->comment_count ) {
3215
			return true;
3216
		} elseif ( $this->current_comment + 1 == $this->comment_count ) {
3217
			$this->rewind_comments();
3218
		}
3219
3220
		return false;
3221
	}
3222
3223
	/**
3224
	 * Rewind the comments, resets the comment index and comment to first.
3225
	 *
3226
	 * @since 2.2.0
3227
	 * @access public
3228
	 */
3229
	public function rewind_comments() {
3230
		$this->current_comment = -1;
3231
		if ( $this->comment_count > 0 ) {
3232
			$this->comment = $this->comments[0];
3233
		}
3234
	}
3235
3236
	/**
3237
	 * Sets up the WordPress query by parsing query string.
3238
	 *
3239
	 * @since 1.5.0
3240
	 * @access public
3241
	 *
3242
	 * @param string|array $query URL query string or array of query arguments.
3243
	 * @return array List of posts.
3244
	 */
3245
	public function query( $query ) {
3246
		$this->init();
3247
		$this->query = $this->query_vars = wp_parse_args( $query );
3248
		return $this->get_posts();
3249
	}
3250
3251
	/**
3252
	 * Retrieve queried object.
3253
	 *
3254
	 * If queried object is not set, then the queried object will be set from
3255
	 * the category, tag, taxonomy, posts page, single post, page, or author
3256
	 * query variable. After it is set up, it will be returned.
3257
	 *
3258
	 * @since 1.5.0
3259
	 * @access public
3260
	 *
3261
	 * @return object
0 ignored issues
show
Should the return type not be object|array|null|false? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
3262
	 */
3263
	public function get_queried_object() {
3264
		if ( isset($this->queried_object) )
3265
			return $this->queried_object;
3266
3267
		$this->queried_object = null;
3268
		$this->queried_object_id = null;
3269
3270
		if ( $this->is_category || $this->is_tag || $this->is_tax ) {
3271
			if ( $this->is_category ) {
3272
				if ( $this->get( 'cat' ) ) {
3273
					$term = get_term( $this->get( 'cat' ), 'category' );
3274
				} elseif ( $this->get( 'category_name' ) ) {
3275
					$term = get_term_by( 'slug', $this->get( 'category_name' ), 'category' );
3276
				}
3277
			} elseif ( $this->is_tag ) {
3278
				if ( $this->get( 'tag_id' ) ) {
3279
					$term = get_term( $this->get( 'tag_id' ), 'post_tag' );
3280
				} elseif ( $this->get( 'tag' ) ) {
3281
					$term = get_term_by( 'slug', $this->get( 'tag' ), 'post_tag' );
3282
				}
3283
			} else {
3284
				// For other tax queries, grab the first term from the first clause.
3285
				if ( ! empty( $this->tax_query->queried_terms ) ) {
3286
					$queried_taxonomies = array_keys( $this->tax_query->queried_terms );
3287
					$matched_taxonomy = reset( $queried_taxonomies );
3288
					$query = $this->tax_query->queried_terms[ $matched_taxonomy ];
3289
3290
					if ( ! empty( $query['terms'] ) ) {
3291
						if ( 'term_id' == $query['field'] ) {
3292
							$term = get_term( reset( $query['terms'] ), $matched_taxonomy );
3293
						} else {
3294
							$term = get_term_by( $query['field'], reset( $query['terms'] ), $matched_taxonomy );
3295
						}
3296
					}
3297
				}
3298
			}
3299
3300
			if ( ! empty( $term ) && ! is_wp_error( $term ) )  {
3301
				$this->queried_object = $term;
3302
				$this->queried_object_id = (int) $term->term_id;
3303
3304
				if ( $this->is_category && 'category' === $this->queried_object->taxonomy )
3305
					_make_cat_compat( $this->queried_object );
3306
			}
3307
		} elseif ( $this->is_post_type_archive ) {
3308
			$post_type = $this->get( 'post_type' );
3309
			if ( is_array( $post_type ) )
3310
				$post_type = reset( $post_type );
3311
			$this->queried_object = get_post_type_object( $post_type );
3312
		} elseif ( $this->is_posts_page ) {
3313
			$page_for_posts = get_option('page_for_posts');
3314
			$this->queried_object = get_post( $page_for_posts );
3315
			$this->queried_object_id = (int) $this->queried_object->ID;
3316
		} elseif ( $this->is_singular && ! empty( $this->post ) ) {
3317
			$this->queried_object = $this->post;
3318
			$this->queried_object_id = (int) $this->post->ID;
3319
		} elseif ( $this->is_author ) {
3320
			$this->queried_object_id = (int) $this->get('author');
3321
			$this->queried_object = get_userdata( $this->queried_object_id );
0 ignored issues
show
Documentation Bug introduced by
It seems like get_userdata($this->queried_object_id) can also be of type false. However, the property $queried_object is declared as type object|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...
3322
		}
3323
3324
		return $this->queried_object;
3325
	}
3326
3327
	/**
3328
	 * Retrieve ID of the current queried object.
3329
	 *
3330
	 * @since 1.5.0
3331
	 * @access public
3332
	 *
3333
	 * @return int
3334
	 */
3335
	public function get_queried_object_id() {
3336
		$this->get_queried_object();
3337
3338
		if ( isset($this->queried_object_id) ) {
3339
			return $this->queried_object_id;
3340
		}
3341
3342
		return 0;
3343
	}
3344
3345
	/**
3346
	 * Constructor.
3347
	 *
3348
	 * Sets up the WordPress query, if parameter is not empty.
3349
	 *
3350
	 * @since 1.5.0
3351
	 * @access public
3352
	 *
3353
	 * @param string|array $query URL query string or array of vars.
3354
	 */
3355
	public function __construct( $query = '' ) {
3356
		if ( ! empty( $query ) ) {
3357
			$this->query( $query );
3358
		}
3359
	}
3360
3361
	/**
3362
	 * Make private properties readable for backward compatibility.
3363
	 *
3364
	 * @since 4.0.0
3365
	 * @access public
3366
	 *
3367
	 * @param string $name Property to get.
3368
	 * @return mixed Property.
3369
	 */
3370
	public function __get( $name ) {
3371
		if ( in_array( $name, $this->compat_fields ) ) {
3372
			return $this->$name;
3373
		}
3374
	}
3375
3376
	/**
3377
	 * Make private properties checkable for backward compatibility.
3378
	 *
3379
	 * @since 4.0.0
3380
	 * @access public
3381
	 *
3382
	 * @param string $name Property to check if set.
3383
	 * @return bool Whether the property is set.
0 ignored issues
show
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
3384
	 */
3385
	public function __isset( $name ) {
3386
		if ( in_array( $name, $this->compat_fields ) ) {
3387
			return isset( $this->$name );
3388
		}
3389
	}
3390
3391
	/**
3392
	 * Make private/protected methods readable for backward compatibility.
3393
	 *
3394
	 * @since 4.0.0
3395
	 * @access public
3396
	 *
3397
	 * @param callable $name      Method to call.
3398
	 * @param array    $arguments Arguments to pass when calling.
3399
	 * @return mixed|false Return value of the callback, false otherwise.
3400
	 */
3401
	public function __call( $name, $arguments ) {
3402
		if ( in_array( $name, $this->compat_methods ) ) {
3403
			return call_user_func_array( array( $this, $name ), $arguments );
3404
		}
3405
		return false;
3406
	}
3407
3408
	/**
3409
 	 * Is the query for an existing archive page?
3410
 	 *
3411
 	 * Month, Year, Category, Author, Post Type archive...
3412
	 *
3413
 	 * @since 3.1.0
3414
 	 *
3415
 	 * @return bool
3416
 	 */
3417
	public function is_archive() {
3418
		return (bool) $this->is_archive;
3419
	}
3420
3421
	/**
3422
	 * Is the query for an existing post type archive page?
3423
	 *
3424
	 * @since 3.1.0
3425
	 *
3426
	 * @param mixed $post_types Optional. Post type or array of posts types to check against.
3427
	 * @return bool
3428
	 */
3429
	public function is_post_type_archive( $post_types = '' ) {
3430
		if ( empty( $post_types ) || ! $this->is_post_type_archive )
3431
			return (bool) $this->is_post_type_archive;
3432
3433
		$post_type = $this->get( 'post_type' );
3434
		if ( is_array( $post_type ) )
3435
			$post_type = reset( $post_type );
3436
		$post_type_object = get_post_type_object( $post_type );
3437
3438
		return in_array( $post_type_object->name, (array) $post_types );
3439
	}
3440
3441
	/**
3442
	 * Is the query for an existing attachment page?
3443
	 *
3444
	 * @since 3.1.0
3445
	 *
3446
	 * @param mixed $attachment Attachment ID, title, slug, or array of such.
3447
	 * @return bool
3448
	 */
3449 View Code Duplication
	public function is_attachment( $attachment = '' ) {
3450
		if ( ! $this->is_attachment ) {
3451
			return false;
3452
		}
3453
3454
		if ( empty( $attachment ) ) {
3455
			return true;
3456
		}
3457
3458
		$attachment = array_map( 'strval', (array) $attachment );
3459
3460
		$post_obj = $this->get_queried_object();
3461
3462
		if ( in_array( (string) $post_obj->ID, $attachment ) ) {
3463
			return true;
3464
		} elseif ( in_array( $post_obj->post_title, $attachment ) ) {
3465
			return true;
3466
		} elseif ( in_array( $post_obj->post_name, $attachment ) ) {
3467
			return true;
3468
		}
3469
		return false;
3470
	}
3471
3472
	/**
3473
	 * Is the query for an existing author archive page?
3474
	 *
3475
	 * If the $author parameter is specified, this function will additionally
3476
	 * check if the query is for one of the authors specified.
3477
	 *
3478
	 * @since 3.1.0
3479
	 *
3480
	 * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
3481
	 * @return bool
3482
	 */
3483 View Code Duplication
	public function is_author( $author = '' ) {
3484
		if ( !$this->is_author )
3485
			return false;
3486
3487
		if ( empty($author) )
3488
			return true;
3489
3490
		$author_obj = $this->get_queried_object();
3491
3492
		$author = array_map( 'strval', (array) $author );
3493
3494
		if ( in_array( (string) $author_obj->ID, $author ) )
3495
			return true;
3496
		elseif ( in_array( $author_obj->nickname, $author ) )
3497
			return true;
3498
		elseif ( in_array( $author_obj->user_nicename, $author ) )
3499
			return true;
3500
3501
		return false;
3502
	}
3503
3504
	/**
3505
	 * Is the query for an existing category archive page?
3506
	 *
3507
	 * If the $category parameter is specified, this function will additionally
3508
	 * check if the query is for one of the categories specified.
3509
	 *
3510
	 * @since 3.1.0
3511
	 *
3512
	 * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
3513
	 * @return bool
3514
	 */
3515 View Code Duplication
	public function is_category( $category = '' ) {
3516
		if ( !$this->is_category )
3517
			return false;
3518
3519
		if ( empty($category) )
3520
			return true;
3521
3522
		$cat_obj = $this->get_queried_object();
3523
3524
		$category = array_map( 'strval', (array) $category );
3525
3526
		if ( in_array( (string) $cat_obj->term_id, $category ) )
3527
			return true;
3528
		elseif ( in_array( $cat_obj->name, $category ) )
3529
			return true;
3530
		elseif ( in_array( $cat_obj->slug, $category ) )
3531
			return true;
3532
3533
		return false;
3534
	}
3535
3536
	/**
3537
	 * Is the query for an existing tag archive page?
3538
	 *
3539
	 * If the $tag parameter is specified, this function will additionally
3540
	 * check if the query is for one of the tags specified.
3541
	 *
3542
	 * @since 3.1.0
3543
	 *
3544
	 * @param mixed $tag Optional. Tag ID, name, slug, or array of Tag IDs, names, and slugs.
3545
	 * @return bool
3546
	 */
3547 View Code Duplication
	public function is_tag( $tag = '' ) {
3548
		if ( ! $this->is_tag )
3549
			return false;
3550
3551
		if ( empty( $tag ) )
3552
			return true;
3553
3554
		$tag_obj = $this->get_queried_object();
3555
3556
		$tag = array_map( 'strval', (array) $tag );
3557
3558
		if ( in_array( (string) $tag_obj->term_id, $tag ) )
3559
			return true;
3560
		elseif ( in_array( $tag_obj->name, $tag ) )
3561
			return true;
3562
		elseif ( in_array( $tag_obj->slug, $tag ) )
3563
			return true;
3564
3565
		return false;
3566
	}
3567
3568
	/**
3569
	 * Is the query for an existing custom taxonomy archive page?
3570
	 *
3571
	 * If the $taxonomy parameter is specified, this function will additionally
3572
	 * check if the query is for that specific $taxonomy.
3573
	 *
3574
	 * If the $term parameter is specified in addition to the $taxonomy parameter,
3575
	 * this function will additionally check if the query is for one of the terms
3576
	 * specified.
3577
	 *
3578
	 * @since 3.1.0
3579
	 *
3580
	 * @global array $wp_taxonomies
3581
	 *
3582
	 * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
3583
	 * @param mixed $term     Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
3584
	 * @return bool True for custom taxonomy archive pages, false for built-in taxonomies (category and tag archives).
3585
	 */
3586
	public function is_tax( $taxonomy = '', $term = '' ) {
3587
		global $wp_taxonomies;
3588
3589
		if ( !$this->is_tax )
3590
			return false;
3591
3592
		if ( empty( $taxonomy ) )
3593
			return true;
3594
3595
		$queried_object = $this->get_queried_object();
3596
		$tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
3597
		$term_array = (array) $term;
3598
3599
		// Check that the taxonomy matches.
3600
		if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
3601
			return false;
3602
3603
		// Only a Taxonomy provided.
3604
		if ( empty( $term ) )
3605
			return true;
3606
3607
		return isset( $queried_object->term_id ) &&
3608
			count( array_intersect(
3609
				array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
3610
				$term_array
3611
			) );
3612
	}
3613
3614
	/**
3615
	 * Whether the current URL is within the comments popup window.
3616
	 *
3617
	 * @since 3.1.0
3618
	 * @deprecated 4.5.0
3619
	 *
3620
	 * @return bool
3621
	 */
3622
	public function is_comments_popup() {
3623
		_deprecated_function( __FUNCTION__, '4.5.0' );
3624
3625
		return false;
3626
	}
3627
3628
	/**
3629
	 * Is the query for an existing date archive?
3630
	 *
3631
	 * @since 3.1.0
3632
	 *
3633
	 * @return bool
3634
	 */
3635
	public function is_date() {
3636
		return (bool) $this->is_date;
3637
	}
3638
3639
	/**
3640
	 * Is the query for an existing day archive?
3641
	 *
3642
	 * @since 3.1.0
3643
	 *
3644
	 * @return bool
3645
	 */
3646
	public function is_day() {
3647
		return (bool) $this->is_day;
3648
	}
3649
3650
	/**
3651
	 * Is the query for a feed?
3652
	 *
3653
	 * @since 3.1.0
3654
	 *
3655
	 * @param string|array $feeds Optional feed types to check.
3656
	 * @return bool
3657
	 */
3658
	public function is_feed( $feeds = '' ) {
3659
		if ( empty( $feeds ) || ! $this->is_feed )
3660
			return (bool) $this->is_feed;
3661
		$qv = $this->get( 'feed' );
3662
		if ( 'feed' == $qv )
3663
			$qv = get_default_feed();
3664
		return in_array( $qv, (array) $feeds );
3665
	}
3666
3667
	/**
3668
	 * Is the query for a comments feed?
3669
	 *
3670
	 * @since 3.1.0
3671
	 *
3672
	 * @return bool
3673
	 */
3674
	public function is_comment_feed() {
3675
		return (bool) $this->is_comment_feed;
3676
	}
3677
3678
	/**
3679
	 * Is the query for the front page of the site?
3680
	 *
3681
	 * This is for what is displayed at your site's main URL.
3682
	 *
3683
	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
3684
	 *
3685
	 * If you set a static page for the front page of your site, this function will return
3686
	 * true when viewing that page.
3687
	 *
3688
	 * Otherwise the same as @see WP_Query::is_home()
3689
	 *
3690
	 * @since 3.1.0
3691
	 *
3692
	 * @return bool True, if front of site.
3693
	 */
3694
	public function is_front_page() {
3695
		// most likely case
3696
		if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
3697
			return true;
3698
		elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
3699
			return true;
3700
		else
3701
			return false;
3702
	}
3703
3704
	/**
3705
	 * Is the query for the blog homepage?
3706
	 *
3707
	 * This is the page which shows the time based blog content of your site.
3708
	 *
3709
	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
3710
	 *
3711
	 * If you set a static page for the front page of your site, this function will return
3712
	 * true only on the page you set as the "Posts page".
3713
	 *
3714
	 * @see WP_Query::is_front_page()
3715
	 *
3716
	 * @since 3.1.0
3717
	 *
3718
	 * @return bool True if blog view homepage.
3719
	 */
3720
	public function is_home() {
3721
		return (bool) $this->is_home;
3722
	}
3723
3724
	/**
3725
	 * Is the query for an existing month archive?
3726
	 *
3727
	 * @since 3.1.0
3728
	 *
3729
	 * @return bool
3730
	 */
3731
	public function is_month() {
3732
		return (bool) $this->is_month;
3733
	}
3734
3735
	/**
3736
	 * Is the query for an existing single page?
3737
	 *
3738
	 * If the $page parameter is specified, this function will additionally
3739
	 * check if the query is for one of the pages specified.
3740
	 *
3741
	 * @see WP_Query::is_single()
3742
	 * @see WP_Query::is_singular()
3743
	 *
3744
	 * @since 3.1.0
3745
	 *
3746
	 * @param int|string|array $page Optional. Page ID, title, slug, path, or array of such. Default empty.
3747
	 * @return bool Whether the query is for an existing single page.
3748
	 */
3749 View Code Duplication
	public function is_page( $page = '' ) {
3750
		if ( !$this->is_page )
3751
			return false;
3752
3753
		if ( empty( $page ) )
3754
			return true;
3755
3756
		$page_obj = $this->get_queried_object();
3757
3758
		$page = array_map( 'strval', (array) $page );
3759
3760
		if ( in_array( (string) $page_obj->ID, $page ) ) {
3761
			return true;
3762
		} elseif ( in_array( $page_obj->post_title, $page ) ) {
3763
			return true;
3764
		} elseif ( in_array( $page_obj->post_name, $page ) ) {
3765
			return true;
3766
		} else {
3767
			foreach ( $page as $pagepath ) {
3768
				if ( ! strpos( $pagepath, '/' ) ) {
3769
					continue;
3770
				}
3771
				$pagepath_obj = get_page_by_path( $pagepath );
3772
3773
				if ( $pagepath_obj && ( $pagepath_obj->ID == $page_obj->ID ) ) {
3774
					return true;
3775
				}
3776
			}
3777
		}
3778
3779
		return false;
3780
	}
3781
3782
	/**
3783
	 * Is the query for paged result and not for the first page?
3784
	 *
3785
	 * @since 3.1.0
3786
	 *
3787
	 * @return bool
3788
	 */
3789
	public function is_paged() {
3790
		return (bool) $this->is_paged;
3791
	}
3792
3793
	/**
3794
	 * Is the query for a post or page preview?
3795
	 *
3796
	 * @since 3.1.0
3797
	 *
3798
	 * @return bool
3799
	 */
3800
	public function is_preview() {
3801
		return (bool) $this->is_preview;
3802
	}
3803
3804
	/**
3805
	 * Is the query for the robots file?
3806
	 *
3807
	 * @since 3.1.0
3808
	 *
3809
	 * @return bool
3810
	 */
3811
	public function is_robots() {
3812
		return (bool) $this->is_robots;
3813
	}
3814
3815
	/**
3816
	 * Is the query for a search?
3817
	 *
3818
	 * @since 3.1.0
3819
	 *
3820
	 * @return bool
3821
	 */
3822
	public function is_search() {
3823
		return (bool) $this->is_search;
3824
	}
3825
3826
	/**
3827
	 * Is the query for an existing single post?
3828
	 *
3829
	 * Works for any post type excluding pages.
3830
	 *
3831
	 * If the $post parameter is specified, this function will additionally
3832
	 * check if the query is for one of the Posts specified.
3833
	 *
3834
	 * @see WP_Query::is_page()
3835
	 * @see WP_Query::is_singular()
3836
	 *
3837
	 * @since 3.1.0
3838
	 *
3839
	 * @param int|string|array $post Optional. Post ID, title, slug, path, or array of such. Default empty.
3840
	 * @return bool Whether the query is for an existing single post.
3841
	 */
3842 View Code Duplication
	public function is_single( $post = '' ) {
3843
		if ( !$this->is_single )
3844
			return false;
3845
3846
		if ( empty($post) )
3847
			return true;
3848
3849
		$post_obj = $this->get_queried_object();
3850
3851
		$post = array_map( 'strval', (array) $post );
3852
3853
		if ( in_array( (string) $post_obj->ID, $post ) ) {
3854
			return true;
3855
		} elseif ( in_array( $post_obj->post_title, $post ) ) {
3856
			return true;
3857
		} elseif ( in_array( $post_obj->post_name, $post ) ) {
3858
			return true;
3859
		} else {
3860
			foreach ( $post as $postpath ) {
3861
				if ( ! strpos( $postpath, '/' ) ) {
3862
					continue;
3863
				}
3864
				$postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );
3865
3866
				if ( $postpath_obj && ( $postpath_obj->ID == $post_obj->ID ) ) {
3867
					return true;
3868
				}
3869
			}
3870
		}
3871
		return false;
3872
	}
3873
3874
	/**
3875
	 * Is the query for an existing single post of any post type (post, attachment, page,
3876
	 * custom post types)?
3877
	 *
3878
	 * If the $post_types parameter is specified, this function will additionally
3879
	 * check if the query is for one of the Posts Types specified.
3880
	 *
3881
	 * @see WP_Query::is_page()
3882
	 * @see WP_Query::is_single()
3883
	 *
3884
	 * @since 3.1.0
3885
	 *
3886
	 * @param string|array $post_types Optional. Post type or array of post types. Default empty.
3887
	 * @return bool Whether the query is for an existing single post of any of the given post types.
3888
	 */
3889
	public function is_singular( $post_types = '' ) {
3890
		if ( empty( $post_types ) || !$this->is_singular )
3891
			return (bool) $this->is_singular;
3892
3893
		$post_obj = $this->get_queried_object();
3894
3895
		return in_array( $post_obj->post_type, (array) $post_types );
3896
	}
3897
3898
	/**
3899
	 * Is the query for a specific time?
3900
	 *
3901
	 * @since 3.1.0
3902
	 *
3903
	 * @return bool
3904
	 */
3905
	public function is_time() {
3906
		return (bool) $this->is_time;
3907
	}
3908
3909
	/**
3910
	 * Is the query for a trackback endpoint call?
3911
	 *
3912
	 * @since 3.1.0
3913
	 *
3914
	 * @return bool
3915
	 */
3916
	public function is_trackback() {
3917
		return (bool) $this->is_trackback;
3918
	}
3919
3920
	/**
3921
	 * Is the query for an existing year archive?
3922
	 *
3923
	 * @since 3.1.0
3924
	 *
3925
	 * @return bool
3926
	 */
3927
	public function is_year() {
3928
		return (bool) $this->is_year;
3929
	}
3930
3931
	/**
3932
	 * Is the query a 404 (returns no results)?
3933
	 *
3934
	 * @since 3.1.0
3935
	 *
3936
	 * @return bool
3937
	 */
3938
	public function is_404() {
3939
		return (bool) $this->is_404;
3940
	}
3941
3942
	/**
3943
	 * Is the query for an embedded post?
3944
	 *
3945
	 * @since 4.4.0
3946
	 *
3947
	 * @return bool
3948
	 */
3949
	public function is_embed() {
3950
		return (bool) $this->is_embed;
3951
	}
3952
3953
	/**
3954
	 * Is the query the main query?
3955
	 *
3956
	 * @since 3.3.0
3957
	 *
3958
	 * @global WP_Query $wp_query Global WP_Query instance.
3959
	 *
3960
	 * @return bool
3961
	 */
3962
	public function is_main_query() {
3963
		global $wp_the_query;
3964
		return $wp_the_query === $this;
3965
	}
3966
3967
	/**
3968
	 * Set up global post data.
3969
	 *
3970
	 * @since 4.1.0
3971
	 * @since 4.4.0 Added the ability to pass a post ID to `$post`.
3972
	 *
3973
	 * @global int             $id
3974
	 * @global WP_User         $authordata
3975
	 * @global string|int|bool $currentday
3976
	 * @global string|int|bool $currentmonth
3977
	 * @global int             $page
3978
	 * @global array           $pages
3979
	 * @global int             $multipage
3980
	 * @global int             $more
3981
	 * @global int             $numpages
3982
	 *
3983
	 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
3984
	 * @return true True when finished.
0 ignored issues
show
Should the return type not be null|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
3985
	 */
3986
	public function setup_postdata( $post ) {
3987
		global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;
3988
3989
		if ( ! ( $post instanceof WP_Post ) ) {
3990
			$post = get_post( $post );
3991
		}
3992
3993
		if ( ! $post ) {
3994
			return;
3995
		}
3996
3997
		$id = (int) $post->ID;
3998
3999
		$authordata = get_userdata($post->post_author);
4000
4001
		$currentday = mysql2date('d.m.y', $post->post_date, false);
4002
		$currentmonth = mysql2date('m', $post->post_date, false);
4003
		$numpages = 1;
4004
		$multipage = 0;
4005
		$page = $this->get( 'page' );
4006
		if ( ! $page )
4007
			$page = 1;
4008
4009
		/*
4010
		 * Force full post content when viewing the permalink for the $post,
4011
		 * or when on an RSS feed. Otherwise respect the 'more' tag.
4012
		 */
4013
		if ( $post->ID === get_queried_object_id() && ( $this->is_page() || $this->is_single() ) ) {
4014
			$more = 1;
4015
		} elseif ( $this->is_feed() ) {
4016
			$more = 1;
4017
		} else {
4018
			$more = 0;
4019
		}
4020
4021
		$content = $post->post_content;
4022
		if ( false !== strpos( $content, '<!--nextpage-->' ) ) {
4023
			$content = str_replace( "\n<!--nextpage-->\n", '<!--nextpage-->', $content );
4024
			$content = str_replace( "\n<!--nextpage-->", '<!--nextpage-->', $content );
4025
			$content = str_replace( "<!--nextpage-->\n", '<!--nextpage-->', $content );
4026
4027
			// Ignore nextpage at the beginning of the content.
4028
			if ( 0 === strpos( $content, '<!--nextpage-->' ) )
4029
				$content = substr( $content, 15 );
4030
4031
			$pages = explode('<!--nextpage-->', $content);
4032
		} else {
4033
			$pages = array( $post->post_content );
4034
		}
4035
4036
		/**
4037
		 * Filters the "pages" derived from splitting the post content.
4038
		 *
4039
		 * "Pages" are determined by splitting the post content based on the presence
4040
		 * of `<!-- nextpage -->` tags.
4041
		 *
4042
		 * @since 4.4.0
4043
		 *
4044
		 * @param array   $pages Array of "pages" derived from the post content.
4045
		 *                       of `<!-- nextpage -->` tags..
4046
		 * @param WP_Post $post  Current post object.
4047
		 */
4048
		$pages = apply_filters( 'content_pagination', $pages, $post );
4049
4050
		$numpages = count( $pages );
4051
4052
		if ( $numpages > 1 ) {
4053
			if ( $page > 1 ) {
4054
				$more = 1;
4055
			}
4056
			$multipage = 1;
4057
		} else {
4058
	 		$multipage = 0;
4059
	 	}
4060
4061
		/**
4062
		 * Fires once the post data has been setup.
4063
		 *
4064
		 * @since 2.8.0
4065
		 * @since 4.1.0 Introduced `$this` parameter.
4066
		 *
4067
		 * @param WP_Post  &$post The Post object (passed by reference).
4068
		 * @param WP_Query &$this The current Query object (passed by reference).
4069
		 */
4070
		do_action_ref_array( 'the_post', array( &$post, &$this ) );
4071
4072
		return true;
4073
	}
4074
	/**
4075
	 * After looping through a nested query, this function
4076
	 * restores the $post global to the current post in this query.
4077
	 *
4078
	 * @since 3.7.0
4079
	 *
4080
	 * @global WP_Post $post
4081
	 */
4082
	public function reset_postdata() {
4083
		if ( ! empty( $this->post ) ) {
4084
			$GLOBALS['post'] = $this->post;
4085
			$this->setup_postdata( $this->post );
4086
		}
4087
	}
4088
4089
	/**
4090
	 * Lazyload term meta for posts in the loop.
4091
	 *
4092
	 * @since 4.4.0
4093
	 * @deprecated 4.5.0 See wp_queue_posts_for_term_meta_lazyload().
4094
	 *
4095
	 * @param mixed $check
4096
	 * @param int   $term_id
4097
	 * @return mixed
4098
	 */
4099
	public function lazyload_term_meta( $check, $term_id ) {
0 ignored issues
show
The parameter $term_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
4100
		_deprecated_function( __METHOD__, '4.5.0' );
4101
		return $check;
4102
	}
4103
4104
	/**
4105
	 * Lazyload comment meta for comments in the loop.
4106
	 *
4107
	 * @since 4.4.0
4108
	 * @deprecated 4.5.0 See wp_queue_comments_for_comment_meta_lazyload().
4109
	 *
4110
	 * @param mixed $check
4111
	 * @param int   $comment_id
4112
	 * @return mixed
4113
	 */
4114
	public function lazyload_comment_meta( $check, $comment_id ) {
0 ignored issues
show
The parameter $comment_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
4115
		_deprecated_function( __METHOD__, '4.5.0' );
4116
		return $check;
4117
	}
4118
}
4119