changeset 7 | cf61fcea0001 |
parent 5 | 5e2f62d02dcd |
child 9 | 177826044cd9 |
6:490d5cc509ed | 7:cf61fcea0001 |
---|---|
10 * Public query variables. |
10 * Public query variables. |
11 * |
11 * |
12 * Long list of public query variables. |
12 * Long list of public query variables. |
13 * |
13 * |
14 * @since 2.0.0 |
14 * @since 2.0.0 |
15 * @access public |
|
16 * @var array |
15 * @var array |
17 */ |
16 */ |
18 public $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type'); |
17 public $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' ); |
19 |
18 |
20 /** |
19 /** |
21 * Private query variables. |
20 * Private query variables. |
22 * |
21 * |
23 * Long list of private query variables. |
22 * Long list of private query variables. |
24 * |
23 * |
25 * @since 2.0.0 |
24 * @since 2.0.0 |
26 * @var array |
25 * @var array |
27 */ |
26 */ |
28 public $private_query_vars = array( 'offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in', 'post_parent', 'post_parent__in', 'post_parent__not_in' ); |
27 public $private_query_vars = array( 'offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in', 'post_parent', 'post_parent__in', 'post_parent__not_in', 'title', 'fields' ); |
29 |
28 |
30 /** |
29 /** |
31 * Extra query variables set by the user. |
30 * Extra query variables set by the user. |
32 * |
31 * |
33 * @since 2.1.0 |
32 * @since 2.1.0 |
50 * @var string |
49 * @var string |
51 */ |
50 */ |
52 public $query_string; |
51 public $query_string; |
53 |
52 |
54 /** |
53 /** |
55 * Permalink or requested URI. |
54 * The request path, e.g. 2015/05/06. |
56 * |
55 * |
57 * @since 2.0.0 |
56 * @since 2.0.0 |
58 * @var string |
57 * @var string |
59 */ |
58 */ |
60 public $request; |
59 public $request; |
94 if ( !in_array($qv, $this->public_query_vars) ) |
93 if ( !in_array($qv, $this->public_query_vars) ) |
95 $this->public_query_vars[] = $qv; |
94 $this->public_query_vars[] = $qv; |
96 } |
95 } |
97 |
96 |
98 /** |
97 /** |
98 * Removes a query variable from a list of public query variables. |
|
99 * |
|
100 * @since 4.5.0 |
|
101 * |
|
102 * @param string $name Query variable name. |
|
103 */ |
|
104 public function remove_query_var( $name ) { |
|
105 $this->public_query_vars = array_diff( $this->public_query_vars, array( $name ) ); |
|
106 } |
|
107 |
|
108 /** |
|
99 * Set the value of a query variable. |
109 * Set the value of a query variable. |
100 * |
110 * |
101 * @since 2.3.0 |
111 * @since 2.3.0 |
102 * |
112 * |
103 * @param string $key Query variable name. |
113 * @param string $key Query variable name. |
113 * Sets up the query variables based on the request. There are also many |
123 * Sets up the query variables based on the request. There are also many |
114 * filters and actions that can be used to further manipulate the result. |
124 * filters and actions that can be used to further manipulate the result. |
115 * |
125 * |
116 * @since 2.0.0 |
126 * @since 2.0.0 |
117 * |
127 * |
128 * @global WP_Rewrite $wp_rewrite |
|
129 * |
|
118 * @param array|string $extra_query_vars Set the extra query variables. |
130 * @param array|string $extra_query_vars Set the extra query variables. |
119 */ |
131 */ |
120 public function parse_request($extra_query_vars = '') { |
132 public function parse_request($extra_query_vars = '') { |
121 global $wp_rewrite; |
133 global $wp_rewrite; |
122 |
134 |
123 /** |
135 /** |
124 * Filter whether to parse the request. |
136 * Filters whether to parse the request. |
125 * |
137 * |
126 * @since 3.5.0 |
138 * @since 3.5.0 |
127 * |
139 * |
128 * @param bool $bool Whether or not to parse the request. Default true. |
140 * @param bool $bool Whether or not to parse the request. Default true. |
129 * @param WP $this Current WordPress environment instance. |
141 * @param WP $this Current WordPress environment instance. |
155 $pathinfo = str_replace( "%", "%25", $pathinfo ); |
167 $pathinfo = str_replace( "%", "%25", $pathinfo ); |
156 |
168 |
157 list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] ); |
169 list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] ); |
158 $self = $_SERVER['PHP_SELF']; |
170 $self = $_SERVER['PHP_SELF']; |
159 $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' ); |
171 $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' ); |
172 $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) ); |
|
160 |
173 |
161 // Trim path info from the end and the leading home path from the |
174 // Trim path info from the end and the leading home path from the |
162 // front. For path info requests, this leaves us with the requesting |
175 // front. For path info requests, this leaves us with the requesting |
163 // filename, if any. For 404 requests, this leaves us with the |
176 // filename, if any. For 404 requests, this leaves us with the |
164 // requested permalink. |
177 // requested permalink. |
165 $req_uri = str_replace($pathinfo, '', $req_uri); |
178 $req_uri = str_replace($pathinfo, '', $req_uri); |
166 $req_uri = trim($req_uri, '/'); |
179 $req_uri = trim($req_uri, '/'); |
167 $req_uri = preg_replace("|^$home_path|i", '', $req_uri); |
180 $req_uri = preg_replace( $home_path_regex, '', $req_uri ); |
168 $req_uri = trim($req_uri, '/'); |
181 $req_uri = trim($req_uri, '/'); |
169 $pathinfo = trim($pathinfo, '/'); |
182 $pathinfo = trim($pathinfo, '/'); |
170 $pathinfo = preg_replace("|^$home_path|i", '', $pathinfo); |
183 $pathinfo = preg_replace( $home_path_regex, '', $pathinfo ); |
171 $pathinfo = trim($pathinfo, '/'); |
184 $pathinfo = trim($pathinfo, '/'); |
172 $self = trim($self, '/'); |
185 $self = trim($self, '/'); |
173 $self = preg_replace("|^$home_path|i", '', $self); |
186 $self = preg_replace( $home_path_regex, '', $self ); |
174 $self = trim($self, '/'); |
187 $self = trim($self, '/'); |
175 |
188 |
176 // The requested permalink is in $pathinfo for path info requests and |
189 // The requested permalink is in $pathinfo for path info requests and |
177 // $req_uri for other requests. |
190 // $req_uri for other requests. |
178 if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) { |
191 if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) { |
179 $request = $pathinfo; |
192 $requested_path = $pathinfo; |
180 } else { |
193 } else { |
181 // If the request uri is the index, blank it out so that we don't try to match it against a rule. |
194 // If the request uri is the index, blank it out so that we don't try to match it against a rule. |
182 if ( $req_uri == $wp_rewrite->index ) |
195 if ( $req_uri == $wp_rewrite->index ) |
183 $req_uri = ''; |
196 $req_uri = ''; |
184 $request = $req_uri; |
197 $requested_path = $req_uri; |
185 } |
198 } |
186 |
199 $requested_file = $req_uri; |
187 $this->request = $request; |
200 |
201 $this->request = $requested_path; |
|
188 |
202 |
189 // Look for matches. |
203 // Look for matches. |
190 $request_match = $request; |
204 $request_match = $requested_path; |
191 if ( empty( $request_match ) ) { |
205 if ( empty( $request_match ) ) { |
192 // An empty request could only match against ^$ regex |
206 // An empty request could only match against ^$ regex |
193 if ( isset( $rewrite['$'] ) ) { |
207 if ( isset( $rewrite['$'] ) ) { |
194 $this->matched_rule = '$'; |
208 $this->matched_rule = '$'; |
195 $query = $rewrite['$']; |
209 $query = $rewrite['$']; |
196 $matches = array(''); |
210 $matches = array(''); |
197 } |
211 } |
198 } else { |
212 } else { |
199 foreach ( (array) $rewrite as $match => $query ) { |
213 foreach ( (array) $rewrite as $match => $query ) { |
200 // If the requesting file is the anchor of the match, prepend it to the path info. |
214 // If the requested file is the anchor of the match, prepend it to the path info. |
201 if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request ) |
215 if ( ! empty($requested_file) && strpos($match, $requested_file) === 0 && $requested_file != $requested_path ) |
202 $request_match = $req_uri . '/' . $request; |
216 $request_match = $requested_file . '/' . $requested_path; |
203 |
217 |
204 if ( preg_match("#^$match#", $request_match, $matches) || |
218 if ( preg_match("#^$match#", $request_match, $matches) || |
205 preg_match("#^$match#", urldecode($request_match), $matches) ) { |
219 preg_match("#^$match#", urldecode($request_match), $matches) ) { |
206 |
220 |
207 if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) { |
221 if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) { |
208 // This is a verbose page match, let's check to be sure about it. |
222 // This is a verbose page match, let's check to be sure about it. |
209 if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) ) |
223 $page = get_page_by_path( $matches[ $varmatch[1] ] ); |
224 if ( ! $page ) { |
|
210 continue; |
225 continue; |
226 } |
|
227 |
|
228 $post_status_obj = get_post_status_object( $page->post_status ); |
|
229 if ( ! $post_status_obj->public && ! $post_status_obj->protected |
|
230 && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) { |
|
231 continue; |
|
232 } |
|
211 } |
233 } |
212 |
234 |
213 // Got a match. |
235 // Got a match. |
214 $this->matched_rule = $match; |
236 $this->matched_rule = $match; |
215 break; |
237 break; |
233 if ( '404' == $error ) |
255 if ( '404' == $error ) |
234 unset( $error, $_GET['error'] ); |
256 unset( $error, $_GET['error'] ); |
235 } |
257 } |
236 |
258 |
237 // If req_uri is empty or if it is a request for ourself, unset error. |
259 // If req_uri is empty or if it is a request for ourself, unset error. |
238 if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) { |
260 if ( empty($requested_path) || $requested_file == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) { |
239 unset( $error, $_GET['error'] ); |
261 unset( $error, $_GET['error'] ); |
240 |
262 |
241 if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) |
263 if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) |
242 unset( $perma_query_vars ); |
264 unset( $perma_query_vars ); |
243 |
265 |
244 $this->did_permalink = false; |
266 $this->did_permalink = false; |
245 } |
267 } |
246 } |
268 } |
247 |
269 |
248 /** |
270 /** |
249 * Filter the query variables whitelist before processing. |
271 * Filters the query variables whitelist before processing. |
250 * |
272 * |
251 * Allows (publicly allowed) query vars to be added, removed, or changed prior |
273 * Allows (publicly allowed) query vars to be added, removed, or changed prior |
252 * to executing the query. Needed to allow custom rewrite rules using your own arguments |
274 * to executing the query. Needed to allow custom rewrite rules using your own arguments |
253 * to work, or any other custom query variables you want to be publicly available. |
275 * to work, or any other custom query variables you want to be publicly available. |
254 * |
276 * |
256 * |
278 * |
257 * @param array $public_query_vars The array of whitelisted query variables. |
279 * @param array $public_query_vars The array of whitelisted query variables. |
258 */ |
280 */ |
259 $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars ); |
281 $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars ); |
260 |
282 |
261 foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) |
283 foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) { |
262 if ( $t->query_var ) |
284 if ( is_post_type_viewable( $t ) && $t->query_var ) { |
263 $post_type_query_vars[$t->query_var] = $post_type; |
285 $post_type_query_vars[$t->query_var] = $post_type; |
286 } |
|
287 } |
|
264 |
288 |
265 foreach ( $this->public_query_vars as $wpvar ) { |
289 foreach ( $this->public_query_vars as $wpvar ) { |
266 if ( isset( $this->extra_query_vars[$wpvar] ) ) |
290 if ( isset( $this->extra_query_vars[$wpvar] ) ) |
267 $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar]; |
291 $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar]; |
268 elseif ( isset( $_POST[$wpvar] ) ) |
292 elseif ( isset( $_POST[$wpvar] ) ) |
293 // Convert urldecoded spaces back into + |
317 // Convert urldecoded spaces back into + |
294 foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) |
318 foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) |
295 if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) ) |
319 if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) ) |
296 $this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] ); |
320 $this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] ); |
297 |
321 |
322 // Don't allow non-publicly queryable taxonomies to be queried from the front end. |
|
323 if ( ! is_admin() ) { |
|
324 foreach ( get_taxonomies( array( 'publicly_queryable' => false ), 'objects' ) as $taxonomy => $t ) { |
|
325 /* |
|
326 * Disallow when set to the 'taxonomy' query var. |
|
327 * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy(). |
|
328 */ |
|
329 if ( isset( $this->query_vars['taxonomy'] ) && $taxonomy === $this->query_vars['taxonomy'] ) { |
|
330 unset( $this->query_vars['taxonomy'], $this->query_vars['term'] ); |
|
331 } |
|
332 } |
|
333 } |
|
334 |
|
298 // Limit publicly queried post_types to those that are publicly_queryable |
335 // Limit publicly queried post_types to those that are publicly_queryable |
299 if ( isset( $this->query_vars['post_type']) ) { |
336 if ( isset( $this->query_vars['post_type']) ) { |
300 $queryable_post_types = get_post_types( array('publicly_queryable' => true) ); |
337 $queryable_post_types = get_post_types( array('publicly_queryable' => true) ); |
301 if ( ! is_array( $this->query_vars['post_type'] ) ) { |
338 if ( ! is_array( $this->query_vars['post_type'] ) ) { |
302 if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) ) |
339 if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) ) |
304 } else { |
341 } else { |
305 $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types ); |
342 $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types ); |
306 } |
343 } |
307 } |
344 } |
308 |
345 |
346 // Resolve conflicts between posts with numeric slugs and date archive queries. |
|
347 $this->query_vars = wp_resolve_numeric_slug_conflicts( $this->query_vars ); |
|
348 |
|
309 foreach ( (array) $this->private_query_vars as $var) { |
349 foreach ( (array) $this->private_query_vars as $var) { |
310 if ( isset($this->extra_query_vars[$var]) ) |
350 if ( isset($this->extra_query_vars[$var]) ) |
311 $this->query_vars[$var] = $this->extra_query_vars[$var]; |
351 $this->query_vars[$var] = $this->extra_query_vars[$var]; |
312 } |
352 } |
313 |
353 |
314 if ( isset($error) ) |
354 if ( isset($error) ) |
315 $this->query_vars['error'] = $error; |
355 $this->query_vars['error'] = $error; |
316 |
356 |
317 /** |
357 /** |
318 * Filter the array of parsed query variables. |
358 * Filters the array of parsed query variables. |
319 * |
359 * |
320 * @since 2.1.0 |
360 * @since 2.1.0 |
321 * |
361 * |
322 * @param array $query_vars The array of requested query variables. |
362 * @param array $query_vars The array of requested query variables. |
323 */ |
363 */ |
326 /** |
366 /** |
327 * Fires once all query variables for the current request have been parsed. |
367 * Fires once all query variables for the current request have been parsed. |
328 * |
368 * |
329 * @since 2.1.0 |
369 * @since 2.1.0 |
330 * |
370 * |
331 * @param WP &$this Current WordPress environment instance (passed by reference). |
371 * @param WP $this Current WordPress environment instance (passed by reference). |
332 */ |
372 */ |
333 do_action_ref_array( 'parse_request', array( &$this ) ); |
373 do_action_ref_array( 'parse_request', array( &$this ) ); |
334 } |
374 } |
335 |
375 |
336 /** |
376 /** |
337 * Send additional HTTP headers for caching, content type, etc. |
377 * Sends additional HTTP headers for caching, content type, etc. |
338 * |
378 * |
339 * Sets the X-Pingback header, 404 status (if 404), Content-type. If showing |
379 * Sets the Content-Type header. Sets the 'error' status (if passed) and optionally exits. |
340 * a feed, it will also send last-modified, etag, and 304 status if needed. |
380 * If showing a feed, it will also send Last-Modified, ETag, and 304 status if needed. |
341 * |
381 * |
342 * @since 2.0.0 |
382 * @since 2.0.0 |
383 * @since 4.4.0 `X-Pingback` header is added conditionally after posts have been queried in handle_404(). |
|
343 */ |
384 */ |
344 public function send_headers() { |
385 public function send_headers() { |
345 $headers = array('X-Pingback' => get_bloginfo('pingback_url')); |
386 $headers = array(); |
346 $status = null; |
387 $status = null; |
347 $exit_required = false; |
388 $exit_required = false; |
348 |
389 |
349 if ( is_user_logged_in() ) |
390 if ( is_user_logged_in() ) |
350 $headers = array_merge($headers, wp_get_nocache_headers()); |
391 $headers = array_merge($headers, wp_get_nocache_headers()); |
358 $exit_required = true; |
399 $exit_required = true; |
359 } |
400 } |
360 } elseif ( empty( $this->query_vars['feed'] ) ) { |
401 } elseif ( empty( $this->query_vars['feed'] ) ) { |
361 $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset'); |
402 $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset'); |
362 } else { |
403 } else { |
363 // We're showing a feed, so WP is indeed the only thing that last changed |
404 // Set the correct content type for feeds |
364 if ( !empty($this->query_vars['withcomments']) |
405 $type = $this->query_vars['feed']; |
365 || false !== strpos( $this->query_vars['feed'], 'comments-' ) |
406 if ( 'feed' == $this->query_vars['feed'] ) { |
366 || ( empty($this->query_vars['withoutcomments']) |
407 $type = get_default_feed(); |
367 && ( !empty($this->query_vars['p']) |
408 } |
368 || !empty($this->query_vars['name']) |
409 $headers['Content-Type'] = feed_content_type( $type ) . '; charset=' . get_option( 'blog_charset' ); |
369 || !empty($this->query_vars['page_id']) |
410 |
370 || !empty($this->query_vars['pagename']) |
411 // We're showing a feed, so WP is indeed the only thing that last changed. |
371 || !empty($this->query_vars['attachment']) |
412 if ( ! empty( $this->query_vars['withcomments'] ) |
372 || !empty($this->query_vars['attachment_id']) |
413 || false !== strpos( $this->query_vars['feed'], 'comments-' ) |
373 ) |
414 || ( empty( $this->query_vars['withoutcomments'] ) |
374 ) |
415 && ( ! empty( $this->query_vars['p'] ) |
375 ) |
416 || ! empty( $this->query_vars['name'] ) |
376 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT'; |
417 || ! empty( $this->query_vars['page_id'] ) |
377 else |
418 || ! empty( $this->query_vars['pagename'] ) |
378 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT'; |
419 || ! empty( $this->query_vars['attachment'] ) |
420 || ! empty( $this->query_vars['attachment_id'] ) |
|
421 ) |
|
422 ) |
|
423 ) { |
|
424 $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastcommentmodified( 'GMT' ), false ); |
|
425 } else { |
|
426 $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastpostmodified( 'GMT' ), false ); |
|
427 } |
|
428 |
|
429 if ( ! $wp_last_modified ) { |
|
430 $wp_last_modified = date( 'D, d M Y H:i:s' ); |
|
431 } |
|
432 |
|
433 $wp_last_modified .= ' GMT'; |
|
434 |
|
379 $wp_etag = '"' . md5($wp_last_modified) . '"'; |
435 $wp_etag = '"' . md5($wp_last_modified) . '"'; |
380 $headers['Last-Modified'] = $wp_last_modified; |
436 $headers['Last-Modified'] = $wp_last_modified; |
381 $headers['ETag'] = $wp_etag; |
437 $headers['ETag'] = $wp_etag; |
382 |
438 |
383 // Support for Conditional GET |
439 // Support for Conditional GET |
399 $exit_required = true; |
455 $exit_required = true; |
400 } |
456 } |
401 } |
457 } |
402 |
458 |
403 /** |
459 /** |
404 * Filter the HTTP headers before they're sent to the browser. |
460 * Filters the HTTP headers before they're sent to the browser. |
405 * |
461 * |
406 * @since 2.8.0 |
462 * @since 2.8.0 |
407 * |
463 * |
408 * @param array $headers The list of headers to be sent. |
464 * @param array $headers The list of headers to be sent. |
409 * @param WP $this Current WordPress environment instance. |
465 * @param WP $this Current WordPress environment instance. |
430 } |
486 } |
431 } |
487 } |
432 } |
488 } |
433 } |
489 } |
434 |
490 |
435 foreach( (array) $headers as $name => $field_value ) |
491 foreach ( (array) $headers as $name => $field_value ) |
436 @header("{$name}: {$field_value}"); |
492 @header("{$name}: {$field_value}"); |
437 |
493 |
438 if ( $exit_required ) |
494 if ( $exit_required ) |
439 exit(); |
495 exit(); |
440 |
496 |
441 /** |
497 /** |
442 * Fires once the requested HTTP headers for caching, content type, etc. have been sent. |
498 * Fires once the requested HTTP headers for caching, content type, etc. have been sent. |
443 * |
499 * |
444 * @since 2.1.0 |
500 * @since 2.1.0 |
445 * |
501 * |
446 * @param WP &$this Current WordPress environment instance (passed by reference). |
502 * @param WP $this Current WordPress environment instance (passed by reference). |
447 */ |
503 */ |
448 do_action_ref_array( 'send_headers', array( &$this ) ); |
504 do_action_ref_array( 'send_headers', array( &$this ) ); |
449 } |
505 } |
450 |
506 |
451 /** |
507 /** |
452 * Sets the query string property based off of the query variable property. |
508 * Sets the query string property based off of the query variable property. |
453 * |
509 * |
454 * The 'query_string' filter is deprecated, but still works. Plugins should |
510 * The {@see 'query_string'} filter is deprecated, but still works. Plugins should |
455 * use the 'request' filter instead. |
511 * use the {@see 'request'} filter instead. |
456 * |
512 * |
457 * @since 2.0.0 |
513 * @since 2.0.0 |
458 */ |
514 */ |
459 public function build_query_string() { |
515 public function build_query_string() { |
460 $this->query_string = ''; |
516 $this->query_string = ''; |
467 } |
523 } |
468 } |
524 } |
469 |
525 |
470 if ( has_filter( 'query_string' ) ) { // Don't bother filtering and parsing if no plugins are hooked in. |
526 if ( has_filter( 'query_string' ) ) { // Don't bother filtering and parsing if no plugins are hooked in. |
471 /** |
527 /** |
472 * Filter the query string before parsing. |
528 * Filters the query string before parsing. |
473 * |
529 * |
474 * @since 1.5.0 |
530 * @since 1.5.0 |
475 * @deprecated 2.1.0 Use 'query_vars' or 'request' filters instead. |
531 * @deprecated 2.1.0 Use 'query_vars' or 'request' filters instead. |
476 * |
532 * |
477 * @param string $query_string The query string to modify. |
533 * @param string $query_string The query string to modify. |
486 * |
542 * |
487 * The query_vars property will be extracted to the GLOBALS. So care should |
543 * The query_vars property will be extracted to the GLOBALS. So care should |
488 * be taken when naming global variables that might interfere with the |
544 * be taken when naming global variables that might interfere with the |
489 * WordPress environment. |
545 * WordPress environment. |
490 * |
546 * |
491 * @global string $query_string Query string for the loop. |
547 * @since 2.0.0 |
492 * @global array $posts The found posts. |
548 * |
549 * @global WP_Query $wp_query |
|
550 * @global string $query_string Query string for the loop. |
|
551 * @global array $posts The found posts. |
|
493 * @global WP_Post|null $post The current post, if available. |
552 * @global WP_Post|null $post The current post, if available. |
494 * @global string $request The SQL statement for the request. |
553 * @global string $request The SQL statement for the request. |
495 * @global int $more Only set, if single page or post. |
554 * @global int $more Only set, if single page or post. |
496 * @global int $single If single page or post. Only set, if single page or post. |
555 * @global int $single If single page or post. Only set, if single page or post. |
497 * @global WP_User $authordata Only set, if author archive. |
556 * @global WP_User $authordata Only set, if author archive. |
498 * |
|
499 * @since 2.0.0 |
|
500 */ |
557 */ |
501 public function register_globals() { |
558 public function register_globals() { |
502 global $wp_query; |
559 global $wp_query; |
503 |
560 |
504 // Extract updated query vars back into global namespace. |
561 // Extract updated query vars back into global namespace. |
531 |
588 |
532 /** |
589 /** |
533 * Set up the Loop based on the query variables. |
590 * Set up the Loop based on the query variables. |
534 * |
591 * |
535 * @since 2.0.0 |
592 * @since 2.0.0 |
593 * |
|
594 * @global WP_Query $wp_the_query |
|
536 */ |
595 */ |
537 public function query_posts() { |
596 public function query_posts() { |
538 global $wp_the_query; |
597 global $wp_the_query; |
539 $this->build_query_string(); |
598 $this->build_query_string(); |
540 $wp_the_query->query($this->query_vars); |
599 $wp_the_query->query($this->query_vars); |
547 * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already |
606 * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already |
548 * issued, and if the request was not a search or the homepage. |
607 * issued, and if the request was not a search or the homepage. |
549 * |
608 * |
550 * Otherwise, issue a 200. |
609 * Otherwise, issue a 200. |
551 * |
610 * |
552 * @since 2.0.0 |
611 * This sets headers after posts have been queried. handle_404() really means "handle status." |
612 * By inspecting the result of querying posts, seemingly successful requests can be switched to |
|
613 * a 404 so that canonical redirection logic can kick in. |
|
614 * |
|
615 * @since 2.0.0 |
|
616 * |
|
617 * @global WP_Query $wp_query |
|
553 */ |
618 */ |
554 public function handle_404() { |
619 public function handle_404() { |
555 global $wp_query; |
620 global $wp_query; |
556 |
621 |
622 /** |
|
623 * Filters whether to short-circuit default header status handling. |
|
624 * |
|
625 * Returning a non-false value from the filter will short-circuit the handling |
|
626 * and return early. |
|
627 * |
|
628 * @since 4.5.0 |
|
629 * |
|
630 * @param bool $preempt Whether to short-circuit default header status handling. Default false. |
|
631 * @param WP_Query $wp_query WordPress Query object. |
|
632 */ |
|
633 if ( false !== apply_filters( 'pre_handle_404', false, $wp_query ) ) { |
|
634 return; |
|
635 } |
|
636 |
|
557 // If we've already issued a 404, bail. |
637 // If we've already issued a 404, bail. |
558 if ( is_404() ) |
638 if ( is_404() ) |
559 return; |
639 return; |
560 |
640 |
561 // Never 404 for the admin, robots, or if we found posts. |
641 // Never 404 for the admin, robots, or if we found posts. |
562 if ( is_admin() || is_robots() || $wp_query->posts ) { |
642 if ( is_admin() || is_robots() || $wp_query->posts ) { |
563 status_header( 200 ); |
643 |
564 return; |
644 $success = true; |
645 if ( is_singular() ) { |
|
646 $p = false; |
|
647 |
|
648 if ( $wp_query->post instanceof WP_Post ) { |
|
649 $p = clone $wp_query->post; |
|
650 } |
|
651 |
|
652 // Only set X-Pingback for single posts that allow pings. |
|
653 if ( $p && pings_open( $p ) ) { |
|
654 @header( 'X-Pingback: ' . get_bloginfo( 'pingback_url', 'display' ) ); |
|
655 } |
|
656 |
|
657 // check for paged content that exceeds the max number of pages |
|
658 $next = '<!--nextpage-->'; |
|
659 if ( $p && false !== strpos( $p->post_content, $next ) && ! empty( $this->query_vars['page'] ) ) { |
|
660 $page = trim( $this->query_vars['page'], '/' ); |
|
661 $success = (int) $page <= ( substr_count( $p->post_content, $next ) + 1 ); |
|
662 } |
|
663 } |
|
664 |
|
665 if ( $success ) { |
|
666 status_header( 200 ); |
|
667 return; |
|
668 } |
|
565 } |
669 } |
566 |
670 |
567 // We will 404 for paged queries, as no posts were found. |
671 // We will 404 for paged queries, as no posts were found. |
568 if ( ! is_paged() ) { |
672 if ( ! is_paged() ) { |
569 |
673 |
594 } |
698 } |
595 |
699 |
596 /** |
700 /** |
597 * Sets up all of the variables required by the WordPress environment. |
701 * Sets up all of the variables required by the WordPress environment. |
598 * |
702 * |
599 * The action 'wp' has one parameter that references the WP object. It |
703 * The action {@see 'wp'} has one parameter that references the WP object. It |
600 * allows for accessing the properties and methods to further manipulate the |
704 * allows for accessing the properties and methods to further manipulate the |
601 * object. |
705 * object. |
602 * |
706 * |
603 * @since 2.0.0 |
707 * @since 2.0.0 |
604 * |
708 * |
605 * @param string|array $query_args Passed to {@link parse_request()} |
709 * @param string|array $query_args Passed to parse_request(). |
606 */ |
710 */ |
607 public function main($query_args = '') { |
711 public function main($query_args = '') { |
608 $this->init(); |
712 $this->init(); |
609 $this->parse_request($query_args); |
713 $this->parse_request($query_args); |
610 $this->send_headers(); |
714 $this->send_headers(); |
615 /** |
719 /** |
616 * Fires once the WordPress environment has been set up. |
720 * Fires once the WordPress environment has been set up. |
617 * |
721 * |
618 * @since 2.1.0 |
722 * @since 2.1.0 |
619 * |
723 * |
620 * @param WP &$this Current WordPress environment instance (passed by reference). |
724 * @param WP $this Current WordPress environment instance (passed by reference). |
621 */ |
725 */ |
622 do_action_ref_array( 'wp', array( &$this ) ); |
726 do_action_ref_array( 'wp', array( &$this ) ); |
623 } |
727 } |
624 |
|
625 } |
728 } |
626 |
|
627 /** |
|
628 * Helper class to remove the need to use eval to replace $matches[] in query strings. |
|
629 * |
|
630 * @since 2.9.0 |
|
631 */ |
|
632 class WP_MatchesMapRegex { |
|
633 /** |
|
634 * store for matches |
|
635 * |
|
636 * @access private |
|
637 * @var array |
|
638 */ |
|
639 private $_matches; |
|
640 |
|
641 /** |
|
642 * store for mapping result |
|
643 * |
|
644 * @access public |
|
645 * @var string |
|
646 */ |
|
647 public $output; |
|
648 |
|
649 /** |
|
650 * subject to perform mapping on (query string containing $matches[] references |
|
651 * |
|
652 * @access private |
|
653 * @var string |
|
654 */ |
|
655 private $_subject; |
|
656 |
|
657 /** |
|
658 * regexp pattern to match $matches[] references |
|
659 * |
|
660 * @var string |
|
661 */ |
|
662 public $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number |
|
663 |
|
664 /** |
|
665 * constructor |
|
666 * |
|
667 * @param string $subject subject if regex |
|
668 * @param array $matches data to use in map |
|
669 */ |
|
670 public function __construct($subject, $matches) { |
|
671 $this->_subject = $subject; |
|
672 $this->_matches = $matches; |
|
673 $this->output = $this->_map(); |
|
674 } |
|
675 |
|
676 /** |
|
677 * Substitute substring matches in subject. |
|
678 * |
|
679 * static helper function to ease use |
|
680 * |
|
681 * @access public |
|
682 * @param string $subject subject |
|
683 * @param array $matches data used for substitution |
|
684 * @return string |
|
685 */ |
|
686 public static function apply($subject, $matches) { |
|
687 $oSelf = new WP_MatchesMapRegex($subject, $matches); |
|
688 return $oSelf->output; |
|
689 } |
|
690 |
|
691 /** |
|
692 * do the actual mapping |
|
693 * |
|
694 * @access private |
|
695 * @return string |
|
696 */ |
|
697 private function _map() { |
|
698 $callback = array($this, 'callback'); |
|
699 return preg_replace_callback($this->_pattern, $callback, $this->_subject); |
|
700 } |
|
701 |
|
702 /** |
|
703 * preg_replace_callback hook |
|
704 * |
|
705 * @access public |
|
706 * @param array $matches preg_replace regexp matches |
|
707 * @return string |
|
708 */ |
|
709 public function callback($matches) { |
|
710 $index = intval(substr($matches[0], 9, -1)); |
|
711 return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' ); |
|
712 } |
|
713 |
|
714 } |