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