WordPress.org

Make WordPress Core

Changeset 48872


Ignore:
Timestamp:
08/27/2020 01:28:24 AM (15 months ago)
Author:
peterwilsoncc
Message:

Sitemaps: Prevent incorrect redirection of paged sitemap requests.

Update redirect_canonical() to account for custom pagination and URL format used by sitemaps in order to follow standard practices.

Introduce the function get_sitemap_url() to simplify getting the index and provider URLs as needed.

Props jonathanstegall, pbiron, GamerZ, salvoaranzulla, peterwilsoncc.
Fixes #50910.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/canonical.php

    r48586 r48872  
    411411        }
    412412
    413         // Paging and feeds.
    414         if ( get_query_var( 'paged' ) || is_feed() || get_query_var( 'cpage' ) ) {
     413        if ( get_query_var( 'sitemap' ) ) {
     414            $redirect_url      = get_sitemap_url( get_query_var( 'sitemap' ), get_query_var( 'sitemap-subtype' ), get_query_var( 'paged' ) );
     415            $redirect['query'] = remove_query_arg( array( 'sitemap', 'sitemap-subtype', 'paged' ), $redirect['query'] );
     416        } elseif ( get_query_var( 'paged' ) || is_feed() || get_query_var( 'cpage' ) ) {
     417            // Paging and feeds.
    415418            $paged = get_query_var( 'paged' );
    416419            $feed  = get_query_var( 'feed' );
     
    507510            if ( ! empty( $addl_path ) ) {
    508511                $redirect['path'] = trailingslashit( $redirect['path'] ) . $addl_path;
    509             }
    510 
    511             // Remove trailing slash for sitemaps requests.
    512             if ( ! empty( get_query_var( 'sitemap' ) ) ) {
    513                 $redirect['path'] = untrailingslashit( $redirect['path'] );
    514512            }
    515513
  • trunk/src/wp-includes/sitemaps.php

    r48574 r48872  
    8888    return apply_filters( 'wp_sitemaps_max_urls', 2000, $object_type );
    8989}
     90
     91/**
     92 * Retrieves the full URL for a sitemap.
     93 *
     94 * @since 5.5.1
     95 *
     96 * @param string $name         The sitemap name.
     97 * @param string $subtype_name The sitemap subtype name.  Default empty string.
     98 * @param int    $page         The page of the sitemap.  Default 1.
     99 * @return string|false The sitemap URL or false if the sitemap doesn't exist.
     100 */
     101function get_sitemap_url( $name, $subtype_name = '', $page = 1 ) {
     102    $sitemaps = wp_sitemaps_get_server();
     103    if ( ! $sitemaps ) {
     104        return false;
     105    }
     106
     107    if ( 'index' === $name ) {
     108        return $sitemaps->index->get_index_url();
     109    }
     110
     111    $provider = $sitemaps->registry->get_provider( $name );
     112    if ( ! $provider ) {
     113        return false;
     114    }
     115
     116    if ( $subtype_name && ! in_array( $subtype_name, array_keys( $provider->get_object_subtypes() ), true ) ) {
     117        return false;
     118    }
     119
     120    $page = absint( $page );
     121    if ( 0 >= $page ) {
     122        $page = 1;
     123    }
     124    return $provider->get_sitemap_url( $subtype_name, $page );
     125}
  • trunk/tests/phpunit/tests/canonical/sitemaps.php

    r48166 r48872  
    4141    }
    4242
     43    /**
     44     * Ensure sitemaps redirects work as expected with pretty permalinks.
     45     *
     46     * @dataProvider data_sitemaps_canonical_pretty_redirects
     47     * @ticket 50910
     48     */
     49    public function test_sitemaps_canonical_pretty_redirects( $test_url, $expected ) {
     50        $this->set_permalink_structure( '/%postname%/' );
     51        $this->assertCanonical( $test_url, $expected, 50910 );
     52    }
     53
     54    /**
     55     * Data provider for test_sitemaps_canonical_pretty_redirects.
     56     *
     57     * @return array[] {
     58     *     Data to test with.
     59     *
     60     *     @type string $0 The test URL.
     61     *     @type string $1 The expected canonical URL.
     62     * }
     63     */
     64    public function data_sitemaps_canonical_pretty_redirects() {
     65        return array(
     66            // Ugly/incorrect versions redirect correctly.
     67            array( '/?sitemap=index', '/wp-sitemap.xml' ),
     68            array( '/wp-sitemap.xml/', '/wp-sitemap.xml' ),
     69            array( '/?sitemap=posts&sitemap-subtype=post', '/wp-sitemap-posts-post-1.xml' ),
     70            array( '/?sitemap=posts&sitemap-subtype=post&paged=2', '/wp-sitemap-posts-post-2.xml' ),
     71            array( '/?sitemap=taxonomies&sitemap-subtype=category', '/wp-sitemap-taxonomies-category-1.xml' ),
     72            array( '/?sitemap=taxonomies&sitemap-subtype=category&paged=2', '/wp-sitemap-taxonomies-category-2.xml' ),
     73
     74            // Pretty versions don't redirect incorrectly.
     75            array( '/wp-sitemap.xml', '/wp-sitemap.xml' ),
     76            array( '/wp-sitemap-posts-post-1.xml', '/wp-sitemap-posts-post-1.xml' ),
     77            array( '/wp-sitemap-posts-post-2.xml', '/wp-sitemap-posts-post-2.xml' ),
     78            array( '/wp-sitemap-taxonomies-category-1.xml', '/wp-sitemap-taxonomies-category-1.xml' ),
     79            array( '/wp-sitemap-taxonomies-category-2.xml', '/wp-sitemap-taxonomies-category-2.xml' ),
     80        );
     81    }
     82
     83    /**
     84     * Ensure sitemaps redirects work as expected with ugly permalinks.
     85     *
     86     * @dataProvider data_sitemaps_canonical_ugly_redirects
     87     * @ticket 50910
     88     */
     89    public function test_sitemaps_canonical_ugly_redirects( $test_url, $expected ) {
     90        $this->set_permalink_structure( '' );
     91        $this->assertCanonical( $test_url, $expected, 50910 );
     92    }
     93
     94    /**
     95     * Data provider for test_sitemaps_canonical_ugly_redirects.
     96     *
     97     * @return array[] {
     98     *     Data to test with.
     99     *
     100     *     @type string $0 The test URL.
     101     *     @type string $1 The expected canonical URL.
     102     * }
     103     */
     104    public function data_sitemaps_canonical_ugly_redirects() {
     105        return array(
     106            // Ugly permalinks remain ugly.
     107            array( '/?sitemap=index', '/?sitemap=index' ),
     108            array( '/?sitemap=posts&sitemap-subtype=post', '/?sitemap=posts&sitemap-subtype=post' ),
     109            array( '/?sitemap=posts&sitemap-subtype=post&paged=2', '/?sitemap=posts&sitemap-subtype=post&paged=2' ),
     110            array( '/?sitemap=taxonomies&sitemap-subtype=category', '/?sitemap=taxonomies&sitemap-subtype=category' ),
     111            array( '/?sitemap=taxonomies&sitemap-subtype=category&paged=2', '/?sitemap=taxonomies&sitemap-subtype=category&paged=2' ),
     112        );
     113    }
    43114}
  • trunk/tests/phpunit/tests/sitemaps/functions.php

    r48541 r48872  
    5959        }
    6060    }
     61
     62    /**
     63     * Test get_sitemap_url() with ugly permalinks.
     64     *
     65     * @dataProvider ugly_permalinks_provider
     66     */
     67    public function test_get_sitemap_url_ugly_permalinks( $name, $subtype_name, $page, $expected ) {
     68        $actual = get_sitemap_url( $name, $subtype_name, $page );
     69
     70        $this->assertSame( $expected, $actual );
     71    }
     72
     73    /**
     74     * Test get_sitemap_url() with pretty permalinks.
     75     *
     76     * @dataProvider pretty_permalinks_provider
     77     */
     78    public function test_get_sitemap_url_pretty_permalinks( $name, $subtype_name, $page, $expected ) {
     79        $this->set_permalink_structure( '/%postname%/' );
     80
     81        $actual = get_sitemap_url( $name, $subtype_name, $page );
     82
     83        $this->assertSame( $expected, $actual );
     84    }
     85
     86    /**
     87     * Data provider for test_get_sitemap_url_ugly_permalinks.
     88     *
     89     * @return array[] {
     90     *     Data to test with.
     91     *
     92     *     @type string       $0 Sitemap name.
     93     *     @type string       $1 Sitemap subtype name.
     94     *     @type int          $3 Sitemap page.
     95     *     @type string|false $4 Sitemap URL.
     96     * }
     97     */
     98    function ugly_permalinks_provider() {
     99        return array(
     100            array( 'posts', 'post', 1, home_url( '/?sitemap=posts&sitemap-subtype=post&paged=1' ) ),
     101            array( 'posts', 'post', 0, home_url( '/?sitemap=posts&sitemap-subtype=post&paged=1' ) ),
     102            array( 'posts', 'page', 1, home_url( '/?sitemap=posts&sitemap-subtype=page&paged=1' ) ),
     103            array( 'posts', 'page', 5, home_url( '/?sitemap=posts&sitemap-subtype=page&paged=5' ) ),
     104            // post_type doesn't exist.
     105            array( 'posts', 'foo', 5, false ),
     106            array( 'taxonomies', 'category', 1, home_url( '/?sitemap=taxonomies&sitemap-subtype=category&paged=1' ) ),
     107            array( 'taxonomies', 'post_tag', 1, home_url( '/?sitemap=taxonomies&sitemap-subtype=post_tag&paged=1' ) ),
     108            array( 'taxonomies', 'post_tag', -1, home_url( '/?sitemap=taxonomies&sitemap-subtype=post_tag&paged=1' ) ),
     109            // negative paged, gets converted to it's absolute value.
     110            array( 'users', '', 4, home_url( '/?sitemap=users&paged=4' ) ),
     111            // users provider doesn't allow subtypes.
     112            array( 'users', 'foo', 4, false ),
     113            // provider doesn't exist.
     114            array( 'foo', '', 4, false ),
     115        );
     116    }
     117
     118    /**
     119     * Data provider for test_get_sitemap_url_pretty_permalinks
     120     *
     121     * @return array[] {
     122     *     Data to test with.
     123     *
     124     *     @type string       $0 Sitemap name.
     125     *     @type string       $1 Sitemap subtype name.
     126     *     @type int          $3 Sitemap page.
     127     *     @type string|false $4 Sitemap URL.
     128     * }
     129     */
     130    function pretty_permalinks_provider() {
     131        return array(
     132            array( 'posts', 'post', 1, home_url( '/wp-sitemap-posts-post-1.xml' ) ),
     133            array( 'posts', 'post', 0, home_url( '/wp-sitemap-posts-post-1.xml' ) ),
     134            array( 'posts', 'page', 1, home_url( '/wp-sitemap-posts-page-1.xml' ) ),
     135            array( 'posts', 'page', 5, home_url( '/wp-sitemap-posts-page-5.xml' ) ),
     136            // post_type doesn't exist.
     137            array( 'posts', 'foo', 5, false ),
     138            array( 'taxonomies', 'category', 1, home_url( '/wp-sitemap-taxonomies-category-1.xml' ) ),
     139            array( 'taxonomies', 'post_tag', 1, home_url( '/wp-sitemap-taxonomies-post_tag-1.xml' ) ),
     140            // negative paged, gets converted to it's absolute value.
     141            array( 'taxonomies', 'post_tag', -1, home_url( '/wp-sitemap-taxonomies-post_tag-1.xml' ) ),
     142            array( 'users', '', 4, home_url( '/wp-sitemap-users-4.xml' ) ),
     143            // users provider doesn't allow subtypes.
     144            array( 'users', 'foo', 4, false ),
     145            // provider doesn't exist.
     146            array( 'foo', '', 4, false ),
     147        );
     148    }
    61149}
Note: See TracChangeset for help on using the changeset viewer.