Completed
Push — master ( a7cd2a...eabd6c )
by Stephen
38:42
created

WP_Query::next_post()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4285
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
/**
3
 * WordPress Query API
4
 *
5
 * The query API attempts to get which part of WordPress the user is on. It
6
 * also provides functionality for getting URL query information.
7
 *
8
 * @link https://codex.wordpress.org/The_Loop More information on The Loop.
9
 *
10
 * @package WordPress
11
 * @subpackage Query
12
 */
13
14
/**
15
 * Retrieve variable in the WP_Query class.
16
 *
17
 * @since 1.5.0
18
 * @since 3.9.0 The `$default` argument was introduced.
19
 *
20
 * @global WP_Query $wp_query Global WP_Query instance.
21
 *
22
 * @param string $var       The variable key to retrieve.
23
 * @param mixed  $default   Optional. Value to return if the query variable is not set. Default empty.
24
 * @return mixed Contents of the query variable.
25
 */
26
function get_query_var( $var, $default = '' ) {
27
	global $wp_query;
28
	return $wp_query->get( $var, $default );
29
}
30
31
/**
32
 * Retrieve the currently-queried object.
33
 *
34
 * Wrapper for WP_Query::get_queried_object().
35
 *
36
 * @since 3.1.0
37
 * @access public
38
 *
39
 * @global WP_Query $wp_query Global WP_Query instance.
40
 *
41
 * @return object Queried object.
42
 */
43
function get_queried_object() {
44
	global $wp_query;
45
	return $wp_query->get_queried_object();
46
}
47
48
/**
49
 * Retrieve ID of the current queried object.
50
 *
51
 * Wrapper for WP_Query::get_queried_object_id().
52
 *
53
 * @since 3.1.0
54
 *
55
 * @global WP_Query $wp_query Global WP_Query instance.
56
 *
57
 * @return int ID of the queried object.
58
 */
59
function get_queried_object_id() {
60
	global $wp_query;
61
	return $wp_query->get_queried_object_id();
62
}
63
64
/**
65
 * Set query variable.
66
 *
67
 * @since 2.2.0
68
 *
69
 * @global WP_Query $wp_query Global WP_Query instance.
70
 *
71
 * @param string $var   Query variable key.
72
 * @param mixed  $value Query variable value.
73
 */
74
function set_query_var( $var, $value ) {
75
	global $wp_query;
76
	$wp_query->set( $var, $value );
77
}
78
79
/**
80
 * Set up The Loop with query parameters.
81
 *
82
 * This will override the current WordPress Loop and shouldn't be used more than
83
 * once. This must not be used within the WordPress Loop.
84
 *
85
 * @since 1.5.0
86
 *
87
 * @global WP_Query $wp_query Global WP_Query instance.
88
 *
89
 * @param string $query
90
 * @return array List of posts
91
 */
92
function query_posts($query) {
93
	$GLOBALS['wp_query'] = new WP_Query();
94
	return $GLOBALS['wp_query']->query($query);
95
}
96
97
/**
98
 * Destroy the previous query and set up a new query.
99
 *
100
 * This should be used after {@link query_posts()} and before another {@link
101
 * query_posts()}. This will remove obscure bugs that occur when the previous
102
 * wp_query object is not destroyed properly before another is set up.
103
 *
104
 * @since 2.3.0
105
 *
106
 * @global WP_Query $wp_query     Global WP_Query instance.
107
 * @global WP_Query $wp_the_query Copy of the global WP_Query instance created during wp_reset_query().
108
 */
109
function wp_reset_query() {
110
	$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
111
	wp_reset_postdata();
112
}
113
114
/**
115
 * After looping through a separate query, this function restores
116
 * the $post global to the current post in the main query.
117
 *
118
 * @since 3.0.0
119
 *
120
 * @global WP_Query $wp_query Global WP_Query instance.
121
 */
122
function wp_reset_postdata() {
123
	global $wp_query;
124
125
	if ( isset( $wp_query ) ) {
126
		$wp_query->reset_postdata();
127
	}
128
}
129
130
/*
131
 * Query type checks.
132
 */
133
134
/**
135
 * Is the query for an existing archive page?
136
 *
137
 * Month, Year, Category, Author, Post Type archive...
138
 *
139
 * @since 1.5.0
140
 *
141
 * @global WP_Query $wp_query Global WP_Query instance.
142
 *
143
 * @return bool
144
 */
145
function is_archive() {
146
	global $wp_query;
147
148
	if ( ! isset( $wp_query ) ) {
149
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
150
		return false;
151
	}
152
153
	return $wp_query->is_archive();
154
}
155
156
/**
157
 * Is the query for an existing post type archive page?
158
 *
159
 * @since 3.1.0
160
 *
161
 * @global WP_Query $wp_query Global WP_Query instance.
162
 *
163
 * @param string|array $post_types Optional. Post type or array of posts types to check against.
164
 * @return bool
165
 */
166 View Code Duplication
function is_post_type_archive( $post_types = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
167
	global $wp_query;
168
169
	if ( ! isset( $wp_query ) ) {
170
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
171
		return false;
172
	}
173
174
	return $wp_query->is_post_type_archive( $post_types );
175
}
176
177
/**
178
 * Is the query for an existing attachment page?
179
 *
180
 * @since 2.0.0
181
 *
182
 * @global WP_Query $wp_query Global WP_Query instance.
183
 *
184
 * @param int|string|array|object $attachment Attachment ID, title, slug, or array of such.
185
 * @return bool
186
 */
187 View Code Duplication
function is_attachment( $attachment = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
188
	global $wp_query;
189
190
	if ( ! isset( $wp_query ) ) {
191
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
192
		return false;
193
	}
194
195
	return $wp_query->is_attachment( $attachment );
196
}
197
198
/**
199
 * Is the query for an existing author archive page?
200
 *
201
 * If the $author parameter is specified, this function will additionally
202
 * check if the query is for one of the authors specified.
203
 *
204
 * @since 1.5.0
205
 *
206
 * @global WP_Query $wp_query Global WP_Query instance.
207
 *
208
 * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
209
 * @return bool
210
 */
211 View Code Duplication
function is_author( $author = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
212
	global $wp_query;
213
214
	if ( ! isset( $wp_query ) ) {
215
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
216
		return false;
217
	}
218
219
	return $wp_query->is_author( $author );
220
}
221
222
/**
223
 * Is the query for an existing category archive page?
224
 *
225
 * If the $category parameter is specified, this function will additionally
226
 * check if the query is for one of the categories specified.
227
 *
228
 * @since 1.5.0
229
 *
230
 * @global WP_Query $wp_query Global WP_Query instance.
231
 *
232
 * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
233
 * @return bool
234
 */
235 View Code Duplication
function is_category( $category = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
236
	global $wp_query;
237
238
	if ( ! isset( $wp_query ) ) {
239
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
240
		return false;
241
	}
242
243
	return $wp_query->is_category( $category );
244
}
245
246
/**
247
 * Is the query for an existing tag archive page?
248
 *
249
 * If the $tag parameter is specified, this function will additionally
250
 * check if the query is for one of the tags specified.
251
 *
252
 * @since 2.3.0
253
 *
254
 * @global WP_Query $wp_query Global WP_Query instance.
255
 *
256
 * @param mixed $tag Optional. Tag ID, name, slug, or array of Tag IDs, names, and slugs.
257
 * @return bool
258
 */
259 View Code Duplication
function is_tag( $tag = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
260
	global $wp_query;
261
262
	if ( ! isset( $wp_query ) ) {
263
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
264
		return false;
265
	}
266
267
	return $wp_query->is_tag( $tag );
268
}
269
270
/**
271
 * Is the query for an existing taxonomy archive page?
272
 *
273
 * If the $taxonomy parameter is specified, this function will additionally
274
 * check if the query is for that specific $taxonomy.
275
 *
276
 * If the $term parameter is specified in addition to the $taxonomy parameter,
277
 * this function will additionally check if the query is for one of the terms
278
 * specified.
279
 *
280
 * @since 2.5.0
281
 *
282
 * @global WP_Query $wp_query Global WP_Query instance.
283
 *
284
 * @param string|array     $taxonomy Optional. Taxonomy slug or slugs.
285
 * @param int|string|array $term     Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
286
 * @return bool
287
 */
288 View Code Duplication
function is_tax( $taxonomy = '', $term = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
289
	global $wp_query;
290
291
	if ( ! isset( $wp_query ) ) {
292
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
293
		return false;
294
	}
295
296
	return $wp_query->is_tax( $taxonomy, $term );
297
}
298
299
/**
300
 * Is the query for an existing date archive?
301
 *
302
 * @since 1.5.0
303
 *
304
 * @global WP_Query $wp_query Global WP_Query instance.
305
 *
306
 * @return bool
307
 */
308
function is_date() {
309
	global $wp_query;
310
311
	if ( ! isset( $wp_query ) ) {
312
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
313
		return false;
314
	}
315
316
	return $wp_query->is_date();
317
}
318
319
/**
320
 * Is the query for an existing day archive?
321
 *
322
 * @since 1.5.0
323
 *
324
 * @global WP_Query $wp_query Global WP_Query instance.
325
 *
326
 * @return bool
327
 */
328
function is_day() {
329
	global $wp_query;
330
331
	if ( ! isset( $wp_query ) ) {
332
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
333
		return false;
334
	}
335
336
	return $wp_query->is_day();
337
}
338
339
/**
340
 * Is the query for a feed?
341
 *
342
 * @since 1.5.0
343
 *
344
 * @global WP_Query $wp_query Global WP_Query instance.
345
 *
346
 * @param string|array $feeds Optional feed types to check.
347
 * @return bool
348
 */
349 View Code Duplication
function is_feed( $feeds = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
350
	global $wp_query;
351
352
	if ( ! isset( $wp_query ) ) {
353
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
354
		return false;
355
	}
356
357
	return $wp_query->is_feed( $feeds );
358
}
359
360
/**
361
 * Is the query for a comments feed?
362
 *
363
 * @since 3.0.0
364
 *
365
 * @global WP_Query $wp_query Global WP_Query instance.
366
 *
367
 * @return bool
368
 */
369
function is_comment_feed() {
370
	global $wp_query;
371
372
	if ( ! isset( $wp_query ) ) {
373
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
374
		return false;
375
	}
376
377
	return $wp_query->is_comment_feed();
378
}
379
380
/**
381
 * Is the query for the front page of the site?
382
 *
383
 * This is for what is displayed at your site's main URL.
384
 *
385
 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
386
 *
387
 * If you set a static page for the front page of your site, this function will return
388
 * true when viewing that page.
389
 *
390
 * Otherwise the same as @see is_home()
391
 *
392
 * @since 2.5.0
393
 *
394
 * @global WP_Query $wp_query Global WP_Query instance.
395
 *
396
 * @return bool True, if front of site.
397
 */
398
function is_front_page() {
399
	global $wp_query;
400
401
	if ( ! isset( $wp_query ) ) {
402
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
403
		return false;
404
	}
405
406
	return $wp_query->is_front_page();
407
}
408
409
/**
410
 * Is the query for the blog homepage?
411
 *
412
 * This is the page which shows the time based blog content of your site.
413
 *
414
 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
415
 *
416
 * If you set a static page for the front page of your site, this function will return
417
 * true only on the page you set as the "Posts page".
418
 *
419
 * @see is_front_page()
420
 *
421
 * @since 1.5.0
422
 *
423
 * @global WP_Query $wp_query Global WP_Query instance.
424
 *
425
 * @return bool True if blog view homepage.
426
 */
427
function is_home() {
428
	global $wp_query;
429
430
	if ( ! isset( $wp_query ) ) {
431
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
432
		return false;
433
	}
434
435
	return $wp_query->is_home();
436
}
437
438
/**
439
 * Is the query for an existing month archive?
440
 *
441
 * @since 1.5.0
442
 *
443
 * @global WP_Query $wp_query Global WP_Query instance.
444
 *
445
 * @return bool
446
 */
447
function is_month() {
448
	global $wp_query;
449
450
	if ( ! isset( $wp_query ) ) {
451
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
452
		return false;
453
	}
454
455
	return $wp_query->is_month();
456
}
457
458
/**
459
 * Is the query for an existing single page?
460
 *
461
 * If the $page parameter is specified, this function will additionally
462
 * check if the query is for one of the pages specified.
463
 *
464
 * @see is_single()
465
 * @see is_singular()
466
 *
467
 * @since 1.5.0
468
 *
469
 * @global WP_Query $wp_query Global WP_Query instance.
470
 *
471
 * @param int|string|array $page Optional. Page ID, title, slug, or array of such. Default empty.
472
 * @return bool Whether the query is for an existing single page.
473
 */
474 View Code Duplication
function is_page( $page = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
475
	global $wp_query;
476
477
	if ( ! isset( $wp_query ) ) {
478
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
479
		return false;
480
	}
481
482
	return $wp_query->is_page( $page );
483
}
484
485
/**
486
 * Is the query for paged result and not for the first page?
487
 *
488
 * @since 1.5.0
489
 *
490
 * @global WP_Query $wp_query Global WP_Query instance.
491
 *
492
 * @return bool
493
 */
494
function is_paged() {
495
	global $wp_query;
496
497
	if ( ! isset( $wp_query ) ) {
498
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
499
		return false;
500
	}
501
502
	return $wp_query->is_paged();
503
}
504
505
/**
506
 * Is the query for a post or page preview?
507
 *
508
 * @since 2.0.0
509
 *
510
 * @global WP_Query $wp_query Global WP_Query instance.
511
 *
512
 * @return bool
513
 */
514
function is_preview() {
515
	global $wp_query;
516
517
	if ( ! isset( $wp_query ) ) {
518
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
519
		return false;
520
	}
521
522
	return $wp_query->is_preview();
523
}
524
525
/**
526
 * Is the query for the robots file?
527
 *
528
 * @since 2.1.0
529
 *
530
 * @global WP_Query $wp_query Global WP_Query instance.
531
 *
532
 * @return bool
533
 */
534
function is_robots() {
535
	global $wp_query;
536
537
	if ( ! isset( $wp_query ) ) {
538
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
539
		return false;
540
	}
541
542
	return $wp_query->is_robots();
543
}
544
545
/**
546
 * Is the query for a search?
547
 *
548
 * @since 1.5.0
549
 *
550
 * @global WP_Query $wp_query Global WP_Query instance.
551
 *
552
 * @return bool
553
 */
554
function is_search() {
555
	global $wp_query;
556
557
	if ( ! isset( $wp_query ) ) {
558
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
559
		return false;
560
	}
561
562
	return $wp_query->is_search();
563
}
564
565
/**
566
 * Is the query for an existing single post?
567
 *
568
 * Works for any post type, except attachments and pages
569
 *
570
 * If the $post parameter is specified, this function will additionally
571
 * check if the query is for one of the Posts specified.
572
 *
573
 * @see is_page()
574
 * @see is_singular()
575
 *
576
 * @since 1.5.0
577
 *
578
 * @global WP_Query $wp_query Global WP_Query instance.
579
 *
580
 * @param int|string|array $post Optional. Post ID, title, slug, or array of such. Default empty.
581
 * @return bool Whether the query is for an existing single post.
582
 */
583 View Code Duplication
function is_single( $post = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
584
	global $wp_query;
585
586
	if ( ! isset( $wp_query ) ) {
587
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
588
		return false;
589
	}
590
591
	return $wp_query->is_single( $post );
592
}
593
594
/**
595
 * Is the query for an existing single post of any post type (post, attachment, page, ... )?
596
 *
597
 * If the $post_types parameter is specified, this function will additionally
598
 * check if the query is for one of the Posts Types specified.
599
 *
600
 * @see is_page()
601
 * @see is_single()
602
 *
603
 * @since 1.5.0
604
 *
605
 * @global WP_Query $wp_query Global WP_Query instance.
606
 *
607
 * @param string|array $post_types Optional. Post type or array of post types. Default empty.
608
 * @return bool Whether the query is for an existing single post of any of the given post types.
609
 */
610 View Code Duplication
function is_singular( $post_types = '' ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

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

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

Loading history...
611
	global $wp_query;
612
613
	if ( ! isset( $wp_query ) ) {
614
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
615
		return false;
616
	}
617
618
	return $wp_query->is_singular( $post_types );
619
}
620
621
/**
622
 * Is the query for a specific time?
623
 *
624
 * @since 1.5.0
625
 *
626
 * @global WP_Query $wp_query Global WP_Query instance.
627
 *
628
 * @return bool
629
 */
630
function is_time() {
631
	global $wp_query;
632
633
	if ( ! isset( $wp_query ) ) {
634
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
635
		return false;
636
	}
637
638
	return $wp_query->is_time();
639
}
640
641
/**
642
 * Is the query for a trackback endpoint call?
643
 *
644
 * @since 1.5.0
645
 *
646
 * @global WP_Query $wp_query Global WP_Query instance.
647
 *
648
 * @return bool
649
 */
650
function is_trackback() {
651
	global $wp_query;
652
653
	if ( ! isset( $wp_query ) ) {
654
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
655
		return false;
656
	}
657
658
	return $wp_query->is_trackback();
659
}
660
661
/**
662
 * Is the query for an existing year archive?
663
 *
664
 * @since 1.5.0
665
 *
666
 * @global WP_Query $wp_query Global WP_Query instance.
667
 *
668
 * @return bool
669
 */
670
function is_year() {
671
	global $wp_query;
672
673
	if ( ! isset( $wp_query ) ) {
674
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
675
		return false;
676
	}
677
678
	return $wp_query->is_year();
679
}
680
681
/**
682
 * Is the query a 404 (returns no results)?
683
 *
684
 * @since 1.5.0
685
 *
686
 * @global WP_Query $wp_query Global WP_Query instance.
687
 *
688
 * @return bool
689
 */
690
function is_404() {
691
	global $wp_query;
692
693
	if ( ! isset( $wp_query ) ) {
694
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
695
		return false;
696
	}
697
698
	return $wp_query->is_404();
699
}
700
701
/**
702
 * Is the query for an embedded post?
703
 *
704
 * @since 4.4.0
705
 *
706
 * @global WP_Query $wp_query Global WP_Query instance.
707
 *
708
 * @return bool Whether we're in an embedded post or not.
709
 */
710
function is_embed() {
711
	global $wp_query;
712
713
	if ( ! isset( $wp_query ) ) {
714
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
715
		return false;
716
	}
717
718
	return $wp_query->is_embed();
719
}
720
721
/**
722
 * Is the query the main query?
723
 *
724
 * @since 3.3.0
725
 *
726
 * @global WP_Query $wp_query Global WP_Query instance.
727
 *
728
 * @return bool
729
 */
730
function is_main_query() {
731
	if ( 'pre_get_posts' === current_filter() ) {
732
		$message = sprintf(
733
			/* translators: 1: pre_get_posts 2: WP_Query->is_main_query() 3: is_main_query() 4: link to codex is_main_query() page. */
734
			__( 'In %1$s, use the %2$s method, not the %3$s function. See %4$s.' ),
735
			'<code>pre_get_posts</code>',
736
			'<code>WP_Query->is_main_query()</code>',
737
			'<code>is_main_query()</code>',
738
			__( 'https://codex.wordpress.org/Function_Reference/is_main_query' )
739
		);
740
		_doing_it_wrong( __FUNCTION__, $message, '3.7' );
741
	}
742
743
	global $wp_query;
744
	return $wp_query->is_main_query();
745
}
746
747
/*
748
 * The Loop. Post loop control.
749
 */
750
751
/**
752
 * Whether current WordPress query has results to loop over.
753
 *
754
 * @since 1.5.0
755
 *
756
 * @global WP_Query $wp_query Global WP_Query instance.
757
 *
758
 * @return bool
759
 */
760
function have_posts() {
761
	global $wp_query;
762
	return $wp_query->have_posts();
763
}
764
765
/**
766
 * Whether the caller is in the Loop.
767
 *
768
 * @since 2.0.0
769
 *
770
 * @global WP_Query $wp_query Global WP_Query instance.
771
 *
772
 * @return bool True if caller is within loop, false if loop hasn't started or ended.
773
 */
774
function in_the_loop() {
775
	global $wp_query;
776
	return $wp_query->in_the_loop;
777
}
778
779
/**
780
 * Rewind the loop posts.
781
 *
782
 * @since 1.5.0
783
 *
784
 * @global WP_Query $wp_query Global WP_Query instance.
785
 */
786
function rewind_posts() {
787
	global $wp_query;
788
	$wp_query->rewind_posts();
789
}
790
791
/**
792
 * Iterate the post index in the loop.
793
 *
794
 * @since 1.5.0
795
 *
796
 * @global WP_Query $wp_query Global WP_Query instance.
797
 */
798
function the_post() {
799
	global $wp_query;
800
	$wp_query->the_post();
801
}
802
803
/*
804
 * Comments loop.
805
 */
806
807
/**
808
 * Whether there are comments to loop over.
809
 *
810
 * @since 2.2.0
811
 *
812
 * @global WP_Query $wp_query Global WP_Query instance.
813
 *
814
 * @return bool
815
 */
816
function have_comments() {
817
	global $wp_query;
818
	return $wp_query->have_comments();
819
}
820
821
/**
822
 * Iterate comment index in the comment loop.
823
 *
824
 * @since 2.2.0
825
 *
826
 * @global WP_Query $wp_query Global WP_Query instance.
827
 *
828
 * @return object
829
 */
830
function the_comment() {
831
	global $wp_query;
832
	return $wp_query->the_comment();
833
}
834
835
/*
836
 * WP_Query
837
 */
838
839
/**
840
 * The WordPress Query class.
841
 *
842
 * @link https://codex.wordpress.org/Function_Reference/WP_Query Codex page.
843
 *
844
 * @since 1.5.0
845
 * @since 4.5.0 Removed the `$comments_popup` property.
846
 */
847
class WP_Query {
848
849
	/**
850
	 * Query vars set by the user
851
	 *
852
	 * @since 1.5.0
853
	 * @access public
854
	 * @var array
855
	 */
856
	public $query;
857
858
	/**
859
	 * Query vars, after parsing
860
	 *
861
	 * @since 1.5.0
862
	 * @access public
863
	 * @var array
864
	 */
865
	public $query_vars = array();
866
867
	/**
868
	 * Taxonomy query, as passed to get_tax_sql()
869
	 *
870
	 * @since 3.1.0
871
	 * @access public
872
	 * @var object WP_Tax_Query
873
	 */
874
	public $tax_query;
875
876
	/**
877
	 * Metadata query container
878
	 *
879
	 * @since 3.2.0
880
	 * @access public
881
	 * @var object WP_Meta_Query
882
	 */
883
	public $meta_query = false;
884
885
	/**
886
	 * Date query container
887
	 *
888
	 * @since 3.7.0
889
	 * @access public
890
	 * @var object WP_Date_Query
891
	 */
892
	public $date_query = false;
893
894
	/**
895
	 * Holds the data for a single object that is queried.
896
	 *
897
	 * Holds the contents of a post, page, category, attachment.
898
	 *
899
	 * @since 1.5.0
900
	 * @access public
901
	 * @var object|array
902
	 */
903
	public $queried_object;
904
905
	/**
906
	 * The ID of the queried object.
907
	 *
908
	 * @since 1.5.0
909
	 * @access public
910
	 * @var int
911
	 */
912
	public $queried_object_id;
913
914
	/**
915
	 * Get post database query.
916
	 *
917
	 * @since 2.0.1
918
	 * @access public
919
	 * @var string
920
	 */
921
	public $request;
922
923
	/**
924
	 * List of posts.
925
	 *
926
	 * @since 1.5.0
927
	 * @access public
928
	 * @var array
929
	 */
930
	public $posts;
931
932
	/**
933
	 * The amount of posts for the current query.
934
	 *
935
	 * @since 1.5.0
936
	 * @access public
937
	 * @var int
938
	 */
939
	public $post_count = 0;
940
941
	/**
942
	 * Index of the current item in the loop.
943
	 *
944
	 * @since 1.5.0
945
	 * @access public
946
	 * @var int
947
	 */
948
	public $current_post = -1;
949
950
	/**
951
	 * Whether the loop has started and the caller is in the loop.
952
	 *
953
	 * @since 2.0.0
954
	 * @access public
955
	 * @var bool
956
	 */
957
	public $in_the_loop = false;
958
959
	/**
960
	 * The current post.
961
	 *
962
	 * @since 1.5.0
963
	 * @access public
964
	 * @var WP_Post
965
	 */
966
	public $post;
967
968
	/**
969
	 * The list of comments for current post.
970
	 *
971
	 * @since 2.2.0
972
	 * @access public
973
	 * @var array
974
	 */
975
	public $comments;
976
977
	/**
978
	 * The amount of comments for the posts.
979
	 *
980
	 * @since 2.2.0
981
	 * @access public
982
	 * @var int
983
	 */
984
	public $comment_count = 0;
985
986
	/**
987
	 * The index of the comment in the comment loop.
988
	 *
989
	 * @since 2.2.0
990
	 * @access public
991
	 * @var int
992
	 */
993
	public $current_comment = -1;
994
995
	/**
996
	 * Current comment ID.
997
	 *
998
	 * @since 2.2.0
999
	 * @access public
1000
	 * @var int
1001
	 */
1002
	public $comment;
1003
1004
	/**
1005
	 * The amount of found posts for the current query.
1006
	 *
1007
	 * If limit clause was not used, equals $post_count.
1008
	 *
1009
	 * @since 2.1.0
1010
	 * @access public
1011
	 * @var int
1012
	 */
1013
	public $found_posts = 0;
1014
1015
	/**
1016
	 * The amount of pages.
1017
	 *
1018
	 * @since 2.1.0
1019
	 * @access public
1020
	 * @var int
1021
	 */
1022
	public $max_num_pages = 0;
1023
1024
	/**
1025
	 * The amount of comment pages.
1026
	 *
1027
	 * @since 2.7.0
1028
	 * @access public
1029
	 * @var int
1030
	 */
1031
	public $max_num_comment_pages = 0;
1032
1033
	/**
1034
	 * Set if query is single post.
1035
	 *
1036
	 * @since 1.5.0
1037
	 * @access public
1038
	 * @var bool
1039
	 */
1040
	public $is_single = false;
1041
1042
	/**
1043
	 * Set if query is preview of blog.
1044
	 *
1045
	 * @since 2.0.0
1046
	 * @access public
1047
	 * @var bool
1048
	 */
1049
	public $is_preview = false;
1050
1051
	/**
1052
	 * Set if query returns a page.
1053
	 *
1054
	 * @since 1.5.0
1055
	 * @access public
1056
	 * @var bool
1057
	 */
1058
	public $is_page = false;
1059
1060
	/**
1061
	 * Set if query is an archive list.
1062
	 *
1063
	 * @since 1.5.0
1064
	 * @access public
1065
	 * @var bool
1066
	 */
1067
	public $is_archive = false;
1068
1069
	/**
1070
	 * Set if query is part of a date.
1071
	 *
1072
	 * @since 1.5.0
1073
	 * @access public
1074
	 * @var bool
1075
	 */
1076
	public $is_date = false;
1077
1078
	/**
1079
	 * Set if query contains a year.
1080
	 *
1081
	 * @since 1.5.0
1082
	 * @access public
1083
	 * @var bool
1084
	 */
1085
	public $is_year = false;
1086
1087
	/**
1088
	 * Set if query contains a month.
1089
	 *
1090
	 * @since 1.5.0
1091
	 * @access public
1092
	 * @var bool
1093
	 */
1094
	public $is_month = false;
1095
1096
	/**
1097
	 * Set if query contains a day.
1098
	 *
1099
	 * @since 1.5.0
1100
	 * @access public
1101
	 * @var bool
1102
	 */
1103
	public $is_day = false;
1104
1105
	/**
1106
	 * Set if query contains time.
1107
	 *
1108
	 * @since 1.5.0
1109
	 * @access public
1110
	 * @var bool
1111
	 */
1112
	public $is_time = false;
1113
1114
	/**
1115
	 * Set if query contains an author.
1116
	 *
1117
	 * @since 1.5.0
1118
	 * @access public
1119
	 * @var bool
1120
	 */
1121
	public $is_author = false;
1122
1123
	/**
1124
	 * Set if query contains category.
1125
	 *
1126
	 * @since 1.5.0
1127
	 * @access public
1128
	 * @var bool
1129
	 */
1130
	public $is_category = false;
1131
1132
	/**
1133
	 * Set if query contains tag.
1134
	 *
1135
	 * @since 2.3.0
1136
	 * @access public
1137
	 * @var bool
1138
	 */
1139
	public $is_tag = false;
1140
1141
	/**
1142
	 * Set if query contains taxonomy.
1143
	 *
1144
	 * @since 2.5.0
1145
	 * @access public
1146
	 * @var bool
1147
	 */
1148
	public $is_tax = false;
1149
1150
	/**
1151
	 * Set if query was part of a search result.
1152
	 *
1153
	 * @since 1.5.0
1154
	 * @access public
1155
	 * @var bool
1156
	 */
1157
	public $is_search = false;
1158
1159
	/**
1160
	 * Set if query is feed display.
1161
	 *
1162
	 * @since 1.5.0
1163
	 * @access public
1164
	 * @var bool
1165
	 */
1166
	public $is_feed = false;
1167
1168
	/**
1169
	 * Set if query is comment feed display.
1170
	 *
1171
	 * @since 2.2.0
1172
	 * @access public
1173
	 * @var bool
1174
	 */
1175
	public $is_comment_feed = false;
1176
1177
	/**
1178
	 * Set if query is trackback.
1179
	 *
1180
	 * @since 1.5.0
1181
	 * @access public
1182
	 * @var bool
1183
	 */
1184
	public $is_trackback = false;
1185
1186
	/**
1187
	 * Set if query is blog homepage.
1188
	 *
1189
	 * @since 1.5.0
1190
	 * @access public
1191
	 * @var bool
1192
	 */
1193
	public $is_home = false;
1194
1195
	/**
1196
	 * Set if query couldn't found anything.
1197
	 *
1198
	 * @since 1.5.0
1199
	 * @access public
1200
	 * @var bool
1201
	 */
1202
	public $is_404 = false;
1203
1204
	/**
1205
	 * Set if query is embed.
1206
	 *
1207
	 * @since 4.4.0
1208
	 * @access public
1209
	 * @var bool
1210
	 */
1211
	public $is_embed = false;
1212
1213
	/**
1214
	 * Set if query is paged
1215
	 *
1216
	 * @since 1.5.0
1217
	 * @access public
1218
	 * @var bool
1219
	 */
1220
	public $is_paged = false;
1221
1222
	/**
1223
	 * Set if query is part of administration page.
1224
	 *
1225
	 * @since 1.5.0
1226
	 * @access public
1227
	 * @var bool
1228
	 */
1229
	public $is_admin = false;
1230
1231
	/**
1232
	 * Set if query is an attachment.
1233
	 *
1234
	 * @since 2.0.0
1235
	 * @access public
1236
	 * @var bool
1237
	 */
1238
	public $is_attachment = false;
1239
1240
	/**
1241
	 * Set if is single, is a page, or is an attachment.
1242
	 *
1243
	 * @since 2.1.0
1244
	 * @access public
1245
	 * @var bool
1246
	 */
1247
	public $is_singular = false;
1248
1249
	/**
1250
	 * Set if query is for robots.
1251
	 *
1252
	 * @since 2.1.0
1253
	 * @access public
1254
	 * @var bool
1255
	 */
1256
	public $is_robots = false;
1257
1258
	/**
1259
	 * Set if query contains posts.
1260
	 *
1261
	 * Basically, the homepage if the option isn't set for the static homepage.
1262
	 *
1263
	 * @since 2.1.0
1264
	 * @access public
1265
	 * @var bool
1266
	 */
1267
	public $is_posts_page = false;
1268
1269
	/**
1270
	 * Set if query is for a post type archive.
1271
	 *
1272
	 * @since 3.1.0
1273
	 * @access public
1274
	 * @var bool
1275
	 */
1276
	public $is_post_type_archive = false;
1277
1278
	/**
1279
	 * Stores the ->query_vars state like md5(serialize( $this->query_vars ) ) so we know
1280
	 * whether we have to re-parse because something has changed
1281
	 *
1282
	 * @since 3.1.0
1283
	 * @access private
1284
	 * @var bool|string
1285
	 */
1286
	private $query_vars_hash = false;
1287
1288
	/**
1289
	 * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
1290
	 * via pre_get_posts hooks.
1291
	 *
1292
	 * @since 3.1.1
1293
	 * @access private
1294
	 */
1295
	private $query_vars_changed = true;
1296
1297
	/**
1298
	 * Set if post thumbnails are cached
1299
	 *
1300
	 * @since 3.2.0
1301
	 * @access public
1302
	 * @var bool
1303
	 */
1304
	 public $thumbnails_cached = false;
1305
1306
	/**
1307
	 * Cached list of search stopwords.
1308
	 *
1309
	 * @since 3.7.0
1310
	 * @var array
1311
	 */
1312
	private $stopwords;
1313
1314
	private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );
1315
1316
	private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
1317
1318
	/**
1319
	 * Resets query flags to false.
1320
	 *
1321
	 * The query flags are what page info WordPress was able to figure out.
1322
	 *
1323
	 * @since 2.0.0
1324
	 * @access private
1325
	 */
1326
	private function init_query_flags() {
1327
		$this->is_single = false;
1328
		$this->is_preview = false;
1329
		$this->is_page = false;
1330
		$this->is_archive = false;
1331
		$this->is_date = false;
1332
		$this->is_year = false;
1333
		$this->is_month = false;
1334
		$this->is_day = false;
1335
		$this->is_time = false;
1336
		$this->is_author = false;
1337
		$this->is_category = false;
1338
		$this->is_tag = false;
1339
		$this->is_tax = false;
1340
		$this->is_search = false;
1341
		$this->is_feed = false;
1342
		$this->is_comment_feed = false;
1343
		$this->is_trackback = false;
1344
		$this->is_home = false;
1345
		$this->is_404 = false;
1346
		$this->is_paged = false;
1347
		$this->is_admin = false;
1348
		$this->is_attachment = false;
1349
		$this->is_singular = false;
1350
		$this->is_robots = false;
1351
		$this->is_posts_page = false;
1352
		$this->is_post_type_archive = false;
1353
	}
1354
1355
	/**
1356
	 * Initiates object properties and sets default values.
1357
	 *
1358
	 * @since 1.5.0
1359
	 * @access public
1360
	 */
1361
	public function init() {
1362
		unset($this->posts);
1363
		unset($this->query);
1364
		$this->query_vars = array();
1365
		unset($this->queried_object);
1366
		unset($this->queried_object_id);
1367
		$this->post_count = 0;
1368
		$this->current_post = -1;
1369
		$this->in_the_loop = false;
1370
		unset( $this->request );
1371
		unset( $this->post );
1372
		unset( $this->comments );
1373
		unset( $this->comment );
1374
		$this->comment_count = 0;
1375
		$this->current_comment = -1;
1376
		$this->found_posts = 0;
1377
		$this->max_num_pages = 0;
1378
		$this->max_num_comment_pages = 0;
1379
1380
		$this->init_query_flags();
1381
	}
1382
1383
	/**
1384
	 * Reparse the query vars.
1385
	 *
1386
	 * @since 1.5.0
1387
	 * @access public
1388
	 */
1389
	public function parse_query_vars() {
1390
		$this->parse_query();
1391
	}
1392
1393
	/**
1394
	 * Fills in the query variables, which do not exist within the parameter.
1395
	 *
1396
	 * @since 2.1.0
1397
	 * @since 4.4.0 Removed the `comments_popup` public query variable.
1398
	 * @access public
1399
	 *
1400
	 * @param array $array Defined query variables.
1401
	 * @return array Complete query variables with undefined ones filled in empty.
1402
	 */
1403
	public function fill_query_vars($array) {
1404
		$keys = array(
1405
			'error'
1406
			, 'm'
1407
			, 'p'
1408
			, 'post_parent'
1409
			, 'subpost'
1410
			, 'subpost_id'
1411
			, 'attachment'
1412
			, 'attachment_id'
1413
			, 'name'
1414
			, 'static'
1415
			, 'pagename'
1416
			, 'page_id'
1417
			, 'second'
1418
			, 'minute'
1419
			, 'hour'
1420
			, 'day'
1421
			, 'monthnum'
1422
			, 'year'
1423
			, 'w'
1424
			, 'category_name'
1425
			, 'tag'
1426
			, 'cat'
1427
			, 'tag_id'
1428
			, 'author'
1429
			, 'author_name'
1430
			, 'feed'
1431
			, 'tb'
1432
			, 'paged'
1433
			, 'meta_key'
1434
			, 'meta_value'
1435
			, 'preview'
1436
			, 's'
1437
			, 'sentence'
1438
			, 'title'
1439
			, 'fields'
1440
			, 'menu_order'
1441
			, 'embed'
1442
		);
1443
1444
		foreach ( $keys as $key ) {
1445
			if ( !isset($array[$key]) )
1446
				$array[$key] = '';
1447
		}
1448
1449
		$array_keys = array( 'category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in', 'post_name__in',
1450
			'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'post_parent__in', 'post_parent__not_in',
1451
			'author__in', 'author__not_in' );
1452
1453
		foreach ( $array_keys as $key ) {
1454
			if ( !isset($array[$key]) )
1455
				$array[$key] = array();
1456
		}
1457
		return $array;
1458
	}
1459
1460
	/**
1461
	 * Parse a query string and set query type booleans.
1462
	 *
1463
	 * @since 1.5.0
1464
	 * @since 4.2.0 Introduced the ability to order by specific clauses of a `$meta_query`, by passing the clause's
1465
	 *              array key to `$orderby`.
1466
	 * @since 4.4.0 Introduced `$post_name__in` and `$title` parameters. `$s` was updated to support excluded
1467
	 *              search terms, by prepending a hyphen.
1468
	 * @since 4.5.0 Removed the `$comments_popup` parameter.
1469
	 *              Introduced the `$comment_status` and `$ping_status` parameters.
1470
	 *              Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts.
1471
	 * @access public
1472
	 *
1473
	 * @param string|array $query {
1474
	 *     Optional. Array or string of Query parameters.
1475
	 *
1476
	 *     @type int          $attachment_id           Attachment post ID. Used for 'attachment' post_type.
1477
	 *     @type int|string   $author                  Author ID, or comma-separated list of IDs.
1478
	 *     @type string       $author_name             User 'user_nicename'.
1479
	 *     @type array        $author__in              An array of author IDs to query from.
1480
	 *     @type array        $author__not_in          An array of author IDs not to query from.
1481
	 *     @type bool         $cache_results           Whether to cache post information. Default true.
1482
	 *     @type int|string   $cat                     Category ID or comma-separated list of IDs (this or any children).
1483
	 *     @type array        $category__and           An array of category IDs (AND in).
1484
	 *     @type array        $category__in            An array of category IDs (OR in, no children).
1485
	 *     @type array        $category__not_in        An array of category IDs (NOT in).
1486
	 *     @type string       $category_name           Use category slug (not name, this or any children).
1487
	 *     @type string       $comment_status          Comment status.
1488
	 *     @type int          $comments_per_page       The number of comments to return per page.
1489
	 *                                                 Default 'comments_per_page' option.
1490
	 *     @type array        $date_query              An associative array of WP_Date_Query arguments.
1491
	 *                                                 {@see WP_Date_Query::__construct()}
1492
	 *     @type int          $day                     Day of the month. Default empty. Accepts numbers 1-31.
1493
	 *     @type bool         $exact                   Whether to search by exact keyword. Default false.
1494
	 *     @type string|array $fields                  Which fields to return. Single field or all fields (string),
1495
	 *                                                 or array of fields. 'id=>parent' uses 'id' and 'post_parent'.
1496
	 *                                                 Default all fields. Accepts 'ids', 'id=>parent'.
1497
	 *     @type int          $hour                    Hour of the day. Default empty. Accepts numbers 0-23.
1498
	 *     @type int|bool     $ignore_sticky_posts     Whether to ignore sticky posts or not. Setting this to false
1499
	 *                                                 excludes stickies from 'post__in'. Accepts 1|true, 0|false.
1500
	 *                                                 Default 0|false.
1501
	 *     @type int          $m                       Combination YearMonth. Accepts any four-digit year and month
1502
	 *                                                 numbers 1-12. Default empty.
1503
	 *     @type string       $meta_compare            Comparison operator to test the 'meta_value'.
1504
	 *     @type string       $meta_key                Custom field key.
1505
	 *     @type array        $meta_query              An associative array of WP_Meta_Query arguments.
1506
	 *                                                 {@see WP_Meta_Query}
1507
	 *     @type string       $meta_value              Custom field value.
1508
	 *     @type int          $meta_value_num          Custom field value number.
1509
	 *     @type int          $menu_order              The menu order of the posts.
1510
	 *     @type int          $monthnum                The two-digit month. Default empty. Accepts numbers 1-12.
1511
	 *     @type string       $name                    Post slug.
1512
	 *     @type bool         $nopaging                Show all posts (true) or paginate (false). Default false.
1513
	 *     @type bool         $no_found_rows           Whether to skip counting the total rows found. Enabling can improve
1514
	 *                                                 performance. Default false.
1515
	 *     @type int          $offset                  The number of posts to offset before retrieval.
1516
	 *     @type string       $order                   Designates ascending or descending order of posts. Default 'DESC'.
1517
	 *                                                 Accepts 'ASC', 'DESC'.
1518
	 *     @type string|array $orderby                 Sort retrieved posts by parameter. One or more options may be
1519
	 *                                                 passed. To use 'meta_value', or 'meta_value_num',
1520
	 *                                                 'meta_key=keyname' must be also be defined. To sort by a
1521
	 *                                                 specific `$meta_query` clause, use that clause's array key.
1522
	 *                                                 Default 'date'. Accepts 'none', 'name', 'author', 'date',
1523
	 *                                                 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand',
1524
	 *                                                 'RAND(x)' (where 'x' is an integer seed value),
1525
	 *                                                 'comment_count', 'meta_value', 'meta_value_num', 'post__in',
1526
	 *                                                 and the array keys of `$meta_query`.
1527
	 *     @type int          $p                       Post ID.
1528
	 *     @type int          $page                    Show the number of posts that would show up on page X of a
1529
	 *                                                 static front page.
1530
	 *     @type int          $paged                   The number of the current page.
1531
	 *     @type int          $page_id                 Page ID.
1532
	 *     @type string       $pagename                Page slug.
1533
	 *     @type string       $perm                    Show posts if user has the appropriate capability.
1534
	 *     @type string       $ping_status             Ping status.
1535
	 *     @type array        $post__in                An array of post IDs to retrieve, sticky posts will be included
1536
	 *     @type string       $post_mime_type          The mime type of the post. Used for 'attachment' post_type.
1537
	 *     @type array        $post__not_in            An array of post IDs not to retrieve. Note: a string of comma-
1538
	 *                                                 separated IDs will NOT work.
1539
	 *     @type int          $post_parent             Page ID to retrieve child pages for. Use 0 to only retrieve
1540
	 *                                                 top-level pages.
1541
	 *     @type array        $post_parent__in         An array containing parent page IDs to query child pages from.
1542
	 *     @type array        $post_parent__not_in     An array containing parent page IDs not to query child pages from.
1543
	 *     @type string|array $post_type               A post type slug (string) or array of post type slugs.
1544
	 *                                                 Default 'any' if using 'tax_query'.
1545
	 *     @type string|array $post_status             A post status (string) or array of post statuses.
1546
	 *     @type int          $posts_per_page          The number of posts to query for. Use -1 to request all posts.
1547
	 *     @type int          $posts_per_archive_page  The number of posts to query for by archive page. Overrides
1548
	 *                                                 'posts_per_page' when is_archive(), or is_search() are true.
1549
	 *     @type array        $post_name__in           An array of post slugs that results must match.
1550
	 *     @type string       $s                       Search keyword(s). Prepending a term with a hyphen will
1551
	 *                                                 exclude posts matching that term. Eg, 'pillow -sofa' will
1552
	 *                                                 return posts containing 'pillow' but not 'sofa'.
1553
	 *     @type int          $second                  Second of the minute. Default empty. Accepts numbers 0-60.
1554
	 *     @type bool         $sentence                Whether to search by phrase. Default false.
1555
	 *     @type bool         $suppress_filters        Whether to suppress filters. Default false.
1556
	 *     @type string       $tag                     Tag slug. Comma-separated (either), Plus-separated (all).
1557
	 *     @type array        $tag__and                An array of tag ids (AND in).
1558
	 *     @type array        $tag__in                 An array of tag ids (OR in).
1559
	 *     @type array        $tag__not_in             An array of tag ids (NOT in).
1560
	 *     @type int          $tag_id                  Tag id or comma-separated list of IDs.
1561
	 *     @type array        $tag_slug__and           An array of tag slugs (AND in).
1562
	 *     @type array        $tag_slug__in            An array of tag slugs (OR in). unless 'ignore_sticky_posts' is
1563
	 *                                                 true. Note: a string of comma-separated IDs will NOT work.
1564
	 *     @type array        $tax_query               An associative array of WP_Tax_Query arguments.
1565
	 *                                                 {@see WP_Tax_Query->queries}
1566
	 *     @type string       $title                   Post title.
1567
	 *     @type bool         $update_post_meta_cache  Whether to update the post meta cache. Default true.
1568
	 *     @type bool         $update_post_term_cache  Whether to update the post term cache. Default true.
1569
	 *     @type int          $w                       The week number of the year. Default empty. Accepts numbers 0-53.
1570
	 *     @type int          $year                    The four-digit year. Default empty. Accepts any four-digit year.
1571
	 * }
1572
	 */
1573
	public function parse_query( $query =  '' ) {
1574
		if ( ! empty( $query ) ) {
1575
			$this->init();
1576
			$this->query = $this->query_vars = wp_parse_args( $query );
1577
		} elseif ( ! isset( $this->query ) ) {
1578
			$this->query = $this->query_vars;
1579
		}
1580
1581
		$this->query_vars = $this->fill_query_vars($this->query_vars);
1582
		$qv = &$this->query_vars;
1583
		$this->query_vars_changed = true;
1584
1585
		if ( ! empty($qv['robots']) )
1586
			$this->is_robots = true;
1587
1588
		$qv['p'] =  absint($qv['p']);
1589
		$qv['page_id'] =  absint($qv['page_id']);
1590
		$qv['year'] = absint($qv['year']);
1591
		$qv['monthnum'] = absint($qv['monthnum']);
1592
		$qv['day'] = absint($qv['day']);
1593
		$qv['w'] = absint($qv['w']);
1594
		$qv['m'] = preg_replace( '|[^0-9]|', '', $qv['m'] );
1595
		$qv['paged'] = absint($qv['paged']);
1596
		$qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers
1597
		$qv['author'] = preg_replace( '|[^0-9,-]|', '', $qv['author'] ); // comma separated list of positive or negative integers
1598
		$qv['pagename'] = trim( $qv['pagename'] );
1599
		$qv['name'] = trim( $qv['name'] );
1600
		$qv['title'] = trim( $qv['title'] );
1601
		if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']);
1602
		if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']);
1603
		if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']);
1604
		if ( '' !== $qv['menu_order'] ) $qv['menu_order'] = absint($qv['menu_order']);
1605
1606
		// Fairly insane upper bound for search string lengths.
1607
		if ( ! is_scalar( $qv['s'] ) || ( ! empty( $qv['s'] ) && strlen( $qv['s'] ) > 1600 ) ) {
1608
			$qv['s'] = '';
1609
		}
1610
1611
		// Compat. Map subpost to attachment.
1612
		if ( '' != $qv['subpost'] )
1613
			$qv['attachment'] = $qv['subpost'];
1614
		if ( '' != $qv['subpost_id'] )
1615
			$qv['attachment_id'] = $qv['subpost_id'];
1616
1617
		$qv['attachment_id'] = absint($qv['attachment_id']);
1618
1619
		if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
1620
			$this->is_single = true;
1621
			$this->is_attachment = true;
1622
		} elseif ( '' != $qv['name'] ) {
1623
			$this->is_single = true;
1624
		} elseif ( $qv['p'] ) {
1625
			$this->is_single = true;
1626
		} elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) {
1627
			// If year, month, day, hour, minute, and second are set, a single
1628
			// post is being queried.
1629
			$this->is_single = true;
1630
		} elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) {
1631
			$this->is_page = true;
1632
			$this->is_single = false;
1633
		} else {
1634
			// Look for archive queries. Dates, categories, authors, search, post type archives.
1635
1636
			if ( isset( $this->query['s'] ) ) {
1637
				$this->is_search = true;
1638
			}
1639
1640
			if ( '' !== $qv['second'] ) {
1641
				$this->is_time = true;
1642
				$this->is_date = true;
1643
			}
1644
1645 View Code Duplication
			if ( '' !== $qv['minute'] ) {
1646
				$this->is_time = true;
1647
				$this->is_date = true;
1648
			}
1649
1650 View Code Duplication
			if ( '' !== $qv['hour'] ) {
1651
				$this->is_time = true;
1652
				$this->is_date = true;
1653
			}
1654
1655
			if ( $qv['day'] ) {
1656
				if ( ! $this->is_date ) {
1657
					$date = sprintf( '%04d-%02d-%02d', $qv['year'], $qv['monthnum'], $qv['day'] );
1658
					if ( $qv['monthnum'] && $qv['year'] && ! wp_checkdate( $qv['monthnum'], $qv['day'], $qv['year'], $date ) ) {
1659
						$qv['error'] = '404';
1660
					} else {
1661
						$this->is_day = true;
1662
						$this->is_date = true;
1663
					}
1664
				}
1665
			}
1666
1667
			if ( $qv['monthnum'] ) {
1668
				if ( ! $this->is_date ) {
1669
					if ( 12 < $qv['monthnum'] ) {
1670
						$qv['error'] = '404';
1671
					} else {
1672
						$this->is_month = true;
1673
						$this->is_date = true;
1674
					}
1675
				}
1676
			}
1677
1678
			if ( $qv['year'] ) {
1679
				if ( ! $this->is_date ) {
1680
					$this->is_year = true;
1681
					$this->is_date = true;
1682
				}
1683
			}
1684
1685
			if ( $qv['m'] ) {
1686
				$this->is_date = true;
1687
				if ( strlen($qv['m']) > 9 ) {
1688
					$this->is_time = true;
1689
				} elseif ( strlen( $qv['m'] ) > 7 ) {
1690
					$this->is_day = true;
1691
				} elseif ( strlen( $qv['m'] ) > 5 ) {
1692
					$this->is_month = true;
1693
				} else {
1694
					$this->is_year = true;
1695
				}
1696
			}
1697
1698
			if ( '' != $qv['w'] ) {
1699
				$this->is_date = true;
1700
			}
1701
1702
			$this->query_vars_hash = false;
1703
			$this->parse_tax_query( $qv );
1704
1705
			foreach ( $this->tax_query->queries as $tax_query ) {
1706
				if ( ! is_array( $tax_query ) ) {
1707
					continue;
1708
				}
1709
1710
				if ( isset( $tax_query['operator'] ) && 'NOT IN' != $tax_query['operator'] ) {
1711
					switch ( $tax_query['taxonomy'] ) {
1712
						case 'category':
1713
							$this->is_category = true;
1714
							break;
1715
						case 'post_tag':
1716
							$this->is_tag = true;
1717
							break;
1718
						default:
1719
							$this->is_tax = true;
1720
					}
1721
				}
1722
			}
1723
			unset( $tax_query );
1724
1725
			if ( empty($qv['author']) || ($qv['author'] == '0') ) {
1726
				$this->is_author = false;
1727
			} else {
1728
				$this->is_author = true;
1729
			}
1730
1731
			if ( '' != $qv['author_name'] )
1732
				$this->is_author = true;
1733
1734
			if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) {
1735
				$post_type_obj = get_post_type_object( $qv['post_type'] );
1736
				if ( ! empty( $post_type_obj->has_archive ) )
1737
					$this->is_post_type_archive = true;
1738
			}
1739
1740
			if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
1741
				$this->is_archive = true;
1742
		}
1743
1744
		if ( '' != $qv['feed'] )
1745
			$this->is_feed = true;
1746
1747
		if ( '' != $qv['embed'] ) {
1748
			$this->is_embed = true;
1749
		}
1750
1751
		if ( '' != $qv['tb'] )
1752
			$this->is_trackback = true;
1753
1754
		if ( '' != $qv['paged'] && ( intval($qv['paged']) > 1 ) )
1755
			$this->is_paged = true;
1756
1757
		// if we're previewing inside the write screen
1758
		if ( '' != $qv['preview'] )
1759
			$this->is_preview = true;
1760
1761
		if ( is_admin() )
1762
			$this->is_admin = true;
1763
1764
		if ( false !== strpos($qv['feed'], 'comments-') ) {
1765
			$qv['feed'] = str_replace('comments-', '', $qv['feed']);
1766
			$qv['withcomments'] = 1;
1767
		}
1768
1769
		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
1770
1771
		if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
1772
			$this->is_comment_feed = true;
1773
1774
		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 ) )
1775
			$this->is_home = true;
1776
1777
		// Correct is_* for page_on_front and page_for_posts
1778
		if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
1779
			$_query = wp_parse_args($this->query);
1780
			// pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
1781
			if ( isset($_query['pagename']) && '' == $_query['pagename'] )
1782
				unset($_query['pagename']);
1783
1784
			unset( $_query['embed'] );
1785
1786
			if ( empty($_query) || !array_diff( array_keys($_query), array('preview', 'page', 'paged', 'cpage') ) ) {
1787
				$this->is_page = true;
1788
				$this->is_home = false;
1789
				$qv['page_id'] = get_option('page_on_front');
1790
				// Correct <!--nextpage--> for page_on_front
1791
				if ( !empty($qv['paged']) ) {
1792
					$qv['page'] = $qv['paged'];
1793
					unset($qv['paged']);
1794
				}
1795
			}
1796
		}
1797
1798
		if ( '' != $qv['pagename'] ) {
1799
			$this->queried_object = get_page_by_path( $qv['pagename'] );
1800
1801
			if ( $this->queried_object && 'attachment' == $this->queried_object->post_type ) {
1802
				if ( preg_match( "/^[^%]*%(?:postname)%/", get_option( 'permalink_structure' ) ) ) {
1803
					// See if we also have a post with the same slug
1804
					$post = get_page_by_path( $qv['pagename'], OBJECT, 'post' );
1805
					if ( $post ) {
1806
						$this->queried_object = $post;
1807
						$this->is_page = false;
1808
						$this->is_single = true;
1809
					}
1810
				}
1811
			}
1812
1813
			if ( ! empty( $this->queried_object ) ) {
1814
				$this->queried_object_id = (int) $this->queried_object->ID;
1815
			} else {
1816
				unset( $this->queried_object );
1817
			}
1818
1819
			if  ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) {
1820
				$this->is_page = false;
1821
				$this->is_home = true;
1822
				$this->is_posts_page = true;
1823
			}
1824
		}
1825
1826
		if ( $qv['page_id'] ) {
1827
			if  ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
1828
				$this->is_page = false;
1829
				$this->is_home = true;
1830
				$this->is_posts_page = true;
1831
			}
1832
		}
1833
1834
		if ( !empty($qv['post_type']) ) {
1835
			if ( is_array($qv['post_type']) )
1836
				$qv['post_type'] = array_map('sanitize_key', $qv['post_type']);
1837
			else
1838
				$qv['post_type'] = sanitize_key($qv['post_type']);
1839
		}
1840
1841 View Code Duplication
		if ( ! empty( $qv['post_status'] ) ) {
1842
			if ( is_array( $qv['post_status'] ) )
1843
				$qv['post_status'] = array_map('sanitize_key', $qv['post_status']);
1844
			else
1845
				$qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']);
1846
		}
1847
1848
		if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) )
1849
			$this->is_comment_feed = false;
1850
1851
		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
1852
		// Done correcting is_* for page_on_front and page_for_posts
1853
1854
		if ( '404' == $qv['error'] )
1855
			$this->set_404();
1856
1857
		$this->is_embed = $this->is_embed && ( $this->is_singular || $this->is_404 );
1858
1859
		$this->query_vars_hash = md5( serialize( $this->query_vars ) );
1860
		$this->query_vars_changed = false;
1861
1862
		/**
1863
		 * Fires after the main query vars have been parsed.
1864
		 *
1865
		 * @since 1.5.0
1866
		 *
1867
		 * @param WP_Query &$this The WP_Query instance (passed by reference).
1868
		 */
1869
		do_action_ref_array( 'parse_query', array( &$this ) );
1870
	}
1871
1872
	/**
1873
	 * Parses various taxonomy related query vars.
1874
	 *
1875
	 * For BC, this method is not marked as protected. See [28987].
1876
	 *
1877
	 * @access protected
1878
	 * @since 3.1.0
1879
	 *
1880
	 * @param array $q The query variables. Passed by reference.
1881
	 */
1882
	public function parse_tax_query( &$q ) {
1883
		if ( ! empty( $q['tax_query'] ) && is_array( $q['tax_query'] ) ) {
1884
			$tax_query = $q['tax_query'];
1885
		} else {
1886
			$tax_query = array();
1887
		}
1888
1889
		if ( !empty($q['taxonomy']) && !empty($q['term']) ) {
1890
			$tax_query[] = array(
1891
				'taxonomy' => $q['taxonomy'],
1892
				'terms' => array( $q['term'] ),
1893
				'field' => 'slug',
1894
			);
1895
		}
1896
1897
		foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) {
1898
			if ( 'post_tag' == $taxonomy )
1899
				continue;	// Handled further down in the $q['tag'] block
1900
1901
			if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
1902
				$tax_query_defaults = array(
1903
					'taxonomy' => $taxonomy,
1904
					'field' => 'slug',
1905
				);
1906
1907
 				if ( isset( $t->rewrite['hierarchical'] ) && $t->rewrite['hierarchical'] ) {
1908
					$q[$t->query_var] = wp_basename( $q[$t->query_var] );
1909
				}
1910
1911
				$term = $q[$t->query_var];
1912
1913
				if ( is_array( $term ) ) {
1914
					$term = implode( ',', $term );
1915
				}
1916
1917
				if ( strpos($term, '+') !== false ) {
1918
					$terms = preg_split( '/[+]+/', $term );
1919
					foreach ( $terms as $term ) {
1920
						$tax_query[] = array_merge( $tax_query_defaults, array(
1921
							'terms' => array( $term )
1922
						) );
1923
					}
1924
				} else {
1925
					$tax_query[] = array_merge( $tax_query_defaults, array(
1926
						'terms' => preg_split( '/[,]+/', $term )
1927
					) );
1928
				}
1929
			}
1930
		}
1931
1932
		// If querystring 'cat' is an array, implode it.
1933 View Code Duplication
		if ( is_array( $q['cat'] ) ) {
1934
			$q['cat'] = implode( ',', $q['cat'] );
1935
		}
1936
1937
		// Category stuff
1938
		if ( ! empty( $q['cat'] ) && ! $this->is_singular ) {
1939
			$cat_in = $cat_not_in = array();
1940
1941
			$cat_array = preg_split( '/[,\s]+/', urldecode( $q['cat'] ) );
1942
			$cat_array = array_map( 'intval', $cat_array );
1943
			$q['cat'] = implode( ',', $cat_array );
1944
1945
			foreach ( $cat_array as $cat ) {
1946
				if ( $cat > 0 )
1947
					$cat_in[] = $cat;
1948
				elseif ( $cat < 0 )
1949
					$cat_not_in[] = abs( $cat );
1950
			}
1951
1952 View Code Duplication
			if ( ! empty( $cat_in ) ) {
1953
				$tax_query[] = array(
1954
					'taxonomy' => 'category',
1955
					'terms' => $cat_in,
1956
					'field' => 'term_id',
1957
					'include_children' => true
1958
				);
1959
			}
1960
1961 View Code Duplication
			if ( ! empty( $cat_not_in ) ) {
1962
				$tax_query[] = array(
1963
					'taxonomy' => 'category',
1964
					'terms' => $cat_not_in,
1965
					'field' => 'term_id',
1966
					'operator' => 'NOT IN',
1967
					'include_children' => true
1968
				);
1969
			}
1970
			unset( $cat_array, $cat_in, $cat_not_in );
1971
		}
1972
1973
		if ( ! empty( $q['category__and'] ) && 1 === count( (array) $q['category__and'] ) ) {
1974
			$q['category__and'] = (array) $q['category__and'];
1975
			if ( ! isset( $q['category__in'] ) )
1976
				$q['category__in'] = array();
1977
			$q['category__in'][] = absint( reset( $q['category__and'] ) );
1978
			unset( $q['category__and'] );
1979
		}
1980
1981
		if ( ! empty( $q['category__in'] ) ) {
1982
			$q['category__in'] = array_map( 'absint', array_unique( (array) $q['category__in'] ) );
1983
			$tax_query[] = array(
1984
				'taxonomy' => 'category',
1985
				'terms' => $q['category__in'],
1986
				'field' => 'term_id',
1987
				'include_children' => false
1988
			);
1989
		}
1990
1991
		if ( ! empty($q['category__not_in']) ) {
1992
			$q['category__not_in'] = array_map( 'absint', array_unique( (array) $q['category__not_in'] ) );
1993
			$tax_query[] = array(
1994
				'taxonomy' => 'category',
1995
				'terms' => $q['category__not_in'],
1996
				'operator' => 'NOT IN',
1997
				'include_children' => false
1998
			);
1999
		}
2000
2001
		if ( ! empty($q['category__and']) ) {
2002
			$q['category__and'] = array_map( 'absint', array_unique( (array) $q['category__and'] ) );
2003
			$tax_query[] = array(
2004
				'taxonomy' => 'category',
2005
				'terms' => $q['category__and'],
2006
				'field' => 'term_id',
2007
				'operator' => 'AND',
2008
				'include_children' => false
2009
			);
2010
		}
2011
2012
		// If querystring 'tag' is array, implode it.
2013 View Code Duplication
		if ( is_array( $q['tag'] ) ) {
2014
			$q['tag'] = implode( ',', $q['tag'] );
2015
		}
2016
2017
		// Tag stuff
2018
		if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) {
2019
			if ( strpos($q['tag'], ',') !== false ) {
2020
				$tags = preg_split('/[,\r\n\t ]+/', $q['tag']);
2021 View Code Duplication
				foreach ( (array) $tags as $tag ) {
2022
					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
2023
					$q['tag_slug__in'][] = $tag;
2024
				}
2025
			} elseif ( preg_match('/[+\r\n\t ]+/', $q['tag'] ) || ! empty( $q['cat'] ) ) {
2026
				$tags = preg_split('/[+\r\n\t ]+/', $q['tag']);
2027 View Code Duplication
				foreach ( (array) $tags as $tag ) {
2028
					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
2029
					$q['tag_slug__and'][] = $tag;
2030
				}
2031
			} else {
2032
				$q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
2033
				$q['tag_slug__in'][] = $q['tag'];
2034
			}
2035
		}
2036
2037
		if ( !empty($q['tag_id']) ) {
2038
			$q['tag_id'] = absint( $q['tag_id'] );
2039
			$tax_query[] = array(
2040
				'taxonomy' => 'post_tag',
2041
				'terms' => $q['tag_id']
2042
			);
2043
		}
2044
2045 View Code Duplication
		if ( !empty($q['tag__in']) ) {
2046
			$q['tag__in'] = array_map('absint', array_unique( (array) $q['tag__in'] ) );
2047
			$tax_query[] = array(
2048
				'taxonomy' => 'post_tag',
2049
				'terms' => $q['tag__in']
2050
			);
2051
		}
2052
2053 View Code Duplication
		if ( !empty($q['tag__not_in']) ) {
2054
			$q['tag__not_in'] = array_map('absint', array_unique( (array) $q['tag__not_in'] ) );
2055
			$tax_query[] = array(
2056
				'taxonomy' => 'post_tag',
2057
				'terms' => $q['tag__not_in'],
2058
				'operator' => 'NOT IN'
2059
			);
2060
		}
2061
2062 View Code Duplication
		if ( !empty($q['tag__and']) ) {
2063
			$q['tag__and'] = array_map('absint', array_unique( (array) $q['tag__and'] ) );
2064
			$tax_query[] = array(
2065
				'taxonomy' => 'post_tag',
2066
				'terms' => $q['tag__and'],
2067
				'operator' => 'AND'
2068
			);
2069
		}
2070
2071 View Code Duplication
		if ( !empty($q['tag_slug__in']) ) {
2072
			$q['tag_slug__in'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
2073
			$tax_query[] = array(
2074
				'taxonomy' => 'post_tag',
2075
				'terms' => $q['tag_slug__in'],
2076
				'field' => 'slug'
2077
			);
2078
		}
2079
2080
		if ( !empty($q['tag_slug__and']) ) {
2081
			$q['tag_slug__and'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
2082
			$tax_query[] = array(
2083
				'taxonomy' => 'post_tag',
2084
				'terms' => $q['tag_slug__and'],
2085
				'field' => 'slug',
2086
				'operator' => 'AND'
2087
			);
2088
		}
2089
2090
		$this->tax_query = new WP_Tax_Query( $tax_query );
2091
2092
		/**
2093
		 * Fires after taxonomy-related query vars have been parsed.
2094
		 *
2095
		 * @since 3.7.0
2096
		 *
2097
		 * @param WP_Query $this The WP_Query instance.
2098
		 */
2099
		do_action( 'parse_tax_query', $this );
2100
	}
2101
2102
	/**
2103
	 * Generate SQL for the WHERE clause based on passed search terms.
2104
	 *
2105
	 * @since 3.7.0
2106
	 *
2107
	 * @global wpdb $wpdb WordPress database abstraction object.
2108
	 *
2109
	 * @param array $q Query variables.
2110
	 * @return string WHERE clause.
2111
	 */
2112
	protected function parse_search( &$q ) {
2113
		global $wpdb;
2114
2115
		$search = '';
2116
2117
		// added slashes screw with quote grouping when done early, so done later
2118
		$q['s'] = stripslashes( $q['s'] );
2119
		if ( empty( $_GET['s'] ) && $this->is_main_query() )
2120
			$q['s'] = urldecode( $q['s'] );
2121
		// there are no line breaks in <input /> fields
2122
		$q['s'] = str_replace( array( "\r", "\n" ), '', $q['s'] );
2123
		$q['search_terms_count'] = 1;
2124
		if ( ! empty( $q['sentence'] ) ) {
2125
			$q['search_terms'] = array( $q['s'] );
2126
		} else {
2127
			if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $q['s'], $matches ) ) {
2128
				$q['search_terms_count'] = count( $matches[0] );
2129
				$q['search_terms'] = $this->parse_search_terms( $matches[0] );
2130
				// if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence
2131
				if ( empty( $q['search_terms'] ) || count( $q['search_terms'] ) > 9 )
2132
					$q['search_terms'] = array( $q['s'] );
2133
			} else {
2134
				$q['search_terms'] = array( $q['s'] );
2135
			}
2136
		}
2137
2138
		$n = ! empty( $q['exact'] ) ? '' : '%';
2139
		$searchand = '';
2140
		$q['search_orderby_title'] = array();
2141
		foreach ( $q['search_terms'] as $term ) {
2142
			// Terms prefixed with '-' should be excluded.
2143
			$include = '-' !== substr( $term, 0, 1 );
2144
			if ( $include ) {
2145
				$like_op  = 'LIKE';
2146
				$andor_op = 'OR';
2147
			} else {
2148
				$like_op  = 'NOT LIKE';
2149
				$andor_op = 'AND';
2150
				$term     = substr( $term, 1 );
2151
			}
2152
2153
			if ( $n && $include ) {
2154
				$like = '%' . $wpdb->esc_like( $term ) . '%';
2155
				$q['search_orderby_title'][] = $wpdb->prepare( "$wpdb->posts.post_title LIKE %s", $like );
2156
			}
2157
2158
			$like = $n . $wpdb->esc_like( $term ) . $n;
2159
			$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 );
2160
			$searchand = ' AND ';
2161
		}
2162
2163
		if ( ! empty( $search ) ) {
2164
			$search = " AND ({$search}) ";
2165
			if ( ! is_user_logged_in() )
2166
				$search .= " AND ($wpdb->posts.post_password = '') ";
2167
		}
2168
2169
		return $search;
2170
	}
2171
2172
	/**
2173
	 * Check if the terms are suitable for searching.
2174
	 *
2175
	 * Uses an array of stopwords (terms) that are excluded from the separate
2176
	 * term matching when searching for posts. The list of English stopwords is
2177
	 * the approximate search engines list, and is translatable.
2178
	 *
2179
	 * @since 3.7.0
2180
	 *
2181
	 * @param array $terms Terms to check.
2182
	 * @return array Terms that are not stopwords.
2183
	 */
2184
	protected function parse_search_terms( $terms ) {
2185
		$strtolower = function_exists( 'mb_strtolower' ) ? 'mb_strtolower' : 'strtolower';
2186
		$checked = array();
2187
2188
		$stopwords = $this->get_search_stopwords();
2189
2190
		foreach ( $terms as $term ) {
2191
			// keep before/after spaces when term is for exact match
2192
			if ( preg_match( '/^".+"$/', $term ) )
2193
				$term = trim( $term, "\"'" );
2194
			else
2195
				$term = trim( $term, "\"' " );
2196
2197
			// Avoid single A-Z and single dashes.
2198
			if ( ! $term || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) )
2199
				continue;
2200
2201
			if ( in_array( call_user_func( $strtolower, $term ), $stopwords, true ) )
2202
				continue;
2203
2204
			$checked[] = $term;
2205
		}
2206
2207
		return $checked;
2208
	}
2209
2210
	/**
2211
	 * Retrieve stopwords used when parsing search terms.
2212
	 *
2213
	 * @since 3.7.0
2214
	 *
2215
	 * @return array Stopwords.
2216
	 */
2217
	protected function get_search_stopwords() {
2218
		if ( isset( $this->stopwords ) )
2219
			return $this->stopwords;
2220
2221
		/* translators: This is a comma-separated list of very common words that should be excluded from a search,
2222
		 * like a, an, and the. These are usually called "stopwords". You should not simply translate these individual
2223
		 * words into your language. Instead, look for and provide commonly accepted stopwords in your language.
2224
		 */
2225
		$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',
2226
			'Comma-separated list of search stopwords in your language' ) );
2227
2228
		$stopwords = array();
2229
		foreach ( $words as $word ) {
2230
			$word = trim( $word, "\r\n\t " );
2231
			if ( $word )
2232
				$stopwords[] = $word;
2233
		}
2234
2235
		/**
2236
		 * Filter stopwords used when parsing search terms.
2237
		 *
2238
		 * @since 3.7.0
2239
		 *
2240
		 * @param array $stopwords Stopwords.
2241
		 */
2242
		$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...
2243
		return $this->stopwords;
2244
	}
2245
2246
	/**
2247
	 * Generate SQL for the ORDER BY condition based on passed search terms.
2248
	 *
2249
	 * @global wpdb $wpdb WordPress database abstraction object.
2250
	 *
2251
	 * @param array $q Query variables.
2252
	 * @return string ORDER BY clause.
2253
	 */
2254
	protected function parse_search_order( &$q ) {
2255
		global $wpdb;
2256
2257
		if ( $q['search_terms_count'] > 1 ) {
2258
			$num_terms = count( $q['search_orderby_title'] );
2259
2260
			// If the search terms contain negative queries, don't bother ordering by sentence matches.
2261
			$like = '';
2262
			if ( ! preg_match( '/(?:\s|^)\-/', $q['s'] ) ) {
2263
				$like = '%' . $wpdb->esc_like( $q['s'] ) . '%';
2264
			}
2265
2266
			$search_orderby = '';
2267
2268
			// sentence match in 'post_title'
2269
			if ( $like ) {
2270
				$search_orderby .= $wpdb->prepare( "WHEN $wpdb->posts.post_title LIKE %s THEN 1 ", $like );
2271
			}
2272
2273
			// sanity limit, sort as sentence when more than 6 terms
2274
			// (few searches are longer than 6 terms and most titles are not)
2275
			if ( $num_terms < 7 ) {
2276
				// all words in title
2277
				$search_orderby .= 'WHEN ' . implode( ' AND ', $q['search_orderby_title'] ) . ' THEN 2 ';
2278
				// any word in title, not needed when $num_terms == 1
2279
				if ( $num_terms > 1 )
2280
					$search_orderby .= 'WHEN ' . implode( ' OR ', $q['search_orderby_title'] ) . ' THEN 3 ';
2281
			}
2282
2283
			// Sentence match in 'post_content' and 'post_excerpt'.
2284
			if ( $like ) {
2285
				$search_orderby .= $wpdb->prepare( "WHEN $wpdb->posts.post_excerpt LIKE %s THEN 4 ", $like );
2286
				$search_orderby .= $wpdb->prepare( "WHEN $wpdb->posts.post_content LIKE %s THEN 5 ", $like );
2287
			}
2288
2289
			if ( $search_orderby ) {
2290
				$search_orderby = '(CASE ' . $search_orderby . 'ELSE 6 END)';
2291
			}
2292
		} else {
2293
			// single word or sentence search
2294
			$search_orderby = reset( $q['search_orderby_title'] ) . ' DESC';
2295
		}
2296
2297
		return $search_orderby;
2298
	}
2299
2300
	/**
2301
	 * If the passed orderby value is allowed, convert the alias to a
2302
	 * properly-prefixed orderby value.
2303
	 *
2304
	 * @since 4.0.0
2305
	 * @access protected
2306
	 *
2307
	 * @global wpdb $wpdb WordPress database abstraction object.
2308
	 *
2309
	 * @param string $orderby Alias for the field to order by.
2310
	 * @return string|false Table-prefixed value to used in the ORDER clause. False otherwise.
2311
	 */
2312
	protected function parse_orderby( $orderby ) {
2313
		global $wpdb;
2314
2315
		// Used to filter values.
2316
		$allowed_keys = array(
2317
			'post_name', 'post_author', 'post_date', 'post_title', 'post_modified',
2318
			'post_parent', 'post_type', 'name', 'author', 'date', 'title', 'modified',
2319
			'parent', 'type', 'ID', 'menu_order', 'comment_count', 'rand',
2320
		);
2321
2322
		$primary_meta_key = '';
2323
		$primary_meta_query = false;
2324
		$meta_clauses = $this->meta_query->get_clauses();
2325
		if ( ! empty( $meta_clauses ) ) {
2326
			$primary_meta_query = reset( $meta_clauses );
2327
2328
			if ( ! empty( $primary_meta_query['key'] ) ) {
2329
				$primary_meta_key = $primary_meta_query['key'];
2330
				$allowed_keys[] = $primary_meta_key;
2331
			}
2332
2333
			$allowed_keys[] = 'meta_value';
2334
			$allowed_keys[] = 'meta_value_num';
2335
			$allowed_keys   = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
2336
		}
2337
2338
		// If RAND() contains a seed value, sanitize and add to allowed keys.
2339
		$rand_with_seed = false;
2340
		if ( preg_match( '/RAND\(([0-9]+)\)/i', $orderby, $matches ) ) {
2341
			$orderby = sprintf( 'RAND(%s)', intval( $matches[1] ) );
2342
			$allowed_keys[] = $orderby;
2343
			$rand_with_seed = true;
2344
		}
2345
2346
		if ( ! in_array( $orderby, $allowed_keys, true ) ) {
2347
			return false;
2348
		}
2349
2350
		switch ( $orderby ) {
2351
			case 'post_name':
2352
			case 'post_author':
2353
			case 'post_date':
2354
			case 'post_title':
2355
			case 'post_modified':
2356
			case 'post_parent':
2357
			case 'post_type':
2358
			case 'ID':
2359
			case 'menu_order':
2360
			case 'comment_count':
2361
				$orderby_clause = "$wpdb->posts.{$orderby}";
2362
				break;
2363
			case 'rand':
2364
				$orderby_clause = 'RAND()';
2365
				break;
2366
			case $primary_meta_key:
2367 View Code Duplication
			case 'meta_value':
2368
				if ( ! empty( $primary_meta_query['type'] ) ) {
2369
					$orderby_clause = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
2370
				} else {
2371
					$orderby_clause = "{$primary_meta_query['alias']}.meta_value";
2372
				}
2373
				break;
2374
			case 'meta_value_num':
2375
				$orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
2376
				break;
2377
			default:
2378
				if ( array_key_exists( $orderby, $meta_clauses ) ) {
2379
					// $orderby corresponds to a meta_query clause.
2380
					$meta_clause = $meta_clauses[ $orderby ];
2381
					$orderby_clause = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
2382
				} elseif ( $rand_with_seed ) {
2383
					$orderby_clause = $orderby;
2384
				} else {
2385
					// Default: order by post field.
2386
					$orderby_clause = "$wpdb->posts.post_" . sanitize_key( $orderby );
2387
				}
2388
2389
				break;
2390
		}
2391
2392
		return $orderby_clause;
2393
	}
2394
2395
	/**
2396
	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
2397
	 *
2398
	 * @since 4.0.0
2399
	 * @access protected
2400
	 *
2401
	 * @param string $order The 'order' query variable.
2402
	 * @return string The sanitized 'order' query variable.
2403
	 */
2404 View Code Duplication
	protected function parse_order( $order ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2405
		if ( ! is_string( $order ) || empty( $order ) ) {
2406
			return 'DESC';
2407
		}
2408
2409
		if ( 'ASC' === strtoupper( $order ) ) {
2410
			return 'ASC';
2411
		} else {
2412
			return 'DESC';
2413
		}
2414
	}
2415
2416
	/**
2417
	 * Sets the 404 property and saves whether query is feed.
2418
	 *
2419
	 * @since 2.0.0
2420
	 * @access public
2421
	 */
2422
	public function set_404() {
2423
		$is_feed = $this->is_feed;
2424
2425
		$this->init_query_flags();
2426
		$this->is_404 = true;
2427
2428
		$this->is_feed = $is_feed;
2429
	}
2430
2431
	/**
2432
	 * Retrieve query variable.
2433
	 *
2434
	 * @since 1.5.0
2435
	 * @since 3.9.0 The `$default` argument was introduced.
2436
	 *
2437
	 * @access public
2438
	 *
2439
	 * @param string $query_var Query variable key.
2440
	 * @param mixed  $default   Optional. Value to return if the query variable is not set. Default empty.
2441
	 * @return mixed Contents of the query variable.
2442
	 */
2443
	public function get( $query_var, $default = '' ) {
2444
		if ( isset( $this->query_vars[ $query_var ] ) ) {
2445
			return $this->query_vars[ $query_var ];
2446
		}
2447
2448
		return $default;
2449
	}
2450
2451
	/**
2452
	 * Set query variable.
2453
	 *
2454
	 * @since 1.5.0
2455
	 * @access public
2456
	 *
2457
	 * @param string $query_var Query variable key.
2458
	 * @param mixed  $value     Query variable value.
2459
	 */
2460
	public function set($query_var, $value) {
2461
		$this->query_vars[$query_var] = $value;
2462
	}
2463
2464
	/**
2465
	 * Retrieve the posts based on query variables.
2466
	 *
2467
	 * There are a few filters and actions that can be used to modify the post
2468
	 * database query.
2469
	 *
2470
	 * @since 1.5.0
2471
	 * @access public
2472
	 *
2473
	 * @global wpdb $wpdb WordPress database abstraction object.
2474
	 *
2475
	 * @return array List of posts.
2476
	 */
2477
	public function get_posts() {
2478
		global $wpdb;
2479
2480
		$this->parse_query();
2481
2482
		/**
2483
		 * Fires after the query variable object is created, but before the actual query is run.
2484
		 *
2485
		 * Note: If using conditional tags, use the method versions within the passed instance
2486
		 * (e.g. $this->is_main_query() instead of is_main_query()). This is because the functions
2487
		 * like is_main_query() test against the global $wp_query instance, not the passed one.
2488
		 *
2489
		 * @since 2.0.0
2490
		 *
2491
		 * @param WP_Query &$this The WP_Query instance (passed by reference).
2492
		 */
2493
		do_action_ref_array( 'pre_get_posts', array( &$this ) );
2494
2495
		// Shorthand.
2496
		$q = &$this->query_vars;
2497
2498
		// Fill again in case pre_get_posts unset some vars.
2499
		$q = $this->fill_query_vars($q);
2500
2501
		// Parse meta query
2502
		$this->meta_query = new WP_Meta_Query();
2503
		$this->meta_query->parse_query_vars( $q );
2504
2505
		// Set a flag if a pre_get_posts hook changed the query vars.
2506
		$hash = md5( serialize( $this->query_vars ) );
2507
		if ( $hash != $this->query_vars_hash ) {
2508
			$this->query_vars_changed = true;
2509
			$this->query_vars_hash = $hash;
2510
		}
2511
		unset($hash);
2512
2513
		// First let's clear some variables
2514
		$distinct = '';
2515
		$whichauthor = '';
2516
		$whichmimetype = '';
2517
		$where = '';
2518
		$limits = '';
2519
		$join = '';
2520
		$search = '';
2521
		$groupby = '';
2522
		$post_status_join = false;
2523
		$page = 1;
2524
2525
		if ( isset( $q['caller_get_posts'] ) ) {
2526
			_deprecated_argument( 'WP_Query', '3.1', __( '"caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.' ) );
2527
			if ( !isset( $q['ignore_sticky_posts'] ) )
2528
				$q['ignore_sticky_posts'] = $q['caller_get_posts'];
2529
		}
2530
2531
		if ( !isset( $q['ignore_sticky_posts'] ) )
2532
			$q['ignore_sticky_posts'] = false;
2533
2534
		if ( !isset($q['suppress_filters']) )
2535
			$q['suppress_filters'] = false;
2536
2537
		if ( !isset($q['cache_results']) ) {
2538
			if ( wp_using_ext_object_cache() )
2539
				$q['cache_results'] = false;
2540
			else
2541
				$q['cache_results'] = true;
2542
		}
2543
2544
		if ( !isset($q['update_post_term_cache']) )
2545
			$q['update_post_term_cache'] = true;
2546
2547
		if ( !isset($q['update_post_meta_cache']) )
2548
			$q['update_post_meta_cache'] = true;
2549
2550
		if ( !isset($q['post_type']) ) {
2551
			if ( $this->is_search )
2552
				$q['post_type'] = 'any';
2553
			else
2554
				$q['post_type'] = '';
2555
		}
2556
		$post_type = $q['post_type'];
2557
		if ( empty( $q['posts_per_page'] ) ) {
2558
			$q['posts_per_page'] = get_option( 'posts_per_page' );
2559
		}
2560
		if ( isset($q['showposts']) && $q['showposts'] ) {
2561
			$q['showposts'] = (int) $q['showposts'];
2562
			$q['posts_per_page'] = $q['showposts'];
2563
		}
2564
		if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
2565
			$q['posts_per_page'] = $q['posts_per_archive_page'];
2566
		if ( !isset($q['nopaging']) ) {
2567
			if ( $q['posts_per_page'] == -1 ) {
2568
				$q['nopaging'] = true;
2569
			} else {
2570
				$q['nopaging'] = false;
2571
			}
2572
		}
2573
2574
		if ( $this->is_feed ) {
2575
			// This overrides posts_per_page.
2576
			if ( ! empty( $q['posts_per_rss'] ) ) {
2577
				$q['posts_per_page'] = $q['posts_per_rss'];
2578
			} else {
2579
				$q['posts_per_page'] = get_option( 'posts_per_rss' );
2580
			}
2581
			$q['nopaging'] = false;
2582
		}
2583
		$q['posts_per_page'] = (int) $q['posts_per_page'];
2584
		if ( $q['posts_per_page'] < -1 )
2585
			$q['posts_per_page'] = abs($q['posts_per_page']);
2586
		elseif ( $q['posts_per_page'] == 0 )
2587
			$q['posts_per_page'] = 1;
2588
2589
		if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
2590
			$q['comments_per_page'] = get_option('comments_per_page');
2591
2592
		if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
2593
			$this->is_page = true;
2594
			$this->is_home = false;
2595
			$q['page_id'] = get_option('page_on_front');
2596
		}
2597
2598
		if ( isset($q['page']) ) {
2599
			$q['page'] = trim($q['page'], '/');
2600
			$q['page'] = absint($q['page']);
2601
		}
2602
2603
		// If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
2604
		if ( isset($q['no_found_rows']) )
2605
			$q['no_found_rows'] = (bool) $q['no_found_rows'];
2606
		else
2607
			$q['no_found_rows'] = false;
2608
2609
		switch ( $q['fields'] ) {
2610
			case 'ids':
2611
				$fields = "$wpdb->posts.ID";
2612
				break;
2613
			case 'id=>parent':
2614
				$fields = "$wpdb->posts.ID, $wpdb->posts.post_parent";
2615
				break;
2616
			default:
2617
				$fields = "$wpdb->posts.*";
2618
		}
2619
2620
		if ( '' !== $q['menu_order'] )
2621
			$where .= " AND $wpdb->posts.menu_order = " . $q['menu_order'];
2622
2623
		// The "m" parameter is meant for months but accepts datetimes of varying specificity
2624
		if ( $q['m'] ) {
2625
			$where .= " AND YEAR($wpdb->posts.post_date)=" . substr($q['m'], 0, 4);
2626 View Code Duplication
			if ( strlen($q['m']) > 5 )
2627
				$where .= " AND MONTH($wpdb->posts.post_date)=" . substr($q['m'], 4, 2);
2628 View Code Duplication
			if ( strlen($q['m']) > 7 )
2629
				$where .= " AND DAYOFMONTH($wpdb->posts.post_date)=" . substr($q['m'], 6, 2);
2630 View Code Duplication
			if ( strlen($q['m']) > 9 )
2631
				$where .= " AND HOUR($wpdb->posts.post_date)=" . substr($q['m'], 8, 2);
2632 View Code Duplication
			if ( strlen($q['m']) > 11 )
2633
				$where .= " AND MINUTE($wpdb->posts.post_date)=" . substr($q['m'], 10, 2);
2634 View Code Duplication
			if ( strlen($q['m']) > 13 )
2635
				$where .= " AND SECOND($wpdb->posts.post_date)=" . substr($q['m'], 12, 2);
2636
		}
2637
2638
		// Handle the other individual date parameters
2639
		$date_parameters = array();
2640
2641
		if ( '' !== $q['hour'] )
2642
			$date_parameters['hour'] = $q['hour'];
2643
2644
		if ( '' !== $q['minute'] )
2645
			$date_parameters['minute'] = $q['minute'];
2646
2647
		if ( '' !== $q['second'] )
2648
			$date_parameters['second'] = $q['second'];
2649
2650
		if ( $q['year'] )
2651
			$date_parameters['year'] = $q['year'];
2652
2653
		if ( $q['monthnum'] )
2654
			$date_parameters['monthnum'] = $q['monthnum'];
2655
2656
		if ( $q['w'] )
2657
			$date_parameters['week'] = $q['w'];
2658
2659
		if ( $q['day'] )
2660
			$date_parameters['day'] = $q['day'];
2661
2662
		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...
2663
			$date_query = new WP_Date_Query( array( $date_parameters ) );
2664
			$where .= $date_query->get_sql();
2665
		}
2666
		unset( $date_parameters, $date_query );
2667
2668
		// Handle complex date queries
2669
		if ( ! empty( $q['date_query'] ) ) {
2670
			$this->date_query = new WP_Date_Query( $q['date_query'] );
2671
			$where .= $this->date_query->get_sql();
2672
		}
2673
2674
2675
		// If we've got a post_type AND it's not "any" post_type.
2676
		if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
2677
			foreach ( (array)$q['post_type'] as $_post_type ) {
2678
				$ptype_obj = get_post_type_object($_post_type);
2679
				if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
2680
					continue;
2681
2682
				if ( ! $ptype_obj->hierarchical ) {
2683
					// Non-hierarchical post types can directly use 'name'.
2684
					$q['name'] = $q[ $ptype_obj->query_var ];
2685
				} else {
2686
					// Hierarchical post types will operate through 'pagename'.
2687
					$q['pagename'] = $q[ $ptype_obj->query_var ];
2688
					$q['name'] = '';
2689
				}
2690
2691
				// Only one request for a slug is possible, this is why name & pagename are overwritten above.
2692
				break;
2693
			} //end foreach
2694
			unset($ptype_obj);
2695
		}
2696
2697
		if ( '' !== $q['title'] ) {
2698
			$where .= $wpdb->prepare( " AND $wpdb->posts.post_title = %s", stripslashes( $q['title'] ) );
2699
		}
2700
2701
		// Parameters related to 'post_name'.
2702
		if ( '' != $q['name'] ) {
2703
			$q['name'] = sanitize_title_for_query( $q['name'] );
2704
			$where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";
2705
		} elseif ( '' != $q['pagename'] ) {
2706
			if ( isset($this->queried_object_id) ) {
2707
				$reqpage = $this->queried_object_id;
2708
			} else {
2709
				if ( 'page' != $q['post_type'] ) {
2710
					foreach ( (array)$q['post_type'] as $_post_type ) {
2711
						$ptype_obj = get_post_type_object($_post_type);
2712
						if ( !$ptype_obj || !$ptype_obj->hierarchical )
2713
							continue;
2714
2715
						$reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
2716
						if ( $reqpage )
2717
							break;
2718
					}
2719
					unset($ptype_obj);
2720
				} else {
2721
					$reqpage = get_page_by_path($q['pagename']);
2722
				}
2723
				if ( !empty($reqpage) )
2724
					$reqpage = $reqpage->ID;
2725
				else
2726
					$reqpage = 0;
2727
			}
2728
2729
			$page_for_posts = get_option('page_for_posts');
2730
			if  ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
2731
				$q['pagename'] = sanitize_title_for_query( wp_basename( $q['pagename'] ) );
2732
				$q['name'] = $q['pagename'];
2733
				$where .= " AND ($wpdb->posts.ID = '$reqpage')";
2734
				$reqpage_obj = get_post( $reqpage );
2735
				if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
2736
					$this->is_attachment = true;
2737
					$post_type = $q['post_type'] = 'attachment';
2738
					$this->is_page = true;
2739
					$q['attachment_id'] = $reqpage;
2740
				}
2741
			}
2742
		} elseif ( '' != $q['attachment'] ) {
2743
			$q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
2744
			$q['name'] = $q['attachment'];
2745
			$where .= " AND $wpdb->posts.post_name = '" . $q['attachment'] . "'";
2746
		} elseif ( is_array( $q['post_name__in'] ) && ! empty( $q['post_name__in'] ) ) {
2747
			$q['post_name__in'] = array_map( 'sanitize_title_for_query', $q['post_name__in'] );
2748
			$where .= " AND $wpdb->posts.post_name IN ('" . implode( "' ,'", $q['post_name__in'] ) . "')";
2749
		}
2750
2751
		// If an attachment is requested by number, let it supersede any post number.
2752
		if ( $q['attachment_id'] )
2753
			$q['p'] = absint($q['attachment_id']);
2754
2755
		// If a post number is specified, load that post
2756 View Code Duplication
		if ( $q['p'] ) {
2757
			$where .= " AND {$wpdb->posts}.ID = " . $q['p'];
2758
		} elseif ( $q['post__in'] ) {
2759
			$post__in = implode(',', array_map( 'absint', $q['post__in'] ));
2760
			$where .= " AND {$wpdb->posts}.ID IN ($post__in)";
2761
		} elseif ( $q['post__not_in'] ) {
2762
			$post__not_in = implode(',',  array_map( 'absint', $q['post__not_in'] ));
2763
			$where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
2764
		}
2765
2766 View Code Duplication
		if ( is_numeric( $q['post_parent'] ) ) {
2767
			$where .= $wpdb->prepare( " AND $wpdb->posts.post_parent = %d ", $q['post_parent'] );
2768
		} elseif ( $q['post_parent__in'] ) {
2769
			$post_parent__in = implode( ',', array_map( 'absint', $q['post_parent__in'] ) );
2770
			$where .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
2771
		} elseif ( $q['post_parent__not_in'] ) {
2772
			$post_parent__not_in = implode( ',',  array_map( 'absint', $q['post_parent__not_in'] ) );
2773
			$where .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
2774
		}
2775
2776
		if ( $q['page_id'] ) {
2777
			if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
2778
				$q['p'] = $q['page_id'];
2779
				$where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
2780
			}
2781
		}
2782
2783
		// If a search pattern is specified, load the posts that match.
2784
		if ( strlen( $q['s'] ) ) {
2785
			$search = $this->parse_search( $q );
2786
		}
2787
2788
		if ( ! $q['suppress_filters'] ) {
2789
			/**
2790
			 * Filter the search SQL that is used in the WHERE clause of WP_Query.
2791
			 *
2792
			 * @since 3.0.0
2793
			 *
2794
			 * @param string   $search Search SQL for WHERE clause.
2795
			 * @param WP_Query $this   The current WP_Query object.
2796
			 */
2797
			$search = apply_filters_ref_array( 'posts_search', array( $search, &$this ) );
2798
		}
2799
2800
		// Taxonomies
2801
		if ( !$this->is_singular ) {
2802
			$this->parse_tax_query( $q );
2803
2804
			$clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );
2805
2806
			$join .= $clauses['join'];
2807
			$where .= $clauses['where'];
2808
		}
2809
2810
		if ( $this->is_tax ) {
2811
			if ( empty($post_type) ) {
2812
				// Do a fully inclusive search for currently registered post types of queried taxonomies
2813
				$post_type = array();
2814
				$taxonomies = array_keys( $this->tax_query->queried_terms );
2815
				foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
2816
					$object_taxonomies = $pt === 'attachment' ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
2817
					if ( array_intersect( $taxonomies, $object_taxonomies ) )
2818
						$post_type[] = $pt;
2819
				}
2820
				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...
2821
					$post_type = 'any';
2822
				elseif ( count( $post_type ) == 1 )
2823
					$post_type = $post_type[0];
2824
2825
				$post_status_join = true;
2826
			} elseif ( in_array('attachment', (array) $post_type) ) {
2827
				$post_status_join = true;
2828
			}
2829
		}
2830
2831
		/*
2832
		 * Ensure that 'taxonomy', 'term', 'term_id', 'cat', and
2833
		 * 'category_name' vars are set for backward compatibility.
2834
		 */
2835
		if ( ! empty( $this->tax_query->queried_terms ) ) {
2836
2837
			/*
2838
			 * Set 'taxonomy', 'term', and 'term_id' to the
2839
			 * first taxonomy other than 'post_tag' or 'category'.
2840
			 */
2841
			if ( ! isset( $q['taxonomy'] ) ) {
2842
				foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
2843
					if ( empty( $queried_items['terms'][0] ) ) {
2844
						continue;
2845
					}
2846
2847
					if ( ! in_array( $queried_taxonomy, array( 'category', 'post_tag' ) ) ) {
2848
						$q['taxonomy'] = $queried_taxonomy;
2849
2850
						if ( 'slug' === $queried_items['field'] ) {
2851
							$q['term'] = $queried_items['terms'][0];
2852
						} else {
2853
							$q['term_id'] = $queried_items['terms'][0];
2854
						}
2855
2856
						// Take the first one we find.
2857
						break;
2858
					}
2859
				}
2860
			}
2861
2862
			// 'cat', 'category_name', 'tag_id'
2863
			foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
2864
				if ( empty( $queried_items['terms'][0] ) ) {
2865
					continue;
2866
				}
2867
2868 View Code Duplication
				if ( 'category' === $queried_taxonomy ) {
2869
					$the_cat = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'category' );
2870
					if ( $the_cat ) {
2871
						$this->set( 'cat', $the_cat->term_id );
2872
						$this->set( 'category_name', $the_cat->slug );
2873
					}
2874
					unset( $the_cat );
2875
				}
2876
2877 View Code Duplication
				if ( 'post_tag' === $queried_taxonomy ) {
2878
					$the_tag = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'post_tag' );
2879
					if ( $the_tag ) {
2880
						$this->set( 'tag_id', $the_tag->term_id );
2881
					}
2882
					unset( $the_tag );
2883
				}
2884
			}
2885
		}
2886
2887
		if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) {
2888
			$groupby = "{$wpdb->posts}.ID";
2889
		}
2890
2891
		// Author/user stuff
2892
2893
		if ( ! empty( $q['author'] ) && $q['author'] != '0' ) {
2894
			$q['author'] = addslashes_gpc( '' . urldecode( $q['author'] ) );
2895
			$authors = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $q['author'] ) ) );
2896
			foreach ( $authors as $author ) {
2897
				$key = $author > 0 ? 'author__in' : 'author__not_in';
2898
				$q[$key][] = abs( $author );
2899
			}
2900
			$q['author'] = implode( ',', $authors );
2901
		}
2902
2903
		if ( ! empty( $q['author__not_in'] ) ) {
2904
			$author__not_in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__not_in'] ) ) );
2905
			$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
2906
		} elseif ( ! empty( $q['author__in'] ) ) {
2907
			$author__in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__in'] ) ) );
2908
			$where .= " AND {$wpdb->posts}.post_author IN ($author__in) ";
2909
		}
2910
2911
		// Author stuff for nice URLs
2912
2913
		if ( '' != $q['author_name'] ) {
2914
			if ( strpos($q['author_name'], '/') !== false ) {
2915
				$q['author_name'] = explode('/', $q['author_name']);
2916
				if ( $q['author_name'][ count($q['author_name'])-1 ] ) {
2917
					$q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash
2918
				} else {
2919
					$q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash
2920
				}
2921
			}
2922
			$q['author_name'] = sanitize_title_for_query( $q['author_name'] );
2923
			$q['author'] = get_user_by('slug', $q['author_name']);
2924
			if ( $q['author'] )
2925
				$q['author'] = $q['author']->ID;
2926
			$whichauthor .= " AND ($wpdb->posts.post_author = " . absint($q['author']) . ')';
2927
		}
2928
2929
		// MIME-Type stuff for attachment browsing
2930
2931
		if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] )
2932
			$whichmimetype = wp_post_mime_type_where( $q['post_mime_type'], $wpdb->posts );
2933
2934
		$where .= $search . $whichauthor . $whichmimetype;
2935
2936
		if ( ! empty( $this->meta_query->queries ) ) {
2937
			$clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
2938
			$join   .= $clauses['join'];
2939
			$where  .= $clauses['where'];
2940
		}
2941
2942
		$rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
2943
		if ( ! isset( $q['order'] ) ) {
2944
			$q['order'] = $rand ? '' : 'DESC';
2945
		} else {
2946
			$q['order'] = $rand ? '' : $this->parse_order( $q['order'] );
2947
		}
2948
2949
		// Order by.
2950
		if ( empty( $q['orderby'] ) ) {
2951
			/*
2952
			 * Boolean false or empty array blanks out ORDER BY,
2953
			 * while leaving the value unset or otherwise empty sets the default.
2954
			 */
2955
			if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
2956
				$orderby = '';
2957
			} else {
2958
				$orderby = "$wpdb->posts.post_date " . $q['order'];
2959
			}
2960
		} elseif ( 'none' == $q['orderby'] ) {
2961
			$orderby = '';
2962
		} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
2963
			$orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
2964
		} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
2965
			$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
2966
		} else {
2967
			$orderby_array = array();
2968
			if ( is_array( $q['orderby'] ) ) {
2969
				foreach ( $q['orderby'] as $_orderby => $order ) {
2970
					$orderby = addslashes_gpc( urldecode( $_orderby ) );
2971
					$parsed  = $this->parse_orderby( $orderby );
0 ignored issues
show
Bug introduced by
It seems like $orderby defined by addslashes_gpc(urldecode($_orderby)) on line 2970 can also be of type array; however, WP_Query::parse_orderby() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
2972
2973
					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...
2974
						continue;
2975
					}
2976
2977
					$orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
2978
				}
2979
				$orderby = implode( ', ', $orderby_array );
2980
2981
			} else {
2982
				$q['orderby'] = urldecode( $q['orderby'] );
2983
				$q['orderby'] = addslashes_gpc( $q['orderby'] );
2984
2985
				foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
2986
					$parsed = $this->parse_orderby( $orderby );
2987
					// Only allow certain values for safety.
2988
					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...
2989
						continue;
2990
					}
2991
2992
					$orderby_array[] = $parsed;
2993
				}
2994
				$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
2995
2996
				if ( empty( $orderby ) ) {
2997
					$orderby = "$wpdb->posts.post_date " . $q['order'];
2998
				} elseif ( ! empty( $q['order'] ) ) {
2999
					$orderby .= " {$q['order']}";
3000
				}
3001
			}
3002
		}
3003
3004
		// Order search results by relevance only when another "orderby" is not specified in the query.
3005
		if ( ! empty( $q['s'] ) ) {
3006
			$search_orderby = '';
3007
			if ( ! empty( $q['search_orderby_title'] ) && ( empty( $q['orderby'] ) && ! $this->is_feed ) || ( isset( $q['orderby'] ) && 'relevance' === $q['orderby'] ) )
3008
				$search_orderby = $this->parse_search_order( $q );
3009
3010
			if ( ! $q['suppress_filters'] ) {
3011
				/**
3012
				 * Filter the ORDER BY used when ordering search results.
3013
				 *
3014
				 * @since 3.7.0
3015
				 *
3016
				 * @param string   $search_orderby The ORDER BY clause.
3017
				 * @param WP_Query $this           The current WP_Query instance.
3018
				 */
3019
				$search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );
3020
			}
3021
3022
			if ( $search_orderby )
3023
				$orderby = $orderby ? $search_orderby . ', ' . $orderby : $search_orderby;
3024
		}
3025
3026
		if ( is_array( $post_type ) && count( $post_type ) > 1 ) {
3027
			$post_type_cap = 'multiple_post_type';
3028
		} else {
3029
			if ( is_array( $post_type ) )
3030
				$post_type = reset( $post_type );
3031
			$post_type_object = get_post_type_object( $post_type );
3032
			if ( empty( $post_type_object ) )
3033
				$post_type_cap = $post_type;
3034
		}
3035
3036
		if ( isset( $q['post_password'] ) ) {
3037
			$where .= $wpdb->prepare( " AND $wpdb->posts.post_password = %s", $q['post_password'] );
3038
			if ( empty( $q['perm'] ) ) {
3039
				$q['perm'] = 'readable';
3040
			}
3041
		} elseif ( isset( $q['has_password'] ) ) {
3042
			$where .= sprintf( " AND $wpdb->posts.post_password %s ''", $q['has_password'] ? '!=' : '=' );
3043
		}
3044
3045 View Code Duplication
		if ( ! empty( $q['comment_status'] ) ) {
3046
			$where .= $wpdb->prepare( " AND $wpdb->posts.comment_status = %s ", $q['comment_status'] );
3047
		}
3048
3049 View Code Duplication
		if ( ! empty( $q['ping_status'] ) )  {
3050
			$where .= $wpdb->prepare( " AND $wpdb->posts.ping_status = %s ", $q['ping_status'] );
3051
		}
3052
3053
		if ( 'any' == $post_type ) {
3054
			$in_search_post_types = get_post_types( array('exclude_from_search' => false) );
3055
			if ( empty( $in_search_post_types ) )
3056
				$where .= ' AND 1=0 ';
3057
			else
3058
				$where .= " AND $wpdb->posts.post_type IN ('" . join("', '", $in_search_post_types ) . "')";
3059
		} elseif ( !empty( $post_type ) && is_array( $post_type ) ) {
3060
			$where .= " AND $wpdb->posts.post_type IN ('" . join("', '", $post_type) . "')";
3061
		} elseif ( ! empty( $post_type ) ) {
3062
			$where .= " AND $wpdb->posts.post_type = '$post_type'";
3063
			$post_type_object = get_post_type_object ( $post_type );
3064
		} elseif ( $this->is_attachment ) {
3065
			$where .= " AND $wpdb->posts.post_type = 'attachment'";
3066
			$post_type_object = get_post_type_object ( 'attachment' );
3067
		} elseif ( $this->is_page ) {
3068
			$where .= " AND $wpdb->posts.post_type = 'page'";
3069
			$post_type_object = get_post_type_object ( 'page' );
3070
		} else {
3071
			$where .= " AND $wpdb->posts.post_type = 'post'";
3072
			$post_type_object = get_post_type_object ( 'post' );
3073
		}
3074
3075
		$edit_cap = 'edit_post';
3076
		$read_cap = 'read_post';
3077
3078
		if ( ! empty( $post_type_object ) ) {
3079
			$edit_others_cap = $post_type_object->cap->edit_others_posts;
3080
			$read_private_cap = $post_type_object->cap->read_private_posts;
3081
		} else {
3082
			$edit_others_cap = 'edit_others_' . $post_type_cap . 's';
0 ignored issues
show
Bug introduced by
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...
3083
			$read_private_cap = 'read_private_' . $post_type_cap . 's';
3084
		}
3085
3086
		$user_id = get_current_user_id();
3087
3088
		$q_status = array();
3089
		if ( ! empty( $q['post_status'] ) ) {
3090
			$statuswheres = array();
3091
			$q_status = $q['post_status'];
3092
			if ( ! is_array( $q_status ) )
3093
				$q_status = explode(',', $q_status);
3094
			$r_status = array();
3095
			$p_status = array();
3096
			$e_status = array();
3097
			if ( in_array( 'any', $q_status ) ) {
3098
				foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
3099
					if ( ! in_array( $status, $q_status ) ) {
3100
						$e_status[] = "$wpdb->posts.post_status <> '$status'";
3101
					}
3102
				}
3103
			} else {
3104
				foreach ( get_post_stati() as $status ) {
3105
					if ( in_array( $status, $q_status ) ) {
3106
						if ( 'private' == $status )
3107
							$p_status[] = "$wpdb->posts.post_status = '$status'";
3108
						else
3109
							$r_status[] = "$wpdb->posts.post_status = '$status'";
3110
					}
3111
				}
3112
			}
3113
3114
			if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
3115
				$r_status = array_merge($r_status, $p_status);
3116
				unset($p_status);
3117
			}
3118
3119
			if ( !empty($e_status) ) {
3120
				$statuswheres[] = "(" . join( ' AND ', $e_status ) . ")";
3121
			}
3122 View Code Duplication
			if ( !empty($r_status) ) {
3123
				if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) )
3124
					$statuswheres[] = "($wpdb->posts.post_author = $user_id " . "AND (" . join( ' OR ', $r_status ) . "))";
3125
				else
3126
					$statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
3127
			}
3128 View Code Duplication
			if ( !empty($p_status) ) {
3129
				if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) )
3130
					$statuswheres[] = "($wpdb->posts.post_author = $user_id " . "AND (" . join( ' OR ', $p_status ) . "))";
3131
				else
3132
					$statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
3133
			}
3134
			if ( $post_status_join ) {
3135
				$join .= " LEFT JOIN $wpdb->posts AS p2 ON ($wpdb->posts.post_parent = p2.ID) ";
3136
				foreach ( $statuswheres as $index => $statuswhere )
3137
					$statuswheres[$index] = "($statuswhere OR ($wpdb->posts.post_status = 'inherit' AND " . str_replace($wpdb->posts, 'p2', $statuswhere) . "))";
3138
			}
3139
			$where_status = implode( ' OR ', $statuswheres );
3140
			if ( ! empty( $where_status ) ) {
3141
				$where .= " AND ($where_status)";
3142
			}
3143
		} elseif ( !$this->is_singular ) {
3144
			$where .= " AND ($wpdb->posts.post_status = 'publish'";
3145
3146
			// Add public states.
3147
			$public_states = get_post_stati( array('public' => true) );
3148
			foreach ( (array) $public_states as $state ) {
3149
				if ( 'publish' == $state ) // Publish is hard-coded above.
3150
					continue;
3151
				$where .= " OR $wpdb->posts.post_status = '$state'";
3152
			}
3153
3154
			if ( $this->is_admin ) {
3155
				// Add protected states that should show in the admin all list.
3156
				$admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
3157
				foreach ( (array) $admin_all_states as $state )
3158
					$where .= " OR $wpdb->posts.post_status = '$state'";
3159
			}
3160
3161
			if ( is_user_logged_in() ) {
3162
				// Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
3163
				$private_states = get_post_stati( array('private' => true) );
3164
				foreach ( (array) $private_states as $state )
3165
					$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'";
3166
			}
3167
3168
			$where .= ')';
3169
		}
3170
3171
		/*
3172
		 * Apply filters on where and join prior to paging so that any
3173
		 * manipulations to them are reflected in the paging by day queries.
3174
		 */
3175
		if ( !$q['suppress_filters'] ) {
3176
			/**
3177
			 * Filter the WHERE clause of the query.
3178
			 *
3179
			 * @since 1.5.0
3180
			 *
3181
			 * @param string   $where The WHERE clause of the query.
3182
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3183
			 */
3184
			$where = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
3185
3186
			/**
3187
			 * Filter the JOIN clause of the query.
3188
			 *
3189
			 * @since 1.5.0
3190
			 *
3191
			 * @param string   $where The JOIN clause of the query.
3192
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3193
			 */
3194
			$join = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
3195
		}
3196
3197
		// Paging
3198
		if ( empty($q['nopaging']) && !$this->is_singular ) {
3199
			$page = absint($q['paged']);
3200
			if ( !$page )
3201
				$page = 1;
3202
3203
			// If 'offset' is provided, it takes precedence over 'paged'.
3204
			if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
3205
				$q['offset'] = absint( $q['offset'] );
3206
				$pgstrt = $q['offset'] . ', ';
3207
			} else {
3208
				$pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
3209
			}
3210
			$limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
3211
		}
3212
3213
		// Comments feeds
3214
		if ( $this->is_comment_feed && ! $this->is_singular ) {
3215
			if ( $this->is_archive || $this->is_search ) {
3216
				$cjoin = "JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID = $wpdb->posts.ID) $join ";
3217
				$cwhere = "WHERE comment_approved = '1' $where";
3218
				$cgroupby = "$wpdb->comments.comment_id";
3219
			} else { // Other non singular e.g. front
3220
				$cjoin = "JOIN $wpdb->posts ON ( $wpdb->comments.comment_post_ID = $wpdb->posts.ID )";
3221
				$cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' && post_type = 'attachment' ) ) AND comment_approved = '1'";
3222
				$cgroupby = '';
3223
			}
3224
3225
			if ( !$q['suppress_filters'] ) {
3226
				/**
3227
				 * Filter the JOIN clause of the comments feed query before sending.
3228
				 *
3229
				 * @since 2.2.0
3230
				 *
3231
				 * @param string   $cjoin The JOIN clause of the query.
3232
				 * @param WP_Query &$this The WP_Query instance (passed by reference).
3233
				 */
3234
				$cjoin = apply_filters_ref_array( 'comment_feed_join', array( $cjoin, &$this ) );
3235
3236
				/**
3237
				 * Filter the WHERE clause of the comments feed query before sending.
3238
				 *
3239
				 * @since 2.2.0
3240
				 *
3241
				 * @param string   $cwhere The WHERE clause of the query.
3242
				 * @param WP_Query &$this  The WP_Query instance (passed by reference).
3243
				 */
3244
				$cwhere = apply_filters_ref_array( 'comment_feed_where', array( $cwhere, &$this ) );
3245
3246
				/**
3247
				 * Filter the GROUP BY clause of the comments feed query before sending.
3248
				 *
3249
				 * @since 2.2.0
3250
				 *
3251
				 * @param string   $cgroupby The GROUP BY clause of the query.
3252
				 * @param WP_Query &$this    The WP_Query instance (passed by reference).
3253
				 */
3254
				$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( $cgroupby, &$this ) );
3255
3256
				/**
3257
				 * Filter the ORDER BY clause of the comments feed query before sending.
3258
				 *
3259
				 * @since 2.8.0
3260
				 *
3261
				 * @param string   $corderby The ORDER BY clause of the query.
3262
				 * @param WP_Query &$this    The WP_Query instance (passed by reference).
3263
				 */
3264
				$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
3265
3266
				/**
3267
				 * Filter the LIMIT clause of the comments feed query before sending.
3268
				 *
3269
				 * @since 2.8.0
3270
				 *
3271
				 * @param string   $climits The JOIN clause of the query.
3272
				 * @param WP_Query &$this   The WP_Query instance (passed by reference).
3273
				 */
3274
				$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
3275
			}
3276
			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
3277
			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
3278
3279
			$comments = (array) $wpdb->get_results("SELECT $distinct $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits");
0 ignored issues
show
Bug introduced by
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...
3280
			// Convert to WP_Comment
3281
			$this->comments = array_map( 'get_comment', $comments );
3282
			$this->comment_count = count($this->comments);
3283
3284
			$post_ids = array();
3285
3286
			foreach ( $this->comments as $comment )
3287
				$post_ids[] = (int) $comment->comment_post_ID;
3288
3289
			$post_ids = join(',', $post_ids);
3290
			$join = '';
3291
			if ( $post_ids )
3292
				$where = "AND $wpdb->posts.ID IN ($post_ids) ";
3293
			else
3294
				$where = "AND 0";
3295
		}
3296
3297
		$pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );
3298
3299
		/*
3300
		 * Apply post-paging filters on where and join. Only plugins that
3301
		 * manipulate paging queries should use these hooks.
3302
		 */
3303 View Code Duplication
		if ( !$q['suppress_filters'] ) {
3304
			/**
3305
			 * Filter the WHERE clause of the query.
3306
			 *
3307
			 * Specifically for manipulating paging queries.
3308
			 *
3309
			 * @since 1.5.0
3310
			 *
3311
			 * @param string   $where The WHERE clause of the query.
3312
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3313
			 */
3314
			$where = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
3315
3316
			/**
3317
			 * Filter the GROUP BY clause of the query.
3318
			 *
3319
			 * @since 2.0.0
3320
			 *
3321
			 * @param string   $groupby The GROUP BY clause of the query.
3322
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
3323
			 */
3324
			$groupby = apply_filters_ref_array( 'posts_groupby', array( $groupby, &$this ) );
3325
3326
			/**
3327
			 * Filter the JOIN clause of the query.
3328
			 *
3329
			 * Specifically for manipulating paging queries.
3330
			 *
3331
			 * @since 1.5.0
3332
			 *
3333
			 * @param string   $join  The JOIN clause of the query.
3334
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3335
			 */
3336
			$join = apply_filters_ref_array( 'posts_join_paged', array( $join, &$this ) );
3337
3338
			/**
3339
			 * Filter the ORDER BY clause of the query.
3340
			 *
3341
			 * @since 1.5.1
3342
			 *
3343
			 * @param string   $orderby The ORDER BY clause of the query.
3344
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
3345
			 */
3346
			$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
3347
3348
			/**
3349
			 * Filter the DISTINCT clause of the query.
3350
			 *
3351
			 * @since 2.1.0
3352
			 *
3353
			 * @param string   $distinct The DISTINCT clause of the query.
3354
			 * @param WP_Query &$this    The WP_Query instance (passed by reference).
3355
			 */
3356
			$distinct = apply_filters_ref_array( 'posts_distinct', array( $distinct, &$this ) );
3357
3358
			/**
3359
			 * Filter the LIMIT clause of the query.
3360
			 *
3361
			 * @since 2.1.0
3362
			 *
3363
			 * @param string   $limits The LIMIT clause of the query.
3364
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
3365
			 */
3366
			$limits = apply_filters_ref_array( 'post_limits', array( $limits, &$this ) );
3367
3368
			/**
3369
			 * Filter the SELECT clause of the query.
3370
			 *
3371
			 * @since 2.1.0
3372
			 *
3373
			 * @param string   $fields The SELECT clause of the query.
3374
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
3375
			 */
3376
			$fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );
3377
3378
			/**
3379
			 * Filter all query clauses at once, for convenience.
3380
			 *
3381
			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
3382
			 * fields (SELECT), and LIMITS clauses.
3383
			 *
3384
			 * @since 3.1.0
3385
			 *
3386
			 * @param array    $clauses The list of clauses for the query.
3387
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
3388
			 */
3389
			$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
3390
3391
			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
3392
			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
3393
			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
3394
			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
3395
			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
3396
			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
3397
			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
3398
		}
3399
3400
		/**
3401
		 * Fires to announce the query's current selection parameters.
3402
		 *
3403
		 * For use by caching plugins.
3404
		 *
3405
		 * @since 2.3.0
3406
		 *
3407
		 * @param string $selection The assembled selection query.
3408
		 */
3409
		do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
3410
3411
		/*
3412
		 * Filter again for the benefit of caching plugins.
3413
		 * Regular plugins should use the hooks above.
3414
		 */
3415 View Code Duplication
		if ( !$q['suppress_filters'] ) {
3416
			/**
3417
			 * Filter the WHERE clause of the query.
3418
			 *
3419
			 * For use by caching plugins.
3420
			 *
3421
			 * @since 2.5.0
3422
			 *
3423
			 * @param string   $where The WHERE clause of the query.
3424
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3425
			 */
3426
			$where = apply_filters_ref_array( 'posts_where_request', array( $where, &$this ) );
3427
3428
			/**
3429
			 * Filter the GROUP BY clause of the query.
3430
			 *
3431
			 * For use by caching plugins.
3432
			 *
3433
			 * @since 2.5.0
3434
			 *
3435
			 * @param string   $groupby The GROUP BY clause of the query.
3436
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
3437
			 */
3438
			$groupby = apply_filters_ref_array( 'posts_groupby_request', array( $groupby, &$this ) );
3439
3440
			/**
3441
			 * Filter the JOIN clause of the query.
3442
			 *
3443
			 * For use by caching plugins.
3444
			 *
3445
			 * @since 2.5.0
3446
			 *
3447
			 * @param string   $join  The JOIN clause of the query.
3448
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3449
			 */
3450
			$join = apply_filters_ref_array( 'posts_join_request', array( $join, &$this ) );
3451
3452
			/**
3453
			 * Filter the ORDER BY clause of the query.
3454
			 *
3455
			 * For use by caching plugins.
3456
			 *
3457
			 * @since 2.5.0
3458
			 *
3459
			 * @param string   $orderby The ORDER BY clause of the query.
3460
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
3461
			 */
3462
			$orderby = apply_filters_ref_array( 'posts_orderby_request', array( $orderby, &$this ) );
3463
3464
			/**
3465
			 * Filter the DISTINCT clause of the query.
3466
			 *
3467
			 * For use by caching plugins.
3468
			 *
3469
			 * @since 2.5.0
3470
			 *
3471
			 * @param string   $distinct The DISTINCT clause of the query.
3472
			 * @param WP_Query &$this    The WP_Query instance (passed by reference).
3473
			 */
3474
			$distinct = apply_filters_ref_array( 'posts_distinct_request', array( $distinct, &$this ) );
3475
3476
			/**
3477
			 * Filter the SELECT clause of the query.
3478
			 *
3479
			 * For use by caching plugins.
3480
			 *
3481
			 * @since 2.5.0
3482
			 *
3483
			 * @param string   $fields The SELECT clause of the query.
3484
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
3485
			 */
3486
			$fields = apply_filters_ref_array( 'posts_fields_request', array( $fields, &$this ) );
3487
3488
			/**
3489
			 * Filter the LIMIT clause of the query.
3490
			 *
3491
			 * For use by caching plugins.
3492
			 *
3493
			 * @since 2.5.0
3494
			 *
3495
			 * @param string   $limits The LIMIT clause of the query.
3496
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
3497
			 */
3498
			$limits = apply_filters_ref_array( 'post_limits_request', array( $limits, &$this ) );
3499
3500
			/**
3501
			 * Filter all query clauses at once, for convenience.
3502
			 *
3503
			 * For use by caching plugins.
3504
			 *
3505
			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
3506
			 * fields (SELECT), and LIMITS clauses.
3507
			 *
3508
			 * @since 3.1.0
3509
			 *
3510
			 * @param array    $pieces The pieces of the query.
3511
			 * @param WP_Query &$this  The WP_Query instance (passed by reference).
3512
			 */
3513
			$clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
3514
3515
			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
3516
			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
3517
			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
3518
			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
3519
			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
3520
			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
3521
			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
3522
		}
3523
3524
		if ( ! empty($groupby) )
3525
			$groupby = 'GROUP BY ' . $groupby;
3526
		if ( !empty( $orderby ) )
3527
			$orderby = 'ORDER BY ' . $orderby;
3528
3529
		$found_rows = '';
3530
		if ( !$q['no_found_rows'] && !empty($limits) )
3531
			$found_rows = 'SQL_CALC_FOUND_ROWS';
3532
3533
		$this->request = $old_request = "SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
3534
3535
		if ( !$q['suppress_filters'] ) {
3536
			/**
3537
			 * Filter the completed SQL query before sending.
3538
			 *
3539
			 * @since 2.0.0
3540
			 *
3541
			 * @param array    $request The complete SQL query.
3542
			 * @param WP_Query &$this   The WP_Query instance (passed by reference).
3543
			 */
3544
			$this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
3545
		}
3546
3547
		if ( 'ids' == $q['fields'] ) {
3548
			$this->posts = $wpdb->get_col( $this->request );
3549
			$this->posts = array_map( 'intval', $this->posts );
3550
			$this->post_count = count( $this->posts );
3551
			$this->set_found_posts( $q, $limits );
3552
3553
			return $this->posts;
3554
		}
3555
3556
		if ( 'id=>parent' == $q['fields'] ) {
3557
			$this->posts = $wpdb->get_results( $this->request );
3558
			$this->post_count = count( $this->posts );
3559
			$this->set_found_posts( $q, $limits );
3560
3561
			$r = array();
3562
			foreach ( $this->posts as $key => $post ) {
3563
				$this->posts[ $key ]->ID = (int) $post->ID;
3564
				$this->posts[ $key ]->post_parent = (int) $post->post_parent;
3565
3566
				$r[ (int) $post->ID ] = (int) $post->post_parent;
3567
			}
3568
3569
			return $r;
3570
		}
3571
3572
		$split_the_query = ( $old_request == $this->request && "$wpdb->posts.*" == $fields && !empty( $limits ) && $q['posts_per_page'] < 500 );
3573
3574
		/**
3575
		 * Filter whether to split the query.
3576
		 *
3577
		 * Splitting the query will cause it to fetch just the IDs of the found posts
3578
		 * (and then individually fetch each post by ID), rather than fetching every
3579
		 * complete row at once. One massive result vs. many small results.
3580
		 *
3581
		 * @since 3.4.0
3582
		 *
3583
		 * @param bool     $split_the_query Whether or not to split the query.
3584
		 * @param WP_Query $this            The WP_Query instance.
3585
		 */
3586
		$split_the_query = apply_filters( 'split_the_query', $split_the_query, $this );
3587
3588
		if ( $split_the_query ) {
3589
			// First get the IDs and then fill in the objects
3590
3591
			$this->request = "SELECT $found_rows $distinct $wpdb->posts.ID FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
3592
3593
			/**
3594
			 * Filter the Post IDs SQL request before sending.
3595
			 *
3596
			 * @since 3.4.0
3597
			 *
3598
			 * @param string   $request The post ID request.
3599
			 * @param WP_Query $this    The WP_Query instance.
3600
			 */
3601
			$this->request = apply_filters( 'posts_request_ids', $this->request, $this );
3602
3603
			$ids = $wpdb->get_col( $this->request );
3604
3605
			if ( $ids ) {
3606
				$this->posts = $ids;
3607
				$this->set_found_posts( $q, $limits );
3608
				_prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
3609
			} else {
3610
				$this->posts = array();
3611
			}
3612
		} else {
3613
			$this->posts = $wpdb->get_results( $this->request );
3614
			$this->set_found_posts( $q, $limits );
3615
		}
3616
3617
		// Convert to WP_Post objects
3618
		if ( $this->posts )
3619
			$this->posts = array_map( 'get_post', $this->posts );
3620
3621 View Code Duplication
		if ( ! $q['suppress_filters'] ) {
3622
			/**
3623
			 * Filter the raw post results array, prior to status checks.
3624
			 *
3625
			 * @since 2.3.0
3626
			 *
3627
			 * @param array    $posts The post results array.
3628
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3629
			 */
3630
			$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...
3631
		}
3632
3633
		if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
3634
			/** This filter is documented in wp-includes/query.php */
3635
			$cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
3636
3637
			/** This filter is documented in wp-includes/query.php */
3638
			$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
3639
3640
			/** This filter is documented in wp-includes/query.php */
3641
			$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
3642
			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
3643
3644
			/** This filter is documented in wp-includes/query.php */
3645
			$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
3646
			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
3647
3648
			/** This filter is documented in wp-includes/query.php */
3649
			$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
3650
3651
			$comments_request = "SELECT $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits";
3652
			$comments = $wpdb->get_results($comments_request);
3653
			// Convert to WP_Comment
3654
			$this->comments = array_map( 'get_comment', $comments );
3655
			$this->comment_count = count($this->comments);
3656
		}
3657
3658
		// Check post status to determine if post should be displayed.
3659
		if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
3660
			$status = get_post_status($this->posts[0]);
3661
			if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) {
3662
				$this->is_page = false;
3663
				$this->is_single = true;
3664
				$this->is_attachment = true;
3665
			}
3666
			$post_status_obj = get_post_status_object($status);
0 ignored issues
show
Security Bug introduced by
It seems like $status defined by get_post_status($this->posts[0]) on line 3660 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...
3667
3668
			// If the post_status was specifically requested, let it pass through.
3669
			if ( !$post_status_obj->public && ! in_array( $status, $q_status ) ) {
3670
3671
				if ( ! is_user_logged_in() ) {
3672
					// User must be logged in to view unpublished posts.
3673
					$this->posts = array();
3674
				} else {
3675
					if  ( $post_status_obj->protected ) {
3676
						// User must have edit permissions on the draft to preview.
3677
						if ( ! current_user_can($edit_cap, $this->posts[0]->ID) ) {
3678
							$this->posts = array();
3679
						} else {
3680
							$this->is_preview = true;
3681
							if ( 'future' != $status )
3682
								$this->posts[0]->post_date = current_time('mysql');
3683
						}
3684
					} elseif ( $post_status_obj->private ) {
3685
						if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
3686
							$this->posts = array();
3687
					} else {
3688
						$this->posts = array();
3689
					}
3690
				}
3691
			}
3692
3693
			if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
3694
				/**
3695
				 * Filter the single post for preview mode.
3696
				 *
3697
				 * @since 2.7.0
3698
				 *
3699
				 * @param WP_Post  $post_preview  The Post object.
3700
				 * @param WP_Query &$this         The WP_Query instance (passed by reference).
3701
				 */
3702
				$this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
3703
			}
3704
		}
3705
3706
		// Put sticky posts at the top of the posts array
3707
		$sticky_posts = get_option('sticky_posts');
3708
		if ( $this->is_home && $page <= 1 && is_array($sticky_posts) && !empty($sticky_posts) && !$q['ignore_sticky_posts'] ) {
3709
			$num_posts = count($this->posts);
3710
			$sticky_offset = 0;
3711
			// Loop over posts and relocate stickies to the front.
3712
			for ( $i = 0; $i < $num_posts; $i++ ) {
3713
				if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
3714
					$sticky_post = $this->posts[$i];
3715
					// Remove sticky from current position
3716
					array_splice($this->posts, $i, 1);
3717
					// Move to front, after other stickies
3718
					array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
3719
					// Increment the sticky offset. The next sticky will be placed at this offset.
3720
					$sticky_offset++;
3721
					// Remove post from sticky posts array
3722
					$offset = array_search($sticky_post->ID, $sticky_posts);
3723
					unset( $sticky_posts[$offset] );
3724
				}
3725
			}
3726
3727
			// If any posts have been excluded specifically, Ignore those that are sticky.
3728
			if ( !empty($sticky_posts) && !empty($q['post__not_in']) )
3729
				$sticky_posts = array_diff($sticky_posts, $q['post__not_in']);
3730
3731
			// Fetch sticky posts that weren't in the query results
3732
			if ( !empty($sticky_posts) ) {
3733
				$stickies = get_posts( array(
3734
					'post__in' => $sticky_posts,
3735
					'post_type' => $post_type,
3736
					'post_status' => 'publish',
3737
					'nopaging' => true
3738
				) );
3739
3740
				foreach ( $stickies as $sticky_post ) {
3741
					array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
3742
					$sticky_offset++;
3743
				}
3744
			}
3745
		}
3746
3747
		// If comments have been fetched as part of the query, make sure comment meta lazy-loading is set up.
3748
		if ( ! empty( $this->comments ) ) {
3749
			wp_queue_comments_for_comment_meta_lazyload( $this->comments );
3750
		}
3751
3752 View Code Duplication
		if ( ! $q['suppress_filters'] ) {
3753
			/**
3754
			 * Filter the array of retrieved posts after they've been fetched and
3755
			 * internally processed.
3756
			 *
3757
			 * @since 1.5.0
3758
			 *
3759
			 * @param array    $posts The array of retrieved posts.
3760
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3761
			 */
3762
			$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...
3763
		}
3764
3765
		// Ensure that any posts added/modified via one of the filters above are
3766
		// of the type WP_Post and are filtered.
3767
		if ( $this->posts ) {
3768
			$this->post_count = count( $this->posts );
3769
3770
			$this->posts = array_map( 'get_post', $this->posts );
3771
3772
			if ( $q['cache_results'] )
3773
				update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
3774
3775
			$this->post = reset( $this->posts );
3776
		} else {
3777
			$this->post_count = 0;
3778
			$this->posts = array();
3779
		}
3780
3781
		if ( $q['update_post_term_cache'] ) {
3782
			wp_queue_posts_for_term_meta_lazyload( $this->posts );
3783
		}
3784
3785
		return $this->posts;
3786
	}
3787
3788
	/**
3789
	 * Set up the amount of found posts and the number of pages (if limit clause was used)
3790
	 * for the current query.
3791
	 *
3792
	 * @since 3.5.0
3793
	 * @access private
3794
	 *
3795
	 * @global wpdb $wpdb WordPress database abstraction object.
3796
	 *
3797
	 * @param array  $q      Query variables.
3798
	 * @param string $limits LIMIT clauses of the query.
3799
	 */
3800
	private function set_found_posts( $q, $limits ) {
3801
		global $wpdb;
3802
3803
		// Bail if posts is an empty array. Continue if posts is an empty string,
3804
		// null, or false to accommodate caching plugins that fill posts later.
3805
		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...
3806
			return;
3807
3808
		if ( ! empty( $limits ) ) {
3809
			/**
3810
			 * Filter the query to run for retrieving the found posts.
3811
			 *
3812
			 * @since 2.1.0
3813
			 *
3814
			 * @param string   $found_posts The query to run to find the found posts.
3815
			 * @param WP_Query &$this       The WP_Query instance (passed by reference).
3816
			 */
3817
			$this->found_posts = $wpdb->get_var( apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ) );
3818
		} else {
3819
			$this->found_posts = count( $this->posts );
3820
		}
3821
3822
		/**
3823
		 * Filter the number of found posts for the query.
3824
		 *
3825
		 * @since 2.1.0
3826
		 *
3827
		 * @param int      $found_posts The number of posts found.
3828
		 * @param WP_Query &$this       The WP_Query instance (passed by reference).
3829
		 */
3830
		$this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
3831
3832
		if ( ! empty( $limits ) )
3833
			$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...
3834
	}
3835
3836
	/**
3837
	 * Set up the next post and iterate current post index.
3838
	 *
3839
	 * @since 1.5.0
3840
	 * @access public
3841
	 *
3842
	 * @return WP_Post Next post.
3843
	 */
3844
	public function next_post() {
3845
3846
		$this->current_post++;
3847
3848
		$this->post = $this->posts[$this->current_post];
3849
		return $this->post;
3850
	}
3851
3852
	/**
3853
	 * Sets up the current post.
3854
	 *
3855
	 * Retrieves the next post, sets up the post, sets the 'in the loop'
3856
	 * property to true.
3857
	 *
3858
	 * @since 1.5.0
3859
	 * @access public
3860
	 *
3861
	 * @global WP_Post $post
3862
	 */
3863
	public function the_post() {
3864
		global $post;
3865
		$this->in_the_loop = true;
3866
3867
		if ( $this->current_post == -1 ) // loop has just started
3868
			/**
3869
			 * Fires once the loop is started.
3870
			 *
3871
			 * @since 2.0.0
3872
			 *
3873
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3874
			 */
3875
			do_action_ref_array( 'loop_start', array( &$this ) );
3876
3877
		$post = $this->next_post();
3878
		$this->setup_postdata( $post );
3879
	}
3880
3881
	/**
3882
	 * Whether there are more posts available in the loop.
3883
	 *
3884
	 * Calls action 'loop_end', when the loop is complete.
3885
	 *
3886
	 * @since 1.5.0
3887
	 * @access public
3888
	 *
3889
	 * @return bool True if posts are available, false if end of loop.
3890
	 */
3891
	public function have_posts() {
3892
		if ( $this->current_post + 1 < $this->post_count ) {
3893
			return true;
3894
		} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
3895
			/**
3896
			 * Fires once the loop has ended.
3897
			 *
3898
			 * @since 2.0.0
3899
			 *
3900
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
3901
			 */
3902
			do_action_ref_array( 'loop_end', array( &$this ) );
3903
			// Do some cleaning up after the loop
3904
			$this->rewind_posts();
3905
		}
3906
3907
		$this->in_the_loop = false;
3908
		return false;
3909
	}
3910
3911
	/**
3912
	 * Rewind the posts and reset post index.
3913
	 *
3914
	 * @since 1.5.0
3915
	 * @access public
3916
	 */
3917
	public function rewind_posts() {
3918
		$this->current_post = -1;
3919
		if ( $this->post_count > 0 ) {
3920
			$this->post = $this->posts[0];
3921
		}
3922
	}
3923
3924
	/**
3925
	 * Iterate current comment index and return WP_Comment object.
3926
	 *
3927
	 * @since 2.2.0
3928
	 * @access public
3929
	 *
3930
	 * @return WP_Comment Comment object.
3931
	 */
3932
	public function next_comment() {
3933
		$this->current_comment++;
3934
3935
		$this->comment = $this->comments[$this->current_comment];
3936
		return $this->comment;
3937
	}
3938
3939
	/**
3940
	 * Sets up the current comment.
3941
	 *
3942
	 * @since 2.2.0
3943
	 * @access public
3944
	 * @global WP_Comment $comment Current comment.
3945
	 */
3946
	public function the_comment() {
3947
		global $comment;
3948
3949
		$comment = $this->next_comment();
3950
3951
		if ( $this->current_comment == 0 ) {
3952
			/**
3953
			 * Fires once the comment loop is started.
3954
			 *
3955
			 * @since 2.2.0
3956
			 */
3957
			do_action( 'comment_loop_start' );
3958
		}
3959
	}
3960
3961
	/**
3962
	 * Whether there are more comments available.
3963
	 *
3964
	 * Automatically rewinds comments when finished.
3965
	 *
3966
	 * @since 2.2.0
3967
	 * @access public
3968
	 *
3969
	 * @return bool True, if more comments. False, if no more posts.
3970
	 */
3971
	public function have_comments() {
3972
		if ( $this->current_comment + 1 < $this->comment_count ) {
3973
			return true;
3974
		} elseif ( $this->current_comment + 1 == $this->comment_count ) {
3975
			$this->rewind_comments();
3976
		}
3977
3978
		return false;
3979
	}
3980
3981
	/**
3982
	 * Rewind the comments, resets the comment index and comment to first.
3983
	 *
3984
	 * @since 2.2.0
3985
	 * @access public
3986
	 */
3987
	public function rewind_comments() {
3988
		$this->current_comment = -1;
3989
		if ( $this->comment_count > 0 ) {
3990
			$this->comment = $this->comments[0];
3991
		}
3992
	}
3993
3994
	/**
3995
	 * Sets up the WordPress query by parsing query string.
3996
	 *
3997
	 * @since 1.5.0
3998
	 * @access public
3999
	 *
4000
	 * @param string $query URL query string.
4001
	 * @return array List of posts.
4002
	 */
4003
	public function query( $query ) {
4004
		$this->init();
4005
		$this->query = $this->query_vars = wp_parse_args( $query );
4006
		return $this->get_posts();
4007
	}
4008
4009
	/**
4010
	 * Retrieve queried object.
4011
	 *
4012
	 * If queried object is not set, then the queried object will be set from
4013
	 * the category, tag, taxonomy, posts page, single post, page, or author
4014
	 * query variable. After it is set up, it will be returned.
4015
	 *
4016
	 * @since 1.5.0
4017
	 * @access public
4018
	 *
4019
	 * @return object
4020
	 */
4021
	public function get_queried_object() {
4022
		if ( isset($this->queried_object) )
4023
			return $this->queried_object;
4024
4025
		$this->queried_object = null;
4026
		$this->queried_object_id = null;
4027
4028
		if ( $this->is_category || $this->is_tag || $this->is_tax ) {
4029
			if ( $this->is_category ) {
4030
				if ( $this->get( 'cat' ) ) {
4031
					$term = get_term( $this->get( 'cat' ), 'category' );
4032
				} elseif ( $this->get( 'category_name' ) ) {
4033
					$term = get_term_by( 'slug', $this->get( 'category_name' ), 'category' );
4034
				}
4035
			} elseif ( $this->is_tag ) {
4036
				if ( $this->get( 'tag_id' ) ) {
4037
					$term = get_term( $this->get( 'tag_id' ), 'post_tag' );
4038
				} elseif ( $this->get( 'tag' ) ) {
4039
					$term = get_term_by( 'slug', $this->get( 'tag' ), 'post_tag' );
4040
				}
4041
			} else {
4042
				// For other tax queries, grab the first term from the first clause.
4043
				$tax_query_in_and = wp_list_filter( $this->tax_query->queried_terms, array( 'operator' => 'NOT IN' ), 'NOT' );
4044
4045
				if ( ! empty( $tax_query_in_and ) ) {
4046
					$queried_taxonomies = array_keys( $tax_query_in_and );
4047
					$matched_taxonomy = reset( $queried_taxonomies );
4048
					$query = $tax_query_in_and[ $matched_taxonomy ];
4049
4050
					if ( $query['terms'] ) {
4051
						if ( 'term_id' == $query['field'] ) {
4052
							$term = get_term( reset( $query['terms'] ), $matched_taxonomy );
4053
						} else {
4054
							$term = get_term_by( $query['field'], reset( $query['terms'] ), $matched_taxonomy );
4055
						}
4056
					}
4057
				}
4058
			}
4059
4060
			if ( ! empty( $term ) && ! is_wp_error( $term ) )  {
4061
				$this->queried_object = $term;
4062
				$this->queried_object_id = (int) $term->term_id;
4063
4064
				if ( $this->is_category && 'category' === $this->queried_object->taxonomy )
4065
					_make_cat_compat( $this->queried_object );
4066
			}
4067
		} elseif ( $this->is_post_type_archive ) {
4068
			$post_type = $this->get( 'post_type' );
4069
			if ( is_array( $post_type ) )
4070
				$post_type = reset( $post_type );
4071
			$this->queried_object = get_post_type_object( $post_type );
4072
		} elseif ( $this->is_posts_page ) {
4073
			$page_for_posts = get_option('page_for_posts');
4074
			$this->queried_object = get_post( $page_for_posts );
4075
			$this->queried_object_id = (int) $this->queried_object->ID;
4076
		} elseif ( $this->is_singular && ! empty( $this->post ) ) {
4077
			$this->queried_object = $this->post;
4078
			$this->queried_object_id = (int) $this->post->ID;
4079
		} elseif ( $this->is_author ) {
4080
			$this->queried_object_id = (int) $this->get('author');
4081
			$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...
4082
		}
4083
4084
		return $this->queried_object;
4085
	}
4086
4087
	/**
4088
	 * Retrieve ID of the current queried object.
4089
	 *
4090
	 * @since 1.5.0
4091
	 * @access public
4092
	 *
4093
	 * @return int
4094
	 */
4095
	public function get_queried_object_id() {
4096
		$this->get_queried_object();
4097
4098
		if ( isset($this->queried_object_id) ) {
4099
			return $this->queried_object_id;
4100
		}
4101
4102
		return 0;
4103
	}
4104
4105
	/**
4106
	 * Constructor.
4107
	 *
4108
	 * Sets up the WordPress query, if parameter is not empty.
4109
	 *
4110
	 * @since 1.5.0
4111
	 * @access public
4112
	 *
4113
	 * @param string|array $query URL query string or array of vars.
4114
	 */
4115
	public function __construct($query = '') {
4116
		if ( ! empty($query) ) {
4117
			$this->query($query);
0 ignored issues
show
Bug introduced by
It seems like $query defined by parameter $query on line 4115 can also be of type array; however, WP_Query::query() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
4118
		}
4119
	}
4120
4121
	/**
4122
	 * Make private properties readable for backwards compatibility.
4123
	 *
4124
	 * @since 4.0.0
4125
	 * @access public
4126
	 *
4127
	 * @param string $name Property to get.
4128
	 * @return mixed Property.
4129
	 */
4130
	public function __get( $name ) {
4131
		if ( in_array( $name, $this->compat_fields ) ) {
4132
			return $this->$name;
4133
		}
4134
	}
4135
4136
	/**
4137
	 * Make private properties checkable for backwards compatibility.
4138
	 *
4139
	 * @since 4.0.0
4140
	 * @access public
4141
	 *
4142
	 * @param string $name Property to check if set.
4143
	 * @return bool Whether the property is set.
4144
	 */
4145
	public function __isset( $name ) {
4146
		if ( in_array( $name, $this->compat_fields ) ) {
4147
			return isset( $this->$name );
4148
		}
4149
	}
4150
4151
	/**
4152
	 * Make private/protected methods readable for backwards compatibility.
4153
	 *
4154
	 * @since 4.0.0
4155
	 * @access public
4156
	 *
4157
	 * @param callable $name      Method to call.
4158
	 * @param array    $arguments Arguments to pass when calling.
4159
	 * @return mixed|false Return value of the callback, false otherwise.
4160
	 */
4161
	public function __call( $name, $arguments ) {
4162
		if ( in_array( $name, $this->compat_methods ) ) {
4163
			return call_user_func_array( array( $this, $name ), $arguments );
4164
		}
4165
		return false;
4166
	}
4167
4168
	/**
4169
 	 * Is the query for an existing archive page?
4170
 	 *
4171
 	 * Month, Year, Category, Author, Post Type archive...
4172
	 *
4173
 	 * @since 3.1.0
4174
 	 *
4175
 	 * @return bool
4176
 	 */
4177
	public function is_archive() {
4178
		return (bool) $this->is_archive;
4179
	}
4180
4181
	/**
4182
	 * Is the query for an existing post type archive page?
4183
	 *
4184
	 * @since 3.1.0
4185
	 *
4186
	 * @param mixed $post_types Optional. Post type or array of posts types to check against.
4187
	 * @return bool
4188
	 */
4189
	public function is_post_type_archive( $post_types = '' ) {
4190
		if ( empty( $post_types ) || ! $this->is_post_type_archive )
4191
			return (bool) $this->is_post_type_archive;
4192
4193
		$post_type = $this->get( 'post_type' );
4194
		if ( is_array( $post_type ) )
4195
			$post_type = reset( $post_type );
4196
		$post_type_object = get_post_type_object( $post_type );
4197
4198
		return in_array( $post_type_object->name, (array) $post_types );
4199
	}
4200
4201
	/**
4202
	 * Is the query for an existing attachment page?
4203
	 *
4204
	 * @since 3.1.0
4205
	 *
4206
	 * @param mixed $attachment Attachment ID, title, slug, or array of such.
4207
	 * @return bool
4208
	 */
4209 View Code Duplication
	public function is_attachment( $attachment = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4210
		if ( ! $this->is_attachment ) {
4211
			return false;
4212
		}
4213
4214
		if ( empty( $attachment ) ) {
4215
			return true;
4216
		}
4217
4218
		$attachment = array_map( 'strval', (array) $attachment );
4219
4220
		$post_obj = $this->get_queried_object();
4221
4222
		if ( in_array( (string) $post_obj->ID, $attachment ) ) {
4223
			return true;
4224
		} elseif ( in_array( $post_obj->post_title, $attachment ) ) {
4225
			return true;
4226
		} elseif ( in_array( $post_obj->post_name, $attachment ) ) {
4227
			return true;
4228
		}
4229
		return false;
4230
	}
4231
4232
	/**
4233
	 * Is the query for an existing author archive page?
4234
	 *
4235
	 * If the $author parameter is specified, this function will additionally
4236
	 * check if the query is for one of the authors specified.
4237
	 *
4238
	 * @since 3.1.0
4239
	 *
4240
	 * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
4241
	 * @return bool
4242
	 */
4243 View Code Duplication
	public function is_author( $author = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4244
		if ( !$this->is_author )
4245
			return false;
4246
4247
		if ( empty($author) )
4248
			return true;
4249
4250
		$author_obj = $this->get_queried_object();
4251
4252
		$author = array_map( 'strval', (array) $author );
4253
4254
		if ( in_array( (string) $author_obj->ID, $author ) )
4255
			return true;
4256
		elseif ( in_array( $author_obj->nickname, $author ) )
4257
			return true;
4258
		elseif ( in_array( $author_obj->user_nicename, $author ) )
4259
			return true;
4260
4261
		return false;
4262
	}
4263
4264
	/**
4265
	 * Is the query for an existing category archive page?
4266
	 *
4267
	 * If the $category parameter is specified, this function will additionally
4268
	 * check if the query is for one of the categories specified.
4269
	 *
4270
	 * @since 3.1.0
4271
	 *
4272
	 * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
4273
	 * @return bool
4274
	 */
4275 View Code Duplication
	public function is_category( $category = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4276
		if ( !$this->is_category )
4277
			return false;
4278
4279
		if ( empty($category) )
4280
			return true;
4281
4282
		$cat_obj = $this->get_queried_object();
4283
4284
		$category = array_map( 'strval', (array) $category );
4285
4286
		if ( in_array( (string) $cat_obj->term_id, $category ) )
4287
			return true;
4288
		elseif ( in_array( $cat_obj->name, $category ) )
4289
			return true;
4290
		elseif ( in_array( $cat_obj->slug, $category ) )
4291
			return true;
4292
4293
		return false;
4294
	}
4295
4296
	/**
4297
	 * Is the query for an existing tag archive page?
4298
	 *
4299
	 * If the $tag parameter is specified, this function will additionally
4300
	 * check if the query is for one of the tags specified.
4301
	 *
4302
	 * @since 3.1.0
4303
	 *
4304
	 * @param mixed $tag Optional. Tag ID, name, slug, or array of Tag IDs, names, and slugs.
4305
	 * @return bool
4306
	 */
4307 View Code Duplication
	public function is_tag( $tag = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4308
		if ( ! $this->is_tag )
4309
			return false;
4310
4311
		if ( empty( $tag ) )
4312
			return true;
4313
4314
		$tag_obj = $this->get_queried_object();
4315
4316
		$tag = array_map( 'strval', (array) $tag );
4317
4318
		if ( in_array( (string) $tag_obj->term_id, $tag ) )
4319
			return true;
4320
		elseif ( in_array( $tag_obj->name, $tag ) )
4321
			return true;
4322
		elseif ( in_array( $tag_obj->slug, $tag ) )
4323
			return true;
4324
4325
		return false;
4326
	}
4327
4328
	/**
4329
	 * Is the query for an existing taxonomy archive page?
4330
	 *
4331
	 * If the $taxonomy parameter is specified, this function will additionally
4332
	 * check if the query is for that specific $taxonomy.
4333
	 *
4334
	 * If the $term parameter is specified in addition to the $taxonomy parameter,
4335
	 * this function will additionally check if the query is for one of the terms
4336
	 * specified.
4337
	 *
4338
	 * @since 3.1.0
4339
	 *
4340
	 * @global array $wp_taxonomies
4341
	 *
4342
	 * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
4343
	 * @param mixed $term     Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
4344
	 * @return bool
4345
	 */
4346
	public function is_tax( $taxonomy = '', $term = '' ) {
4347
		global $wp_taxonomies;
4348
4349
		if ( !$this->is_tax )
4350
			return false;
4351
4352
		if ( empty( $taxonomy ) )
4353
			return true;
4354
4355
		$queried_object = $this->get_queried_object();
4356
		$tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
4357
		$term_array = (array) $term;
4358
4359
		// Check that the taxonomy matches.
4360
		if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
4361
			return false;
4362
4363
		// Only a Taxonomy provided.
4364
		if ( empty( $term ) )
4365
			return true;
4366
4367
		return isset( $queried_object->term_id ) &&
4368
			count( array_intersect(
4369
				array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
4370
				$term_array
4371
			) );
4372
	}
4373
4374
	/**
4375
	 * Whether the current URL is within the comments popup window.
4376
	 *
4377
	 * @since 3.1.0
4378
	 * @deprecated 4.5.0
4379
	 *
4380
	 * @return bool
4381
	 */
4382
	public function is_comments_popup() {
4383
		_deprecated_function( __FUNCTION__, '4.5' );
4384
4385
		return false;
4386
	}
4387
4388
	/**
4389
	 * Is the query for an existing date archive?
4390
	 *
4391
	 * @since 3.1.0
4392
	 *
4393
	 * @return bool
4394
	 */
4395
	public function is_date() {
4396
		return (bool) $this->is_date;
4397
	}
4398
4399
	/**
4400
	 * Is the query for an existing day archive?
4401
	 *
4402
	 * @since 3.1.0
4403
	 *
4404
	 * @return bool
4405
	 */
4406
	public function is_day() {
4407
		return (bool) $this->is_day;
4408
	}
4409
4410
	/**
4411
	 * Is the query for a feed?
4412
	 *
4413
	 * @since 3.1.0
4414
	 *
4415
	 * @param string|array $feeds Optional feed types to check.
4416
	 * @return bool
4417
	 */
4418
	public function is_feed( $feeds = '' ) {
4419
		if ( empty( $feeds ) || ! $this->is_feed )
4420
			return (bool) $this->is_feed;
4421
		$qv = $this->get( 'feed' );
4422
		if ( 'feed' == $qv )
4423
			$qv = get_default_feed();
4424
		return in_array( $qv, (array) $feeds );
4425
	}
4426
4427
	/**
4428
	 * Is the query for a comments feed?
4429
	 *
4430
	 * @since 3.1.0
4431
	 *
4432
	 * @return bool
4433
	 */
4434
	public function is_comment_feed() {
4435
		return (bool) $this->is_comment_feed;
4436
	}
4437
4438
	/**
4439
	 * Is the query for the front page of the site?
4440
	 *
4441
	 * This is for what is displayed at your site's main URL.
4442
	 *
4443
	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
4444
	 *
4445
	 * If you set a static page for the front page of your site, this function will return
4446
	 * true when viewing that page.
4447
	 *
4448
	 * Otherwise the same as @see WP_Query::is_home()
4449
	 *
4450
	 * @since 3.1.0
4451
	 *
4452
	 * @return bool True, if front of site.
4453
	 */
4454
	public function is_front_page() {
4455
		// most likely case
4456
		if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
4457
			return true;
4458
		elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
4459
			return true;
4460
		else
4461
			return false;
4462
	}
4463
4464
	/**
4465
	 * Is the query for the blog homepage?
4466
	 *
4467
	 * This is the page which shows the time based blog content of your site.
4468
	 *
4469
	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
4470
	 *
4471
	 * If you set a static page for the front page of your site, this function will return
4472
	 * true only on the page you set as the "Posts page".
4473
	 *
4474
	 * @see WP_Query::is_front_page()
4475
	 *
4476
	 * @since 3.1.0
4477
	 *
4478
	 * @return bool True if blog view homepage.
4479
	 */
4480
	public function is_home() {
4481
		return (bool) $this->is_home;
4482
	}
4483
4484
	/**
4485
	 * Is the query for an existing month archive?
4486
	 *
4487
	 * @since 3.1.0
4488
	 *
4489
	 * @return bool
4490
	 */
4491
	public function is_month() {
4492
		return (bool) $this->is_month;
4493
	}
4494
4495
	/**
4496
	 * Is the query for an existing single page?
4497
	 *
4498
	 * If the $page parameter is specified, this function will additionally
4499
	 * check if the query is for one of the pages specified.
4500
	 *
4501
	 * @see WP_Query::is_single()
4502
	 * @see WP_Query::is_singular()
4503
	 *
4504
	 * @since 3.1.0
4505
	 *
4506
	 * @param int|string|array $page Optional. Page ID, title, slug, path, or array of such. Default empty.
4507
	 * @return bool Whether the query is for an existing single page.
4508
	 */
4509 View Code Duplication
	public function is_page( $page = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4510
		if ( !$this->is_page )
4511
			return false;
4512
4513
		if ( empty( $page ) )
4514
			return true;
4515
4516
		$page_obj = $this->get_queried_object();
4517
4518
		$page = array_map( 'strval', (array) $page );
4519
4520
		if ( in_array( (string) $page_obj->ID, $page ) ) {
4521
			return true;
4522
		} elseif ( in_array( $page_obj->post_title, $page ) ) {
4523
			return true;
4524
		} elseif ( in_array( $page_obj->post_name, $page ) ) {
4525
			return true;
4526
		} else {
4527
			foreach ( $page as $pagepath ) {
4528
				if ( ! strpos( $pagepath, '/' ) ) {
4529
					continue;
4530
				}
4531
				$pagepath_obj = get_page_by_path( $pagepath );
4532
4533
				if ( $pagepath_obj && ( $pagepath_obj->ID == $page_obj->ID ) ) {
4534
					return true;
4535
				}
4536
			}
4537
		}
4538
4539
		return false;
4540
	}
4541
4542
	/**
4543
	 * Is the query for paged result and not for the first page?
4544
	 *
4545
	 * @since 3.1.0
4546
	 *
4547
	 * @return bool
4548
	 */
4549
	public function is_paged() {
4550
		return (bool) $this->is_paged;
4551
	}
4552
4553
	/**
4554
	 * Is the query for a post or page preview?
4555
	 *
4556
	 * @since 3.1.0
4557
	 *
4558
	 * @return bool
4559
	 */
4560
	public function is_preview() {
4561
		return (bool) $this->is_preview;
4562
	}
4563
4564
	/**
4565
	 * Is the query for the robots file?
4566
	 *
4567
	 * @since 3.1.0
4568
	 *
4569
	 * @return bool
4570
	 */
4571
	public function is_robots() {
4572
		return (bool) $this->is_robots;
4573
	}
4574
4575
	/**
4576
	 * Is the query for a search?
4577
	 *
4578
	 * @since 3.1.0
4579
	 *
4580
	 * @return bool
4581
	 */
4582
	public function is_search() {
4583
		return (bool) $this->is_search;
4584
	}
4585
4586
	/**
4587
	 * Is the query for an existing single post?
4588
	 *
4589
	 * Works for any post type, except attachments and pages
4590
	 *
4591
	 * If the $post parameter is specified, this function will additionally
4592
	 * check if the query is for one of the Posts specified.
4593
	 *
4594
	 * @see WP_Query::is_page()
4595
	 * @see WP_Query::is_singular()
4596
	 *
4597
	 * @since 3.1.0
4598
	 *
4599
	 * @param int|string|array $post Optional. Post ID, title, slug, path, or array of such. Default empty.
4600
	 * @return bool Whether the query is for an existing single post.
4601
	 */
4602 View Code Duplication
	public function is_single( $post = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4603
		if ( !$this->is_single )
4604
			return false;
4605
4606
		if ( empty($post) )
4607
			return true;
4608
4609
		$post_obj = $this->get_queried_object();
4610
4611
		$post = array_map( 'strval', (array) $post );
4612
4613
		if ( in_array( (string) $post_obj->ID, $post ) ) {
4614
			return true;
4615
		} elseif ( in_array( $post_obj->post_title, $post ) ) {
4616
			return true;
4617
		} elseif ( in_array( $post_obj->post_name, $post ) ) {
4618
			return true;
4619
		} else {
4620
			foreach ( $post as $postpath ) {
4621
				if ( ! strpos( $postpath, '/' ) ) {
4622
					continue;
4623
				}
4624
				$postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );
4625
4626
				if ( $postpath_obj && ( $postpath_obj->ID == $post_obj->ID ) ) {
4627
					return true;
4628
				}
4629
			}
4630
		}
4631
		return false;
4632
	}
4633
4634
	/**
4635
	 * Is the query for an existing single post of any post type (post, attachment, page, ... )?
4636
	 *
4637
	 * If the $post_types parameter is specified, this function will additionally
4638
	 * check if the query is for one of the Posts Types specified.
4639
	 *
4640
	 * @see WP_Query::is_page()
4641
	 * @see WP_Query::is_single()
4642
	 *
4643
	 * @since 3.1.0
4644
	 *
4645
	 * @param string|array $post_types Optional. Post type or array of post types. Default empty.
4646
	 * @return bool Whether the query is for an existing single post of any of the given post types.
4647
	 */
4648
	public function is_singular( $post_types = '' ) {
4649
		if ( empty( $post_types ) || !$this->is_singular )
4650
			return (bool) $this->is_singular;
4651
4652
		$post_obj = $this->get_queried_object();
4653
4654
		return in_array( $post_obj->post_type, (array) $post_types );
4655
	}
4656
4657
	/**
4658
	 * Is the query for a specific time?
4659
	 *
4660
	 * @since 3.1.0
4661
	 *
4662
	 * @return bool
4663
	 */
4664
	public function is_time() {
4665
		return (bool) $this->is_time;
4666
	}
4667
4668
	/**
4669
	 * Is the query for a trackback endpoint call?
4670
	 *
4671
	 * @since 3.1.0
4672
	 *
4673
	 * @return bool
4674
	 */
4675
	public function is_trackback() {
4676
		return (bool) $this->is_trackback;
4677
	}
4678
4679
	/**
4680
	 * Is the query for an existing year archive?
4681
	 *
4682
	 * @since 3.1.0
4683
	 *
4684
	 * @return bool
4685
	 */
4686
	public function is_year() {
4687
		return (bool) $this->is_year;
4688
	}
4689
4690
	/**
4691
	 * Is the query a 404 (returns no results)?
4692
	 *
4693
	 * @since 3.1.0
4694
	 *
4695
	 * @return bool
4696
	 */
4697
	public function is_404() {
4698
		return (bool) $this->is_404;
4699
	}
4700
4701
	/**
4702
	 * Is the query for an embedded post?
4703
	 *
4704
	 * @since 4.4.0
4705
	 *
4706
	 * @return bool
4707
	 */
4708
	public function is_embed() {
4709
		return (bool) $this->is_embed;
4710
	}
4711
4712
	/**
4713
	 * Is the query the main query?
4714
	 *
4715
	 * @since 3.3.0
4716
	 *
4717
	 * @global WP_Query $wp_query Global WP_Query instance.
4718
	 *
4719
	 * @return bool
4720
	 */
4721
	public function is_main_query() {
4722
		global $wp_the_query;
4723
		return $wp_the_query === $this;
4724
	}
4725
4726
	/**
4727
	 * Set up global post data.
4728
	 *
4729
	 * @since 4.1.0
4730
	 * @since 4.4.0 Added the ability to pass a post ID to `$post`.
4731
	 *
4732
	 * @global int             $id
4733
	 * @global WP_User         $authordata
4734
	 * @global string|int|bool $currentday
4735
	 * @global string|int|bool $currentmonth
4736
	 * @global int             $page
4737
	 * @global array           $pages
4738
	 * @global int             $multipage
4739
	 * @global int             $more
4740
	 * @global int             $numpages
4741
	 *
4742
	 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
4743
	 * @return true True when finished.
4744
	 */
4745
	public function setup_postdata( $post ) {
4746
		global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;
4747
4748
		if ( ! ( $post instanceof WP_Post ) ) {
4749
			$post = get_post( $post );
0 ignored issues
show
Bug introduced by
It seems like $post defined by get_post($post) on line 4749 can also be of type object; however, get_post() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
4750
		}
4751
4752
		if ( ! $post ) {
4753
			return;
4754
		}
4755
4756
		$id = (int) $post->ID;
4757
4758
		$authordata = get_userdata($post->post_author);
4759
4760
		$currentday = mysql2date('d.m.y', $post->post_date, false);
4761
		$currentmonth = mysql2date('m', $post->post_date, false);
4762
		$numpages = 1;
4763
		$multipage = 0;
4764
		$page = $this->get( 'page' );
4765
		if ( ! $page )
4766
			$page = 1;
4767
4768
		/*
4769
		 * Force full post content when viewing the permalink for the $post,
4770
		 * or when on an RSS feed. Otherwise respect the 'more' tag.
4771
		 */
4772
		if ( $post->ID === get_queried_object_id() && ( $this->is_page() || $this->is_single() ) ) {
4773
			$more = 1;
4774
		} elseif ( $this->is_feed() ) {
4775
			$more = 1;
4776
		} else {
4777
			$more = 0;
4778
		}
4779
4780
		$content = $post->post_content;
4781
		if ( false !== strpos( $content, '<!--nextpage-->' ) ) {
4782
			$content = str_replace( "\n<!--nextpage-->\n", '<!--nextpage-->', $content );
4783
			$content = str_replace( "\n<!--nextpage-->", '<!--nextpage-->', $content );
4784
			$content = str_replace( "<!--nextpage-->\n", '<!--nextpage-->', $content );
4785
4786
			// Ignore nextpage at the beginning of the content.
4787
			if ( 0 === strpos( $content, '<!--nextpage-->' ) )
4788
				$content = substr( $content, 15 );
4789
4790
			$pages = explode('<!--nextpage-->', $content);
4791
		} else {
4792
			$pages = array( $post->post_content );
4793
		}
4794
4795
		/**
4796
		 * Filter the "pages" derived from splitting the post content.
4797
		 *
4798
		 * "Pages" are determined by splitting the post content based on the presence
4799
		 * of `<!-- nextpage -->` tags.
4800
		 *
4801
		 * @since 4.4.0
4802
		 *
4803
		 * @param array   $pages Array of "pages" derived from the post content.
4804
		 *                       of `<!-- nextpage -->` tags..
4805
		 * @param WP_Post $post  Current post object.
4806
		 */
4807
		$pages = apply_filters( 'content_pagination', $pages, $post );
4808
4809
		$numpages = count( $pages );
4810
4811
		if ( $numpages > 1 ) {
4812
			if ( $page > 1 ) {
4813
				$more = 1;
4814
			}
4815
			$multipage = 1;
4816
		} else {
4817
	 		$multipage = 0;
4818
	 	}
4819
4820
		/**
4821
		 * Fires once the post data has been setup.
4822
		 *
4823
		 * @since 2.8.0
4824
		 * @since 4.1.0 Introduced `$this` parameter.
4825
		 *
4826
		 * @param WP_Post  &$post The Post object (passed by reference).
4827
		 * @param WP_Query &$this The current Query object (passed by reference).
4828
		 */
4829
		do_action_ref_array( 'the_post', array( &$post, &$this ) );
4830
4831
		return true;
4832
	}
4833
	/**
4834
	 * After looping through a nested query, this function
4835
	 * restores the $post global to the current post in this query.
4836
	 *
4837
	 * @since 3.7.0
4838
	 *
4839
	 * @global WP_Post $post
4840
	 */
4841
	public function reset_postdata() {
4842
		if ( ! empty( $this->post ) ) {
4843
			$GLOBALS['post'] = $this->post;
4844
			$this->setup_postdata( $this->post );
4845
		}
4846
	}
4847
4848
	/**
4849
	 * Lazyload term meta for posts in the loop.
4850
	 *
4851
	 * @since 4.4.0
4852
	 * @deprecated 4.5.0 See wp_queue_posts_for_term_meta_lazyload().
4853
	 *
4854
	 * @param mixed $check
4855
	 * @param int   $term_id
4856
	 * @return mixed
4857
	 */
4858
	public function lazyload_term_meta( $check, $term_id ) {
0 ignored issues
show
Unused Code introduced by
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...
4859
		_deprecated_function( __METHOD__, '4.5.0' );
4860
		return $check;
4861
	}
4862
4863
	/**
4864
	 * Lazyload comment meta for comments in the loop.
4865
	 *
4866
	 * @since 4.4.0
4867
	 * @deprecated 4.5.0 See wp_queue_comments_for_comment_meta_lazyload().
4868
	 *
4869
	 * @param mixed $check
4870
	 * @param int   $comment_id
4871
	 * @return mixed
4872
	 */
4873
	public function lazyload_comment_meta( $check, $comment_id ) {
0 ignored issues
show
Unused Code introduced by
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...
4874
		_deprecated_function( __METHOD__, '4.5.0' );
4875
		return $check;
4876
	}
4877
}
4878
4879
/**
4880
 * Redirect old slugs to the correct permalink.
4881
 *
4882
 * Attempts to find the current slug from the past slugs.
4883
 *
4884
 * @since 2.1.0
4885
 *
4886
 * @global WP_Query   $wp_query   Global WP_Query instance.
4887
 * @global wpdb       $wpdb       WordPress database abstraction object.
4888
 * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
4889
 */
4890
function wp_old_slug_redirect() {
4891
	global $wp_query, $wp_rewrite;
4892
4893
	if ( get_queried_object() ) {
4894
		return;
4895
	}
4896
4897
	if ( '' !== $wp_query->query_vars['name'] ) :
4898
		global $wpdb;
4899
4900
		// Guess the current post_type based on the query vars.
4901
		if ( get_query_var( 'post_type' ) ) {
4902
			$post_type = get_query_var( 'post_type' );
4903
		} elseif ( get_query_var( 'attachment' ) ) {
4904
			$post_type = 'attachment';
4905
		} elseif ( ! empty( $wp_query->query_vars['pagename'] ) ) {
4906
			$post_type = 'page';
4907
		} else {
4908
			$post_type = 'post';
4909
		}
4910
4911
		if ( is_array( $post_type ) ) {
4912
			if ( count( $post_type ) > 1 )
4913
				return;
4914
			$post_type = reset( $post_type );
4915
		}
4916
4917
		// Do not attempt redirect for hierarchical post types
4918
		if ( is_post_type_hierarchical( $post_type ) )
4919
			return;
4920
4921
		$query = $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, $wp_query->query_vars['name']);
4922
4923
		// if year, monthnum, or day have been specified, make our query more precise
4924
		// just in case there are multiple identical _wp_old_slug values
4925 View Code Duplication
		if ( '' != $wp_query->query_vars['year'] )
4926
			$query .= $wpdb->prepare(" AND YEAR(post_date) = %d", $wp_query->query_vars['year']);
4927 View Code Duplication
		if ( '' != $wp_query->query_vars['monthnum'] )
4928
			$query .= $wpdb->prepare(" AND MONTH(post_date) = %d", $wp_query->query_vars['monthnum']);
4929 View Code Duplication
		if ( '' != $wp_query->query_vars['day'] )
4930
			$query .= $wpdb->prepare(" AND DAYOFMONTH(post_date) = %d", $wp_query->query_vars['day']);
4931
4932
		$id = (int) $wpdb->get_var($query);
4933
4934
		if ( ! $id )
4935
			return;
4936
4937
		$link = get_permalink( $id );
4938
4939
		if ( is_feed() ) {
4940
			$link = user_trailingslashit( trailingslashit( $link ) . 'feed' );
0 ignored issues
show
Security Bug introduced by
It seems like $link can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
4941
		} elseif ( isset( $GLOBALS['wp_query']->query_vars['paged'] ) && $GLOBALS['wp_query']->query_vars['paged'] > 1 ) {
4942
			$link = user_trailingslashit( trailingslashit( $link ) . 'page/' . $GLOBALS['wp_query']->query_vars['paged'] );
0 ignored issues
show
Security Bug introduced by
It seems like $link can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
4943
		} elseif( is_embed() ) {
4944
			$link = user_trailingslashit( trailingslashit( $link ) . 'embed' );
0 ignored issues
show
Security Bug introduced by
It seems like $link can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
4945
		} elseif ( is_404() ) {
4946
			// Add rewrite endpoints if necessary.
4947
			foreach ( $wp_rewrite->endpoints as $endpoint ) {
4948
				if ( $endpoint[2] && false !== get_query_var( $endpoint[2], false ) ) {
4949
					$link = user_trailingslashit( trailingslashit( $link ) . $endpoint[1] );
0 ignored issues
show
Security Bug introduced by
It seems like $link can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
4950
				}
4951
			}
4952
		}
4953
4954
		/**
4955
		 * Filter the old slug redirect URL.
4956
		 *
4957
		 * @since 4.4.0
4958
		 *
4959
		 * @param string $link The redirect URL.
4960
		 */
4961
		$link = apply_filters( 'old_slug_redirect_url', $link );
4962
4963
		if ( ! $link ) {
4964
			return;
4965
		}
4966
4967
		wp_redirect( $link, 301 ); // Permanent redirect
4968
		exit;
4969
	endif;
4970
}
4971
4972
/**
4973
 * Set up global post data.
4974
 *
4975
 * @since 1.5.0
4976
 * @since 4.4.0 Added the ability to pass a post ID to `$post`.
4977
 *
4978
 * @global WP_Query $wp_query Global WP_Query instance.
4979
 *
4980
 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
4981
 * @return bool True when finished.
4982
 */
4983
function setup_postdata( $post ) {
4984
	global $wp_query;
4985
4986
	if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) {
4987
		return $wp_query->setup_postdata( $post );
4988
	}
4989
4990
	return false;
4991
}
4992