changeset 16 | a86126ab1dd4 |
parent 13 | d255fe9cd479 |
child 18 | be944660c56a |
15:3d4e9c994f10 | 16:a86126ab1dd4 |
---|---|
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 * @var string[] |
15 * @var string[] |
16 */ |
16 */ |
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', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' ); |
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', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'favicon', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' ); |
18 |
18 |
19 /** |
19 /** |
20 * Private query variables. |
20 * Private query variables. |
21 * |
21 * |
22 * Long list of private query variables. |
22 * Long list of private query variables. |
88 * @since 2.1.0 |
88 * @since 2.1.0 |
89 * |
89 * |
90 * @param string $qv Query variable name. |
90 * @param string $qv Query variable name. |
91 */ |
91 */ |
92 public function add_query_var( $qv ) { |
92 public function add_query_var( $qv ) { |
93 if ( ! in_array( $qv, $this->public_query_vars ) ) { |
93 if ( ! in_array( $qv, $this->public_query_vars, true ) ) { |
94 $this->public_query_vars[] = $qv; |
94 $this->public_query_vars[] = $qv; |
95 } |
95 } |
96 } |
96 } |
97 |
97 |
98 /** |
98 /** |
109 /** |
109 /** |
110 * Set the value of a query variable. |
110 * Set the value of a query variable. |
111 * |
111 * |
112 * @since 2.3.0 |
112 * @since 2.3.0 |
113 * |
113 * |
114 * @param string $key Query variable name. |
114 * @param string $key Query variable name. |
115 * @param mixed $value Query variable value. |
115 * @param mixed $value Query variable value. |
116 */ |
116 */ |
117 public function set_query_var( $key, $value ) { |
117 public function set_query_var( $key, $value ) { |
118 $this->query_vars[ $key ] = $value; |
118 $this->query_vars[ $key ] = $value; |
119 } |
119 } |
120 |
120 |
124 * Sets up the query variables based on the request. There are also many |
124 * Sets up the query variables based on the request. There are also many |
125 * filters and actions that can be used to further manipulate the result. |
125 * filters and actions that can be used to further manipulate the result. |
126 * |
126 * |
127 * @since 2.0.0 |
127 * @since 2.0.0 |
128 * |
128 * |
129 * @global WP_Rewrite $wp_rewrite |
129 * @global WP_Rewrite $wp_rewrite WordPress rewrite component. |
130 * |
130 * |
131 * @param array|string $extra_query_vars Set the extra query variables. |
131 * @param array|string $extra_query_vars Set the extra query variables. |
132 */ |
132 */ |
133 public function parse_request( $extra_query_vars = '' ) { |
133 public function parse_request( $extra_query_vars = '' ) { |
134 global $wp_rewrite; |
134 global $wp_rewrite; |
171 list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] ); |
171 list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] ); |
172 $self = $_SERVER['PHP_SELF']; |
172 $self = $_SERVER['PHP_SELF']; |
173 $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' ); |
173 $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' ); |
174 $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) ); |
174 $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) ); |
175 |
175 |
176 // Trim path info from the end and the leading home path from the |
176 /* |
177 // front. For path info requests, this leaves us with the requesting |
177 * Trim path info from the end and the leading home path from the front. |
178 // filename, if any. For 404 requests, this leaves us with the |
178 * For path info requests, this leaves us with the requesting filename, if any. |
179 // requested permalink. |
179 * For 404 requests, this leaves us with the requested permalink. |
180 */ |
|
180 $req_uri = str_replace( $pathinfo, '', $req_uri ); |
181 $req_uri = str_replace( $pathinfo, '', $req_uri ); |
181 $req_uri = trim( $req_uri, '/' ); |
182 $req_uri = trim( $req_uri, '/' ); |
182 $req_uri = preg_replace( $home_path_regex, '', $req_uri ); |
183 $req_uri = preg_replace( $home_path_regex, '', $req_uri ); |
183 $req_uri = trim( $req_uri, '/' ); |
184 $req_uri = trim( $req_uri, '/' ); |
184 $pathinfo = trim( $pathinfo, '/' ); |
185 $pathinfo = trim( $pathinfo, '/' ); |
187 $self = trim( $self, '/' ); |
188 $self = trim( $self, '/' ); |
188 $self = preg_replace( $home_path_regex, '', $self ); |
189 $self = preg_replace( $home_path_regex, '', $self ); |
189 $self = trim( $self, '/' ); |
190 $self = trim( $self, '/' ); |
190 |
191 |
191 // The requested permalink is in $pathinfo for path info requests and |
192 // The requested permalink is in $pathinfo for path info requests and |
192 // $req_uri for other requests. |
193 // $req_uri for other requests. |
193 if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $wp_rewrite->index . '$|', $pathinfo ) ) { |
194 if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $wp_rewrite->index . '$|', $pathinfo ) ) { |
194 $requested_path = $pathinfo; |
195 $requested_path = $pathinfo; |
195 } else { |
196 } else { |
196 // If the request uri is the index, blank it out so that we don't try to match it against a rule. |
197 // If the request uri is the index, blank it out so that we don't try to match it against a rule. |
197 if ( $req_uri == $wp_rewrite->index ) { |
198 if ( $req_uri == $wp_rewrite->index ) { |
204 $this->request = $requested_path; |
205 $this->request = $requested_path; |
205 |
206 |
206 // Look for matches. |
207 // Look for matches. |
207 $request_match = $requested_path; |
208 $request_match = $requested_path; |
208 if ( empty( $request_match ) ) { |
209 if ( empty( $request_match ) ) { |
209 // An empty request could only match against ^$ regex |
210 // An empty request could only match against ^$ regex. |
210 if ( isset( $rewrite['$'] ) ) { |
211 if ( isset( $rewrite['$'] ) ) { |
211 $this->matched_rule = '$'; |
212 $this->matched_rule = '$'; |
212 $query = $rewrite['$']; |
213 $query = $rewrite['$']; |
213 $matches = array( '' ); |
214 $matches = array( '' ); |
214 } |
215 } |
272 $this->did_permalink = false; |
273 $this->did_permalink = false; |
273 } |
274 } |
274 } |
275 } |
275 |
276 |
276 /** |
277 /** |
277 * Filters the query variables whitelist before processing. |
278 * Filters the query variables allowed before processing. |
278 * |
279 * |
279 * Allows (publicly allowed) query vars to be added, removed, or changed prior |
280 * Allows (publicly allowed) query vars to be added, removed, or changed prior |
280 * to executing the query. Needed to allow custom rewrite rules using your own arguments |
281 * to executing the query. Needed to allow custom rewrite rules using your own arguments |
281 * to work, or any other custom query variables you want to be publicly available. |
282 * to work, or any other custom query variables you want to be publicly available. |
282 * |
283 * |
283 * @since 1.5.0 |
284 * @since 1.5.0 |
284 * |
285 * |
285 * @param string[] $public_query_vars The array of whitelisted query variable names. |
286 * @param string[] $public_query_vars The array of allowed query variable names. |
286 */ |
287 */ |
287 $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars ); |
288 $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars ); |
288 |
289 |
289 foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) { |
290 foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) { |
290 if ( is_post_type_viewable( $t ) && $t->query_var ) { |
291 if ( is_post_type_viewable( $t ) && $t->query_var ) { |
321 $this->query_vars['name'] = $this->query_vars[ $wpvar ]; |
322 $this->query_vars['name'] = $this->query_vars[ $wpvar ]; |
322 } |
323 } |
323 } |
324 } |
324 } |
325 } |
325 |
326 |
326 // Convert urldecoded spaces back into + |
327 // Convert urldecoded spaces back into '+'. |
327 foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) { |
328 foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) { |
328 if ( $t->query_var && isset( $this->query_vars[ $t->query_var ] ) ) { |
329 if ( $t->query_var && isset( $this->query_vars[ $t->query_var ] ) ) { |
329 $this->query_vars[ $t->query_var ] = str_replace( ' ', '+', $this->query_vars[ $t->query_var ] ); |
330 $this->query_vars[ $t->query_var ] = str_replace( ' ', '+', $this->query_vars[ $t->query_var ] ); |
330 } |
331 } |
331 } |
332 } |
341 unset( $this->query_vars['taxonomy'], $this->query_vars['term'] ); |
342 unset( $this->query_vars['taxonomy'], $this->query_vars['term'] ); |
342 } |
343 } |
343 } |
344 } |
344 } |
345 } |
345 |
346 |
346 // Limit publicly queried post_types to those that are publicly_queryable |
347 // Limit publicly queried post_types to those that are 'publicly_queryable'. |
347 if ( isset( $this->query_vars['post_type'] ) ) { |
348 if ( isset( $this->query_vars['post_type'] ) ) { |
348 $queryable_post_types = get_post_types( array( 'publicly_queryable' => true ) ); |
349 $queryable_post_types = get_post_types( array( 'publicly_queryable' => true ) ); |
349 if ( ! is_array( $this->query_vars['post_type'] ) ) { |
350 if ( ! is_array( $this->query_vars['post_type'] ) ) { |
350 if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) ) { |
351 if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types, true ) ) { |
351 unset( $this->query_vars['post_type'] ); |
352 unset( $this->query_vars['post_type'] ); |
352 } |
353 } |
353 } else { |
354 } else { |
354 $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types ); |
355 $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types ); |
355 } |
356 } |
401 $status = null; |
402 $status = null; |
402 $exit_required = false; |
403 $exit_required = false; |
403 |
404 |
404 if ( is_user_logged_in() ) { |
405 if ( is_user_logged_in() ) { |
405 $headers = array_merge( $headers, wp_get_nocache_headers() ); |
406 $headers = array_merge( $headers, wp_get_nocache_headers() ); |
407 } elseif ( ! empty( $_GET['unapproved'] ) && ! empty( $_GET['moderation-hash'] ) ) { |
|
408 // Unmoderated comments are only visible for one minute via the moderation hash. |
|
409 $headers['Expires'] = gmdate( 'D, d M Y H:i:s', time() + MINUTE_IN_SECONDS ); |
|
410 $headers['Cache-Control'] = 'max-age=60, must-revalidate'; |
|
406 } |
411 } |
407 if ( ! empty( $this->query_vars['error'] ) ) { |
412 if ( ! empty( $this->query_vars['error'] ) ) { |
408 $status = (int) $this->query_vars['error']; |
413 $status = (int) $this->query_vars['error']; |
409 if ( 404 === $status ) { |
414 if ( 404 === $status ) { |
410 if ( ! is_user_logged_in() ) { |
415 if ( ! is_user_logged_in() ) { |
411 $headers = array_merge( $headers, wp_get_nocache_headers() ); |
416 $headers = array_merge( $headers, wp_get_nocache_headers() ); |
412 } |
417 } |
413 $headers['Content-Type'] = get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ); |
418 $headers['Content-Type'] = get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ); |
414 } elseif ( in_array( $status, array( 403, 500, 502, 503 ) ) ) { |
419 } elseif ( in_array( $status, array( 403, 500, 502, 503 ), true ) ) { |
415 $exit_required = true; |
420 $exit_required = true; |
416 } |
421 } |
417 } elseif ( empty( $this->query_vars['feed'] ) ) { |
422 } elseif ( empty( $this->query_vars['feed'] ) ) { |
418 $headers['Content-Type'] = get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ); |
423 $headers['Content-Type'] = get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ); |
419 } else { |
424 } else { |
420 // Set the correct content type for feeds |
425 // Set the correct content type for feeds. |
421 $type = $this->query_vars['feed']; |
426 $type = $this->query_vars['feed']; |
422 if ( 'feed' == $this->query_vars['feed'] ) { |
427 if ( 'feed' === $this->query_vars['feed'] ) { |
423 $type = get_default_feed(); |
428 $type = get_default_feed(); |
424 } |
429 } |
425 $headers['Content-Type'] = feed_content_type( $type ) . '; charset=' . get_option( 'blog_charset' ); |
430 $headers['Content-Type'] = feed_content_type( $type ) . '; charset=' . get_option( 'blog_charset' ); |
426 |
431 |
427 // We're showing a feed, so WP is indeed the only thing that last changed. |
432 // We're showing a feed, so WP is indeed the only thing that last changed. |
441 } else { |
446 } else { |
442 $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastpostmodified( 'GMT' ), false ); |
447 $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastpostmodified( 'GMT' ), false ); |
443 } |
448 } |
444 |
449 |
445 if ( ! $wp_last_modified ) { |
450 if ( ! $wp_last_modified ) { |
446 $wp_last_modified = date( 'D, d M Y H:i:s' ); |
451 $wp_last_modified = gmdate( 'D, d M Y H:i:s' ); |
447 } |
452 } |
448 |
453 |
449 $wp_last_modified .= ' GMT'; |
454 $wp_last_modified .= ' GMT'; |
450 |
455 |
451 $wp_etag = '"' . md5( $wp_last_modified ) . '"'; |
456 $wp_etag = '"' . md5( $wp_last_modified ) . '"'; |
452 $headers['Last-Modified'] = $wp_last_modified; |
457 $headers['Last-Modified'] = $wp_last_modified; |
453 $headers['ETag'] = $wp_etag; |
458 $headers['ETag'] = $wp_etag; |
454 |
459 |
455 // Support for Conditional GET |
460 // Support for conditional GET. |
456 if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) { |
461 if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) { |
457 $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] ); |
462 $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] ); |
458 } else { |
463 } else { |
459 $client_etag = false; |
464 $client_etag = false; |
460 } |
465 } |
461 |
466 |
462 $client_last_modified = empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ); |
467 $client_last_modified = empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ); |
463 // If string is empty, return 0. If not, attempt to parse into a timestamp |
468 // If string is empty, return 0. If not, attempt to parse into a timestamp. |
464 $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0; |
469 $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0; |
465 |
470 |
466 // Make a timestamp for our most recent modification... |
471 // Make a timestamp for our most recent modification.. |
467 $wp_modified_timestamp = strtotime( $wp_last_modified ); |
472 $wp_modified_timestamp = strtotime( $wp_last_modified ); |
468 |
473 |
469 if ( ( $client_last_modified && $client_etag ) ? |
474 if ( ( $client_last_modified && $client_etag ) ? |
470 ( ( $client_modified_timestamp >= $wp_modified_timestamp ) && ( $client_etag == $wp_etag ) ) : |
475 ( ( $client_modified_timestamp >= $wp_modified_timestamp ) && ( $client_etag == $wp_etag ) ) : |
471 ( ( $client_modified_timestamp >= $wp_modified_timestamp ) || ( $client_etag == $wp_etag ) ) ) { |
476 ( ( $client_modified_timestamp >= $wp_modified_timestamp ) || ( $client_etag == $wp_etag ) ) ) { |
490 |
495 |
491 // If Last-Modified is set to false, it should not be sent (no-cache situation). |
496 // If Last-Modified is set to false, it should not be sent (no-cache situation). |
492 if ( isset( $headers['Last-Modified'] ) && false === $headers['Last-Modified'] ) { |
497 if ( isset( $headers['Last-Modified'] ) && false === $headers['Last-Modified'] ) { |
493 unset( $headers['Last-Modified'] ); |
498 unset( $headers['Last-Modified'] ); |
494 |
499 |
495 // In PHP 5.3+, make sure we are not sending a Last-Modified header. |
500 if ( ! headers_sent() ) { |
496 if ( function_exists( 'header_remove' ) ) { |
501 header_remove( 'Last-Modified' ); |
497 @header_remove( 'Last-Modified' ); |
502 } |
498 } else { |
503 } |
499 // In PHP 5.2, send an empty Last-Modified header, but only as a |
504 |
500 // last resort to override a header already sent. #WP23021 |
505 if ( ! headers_sent() ) { |
501 foreach ( headers_list() as $header ) { |
506 foreach ( (array) $headers as $name => $field_value ) { |
502 if ( 0 === stripos( $header, 'Last-Modified' ) ) { |
507 header( "{$name}: {$field_value}" ); |
503 $headers['Last-Modified'] = ''; |
508 } |
504 break; |
|
505 } |
|
506 } |
|
507 } |
|
508 } |
|
509 |
|
510 foreach ( (array) $headers as $name => $field_value ) { |
|
511 @header( "{$name}: {$field_value}" ); |
|
512 } |
509 } |
513 |
510 |
514 if ( $exit_required ) { |
511 if ( $exit_required ) { |
515 exit(); |
512 exit; |
516 } |
513 } |
517 |
514 |
518 /** |
515 /** |
519 * Fires once the requested HTTP headers for caching, content type, etc. have been sent. |
516 * Fires once the requested HTTP headers for caching, content type, etc. have been sent. |
520 * |
517 * |
548 if ( has_filter( 'query_string' ) ) { // Don't bother filtering and parsing if no plugins are hooked in. |
545 if ( has_filter( 'query_string' ) ) { // Don't bother filtering and parsing if no plugins are hooked in. |
549 /** |
546 /** |
550 * Filters the query string before parsing. |
547 * Filters the query string before parsing. |
551 * |
548 * |
552 * @since 1.5.0 |
549 * @since 1.5.0 |
553 * @deprecated 2.1.0 Use 'query_vars' or 'request' filters instead. |
550 * @deprecated 2.1.0 Use {@see 'query_vars'} or {@see 'request'} filters instead. |
554 * |
551 * |
555 * @param string $query_string The query string to modify. |
552 * @param string $query_string The query string to modify. |
556 */ |
553 */ |
557 $this->query_string = apply_filters( 'query_string', $this->query_string ); |
554 $this->query_string = apply_filters_deprecated( |
555 'query_string', |
|
556 array( $this->query_string ), |
|
557 '2.1.0', |
|
558 'query_vars, request' |
|
559 ); |
|
558 parse_str( $this->query_string, $this->query_vars ); |
560 parse_str( $this->query_string, $this->query_vars ); |
559 } |
561 } |
560 } |
562 } |
561 |
563 |
562 /** |
564 /** |
566 * be taken when naming global variables that might interfere with the |
568 * be taken when naming global variables that might interfere with the |
567 * WordPress environment. |
569 * WordPress environment. |
568 * |
570 * |
569 * @since 2.0.0 |
571 * @since 2.0.0 |
570 * |
572 * |
571 * @global WP_Query $wp_query |
573 * @global WP_Query $wp_query WordPress Query object. |
572 * @global string $query_string Query string for the loop. |
574 * @global string $query_string Query string for the loop. |
573 * @global array $posts The found posts. |
575 * @global array $posts The found posts. |
574 * @global WP_Post|null $post The current post, if available. |
576 * @global WP_Post|null $post The current post, if available. |
575 * @global string $request The SQL statement for the request. |
577 * @global string $request The SQL statement for the request. |
576 * @global int $more Only set, if single page or post. |
578 * @global int $more Only set, if single page or post. |
577 * @global int $single If single page or post. Only set, if single page or post. |
579 * @global int $single If single page or post. Only set, if single page or post. |
578 * @global WP_User $authordata Only set, if author archive. |
580 * @global WP_User $authordata Only set, if author archive. |
579 */ |
581 */ |
580 public function register_globals() { |
582 public function register_globals() { |
581 global $wp_query; |
583 global $wp_query; |
582 |
584 |
583 // Extract updated query vars back into global namespace. |
585 // Extract updated query vars back into global namespace. |
612 /** |
614 /** |
613 * Set up the Loop based on the query variables. |
615 * Set up the Loop based on the query variables. |
614 * |
616 * |
615 * @since 2.0.0 |
617 * @since 2.0.0 |
616 * |
618 * |
617 * @global WP_Query $wp_the_query |
619 * @global WP_Query $wp_the_query WordPress Query object. |
618 */ |
620 */ |
619 public function query_posts() { |
621 public function query_posts() { |
620 global $wp_the_query; |
622 global $wp_the_query; |
621 $this->build_query_string(); |
623 $this->build_query_string(); |
622 $wp_the_query->query( $this->query_vars ); |
624 $wp_the_query->query( $this->query_vars ); |
623 } |
625 } |
624 |
626 |
625 /** |
627 /** |
626 * Set the Headers for 404, if nothing is found for requested URL. |
628 * Set the Headers for 404, if nothing is found for requested URL. |
627 * |
629 * |
628 * Issue a 404 if a request doesn't match any posts and doesn't match |
630 * Issue a 404 if a request doesn't match any posts and doesn't match any object |
629 * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already |
631 * (e.g. an existing-but-empty category, tag, author) and a 404 was not already issued, |
630 * issued, and if the request was not a search or the homepage. |
632 * and if the request was not a search or the homepage. |
631 * |
633 * |
632 * Otherwise, issue a 200. |
634 * Otherwise, issue a 200. |
633 * |
635 * |
634 * This sets headers after posts have been queried. handle_404() really means "handle status." |
636 * This sets headers after posts have been queried. handle_404() really means "handle status". |
635 * By inspecting the result of querying posts, seemingly successful requests can be switched to |
637 * By inspecting the result of querying posts, seemingly successful requests can be switched to |
636 * a 404 so that canonical redirection logic can kick in. |
638 * a 404 so that canonical redirection logic can kick in. |
637 * |
639 * |
638 * @since 2.0.0 |
640 * @since 2.0.0 |
639 * |
641 * |
640 * @global WP_Query $wp_query |
642 * @global WP_Query $wp_query WordPress Query object. |
641 */ |
643 */ |
642 public function handle_404() { |
644 public function handle_404() { |
643 global $wp_query; |
645 global $wp_query; |
644 |
646 |
645 /** |
647 /** |
660 // If we've already issued a 404, bail. |
662 // If we've already issued a 404, bail. |
661 if ( is_404() ) { |
663 if ( is_404() ) { |
662 return; |
664 return; |
663 } |
665 } |
664 |
666 |
665 // Never 404 for the admin, robots, or if we found posts. |
667 $set_404 = true; |
666 if ( is_admin() || is_robots() || $wp_query->posts ) { |
668 |
667 |
669 // Never 404 for the admin, robots, or favicon. |
668 $success = true; |
670 if ( is_admin() || is_robots() || is_favicon() ) { |
671 $set_404 = false; |
|
672 |
|
673 // If posts were found, check for paged content. |
|
674 } elseif ( $wp_query->posts ) { |
|
675 $content_found = true; |
|
676 |
|
669 if ( is_singular() ) { |
677 if ( is_singular() ) { |
670 $p = false; |
678 $post = isset( $wp_query->post ) ? $wp_query->post : null; |
671 |
|
672 if ( $wp_query->post instanceof WP_Post ) { |
|
673 $p = clone $wp_query->post; |
|
674 } |
|
675 |
679 |
676 // Only set X-Pingback for single posts that allow pings. |
680 // Only set X-Pingback for single posts that allow pings. |
677 if ( $p && pings_open( $p ) ) { |
681 if ( $post && pings_open( $post ) && ! headers_sent() ) { |
678 @header( 'X-Pingback: ' . get_bloginfo( 'pingback_url', 'display' ) ); |
682 header( 'X-Pingback: ' . get_bloginfo( 'pingback_url', 'display' ) ); |
679 } |
683 } |
680 |
684 |
681 // check for paged content that exceeds the max number of pages |
685 // Check for paged content that exceeds the max number of pages. |
682 $next = '<!--nextpage-->'; |
686 $next = '<!--nextpage-->'; |
683 if ( $p && false !== strpos( $p->post_content, $next ) && ! empty( $this->query_vars['page'] ) ) { |
687 if ( $post && ! empty( $this->query_vars['page'] ) ) { |
684 $page = trim( $this->query_vars['page'], '/' ); |
688 // Check if content is actually intended to be paged. |
685 $success = (int) $page <= ( substr_count( $p->post_content, $next ) + 1 ); |
689 if ( false !== strpos( $post->post_content, $next ) ) { |
686 } |
690 $page = trim( $this->query_vars['page'], '/' ); |
687 } |
691 $content_found = (int) $page <= ( substr_count( $post->post_content, $next ) + 1 ); |
688 |
692 } else { |
689 if ( $success ) { |
693 $content_found = false; |
690 status_header( 200 ); |
694 } |
691 return; |
695 } |
692 } |
696 } |
693 } |
697 |
694 |
698 // The posts page does not support the <!--nextpage--> pagination. |
695 // We will 404 for paged queries, as no posts were found. |
699 if ( $wp_query->is_posts_page && ! empty( $this->query_vars['page'] ) ) { |
696 if ( ! is_paged() ) { |
700 $content_found = false; |
701 } |
|
702 |
|
703 if ( $content_found ) { |
|
704 $set_404 = false; |
|
705 } |
|
706 |
|
707 // We will 404 for paged queries, as no posts were found. |
|
708 } elseif ( ! is_paged() ) { |
|
709 $author = get_query_var( 'author' ); |
|
697 |
710 |
698 // Don't 404 for authors without posts as long as they matched an author on this site. |
711 // Don't 404 for authors without posts as long as they matched an author on this site. |
699 $author = get_query_var( 'author' ); |
712 if ( is_author() && is_numeric( $author ) && $author > 0 && is_user_member_of_blog( $author ) |
700 if ( is_author() && is_numeric( $author ) && $author > 0 && is_user_member_of_blog( $author ) ) { |
713 // Don't 404 for these queries if they matched an object. |
701 status_header( 200 ); |
714 || ( is_tag() || is_category() || is_tax() || is_post_type_archive() ) && get_queried_object() |
702 return; |
715 // Don't 404 for these queries either. |
703 } |
716 || is_home() || is_search() || is_feed() |
704 |
717 ) { |
705 // Don't 404 for these queries if they matched an object. |
718 $set_404 = false; |
706 if ( ( is_tag() || is_category() || is_tax() || is_post_type_archive() ) && get_queried_object() ) { |
719 } |
707 status_header( 200 ); |
720 } |
708 return; |
721 |
709 } |
722 if ( $set_404 ) { |
710 |
723 // Guess it's time to 404. |
711 // Don't 404 for these queries either. |
724 $wp_query->set_404(); |
712 if ( is_home() || is_search() || is_feed() ) { |
725 status_header( 404 ); |
713 status_header( 200 ); |
726 nocache_headers(); |
714 return; |
727 } else { |
715 } |
728 status_header( 200 ); |
716 } |
729 } |
717 |
|
718 // Guess it's time to 404. |
|
719 $wp_query->set_404(); |
|
720 status_header( 404 ); |
|
721 nocache_headers(); |
|
722 } |
730 } |
723 |
731 |
724 /** |
732 /** |
725 * Sets up all of the variables required by the WordPress environment. |
733 * Sets up all of the variables required by the WordPress environment. |
726 * |
734 * |