Changeset 63573
- Timestamp:
- 09/10/2026 12:38:33 AM (8 hours ago)
- Location:
- branches/7.0
- Files:
-
- 4 edited
- 1 copied
-
. (modified) (1 prop)
-
src/wp-includes/class-wp.php (modified) (1 diff)
-
src/wp-includes/sitemaps/class-wp-sitemaps.php (modified) (6 diffs)
-
tests/phpunit/tests/sitemaps/sitemaps.php (modified) (1 diff)
-
tests/phpunit/tests/wp/handle404.php (copied) (copied from trunk/tests/phpunit/tests/wp/handle404.php )
Legend:
- Unmodified
- Added
- Removed
-
branches/7.0
-
branches/7.0/src/wp-includes/class-wp.php
r61445 r63573 747 747 $set_404 = true; 748 748 749 // Never 404 for the admin, robots, or favicon. 750 if ( is_admin() || is_robots() || is_favicon() ) { 749 // Never 404 here for the admin, robots, favicon, or sitemaps. 750 // Sitemap routes send their own status in WP_Sitemaps::render_sitemaps(). 751 if ( is_admin() || is_robots() || is_favicon() || is_sitemap() || get_query_var( 'sitemap-stylesheet' ) ) { 751 752 $set_404 = false; 752 753 -
branches/7.0/src/wp-includes/sitemaps/class-wp-sitemaps.php
r59229 r63573 158 158 * 159 159 * @since 5.5.0 160 *161 * @global WP_Query $wp_query WordPress Query object.162 160 */ 163 161 public function render_sitemaps() { 164 global $wp_query; 162 /* 163 * Bail early if this isn't a sitemap or stylesheet route. 164 * 165 * This runs on every front-end request, so it comes before any 166 * sanitizing. The raw query vars are tested here, matching 167 * WP::handle_404(), which exempts sitemap requests from its own 404 on 168 * the same basis. Testing the sanitized values instead would let a 169 * request that handle_404() exempted fall through both, leaving it a 200. 170 */ 171 if ( ! get_query_var( 'sitemap' ) && ! get_query_var( 'sitemap-stylesheet' ) ) { 172 return; 173 } 165 174 166 175 $sitemap = sanitize_text_field( get_query_var( 'sitemap' ) ); … … 169 178 $paged = absint( get_query_var( 'paged' ) ); 170 179 171 // Bail early if this isn't a sitemap or stylesheet route.180 // Force a 404 and bail early if the route did not survive sanitizing. 172 181 if ( ! ( $sitemap || $stylesheet_type ) ) { 182 $this->send_404(); 173 183 return; 174 184 } 175 185 176 186 if ( ! $this->sitemaps_enabled() ) { 177 $wp_query->set_404(); 178 status_header( 404 ); 187 $this->send_404(); 179 188 return; 180 189 } … … 182 191 // Render stylesheet if this is stylesheet route. 183 192 if ( $stylesheet_type ) { 193 // Force a 404 and bail early if the stylesheet type is not recognized. 194 if ( ! in_array( $stylesheet_type, array( 'sitemap', 'index' ), true ) ) { 195 $this->send_404(); 196 return; 197 } 198 184 199 $stylesheet = new WP_Sitemaps_Stylesheet(); 185 200 … … 198 213 $provider = $this->registry->get_provider( $sitemap ); 199 214 215 // Force a 404 and bail early if the requested provider is not registered. 200 216 if ( ! $provider ) { 217 $this->send_404(); 201 218 return; 202 219 } … … 210 227 // Force a 404 and bail early if no URLs are present. 211 228 if ( empty( $url_list ) ) { 212 $wp_query->set_404(); 213 status_header( 404 ); 229 $this->send_404(); 214 230 return; 215 231 } … … 217 233 $this->renderer->render_sitemap( $url_list ); 218 234 exit; 235 } 236 237 /** 238 * Sends a 404 for a sitemap route that cannot be served. 239 * 240 * WP::handle_404() exempts sitemap requests, so every sitemap 404 is issued 241 * here instead. That includes the no-cache headers handle_404() sends with 242 * its own 404, so an intermediary does not retain a 404 for a route that 243 * becomes valid once the site has more content. 244 * 245 * @since 7.1.1 246 * 247 * @global WP_Query $wp_query WordPress Query object. 248 */ 249 private function send_404(): void { 250 global $wp_query; 251 252 $wp_query->set_404(); 253 status_header( 404 ); 254 nocache_headers(); 219 255 } 220 256 -
branches/7.0/tests/phpunit/tests/sitemaps/sitemaps.php
r57987 r63573 494 494 $this->assertTrue( is_404() ); 495 495 } 496 497 /** 498 * Ensures a paged subtype route with no URLs still 404s, now that 499 * WP::handle_404() no longer sets a 404 for sitemap requests. 500 * 501 * @ticket 65945 502 */ 503 public function test_empty_url_list_for_subtype_should_return_404() { 504 wp_register_sitemap_provider( 'foo', new WP_Sitemaps_Empty_Test_Provider( 'foo' ) ); 505 506 $this->go_to( home_url( '/?sitemap=foo&sitemap-subtype=bar&paged=2' ) ); 507 508 wp_sitemaps_get_server()->render_sitemaps(); 509 510 $this->assertTrue( is_404() ); 511 } 512 513 /** 514 * Ensures a sitemap query var that does not survive sanitizing 404s. 515 * 516 * WP::handle_404() exempts these requests on the raw query var, while 517 * render_sitemaps() acts on the sanitized value. Without a matching bail 518 * they fall through both and an arbitrary URL is served as a 200. 519 * 520 * @ticket 65945 521 * 522 * @dataProvider data_unusable_sitemap_query_vars 523 * 524 * @param non-falsy-string $query_string Query string to append to a nonexistent URL. 525 */ 526 public function test_unusable_sitemap_query_var_should_return_404( string $query_string ) { 527 $this->set_permalink_structure( '/%postname%/' ); 528 529 // Instantiate the server before navigating: registering the sitemap 530 // rewrite tags is what adds the query vars to `$wp->public_query_vars`. 531 $sitemaps = wp_sitemaps_get_server(); 532 533 $this->go_to( home_url( '/this-page-does-not-exist/' . $query_string ) ); 534 535 $this->assertFalse( is_404(), 'WP::handle_404() should not have set a 404.' ); 536 537 $sitemaps->render_sitemaps(); 538 539 $this->assertTrue( is_404(), 'render_sitemaps() should have set a 404.' ); 540 } 541 542 /** 543 * Data provider. 544 * 545 * @return array<non-falsy-string, array{ non-falsy-string }> 546 */ 547 public function data_unusable_sitemap_query_vars(): array { 548 return array( 549 'value stripped by sanitizing' => array( '?sitemap=<>' ), 550 'array sitemap value' => array( '?sitemap[]=index' ), 551 'array stylesheet value' => array( '?sitemap-stylesheet[]=sitemap' ), 552 ); 553 } 554 555 /** 556 * Ensures an unrecognized stylesheet type 404s from render_sitemaps(). 557 * 558 * WP::handle_404() exempts any request carrying a `sitemap-stylesheet` 559 * query var, and WP_Sitemaps_Stylesheet::render_stylesheet() echoes nothing 560 * for a type other than 'sitemap' or 'index', so this route would otherwise 561 * be served as a 200 with an empty body. 562 * 563 * @ticket 65945 564 */ 565 public function test_unrecognized_stylesheet_type_should_return_404() { 566 // Instantiate the server before navigating: registering the sitemap rewrite 567 // tags is what adds `sitemap-stylesheet` to `$wp->public_query_vars`. 568 $sitemaps = wp_sitemaps_get_server(); 569 570 $this->go_to( home_url( '/?sitemap-stylesheet=this-is-not-a-stylesheet' ) ); 571 572 $this->assertFalse( is_404(), 'WP::handle_404() should not have set a 404.' ); 573 574 $sitemaps->render_sitemaps(); 575 576 $this->assertTrue( is_404(), 'render_sitemaps() should have set a 404.' ); 577 } 578 579 /** 580 * Ensures an unregistered provider 404s from render_sitemaps(). 581 * 582 * WP::handle_404() exempts every sitemap request, so this route would 583 * otherwise be served with a 200. 584 * 585 * @ticket 65945 586 */ 587 public function test_unregistered_provider_should_return_404() { 588 // Instantiate the server before navigating: registering the sitemap 589 // rewrite tags is what adds `sitemap` to `$wp->public_query_vars`. 590 $sitemaps = wp_sitemaps_get_server(); 591 592 $this->go_to( home_url( '/?sitemap=this-provider-does-not-exist' ) ); 593 594 $this->assertFalse( is_404(), 'WP::handle_404() should not have set a 404.' ); 595 596 $sitemaps->render_sitemaps(); 597 598 $this->assertTrue( is_404(), 'render_sitemaps() should have set a 404.' ); 599 } 496 600 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)