run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄class-wp-query.php
1<?php
2/**
3 * Query API: WP_Query class
4 *
5 * @package WordPress
6 * @subpackage Query
7 * @since 4.7.0
8 */
9
10/**
11 * The WordPress Query class.
12 *
13 * @link https://developer.wordpress.org/reference/classes/wp_query/
14 *
15 * @since 1.5.0
16 * @since 4.5.0 Removed the `$comments_popup` property.
17 */
18#[AllowDynamicProperties]
19class WP_Query {
20
21 /**
22 * Query vars set by the user.
23 *
24 * @since 1.5.0
25 * @var array
26 */
27 public $query;
28
29 /**
30 * Query vars, after parsing.
31 *
32 * @since 1.5.0
33 * @var array
34 */
35 public $query_vars = array();
36
37 /**
38 * Taxonomy query, as passed to get_tax_sql().
39 *
40 * @since 3.1.0
41 * @var WP_Tax_Query|null A taxonomy query instance.
42 */
43 public $tax_query;
44
45 /**
46 * Metadata query container.
47 *
48 * @since 3.2.0
49 * @var WP_Meta_Query A meta query instance.
50 */
51 public $meta_query = false;
52
53 /**
54 * Date query container.
55 *
56 * @since 3.7.0
57 * @var WP_Date_Query A date query instance.
58 */
59 public $date_query = false;
60
61 /**
62 * Holds the data for a single object that is queried.
63 *
64 * Holds the contents of a post, page, category, attachment.
65 *
66 * @since 1.5.0
67 * @var WP_Term|WP_Post_Type|WP_Post|WP_User|null
68 */
69 public $queried_object;
70
71 /**
72 * The ID of the queried object.
73 *
74 * @since 1.5.0
75 * @var int
76 */
77 public $queried_object_id;
78
79 /**
80 * SQL for the database query.
81 *
82 * @since 2.0.1
83 * @var string
84 */
85 public $request;
86
87 /**
88 * Array of post objects or post IDs.
89 *
90 * @since 1.5.0
91 * @var WP_Post[]|int[]
92 */
93 public $posts;
94
95 /**
96 * The number of posts for the current query.
97 *
98 * @since 1.5.0
99 * @var int
100 */
101 public $post_count = 0;
102
103 /**
104 * Index of the current item in the loop.
105 *
106 * @since 1.5.0
107 * @var int
108 */
109 public $current_post = -1;
110
111 /**
112 * Whether the caller is before the loop.
113 *
114 * @since 6.3.0
115 * @var bool
116 */
117 public $before_loop = true;
118
119 /**
120 * Whether the loop has started and the caller is in the loop.
121 *
122 * @since 2.0.0
123 * @var bool
124 */
125 public $in_the_loop = false;
126
127 /**
128 * The current post.
129 *
130 * This property does not get populated when the `fields` argument is set to
131 * `ids` or `id=>parent`.
132 *
133 * @since 1.5.0
134 * @var WP_Post|null
135 */
136 public $post;
137
138 /**
139 * The list of comments for current post.
140 *
141 * @since 2.2.0
142 * @var WP_Comment[]
143 */
144 public $comments;
145
146 /**
147 * The number of comments for the posts.
148 *
149 * @since 2.2.0
150 * @var int
151 */
152 public $comment_count = 0;
153
154 /**
155 * The index of the comment in the comment loop.
156 *
157 * @since 2.2.0
158 * @var int
159 */
160 public $current_comment = -1;
161
162 /**
163 * Current comment object.
164 *
165 * @since 2.2.0
166 * @var WP_Comment
167 */
168 public $comment;
169
170 /**
171 * The number of found posts for the current query.
172 *
173 * If limit clause was not used, equals $post_count.
174 *
175 * @since 2.1.0
176 * @var int
177 */
178 public $found_posts = 0;
179
180 /**
181 * The number of pages.
182 *
183 * @since 2.1.0
184 * @var int
185 */
186 public $max_num_pages = 0;
187
188 /**
189 * The number of comment pages.
190 *
191 * @since 2.7.0
192 * @var int
193 */
194 public $max_num_comment_pages = 0;
195
196 /**
197 * Signifies whether the current query is for a single post.
198 *
199 * @since 1.5.0
200 * @var bool
201 */
202 public $is_single = false;
203
204 /**
205 * Signifies whether the current query is for a preview.
206 *
207 * @since 2.0.0
208 * @var bool
209 */
210 public $is_preview = false;
211
212 /**
213 * Signifies whether the current query is for a page.
214 *
215 * @since 1.5.0
216 * @var bool
217 */
218 public $is_page = false;
219
220 /**
221 * Signifies whether the current query is for an archive.
222 *
223 * @since 1.5.0
224 * @var bool
225 */
226 public $is_archive = false;
227
228 /**
229 * Signifies whether the current query is for a date archive.
230 *
231 * @since 1.5.0
232 * @var bool
233 */
234 public $is_date = false;
235
236 /**
237 * Signifies whether the current query is for a year archive.
238 *
239 * @since 1.5.0
240 * @var bool
241 */
242 public $is_year = false;
243
244 /**
245 * Signifies whether the current query is for a month archive.
246 *
247 * @since 1.5.0
248 * @var bool
249 */
250 public $is_month = false;
251
252 /**
253 * Signifies whether the current query is for a day archive.
254 *
255 * @since 1.5.0
256 * @var bool
257 */
258 public $is_day = false;
259
260 /**
261 * Signifies whether the current query is for a specific time.
262 *
263 * @since 1.5.0
264 * @var bool
265 */
266 public $is_time = false;
267
268 /**
269 * Signifies whether the current query is for an author archive.
270 *
271 * @since 1.5.0
272 * @var bool
273 */
274 public $is_author = false;
275
276 /**
277 * Signifies whether the current query is for a category archive.
278 *
279 * @since 1.5.0
280 * @var bool
281 */
282 public $is_category = false;
283
284 /**
285 * Signifies whether the current query is for a tag archive.
286 *
287 * @since 2.3.0
288 * @var bool
289 */
290 public $is_tag = false;
291
292 /**
293 * Signifies whether the current query is for a taxonomy archive.
294 *
295 * @since 2.5.0
296 * @var bool
297 */
298 public $is_tax = false;
299
300 /**
301 * Signifies whether the current query is for a search.
302 *
303 * @since 1.5.0
304 * @var bool
305 */
306 public $is_search = false;
307
308 /**
309 * Signifies whether the current query is for a feed.
310 *
311 * @since 1.5.0
312 * @var bool
313 */
314 public $is_feed = false;
315
316 /**
317 * Signifies whether the current query is for a comment feed.
318 *
319 * @since 2.2.0
320 * @var bool
321 */
322 public $is_comment_feed = false;
323
324 /**
325 * Signifies whether the current query is for trackback endpoint call.
326 *
327 * @since 1.5.0
328 * @var bool
329 */
330 public $is_trackback = false;
331
332 /**
333 * Signifies whether the current query is for the site homepage.
334 *
335 * @since 1.5.0
336 * @var bool
337 */
338 public $is_home = false;
339
340 /**
341 * Signifies whether the current query is for the Privacy Policy page.
342 *
343 * @since 5.2.0
344 * @var bool
345 */
346 public $is_privacy_policy = false;
347
348 /**
349 * Signifies whether the current query couldn't find anything.
350 *
351 * @since 1.5.0
352 * @var bool
353 */
354 public $is_404 = false;
355
356 /**
357 * Signifies whether the current query is for an embed.
358 *
359 * @since 4.4.0
360 * @var bool
361 */
362 public $is_embed = false;
363
364 /**
365 * Signifies whether the current query is for a paged result and not for the first page.
366 *
367 * @since 1.5.0
368 * @var bool
369 */
370 public $is_paged = false;
371
372 /**
373 * Signifies whether the current query is for an administrative interface page.
374 *
375 * @since 1.5.0
376 * @var bool
377 */
378 public $is_admin = false;
379
380 /**
381 * Signifies whether the current query is for an attachment page.
382 *
383 * @since 2.0.0
384 * @var bool
385 */
386 public $is_attachment = false;
387
388 /**
389 * Signifies whether the current query is for an existing single post of any post type
390 * (post, attachment, page, custom post types).
391 *
392 * @since 2.1.0
393 * @var bool
394 */
395 public $is_singular = false;
396
397 /**
398 * Signifies whether the current query is for the robots.txt file.
399 *
400 * @since 2.1.0
401 * @var bool
402 */
403 public $is_robots = false;
404
405 /**
406 * Signifies whether the current query is for the favicon.ico file.
407 *
408 * @since 5.4.0
409 * @var bool
410 */
411 public $is_favicon = false;
412
413 /**
414 * Signifies whether the current query is for the page_for_posts page.
415 *
416 * Basically, the homepage if the option isn't set for the static homepage.
417 *
418 * @since 2.1.0
419 * @var bool
420 */
421 public $is_posts_page = false;
422
423 /**
424 * Signifies whether the current query is for a post type archive.
425 *
426 * @since 3.1.0
427 * @var bool
428 */
429 public $is_post_type_archive = false;
430
431 /**
432 * Stores the ->query_vars state like md5(serialize( $this->query_vars ) ) so we know
433 * whether we have to re-parse because something has changed
434 *
435 * @since 3.1.0
436 * @var bool|string
437 */
438 private $query_vars_hash = false;
439
440 /**
441 * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
442 * via pre_get_posts hooks.
443 *
444 * @since 3.1.1
445 * @var bool
446 */
447 private $query_vars_changed = true;
448
449 /**
450 * Set if post thumbnails are cached
451 *
452 * @since 3.2.0
453 * @var bool
454 */
455 public $thumbnails_cached = false;
456
457 /**
458 * Controls whether an attachment query should include filenames or not.
459 *
460 * @since 6.0.3
461 * @var bool
462 */
463 protected $allow_query_attachment_by_filename = false;
464
465 /**
466 * Cached list of search stopwords.
467 *
468 * @since 3.7.0
469 * @var array
470 */
471 private $stopwords;
472
473 private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );
474
475 private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
476
477 /**
478 * The cache key generated by the query.
479 *
480 * The cache key is generated by the method ::generate_cache_key() after the
481 * query has been normalized.
482 *
483 * @since 6.8.0
484 * @var string
485 */
486 private $query_cache_key = '';
487
488 /**
489 * Resets query flags to false.
490 *
491 * The query flags are what page info WordPress was able to figure out.
492 *
493 * @since 2.0.0
494 */
495 private function init_query_flags() {
496 $this->is_single = false;
497 $this->is_preview = false;
498 $this->is_page = false;
499 $this->is_archive = false;
500 $this->is_date = false;
501 $this->is_year = false;
502 $this->is_month = false;
503 $this->is_day = false;
504 $this->is_time = false;
505 $this->is_author = false;
506 $this->is_category = false;
507 $this->is_tag = false;
508 $this->is_tax = false;
509 $this->is_search = false;
510 $this->is_feed = false;
511 $this->is_comment_feed = false;
512 $this->is_trackback = false;
513 $this->is_home = false;
514 $this->is_privacy_policy = false;
515 $this->is_404 = false;
516 $this->is_paged = false;
517 $this->is_admin = false;
518 $this->is_attachment = false;
519 $this->is_singular = false;
520 $this->is_robots = false;
521 $this->is_favicon = false;
522 $this->is_posts_page = false;
523 $this->is_post_type_archive = false;
524 }
525
526 /**
527 * Initiates object properties and sets default values.
528 *
529 * @since 1.5.0
530 */
531 public function init() {
532 unset( $this->posts );
533 unset( $this->query );
534 $this->query_vars = array();
535 unset( $this->queried_object );
536 unset( $this->queried_object_id );
537 $this->post_count = 0;
538 $this->current_post = -1;
539 $this->in_the_loop = false;
540 $this->before_loop = true;
541 unset( $this->request );
542 unset( $this->post );
543 unset( $this->comments );
544 unset( $this->comment );
545 $this->comment_count = 0;
546 $this->current_comment = -1;
547 $this->found_posts = 0;
548 $this->max_num_pages = 0;
549 $this->max_num_comment_pages = 0;
550
551 $this->init_query_flags();
552 }
553
554 /**
555 * Reparses the query vars.
556 *
557 * @since 1.5.0
558 */
559 public function parse_query_vars() {
560 $this->parse_query();
561 }
562
563 /**
564 * Fills in the query variables, which do not exist within the parameter.
565 *
566 * @since 2.1.0
567 * @since 4.5.0 Removed the `comments_popup` public query variable.
568 *
569 * @param array $query_vars Defined query variables.
570 * @return array Complete query variables with undefined ones filled in empty.
571 */
572 public function fill_query_vars( $query_vars ) {
573 $keys = array(
574 'error',
575 'm',
576 'p',
577 'post_parent',
578 'subpost',
579 'subpost_id',
580 'attachment',
581 'attachment_id',
582 'name',
583 'pagename',
584 'page_id',
585 'second',
586 'minute',
587 'hour',
588 'day',
589 'monthnum',
590 'year',
591 'w',
592 'category_name',
593 'tag',
594 'cat',
595 'tag_id',
596 'author',
597 'author_name',
598 'feed',
599 'tb',
600 'paged',
601 'meta_key',
602 'meta_value',
603 'preview',
604 's',
605 'sentence',
606 'title',
607 'fields',
608 'menu_order',
609 'embed',
610 );
611
612 foreach ( $keys as $key ) {
613 if ( ! isset( $query_vars[ $key ] ) ) {
614 $query_vars[ $key ] = '';
615 }
616 }
617
618 $array_keys = array(
619 'category__in',
620 'category__not_in',
621 'category__and',
622 'post__in',
623 'post__not_in',
624 'post_name__in',
625 'tag__in',
626 'tag__not_in',
627 'tag__and',
628 'tag_slug__in',
629 'tag_slug__and',
630 'post_parent__in',
631 'post_parent__not_in',
632 'author__in',
633 'author__not_in',
634 'search_columns',
635 );
636
637 foreach ( $array_keys as $key ) {
638 if ( ! isset( $query_vars[ $key ] ) ) {
639 $query_vars[ $key ] = array();
640 }
641 }
642
643 return $query_vars;
644 }
645
646 /**
647 * Parses a query string and sets query type booleans.
648 *
649 * @since 1.5.0
650 * @since 4.2.0 Introduced the ability to order by specific clauses of a `$meta_query`, by passing the clause's
651 * array key to `$orderby`.
652 * @since 4.4.0 Introduced `$post_name__in` and `$title` parameters. `$s` was updated to support excluded
653 * search terms, by prepending a hyphen.
654 * @since 4.5.0 Removed the `$comments_popup` parameter.
655 * Introduced the `$comment_status` and `$ping_status` parameters.
656 * Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts.
657 * @since 4.6.0 Added 'post_name__in' support for `$orderby`. Introduced the `$lazy_load_term_meta` argument.
658 * @since 4.9.0 Introduced the `$comment_count` parameter.
659 * @since 5.1.0 Introduced the `$meta_compare_key` parameter.
660 * @since 5.3.0 Introduced the `$meta_type_key` parameter.
661 * @since 6.1.0 Introduced the `$update_menu_item_cache` parameter.
662 * @since 6.2.0 Introduced the `$search_columns` parameter.
663 *
664 * @param string|array $query {
665 * Optional. Array or string of Query parameters.
666 *
667 * @type int $attachment_id Attachment post ID. Used for 'attachment' post_type.
668 * @type int|string $author Author ID, or comma-separated list of IDs.
669 * @type string $author_name User 'user_nicename'.
670 * @type int[] $author__in An array of author IDs to query from.
671 * @type int[] $author__not_in An array of author IDs not to query from.
672 * @type bool $cache_results Whether to cache post information. Default true.
673 * @type int|string $cat Category ID or comma-separated list of IDs (this or any children).
674 * @type int[] $category__and An array of category IDs (AND in).
675 * @type int[] $category__in An array of category IDs (OR in, no children).
676 * @type int[] $category__not_in An array of category IDs (NOT in).
677 * @type string $category_name Use category slug (not name, this or any children).
678 * @type array|int $comment_count Filter results by comment count. Provide an integer to match
679 * comment count exactly. Provide an array with integer 'value'
680 * and 'compare' operator ('=', '!=', '>', '>=', '<', '<=' ) to
681 * compare against comment_count in a specific way.
682 * @type string $comment_status Comment status.
683 * @type int $comments_per_page The number of comments to return per page.
684 * Default 'comments_per_page' option.
685 * @type array $date_query An associative array of WP_Date_Query arguments.
686 * See WP_Date_Query::__construct().
687 * @type int $day Day of the month. Default empty. Accepts numbers 1-31.
688 * @type bool $exact Whether to search by exact keyword. Default false.
689 * @type string $fields Post fields to query for. Accepts:
690 * - '' Returns an array of complete post objects (`WP_Post[]`).
691 * - 'ids' Returns an array of post IDs (`int[]`).
692 * - 'id=>parent' Returns an associative array of parent post IDs,
693 * keyed by post ID (`int[]`).
694 * Default ''.
695 * @type int $hour Hour of the day. Default empty. Accepts numbers 0-23.
696 * @type int|bool $ignore_sticky_posts Whether to ignore sticky posts or not. Setting this to false
697 * excludes stickies from 'post__in'. Accepts 1|true, 0|false.
698 * Default false.
699 * @type int $m Combination YearMonth. Accepts any four-digit year and month
700 * numbers 01-12. Default empty.
701 * @type string|string[] $meta_key Meta key or keys to filter by.
702 * @type string|string[] $meta_value Meta value or values to filter by.
703 * @type string $meta_compare MySQL operator used for comparing the meta value.
704 * See WP_Meta_Query::__construct() for accepted values and default value.
705 * @type string $meta_compare_key MySQL operator used for comparing the meta key.
706 * See WP_Meta_Query::__construct() for accepted values and default value.
707 * @type string $meta_type MySQL data type that the meta_value column will be CAST to for comparisons.
708 * See WP_Meta_Query::__construct() for accepted values and default value.
709 * @type string $meta_type_key MySQL data type that the meta_key column will be CAST to for comparisons.
710 * See WP_Meta_Query::__construct() for accepted values and default value.
711 * @type array $meta_query An associative array of WP_Meta_Query arguments.
712 * See WP_Meta_Query::__construct() for accepted values.
713 * @type int $menu_order The menu order of the posts.
714 * @type int $minute Minute of the hour. Default empty. Accepts numbers 0-59.
715 * @type int $monthnum The two-digit month. Default empty. Accepts numbers 1-12.
716 * @type string $name Post slug.
717 * @type bool $nopaging Show all posts (true) or paginate (false). Default false.
718 * @type bool $no_found_rows Whether to skip counting the total rows found. Enabling can improve
719 * performance. Default false.
720 * @type int $offset The number of posts to offset before retrieval.
721 * @type string $order Designates ascending or descending order of posts. Default 'DESC'.
722 * Accepts 'ASC', 'DESC'.
723 * @type string|array $orderby Sort retrieved posts by parameter. One or more options may be passed.
724 * To use 'meta_value', or 'meta_value_num', 'meta_key=keyname' must be
725 * also be defined. To sort by a specific `$meta_query` clause, use that
726 * clause's array key. Accepts:
727 * - 'none'
728 * - 'name'
729 * - 'author'
730 * - 'date'
731 * - 'title'
732 * - 'modified'
733 * - 'menu_order'
734 * - 'parent'
735 * - 'ID'
736 * - 'rand'
737 * - 'relevance'
738 * - 'RAND(x)' (where 'x' is an integer seed value)
739 * - 'comment_count'
740 * - 'meta_value'
741 * - 'meta_value_num'
742 * - 'post__in'
743 * - 'post_name__in'
744 * - 'post_parent__in'
745 * - The array keys of `$meta_query`.
746 * Default is 'date', except when a search is being performed, when
747 * the default is 'relevance'.
748 * @type int $p Post ID.
749 * @type int $page Show the number of posts that would show up on page X of a
750 * static front page.
751 * @type int $paged The number of the current page.
752 * @type int $page_id Page ID.
753 * @type string $pagename Page slug.
754 * @type string $perm Show posts if user has the appropriate capability.
755 * @type string $ping_status Ping status.
756 * @type int[] $post__in An array of post IDs to retrieve, sticky posts will be included.
757 * @type int[] $post__not_in An array of post IDs not to retrieve. Note: a string of comma-
758 * separated IDs will NOT work.
759 * @type string $post_mime_type The mime type of the post. Used for 'attachment' post_type.
760 * @type string[] $post_name__in An array of post slugs that results must match.
761 * @type int $post_parent Page ID to retrieve child pages for. Use 0 to only retrieve
762 * top-level pages.
763 * @type int[] $post_parent__in An array containing parent page IDs to query child pages from.
764 * @type int[] $post_parent__not_in An array containing parent page IDs not to query child pages from.
765 * @type string|string[] $post_type A post type slug (string) or array of post type slugs.
766 * Default 'any' if using 'tax_query'.
767 * @type string|string[] $post_status A post status (string) or array of post statuses.
768 * @type int $posts_per_page The number of posts to query for. Use -1 to request all posts.
769 * @type int $posts_per_archive_page The number of posts to query for by archive page. Overrides
770 * 'posts_per_page' when is_archive(), or is_search() are true.
771 * @type string $s Search keyword(s). Prepending a term with a hyphen will
772 * exclude posts matching that term. Eg, 'pillow -sofa' will
773 * return posts containing 'pillow' but not 'sofa'. The
774 * character used for exclusion can be modified using the
775 * the 'wp_query_search_exclusion_prefix' filter.
776 * @type string[] $search_columns Array of column names to be searched. Accepts 'post_title',
777 * 'post_excerpt' and 'post_content'. Default empty array.
778 * @type int $second Second of the minute. Default empty. Accepts numbers 0-59.
779 * @type bool $sentence Whether to search by phrase. Default false.
780 * @type bool $suppress_filters Whether to suppress filters. Default false.
781 * @type string $tag Tag slug. Comma-separated (either), Plus-separated (all).
782 * @type int[] $tag__and An array of tag IDs (AND in).
783 * @type int[] $tag__in An array of tag IDs (OR in).
784 * @type int[] $tag__not_in An array of tag IDs (NOT in).
785 * @type int $tag_id Tag id or comma-separated list of IDs.
786 * @type string[] $tag_slug__and An array of tag slugs (AND in).
787 * @type string[] $tag_slug__in An array of tag slugs (OR in). unless 'ignore_sticky_posts' is
788 * true. Note: a string of comma-separated IDs will NOT work.
789 * @type array $tax_query An associative array of WP_Tax_Query arguments.
790 * See WP_Tax_Query::__construct().
791 * @type string $title Post title.
792 * @type bool $update_post_meta_cache Whether to update the post meta cache. Default true.
793 * @type bool $update_post_term_cache Whether to update the post term cache. Default true.
794 * @type bool $update_menu_item_cache Whether to update the menu item cache. Default false.
795 * @type bool $lazy_load_term_meta Whether to lazy-load term meta. Setting to false will
796 * disable cache priming for term meta, so that each
797 * get_term_meta() call will hit the database.
798 * Defaults to the value of `$update_post_term_cache`.
799 * @type int $w The week number of the year. Default empty. Accepts numbers 0-53.
800 * @type int $year The four-digit year. Default empty. Accepts any four-digit year.
801 * }
802 */
803 public function parse_query( $query = '' ) {
804 if ( ! empty( $query ) ) {
805 $this->init();
806 $this->query = wp_parse_args( $query );
807 $this->query_vars = $this->query;
808 } elseif ( ! isset( $this->query ) ) {
809 $this->query = $this->query_vars;
810 }
811
812 $this->query_vars = $this->fill_query_vars( $this->query_vars );
813 $query_vars = &$this->query_vars;
814 $this->query_vars_changed = true;
815
816 if ( ! empty( $query_vars['robots'] ) ) {
817 $this->is_robots = true;
818 } elseif ( ! empty( $query_vars['favicon'] ) ) {
819 $this->is_favicon = true;
820 }
821
822 if ( ! is_scalar( $query_vars['p'] ) || (int) $query_vars['p'] < 0 ) {
823 $query_vars['p'] = 0;
824 $query_vars['error'] = '404';
825 } else {
826 $query_vars['p'] = (int) $query_vars['p'];
827 }
828
829 $query_vars['page_id'] = is_scalar( $query_vars['page_id'] ) ? absint( $query_vars['page_id'] ) : 0;
830 $query_vars['year'] = is_scalar( $query_vars['year'] ) ? absint( $query_vars['year'] ) : 0;
831 $query_vars['monthnum'] = is_scalar( $query_vars['monthnum'] ) ? absint( $query_vars['monthnum'] ) : 0;
832 $query_vars['day'] = is_scalar( $query_vars['day'] ) ? absint( $query_vars['day'] ) : 0;
833 $query_vars['w'] = is_scalar( $query_vars['w'] ) ? absint( $query_vars['w'] ) : 0;
834 $query_vars['m'] = is_scalar( $query_vars['m'] ) ? preg_replace( '|[^0-9]|', '', $query_vars['m'] ) : '';
835 $query_vars['paged'] = is_scalar( $query_vars['paged'] ) ? absint( $query_vars['paged'] ) : 0;
836 $query_vars['cat'] = preg_replace( '|[^0-9,-]|', '', $query_vars['cat'] ); // Array or comma-separated list of positive or negative integers.
837 $query_vars['author'] = is_scalar( $query_vars['author'] ) ? preg_replace( '|[^0-9,-]|', '', $query_vars['author'] ) : ''; // Comma-separated list of positive or negative integers.
838 $query_vars['pagename'] = is_scalar( $query_vars['pagename'] ) ? trim( $query_vars['pagename'] ) : '';
839 $query_vars['name'] = is_scalar( $query_vars['name'] ) ? trim( $query_vars['name'] ) : '';
840 $query_vars['title'] = is_scalar( $query_vars['title'] ) ? trim( $query_vars['title'] ) : '';
841
842 if ( is_scalar( $query_vars['hour'] ) && '' !== $query_vars['hour'] ) {
843 $query_vars['hour'] = absint( $query_vars['hour'] );
844 } else {
845 $query_vars['hour'] = '';
846 }
847
848 if ( is_scalar( $query_vars['minute'] ) && '' !== $query_vars['minute'] ) {
849 $query_vars['minute'] = absint( $query_vars['minute'] );
850 } else {
851 $query_vars['minute'] = '';
852 }
853
854 if ( is_scalar( $query_vars['second'] ) && '' !== $query_vars['second'] ) {
855 $query_vars['second'] = absint( $query_vars['second'] );
856 } else {
857 $query_vars['second'] = '';
858 }
859
860 if ( is_scalar( $query_vars['menu_order'] ) && '' !== $query_vars['menu_order'] ) {
861 $query_vars['menu_order'] = absint( $query_vars['menu_order'] );
862 } else {
863 $query_vars['menu_order'] = '';
864 }
865
866 // Fairly large, potentially too large, upper bound for search string lengths.
867 if ( ! is_scalar( $query_vars['s'] ) || ( ! empty( $query_vars['s'] ) && strlen( $query_vars['s'] ) > 1600 ) ) {
868 $query_vars['s'] = '';
869 }
870
871 // Compat. Map subpost to attachment.
872 if ( is_scalar( $query_vars['subpost'] ) && '' != $query_vars['subpost'] ) {
873 $query_vars['attachment'] = $query_vars['subpost'];
874 }
875 if ( is_scalar( $query_vars['subpost_id'] ) && '' != $query_vars['subpost_id'] ) {
876 $query_vars['attachment_id'] = $query_vars['subpost_id'];
877 }
878
879 $query_vars['attachment_id'] = is_scalar( $query_vars['attachment_id'] ) ? absint( $query_vars['attachment_id'] ) : 0;
880
881 if ( ( '' !== $query_vars['attachment'] ) || ! empty( $query_vars['attachment_id'] ) ) {
882 $this->is_single = true;
883 $this->is_attachment = true;
884 } elseif ( '' !== $query_vars['name'] ) {
885 $this->is_single = true;
886 } elseif ( $query_vars['p'] ) {
887 $this->is_single = true;
888 } elseif ( '' !== $query_vars['pagename'] || ! empty( $query_vars['page_id'] ) ) {
889 $this->is_page = true;
890 $this->is_single = false;
891 } else {
892 // Look for archive queries. Dates, categories, authors, search, post type archives.
893
894 if ( isset( $this->query['s'] ) ) {
895 $this->is_search = true;
896 }
897
898 if ( '' !== $query_vars['second'] ) {
899 $this->is_time = true;
900 $this->is_date = true;
901 }
902
903 if ( '' !== $query_vars['minute'] ) {
904 $this->is_time = true;
905 $this->is_date = true;
906 }
907
908 if ( '' !== $query_vars['hour'] ) {
909 $this->is_time = true;
910 $this->is_date = true;
911 }
912
913 if ( $query_vars['day'] ) {
914 if ( ! $this->is_date ) {
915 $date = sprintf( '%04d-%02d-%02d', $query_vars['year'], $query_vars['monthnum'], $query_vars['day'] );
916 if ( $query_vars['monthnum'] && $query_vars['year'] && ! wp_checkdate( $query_vars['monthnum'], $query_vars['day'], $query_vars['year'], $date ) ) {
917 $query_vars['error'] = '404';
918 } else {
919 $this->is_day = true;
920 $this->is_date = true;
921 }
922 }
923 }
924
925 if ( $query_vars['monthnum'] ) {
926 if ( ! $this->is_date ) {
927 if ( 12 < $query_vars['monthnum'] ) {
928 $query_vars['error'] = '404';
929 } else {
930 $this->is_month = true;
931 $this->is_date = true;
932 }
933 }
934 }
935
936 if ( $query_vars['year'] ) {
937 if ( ! $this->is_date ) {
938 $this->is_year = true;
939 $this->is_date = true;
940 }
941 }
942
943 if ( $query_vars['m'] ) {
944 $this->is_date = true;
945 if ( strlen( $query_vars['m'] ) > 9 ) {
946 $this->is_time = true;
947 } elseif ( strlen( $query_vars['m'] ) > 7 ) {
948 $this->is_day = true;
949 } elseif ( strlen( $query_vars['m'] ) > 5 ) {
950 $this->is_month = true;
951 } else {
952 $this->is_year = true;
953 }
954 }
955
956 if ( $query_vars['w'] ) {
957 $this->is_date = true;
958 }
959
960 $this->query_vars_hash = false;
961 $this->parse_tax_query( $query_vars );
962
963 foreach ( $this->tax_query->queries as $tax_query ) {
964 if ( ! is_array( $tax_query ) ) {
965 continue;
966 }
967
968 if ( isset( $tax_query['operator'] ) && 'NOT IN' !== $tax_query['operator'] ) {
969 switch ( $tax_query['taxonomy'] ) {
970 case 'category':
971 $this->is_category = true;
972 break;
973 case 'post_tag':
974 $this->is_tag = true;
975 break;
976 default:
977 $this->is_tax = true;
978 }
979 }
980 }
981 unset( $tax_query );
982
983 if ( empty( $query_vars['author'] ) || ( '0' == $query_vars['author'] ) ) {
984 $this->is_author = false;
985 } else {
986 $this->is_author = true;
987 }
988
989 if ( '' !== $query_vars['author_name'] ) {
990 $this->is_author = true;
991 }
992
993 if ( ! empty( $query_vars['post_type'] ) && ! is_array( $query_vars['post_type'] ) ) {
994 $post_type_obj = get_post_type_object( $query_vars['post_type'] );
995 if ( ! empty( $post_type_obj->has_archive ) ) {
996 $this->is_post_type_archive = true;
997 }
998 }
999
1000 if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax ) {
1001 $this->is_archive = true;
1002 }
1003 }
1004
1005 if ( '' != $query_vars['feed'] ) {
1006 $this->is_feed = true;
1007 }
1008
1009 if ( '' != $query_vars['embed'] ) {
1010 $this->is_embed = true;
1011 }
1012
1013 if ( '' != $query_vars['tb'] ) {
1014 $this->is_trackback = true;
1015 }
1016
1017 if ( '' != $query_vars['paged'] && ( (int) $query_vars['paged'] > 1 ) ) {
1018 $this->is_paged = true;
1019 }
1020
1021 // If we're previewing inside the write screen.
1022 if ( '' != $query_vars['preview'] ) {
1023 $this->is_preview = true;
1024 }
1025
1026 if ( is_admin() ) {
1027 $this->is_admin = true;
1028 }
1029
1030 if ( str_contains( $query_vars['feed'], 'comments-' ) ) {
1031 $query_vars['feed'] = str_replace( 'comments-', '', $query_vars['feed'] );
1032 $query_vars['withcomments'] = 1;
1033 }
1034
1035 $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
1036
1037 if ( $this->is_feed && ( ! empty( $query_vars['withcomments'] ) || ( empty( $query_vars['withoutcomments'] ) && $this->is_singular ) ) ) {
1038 $this->is_comment_feed = true;
1039 }
1040
1041 if ( ! ( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed
1042 || ( wp_is_serving_rest_request() && $this->is_main_query() )
1043 || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots || $this->is_favicon ) ) {
1044 $this->is_home = true;
1045 }
1046
1047 // Correct `is_*` for 'page_on_front' and 'page_for_posts'.
1048 if ( $this->is_home && 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) ) {
1049 $_query = wp_parse_args( $this->query );
1050 // 'pagename' can be set and empty depending on matched rewrite rules. Ignore an empty 'pagename'.
1051 if ( isset( $_query['pagename'] ) && '' === $_query['pagename'] ) {
1052 unset( $_query['pagename'] );
1053 }
1054
1055 unset( $_query['embed'] );
1056
1057 if ( empty( $_query ) || ! array_diff( array_keys( $_query ), array( 'preview', 'page', 'paged', 'cpage' ) ) ) {
1058 $this->is_page = true;
1059 $this->is_home = false;
1060 $query_vars['page_id'] = get_option( 'page_on_front' );
1061 // Correct <!--nextpage--> for 'page_on_front'.
1062 if ( ! empty( $query_vars['paged'] ) ) {
1063 $query_vars['page'] = $query_vars['paged'];
1064 unset( $query_vars['paged'] );
1065 }
1066 }
1067 }
1068
1069 if ( '' !== $query_vars['pagename'] ) {
1070 $this->queried_object = get_page_by_path( $query_vars['pagename'] );
1071
1072 if ( $this->queried_object && 'attachment' === $this->queried_object->post_type ) {
1073 if ( preg_match( '/^[^%]*%(?:postname)%/', get_option( 'permalink_structure' ) ) ) {
1074 // See if we also have a post with the same slug.
1075 $post = get_page_by_path( $query_vars['pagename'], OBJECT, 'post' );
1076 if ( $post ) {
1077 $this->queried_object = $post;
1078 $this->is_page = false;
1079 $this->is_single = true;
1080 }
1081 }
1082 }
1083
1084 if ( ! empty( $this->queried_object ) ) {
1085 $this->queried_object_id = (int) $this->queried_object->ID;
1086 } else {
1087 unset( $this->queried_object );
1088 }
1089
1090 if ( 'page' === get_option( 'show_on_front' ) && isset( $this->queried_object_id ) && get_option( 'page_for_posts' ) == $this->queried_object_id ) {
1091 $this->is_page = false;
1092 $this->is_home = true;
1093 $this->is_posts_page = true;
1094 }
1095
1096 if ( isset( $this->queried_object_id ) && get_option( 'wp_page_for_privacy_policy' ) == $this->queried_object_id ) {
1097 $this->is_privacy_policy = true;
1098 }
1099 }
1100
1101 if ( $query_vars['page_id'] ) {
1102 if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) == $query_vars['page_id'] ) {
1103 $this->is_page = false;
1104 $this->is_home = true;
1105 $this->is_posts_page = true;
1106 }
1107
1108 if ( get_option( 'wp_page_for_privacy_policy' ) == $query_vars['page_id'] ) {
1109 $this->is_privacy_policy = true;
1110 }
1111 }
1112
1113 if ( ! empty( $query_vars['post_type'] ) ) {
1114 if ( is_array( $query_vars['post_type'] ) ) {
1115 $query_vars['post_type'] = array_map( 'sanitize_key', array_unique( $query_vars['post_type'] ) );
1116 sort( $query_vars['post_type'] );
1117 } else {
1118 $query_vars['post_type'] = sanitize_key( $query_vars['post_type'] );
1119 }
1120 }
1121
1122 if ( ! empty( $query_vars['post_status'] ) ) {
1123 if ( is_array( $query_vars['post_status'] ) ) {
1124 $query_vars['post_status'] = array_map( 'sanitize_key', array_unique( $query_vars['post_status'] ) );
1125 sort( $query_vars['post_status'] );
1126 } else {
1127 $query_vars['post_status'] = preg_replace( '|[^a-z0-9_,-]|', '', $query_vars['post_status'] );
1128 }
1129 }
1130
1131 if ( $this->is_posts_page && ( ! isset( $query_vars['withcomments'] ) || ! $query_vars['withcomments'] ) ) {
1132 $this->is_comment_feed = false;
1133 }
1134
1135 $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
1136 // Done correcting `is_*` for 'page_on_front' and 'page_for_posts'.
1137
1138 if ( '404' == $query_vars['error'] ) {
1139 $this->set_404();
1140 }
1141
1142 $this->is_embed = $this->is_embed && ( $this->is_singular || $this->is_404 );
1143
1144 $this->query_vars_hash = md5( serialize( $this->query_vars ) );
1145 $this->query_vars_changed = false;
1146
1147 /**
1148 * Fires after the main query vars have been parsed.
1149 *
1150 * @since 1.5.0
1151 *
1152 * @param WP_Query $query The WP_Query instance (passed by reference).
1153 */
1154 do_action_ref_array( 'parse_query', array( &$this ) );
1155 }
1156
1157 /**
1158 * Parses various taxonomy related query vars.
1159 *
1160 * For BC, this method is not marked as protected. See [28987].
1161 *
1162 * @since 3.1.0
1163 *
1164 * @param array $query_vars The query variables. Passed by reference.
1165 */
1166 public function parse_tax_query( &$query_vars ) {
1167 if ( ! empty( $query_vars['tax_query'] ) && is_array( $query_vars['tax_query'] ) ) {
1168 $tax_query = $query_vars['tax_query'];
1169 } else {
1170 $tax_query = array();
1171 }
1172
1173 if ( ! empty( $query_vars['taxonomy'] ) && ! empty( $query_vars['term'] ) ) {
1174 $tax_query[] = array(
1175 'taxonomy' => $query_vars['taxonomy'],
1176 'terms' => array( $query_vars['term'] ),
1177 'field' => 'slug',
1178 );
1179 }
1180
1181 foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) {
1182 if ( 'post_tag' === $taxonomy ) {
1183 continue; // Handled further down in the $query_vars['tag'] block.
1184 }
1185
1186 if ( $t->query_var && ! empty( $query_vars[ $t->query_var ] ) ) {
1187 $tax_query_defaults = array(
1188 'taxonomy' => $taxonomy,
1189 'field' => 'slug',
1190 );
1191
1192 if ( ! empty( $t->rewrite['hierarchical'] ) ) {
1193 $query_vars[ $t->query_var ] = wp_basename( $query_vars[ $t->query_var ] );
1194 }
1195
1196 $term = $query_vars[ $t->query_var ];
1197
1198 if ( ! is_array( $term ) ) {
1199 $term = explode( ',', $term );
1200 $term = array_map( 'trim', $term );
1201 }
1202 sort( $term );
1203 $term = implode( ',', $term );
1204
1205 if ( str_contains( $term, '+' ) ) {
1206 $terms = preg_split( '/[+]+/', $term );
1207 foreach ( $terms as $term ) {
1208 $tax_query[] = array_merge(
1209 $tax_query_defaults,
1210 array(
1211 'terms' => array( $term ),
1212 )
1213 );
1214 }
1215 } else {
1216 $tax_query[] = array_merge(
1217 $tax_query_defaults,
1218 array(
1219 'terms' => preg_split( '/[,]+/', $term ),
1220 )
1221 );
1222 }
1223 }
1224 }
1225
1226 // If query string 'cat' is an array, implode it.
1227 if ( is_array( $query_vars['cat'] ) ) {
1228 $query_vars['cat'] = implode( ',', $query_vars['cat'] );
1229 }
1230
1231 // Category stuff.
1232
1233 if ( ! empty( $query_vars['cat'] ) && ! $this->is_singular ) {
1234 $cat_in = array();
1235 $cat_not_in = array();
1236
1237 $cat_array = preg_split( '/[,\s]+/', urldecode( $query_vars['cat'] ) );
1238 $cat_array = array_map( 'intval', $cat_array );
1239 sort( $cat_array );
1240 $query_vars['cat'] = implode( ',', $cat_array );
1241
1242 foreach ( $cat_array as $cat ) {
1243 if ( $cat > 0 ) {
1244 $cat_in[] = $cat;
1245 } elseif ( $cat < 0 ) {
1246 $cat_not_in[] = abs( $cat );
1247 }
1248 }
1249
1250 if ( ! empty( $cat_in ) ) {
1251 $tax_query[] = array(
1252 'taxonomy' => 'category',
1253 'terms' => $cat_in,
1254 'field' => 'term_id',
1255 'include_children' => true,
1256 );
1257 }
1258
1259 if ( ! empty( $cat_not_in ) ) {
1260 $tax_query[] = array(
1261 'taxonomy' => 'category',
1262 'terms' => $cat_not_in,
1263 'field' => 'term_id',
1264 'operator' => 'NOT IN',
1265 'include_children' => true,
1266 );
1267 }
1268 unset( $cat_array, $cat_in, $cat_not_in );
1269 }
1270
1271 if ( ! empty( $query_vars['category__and'] ) && 1 === count( (array) $query_vars['category__and'] ) ) {
1272 $query_vars['category__and'] = (array) $query_vars['category__and'];
1273 if ( ! isset( $query_vars['category__in'] ) ) {
1274 $query_vars['category__in'] = array();
1275 }
1276 $query_vars['category__in'][] = absint( reset( $query_vars['category__and'] ) );
1277 unset( $query_vars['category__and'] );
1278 }
1279
1280 if ( ! empty( $query_vars['category__in'] ) ) {
1281 $query_vars['category__in'] = array_map( 'absint', array_unique( (array) $query_vars['category__in'] ) );
1282 sort( $query_vars['category__in'] );
1283 $tax_query[] = array(
1284 'taxonomy' => 'category',
1285 'terms' => $query_vars['category__in'],
1286 'field' => 'term_id',
1287 'include_children' => false,
1288 );
1289 }
1290
1291 if ( ! empty( $query_vars['category__not_in'] ) ) {
1292 $query_vars['category__not_in'] = array_map( 'absint', array_unique( (array) $query_vars['category__not_in'] ) );
1293 sort( $query_vars['category__not_in'] );
1294 $tax_query[] = array(
1295 'taxonomy' => 'category',
1296 'terms' => $query_vars['category__not_in'],
1297 'operator' => 'NOT IN',
1298 'include_children' => false,
1299 );
1300 }
1301
1302 if ( ! empty( $query_vars['category__and'] ) ) {
1303 $query_vars['category__and'] = array_map( 'absint', array_unique( (array) $query_vars['category__and'] ) );
1304 sort( $query_vars['category__and'] );
1305 $tax_query[] = array(
1306 'taxonomy' => 'category',
1307 'terms' => $query_vars['category__and'],
1308 'field' => 'term_id',
1309 'operator' => 'AND',
1310 'include_children' => false,
1311 );
1312 }
1313
1314 // If query string 'tag' is array, implode it.
1315 if ( is_array( $query_vars['tag'] ) ) {
1316 $query_vars['tag'] = implode( ',', $query_vars['tag'] );
1317 }
1318
1319 // Tag stuff.
1320
1321 if ( '' !== $query_vars['tag'] && ! $this->is_singular && $this->query_vars_changed ) {
1322 if ( str_contains( $query_vars['tag'], ',' ) ) {
1323 // @todo Handle normalizing `tag` query string.
1324 $tags = preg_split( '/[,\r\n\t ]+/', $query_vars['tag'] );
1325 foreach ( (array) $tags as $tag ) {
1326 $tag = sanitize_term_field( 'slug', $tag, 0, 'post_tag', 'db' );
1327 $query_vars['tag_slug__in'][] = $tag;
1328 sort( $query_vars['tag_slug__in'] );
1329 }
1330 } elseif ( preg_match( '/[+\r\n\t ]+/', $query_vars['tag'] ) || ! empty( $query_vars['cat'] ) ) {
1331 $tags = preg_split( '/[+\r\n\t ]+/', $query_vars['tag'] );
1332 foreach ( (array) $tags as $tag ) {
1333 $tag = sanitize_term_field( 'slug', $tag, 0, 'post_tag', 'db' );
1334 $query_vars['tag_slug__and'][] = $tag;
1335 }
1336 } else {
1337 $query_vars['tag'] = sanitize_term_field( 'slug', $query_vars['tag'], 0, 'post_tag', 'db' );
1338 $query_vars['tag_slug__in'][] = $query_vars['tag'];
1339 sort( $query_vars['tag_slug__in'] );
1340 }
1341 }
1342
1343 if ( ! empty( $query_vars['tag_id'] ) ) {
1344 $query_vars['tag_id'] = absint( $query_vars['tag_id'] );
1345 $tax_query[] = array(
1346 'taxonomy' => 'post_tag',
1347 'terms' => $query_vars['tag_id'],
1348 );
1349 }
1350
1351 if ( ! empty( $query_vars['tag__in'] ) ) {
1352 $query_vars['tag__in'] = array_map( 'absint', array_unique( (array) $query_vars['tag__in'] ) );
1353 sort( $query_vars['tag__in'] );
1354 $tax_query[] = array(
1355 'taxonomy' => 'post_tag',
1356 'terms' => $query_vars['tag__in'],
1357 );
1358 }
1359
1360 if ( ! empty( $query_vars['tag__not_in'] ) ) {
1361 $query_vars['tag__not_in'] = array_map( 'absint', array_unique( (array) $query_vars['tag__not_in'] ) );
1362 sort( $query_vars['tag__not_in'] );
1363 $tax_query[] = array(
1364 'taxonomy' => 'post_tag',
1365 'terms' => $query_vars['tag__not_in'],
1366 'operator' => 'NOT IN',
1367 );
1368 }
1369
1370 if ( ! empty( $query_vars['tag__and'] ) ) {
1371 $query_vars['tag__and'] = array_map( 'absint', array_unique( (array) $query_vars['tag__and'] ) );
1372 sort( $query_vars['tag__and'] );
1373 $tax_query[] = array(
1374 'taxonomy' => 'post_tag',
1375 'terms' => $query_vars['tag__and'],
1376 'operator' => 'AND',
1377 );
1378 }
1379
1380 if ( ! empty( $query_vars['tag_slug__in'] ) ) {
1381 $query_vars['tag_slug__in'] = array_map( 'sanitize_title_for_query', array_unique( (array) $query_vars['tag_slug__in'] ) );
1382 sort( $query_vars['tag_slug__in'] );
1383 $tax_query[] = array(
1384 'taxonomy' => 'post_tag',
1385 'terms' => $query_vars['tag_slug__in'],
1386 'field' => 'slug',
1387 );
1388 }
1389
1390 if ( ! empty( $query_vars['tag_slug__and'] ) ) {
1391 $query_vars['tag_slug__and'] = array_map( 'sanitize_title_for_query', array_unique( (array) $query_vars['tag_slug__and'] ) );
1392 sort( $query_vars['tag_slug__and'] );
1393 $tax_query[] = array(
1394 'taxonomy' => 'post_tag',
1395 'terms' => $query_vars['tag_slug__and'],
1396 'field' => 'slug',
1397 'operator' => 'AND',
1398 );
1399 }
1400
1401 $this->tax_query = new WP_Tax_Query( $tax_query );
1402
1403 /**
1404 * Fires after taxonomy-related query vars have been parsed.
1405 *
1406 * @since 3.7.0
1407 *
1408 * @param WP_Query $query The WP_Query instance.
1409 */
1410 do_action( 'parse_tax_query', $this );
1411 }
1412
1413 /**
1414 * Generates SQL for the WHERE clause based on passed search terms.
1415 *
1416 * @since 3.7.0
1417 *
1418 * @global wpdb $wpdb WordPress database abstraction object.
1419 *
1420 * @param array $query_vars Query variables.
1421 * @return string WHERE clause.
1422 */
1423 protected function parse_search( &$query_vars ) {
1424 global $wpdb;
1425
1426 $search = '';
1427
1428 // Added slashes screw with quote grouping when done early, so done later.
1429 $query_vars['s'] = stripslashes( $query_vars['s'] );
1430 if ( empty( $_GET['s'] ) && $this->is_main_query() ) {
1431 $query_vars['s'] = urldecode( $query_vars['s'] );
1432 }
1433 // There are no line breaks in <input /> fields.
1434 $query_vars['s'] = str_replace( array( "\r", "\n" ), '', $query_vars['s'] );
1435 $query_vars['search_terms_count'] = 1;
1436 if ( ! empty( $query_vars['sentence'] ) ) {
1437 $query_vars['search_terms'] = array( $query_vars['s'] );
1438 } else {
1439 if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $query_vars['s'], $matches ) ) {
1440 $query_vars['search_terms_count'] = count( $matches[0] );
1441 $query_vars['search_terms'] = $this->parse_search_terms( $matches[0] );
1442 // If the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence.
1443 if ( empty( $query_vars['search_terms'] ) || count( $query_vars['search_terms'] ) > 9 ) {
1444 $query_vars['search_terms'] = array( $query_vars['s'] );
1445 }
1446 } else {
1447 $query_vars['search_terms'] = array( $query_vars['s'] );
1448 }
1449 }
1450
1451 $n = ! empty( $query_vars['exact'] ) ? '' : '%';
1452 $searchand = '';
1453 $query_vars['search_orderby_title'] = array();
1454
1455 $default_search_columns = array( 'post_title', 'post_excerpt', 'post_content' );
1456 $search_columns = ! empty( $query_vars['search_columns'] ) ? $query_vars['search_columns'] : $default_search_columns;
1457 if ( ! is_array( $search_columns ) ) {
1458 $search_columns = array( $search_columns );
1459 }
1460
1461 /**
1462 * Filters the columns to search in a WP_Query search.
1463 *
1464 * The supported columns are `post_title`, `post_excerpt` and `post_content`.
1465 * They are all included by default.
1466 *
1467 * @since 6.2.0
1468 *
1469 * @param string[] $search_columns Array of column names to be searched.
1470 * @param string $search Text being searched.
1471 * @param WP_Query $query The current WP_Query instance.
1472 */
1473 $search_columns = (array) apply_filters( 'post_search_columns', $search_columns, $query_vars['s'], $this );
1474
1475 // Use only supported search columns.
1476 $search_columns = array_intersect( $search_columns, $default_search_columns );
1477 if ( empty( $search_columns ) ) {
1478 $search_columns = $default_search_columns;
1479 }
1480
1481 /**
1482 * Filters the prefix that indicates that a search term should be excluded from results.
1483 *
1484 * @since 4.7.0
1485 *
1486 * @param string $exclusion_prefix The prefix. Default '-'. Returning
1487 * an empty value disables exclusions.
1488 */
1489 $exclusion_prefix = apply_filters( 'wp_query_search_exclusion_prefix', '-' );
1490
1491 foreach ( $query_vars['search_terms'] as $term ) {
1492 // If there is an $exclusion_prefix, terms prefixed with it should be excluded.
1493 $exclude = $exclusion_prefix && str_starts_with( $term, $exclusion_prefix );
1494 if ( $exclude ) {
1495 $like_op = 'NOT LIKE';
1496 $andor_op = 'AND';
1497 $term = substr( $term, 1 );
1498 } else {
1499 $like_op = 'LIKE';
1500 $andor_op = 'OR';
1501 }
1502
1503 if ( $n && ! $exclude ) {
1504 $like = '%' . $wpdb->esc_like( $term ) . '%';
1505 $query_vars['search_orderby_title'][] = $wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", $like );
1506 }
1507
1508 $like = $n . $wpdb->esc_like( $term ) . $n;
1509
1510 $search_columns_parts = array();
1511 foreach ( $search_columns as $search_column ) {
1512 $search_columns_parts[ $search_column ] = $wpdb->prepare( "({$wpdb->posts}.$search_column $like_op %s)", $like );
1513 }
1514
1515 if ( ! empty( $this->allow_query_attachment_by_filename ) ) {
1516 $search_columns_parts['attachment'] = $wpdb->prepare( "(sq1.meta_value $like_op %s)", $like );
1517 }
1518
1519 $search .= "$searchand(" . implode( " $andor_op ", $search_columns_parts ) . ')';
1520
1521 $searchand = ' AND ';
1522 }
1523
1524 if ( ! empty( $search ) ) {
1525 $search = " AND ({$search}) ";
1526 if ( ! is_user_logged_in() ) {
1527 $search .= " AND ({$wpdb->posts}.post_password = '') ";
1528 }
1529 }
1530
1531 return $search;
1532 }
1533
1534 /**
1535 * Checks if the terms are suitable for searching.
1536 *
1537 * Uses an array of stopwords (terms) that are excluded from the separate
1538 * term matching when searching for posts. The list of English stopwords is
1539 * the approximate search engines list, and is translatable.
1540 *
1541 * @since 3.7.0
1542 *
1543 * @param string[] $terms Array of terms to check.
1544 * @return string[] Terms that are not stopwords.
1545 */
1546 protected function parse_search_terms( $terms ) {
1547 $strtolower = function_exists( 'mb_strtolower' ) ? 'mb_strtolower' : 'strtolower';
1548 $checked = array();
1549
1550 $stopwords = $this->get_search_stopwords();
1551
1552 foreach ( $terms as $term ) {
1553 // Keep before/after spaces when term is for exact match.
1554 if ( preg_match( '/^".+"$/', $term ) ) {
1555 $term = trim( $term, "\"'" );
1556 } else {
1557 $term = trim( $term, "\"' " );
1558 }
1559
1560 // Avoid single A-Z and single dashes.
1561 if ( ! $term || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) ) {
1562 continue;
1563 }
1564
1565 if ( in_array( call_user_func( $strtolower, $term ), $stopwords, true ) ) {
1566 continue;
1567 }
1568
1569 $checked[] = $term;
1570 }
1571
1572 return $checked;
1573 }
1574
1575 /**
1576 * Retrieves stopwords used when parsing search terms.
1577 *
1578 * @since 3.7.0
1579 *
1580 * @return string[] Stopwords.
1581 */
1582 protected function get_search_stopwords() {
1583 if ( isset( $this->stopwords ) ) {
1584 return $this->stopwords;
1585 }
1586
1587 /*
1588 * translators: This is a comma-separated list of very common words that should be excluded from a search,
1589 * like a, an, and the. These are usually called "stopwords". You should not simply translate these individual
1590 * words into your language. Instead, look for and provide commonly accepted stopwords in your language.
1591 */
1592 $words = explode(
1593 ',',
1594 _x(
1595 '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',
1596 'Comma-separated list of search stopwords in your language'
1597 )
1598 );
1599
1600 $stopwords = array();
1601 foreach ( $words as $word ) {
1602 $word = trim( $word, "\r\n\t " );
1603 if ( $word ) {
1604 $stopwords[] = $word;
1605 }
1606 }
1607
1608 /**
1609 * Filters stopwords used when parsing search terms.
1610 *
1611 * @since 3.7.0
1612 *
1613 * @param string[] $stopwords Array of stopwords.
1614 */
1615 $this->stopwords = apply_filters( 'wp_search_stopwords', $stopwords );
1616 return $this->stopwords;
1617 }
1618
1619 /**
1620 * Generates SQL for the ORDER BY condition based on passed search terms.
1621 *
1622 * @since 3.7.0
1623 *
1624 * @global wpdb $wpdb WordPress database abstraction object.
1625 *
1626 * @param array $query_vars Query variables.
1627 * @return string ORDER BY clause.
1628 */
1629 protected function parse_search_order( &$query_vars ) {
1630 global $wpdb;
1631
1632 if ( $query_vars['search_terms_count'] > 1 ) {
1633 $num_terms = count( $query_vars['search_orderby_title'] );
1634
1635 // If the search terms contain negative queries, don't bother ordering by sentence matches.
1636 $like = '';
1637 if ( ! preg_match( '/(?:\s|^)\-/', $query_vars['s'] ) ) {
1638 $like = '%' . $wpdb->esc_like( $query_vars['s'] ) . '%';
1639 }
1640
1641 $search_orderby = '';
1642
1643 // Sentence match in 'post_title'.
1644 if ( $like ) {
1645 $search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_title LIKE %s THEN 1 ", $like );
1646 }
1647
1648 /*
1649 * Sanity limit, sort as sentence when more than 6 terms
1650 * (few searches are longer than 6 terms and most titles are not).
1651 */
1652 if ( $num_terms < 7 ) {
1653 // All words in title.
1654 $search_orderby .= 'WHEN ' . implode( ' AND ', $query_vars['search_orderby_title'] ) . ' THEN 2 ';
1655 // Any word in title, not needed when $num_terms == 1.
1656 if ( $num_terms > 1 ) {
1657 $search_orderby .= 'WHEN ' . implode( ' OR ', $query_vars['search_orderby_title'] ) . ' THEN 3 ';
1658 }
1659 }
1660
1661 // Sentence match in 'post_content' and 'post_excerpt'.
1662 if ( $like ) {
1663 $search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_excerpt LIKE %s THEN 4 ", $like );
1664 $search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_content LIKE %s THEN 5 ", $like );
1665 }
1666
1667 if ( $search_orderby ) {
1668 $search_orderby = '(CASE ' . $search_orderby . 'ELSE 6 END)';
1669 }
1670 } else {
1671 // Single word or sentence search.
1672 $search_orderby = reset( $query_vars['search_orderby_title'] ) . ' DESC';
1673 }
1674
1675 return $search_orderby;
1676 }
1677
1678 /**
1679 * Converts the given orderby alias (if allowed) to a properly-prefixed value.
1680 *
1681 * @since 4.0.0
1682 *
1683 * @global wpdb $wpdb WordPress database abstraction object.
1684 *
1685 * @param string $orderby Alias for the field to order by.
1686 * @return string|false Table-prefixed value to used in the ORDER clause. False otherwise.
1687 */
1688 protected function parse_orderby( $orderby ) {
1689 global $wpdb;
1690
1691 // Used to filter values.
1692 $allowed_keys = array(
1693 'post_name',
1694 'post_author',
1695 'post_date',
1696 'post_title',
1697 'post_modified',
1698 'post_parent',
1699 'post_type',
1700 'name',
1701 'author',
1702 'date',
1703 'title',
1704 'modified',
1705 'parent',
1706 'type',
1707 'ID',
1708 'menu_order',
1709 'comment_count',
1710 'rand',
1711 'post__in',
1712 'post_parent__in',
1713 'post_name__in',
1714 );
1715
1716 $primary_meta_key = '';
1717 $primary_meta_query = false;
1718 $meta_clauses = $this->meta_query->get_clauses();
1719 if ( ! empty( $meta_clauses ) ) {
1720 $primary_meta_query = reset( $meta_clauses );
1721
1722 if ( ! empty( $primary_meta_query['key'] ) ) {
1723 $primary_meta_key = $primary_meta_query['key'];
1724 $allowed_keys[] = $primary_meta_key;
1725 }
1726
1727 $allowed_keys[] = 'meta_value';
1728 $allowed_keys[] = 'meta_value_num';
1729 $allowed_keys = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
1730 }
1731
1732 // If RAND() contains a seed value, sanitize and add to allowed keys.
1733 $rand_with_seed = false;
1734 if ( preg_match( '/RAND\(([0-9]+)\)/i', $orderby, $matches ) ) {
1735 $orderby = sprintf( 'RAND(%s)', (int) $matches[1] );
1736 $allowed_keys[] = $orderby;
1737 $rand_with_seed = true;
1738 }
1739
1740 if ( ! in_array( $orderby, $allowed_keys, true ) ) {
1741 return false;
1742 }
1743
1744 $orderby_clause = '';
1745
1746 switch ( $orderby ) {
1747 case 'post_name':
1748 case 'post_author':
1749 case 'post_date':
1750 case 'post_title':
1751 case 'post_modified':
1752 case 'post_parent':
1753 case 'post_type':
1754 case 'ID':
1755 case 'menu_order':
1756 case 'comment_count':
1757 $orderby_clause = "{$wpdb->posts}.{$orderby}";
1758 break;
1759 case 'rand':
1760 $orderby_clause = 'RAND()';
1761 break;
1762 case $primary_meta_key:
1763 case 'meta_value':
1764 if ( ! empty( $primary_meta_query['type'] ) ) {
1765 $orderby_clause = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
1766 } else {
1767 $orderby_clause = "{$primary_meta_query['alias']}.meta_value";
1768 }
1769 break;
1770 case 'meta_value_num':
1771 $orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
1772 break;
1773 case 'post__in':
1774 if ( ! empty( $this->query_vars['post__in'] ) ) {
1775 $orderby_clause = "FIELD({$wpdb->posts}.ID," . implode( ',', array_map( 'absint', $this->query_vars['post__in'] ) ) . ')';
1776 }
1777 break;
1778 case 'post_parent__in':
1779 if ( ! empty( $this->query_vars['post_parent__in'] ) ) {
1780 $orderby_clause = "FIELD( {$wpdb->posts}.post_parent," . implode( ', ', array_map( 'absint', $this->query_vars['post_parent__in'] ) ) . ' )';
1781 }
1782 break;
1783 case 'post_name__in':
1784 if ( ! empty( $this->query_vars['post_name__in'] ) ) {
1785 $post_name__in = array_map( 'sanitize_title_for_query', $this->query_vars['post_name__in'] );
1786 $post_name__in_string = "'" . implode( "','", $post_name__in ) . "'";
1787 $orderby_clause = "FIELD( {$wpdb->posts}.post_name," . $post_name__in_string . ' )';
1788 }
1789 break;
1790 default:
1791 if ( array_key_exists( $orderby, $meta_clauses ) ) {
1792 // $orderby corresponds to a meta_query clause.
1793 $meta_clause = $meta_clauses[ $orderby ];
1794 $orderby_clause = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
1795 } elseif ( $rand_with_seed ) {
1796 $orderby_clause = $orderby;
1797 } else {
1798 // Default: order by post field.
1799 $orderby_clause = "{$wpdb->posts}.post_" . sanitize_key( $orderby );
1800 }
1801
1802 break;
1803 }
1804
1805 return $orderby_clause;
1806 }
1807
1808 /**
1809 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
1810 *
1811 * @since 4.0.0
1812 *
1813 * @param string $order The 'order' query variable.
1814 * @return string The sanitized 'order' query variable.
1815 */
1816 protected function parse_order( $order ) {
1817 if ( ! is_string( $order ) || empty( $order ) ) {
1818 return 'DESC';
1819 }
1820
1821 if ( 'ASC' === strtoupper( $order ) ) {
1822 return 'ASC';
1823 } else {
1824 return 'DESC';
1825 }
1826 }
1827
1828 /**
1829 * Sets the 404 property and saves whether query is feed.
1830 *
1831 * @since 2.0.0
1832 */
1833 public function set_404() {
1834 $is_feed = $this->is_feed;
1835
1836 $this->init_query_flags();
1837 $this->is_404 = true;
1838
1839 $this->is_feed = $is_feed;
1840
1841 /**
1842 * Fires after a 404 is triggered.
1843 *
1844 * @since 5.5.0
1845 *
1846 * @param WP_Query $query The WP_Query instance (passed by reference).
1847 */
1848 do_action_ref_array( 'set_404', array( $this ) );
1849 }
1850
1851 /**
1852 * Retrieves the value of a query variable.
1853 *
1854 * @since 1.5.0
1855 * @since 3.9.0 The `$default_value` argument was introduced.
1856 *
1857 * @param string $query_var Query variable key.
1858 * @param mixed $default_value Optional. Value to return if the query variable is not set.
1859 * Default empty string.
1860 * @return mixed Contents of the query variable.
1861 */
1862 public function get( $query_var, $default_value = '' ) {
1863 if ( isset( $this->query_vars[ $query_var ] ) ) {
1864 return $this->query_vars[ $query_var ];
1865 }
1866
1867 return $default_value;
1868 }
1869
1870 /**
1871 * Sets the value of a query variable.
1872 *
1873 * @since 1.5.0
1874 *
1875 * @param string $query_var Query variable key.
1876 * @param mixed $value Query variable value.
1877 */
1878 public function set( $query_var, $value ) {
1879 $this->query_vars[ $query_var ] = $value;
1880 }
1881
1882 /**
1883 * Retrieves an array of posts based on query variables.
1884 *
1885 * There are a few filters and actions that can be used to modify the post
1886 * database query.
1887 *
1888 * @since 1.5.0
1889 *
1890 * @global wpdb $wpdb WordPress database abstraction object.
1891 *
1892 * @return WP_Post[]|int[] Array of post objects or post IDs.
1893 */
1894 public function get_posts() {
1895 global $wpdb;
1896
1897 $this->parse_query();
1898
1899 /**
1900 * Fires after the query variable object is created, but before the actual query is run.
1901 *
1902 * Note: If using conditional tags, use the method versions within the passed instance
1903 * (e.g. $this->is_main_query() instead of is_main_query()). This is because the functions
1904 * like is_main_query() test against the global $wp_query instance, not the passed one.
1905 *
1906 * @since 2.0.0
1907 *
1908 * @param WP_Query $query The WP_Query instance (passed by reference).
1909 */
1910 do_action_ref_array( 'pre_get_posts', array( &$this ) );
1911
1912 // Locally scoped reference for easy of use.
1913 $query_vars = &$this->query_vars;
1914
1915 // Fill again in case 'pre_get_posts' unset some vars.
1916 $query_vars = $this->fill_query_vars( $query_vars );
1917
1918 /**
1919 * Filters whether an attachment query should include filenames or not.
1920 *
1921 * @since 6.0.3
1922 *
1923 * @param bool $allow_query_attachment_by_filename Whether or not to include filenames.
1924 */
1925 $this->allow_query_attachment_by_filename = apply_filters( 'wp_allow_query_attachment_by_filename', false );
1926 remove_all_filters( 'wp_allow_query_attachment_by_filename' );
1927
1928 // Parse meta query.
1929 $this->meta_query = new WP_Meta_Query();
1930 $this->meta_query->parse_query_vars( $query_vars );
1931
1932 // Set a flag if a 'pre_get_posts' hook changed the query vars.
1933 $hash = md5( serialize( $this->query_vars ) );
1934 if ( $hash !== $this->query_vars_hash ) {
1935 $this->query_vars_changed = true;
1936 $this->query_vars_hash = $hash;
1937 }
1938 unset( $hash );
1939
1940 // First let's clear some variables.
1941 $distinct = '';
1942 $whichauthor = '';
1943 $whichmimetype = '';
1944 $where = '';
1945 $limits = '';
1946 $join = '';
1947 $search = '';
1948 $groupby = '';
1949 $post_status_join = false;
1950 $page = 1;
1951
1952 if ( isset( $query_vars['caller_get_posts'] ) ) {
1953 _deprecated_argument(
1954 'WP_Query',
1955 '3.1.0',
1956 sprintf(
1957 /* translators: 1: caller_get_posts, 2: ignore_sticky_posts */
1958 __( '%1$s is deprecated. Use %2$s instead.' ),
1959 '<code>caller_get_posts</code>',
1960 '<code>ignore_sticky_posts</code>'
1961 )
1962 );
1963
1964 if ( ! isset( $query_vars['ignore_sticky_posts'] ) ) {
1965 $query_vars['ignore_sticky_posts'] = $query_vars['caller_get_posts'];
1966 }
1967 }
1968
1969 if ( ! isset( $query_vars['ignore_sticky_posts'] ) ) {
1970 $query_vars['ignore_sticky_posts'] = false;
1971 }
1972
1973 if ( ! isset( $query_vars['suppress_filters'] ) ) {
1974 $query_vars['suppress_filters'] = false;
1975 }
1976
1977 if ( ! isset( $query_vars['cache_results'] ) ) {
1978 $query_vars['cache_results'] = true;
1979 }
1980
1981 if ( ! isset( $query_vars['update_post_term_cache'] ) ) {
1982 $query_vars['update_post_term_cache'] = true;
1983 }
1984
1985 if ( ! isset( $query_vars['update_menu_item_cache'] ) ) {
1986 $query_vars['update_menu_item_cache'] = false;
1987 }
1988
1989 if ( ! isset( $query_vars['lazy_load_term_meta'] ) ) {
1990 $query_vars['lazy_load_term_meta'] = $query_vars['update_post_term_cache'];
1991 } elseif ( $query_vars['lazy_load_term_meta'] ) { // Lazy loading term meta only works if term caches are primed.
1992 $query_vars['update_post_term_cache'] = true;
1993 }
1994
1995 if ( ! isset( $query_vars['update_post_meta_cache'] ) ) {
1996 $query_vars['update_post_meta_cache'] = true;
1997 }
1998
1999 if ( ! isset( $query_vars['post_type'] ) ) {
2000 if ( $this->is_search ) {
2001 $query_vars['post_type'] = 'any';
2002 } else {
2003 $query_vars['post_type'] = '';
2004 }
2005 }
2006 $post_type = $query_vars['post_type'];
2007 if ( empty( $query_vars['posts_per_page'] ) ) {
2008 $query_vars['posts_per_page'] = get_option( 'posts_per_page' );
2009 }
2010 if ( isset( $query_vars['showposts'] ) && $query_vars['showposts'] ) {
2011 $query_vars['showposts'] = (int) $query_vars['showposts'];
2012 $query_vars['posts_per_page'] = $query_vars['showposts'];
2013 }
2014 if ( ( isset( $query_vars['posts_per_archive_page'] ) && 0 != $query_vars['posts_per_archive_page'] ) && ( $this->is_archive || $this->is_search ) ) {
2015 $query_vars['posts_per_page'] = $query_vars['posts_per_archive_page'];
2016 }
2017 if ( ! isset( $query_vars['nopaging'] ) ) {
2018 if ( -1 == $query_vars['posts_per_page'] ) {
2019 $query_vars['nopaging'] = true;
2020 } else {
2021 $query_vars['nopaging'] = false;
2022 }
2023 }
2024
2025 if ( $this->is_feed ) {
2026 // This overrides 'posts_per_page'.
2027 if ( ! empty( $query_vars['posts_per_rss'] ) ) {
2028 $query_vars['posts_per_page'] = $query_vars['posts_per_rss'];
2029 } else {
2030 $query_vars['posts_per_page'] = get_option( 'posts_per_rss' );
2031 }
2032 $query_vars['nopaging'] = false;
2033 }
2034
2035 $query_vars['posts_per_page'] = (int) $query_vars['posts_per_page'];
2036 if ( $query_vars['posts_per_page'] < -1 ) {
2037 $query_vars['posts_per_page'] = abs( $query_vars['posts_per_page'] );
2038 } elseif ( 0 === $query_vars['posts_per_page'] ) {
2039 $query_vars['posts_per_page'] = 1;
2040 }
2041
2042 if ( ! isset( $query_vars['comments_per_page'] ) || 0 == $query_vars['comments_per_page'] ) {
2043 $query_vars['comments_per_page'] = get_option( 'comments_per_page' );
2044 }
2045
2046 if ( $this->is_home && ( empty( $this->query ) || 'true' === $query_vars['preview'] ) && ( 'page' === get_option( 'show_on_front' ) ) && get_option( 'page_on_front' ) ) {
2047 $this->is_page = true;
2048 $this->is_home = false;
2049 $query_vars['page_id'] = get_option( 'page_on_front' );
2050 }
2051
2052 if ( isset( $query_vars['page'] ) ) {
2053 $query_vars['page'] = is_scalar( $query_vars['page'] ) ? absint( trim( $query_vars['page'], '/' ) ) : 0;
2054 }
2055
2056 // If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
2057 if ( isset( $query_vars['no_found_rows'] ) ) {
2058 $query_vars['no_found_rows'] = (bool) $query_vars['no_found_rows'];
2059 } else {
2060 $query_vars['no_found_rows'] = false;
2061 }
2062
2063 switch ( $query_vars['fields'] ) {
2064 case 'ids':
2065 $fields = "{$wpdb->posts}.ID";
2066 break;
2067 case 'id=>parent':
2068 $fields = "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent";
2069 break;
2070 case '':
2071 /*
2072 * Set the default to 'all'.
2073 *
2074 * This is used in `WP_Query::the_post` to determine if the
2075 * entire post object has been queried.
2076 */
2077 $query_vars['fields'] = 'all';
2078 // Falls through.
2079 default:
2080 $fields = "{$wpdb->posts}.*";
2081 }
2082
2083 if ( '' !== $query_vars['menu_order'] ) {
2084 $where .= " AND {$wpdb->posts}.menu_order = " . $query_vars['menu_order'];
2085 }
2086 // The "m" parameter is meant for months but accepts datetimes of varying specificity.
2087 if ( $query_vars['m'] ) {
2088 $where .= " AND YEAR({$wpdb->posts}.post_date)=" . substr( $query_vars['m'], 0, 4 );
2089 if ( strlen( $query_vars['m'] ) > 5 ) {
2090 $where .= " AND MONTH({$wpdb->posts}.post_date)=" . substr( $query_vars['m'], 4, 2 );
2091 }
2092 if ( strlen( $query_vars['m'] ) > 7 ) {
2093 $where .= " AND DAYOFMONTH({$wpdb->posts}.post_date)=" . substr( $query_vars['m'], 6, 2 );
2094 }
2095 if ( strlen( $query_vars['m'] ) > 9 ) {
2096 $where .= " AND HOUR({$wpdb->posts}.post_date)=" . substr( $query_vars['m'], 8, 2 );
2097 }
2098 if ( strlen( $query_vars['m'] ) > 11 ) {
2099 $where .= " AND MINUTE({$wpdb->posts}.post_date)=" . substr( $query_vars['m'], 10, 2 );
2100 }
2101 if ( strlen( $query_vars['m'] ) > 13 ) {
2102 $where .= " AND SECOND({$wpdb->posts}.post_date)=" . substr( $query_vars['m'], 12, 2 );
2103 }
2104 }
2105
2106 // Handle the other individual date parameters.
2107 $date_parameters = array();
2108
2109 if ( '' !== $query_vars['hour'] ) {
2110 $date_parameters['hour'] = $query_vars['hour'];
2111 }
2112
2113 if ( '' !== $query_vars['minute'] ) {
2114 $date_parameters['minute'] = $query_vars['minute'];
2115 }
2116
2117 if ( '' !== $query_vars['second'] ) {
2118 $date_parameters['second'] = $query_vars['second'];
2119 }
2120
2121 if ( $query_vars['year'] ) {
2122 $date_parameters['year'] = $query_vars['year'];
2123 }
2124
2125 if ( $query_vars['monthnum'] ) {
2126 $date_parameters['monthnum'] = $query_vars['monthnum'];
2127 }
2128
2129 if ( $query_vars['w'] ) {
2130 $date_parameters['week'] = $query_vars['w'];
2131 }
2132
2133 if ( $query_vars['day'] ) {
2134 $date_parameters['day'] = $query_vars['day'];
2135 }
2136
2137 if ( $date_parameters ) {
2138 $date_query = new WP_Date_Query( array( $date_parameters ) );
2139 $where .= $date_query->get_sql();
2140 }
2141 unset( $date_parameters, $date_query );
2142
2143 // Handle complex date queries.
2144 if ( ! empty( $query_vars['date_query'] ) ) {
2145 $this->date_query = new WP_Date_Query( $query_vars['date_query'] );
2146 $where .= $this->date_query->get_sql();
2147 }
2148
2149 // If we've got a post_type AND it's not "any" post_type.
2150 if ( ! empty( $query_vars['post_type'] ) && 'any' !== $query_vars['post_type'] ) {
2151 foreach ( (array) $query_vars['post_type'] as $_post_type ) {
2152 $ptype_obj = get_post_type_object( $_post_type );
2153 if ( ! $ptype_obj || ! $ptype_obj->query_var || empty( $query_vars[ $ptype_obj->query_var ] ) ) {
2154 continue;
2155 }
2156
2157 if ( ! $ptype_obj->hierarchical ) {
2158 // Non-hierarchical post types can directly use 'name'.
2159 $query_vars['name'] = $query_vars[ $ptype_obj->query_var ];
2160 } else {
2161 // Hierarchical post types will operate through 'pagename'.
2162 $query_vars['pagename'] = $query_vars[ $ptype_obj->query_var ];
2163 $query_vars['name'] = '';
2164 }
2165
2166 // Only one request for a slug is possible, this is why name & pagename are overwritten above.
2167 break;
2168 } // End foreach.
2169 unset( $ptype_obj );
2170 }
2171
2172 if ( '' !== $query_vars['title'] ) {
2173 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title = %s", stripslashes( $query_vars['title'] ) );
2174 }
2175
2176 // Parameters related to 'post_name'.
2177 if ( '' !== $query_vars['name'] ) {
2178 $query_vars['name'] = sanitize_title_for_query( $query_vars['name'] );
2179 $where .= " AND {$wpdb->posts}.post_name = '" . $query_vars['name'] . "'";
2180 } elseif ( '' !== $query_vars['pagename'] ) {
2181 if ( isset( $this->queried_object_id ) ) {
2182 $reqpage = $this->queried_object_id;
2183 } else {
2184 if ( 'page' !== $query_vars['post_type'] ) {
2185 foreach ( (array) $query_vars['post_type'] as $_post_type ) {
2186 $ptype_obj = get_post_type_object( $_post_type );
2187 if ( ! $ptype_obj || ! $ptype_obj->hierarchical ) {
2188 continue;
2189 }
2190
2191 $reqpage = get_page_by_path( $query_vars['pagename'], OBJECT, $_post_type );
2192 if ( $reqpage ) {
2193 break;
2194 }
2195 }
2196 unset( $ptype_obj );
2197 } else {
2198 $reqpage = get_page_by_path( $query_vars['pagename'] );
2199 }
2200 if ( ! empty( $reqpage ) ) {
2201 $reqpage = $reqpage->ID;
2202 } else {
2203 $reqpage = 0;
2204 }
2205 }
2206
2207 $page_for_posts = get_option( 'page_for_posts' );
2208 if ( ( 'page' !== get_option( 'show_on_front' ) ) || empty( $page_for_posts ) || ( $reqpage != $page_for_posts ) ) {
2209 $query_vars['pagename'] = sanitize_title_for_query( wp_basename( $query_vars['pagename'] ) );
2210 $query_vars['name'] = $query_vars['pagename'];
2211 $where .= " AND ({$wpdb->posts}.ID = '$reqpage')";
2212 $reqpage_obj = get_post( $reqpage );
2213 if ( is_object( $reqpage_obj ) && 'attachment' === $reqpage_obj->post_type ) {
2214 $this->is_attachment = true;
2215 $post_type = 'attachment';
2216 $query_vars['post_type'] = 'attachment';
2217 $this->is_page = true;
2218 $query_vars['attachment_id'] = $reqpage;
2219 }
2220 }
2221 } elseif ( '' !== $query_vars['attachment'] ) {
2222 $query_vars['attachment'] = sanitize_title_for_query( wp_basename( $query_vars['attachment'] ) );
2223 $query_vars['name'] = $query_vars['attachment'];
2224 $where .= " AND {$wpdb->posts}.post_name = '" . $query_vars['attachment'] . "'";
2225 } elseif ( is_array( $query_vars['post_name__in'] ) && ! empty( $query_vars['post_name__in'] ) ) {
2226 $query_vars['post_name__in'] = array_map( 'sanitize_title_for_query', $query_vars['post_name__in'] );
2227 // Duplicate array before sorting to allow for the orderby clause.
2228 $post_name__in_for_where = array_unique( $query_vars['post_name__in'] );
2229 sort( $post_name__in_for_where );
2230 $post_name__in = "'" . implode( "','", $post_name__in_for_where ) . "'";
2231 $where .= " AND {$wpdb->posts}.post_name IN ($post_name__in)";
2232 }
2233
2234 // If an attachment is requested by number, let it supersede any post number.
2235 if ( $query_vars['attachment_id'] ) {
2236 $query_vars['p'] = absint( $query_vars['attachment_id'] );
2237 }
2238
2239 // If a post number is specified, load that post.
2240 if ( $query_vars['p'] ) {
2241 $where .= " AND {$wpdb->posts}.ID = " . $query_vars['p'];
2242 } elseif ( $query_vars['post__in'] ) {
2243 // Duplicate array before sorting to allow for the orderby clause.
2244 $post__in_for_where = $query_vars['post__in'];
2245 $post__in_for_where = array_unique( array_map( 'absint', $post__in_for_where ) );
2246 sort( $post__in_for_where );
2247 $post__in = implode( ',', array_map( 'absint', $post__in_for_where ) );
2248 $where .= " AND {$wpdb->posts}.ID IN ($post__in)";
2249 } elseif ( $query_vars['post__not_in'] ) {
2250 sort( $query_vars['post__not_in'] );
2251 $post__not_in = implode( ',', array_map( 'absint', $query_vars['post__not_in'] ) );
2252 $where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
2253 }
2254
2255 if ( is_numeric( $query_vars['post_parent'] ) ) {
2256 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_parent = %d ", $query_vars['post_parent'] );
2257 } elseif ( $query_vars['post_parent__in'] ) {
2258 // Duplicate array before sorting to allow for the orderby clause.
2259 $post_parent__in_for_where = $query_vars['post_parent__in'];
2260 $post_parent__in_for_where = array_unique( array_map( 'absint', $post_parent__in_for_where ) );
2261 sort( $post_parent__in_for_where );
2262 $post_parent__in = implode( ',', array_map( 'absint', $post_parent__in_for_where ) );
2263 $where .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
2264 } elseif ( $query_vars['post_parent__not_in'] ) {
2265 sort( $query_vars['post_parent__not_in'] );
2266 $post_parent__not_in = implode( ',', array_map( 'absint', $query_vars['post_parent__not_in'] ) );
2267 $where .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
2268 }
2269
2270 if ( $query_vars['page_id'] ) {
2271 if ( ( 'page' !== get_option( 'show_on_front' ) ) || ( get_option( 'page_for_posts' ) != $query_vars['page_id'] ) ) {
2272 $query_vars['p'] = $query_vars['page_id'];
2273 $where = " AND {$wpdb->posts}.ID = " . $query_vars['page_id'];
2274 }
2275 }
2276
2277 // If a search pattern is specified, load the posts that match.
2278 if ( strlen( $query_vars['s'] ) ) {
2279 $search = $this->parse_search( $query_vars );
2280 }
2281
2282 if ( ! $query_vars['suppress_filters'] ) {
2283 /**
2284 * Filters the search SQL that is used in the WHERE clause of WP_Query.
2285 *
2286 * @since 3.0.0
2287 *
2288 * @param string $search Search SQL for WHERE clause.
2289 * @param WP_Query $query The current WP_Query object.
2290 */
2291 $search = apply_filters_ref_array( 'posts_search', array( $search, &$this ) );
2292 }
2293
2294 // Taxonomies.
2295 if ( ! $this->is_singular ) {
2296 $this->parse_tax_query( $query_vars );
2297
2298 $clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );
2299
2300 $join .= $clauses['join'];
2301 $where .= $clauses['where'];
2302 }
2303
2304 if ( $this->is_tax ) {
2305 if ( empty( $post_type ) ) {
2306 // Do a fully inclusive search for currently registered post types of queried taxonomies.
2307 $post_type = array();
2308 $taxonomies = array_keys( $this->tax_query->queried_terms );
2309 foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
2310 $object_taxonomies = 'attachment' === $pt ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
2311 if ( array_intersect( $taxonomies, $object_taxonomies ) ) {
2312 $post_type[] = $pt;
2313 }
2314 }
2315 if ( ! $post_type ) {
2316 $post_type = 'any';
2317 } elseif ( count( $post_type ) === 1 ) {
2318 $post_type = $post_type[0];
2319 } else {
2320 // Sort post types to ensure same cache key generation.
2321 sort( $post_type );
2322 }
2323
2324 $post_status_join = true;
2325 } elseif ( in_array( 'attachment', (array) $post_type, true ) ) {
2326 $post_status_join = true;
2327 }
2328 }
2329
2330 /*
2331 * Ensure that 'taxonomy', 'term', 'term_id', 'cat', and
2332 * 'category_name' vars are set for backward compatibility.
2333 */
2334 if ( ! empty( $this->tax_query->queried_terms ) ) {
2335
2336 /*
2337 * Set 'taxonomy', 'term', and 'term_id' to the
2338 * first taxonomy other than 'post_tag' or 'category'.
2339 */
2340 if ( ! isset( $query_vars['taxonomy'] ) ) {
2341 foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
2342 if ( empty( $queried_items['terms'][0] ) ) {
2343 continue;
2344 }
2345
2346 if ( ! in_array( $queried_taxonomy, array( 'category', 'post_tag' ), true ) ) {
2347 $query_vars['taxonomy'] = $queried_taxonomy;
2348
2349 if ( 'slug' === $queried_items['field'] ) {
2350 $query_vars['term'] = $queried_items['terms'][0];
2351 } else {
2352 $query_vars['term_id'] = $queried_items['terms'][0];
2353 }
2354
2355 // Take the first one we find.
2356 break;
2357 }
2358 }
2359 }
2360
2361 // 'cat', 'category_name', 'tag_id'.
2362 foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
2363 if ( empty( $queried_items['terms'][0] ) ) {
2364 continue;
2365 }
2366
2367 if ( 'category' === $queried_taxonomy ) {
2368 $the_cat = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'category' );
2369 if ( $the_cat ) {
2370 $this->set( 'cat', $the_cat->term_id );
2371 $this->set( 'category_name', $the_cat->slug );
2372 }
2373 unset( $the_cat );
2374 }
2375
2376 if ( 'post_tag' === $queried_taxonomy ) {
2377 $the_tag = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'post_tag' );
2378 if ( $the_tag ) {
2379 $this->set( 'tag_id', $the_tag->term_id );
2380 }
2381 unset( $the_tag );
2382 }
2383 }
2384 }
2385
2386 if ( ! empty( $this->tax_query->queries ) || ! empty( $this->meta_query->queries ) || ! empty( $this->allow_query_attachment_by_filename ) ) {
2387 $groupby = "{$wpdb->posts}.ID";
2388 }
2389
2390 // Author/user stuff.
2391
2392 if ( ! empty( $query_vars['author'] ) && '0' != $query_vars['author'] ) {
2393 $query_vars['author'] = addslashes_gpc( '' . urldecode( $query_vars['author'] ) );
2394 $authors = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $query_vars['author'] ) ) );
2395 sort( $authors );
2396 foreach ( $authors as $author ) {
2397 $key = $author > 0 ? 'author__in' : 'author__not_in';
2398 $query_vars[ $key ][] = abs( $author );
2399 }
2400 $query_vars['author'] = implode( ',', $authors );
2401 }
2402
2403 if ( ! empty( $query_vars['author__not_in'] ) ) {
2404 if ( is_array( $query_vars['author__not_in'] ) ) {
2405 $query_vars['author__not_in'] = array_unique( array_map( 'absint', $query_vars['author__not_in'] ) );
2406 sort( $query_vars['author__not_in'] );
2407 }
2408 $author__not_in = implode( ',', (array) $query_vars['author__not_in'] );
2409 $where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
2410 } elseif ( ! empty( $query_vars['author__in'] ) ) {
2411 if ( is_array( $query_vars['author__in'] ) ) {
2412 $query_vars['author__in'] = array_unique( array_map( 'absint', $query_vars['author__in'] ) );
2413 sort( $query_vars['author__in'] );
2414 }
2415 $author__in = implode( ',', array_map( 'absint', array_unique( (array) $query_vars['author__in'] ) ) );
2416 $where .= " AND {$wpdb->posts}.post_author IN ($author__in) ";
2417 }
2418
2419 // Author stuff for nice URLs.
2420
2421 if ( '' !== $query_vars['author_name'] ) {
2422 if ( str_contains( $query_vars['author_name'], '/' ) ) {
2423 $query_vars['author_name'] = explode( '/', $query_vars['author_name'] );
2424 if ( $query_vars['author_name'][ count( $query_vars['author_name'] ) - 1 ] ) {
2425 $query_vars['author_name'] = $query_vars['author_name'][ count( $query_vars['author_name'] ) - 1 ]; // No trailing slash.
2426 } else {
2427 $query_vars['author_name'] = $query_vars['author_name'][ count( $query_vars['author_name'] ) - 2 ]; // There was a trailing slash.
2428 }
2429 }
2430 $query_vars['author_name'] = sanitize_title_for_query( $query_vars['author_name'] );
2431 $query_vars['author'] = get_user_by( 'slug', $query_vars['author_name'] );
2432 if ( $query_vars['author'] ) {
2433 $query_vars['author'] = $query_vars['author']->ID;
2434 }
2435 $whichauthor .= " AND ({$wpdb->posts}.post_author = " . absint( $query_vars['author'] ) . ')';
2436 }
2437
2438 // Matching by comment count.
2439 if ( isset( $query_vars['comment_count'] ) ) {
2440 // Numeric comment count is converted to array format.
2441 if ( is_numeric( $query_vars['comment_count'] ) ) {
2442 $query_vars['comment_count'] = array(
2443 'value' => (int) $query_vars['comment_count'],
2444 );
2445 }
2446
2447 if ( isset( $query_vars['comment_count']['value'] ) ) {
2448 $query_vars['comment_count'] = array_merge(
2449 array(
2450 'compare' => '=',
2451 ),
2452 $query_vars['comment_count']
2453 );
2454
2455 // Fallback for invalid compare operators is '='.
2456 $compare_operators = array( '=', '!=', '>', '>=', '<', '<=' );
2457 if ( ! in_array( $query_vars['comment_count']['compare'], $compare_operators, true ) ) {
2458 $query_vars['comment_count']['compare'] = '=';
2459 }
2460
2461 $where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_count {$query_vars['comment_count']['compare']} %d", $query_vars['comment_count']['value'] );
2462 }
2463 }
2464
2465 // MIME-Type stuff for attachment browsing.
2466
2467 if ( isset( $query_vars['post_mime_type'] ) && '' !== $query_vars['post_mime_type'] ) {
2468 $whichmimetype = wp_post_mime_type_where( $query_vars['post_mime_type'], $wpdb->posts );
2469 }
2470 $where .= $search . $whichauthor . $whichmimetype;
2471
2472 if ( ! empty( $this->allow_query_attachment_by_filename ) ) {
2473 $join .= " LEFT JOIN {$wpdb->postmeta} AS sq1 ON ( {$wpdb->posts}.ID = sq1.post_id AND sq1.meta_key = '_wp_attached_file' )";
2474 }
2475
2476 if ( ! empty( $this->meta_query->queries ) ) {
2477 $clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
2478 $join .= $clauses['join'];
2479 $where .= $clauses['where'];
2480 }
2481
2482 $rand = ( isset( $query_vars['orderby'] ) && 'rand' === $query_vars['orderby'] );
2483 if ( ! isset( $query_vars['order'] ) ) {
2484 $query_vars['order'] = $rand ? '' : 'DESC';
2485 } else {
2486 $query_vars['order'] = $rand ? '' : $this->parse_order( $query_vars['order'] );
2487 }
2488
2489 // These values of orderby should ignore the 'order' parameter.
2490 $force_asc = array( 'post__in', 'post_name__in', 'post_parent__in' );
2491 if ( isset( $query_vars['orderby'] ) && in_array( $query_vars['orderby'], $force_asc, true ) ) {
2492 $query_vars['order'] = '';
2493 }
2494
2495 // Order by.
2496 if ( empty( $query_vars['orderby'] ) ) {
2497 /*
2498 * Boolean false or empty array blanks out ORDER BY,
2499 * while leaving the value unset or otherwise empty sets the default.
2500 */
2501 if ( isset( $query_vars['orderby'] ) && ( is_array( $query_vars['orderby'] ) || false === $query_vars['orderby'] ) ) {
2502 $orderby = '';
2503 } else {
2504 $orderby = "{$wpdb->posts}.post_date " . $query_vars['order'];
2505 }
2506 } elseif ( 'none' === $query_vars['orderby'] ) {
2507 $orderby = '';
2508 } else {
2509 $orderby_array = array();
2510 if ( is_array( $query_vars['orderby'] ) ) {
2511 foreach ( $query_vars['orderby'] as $_orderby => $order ) {
2512 $orderby = addslashes_gpc( urldecode( $_orderby ) );
2513 $parsed = $this->parse_orderby( $orderby );
2514
2515 if ( ! $parsed ) {
2516 continue;
2517 }
2518
2519 $orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
2520 }
2521 $orderby = implode( ', ', $orderby_array );
2522
2523 } else {
2524 $query_vars['orderby'] = urldecode( $query_vars['orderby'] );
2525 $query_vars['orderby'] = addslashes_gpc( $query_vars['orderby'] );
2526
2527 foreach ( explode( ' ', $query_vars['orderby'] ) as $i => $orderby ) {
2528 $parsed = $this->parse_orderby( $orderby );
2529 // Only allow certain values for safety.
2530 if ( ! $parsed ) {
2531 continue;
2532 }
2533
2534 $orderby_array[] = $parsed;
2535 }
2536 $orderby = implode( ' ' . $query_vars['order'] . ', ', $orderby_array );
2537
2538 if ( empty( $orderby ) ) {
2539 $orderby = "{$wpdb->posts}.post_date " . $query_vars['order'];
2540 } elseif ( ! empty( $query_vars['order'] ) ) {
2541 $orderby .= " {$query_vars['order']}";
2542 }
2543 }
2544 }
2545
2546 // Order search results by relevance only when another "orderby" is not specified in the query.
2547 if ( ! empty( $query_vars['s'] ) ) {
2548 $search_orderby = '';
2549 if ( ! empty( $query_vars['search_orderby_title'] ) && ( empty( $query_vars['orderby'] ) && ! $this->is_feed ) || ( isset( $query_vars['orderby'] ) && 'relevance' === $query_vars['orderby'] ) ) {
2550 $search_orderby = $this->parse_search_order( $query_vars );
2551 }
2552
2553 if ( ! $query_vars['suppress_filters'] ) {
2554 /**
2555 * Filters the ORDER BY used when ordering search results.
2556 *
2557 * @since 3.7.0
2558 *
2559 * @param string $search_orderby The ORDER BY clause.
2560 * @param WP_Query $query The current WP_Query instance.
2561 */
2562 $search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );
2563 }
2564
2565 if ( $search_orderby ) {
2566 $orderby = $orderby ? $search_orderby . ', ' . $orderby : $search_orderby;
2567 }
2568 }
2569
2570 if ( is_array( $post_type ) && count( $post_type ) > 1 ) {
2571 $post_type_cap = 'multiple_post_type';
2572 } else {
2573 if ( is_array( $post_type ) ) {
2574 $post_type = reset( $post_type );
2575 }
2576 $post_type_object = get_post_type_object( $post_type );
2577 if ( empty( $post_type_object ) ) {
2578 $post_type_cap = $post_type;
2579 }
2580 }
2581
2582 if ( isset( $query_vars['post_password'] ) ) {
2583 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_password = %s", $query_vars['post_password'] );
2584 if ( empty( $query_vars['perm'] ) ) {
2585 $query_vars['perm'] = 'readable';
2586 }
2587 } elseif ( isset( $query_vars['has_password'] ) ) {
2588 $where .= sprintf( " AND {$wpdb->posts}.post_password %s ''", $query_vars['has_password'] ? '!=' : '=' );
2589 }
2590
2591 if ( ! empty( $query_vars['comment_status'] ) ) {
2592 $where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_status = %s ", $query_vars['comment_status'] );
2593 }
2594
2595 if ( ! empty( $query_vars['ping_status'] ) ) {
2596 $where .= $wpdb->prepare( " AND {$wpdb->posts}.ping_status = %s ", $query_vars['ping_status'] );
2597 }
2598
2599 $skip_post_status = false;
2600 if ( 'any' === $post_type ) {
2601 $in_search_post_types = get_post_types( array( 'exclude_from_search' => false ) );
2602 if ( empty( $in_search_post_types ) ) {
2603 $post_type_where = ' AND 1=0 ';
2604 $skip_post_status = true;
2605 } else {
2606 $post_type_where = " AND {$wpdb->posts}.post_type IN ('" . implode( "', '", array_map( 'esc_sql', $in_search_post_types ) ) . "')";
2607 }
2608 } elseif ( ! empty( $post_type ) && is_array( $post_type ) ) {
2609 // Sort post types to ensure same cache key generation.
2610 sort( $post_type );
2611 $post_type_where = " AND {$wpdb->posts}.post_type IN ('" . implode( "', '", esc_sql( $post_type ) ) . "')";
2612 } elseif ( ! empty( $post_type ) ) {
2613 $post_type_where = $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", $post_type );
2614 $post_type_object = get_post_type_object( $post_type );
2615 } elseif ( $this->is_attachment ) {
2616 $post_type_where = " AND {$wpdb->posts}.post_type = 'attachment'";
2617 $post_type_object = get_post_type_object( 'attachment' );
2618 } elseif ( $this->is_page ) {
2619 $post_type_where = " AND {$wpdb->posts}.post_type = 'page'";
2620 $post_type_object = get_post_type_object( 'page' );
2621 } else {
2622 $post_type_where = " AND {$wpdb->posts}.post_type = 'post'";
2623 $post_type_object = get_post_type_object( 'post' );
2624 }
2625
2626 $edit_cap = 'edit_post';
2627 $read_cap = 'read_post';
2628
2629 if ( ! empty( $post_type_object ) ) {
2630 $edit_others_cap = $post_type_object->cap->edit_others_posts;
2631 $read_private_cap = $post_type_object->cap->read_private_posts;
2632 } else {
2633 $edit_others_cap = 'edit_others_' . $post_type_cap . 's';
2634 $read_private_cap = 'read_private_' . $post_type_cap . 's';
2635 }
2636
2637 $user_id = get_current_user_id();
2638
2639 $q_status = array();
2640 if ( $skip_post_status ) {
2641 $where .= $post_type_where;
2642 } elseif ( ! empty( $query_vars['post_status'] ) ) {
2643
2644 $where .= $post_type_where;
2645
2646 $statuswheres = array();
2647 $q_status = $query_vars['post_status'];
2648 if ( ! is_array( $q_status ) ) {
2649 $q_status = explode( ',', $q_status );
2650 }
2651 sort( $q_status );
2652 $r_status = array();
2653 $p_status = array();
2654 $e_status = array();
2655 if ( in_array( 'any', $q_status, true ) ) {
2656 foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
2657 if ( ! in_array( $status, $q_status, true ) ) {
2658 $e_status[] = "{$wpdb->posts}.post_status <> '$status'";
2659 }
2660 }
2661 } else {
2662 foreach ( get_post_stati() as $status ) {
2663 if ( in_array( $status, $q_status, true ) ) {
2664 if ( 'private' === $status ) {
2665 $p_status[] = "{$wpdb->posts}.post_status = '$status'";
2666 } else {
2667 $r_status[] = "{$wpdb->posts}.post_status = '$status'";
2668 }
2669 }
2670 }
2671 }
2672
2673 if ( empty( $query_vars['perm'] ) || 'readable' !== $query_vars['perm'] ) {
2674 $r_status = array_merge( $r_status, $p_status );
2675 unset( $p_status );
2676 }
2677
2678 if ( ! empty( $e_status ) ) {
2679 $statuswheres[] = '(' . implode( ' AND ', $e_status ) . ')';
2680 }
2681 if ( ! empty( $r_status ) ) {
2682 if ( ! empty( $query_vars['perm'] ) && 'editable' === $query_vars['perm'] && ! current_user_can( $edit_others_cap ) ) {
2683 $statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . 'AND (' . implode( ' OR ', $r_status ) . '))';
2684 } else {
2685 $statuswheres[] = '(' . implode( ' OR ', $r_status ) . ')';
2686 }
2687 }
2688 if ( ! empty( $p_status ) ) {
2689 if ( ! empty( $query_vars['perm'] ) && 'readable' === $query_vars['perm'] && ! current_user_can( $read_private_cap ) ) {
2690 $statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . 'AND (' . implode( ' OR ', $p_status ) . '))';
2691 } else {
2692 $statuswheres[] = '(' . implode( ' OR ', $p_status ) . ')';
2693 }
2694 }
2695 if ( $post_status_join ) {
2696 $join .= " LEFT JOIN {$wpdb->posts} AS p2 ON ({$wpdb->posts}.post_parent = p2.ID) ";
2697 foreach ( $statuswheres as $index => $statuswhere ) {
2698 $statuswheres[ $index ] = "($statuswhere OR ({$wpdb->posts}.post_status = 'inherit' AND " . str_replace( $wpdb->posts, 'p2', $statuswhere ) . '))';
2699 }
2700 }
2701 $where_status = implode( ' OR ', $statuswheres );
2702 if ( ! empty( $where_status ) ) {
2703 $where .= " AND ($where_status)";
2704 }
2705 } elseif ( ! $this->is_singular ) {
2706 if ( 'any' === $post_type ) {
2707 $queried_post_types = get_post_types( array( 'exclude_from_search' => false ) );
2708 } elseif ( is_array( $post_type ) ) {
2709 $queried_post_types = $post_type;
2710 } elseif ( ! empty( $post_type ) ) {
2711 $queried_post_types = array( $post_type );
2712 } else {
2713 $queried_post_types = array( 'post' );
2714 }
2715
2716 if ( ! empty( $queried_post_types ) ) {
2717 sort( $queried_post_types );
2718 $status_type_clauses = array();
2719
2720 foreach ( $queried_post_types as $queried_post_type ) {
2721
2722 $queried_post_type_object = get_post_type_object( $queried_post_type );
2723
2724 $type_where = '(' . $wpdb->prepare( "{$wpdb->posts}.post_type = %s AND (", $queried_post_type );
2725
2726 // Public statuses.
2727 $public_statuses = get_post_stati( array( 'public' => true ) );
2728 $status_clauses = array();
2729 foreach ( $public_statuses as $public_status ) {
2730 $status_clauses[] = "{$wpdb->posts}.post_status = '$public_status'";
2731 }
2732 $type_where .= implode( ' OR ', $status_clauses );
2733
2734 // Add protected states that should show in the admin all list.
2735 if ( $this->is_admin ) {
2736 $admin_all_statuses = get_post_stati(
2737 array(
2738 'protected' => true,
2739 'show_in_admin_all_list' => true,
2740 )
2741 );
2742 foreach ( $admin_all_statuses as $admin_all_status ) {
2743 $type_where .= " OR {$wpdb->posts}.post_status = '$admin_all_status'";
2744 }
2745 }
2746
2747 // Add private states that are visible to current user.
2748 if ( is_user_logged_in() && $queried_post_type_object instanceof WP_Post_Type ) {
2749 $read_private_cap = $queried_post_type_object->cap->read_private_posts;
2750 $private_statuses = get_post_stati( array( 'private' => true ) );
2751 foreach ( $private_statuses as $private_status ) {
2752 $type_where .= current_user_can( $read_private_cap ) ? " \nOR {$wpdb->posts}.post_status = '$private_status'" : " \nOR ({$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status = '$private_status')";
2753 }
2754 }
2755
2756 $type_where .= '))';
2757
2758 $status_type_clauses[] = $type_where;
2759 }
2760
2761 if ( ! empty( $status_type_clauses ) ) {
2762 $where .= ' AND (' . implode( ' OR ', $status_type_clauses ) . ')';
2763 }
2764 } else {
2765 $where .= ' AND 1=0 ';
2766 }
2767 } else {
2768 $where .= $post_type_where;
2769 }
2770
2771 /*
2772 * Apply filters on where and join prior to paging so that any
2773 * manipulations to them are reflected in the paging by day queries.
2774 */
2775 if ( ! $query_vars['suppress_filters'] ) {
2776 /**
2777 * Filters the WHERE clause of the query.
2778 *
2779 * @since 1.5.0
2780 *
2781 * @param string $where The WHERE clause of the query.
2782 * @param WP_Query $query The WP_Query instance (passed by reference).
2783 */
2784 $where = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
2785
2786 /**
2787 * Filters the JOIN clause of the query.
2788 *
2789 * @since 1.5.0
2790 *
2791 * @param string $join The JOIN clause of the query.
2792 * @param WP_Query $query The WP_Query instance (passed by reference).
2793 */
2794 $join = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
2795 }
2796
2797 // Paging.
2798 if ( empty( $query_vars['nopaging'] ) && ! $this->is_singular ) {
2799 $page = absint( $query_vars['paged'] );
2800 if ( ! $page ) {
2801 $page = 1;
2802 }
2803
2804 // If 'offset' is provided, it takes precedence over 'paged'.
2805 if ( isset( $query_vars['offset'] ) && is_numeric( $query_vars['offset'] ) ) {
2806 $query_vars['offset'] = absint( $query_vars['offset'] );
2807 $pgstrt = $query_vars['offset'] . ', ';
2808 } else {
2809 $pgstrt = absint( ( $page - 1 ) * $query_vars['posts_per_page'] ) . ', ';
2810 }
2811 $limits = 'LIMIT ' . $pgstrt . $query_vars['posts_per_page'];
2812 }
2813
2814 // Comments feeds.
2815 if ( $this->is_comment_feed && ! $this->is_singular ) {
2816 if ( $this->is_archive || $this->is_search ) {
2817 $cjoin = "JOIN {$wpdb->posts} ON ( {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID ) $join ";
2818 $cwhere = "WHERE comment_approved = '1' $where";
2819 $cgroupby = "{$wpdb->comments}.comment_id";
2820 } else { // Other non-singular, e.g. front.
2821 $cjoin = "JOIN {$wpdb->posts} ON ( {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID )";
2822 $cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' AND post_type = 'attachment' ) ) AND comment_approved = '1'";
2823 $cgroupby = '';
2824 }
2825
2826 if ( ! $query_vars['suppress_filters'] ) {
2827 /**
2828 * Filters the JOIN clause of the comments feed query before sending.
2829 *
2830 * @since 2.2.0
2831 *
2832 * @param string $cjoin The JOIN clause of the query.
2833 * @param WP_Query $query The WP_Query instance (passed by reference).
2834 */
2835 $cjoin = apply_filters_ref_array( 'comment_feed_join', array( $cjoin, &$this ) );
2836
2837 /**
2838 * Filters the WHERE clause of the comments feed query before sending.
2839 *
2840 * @since 2.2.0
2841 *
2842 * @param string $cwhere The WHERE clause of the query.
2843 * @param WP_Query $query The WP_Query instance (passed by reference).
2844 */
2845 $cwhere = apply_filters_ref_array( 'comment_feed_where', array( $cwhere, &$this ) );
2846
2847 /**
2848 * Filters the GROUP BY clause of the comments feed query before sending.
2849 *
2850 * @since 2.2.0
2851 *
2852 * @param string $cgroupby The GROUP BY clause of the query.
2853 * @param WP_Query $query The WP_Query instance (passed by reference).
2854 */
2855 $cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( $cgroupby, &$this ) );
2856
2857 /**
2858 * Filters the ORDER BY clause of the comments feed query before sending.
2859 *
2860 * @since 2.8.0
2861 *
2862 * @param string $corderby The ORDER BY clause of the query.
2863 * @param WP_Query $query The WP_Query instance (passed by reference).
2864 */
2865 $corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
2866
2867 /**
2868 * Filters the LIMIT clause of the comments feed query before sending.
2869 *
2870 * @since 2.8.0
2871 *
2872 * @param string $climits The JOIN clause of the query.
2873 * @param WP_Query $query The WP_Query instance (passed by reference).
2874 */
2875 $climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option( 'posts_per_rss' ), &$this ) );
2876 }
2877
2878 $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
2879 $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
2880 $climits = ( ! empty( $climits ) ) ? $climits : '';
2881
2882 $comments_request = "SELECT $distinct {$wpdb->comments}.comment_ID FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";
2883
2884 $key = md5( $comments_request );
2885 $last_changed = array(
2886 wp_cache_get_last_changed( 'comment' ),
2887 wp_cache_get_last_changed( 'posts' ),
2888 );
2889
2890 $cache_key = "comment_feed:$key";
2891 $comment_ids = wp_cache_get_salted( $cache_key, 'comment-queries', $last_changed );
2892 if ( false === $comment_ids ) {
2893 $comment_ids = $wpdb->get_col( $comments_request );
2894 wp_cache_set_salted( $cache_key, $comment_ids, 'comment-queries', $last_changed );
2895 }
2896 _prime_comment_caches( $comment_ids );
2897
2898 // Convert to WP_Comment.
2899 /** @var WP_Comment[] */
2900 $this->comments = array_map( 'get_comment', $comment_ids );
2901 $this->comment_count = count( $this->comments );
2902
2903 $post_ids = array();
2904
2905 foreach ( $this->comments as $comment ) {
2906 $post_ids[] = (int) $comment->comment_post_ID;
2907 }
2908
2909 $post_ids = implode( ',', $post_ids );
2910 $join = '';
2911 if ( $post_ids ) {
2912 $where = "AND {$wpdb->posts}.ID IN ($post_ids) ";
2913 } else {
2914 $where = 'AND 0';
2915 }
2916 }
2917
2918 $pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );
2919
2920 /*
2921 * Apply post-paging filters on where and join. Only plugins that
2922 * manipulate paging queries should use these hooks.
2923 */
2924 if ( ! $query_vars['suppress_filters'] ) {
2925 /**
2926 * Filters the WHERE clause of the query.
2927 *
2928 * Specifically for manipulating paging queries.
2929 *
2930 * @since 1.5.0
2931 *
2932 * @param string $where The WHERE clause of the query.
2933 * @param WP_Query $query The WP_Query instance (passed by reference).
2934 */
2935 $where = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
2936
2937 /**
2938 * Filters the GROUP BY clause of the query.
2939 *
2940 * @since 2.0.0
2941 *
2942 * @param string $groupby The GROUP BY clause of the query.
2943 * @param WP_Query $query The WP_Query instance (passed by reference).
2944 */
2945 $groupby = apply_filters_ref_array( 'posts_groupby', array( $groupby, &$this ) );
2946
2947 /**
2948 * Filters the JOIN clause of the query.
2949 *
2950 * Specifically for manipulating paging queries.
2951 *
2952 * @since 1.5.0
2953 *
2954 * @param string $join The JOIN clause of the query.
2955 * @param WP_Query $query The WP_Query instance (passed by reference).
2956 */
2957 $join = apply_filters_ref_array( 'posts_join_paged', array( $join, &$this ) );
2958
2959 /**
2960 * Filters the ORDER BY clause of the query.
2961 *
2962 * @since 1.5.1
2963 *
2964 * @param string $orderby The ORDER BY clause of the query.
2965 * @param WP_Query $query The WP_Query instance (passed by reference).
2966 */
2967 $orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
2968
2969 /**
2970 * Filters the DISTINCT clause of the query.
2971 *
2972 * @since 2.1.0
2973 *
2974 * @param string $distinct The DISTINCT clause of the query.
2975 * @param WP_Query $query The WP_Query instance (passed by reference).
2976 */
2977 $distinct = apply_filters_ref_array( 'posts_distinct', array( $distinct, &$this ) );
2978
2979 /**
2980 * Filters the LIMIT clause of the query.
2981 *
2982 * @since 2.1.0
2983 *
2984 * @param string $limits The LIMIT clause of the query.
2985 * @param WP_Query $query The WP_Query instance (passed by reference).
2986 */
2987 $limits = apply_filters_ref_array( 'post_limits', array( $limits, &$this ) );
2988
2989 /**
2990 * Filters the SELECT clause of the query.
2991 *
2992 * @since 2.1.0
2993 *
2994 * @param string $fields The SELECT clause of the query.
2995 * @param WP_Query $query The WP_Query instance (passed by reference).
2996 */
2997 $fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );
2998
2999 /**
3000 * Filters all query clauses at once, for convenience.
3001 *
3002 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
3003 * fields (SELECT), and LIMIT clauses.
3004 *
3005 * @since 3.1.0
3006 *
3007 * @param string[] $clauses {
3008 * Associative array of the clauses for the query.
3009 *
3010 * @type string $where The WHERE clause of the query.
3011 * @type string $groupby The GROUP BY clause of the query.
3012 * @type string $join The JOIN clause of the query.
3013 * @type string $orderby The ORDER BY clause of the query.
3014 * @type string $distinct The DISTINCT clause of the query.
3015 * @type string $fields The SELECT clause of the query.
3016 * @type string $limits The LIMIT clause of the query.
3017 * }
3018 * @param WP_Query $query The WP_Query instance (passed by reference).
3019 */
3020 $clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
3021
3022 $where = isset( $clauses['where'] ) ? $clauses['where'] : '';
3023 $groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : '';
3024 $join = isset( $clauses['join'] ) ? $clauses['join'] : '';
3025 $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : '';
3026 $distinct = isset( $clauses['distinct'] ) ? $clauses['distinct'] : '';
3027 $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : '';
3028 $limits = isset( $clauses['limits'] ) ? $clauses['limits'] : '';
3029 }
3030
3031 /**
3032 * Fires to announce the query's current selection parameters.
3033 *
3034 * For use by caching plugins.
3035 *
3036 * @since 2.3.0
3037 *
3038 * @param string $selection The assembled selection query.
3039 */
3040 do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
3041
3042 /*
3043 * Filters again for the benefit of caching plugins.
3044 * Regular plugins should use the hooks above.
3045 */
3046 if ( ! $query_vars['suppress_filters'] ) {
3047 /**
3048 * Filters the WHERE clause of the query.
3049 *
3050 * For use by caching plugins.
3051 *
3052 * @since 2.5.0
3053 *
3054 * @param string $where The WHERE clause of the query.
3055 * @param WP_Query $query The WP_Query instance (passed by reference).
3056 */
3057 $where = apply_filters_ref_array( 'posts_where_request', array( $where, &$this ) );
3058
3059 /**
3060 * Filters the GROUP BY clause of the query.
3061 *
3062 * For use by caching plugins.
3063 *
3064 * @since 2.5.0
3065 *
3066 * @param string $groupby The GROUP BY clause of the query.
3067 * @param WP_Query $query The WP_Query instance (passed by reference).
3068 */
3069 $groupby = apply_filters_ref_array( 'posts_groupby_request', array( $groupby, &$this ) );
3070
3071 /**
3072 * Filters the JOIN clause of the query.
3073 *
3074 * For use by caching plugins.
3075 *
3076 * @since 2.5.0
3077 *
3078 * @param string $join The JOIN clause of the query.
3079 * @param WP_Query $query The WP_Query instance (passed by reference).
3080 */
3081 $join = apply_filters_ref_array( 'posts_join_request', array( $join, &$this ) );
3082
3083 /**
3084 * Filters the ORDER BY clause of the query.
3085 *
3086 * For use by caching plugins.
3087 *
3088 * @since 2.5.0
3089 *
3090 * @param string $orderby The ORDER BY clause of the query.
3091 * @param WP_Query $query The WP_Query instance (passed by reference).
3092 */
3093 $orderby = apply_filters_ref_array( 'posts_orderby_request', array( $orderby, &$this ) );
3094
3095 /**
3096 * Filters the DISTINCT clause of the query.
3097 *
3098 * For use by caching plugins.
3099 *
3100 * @since 2.5.0
3101 *
3102 * @param string $distinct The DISTINCT clause of the query.
3103 * @param WP_Query $query The WP_Query instance (passed by reference).
3104 */
3105 $distinct = apply_filters_ref_array( 'posts_distinct_request', array( $distinct, &$this ) );
3106
3107 /**
3108 * Filters the SELECT clause of the query.
3109 *
3110 * For use by caching plugins.
3111 *
3112 * @since 2.5.0
3113 *
3114 * @param string $fields The SELECT clause of the query.
3115 * @param WP_Query $query The WP_Query instance (passed by reference).
3116 */
3117 $fields = apply_filters_ref_array( 'posts_fields_request', array( $fields, &$this ) );
3118
3119 /**
3120 * Filters the LIMIT clause of the query.
3121 *
3122 * For use by caching plugins.
3123 *
3124 * @since 2.5.0
3125 *
3126 * @param string $limits The LIMIT clause of the query.
3127 * @param WP_Query $query The WP_Query instance (passed by reference).
3128 */
3129 $limits = apply_filters_ref_array( 'post_limits_request', array( $limits, &$this ) );
3130
3131 /**
3132 * Filters all query clauses at once, for convenience.
3133 *
3134 * For use by caching plugins.
3135 *
3136 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
3137 * fields (SELECT), and LIMIT clauses.
3138 *
3139 * @since 3.1.0
3140 *
3141 * @param string[] $clauses {
3142 * Associative array of the clauses for the query.
3143 *
3144 * @type string $where The WHERE clause of the query.
3145 * @type string $groupby The GROUP BY clause of the query.
3146 * @type string $join The JOIN clause of the query.
3147 * @type string $orderby The ORDER BY clause of the query.
3148 * @type string $distinct The DISTINCT clause of the query.
3149 * @type string $fields The SELECT clause of the query.
3150 * @type string $limits The LIMIT clause of the query.
3151 * }
3152 * @param WP_Query $query The WP_Query instance (passed by reference).
3153 */
3154 $clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
3155
3156 $where = isset( $clauses['where'] ) ? $clauses['where'] : '';
3157 $groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : '';
3158 $join = isset( $clauses['join'] ) ? $clauses['join'] : '';
3159 $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : '';
3160 $distinct = isset( $clauses['distinct'] ) ? $clauses['distinct'] : '';
3161 $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : '';
3162 $limits = isset( $clauses['limits'] ) ? $clauses['limits'] : '';
3163 }
3164
3165 if ( ! empty( $groupby ) ) {
3166 $groupby = 'GROUP BY ' . $groupby;
3167 }
3168 if ( ! empty( $orderby ) ) {
3169 $orderby = 'ORDER BY ' . $orderby;
3170 }
3171
3172 $found_rows = '';
3173 if ( ! $query_vars['no_found_rows'] && ! empty( $limits ) ) {
3174 $found_rows = 'SQL_CALC_FOUND_ROWS';
3175 }
3176
3177 /*
3178 * Beginning of the string is on a new line to prevent leading whitespace.
3179 *
3180 * The additional indentation of subsequent lines is to ensure the SQL
3181 * queries are identical to those generated when splitting queries. This
3182 * improves caching of the query by ensuring the same cache key is
3183 * generated for the same database queries functionally.
3184 *
3185 * See https://core.trac.wordpress.org/ticket/56841.
3186 * See https://github.com/WordPress/wordpress-develop/pull/6393#issuecomment-2088217429
3187 */
3188 $old_request =
3189 "SELECT $found_rows $distinct $fields
3190 FROM {$wpdb->posts} $join
3191 WHERE 1=1 $where
3192 $groupby
3193 $orderby
3194 $limits";
3195
3196 $this->request = $old_request;
3197
3198 if ( ! $query_vars['suppress_filters'] ) {
3199 /**
3200 * Filters the completed SQL query before sending.
3201 *
3202 * @since 2.0.0
3203 *
3204 * @param string $request The complete SQL query.
3205 * @param WP_Query $query The WP_Query instance (passed by reference).
3206 */
3207 $this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
3208 }
3209
3210 /**
3211 * Filters the posts array before the query takes place.
3212 *
3213 * Return a non-null value to bypass WordPress' default post queries.
3214 *
3215 * Filtering functions that require pagination information are encouraged to set
3216 * the `found_posts` and `max_num_pages` properties of the WP_Query object,
3217 * passed to the filter by reference. If WP_Query does not perform a database
3218 * query, it will not have enough information to generate these values itself.
3219 *
3220 * @since 4.6.0
3221 *
3222 * @param WP_Post[]|int[]|null $posts Return an array of post data to short-circuit WP's query,
3223 * or null to allow WP to run its normal queries.
3224 * @param WP_Query $query The WP_Query instance (passed by reference).
3225 */
3226 $this->posts = apply_filters_ref_array( 'posts_pre_query', array( null, &$this ) );
3227
3228 /*
3229 * Ensure the ID database query is able to be cached.
3230 *
3231 * Random queries are expected to have unpredictable results and
3232 * cannot be cached. Note the space before `RAND` in the string
3233 * search, that to ensure against a collision with another
3234 * function.
3235 *
3236 * If `$fields` has been modified by the `posts_fields`,
3237 * `posts_fields_request`, `post_clauses` or `posts_clauses_request`
3238 * filters, then caching is disabled to prevent caching collisions.
3239 */
3240 $id_query_is_cacheable = ! str_contains( strtoupper( $orderby ), ' RAND(' );
3241
3242 $cacheable_field_values = array(
3243 "{$wpdb->posts}.*",
3244 "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent",
3245 "{$wpdb->posts}.ID",
3246 );
3247
3248 if ( ! in_array( $fields, $cacheable_field_values, true ) ) {
3249 $id_query_is_cacheable = false;
3250 }
3251
3252 $last_changed = (array) wp_cache_get_last_changed( 'posts' );
3253 if ( ! empty( $this->tax_query->queries ) ) {
3254 $last_changed[] = wp_cache_get_last_changed( 'terms' );
3255 }
3256
3257 if ( $query_vars['cache_results'] && $id_query_is_cacheable ) {
3258 $new_request = str_replace( $fields, "{$wpdb->posts}.*", $this->request );
3259 $cache_key = $this->generate_cache_key( $query_vars, $new_request );
3260
3261 $cache_found = false;
3262 if ( null === $this->posts ) {
3263 $cached_results = wp_cache_get_salted( $cache_key, 'post-queries', $last_changed );
3264
3265 if ( $cached_results ) {
3266 $cache_found = true;
3267 /** @var int[] */
3268 $post_ids = array_map( 'intval', $cached_results['posts'] );
3269
3270 $this->post_count = count( $post_ids );
3271 $this->found_posts = $cached_results['found_posts'];
3272 $this->max_num_pages = $cached_results['max_num_pages'];
3273
3274 if ( 'ids' === $query_vars['fields'] ) {
3275 $this->posts = $post_ids;
3276
3277 return $this->posts;
3278 } elseif ( 'id=>parent' === $query_vars['fields'] ) {
3279 _prime_post_parent_id_caches( $post_ids );
3280
3281 $post_parent_cache_keys = array();
3282 foreach ( $post_ids as $post_id ) {
3283 $post_parent_cache_keys[] = 'post_parent:' . (string) $post_id;
3284 }
3285
3286 /** @var int[] */
3287 $post_parents = wp_cache_get_multiple( $post_parent_cache_keys, 'posts' );
3288
3289 foreach ( $post_parents as $cache_key => $post_parent ) {
3290 $obj = new stdClass();
3291 $obj->ID = (int) str_replace( 'post_parent:', '', $cache_key );
3292 $obj->post_parent = (int) $post_parent;
3293
3294 $this->posts[] = $obj;
3295 }
3296
3297 return $post_parents;
3298 } else {
3299 _prime_post_caches( $post_ids, $query_vars['update_post_term_cache'], $query_vars['update_post_meta_cache'] );
3300 /** @var WP_Post[] */
3301 $this->posts = array_map( 'get_post', $post_ids );
3302 }
3303 }
3304 }
3305 }
3306
3307 if ( 'ids' === $query_vars['fields'] ) {
3308 if ( null === $this->posts ) {
3309 $this->posts = $wpdb->get_col( $this->request );
3310 }
3311
3312 /** @var int[] */
3313 $this->posts = array_map( 'intval', $this->posts );
3314 $this->post_count = count( $this->posts );
3315 $this->set_found_posts( $query_vars, $limits );
3316
3317 if ( $query_vars['cache_results'] && $id_query_is_cacheable ) {
3318 $cache_value = array(
3319 'posts' => $this->posts,
3320 'found_posts' => $this->found_posts,
3321 'max_num_pages' => $this->max_num_pages,
3322 );
3323
3324 wp_cache_set_salted( $cache_key, $cache_value, 'post-queries', $last_changed );
3325 }
3326
3327 return $this->posts;
3328 }
3329
3330 if ( 'id=>parent' === $query_vars['fields'] ) {
3331 if ( null === $this->posts ) {
3332 $this->posts = $wpdb->get_results( $this->request );
3333 }
3334
3335 $this->post_count = count( $this->posts );
3336 $this->set_found_posts( $query_vars, $limits );
3337
3338 /** @var int[] */
3339 $post_parents = array();
3340 $post_ids = array();
3341 $post_parents_cache = array();
3342
3343 foreach ( $this->posts as $key => $post ) {
3344 $this->posts[ $key ]->ID = (int) $post->ID;
3345 $this->posts[ $key ]->post_parent = (int) $post->post_parent;
3346
3347 $post_parents[ (int) $post->ID ] = (int) $post->post_parent;
3348 $post_ids[] = (int) $post->ID;
3349
3350 $post_parents_cache[ 'post_parent:' . (string) $post->ID ] = (int) $post->post_parent;
3351 }
3352 // Prime post parent caches, so that on second run, there is not another database query.
3353 wp_cache_add_multiple( $post_parents_cache, 'posts' );
3354
3355 if ( $query_vars['cache_results'] && $id_query_is_cacheable ) {
3356 $cache_value = array(
3357 'posts' => $post_ids,
3358 'found_posts' => $this->found_posts,
3359 'max_num_pages' => $this->max_num_pages,
3360 );
3361
3362 wp_cache_set_salted( $cache_key, $cache_value, 'post-queries', $last_changed );
3363 }
3364
3365 return $post_parents;
3366 }
3367
3368 $is_unfiltered_query = $old_request === $this->request && "{$wpdb->posts}.*" === $fields;
3369
3370 if ( null === $this->posts ) {
3371 $split_the_query = (
3372 $is_unfiltered_query
3373 && (
3374 wp_using_ext_object_cache()
3375 || ( ! empty( $limits ) && $query_vars['posts_per_page'] < 500 )
3376 )
3377 );
3378
3379 /**
3380 * Filters whether to split the query.
3381 *
3382 * Splitting the query will cause it to fetch just the IDs of the found posts
3383 * (and then individually fetch each post by ID), rather than fetching every
3384 * complete row at once. One massive result vs. many small results.
3385 *
3386 * @since 3.4.0
3387 * @since 6.6.0 Added the `$old_request` and `$clauses` parameters.
3388 *
3389 * @param bool $split_the_query Whether or not to split the query.
3390 * @param WP_Query $query The WP_Query instance.
3391 * @param string $old_request The complete SQL query before filtering.
3392 * @param string[] $clauses {
3393 * Associative array of the clauses for the query.
3394 *
3395 * @type string $where The WHERE clause of the query.
3396 * @type string $groupby The GROUP BY clause of the query.
3397 * @type string $join The JOIN clause of the query.
3398 * @type string $orderby The ORDER BY clause of the query.
3399 * @type string $distinct The DISTINCT clause of the query.
3400 * @type string $fields The SELECT clause of the query.
3401 * @type string $limits The LIMIT clause of the query.
3402 * }
3403 */
3404 $split_the_query = apply_filters( 'split_the_query', $split_the_query, $this, $old_request, compact( $pieces ) );
3405
3406 if ( $split_the_query ) {
3407 // First get the IDs and then fill in the objects.
3408
3409 // Beginning of the string is on a new line to prevent leading whitespace. See https://core.trac.wordpress.org/ticket/56841.
3410 $this->request =
3411 "SELECT $found_rows $distinct {$wpdb->posts}.ID
3412 FROM {$wpdb->posts} $join
3413 WHERE 1=1 $where
3414 $groupby
3415 $orderby
3416 $limits";
3417
3418 /**
3419 * Filters the Post IDs SQL request before sending.
3420 *
3421 * @since 3.4.0
3422 *
3423 * @param string $request The post ID request.
3424 * @param WP_Query $query The WP_Query instance.
3425 */
3426 $this->request = apply_filters( 'posts_request_ids', $this->request, $this );
3427
3428 $post_ids = $wpdb->get_col( $this->request );
3429
3430 if ( $post_ids ) {
3431 $this->posts = $post_ids;
3432 $this->set_found_posts( $query_vars, $limits );
3433 _prime_post_caches( $post_ids, $query_vars['update_post_term_cache'], $query_vars['update_post_meta_cache'] );
3434 } else {
3435 $this->posts = array();
3436 }
3437 } else {
3438 $this->posts = $wpdb->get_results( $this->request );
3439 $this->set_found_posts( $query_vars, $limits );
3440 }
3441 }
3442
3443 // Convert to WP_Post objects.
3444 if ( $this->posts ) {
3445 $this->posts = apply_filters('godaddy/wp_query/get_posts/before_get_post', $this->posts, $this);
3446
3447 /** @var WP_Post[] */
3448 $this->posts = array_map( 'get_post', $this->posts );
3449 }
3450
3451 $unfiltered_posts = $this->posts;
3452
3453 if ( $query_vars['cache_results'] && $id_query_is_cacheable && ! $cache_found ) {
3454 $post_ids = wp_list_pluck( $this->posts, 'ID' );
3455
3456 $cache_value = array(
3457 'posts' => $post_ids,
3458 'found_posts' => $this->found_posts,
3459 'max_num_pages' => $this->max_num_pages,
3460 );
3461
3462 wp_cache_set_salted( $cache_key, $cache_value, 'post-queries', $last_changed );
3463 }
3464
3465 if ( ! $query_vars['suppress_filters'] ) {
3466 /**
3467 * Filters the raw post results array, prior to status checks.
3468 *
3469 * @since 2.3.0
3470 *
3471 * @param WP_Post[] $posts Array of post objects.
3472 * @param WP_Query $query The WP_Query instance (passed by reference).
3473 */
3474 $this->posts = apply_filters_ref_array( 'posts_results', array( $this->posts, &$this ) );
3475 }
3476
3477 if ( ! empty( $this->posts ) && $this->is_comment_feed && $this->is_singular ) {
3478 /** This filter is documented in wp-includes/query.php */
3479 $cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
3480
3481 /** This filter is documented in wp-includes/query.php */
3482 $cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
3483
3484 /** This filter is documented in wp-includes/query.php */
3485 $cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
3486 $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
3487
3488 /** This filter is documented in wp-includes/query.php */
3489 $corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
3490 $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
3491
3492 /** This filter is documented in wp-includes/query.php */
3493 $climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option( 'posts_per_rss' ), &$this ) );
3494
3495 $comments_request = "SELECT {$wpdb->comments}.comment_ID FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";
3496
3497 $comment_key = md5( $comments_request );
3498 $comment_last_changed = wp_cache_get_last_changed( 'comment' );
3499
3500 $comment_cache_key = "comment_feed:$comment_key";
3501 $comment_ids = wp_cache_get_salted( $comment_cache_key, 'comment-queries', $comment_last_changed );
3502 if ( false === $comment_ids ) {
3503 $comment_ids = $wpdb->get_col( $comments_request );
3504 wp_cache_set_salted( $comment_cache_key, $comment_ids, 'comment-queries', $comment_last_changed );
3505 }
3506 _prime_comment_caches( $comment_ids );
3507
3508 // Convert to WP_Comment.
3509 /** @var WP_Comment[] */
3510 $this->comments = array_map( 'get_comment', $comment_ids );
3511 $this->comment_count = count( $this->comments );
3512 }
3513
3514 // Check post status to determine if post should be displayed.
3515 if ( ! empty( $this->posts ) && ( $this->is_single || $this->is_page ) ) {
3516 $status = get_post_status( $this->posts[0] );
3517
3518 if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) {
3519 $this->is_page = false;
3520 $this->is_single = true;
3521 $this->is_attachment = true;
3522 }
3523
3524 // If the post_status was specifically requested, let it pass through.
3525 if ( ! in_array( $status, $q_status, true ) ) {
3526 $post_status_obj = get_post_status_object( $status );
3527
3528 if ( $post_status_obj && ! $post_status_obj->public ) {
3529 if ( ! is_user_logged_in() ) {
3530 // User must be logged in to view unpublished posts.
3531 $this->posts = array();
3532 } else {
3533 if ( $post_status_obj->protected ) {
3534 // User must have edit permissions on the draft to preview.
3535 if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
3536 $this->posts = array();
3537 } else {
3538 $this->is_preview = true;
3539 if ( 'future' !== $status ) {
3540 $this->posts[0]->post_date = current_time( 'mysql' );
3541 }
3542 }
3543 } elseif ( $post_status_obj->private ) {
3544 if ( ! current_user_can( $read_cap, $this->posts[0]->ID ) ) {
3545 $this->posts = array();
3546 }
3547 } else {
3548 $this->posts = array();
3549 }
3550 }
3551 } elseif ( ! $post_status_obj ) {
3552 // Post status is not registered, assume it's not public.
3553 if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
3554 $this->posts = array();
3555 }
3556 }
3557 }
3558
3559 if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
3560 /**
3561 * Filters the single post for preview mode.
3562 *
3563 * @since 2.7.0
3564 *
3565 * @param WP_Post $post_preview The Post object.
3566 * @param WP_Query $query The WP_Query instance (passed by reference).
3567 */
3568 $this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
3569 }
3570 }
3571
3572 // Put sticky posts at the top of the posts array.
3573 $sticky_posts = get_option( 'sticky_posts' );
3574 if ( $this->is_home && $page <= 1 && is_array( $sticky_posts ) && ! empty( $sticky_posts ) && ! $query_vars['ignore_sticky_posts'] ) {
3575 $num_posts = count( $this->posts );
3576 $sticky_offset = 0;
3577 // Loop over posts and relocate stickies to the front.
3578 for ( $i = 0; $i < $num_posts; $i++ ) {
3579 if ( in_array( $this->posts[ $i ]->ID, $sticky_posts, true ) ) {
3580 $sticky_post = $this->posts[ $i ];
3581 // Remove sticky from current position.
3582 array_splice( $this->posts, $i, 1 );
3583 // Move to front, after other stickies.
3584 array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
3585 // Increment the sticky offset. The next sticky will be placed at this offset.
3586 ++$sticky_offset;
3587 // Remove post from sticky posts array.
3588 $offset = array_search( $sticky_post->ID, $sticky_posts, true );
3589 unset( $sticky_posts[ $offset ] );
3590 }
3591 }
3592
3593 // If any posts have been excluded specifically, Ignore those that are sticky.
3594 if ( ! empty( $sticky_posts ) && ! empty( $query_vars['post__not_in'] ) ) {
3595 $sticky_posts = array_diff( $sticky_posts, $query_vars['post__not_in'] );
3596 }
3597
3598 // Fetch sticky posts that weren't in the query results.
3599 if ( ! empty( $sticky_posts ) ) {
3600 $stickies = get_posts(
3601 array(
3602 'post__in' => $sticky_posts,
3603 'post_type' => $post_type,
3604 'post_status' => 'publish',
3605 'posts_per_page' => count( $sticky_posts ),
3606 'suppress_filters' => $query_vars['suppress_filters'],
3607 'cache_results' => $query_vars['cache_results'],
3608 'update_post_meta_cache' => $query_vars['update_post_meta_cache'],
3609 'update_post_term_cache' => $query_vars['update_post_term_cache'],
3610 'lazy_load_term_meta' => $query_vars['lazy_load_term_meta'],
3611 )
3612 );
3613
3614 foreach ( $stickies as $sticky_post ) {
3615 array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
3616 ++$sticky_offset;
3617 }
3618 }
3619 }
3620
3621 if ( ! $query_vars['suppress_filters'] ) {
3622 /**
3623 * Filters the array of retrieved posts after they've been fetched and
3624 * internally processed.
3625 *
3626 * @since 1.5.0
3627 *
3628 * @param WP_Post[] $posts Array of post objects.
3629 * @param WP_Query $query The WP_Query instance (passed by reference).
3630 */
3631 $this->posts = apply_filters_ref_array( 'the_posts', array( $this->posts, &$this ) );
3632 }
3633
3634 /*
3635 * Ensure that any posts added/modified via one of the filters above are
3636 * of the type WP_Post and are filtered.
3637 */
3638 if ( $this->posts ) {
3639 $this->post_count = count( $this->posts );
3640
3641 /** @var WP_Post[] */
3642 $this->posts = array_map( 'get_post', $this->posts );
3643
3644 if ( $query_vars['cache_results'] ) {
3645 if ( $is_unfiltered_query && $unfiltered_posts === $this->posts ) {
3646 update_post_caches( $this->posts, $post_type, $query_vars['update_post_term_cache'], $query_vars['update_post_meta_cache'] );
3647 } else {
3648 $post_ids = wp_list_pluck( $this->posts, 'ID' );
3649 _prime_post_caches( $post_ids, $query_vars['update_post_term_cache'], $query_vars['update_post_meta_cache'] );
3650 }
3651 }
3652
3653 /** @var WP_Post */
3654 $this->post = reset( $this->posts );
3655 } else {
3656 $this->post_count = 0;
3657 $this->posts = array();
3658 }
3659
3660 if ( ! empty( $this->posts ) && $query_vars['update_menu_item_cache'] ) {
3661 update_menu_item_cache( $this->posts );
3662 }
3663
3664 if ( $query_vars['lazy_load_term_meta'] ) {
3665 wp_queue_posts_for_term_meta_lazyload( $this->posts );
3666 }
3667
3668 return $this->posts;
3669 }
3670
3671 /**
3672 * Sets up the amount of found posts and the number of pages (if limit clause was used)
3673 * for the current query.
3674 *
3675 * @since 3.5.0
3676 *
3677 * @global wpdb $wpdb WordPress database abstraction object.
3678 *
3679 * @param array $query_vars Query variables.
3680 * @param string $limits LIMIT clauses of the query.
3681 */
3682 private function set_found_posts( $query_vars, $limits ) {
3683 global $wpdb;
3684
3685 /*
3686 * Bail if posts is an empty array. Continue if posts is an empty string,
3687 * null, or false to accommodate caching plugins that fill posts later.
3688 */
3689 if ( $query_vars['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) ) {
3690 return;
3691 }
3692
3693 if ( ! empty( $limits ) ) {
3694 /**
3695 * Filters the query to run for retrieving the found posts.
3696 *
3697 * @since 2.1.0
3698 *
3699 * @param string $found_posts_query The query to run to find the found posts.
3700 * @param WP_Query $query The WP_Query instance (passed by reference).
3701 */
3702 $found_posts_query = apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) );
3703
3704 $this->found_posts = (int) $wpdb->get_var( $found_posts_query );
3705 } else {
3706 if ( is_array( $this->posts ) ) {
3707 $this->found_posts = count( $this->posts );
3708 } else {
3709 if ( null === $this->posts ) {
3710 $this->found_posts = 0;
3711 } else {
3712 $this->found_posts = 1;
3713 }
3714 }
3715 }
3716
3717 /**
3718 * Filters the number of found posts for the query.
3719 *
3720 * @since 2.1.0
3721 *
3722 * @param int $found_posts The number of posts found.
3723 * @param WP_Query $query The WP_Query instance (passed by reference).
3724 */
3725 $this->found_posts = (int) apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
3726
3727 if ( ! empty( $limits ) ) {
3728 $this->max_num_pages = (int) ceil( $this->found_posts / $query_vars['posts_per_page'] );
3729 }
3730 }
3731
3732 /**
3733 * Sets up the next post and iterate current post index.
3734 *
3735 * @since 1.5.0
3736 *
3737 * @return WP_Post Next post.
3738 */
3739 public function next_post() {
3740
3741 ++$this->current_post;
3742
3743 /** @var WP_Post */
3744 $this->post = $this->posts[ $this->current_post ];
3745 return $this->post;
3746 }
3747
3748 /**
3749 * Sets up the current post.
3750 *
3751 * Retrieves the next post, sets up the post, sets the 'in the loop'
3752 * property to true.
3753 *
3754 * @since 1.5.0
3755 *
3756 * @global WP_Post $post Global post object.
3757 */
3758 public function the_post() {
3759 global $post;
3760
3761 if ( ! $this->in_the_loop ) {
3762 if ( 'all' === $this->query_vars['fields'] ) {
3763 // Full post objects queried.
3764 $post_objects = $this->posts;
3765 } else {
3766 if ( 'ids' === $this->query_vars['fields'] ) {
3767 // Post IDs queried.
3768 $post_ids = $this->posts;
3769 } else {
3770 // Only partial objects queried, need to prime the cache for the loop.
3771 $post_ids = array_reduce(
3772 $this->posts,
3773 function ( $carry, $post ) {
3774 if ( isset( $post->ID ) ) {
3775 $carry[] = $post->ID;
3776 }
3777
3778 return $carry;
3779 },
3780 array()
3781 );
3782 }
3783 _prime_post_caches( $post_ids, $this->query_vars['update_post_term_cache'], $this->query_vars['update_post_meta_cache'] );
3784 $post_objects = array_map( 'get_post', $post_ids );
3785 }
3786 update_post_author_caches( $post_objects );
3787 }
3788
3789 $this->in_the_loop = true;
3790 $this->before_loop = false;
3791
3792 if ( -1 === $this->current_post ) { // Loop has just started.
3793 /**
3794 * Fires once the loop is started.
3795 *
3796 * @since 2.0.0
3797 *
3798 * @param WP_Query $query The WP_Query instance (passed by reference).
3799 */
3800 do_action_ref_array( 'loop_start', array( &$this ) );
3801 }
3802
3803 $post = $this->next_post();
3804
3805 // Ensure a full post object is available.
3806 if ( 'all' !== $this->query_vars['fields'] ) {
3807 if ( 'ids' === $this->query_vars['fields'] ) {
3808 // Post IDs queried.
3809 $post = get_post( $post );
3810 } elseif ( isset( $post->ID ) ) {
3811 /*
3812 * Partial objecct queried.
3813 *
3814 * The post object was queried with a partial set of
3815 * fields, populate the entire object for the loop.
3816 */
3817 $post = get_post( $post->ID );
3818 }
3819 }
3820
3821 // Set up the global post object for the loop.
3822 $this->setup_postdata( $post );
3823 }
3824
3825 /**
3826 * Determines whether there are more posts available in the loop.
3827 *
3828 * Calls the {@see 'loop_end'} action when the loop is complete.
3829 *
3830 * @since 1.5.0
3831 *
3832 * @return bool True if posts are available, false if end of the loop.
3833 */
3834 public function have_posts() {
3835 if ( $this->current_post + 1 < $this->post_count ) {
3836 return true;
3837 } elseif ( $this->current_post + 1 === $this->post_count && $this->post_count > 0 ) {
3838 /**
3839 * Fires once the loop has ended.
3840 *
3841 * @since 2.0.0
3842 *
3843 * @param WP_Query $query The WP_Query instance (passed by reference).
3844 */
3845 do_action_ref_array( 'loop_end', array( &$this ) );
3846
3847 // Do some cleaning up after the loop.
3848 $this->rewind_posts();
3849 } elseif ( 0 === $this->post_count ) {
3850 $this->before_loop = false;
3851
3852 /**
3853 * Fires if no results are found in a post query.
3854 *
3855 * @since 4.9.0
3856 *
3857 * @param WP_Query $query The WP_Query instance.
3858 */
3859 do_action( 'loop_no_results', $this );
3860 }
3861
3862 $this->in_the_loop = false;
3863 return false;
3864 }
3865
3866 /**
3867 * Rewinds the posts and resets post index.
3868 *
3869 * @since 1.5.0
3870 */
3871 public function rewind_posts() {
3872 $this->current_post = -1;
3873 if ( $this->post_count > 0 ) {
3874 $this->post = $this->posts[0];
3875 }
3876 }
3877
3878 /**
3879 * Iterates current comment index and returns WP_Comment object.
3880 *
3881 * @since 2.2.0
3882 *
3883 * @return WP_Comment Comment object.
3884 */
3885 public function next_comment() {
3886 ++$this->current_comment;
3887
3888 /** @var WP_Comment */
3889 $this->comment = $this->comments[ $this->current_comment ];
3890 return $this->comment;
3891 }
3892
3893 /**
3894 * Sets up the current comment.
3895 *
3896 * @since 2.2.0
3897 *
3898 * @global WP_Comment $comment Global comment object.
3899 */
3900 public function the_comment() {
3901 global $comment;
3902
3903 $comment = $this->next_comment();
3904
3905 if ( 0 === $this->current_comment ) {
3906 /**
3907 * Fires once the comment loop is started.
3908 *
3909 * @since 2.2.0
3910 */
3911 do_action( 'comment_loop_start' );
3912 }
3913 }
3914
3915 /**
3916 * Determines whether there are more comments available.
3917 *
3918 * Automatically rewinds comments when finished.
3919 *
3920 * @since 2.2.0
3921 *
3922 * @return bool True if comments are available, false if no more comments.
3923 */
3924 public function have_comments() {
3925 if ( $this->current_comment + 1 < $this->comment_count ) {
3926 return true;
3927 } elseif ( $this->current_comment + 1 === $this->comment_count ) {
3928 $this->rewind_comments();
3929 }
3930
3931 return false;
3932 }
3933
3934 /**
3935 * Rewinds the comments, resets the comment index and comment to first.
3936 *
3937 * @since 2.2.0
3938 */
3939 public function rewind_comments() {
3940 $this->current_comment = -1;
3941 if ( $this->comment_count > 0 ) {
3942 $this->comment = $this->comments[0];
3943 }
3944 }
3945
3946 /**
3947 * Sets up the WordPress query by parsing query string.
3948 *
3949 * @since 1.5.0
3950 *
3951 * @see WP_Query::parse_query() for all available arguments.
3952 *
3953 * @param string|array $query URL query string or array of query arguments.
3954 * @return WP_Post[]|int[] Array of post objects or post IDs.
3955 */
3956 public function query( $query ) {
3957 $this->init();
3958 $this->query = wp_parse_args( $query );
3959 $this->query_vars = $this->query;
3960 return $this->get_posts();
3961 }
3962
3963 /**
3964 * Retrieves the currently queried object.
3965 *
3966 * If queried object is not set, then the queried object will be set from
3967 * the category, tag, taxonomy, posts page, single post, page, or author
3968 * query variable. After it is set up, it will be returned.
3969 *
3970 * @since 1.5.0
3971 *
3972 * @return WP_Term|WP_Post_Type|WP_Post|WP_User|null The queried object.
3973 */
3974 public function get_queried_object() {
3975 if ( isset( $this->queried_object ) ) {
3976 return $this->queried_object;
3977 }
3978
3979 $this->queried_object = null;
3980 $this->queried_object_id = null;
3981
3982 if ( $this->is_category || $this->is_tag || $this->is_tax ) {
3983 if ( $this->is_category ) {
3984 $cat = $this->get( 'cat' );
3985 $category_name = $this->get( 'category_name' );
3986
3987 if ( $cat ) {
3988 $term = get_term( $cat, 'category' );
3989 } elseif ( $category_name ) {
3990 $term = get_term_by( 'slug', $category_name, 'category' );
3991 }
3992 } elseif ( $this->is_tag ) {
3993 $tag_id = $this->get( 'tag_id' );
3994 $tag = $this->get( 'tag' );
3995
3996 if ( $tag_id ) {
3997 $term = get_term( $tag_id, 'post_tag' );
3998 } elseif ( $tag ) {
3999 $term = get_term_by( 'slug', $tag, 'post_tag' );
4000 }
4001 } else {
4002 // For other tax queries, grab the first term from the first clause.
4003 if ( ! empty( $this->tax_query->queried_terms ) ) {
4004 $queried_taxonomies = array_keys( $this->tax_query->queried_terms );
4005 $matched_taxonomy = reset( $queried_taxonomies );
4006 $query = $this->tax_query->queried_terms[ $matched_taxonomy ];
4007
4008 if ( ! empty( $query['terms'] ) ) {
4009 if ( 'term_id' === $query['field'] ) {
4010 $term = get_term( reset( $query['terms'] ), $matched_taxonomy );
4011 } else {
4012 $term = get_term_by( $query['field'], reset( $query['terms'] ), $matched_taxonomy );
4013 }
4014 }
4015 }
4016 }
4017
4018 if ( ! empty( $term ) && ! is_wp_error( $term ) ) {
4019 $this->queried_object = $term;
4020 $this->queried_object_id = (int) $term->term_id;
4021
4022 if ( $this->is_category && 'category' === $this->queried_object->taxonomy ) {
4023 _make_cat_compat( $this->queried_object );
4024 }
4025 }
4026 } elseif ( $this->is_post_type_archive ) {
4027 $post_type = $this->get( 'post_type' );
4028
4029 if ( is_array( $post_type ) ) {
4030 $post_type = reset( $post_type );
4031 }
4032
4033 $this->queried_object = get_post_type_object( $post_type );
4034 } elseif ( $this->is_posts_page ) {
4035 $page_for_posts = get_option( 'page_for_posts' );
4036
4037 $this->queried_object = get_post( $page_for_posts );
4038 $this->queried_object_id = (int) $this->queried_object->ID;
4039 } elseif ( $this->is_singular && ! empty( $this->post ) ) {
4040 $this->queried_object = $this->post;
4041 $this->queried_object_id = (int) $this->post->ID;
4042 } elseif ( $this->is_author ) {
4043 $author = (int) $this->get( 'author' );
4044 $author_name = $this->get( 'author_name' );
4045
4046 if ( $author ) {
4047 $this->queried_object_id = $author;
4048 } elseif ( $author_name ) {
4049 $user = get_user_by( 'slug', $author_name );
4050
4051 if ( $user ) {
4052 $this->queried_object_id = $user->ID;
4053 }
4054 }
4055
4056 $this->queried_object = get_userdata( $this->queried_object_id );
4057 }
4058
4059 return $this->queried_object;
4060 }
4061
4062 /**
4063 * Retrieves the ID of the currently queried object.
4064 *
4065 * @since 1.5.0
4066 *
4067 * @return int
4068 */
4069 public function get_queried_object_id() {
4070 $this->get_queried_object();
4071
4072 if ( isset( $this->queried_object_id ) ) {
4073 return $this->queried_object_id;
4074 }
4075
4076 return 0;
4077 }
4078
4079 /**
4080 * Constructor.
4081 *
4082 * Sets up the WordPress query, if parameter is not empty.
4083 *
4084 * @since 1.5.0
4085 *
4086 * @see WP_Query::parse_query() for all available arguments.
4087 *
4088 * @param string|array $query URL query string or array of vars.
4089 */
4090 public function __construct( $query = '' ) {
4091 if ( ! empty( $query ) ) {
4092 $this->query( $query );
4093 }
4094 }
4095
4096 /**
4097 * Makes private properties readable for backward compatibility.
4098 *
4099 * @since 4.0.0
4100 *
4101 * @param string $name Property to get.
4102 * @return mixed Property.
4103 */
4104 public function __get( $name ) {
4105 if ( in_array( $name, $this->compat_fields, true ) ) {
4106 return $this->$name;
4107 }
4108 }
4109
4110 /**
4111 * Makes private properties checkable for backward compatibility.
4112 *
4113 * @since 4.0.0
4114 *
4115 * @param string $name Property to check if set.
4116 * @return bool Whether the property is set.
4117 */
4118 public function __isset( $name ) {
4119 if ( in_array( $name, $this->compat_fields, true ) ) {
4120 return isset( $this->$name );
4121 }
4122
4123 return false;
4124 }
4125
4126 /**
4127 * Makes private/protected methods readable for backward compatibility.
4128 *
4129 * @since 4.0.0
4130 *
4131 * @param string $name Method to call.
4132 * @param array $arguments Arguments to pass when calling.
4133 * @return mixed|false Return value of the callback, false otherwise.
4134 */
4135 public function __call( $name, $arguments ) {
4136 if ( in_array( $name, $this->compat_methods, true ) ) {
4137 return $this->$name( ...$arguments );
4138 }
4139 return false;
4140 }
4141
4142 /**
4143 * Determines whether the query is for an existing archive page.
4144 *
4145 * Archive pages include category, tag, author, date, custom post type,
4146 * and custom taxonomy based archives.
4147 *
4148 * @since 3.1.0
4149 *
4150 * @see WP_Query::is_category()
4151 * @see WP_Query::is_tag()
4152 * @see WP_Query::is_author()
4153 * @see WP_Query::is_date()
4154 * @see WP_Query::is_post_type_archive()
4155 * @see WP_Query::is_tax()
4156 *
4157 * @return bool Whether the query is for an existing archive page.
4158 */
4159 public function is_archive() {
4160 return (bool) $this->is_archive;
4161 }
4162
4163 /**
4164 * Determines whether the query is for an existing post type archive page.
4165 *
4166 * @since 3.1.0
4167 *
4168 * @param string|string[] $post_types Optional. Post type or array of posts types
4169 * to check against. Default empty.
4170 * @return bool Whether the query is for an existing post type archive page.
4171 */
4172 public function is_post_type_archive( $post_types = '' ) {
4173 if ( empty( $post_types ) || ! $this->is_post_type_archive ) {
4174 return (bool) $this->is_post_type_archive;
4175 }
4176
4177 $post_type = $this->get( 'post_type' );
4178 if ( is_array( $post_type ) ) {
4179 $post_type = reset( $post_type );
4180 }
4181 $post_type_object = get_post_type_object( $post_type );
4182
4183 if ( ! $post_type_object ) {
4184 return false;
4185 }
4186
4187 return in_array( $post_type_object->name, (array) $post_types, true );
4188 }
4189
4190 /**
4191 * Determines whether the query is for an existing attachment page.
4192 *
4193 * @since 3.1.0
4194 *
4195 * @param int|string|int[]|string[] $attachment Optional. Attachment ID, title, slug, or array of such
4196 * to check against. Default empty.
4197 * @return bool Whether the query is for an existing attachment page.
4198 */
4199 public function is_attachment( $attachment = '' ) {
4200 if ( ! $this->is_attachment ) {
4201 return false;
4202 }
4203
4204 if ( empty( $attachment ) ) {
4205 return true;
4206 }
4207
4208 $attachment = array_map( 'strval', (array) $attachment );
4209
4210 $post_obj = $this->get_queried_object();
4211 if ( ! $post_obj ) {
4212 return false;
4213 }
4214
4215 if ( in_array( (string) $post_obj->ID, $attachment, true ) ) {
4216 return true;
4217 } elseif ( in_array( $post_obj->post_title, $attachment, true ) ) {
4218 return true;
4219 } elseif ( in_array( $post_obj->post_name, $attachment, true ) ) {
4220 return true;
4221 }
4222 return false;
4223 }
4224
4225 /**
4226 * Determines whether the query is for an existing author archive page.
4227 *
4228 * If the $author parameter is specified, this function will additionally
4229 * check if the query is for one of the authors specified.
4230 *
4231 * @since 3.1.0
4232 *
4233 * @param int|string|int[]|string[] $author Optional. User ID, nickname, nicename, or array of such
4234 * to check against. Default empty.
4235 * @return bool Whether the query is for an existing author archive page.
4236 */
4237 public function is_author( $author = '' ) {
4238 if ( ! $this->is_author ) {
4239 return false;
4240 }
4241
4242 if ( empty( $author ) ) {
4243 return true;
4244 }
4245
4246 $author_obj = $this->get_queried_object();
4247 if ( ! $author_obj ) {
4248 return false;
4249 }
4250
4251 $author = array_map( 'strval', (array) $author );
4252
4253 if ( in_array( (string) $author_obj->ID, $author, true ) ) {
4254 return true;
4255 } elseif ( in_array( $author_obj->nickname, $author, true ) ) {
4256 return true;
4257 } elseif ( in_array( $author_obj->user_nicename, $author, true ) ) {
4258 return true;
4259 }
4260
4261 return false;
4262 }
4263
4264 /**
4265 * Determines whether the query is 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 int|string|int[]|string[] $category Optional. Category ID, name, slug, or array of such
4273 * to check against. Default empty.
4274 * @return bool Whether the query is for an existing category archive page.
4275 */
4276 public function is_category( $category = '' ) {
4277 if ( ! $this->is_category ) {
4278 return false;
4279 }
4280
4281 if ( empty( $category ) ) {
4282 return true;
4283 }
4284
4285 $cat_obj = $this->get_queried_object();
4286 if ( ! $cat_obj ) {
4287 return false;
4288 }
4289
4290 $category = array_map( 'strval', (array) $category );
4291
4292 if ( in_array( (string) $cat_obj->term_id, $category, true ) ) {
4293 return true;
4294 } elseif ( in_array( $cat_obj->name, $category, true ) ) {
4295 return true;
4296 } elseif ( in_array( $cat_obj->slug, $category, true ) ) {
4297 return true;
4298 }
4299
4300 return false;
4301 }
4302
4303 /**
4304 * Determines whether the query is for an existing tag archive page.
4305 *
4306 * If the $tag parameter is specified, this function will additionally
4307 * check if the query is for one of the tags specified.
4308 *
4309 * @since 3.1.0
4310 *
4311 * @param int|string|int[]|string[] $tag Optional. Tag ID, name, slug, or array of such
4312 * to check against. Default empty.
4313 * @return bool Whether the query is for an existing tag archive page.
4314 */
4315 public function is_tag( $tag = '' ) {
4316 if ( ! $this->is_tag ) {
4317 return false;
4318 }
4319
4320 if ( empty( $tag ) ) {
4321 return true;
4322 }
4323
4324 $tag_obj = $this->get_queried_object();
4325 if ( ! $tag_obj ) {
4326 return false;
4327 }
4328
4329 $tag = array_map( 'strval', (array) $tag );
4330
4331 if ( in_array( (string) $tag_obj->term_id, $tag, true ) ) {
4332 return true;
4333 } elseif ( in_array( $tag_obj->name, $tag, true ) ) {
4334 return true;
4335 } elseif ( in_array( $tag_obj->slug, $tag, true ) ) {
4336 return true;
4337 }
4338
4339 return false;
4340 }
4341
4342 /**
4343 * Determines whether the query is for an existing custom taxonomy archive page.
4344 *
4345 * If the $taxonomy parameter is specified, this function will additionally
4346 * check if the query is for that specific $taxonomy.
4347 *
4348 * If the $term parameter is specified in addition to the $taxonomy parameter,
4349 * this function will additionally check if the query is for one of the terms
4350 * specified.
4351 *
4352 * @since 3.1.0
4353 *
4354 * @global WP_Taxonomy[] $wp_taxonomies Registered taxonomies.
4355 *
4356 * @param string|string[] $taxonomy Optional. Taxonomy slug or slugs to check against.
4357 * Default empty.
4358 * @param int|string|int[]|string[] $term Optional. Term ID, name, slug, or array of such
4359 * to check against. Default empty.
4360 * @return bool Whether the query is for an existing custom taxonomy archive page.
4361 * True for custom taxonomy archive pages, false for built-in taxonomies
4362 * (category and tag archives).
4363 */
4364 public function is_tax( $taxonomy = '', $term = '' ) {
4365 global $wp_taxonomies;
4366
4367 if ( ! $this->is_tax ) {
4368 return false;
4369 }
4370
4371 if ( empty( $taxonomy ) ) {
4372 return true;
4373 }
4374
4375 $queried_object = $this->get_queried_object();
4376 $tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
4377 $term_array = (array) $term;
4378
4379 // Check that the taxonomy matches.
4380 if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array, true ) ) ) {
4381 return false;
4382 }
4383
4384 // Only a taxonomy provided.
4385 if ( empty( $term ) ) {
4386 return true;
4387 }
4388
4389 return isset( $queried_object->term_id ) &&
4390 count(
4391 array_intersect(
4392 array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
4393 $term_array
4394 )
4395 );
4396 }
4397
4398 /**
4399 * Determines whether the current URL is within the comments popup window.
4400 *
4401 * @since 3.1.0
4402 * @deprecated 4.5.0
4403 *
4404 * @return false Always returns false.
4405 */
4406 public function is_comments_popup() {
4407 _deprecated_function( __FUNCTION__, '4.5.0' );
4408
4409 return false;
4410 }
4411
4412 /**
4413 * Determines whether the query is for an existing date archive.
4414 *
4415 * @since 3.1.0
4416 *
4417 * @return bool Whether the query is for an existing date archive.
4418 */
4419 public function is_date() {
4420 return (bool) $this->is_date;
4421 }
4422
4423 /**
4424 * Determines whether the query is for an existing day archive.
4425 *
4426 * @since 3.1.0
4427 *
4428 * @return bool Whether the query is for an existing day archive.
4429 */
4430 public function is_day() {
4431 return (bool) $this->is_day;
4432 }
4433
4434 /**
4435 * Determines whether the query is for a feed.
4436 *
4437 * @since 3.1.0
4438 *
4439 * @param string|string[] $feeds Optional. Feed type or array of feed types
4440 * to check against. Default empty.
4441 * @return bool Whether the query is for a feed.
4442 */
4443 public function is_feed( $feeds = '' ) {
4444 if ( empty( $feeds ) || ! $this->is_feed ) {
4445 return (bool) $this->is_feed;
4446 }
4447
4448 $query_var = $this->get( 'feed' );
4449 if ( 'feed' === $query_var ) {
4450 $query_var = get_default_feed();
4451 }
4452
4453 return in_array( $query_var, (array) $feeds, true );
4454 }
4455
4456 /**
4457 * Determines whether the query is for a comments feed.
4458 *
4459 * @since 3.1.0
4460 *
4461 * @return bool Whether the query is for a comments feed.
4462 */
4463 public function is_comment_feed() {
4464 return (bool) $this->is_comment_feed;
4465 }
4466
4467 /**
4468 * Determines whether the query is for the front page of the site.
4469 *
4470 * This is for what is displayed at your site's main URL.
4471 *
4472 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
4473 *
4474 * If you set a static page for the front page of your site, this function will return
4475 * true when viewing that page.
4476 *
4477 * Otherwise the same as {@see WP_Query::is_home()}.
4478 *
4479 * @since 3.1.0
4480 *
4481 * @return bool Whether the query is for the front page of the site.
4482 */
4483 public function is_front_page() {
4484 // Most likely case.
4485 if ( 'posts' === get_option( 'show_on_front' ) && $this->is_home() ) {
4486 return true;
4487 } elseif ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' )
4488 && $this->is_page( get_option( 'page_on_front' ) )
4489 ) {
4490 return true;
4491 } else {
4492 return false;
4493 }
4494 }
4495
4496 /**
4497 * Determines whether the query is for the blog homepage.
4498 *
4499 * This is the page which shows the time based blog content of your site.
4500 *
4501 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
4502 *
4503 * If you set a static page for the front page of your site, this function will return
4504 * true only on the page you set as the "Posts page".
4505 *
4506 * @since 3.1.0
4507 *
4508 * @see WP_Query::is_front_page()
4509 *
4510 * @return bool Whether the query is for the blog homepage.
4511 */
4512 public function is_home() {
4513 return (bool) $this->is_home;
4514 }
4515
4516 /**
4517 * Determines whether the query is for the Privacy Policy page.
4518 *
4519 * This is the page which shows the Privacy Policy content of your site.
4520 *
4521 * Depends on the site's "Change your Privacy Policy page" Privacy Settings 'wp_page_for_privacy_policy'.
4522 *
4523 * This function will return true only on the page you set as the "Privacy Policy page".
4524 *
4525 * @since 5.2.0
4526 *
4527 * @return bool Whether the query is for the Privacy Policy page.
4528 */
4529 public function is_privacy_policy() {
4530 if ( get_option( 'wp_page_for_privacy_policy' )
4531 && $this->is_page( get_option( 'wp_page_for_privacy_policy' ) )
4532 ) {
4533 return true;
4534 } else {
4535 return false;
4536 }
4537 }
4538
4539 /**
4540 * Determines whether the query is for an existing month archive.
4541 *
4542 * @since 3.1.0
4543 *
4544 * @return bool Whether the query is for an existing month archive.
4545 */
4546 public function is_month() {
4547 return (bool) $this->is_month;
4548 }
4549
4550 /**
4551 * Determines whether the query is for an existing single page.
4552 *
4553 * If the $page parameter is specified, this function will additionally
4554 * check if the query is for one of the pages specified.
4555 *
4556 * @since 3.1.0
4557 *
4558 * @see WP_Query::is_single()
4559 * @see WP_Query::is_singular()
4560 *
4561 * @param int|string|int[]|string[] $page Optional. Page ID, title, slug, path, or array of such
4562 * to check against. Default empty.
4563 * @return bool Whether the query is for an existing single page.
4564 */
4565 public function is_page( $page = '' ) {
4566 if ( ! $this->is_page ) {
4567 return false;
4568 }
4569
4570 if ( empty( $page ) ) {
4571 return true;
4572 }
4573
4574 $page_obj = $this->get_queried_object();
4575 if ( ! $page_obj ) {
4576 return false;
4577 }
4578
4579 $page = array_map( 'strval', (array) $page );
4580
4581 if ( in_array( (string) $page_obj->ID, $page, true ) ) {
4582 return true;
4583 } elseif ( in_array( $page_obj->post_title, $page, true ) ) {
4584 return true;
4585 } elseif ( in_array( $page_obj->post_name, $page, true ) ) {
4586 return true;
4587 } else {
4588 foreach ( $page as $pagepath ) {
4589 if ( ! strpos( $pagepath, '/' ) ) {
4590 continue;
4591 }
4592
4593 $pagepath_obj = get_page_by_path( $pagepath );
4594
4595 if ( $pagepath_obj && ( $pagepath_obj->ID === $page_obj->ID ) ) {
4596 return true;
4597 }
4598 }
4599 }
4600
4601 return false;
4602 }
4603
4604 /**
4605 * Determines whether the query is for a paged result and not for the first page.
4606 *
4607 * @since 3.1.0
4608 *
4609 * @return bool Whether the query is for a paged result.
4610 */
4611 public function is_paged() {
4612 return (bool) $this->is_paged;
4613 }
4614
4615 /**
4616 * Determines whether the query is for a post or page preview.
4617 *
4618 * @since 3.1.0
4619 *
4620 * @return bool Whether the query is for a post or page preview.
4621 */
4622 public function is_preview() {
4623 return (bool) $this->is_preview;
4624 }
4625
4626 /**
4627 * Determines whether the query is for the robots.txt file.
4628 *
4629 * @since 3.1.0
4630 *
4631 * @return bool Whether the query is for the robots.txt file.
4632 */
4633 public function is_robots() {
4634 return (bool) $this->is_robots;
4635 }
4636
4637 /**
4638 * Determines whether the query is for the favicon.ico file.
4639 *
4640 * @since 5.4.0
4641 *
4642 * @return bool Whether the query is for the favicon.ico file.
4643 */
4644 public function is_favicon() {
4645 return (bool) $this->is_favicon;
4646 }
4647
4648 /**
4649 * Determines whether the query is for a search.
4650 *
4651 * @since 3.1.0
4652 *
4653 * @return bool Whether the query is for a search.
4654 */
4655 public function is_search() {
4656 return (bool) $this->is_search;
4657 }
4658
4659 /**
4660 * Determines whether the query is for an existing single post.
4661 *
4662 * Works for any post type excluding pages.
4663 *
4664 * If the $post parameter is specified, this function will additionally
4665 * check if the query is for one of the Posts specified.
4666 *
4667 * @since 3.1.0
4668 *
4669 * @see WP_Query::is_page()
4670 * @see WP_Query::is_singular()
4671 *
4672 * @param int|string|int[]|string[] $post Optional. Post ID, title, slug, path, or array of such
4673 * to check against. Default empty.
4674 * @return bool Whether the query is for an existing single post.
4675 */
4676 public function is_single( $post = '' ) {
4677 if ( ! $this->is_single ) {
4678 return false;
4679 }
4680
4681 if ( empty( $post ) ) {
4682 return true;
4683 }
4684
4685 $post_obj = $this->get_queried_object();
4686 if ( ! $post_obj ) {
4687 return false;
4688 }
4689
4690 $post = array_map( 'strval', (array) $post );
4691
4692 if ( in_array( (string) $post_obj->ID, $post, true ) ) {
4693 return true;
4694 } elseif ( in_array( $post_obj->post_title, $post, true ) ) {
4695 return true;
4696 } elseif ( in_array( $post_obj->post_name, $post, true ) ) {
4697 return true;
4698 } else {
4699 foreach ( $post as $postpath ) {
4700 if ( ! strpos( $postpath, '/' ) ) {
4701 continue;
4702 }
4703
4704 $postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );
4705
4706 if ( $postpath_obj && ( $postpath_obj->ID === $post_obj->ID ) ) {
4707 return true;
4708 }
4709 }
4710 }
4711 return false;
4712 }
4713
4714 /**
4715 * Determines whether the query is for an existing single post of any post type
4716 * (post, attachment, page, custom post types).
4717 *
4718 * If the $post_types parameter is specified, this function will additionally
4719 * check if the query is for one of the Posts Types specified.
4720 *
4721 * @since 3.1.0
4722 *
4723 * @see WP_Query::is_page()
4724 * @see WP_Query::is_single()
4725 *
4726 * @param string|string[] $post_types Optional. Post type or array of post types
4727 * to check against. Default empty.
4728 * @return bool Whether the query is for an existing single post
4729 * or any of the given post types.
4730 */
4731 public function is_singular( $post_types = '' ) {
4732 if ( empty( $post_types ) || ! $this->is_singular ) {
4733 return (bool) $this->is_singular;
4734 }
4735
4736 $post_obj = $this->get_queried_object();
4737 if ( ! $post_obj ) {
4738 return false;
4739 }
4740
4741 return in_array( $post_obj->post_type, (array) $post_types, true );
4742 }
4743
4744 /**
4745 * Determines whether the query is for a specific time.
4746 *
4747 * @since 3.1.0
4748 *
4749 * @return bool Whether the query is for a specific time.
4750 */
4751 public function is_time() {
4752 return (bool) $this->is_time;
4753 }
4754
4755 /**
4756 * Determines whether the query is for a trackback endpoint call.
4757 *
4758 * @since 3.1.0
4759 *
4760 * @return bool Whether the query is for a trackback endpoint call.
4761 */
4762 public function is_trackback() {
4763 return (bool) $this->is_trackback;
4764 }
4765
4766 /**
4767 * Determines whether the query is for an existing year archive.
4768 *
4769 * @since 3.1.0
4770 *
4771 * @return bool Whether the query is for an existing year archive.
4772 */
4773 public function is_year() {
4774 return (bool) $this->is_year;
4775 }
4776
4777 /**
4778 * Determines whether the query is a 404 (returns no results).
4779 *
4780 * @since 3.1.0
4781 *
4782 * @return bool Whether the query is a 404 error.
4783 */
4784 public function is_404() {
4785 return (bool) $this->is_404;
4786 }
4787
4788 /**
4789 * Determines whether the query is for an embedded post.
4790 *
4791 * @since 4.4.0
4792 *
4793 * @return bool Whether the query is for an embedded post.
4794 */
4795 public function is_embed() {
4796 return (bool) $this->is_embed;
4797 }
4798
4799 /**
4800 * Determines whether the query is the main query.
4801 *
4802 * @since 3.3.0
4803 *
4804 * @global WP_Query $wp_the_query WordPress Query object.
4805 *
4806 * @return bool Whether the query is the main query.
4807 */
4808 public function is_main_query() {
4809 global $wp_the_query;
4810 return $wp_the_query === $this;
4811 }
4812
4813 /**
4814 * Sets up global post data.
4815 *
4816 * @since 4.1.0
4817 * @since 4.4.0 Added the ability to pass a post ID to `$post`.
4818 *
4819 * @global int $id
4820 * @global WP_User $authordata
4821 * @global string $currentday
4822 * @global string $currentmonth
4823 * @global int $page
4824 * @global array $pages
4825 * @global int $multipage
4826 * @global int $more
4827 * @global int $numpages
4828 *
4829 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
4830 * @return true True when finished.
4831 */
4832 public function setup_postdata( $post ) {
4833 global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;
4834
4835 if ( ! ( $post instanceof WP_Post ) ) {
4836 $post = get_post( $post );
4837 }
4838
4839 if ( ! $post ) {
4840 return;
4841 }
4842
4843 $elements = $this->generate_postdata( $post );
4844 if ( false === $elements ) {
4845 return;
4846 }
4847
4848 $id = $elements['id'];
4849 $authordata = $elements['authordata'];
4850 $currentday = $elements['currentday'];
4851 $currentmonth = $elements['currentmonth'];
4852 $page = $elements['page'];
4853 $pages = $elements['pages'];
4854 $multipage = $elements['multipage'];
4855 $more = $elements['more'];
4856 $numpages = $elements['numpages'];
4857
4858 /**
4859 * Fires once the post data has been set up.
4860 *
4861 * @since 2.8.0
4862 * @since 4.1.0 Introduced `$query` parameter.
4863 *
4864 * @param WP_Post $post The Post object (passed by reference).
4865 * @param WP_Query $query The current Query object (passed by reference).
4866 */
4867 do_action_ref_array( 'the_post', array( &$post, &$this ) );
4868
4869 return true;
4870 }
4871
4872 /**
4873 * Generates post data.
4874 *
4875 * @since 5.2.0
4876 *
4877 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
4878 * @return array|false Elements of post or false on failure.
4879 */
4880 public function generate_postdata( $post ) {
4881
4882 if ( ! ( $post instanceof WP_Post ) ) {
4883 $post = get_post( $post );
4884 }
4885
4886 if ( ! $post ) {
4887 return false;
4888 }
4889
4890 $id = (int) $post->ID;
4891
4892 $authordata = get_userdata( $post->post_author );
4893
4894 $currentday = false;
4895 $currentmonth = false;
4896
4897 $post_date = $post->post_date;
4898 if ( ! empty( $post_date ) && '0000-00-00 00:00:00' !== $post_date ) {
4899 // Avoid using mysql2date for performance reasons.
4900 $currentmonth = substr( $post_date, 5, 2 );
4901 $day = substr( $post_date, 8, 2 );
4902 $year = substr( $post_date, 2, 2 );
4903
4904 $currentday = sprintf( '%s.%s.%s', $day, $currentmonth, $year );
4905 }
4906
4907 $numpages = 1;
4908 $multipage = 0;
4909 $page = $this->get( 'page' );
4910 if ( ! $page ) {
4911 $page = 1;
4912 }
4913
4914 /*
4915 * Force full post content when viewing the permalink for the $post,
4916 * or when on an RSS feed. Otherwise respect the 'more' tag.
4917 */
4918 if ( get_queried_object_id() === $post->ID && ( $this->is_page() || $this->is_single() ) ) {
4919 $more = 1;
4920 } elseif ( $this->is_feed() ) {
4921 $more = 1;
4922 } else {
4923 $more = 0;
4924 }
4925
4926 $content = $post->post_content;
4927 if ( str_contains( $content, '<!--nextpage-->' ) ) {
4928 $content = str_replace( "\n<!--nextpage-->\n", '<!--nextpage-->', $content );
4929 $content = str_replace( "\n<!--nextpage-->", '<!--nextpage-->', $content );
4930 $content = str_replace( "<!--nextpage-->\n", '<!--nextpage-->', $content );
4931
4932 // Remove the nextpage block delimiters, to avoid invalid block structures in the split content.
4933 $content = str_replace( '<!-- wp:nextpage -->', '', $content );
4934 $content = str_replace( '<!-- /wp:nextpage -->', '', $content );
4935
4936 // Ignore nextpage at the beginning of the content.
4937 if ( str_starts_with( $content, '<!--nextpage-->' ) ) {
4938 $content = substr( $content, 15 );
4939 }
4940
4941 $pages = explode( '<!--nextpage-->', $content );
4942 } else {
4943 $pages = array( $post->post_content );
4944 }
4945
4946 /**
4947 * Filters the "pages" derived from splitting the post content.
4948 *
4949 * "Pages" are determined by splitting the post content based on the presence
4950 * of `<!-- nextpage -->` tags.
4951 *
4952 * @since 4.4.0
4953 *
4954 * @param string[] $pages Array of "pages" from the post content split by `<!-- nextpage -->` tags.
4955 * @param WP_Post $post Current post object.
4956 */
4957 $pages = apply_filters( 'content_pagination', $pages, $post );
4958
4959 $numpages = count( $pages );
4960
4961 if ( $numpages > 1 ) {
4962 if ( $page > 1 ) {
4963 $more = 1;
4964 }
4965 $multipage = 1;
4966 } else {
4967 $multipage = 0;
4968 }
4969
4970 $elements = compact( 'id', 'authordata', 'currentday', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages' );
4971
4972 return $elements;
4973 }
4974
4975 /**
4976 * Generates cache key.
4977 *
4978 * @since 6.1.0
4979 *
4980 * @global wpdb $wpdb WordPress database abstraction object.
4981 *
4982 * @param array $args Query arguments.
4983 * @param string $sql SQL statement.
4984 * @return string Cache key.
4985 */
4986 protected function generate_cache_key( array $args, $sql ) {
4987 global $wpdb;
4988
4989 unset(
4990 $args['cache_results'],
4991 $args['fields'],
4992 $args['lazy_load_term_meta'],
4993 $args['update_post_meta_cache'],
4994 $args['update_post_term_cache'],
4995 $args['update_menu_item_cache'],
4996 $args['suppress_filters']
4997 );
4998
4999 if ( empty( $args['post_type'] ) ) {
5000 if ( $this->is_attachment ) {
5001 $args['post_type'] = 'attachment';
5002 } elseif ( $this->is_page ) {
5003 $args['post_type'] = 'page';
5004 } else {
5005 $args['post_type'] = 'post';
5006 }
5007 } elseif ( 'any' === $args['post_type'] ) {
5008 $args['post_type'] = array_values( get_post_types( array( 'exclude_from_search' => false ) ) );
5009 }
5010 $args['post_type'] = (array) $args['post_type'];
5011 // Sort post types to ensure same cache key generation.
5012 sort( $args['post_type'] );
5013
5014 /*
5015 * Sort arrays that can be used for ordering prior to cache key generation.
5016 *
5017 * These arrays are sorted in the query generator for the purposes of the
5018 * WHERE clause but the arguments are not modified as they can be used for
5019 * the orderby clause.
5020 *
5021 * Their use in the orderby clause will generate a different SQL query so
5022 * they can be sorted for the cache key generation.
5023 */
5024 $sortable_arrays_with_int_values = array(
5025 'post__in',
5026 'post_parent__in',
5027 );
5028 foreach ( $sortable_arrays_with_int_values as $key ) {
5029 if ( isset( $args[ $key ] ) && is_array( $args[ $key ] ) ) {
5030 $args[ $key ] = array_unique( array_map( 'absint', $args[ $key ] ) );
5031 sort( $args[ $key ] );
5032 }
5033 }
5034
5035 // Sort and unique the 'post_name__in' for cache key generation.
5036 if ( isset( $args['post_name__in'] ) && is_array( $args['post_name__in'] ) ) {
5037 $args['post_name__in'] = array_unique( $args['post_name__in'] );
5038 sort( $args['post_name__in'] );
5039 }
5040
5041 if ( isset( $args['post_status'] ) ) {
5042 $args['post_status'] = (array) $args['post_status'];
5043 // Sort post status to ensure same cache key generation.
5044 sort( $args['post_status'] );
5045 }
5046
5047 // Add a default orderby value of date to ensure same cache key generation.
5048 if ( ! isset( $args['orderby'] ) ) {
5049 $args['orderby'] = 'date';
5050 }
5051
5052 $placeholder = $wpdb->placeholder_escape();
5053 array_walk_recursive(
5054 $args,
5055 /*
5056 * Replace wpdb placeholders with the string used in the database
5057 * query to avoid unreachable cache keys. This is necessary because
5058 * the placeholder is randomly generated in each request.
5059 *
5060 * $value is passed by reference to allow it to be modified.
5061 * array_walk_recursive() does not return an array.
5062 */
5063 static function ( &$value ) use ( $wpdb, $placeholder ) {
5064 if ( is_string( $value ) && str_contains( $value, $placeholder ) ) {
5065 $value = $wpdb->remove_placeholder_escape( $value );
5066 }
5067 }
5068 );
5069
5070 ksort( $args );
5071
5072 // Replace wpdb placeholder in the SQL statement used by the cache key.
5073 $sql = $wpdb->remove_placeholder_escape( $sql );
5074 $key = md5( serialize( $args ) . $sql );
5075
5076 $this->query_cache_key = "wp_query:$key";
5077 return $this->query_cache_key;
5078 }
5079
5080 /**
5081 * After looping through a nested query, this function
5082 * restores the $post global to the current post in this query.
5083 *
5084 * @since 3.7.0
5085 *
5086 * @global WP_Post $post Global post object.
5087 */
5088 public function reset_postdata() {
5089 if ( ! empty( $this->post ) ) {
5090 $GLOBALS['post'] = $this->post;
5091 $this->setup_postdata( $this->post );
5092 }
5093 }
5094
5095 /**
5096 * Lazyloads term meta for posts in the loop.
5097 *
5098 * @since 4.4.0
5099 * @deprecated 4.5.0 See wp_queue_posts_for_term_meta_lazyload().
5100 *
5101 * @param mixed $check
5102 * @param int $term_id
5103 * @return mixed
5104 */
5105 public function lazyload_term_meta( $check, $term_id ) {
5106 _deprecated_function( __METHOD__, '4.5.0' );
5107 return $check;
5108 }
5109
5110 /**
5111 * Lazyloads comment meta for comments in the loop.
5112 *
5113 * @since 4.4.0
5114 * @deprecated 4.5.0 See wp_lazyload_comment_meta().
5115 *
5116 * @param mixed $check
5117 * @param int $comment_id
5118 * @return mixed
5119 */
5120 public function lazyload_comment_meta( $check, $comment_id ) {
5121 _deprecated_function( __METHOD__, '4.5.0' );
5122 return $check;
5123 }
5124}
5125
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1