Make WordPress Core

Changeset 57645


Ignore:
Timestamp:
02/16/2024 11:32:48 PM (3 years ago)
Author:
peterwilsoncc
Message:

Canonical: Limit post types searched by redirect_guess_404_permalink().

Limit the post types searched in redirect_guess_404_permalink() to public, searchable post types. This prevents redirects to 404 pages and the exposure of private post type slugs.

Props francescocarlucci, peterwilsoncc, rajinsharwar.
Fixes #59795.

Location:
trunk
Files:
2 edited

Legend:

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

    r57357 r57645  
    950950
    951951        if ( get_query_var( 'name' ) ) {
     952                $publicly_viewable_statuses   = array_filter( get_post_stati(), 'is_post_status_viewable' );
     953                $publicly_viewable_post_types = array_filter( get_post_types( array( 'exclude_from_search' => false ) ), 'is_post_type_viewable' );
     954
    952955                /**
    953956                 * Filters whether to perform a strict guess for a 404 redirect.
     
    970973                if ( get_query_var( 'post_type' ) ) {
    971974                        if ( is_array( get_query_var( 'post_type' ) ) ) {
     975                                $post_types = array_intersect( get_query_var( 'post_type' ), $publicly_viewable_post_types );
     976                                if ( empty( $post_types ) ) {
     977                                        return false;
     978                                }
    972979                                $where .= " AND post_type IN ('" . join( "', '", esc_sql( get_query_var( 'post_type' ) ) ) . "')";
    973980                        } else {
     981                                if ( ! in_array( get_query_var( 'post_type' ), $publicly_viewable_post_types, true ) ) {
     982                                        return false;
     983                                }
    974984                                $where .= $wpdb->prepare( ' AND post_type = %s', get_query_var( 'post_type' ) );
    975985                        }
    976986                } else {
    977                         $where .= " AND post_type IN ('" . implode( "', '", get_post_types( array( 'public' => true ) ) ) . "')";
     987                        $where .= " AND post_type IN ('" . implode( "', '", esc_sql( $publicly_viewable_post_types ) ) . "')";
    978988                }
    979989
     
    988998                }
    989999
    990                 $publicly_viewable_statuses = array_filter( get_post_stati(), 'is_post_status_viewable' );
    9911000                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    9921001                $post_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE $where AND post_status IN ('" . implode( "', '", esc_sql( $publicly_viewable_statuses ) ) . "')" );
  • trunk/tests/phpunit/tests/canonical.php

    r57357 r57645  
    1111class Tests_Canonical extends WP_Canonical_UnitTestCase {
    1212
     13        public static $private_cpt_post;
     14
     15        public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
     16                // Set up fixtures in WP_Canonical_UnitTestCase.
     17                parent::wpSetUpBeforeClass( $factory );
     18
     19                self::set_up_custom_post_types();
     20                self::$private_cpt_post = $factory->post->create(
     21                        array(
     22                                'post_type'  => 'wp_tests_private',
     23                                'post_title' => 'private-cpt-post',
     24                        )
     25                );
     26        }
     27
    1328        public function set_up() {
    1429                parent::set_up();
    1530                wp_set_current_user( self::$author_id );
     31                self::set_up_custom_post_types();
    1632
    1733                update_option( 'wp_attachment_pages_enabled', 1 );
     34        }
     35
     36        /**
     37         * Register custom post type for tests.
     38         *
     39         * Register non publicly queryable post type with public set to true.
     40         *
     41         * These arguments are intentionally contradictory for the test associated
     42         * with ticket #59795.
     43         */
     44        public static function set_up_custom_post_types() {
     45                register_post_type(
     46                        'wp_tests_private',
     47                        array(
     48                                'public'             => true,
     49                                'publicly_queryable' => false,
     50                        )
     51                );
    1852        }
    1953
     
    344378         *
    345379         * @ticket 43056
    346          */
    347         public function test_redirect_guess_404_permalink_post_types() {
    348                 /*
    349                  * Sample-page is intentionally missspelt as sample-pag to ensure
    350                  * the 404 post permalink guessing runs.
    351                  *
    352                  * Please do not correct the apparent typo.
    353                  */
    354 
    355                 // String format post type.
    356                 $this->assertCanonical( '/?name=sample-pag&post_type=page', '/sample-page/' );
    357                 // Array formatted post type or types.
    358                 $this->assertCanonical( '/?name=sample-pag&post_type[]=page', '/sample-page/' );
    359                 $this->assertCanonical( '/?name=sample-pag&post_type[]=page&post_type[]=post', '/sample-page/' );
     380         * @ticket 59795
     381         *
     382         * @dataProvider data_redirect_guess_404_permalink_post_types
     383         */
     384        public function test_redirect_guess_404_permalink_post_types( $original_url, $expected ) {
     385                $this->assertCanonical( $original_url, $expected );
     386        }
     387
     388        /**
     389         * Data provider for test_redirect_guess_404_permalink_post_types().
     390         *
     391         * In the original URLs the post names are intentionally misspelled
     392         * to test the redirection.
     393         *
     394         * Please do not correct the apparent typos.
     395         *
     396         * @return array[]
     397         */
     398        public function data_redirect_guess_404_permalink_post_types() {
     399                return array(
     400                        'single string formatted post type'    => array(
     401                                'original_url' => '/?name=sample-pag&post_type=page',
     402                                'expected'     => '/sample-page/',
     403                        ),
     404                        'single array formatted post type'     => array(
     405                                'original_url' => '/?name=sample-pag&post_type[]=page',
     406                                'expected'     => '/sample-page/',
     407                        ),
     408                        'multiple array formatted post type'   => array(
     409                                'original_url' => '/?name=sample-pag&post_type[]=page&post_type[]=post',
     410                                'expected'     => '/sample-page/',
     411                        ),
     412                        'do not redirect to private post type' => array(
     413                                'original_url' => '/?name=private-cpt-po&post_type[]=wp_tests_private',
     414                                'expected'     => '/?name=private-cpt-po&post_type[]=wp_tests_private',
     415                        ),
     416                );
    360417        }
    361418
Note: See TracChangeset for help on using the changeset viewer.