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://developer.wordpress.org/themes/basics/the-loop/ More information on The Loop.
9 *
10 * @package WordPress
11 * @subpackage Query
12 */
13
14/**
15 * Retrieves the value of a query 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 WordPress Query object.
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 */
26function get_query_var( $var, $default = '' ) {
27	global $wp_query;
28	return $wp_query->get( $var, $default );
29}
30
31/**
32 * Retrieves the currently queried object.
33 *
34 * Wrapper for WP_Query::get_queried_object().
35 *
36 * @since 3.1.0
37 *
38 * @global WP_Query $wp_query WordPress Query object.
39 *
40 * @return WP_Term|WP_Post_Type|WP_Post|WP_User|null The queried object.
41 */
42function get_queried_object() {
43	global $wp_query;
44	return $wp_query->get_queried_object();
45}
46
47/**
48 * Retrieves the ID of the currently queried object.
49 *
50 * Wrapper for WP_Query::get_queried_object_id().
51 *
52 * @since 3.1.0
53 *
54 * @global WP_Query $wp_query WordPress Query object.
55 *
56 * @return int ID of the queried object.
57 */
58function get_queried_object_id() {
59	global $wp_query;
60	return $wp_query->get_queried_object_id();
61}
62
63/**
64 * Sets the value of a query variable in the WP_Query class.
65 *
66 * @since 2.2.0
67 *
68 * @global WP_Query $wp_query WordPress Query object.
69 *
70 * @param string $var   Query variable key.
71 * @param mixed  $value Query variable value.
72 */
73function set_query_var( $var, $value ) {
74	global $wp_query;
75	$wp_query->set( $var, $value );
76}
77
78/**
79 * Sets up The Loop with query parameters.
80 *
81 * Note: This function will completely override the main query and isn't intended for use
82 * by plugins or themes. Its overly-simplistic approach to modifying the main query can be
83 * problematic and should be avoided wherever possible. In most cases, there are better,
84 * more performant options for modifying the main query such as via the {@see 'pre_get_posts'}
85 * action within WP_Query.
86 *
87 * This must not be used within the WordPress Loop.
88 *
89 * @since 1.5.0
90 *
91 * @global WP_Query $wp_query WordPress Query object.
92 *
93 * @param array|string $query Array or string of WP_Query arguments.
94 * @return WP_Post[]|int[] Array of post objects or post IDs.
95 */
96function query_posts( $query ) {
97	$GLOBALS['wp_query'] = new WP_Query();
98	return $GLOBALS['wp_query']->query( $query );
99}
100
101/**
102 * Destroys the previous query and sets up a new query.
103 *
104 * This should be used after query_posts() and before another query_posts().
105 * This will remove obscure bugs that occur when the previous WP_Query object
106 * is not destroyed properly before another is set up.
107 *
108 * @since 2.3.0
109 *
110 * @global WP_Query $wp_query     WordPress Query object.
111 * @global WP_Query $wp_the_query Copy of the global WP_Query instance created during wp_reset_query().
112 */
113function wp_reset_query() {
114	$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
115	wp_reset_postdata();
116}
117
118/**
119 * After looping through a separate query, this function restores
120 * the $post global to the current post in the main query.
121 *
122 * @since 3.0.0
123 *
124 * @global WP_Query $wp_query WordPress Query object.
125 */
126function wp_reset_postdata() {
127	global $wp_query;
128
129	if ( isset( $wp_query ) ) {
130		$wp_query->reset_postdata();
131	}
132}
133
134/*
135 * Query type checks.
136 */
137
138/**
139 * Determines whether the query is for an existing archive page.
140 *
141 * Archive pages include category, tag, author, date, custom post type,
142 * and custom taxonomy based archives.
143 *
144 * For more information on this and similar theme functions, check out
145 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
146 * Conditional Tags} article in the Theme Developer Handbook.
147 *
148 * @since 1.5.0
149 *
150 * @see is_category()
151 * @see is_tag()
152 * @see is_author()
153 * @see is_date()
154 * @see is_post_type_archive()
155 * @see is_tax()
156 * @global WP_Query $wp_query WordPress Query object.
157 *
158 * @return bool Whether the query is for an existing archive page.
159 */
160function is_archive() {
161	global $wp_query;
162
163	if ( ! isset( $wp_query ) ) {
164		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
165		return false;
166	}
167
168	return $wp_query->is_archive();
169}
170
171/**
172 * Determines whether the query is for an existing post type archive page.
173 *
174 * For more information on this and similar theme functions, check out
175 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
176 * Conditional Tags} article in the Theme Developer Handbook.
177 *
178 * @since 3.1.0
179 *
180 * @global WP_Query $wp_query WordPress Query object.
181 *
182 * @param string|string[] $post_types Optional. Post type or array of posts types
183 *                                    to check against. Default empty.
184 * @return bool Whether the query is for an existing post type archive page.
185 */
186function is_post_type_archive( $post_types = '' ) {
187	global $wp_query;
188
189	if ( ! isset( $wp_query ) ) {
190		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
191		return false;
192	}
193
194	return $wp_query->is_post_type_archive( $post_types );
195}
196
197/**
198 * Determines whether the query is for an existing attachment page.
199 *
200 * For more information on this and similar theme functions, check out
201 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
202 * Conditional Tags} article in the Theme Developer Handbook.
203 *
204 * @since 2.0.0
205 *
206 * @global WP_Query $wp_query WordPress Query object.
207 *
208 * @param int|string|int[]|string[] $attachment Optional. Attachment ID, title, slug, or array of such
209 *                                              to check against. Default empty.
210 * @return bool Whether the query is for an existing attachment page.
211 */
212function is_attachment( $attachment = '' ) {
213	global $wp_query;
214
215	if ( ! isset( $wp_query ) ) {
216		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
217		return false;
218	}
219
220	return $wp_query->is_attachment( $attachment );
221}
222
223/**
224 * Determines whether the query is for an existing author archive page.
225 *
226 * If the $author parameter is specified, this function will additionally
227 * check if the query is for one of the authors specified.
228 *
229 * For more information on this and similar theme functions, check out
230 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
231 * Conditional Tags} article in the Theme Developer Handbook.
232 *
233 * @since 1.5.0
234 *
235 * @global WP_Query $wp_query WordPress Query object.
236 *
237 * @param int|string|int[]|string[] $author Optional. User ID, nickname, nicename, or array of such
238 *                                          to check against. Default empty.
239 * @return bool Whether the query is for an existing author archive page.
240 */
241function is_author( $author = '' ) {
242	global $wp_query;
243
244	if ( ! isset( $wp_query ) ) {
245		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
246		return false;
247	}
248
249	return $wp_query->is_author( $author );
250}
251
252/**
253 * Determines whether the query is for an existing category archive page.
254 *
255 * If the $category parameter is specified, this function will additionally
256 * check if the query is for one of the categories specified.
257 *
258 * For more information on this and similar theme functions, check out
259 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
260 * Conditional Tags} article in the Theme Developer Handbook.
261 *
262 * @since 1.5.0
263 *
264 * @global WP_Query $wp_query WordPress Query object.
265 *
266 * @param int|string|int[]|string[] $category Optional. Category ID, name, slug, or array of such
267 *                                            to check against. Default empty.
268 * @return bool Whether the query is for an existing category archive page.
269 */
270function is_category( $category = '' ) {
271	global $wp_query;
272
273	if ( ! isset( $wp_query ) ) {
274		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
275		return false;
276	}
277
278	return $wp_query->is_category( $category );
279}
280
281/**
282 * Determines whether the query is for an existing tag archive page.
283 *
284 * If the $tag parameter is specified, this function will additionally
285 * check if the query is for one of the tags specified.
286 *
287 * For more information on this and similar theme functions, check out
288 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
289 * Conditional Tags} article in the Theme Developer Handbook.
290 *
291 * @since 2.3.0
292 *
293 * @global WP_Query $wp_query WordPress Query object.
294 *
295 * @param int|string|int[]|string[] $tag Optional. Tag ID, name, slug, or array of such
296 *                                       to check against. Default empty.
297 * @return bool Whether the query is for an existing tag archive page.
298 */
299function is_tag( $tag = '' ) {
300	global $wp_query;
301
302	if ( ! isset( $wp_query ) ) {
303		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
304		return false;
305	}
306
307	return $wp_query->is_tag( $tag );
308}
309
310/**
311 * Determines whether the query is for an existing custom taxonomy archive page.
312 *
313 * If the $taxonomy parameter is specified, this function will additionally
314 * check if the query is for that specific $taxonomy.
315 *
316 * If the $term parameter is specified in addition to the $taxonomy parameter,
317 * this function will additionally check if the query is for one of the terms
318 * specified.
319 *
320 * For more information on this and similar theme functions, check out
321 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
322 * Conditional Tags} article in the Theme Developer Handbook.
323 *
324 * @since 2.5.0
325 *
326 * @global WP_Query $wp_query WordPress Query object.
327 *
328 * @param string|string[]           $taxonomy Optional. Taxonomy slug or slugs to check against.
329 *                                            Default empty.
330 * @param int|string|int[]|string[] $term     Optional. Term ID, name, slug, or array of such
331 *                                            to check against. Default empty.
332 * @return bool Whether the query is for an existing custom taxonomy archive page.
333 *              True for custom taxonomy archive pages, false for built-in taxonomies
334 *              (category and tag archives).
335 */
336function is_tax( $taxonomy = '', $term = '' ) {
337	global $wp_query;
338
339	if ( ! isset( $wp_query ) ) {
340		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
341		return false;
342	}
343
344	return $wp_query->is_tax( $taxonomy, $term );
345}
346
347/**
348 * Determines whether the query is for an existing date archive.
349 *
350 * For more information on this and similar theme functions, check out
351 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
352 * Conditional Tags} article in the Theme Developer Handbook.
353 *
354 * @since 1.5.0
355 *
356 * @global WP_Query $wp_query WordPress Query object.
357 *
358 * @return bool Whether the query is for an existing date archive.
359 */
360function is_date() {
361	global $wp_query;
362
363	if ( ! isset( $wp_query ) ) {
364		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
365		return false;
366	}
367
368	return $wp_query->is_date();
369}
370
371/**
372 * Determines whether the query is for an existing day archive.
373 *
374 * A conditional check to test whether the page is a date-based archive page displaying posts for the current day.
375 *
376 * For more information on this and similar theme functions, check out
377 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
378 * Conditional Tags} article in the Theme Developer Handbook.
379 *
380 * @since 1.5.0
381 *
382 * @global WP_Query $wp_query WordPress Query object.
383 *
384 * @return bool Whether the query is for an existing day archive.
385 */
386function is_day() {
387	global $wp_query;
388
389	if ( ! isset( $wp_query ) ) {
390		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
391		return false;
392	}
393
394	return $wp_query->is_day();
395}
396
397/**
398 * Determines whether the query is for a feed.
399 *
400 * For more information on this and similar theme functions, check out
401 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
402 * Conditional Tags} article in the Theme Developer Handbook.
403 *
404 * @since 1.5.0
405 *
406 * @global WP_Query $wp_query WordPress Query object.
407 *
408 * @param string|string[] $feeds Optional. Feed type or array of feed types
409 *                                         to check against. Default empty.
410 * @return bool Whether the query is for a feed.
411 */
412function is_feed( $feeds = '' ) {
413	global $wp_query;
414
415	if ( ! isset( $wp_query ) ) {
416		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
417		return false;
418	}
419
420	return $wp_query->is_feed( $feeds );
421}
422
423/**
424 * Is the query for a comments feed?
425 *
426 * @since 3.0.0
427 *
428 * @global WP_Query $wp_query WordPress Query object.
429 *
430 * @return bool Whether the query is for a comments feed.
431 */
432function is_comment_feed() {
433	global $wp_query;
434
435	if ( ! isset( $wp_query ) ) {
436		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
437		return false;
438	}
439
440	return $wp_query->is_comment_feed();
441}
442
443/**
444 * Determines whether the query is for the front page of the site.
445 *
446 * This is for what is displayed at your site's main URL.
447 *
448 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
449 *
450 * If you set a static page for the front page of your site, this function will return
451 * true when viewing that page.
452 *
453 * Otherwise the same as @see is_home()
454 *
455 * For more information on this and similar theme functions, check out
456 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
457 * Conditional Tags} article in the Theme Developer Handbook.
458 *
459 * @since 2.5.0
460 *
461 * @global WP_Query $wp_query WordPress Query object.
462 *
463 * @return bool Whether the query is for the front page of the site.
464 */
465function is_front_page() {
466	global $wp_query;
467
468	if ( ! isset( $wp_query ) ) {
469		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
470		return false;
471	}
472
473	return $wp_query->is_front_page();
474}
475
476/**
477 * Determines whether the query is for the blog homepage.
478 *
479 * The blog homepage is the page that shows the time-based blog content of the site.
480 *
481 * is_home() is dependent on the site's "Front page displays" Reading Settings 'show_on_front'
482 * and 'page_for_posts'.
483 *
484 * If a static page is set for the front page of the site, this function will return true only
485 * on the page you set as the "Posts page".
486 *
487 * For more information on this and similar theme functions, check out
488 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
489 * Conditional Tags} article in the Theme Developer Handbook.
490 *
491 * @since 1.5.0
492 *
493 * @see is_front_page()
494 * @global WP_Query $wp_query WordPress Query object.
495 *
496 * @return bool Whether the query is for the blog homepage.
497 */
498function is_home() {
499	global $wp_query;
500
501	if ( ! isset( $wp_query ) ) {
502		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
503		return false;
504	}
505
506	return $wp_query->is_home();
507}
508
509/**
510 * Determines whether the query is for the Privacy Policy page.
511 *
512 * The Privacy Policy page is the page that shows the Privacy Policy content of the site.
513 *
514 * is_privacy_policy() is dependent on the site's "Change your Privacy Policy page" Privacy Settings 'wp_page_for_privacy_policy'.
515 *
516 * This function will return true only on the page you set as the "Privacy Policy page".
517 *
518 * For more information on this and similar theme functions, check out
519 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
520 * Conditional Tags} article in the Theme Developer Handbook.
521 *
522 * @since 5.2.0
523 *
524 * @global WP_Query $wp_query WordPress Query object.
525 *
526 * @return bool Whether the query is for the Privacy Policy page.
527 */
528function is_privacy_policy() {
529	global $wp_query;
530
531	if ( ! isset( $wp_query ) ) {
532		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
533		return false;
534	}
535
536	return $wp_query->is_privacy_policy();
537}
538
539/**
540 * Determines whether the query is for an existing month archive.
541 *
542 * For more information on this and similar theme functions, check out
543 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
544 * Conditional Tags} article in the Theme Developer Handbook.
545 *
546 * @since 1.5.0
547 *
548 * @global WP_Query $wp_query WordPress Query object.
549 *
550 * @return bool Whether the query is for an existing month archive.
551 */
552function is_month() {
553	global $wp_query;
554
555	if ( ! isset( $wp_query ) ) {
556		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
557		return false;
558	}
559
560	return $wp_query->is_month();
561}
562
563/**
564 * Determines whether the query is for an existing single page.
565 *
566 * If the $page parameter is specified, this function will additionally
567 * check if the query is for one of the pages specified.
568 *
569 * For more information on this and similar theme functions, check out
570 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
571 * Conditional Tags} article in the Theme Developer Handbook.
572 *
573 * @since 1.5.0
574 *
575 * @see is_single()
576 * @see is_singular()
577 * @global WP_Query $wp_query WordPress Query object.
578 *
579 * @param int|string|int[]|string[] $page Optional. Page ID, title, slug, or array of such
580 *                                        to check against. Default empty.
581 * @return bool Whether the query is for an existing single page.
582 */
583function is_page( $page = '' ) {
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.0' );
588		return false;
589	}
590
591	return $wp_query->is_page( $page );
592}
593
594/**
595 * Determines whether the query is for a paged result and not for the first page.
596 *
597 * For more information on this and similar theme functions, check out
598 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
599 * Conditional Tags} article in the Theme Developer Handbook.
600 *
601 * @since 1.5.0
602 *
603 * @global WP_Query $wp_query WordPress Query object.
604 *
605 * @return bool Whether the query is for a paged result.
606 */
607function is_paged() {
608	global $wp_query;
609
610	if ( ! isset( $wp_query ) ) {
611		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
612		return false;
613	}
614
615	return $wp_query->is_paged();
616}
617
618/**
619 * Determines whether the query is for a post or page preview.
620 *
621 * For more information on this and similar theme functions, check out
622 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
623 * Conditional Tags} article in the Theme Developer Handbook.
624 *
625 * @since 2.0.0
626 *
627 * @global WP_Query $wp_query WordPress Query object.
628 *
629 * @return bool Whether the query is for a post or page preview.
630 */
631function is_preview() {
632	global $wp_query;
633
634	if ( ! isset( $wp_query ) ) {
635		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
636		return false;
637	}
638
639	return $wp_query->is_preview();
640}
641
642/**
643 * Is the query for the robots.txt file?
644 *
645 * @since 2.1.0
646 *
647 * @global WP_Query $wp_query WordPress Query object.
648 *
649 * @return bool Whether the query is for the robots.txt file.
650 */
651function is_robots() {
652	global $wp_query;
653
654	if ( ! isset( $wp_query ) ) {
655		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
656		return false;
657	}
658
659	return $wp_query->is_robots();
660}
661
662/**
663 * Is the query for the favicon.ico file?
664 *
665 * @since 5.4.0
666 *
667 * @global WP_Query $wp_query WordPress Query object.
668 *
669 * @return bool Whether the query is for the favicon.ico file.
670 */
671function is_favicon() {
672	global $wp_query;
673
674	if ( ! isset( $wp_query ) ) {
675		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
676		return false;
677	}
678
679	return $wp_query->is_favicon();
680}
681
682/**
683 * Determines whether the query is for a search.
684 *
685 * For more information on this and similar theme functions, check out
686 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
687 * Conditional Tags} article in the Theme Developer Handbook.
688 *
689 * @since 1.5.0
690 *
691 * @global WP_Query $wp_query WordPress Query object.
692 *
693 * @return bool Whether the query is for a search.
694 */
695function is_search() {
696	global $wp_query;
697
698	if ( ! isset( $wp_query ) ) {
699		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
700		return false;
701	}
702
703	return $wp_query->is_search();
704}
705
706/**
707 * Determines whether the query is for an existing single post.
708 *
709 * Works for any post type, except attachments and pages
710 *
711 * If the $post parameter is specified, this function will additionally
712 * check if the query is for one of the Posts specified.
713 *
714 * For more information on this and similar theme functions, check out
715 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
716 * Conditional Tags} article in the Theme Developer Handbook.
717 *
718 * @since 1.5.0
719 *
720 * @see is_page()
721 * @see is_singular()
722 * @global WP_Query $wp_query WordPress Query object.
723 *
724 * @param int|string|int[]|string[] $post Optional. Post ID, title, slug, or array of such
725 *                                        to check against. Default empty.
726 * @return bool Whether the query is for an existing single post.
727 */
728function is_single( $post = '' ) {
729	global $wp_query;
730
731	if ( ! isset( $wp_query ) ) {
732		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
733		return false;
734	}
735
736	return $wp_query->is_single( $post );
737}
738
739/**
740 * Determines whether the query is for an existing single post of any post type
741 * (post, attachment, page, custom post types).
742 *
743 * If the $post_types parameter is specified, this function will additionally
744 * check if the query is for one of the Posts Types specified.
745 *
746 * For more information on this and similar theme functions, check out
747 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
748 * Conditional Tags} article in the Theme Developer Handbook.
749 *
750 * @since 1.5.0
751 *
752 * @see is_page()
753 * @see is_single()
754 * @global WP_Query $wp_query WordPress Query object.
755 *
756 * @param string|string[] $post_types Optional. Post type or array of post types
757 *                                    to check against. Default empty.
758 * @return bool Whether the query is for an existing single post
759 *              or any of the given post types.
760 */
761function is_singular( $post_types = '' ) {
762	global $wp_query;
763
764	if ( ! isset( $wp_query ) ) {
765		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
766		return false;
767	}
768
769	return $wp_query->is_singular( $post_types );
770}
771
772/**
773 * Determines whether the query is for a specific time.
774 *
775 * For more information on this and similar theme functions, check out
776 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
777 * Conditional Tags} article in the Theme Developer Handbook.
778 *
779 * @since 1.5.0
780 *
781 * @global WP_Query $wp_query WordPress Query object.
782 *
783 * @return bool Whether the query is for a specific time.
784 */
785function is_time() {
786	global $wp_query;
787
788	if ( ! isset( $wp_query ) ) {
789		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
790		return false;
791	}
792
793	return $wp_query->is_time();
794}
795
796/**
797 * Determines whether the query is for a trackback endpoint call.
798 *
799 * For more information on this and similar theme functions, check out
800 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
801 * Conditional Tags} article in the Theme Developer Handbook.
802 *
803 * @since 1.5.0
804 *
805 * @global WP_Query $wp_query WordPress Query object.
806 *
807 * @return bool Whether the query is for a trackback endpoint call.
808 */
809function is_trackback() {
810	global $wp_query;
811
812	if ( ! isset( $wp_query ) ) {
813		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
814		return false;
815	}
816
817	return $wp_query->is_trackback();
818}
819
820/**
821 * Determines whether the query is for an existing year archive.
822 *
823 * For more information on this and similar theme functions, check out
824 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
825 * Conditional Tags} article in the Theme Developer Handbook.
826 *
827 * @since 1.5.0
828 *
829 * @global WP_Query $wp_query WordPress Query object.
830 *
831 * @return bool Whether the query is for an existing year archive.
832 */
833function is_year() {
834	global $wp_query;
835
836	if ( ! isset( $wp_query ) ) {
837		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
838		return false;
839	}
840
841	return $wp_query->is_year();
842}
843
844/**
845 * Determines whether the query has resulted in a 404 (returns no results).
846 *
847 * For more information on this and similar theme functions, check out
848 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
849 * Conditional Tags} article in the Theme Developer Handbook.
850 *
851 * @since 1.5.0
852 *
853 * @global WP_Query $wp_query WordPress Query object.
854 *
855 * @return bool Whether the query is a 404 error.
856 */
857function is_404() {
858	global $wp_query;
859
860	if ( ! isset( $wp_query ) ) {
861		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
862		return false;
863	}
864
865	return $wp_query->is_404();
866}
867
868/**
869 * Is the query for an embedded post?
870 *
871 * @since 4.4.0
872 *
873 * @global WP_Query $wp_query WordPress Query object.
874 *
875 * @return bool Whether the query is for an embedded post.
876 */
877function is_embed() {
878	global $wp_query;
879
880	if ( ! isset( $wp_query ) ) {
881		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
882		return false;
883	}
884
885	return $wp_query->is_embed();
886}
887
888/**
889 * Determines whether the query is the main query.
890 *
891 * For more information on this and similar theme functions, check out
892 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
893 * Conditional Tags} article in the Theme Developer Handbook.
894 *
895 * @since 3.3.0
896 *
897 * @global WP_Query $wp_query WordPress Query object.
898 *
899 * @return bool Whether the query is the main query.
900 */
901function is_main_query() {
902	global $wp_query;
903
904	if ( 'pre_get_posts' === current_filter() ) {
905		_doing_it_wrong(
906			__FUNCTION__,
907			sprintf(
908				/* translators: 1: pre_get_posts, 2: WP_Query->is_main_query(), 3: is_main_query(), 4: Documentation URL. */
909				__( 'In %1$s, use the %2$s method, not the %3$s function. See %4$s.' ),
910				'<code>pre_get_posts</code>',
911				'<code>WP_Query->is_main_query()</code>',
912				'<code>is_main_query()</code>',
913				__( 'https://developer.wordpress.org/reference/functions/is_main_query/' )
914			),
915			'3.7.0'
916		);
917	}
918
919	return $wp_query->is_main_query();
920}
921
922/*
923 * The Loop. Post loop control.
924 */
925
926/**
927 * Determines whether current WordPress query has posts to loop over.
928 *
929 * @since 1.5.0
930 *
931 * @global WP_Query $wp_query WordPress Query object.
932 *
933 * @return bool True if posts are available, false if end of the loop.
934 */
935function have_posts() {
936	global $wp_query;
937	return $wp_query->have_posts();
938}
939
940/**
941 * Determines whether the caller is in the Loop.
942 *
943 * For more information on this and similar theme functions, check out
944 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
945 * Conditional Tags} article in the Theme Developer Handbook.
946 *
947 * @since 2.0.0
948 *
949 * @global WP_Query $wp_query WordPress Query object.
950 *
951 * @return bool True if caller is within loop, false if loop hasn't started or ended.
952 */
953function in_the_loop() {
954	global $wp_query;
955	return $wp_query->in_the_loop;
956}
957
958/**
959 * Rewind the loop posts.
960 *
961 * @since 1.5.0
962 *
963 * @global WP_Query $wp_query WordPress Query object.
964 */
965function rewind_posts() {
966	global $wp_query;
967	$wp_query->rewind_posts();
968}
969
970/**
971 * Iterate the post index in the loop.
972 *
973 * @since 1.5.0
974 *
975 * @global WP_Query $wp_query WordPress Query object.
976 */
977function the_post() {
978	global $wp_query;
979	$wp_query->the_post();
980}
981
982/*
983 * Comments loop.
984 */
985
986/**
987 * Determines whether current WordPress query has comments to loop over.
988 *
989 * @since 2.2.0
990 *
991 * @global WP_Query $wp_query WordPress Query object.
992 *
993 * @return bool True if comments are available, false if no more comments.
994 */
995function have_comments() {
996	global $wp_query;
997	return $wp_query->have_comments();
998}
999
1000/**
1001 * Iterate comment index in the comment loop.
1002 *
1003 * @since 2.2.0
1004 *
1005 * @global WP_Query $wp_query WordPress Query object.
1006 *
1007 * @return null
1008 */
1009function the_comment() {
1010	global $wp_query;
1011	return $wp_query->the_comment();
1012}
1013
1014/**
1015 * Redirect old slugs to the correct permalink.
1016 *
1017 * Attempts to find the current slug from the past slugs.
1018 *
1019 * @since 2.1.0
1020 */
1021function wp_old_slug_redirect() {
1022	if ( is_404() && '' !== get_query_var( 'name' ) ) {
1023		// Guess the current post type based on the query vars.
1024		if ( get_query_var( 'post_type' ) ) {
1025			$post_type = get_query_var( 'post_type' );
1026		} elseif ( get_query_var( 'attachment' ) ) {
1027			$post_type = 'attachment';
1028		} elseif ( get_query_var( 'pagename' ) ) {
1029			$post_type = 'page';
1030		} else {
1031			$post_type = 'post';
1032		}
1033
1034		if ( is_array( $post_type ) ) {
1035			if ( count( $post_type ) > 1 ) {
1036				return;
1037			}
1038			$post_type = reset( $post_type );
1039		}
1040
1041		// Do not attempt redirect for hierarchical post types.
1042		if ( is_post_type_hierarchical( $post_type ) ) {
1043			return;
1044		}
1045
1046		$id = _find_post_by_old_slug( $post_type );
1047
1048		if ( ! $id ) {
1049			$id = _find_post_by_old_date( $post_type );
1050		}
1051
1052		/**
1053		 * Filters the old slug redirect post ID.
1054		 *
1055		 * @since 4.9.3
1056		 *
1057		 * @param int $id The redirect post ID.
1058		 */
1059		$id = apply_filters( 'old_slug_redirect_post_id', $id );
1060
1061		if ( ! $id ) {
1062			return;
1063		}
1064
1065		$link = get_permalink( $id );
1066
1067		if ( get_query_var( 'paged' ) > 1 ) {
1068			$link = user_trailingslashit( trailingslashit( $link ) . 'page/' . get_query_var( 'paged' ) );
1069		} elseif ( is_embed() ) {
1070			$link = user_trailingslashit( trailingslashit( $link ) . 'embed' );
1071		}
1072
1073		/**
1074		 * Filters the old slug redirect URL.
1075		 *
1076		 * @since 4.4.0
1077		 *
1078		 * @param string $link The redirect URL.
1079		 */
1080		$link = apply_filters( 'old_slug_redirect_url', $link );
1081
1082		if ( ! $link ) {
1083			return;
1084		}
1085
1086		wp_redirect( $link, 301 ); // Permanent redirect.
1087		exit;
1088	}
1089}
1090
1091/**
1092 * Find the post ID for redirecting an old slug.
1093 *
1094 * @since 4.9.3
1095 * @access private
1096 *
1097 * @see wp_old_slug_redirect()
1098 * @global wpdb $wpdb WordPress database abstraction object.
1099 *
1100 * @param string $post_type The current post type based on the query vars.
1101 * @return int The Post ID.
1102 */
1103function _find_post_by_old_slug( $post_type ) {
1104	global $wpdb;
1105
1106	$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, get_query_var( 'name' ) );
1107
1108	// If year, monthnum, or day have been specified, make our query more precise
1109	// just in case there are multiple identical _wp_old_slug values.
1110	if ( get_query_var( 'year' ) ) {
1111		$query .= $wpdb->prepare( ' AND YEAR(post_date) = %d', get_query_var( 'year' ) );
1112	}
1113	if ( get_query_var( 'monthnum' ) ) {
1114		$query .= $wpdb->prepare( ' AND MONTH(post_date) = %d', get_query_var( 'monthnum' ) );
1115	}
1116	if ( get_query_var( 'day' ) ) {
1117		$query .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) );
1118	}
1119
1120	$id = (int) $wpdb->get_var( $query );
1121
1122	return $id;
1123}
1124
1125/**
1126 * Find the post ID for redirecting an old date.
1127 *
1128 * @since 4.9.3
1129 * @access private
1130 *
1131 * @see wp_old_slug_redirect()
1132 * @global wpdb $wpdb WordPress database abstraction object.
1133 *
1134 * @param string $post_type The current post type based on the query vars.
1135 * @return int The Post ID.
1136 */
1137function _find_post_by_old_date( $post_type ) {
1138	global $wpdb;
1139
1140	$date_query = '';
1141	if ( get_query_var( 'year' ) ) {
1142		$date_query .= $wpdb->prepare( ' AND YEAR(pm_date.meta_value) = %d', get_query_var( 'year' ) );
1143	}
1144	if ( get_query_var( 'monthnum' ) ) {
1145		$date_query .= $wpdb->prepare( ' AND MONTH(pm_date.meta_value) = %d', get_query_var( 'monthnum' ) );
1146	}
1147	if ( get_query_var( 'day' ) ) {
1148		$date_query .= $wpdb->prepare( ' AND DAYOFMONTH(pm_date.meta_value) = %d', get_query_var( 'day' ) );
1149	}
1150
1151	$id = 0;
1152	if ( $date_query ) {
1153		$id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta AS pm_date, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_date' AND post_name = %s" . $date_query, $post_type, get_query_var( 'name' ) ) );
1154
1155		if ( ! $id ) {
1156			// Check to see if an old slug matches the old date.
1157			$id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts, $wpdb->postmeta AS pm_slug, $wpdb->postmeta AS pm_date WHERE ID = pm_slug.post_id AND ID = pm_date.post_id AND post_type = %s AND pm_slug.meta_key = '_wp_old_slug' AND pm_slug.meta_value = %s AND pm_date.meta_key = '_wp_old_date'" . $date_query, $post_type, get_query_var( 'name' ) ) );
1158		}
1159	}
1160
1161	return $id;
1162}
1163
1164/**
1165 * Set up global post data.
1166 *
1167 * @since 1.5.0
1168 * @since 4.4.0 Added the ability to pass a post ID to `$post`.
1169 *
1170 * @global WP_Query $wp_query WordPress Query object.
1171 *
1172 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
1173 * @return bool True when finished.
1174 */
1175function setup_postdata( $post ) {
1176	global $wp_query;
1177
1178	if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) {
1179		return $wp_query->setup_postdata( $post );
1180	}
1181
1182	return false;
1183}
1184
1185/**
1186 * Generates post data.
1187 *
1188 * @since 5.2.0
1189 *
1190 * @global WP_Query $wp_query WordPress Query object.
1191 *
1192 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
1193 * @return array|false Elements of post, or false on failure.
1194 */
1195function generate_postdata( $post ) {
1196	global $wp_query;
1197
1198	if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) {
1199		return $wp_query->generate_postdata( $post );
1200	}
1201
1202	return false;
1203}
1204