diff --git a/src/wp-includes/canonical.php b/src/wp-includes/canonical.php index 093493731f..849e15ac76 100644 --- a/src/wp-includes/canonical.php +++ b/src/wp-includes/canonical.php @@ -949,6 +949,9 @@ function redirect_guess_404_permalink() { } if ( get_query_var( 'name' ) ) { + $publicly_viewable_statuses = array_filter( get_post_stati(), 'is_post_status_viewable' ); + $publicly_viewable_post_types = array_filter( get_post_types( array( 'exclude_from_search' => false ) ), 'is_post_type_viewable' ); + /** * Filters whether to perform a strict guess for a 404 redirect. * @@ -969,12 +972,19 @@ function redirect_guess_404_permalink() { // If any of post_type, year, monthnum, or day are set, use them to refine the query. if ( get_query_var( 'post_type' ) ) { if ( is_array( get_query_var( 'post_type' ) ) ) { + $post_types = array_intersect( get_query_var( 'post_type' ), $publicly_viewable_post_types ); + if ( empty( $post_types ) ) { + return false; + } $where .= " AND post_type IN ('" . join( "', '", esc_sql( get_query_var( 'post_type' ) ) ) . "')"; } else { + if ( ! in_array( get_query_var( 'post_type' ), $publicly_viewable_post_types, true ) ) { + return false; + } $where .= $wpdb->prepare( ' AND post_type = %s', get_query_var( 'post_type' ) ); } } else { - $where .= " AND post_type IN ('" . implode( "', '", get_post_types( array( 'public' => true ) ) ) . "')"; + $where .= " AND post_type IN ('" . implode( "', '", esc_sql( $publicly_viewable_post_types ) ) . "')"; } if ( get_query_var( 'year' ) ) { @@ -987,7 +997,6 @@ function redirect_guess_404_permalink() { $where .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) ); } - $publicly_viewable_statuses = array_filter( get_post_stati(), 'is_post_status_viewable' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $post_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE $where AND post_status IN ('" . implode( "', '", esc_sql( $publicly_viewable_statuses ) ) . "')" ); diff --git a/tests/phpunit/tests/canonical.php b/tests/phpunit/tests/canonical.php index 4a0a85d1ad..b83e9563d1 100644 --- a/tests/phpunit/tests/canonical.php +++ b/tests/phpunit/tests/canonical.php @@ -10,13 +10,47 @@ */ class Tests_Canonical extends WP_Canonical_UnitTestCase { + public static $private_cpt_post; + + public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { + // Set up fixtures in WP_Canonical_UnitTestCase. + parent::wpSetUpBeforeClass( $factory ); + + self::set_up_custom_post_types(); + self::$private_cpt_post = $factory->post->create( + array( + 'post_type' => 'wp_tests_private', + 'post_title' => 'private-cpt-post', + ) + ); + } + public function set_up() { parent::set_up(); wp_set_current_user( self::$author_id ); + self::set_up_custom_post_types(); update_option( 'wp_attachment_pages_enabled', 1 ); } + /** + * Register custom post type for tests. + * + * Register non publicly queryable post type with public set to true. + * + * These arguments are intentionally contradictory for the test associated + * with ticket #59795. + */ + public static function set_up_custom_post_types() { + register_post_type( + 'wp_tests_private', + array( + 'public' => true, + 'publicly_queryable' => false, + ) + ); + } + /** * @dataProvider data_canonical */ @@ -343,20 +377,43 @@ class Tests_Canonical extends WP_Canonical_UnitTestCase { * Ensure multiple post types do not throw a notice. * * @ticket 43056 + * @ticket 59795 + * + * @dataProvider data_redirect_guess_404_permalink_post_types */ - public function test_redirect_guess_404_permalink_post_types() { - /* - * Sample-page is intentionally missspelt as sample-pag to ensure - * the 404 post permalink guessing runs. - * - * Please do not correct the apparent typo. - */ + public function test_redirect_guess_404_permalink_post_types( $original_url, $expected ) { + $this->assertCanonical( $original_url, $expected ); + } - // String format post type. - $this->assertCanonical( '/?name=sample-pag&post_type=page', '/sample-page/' ); - // Array formatted post type or types. - $this->assertCanonical( '/?name=sample-pag&post_type[]=page', '/sample-page/' ); - $this->assertCanonical( '/?name=sample-pag&post_type[]=page&post_type[]=post', '/sample-page/' ); + /** + * Data provider for test_redirect_guess_404_permalink_post_types(). + * + * In the original URLs the post names are intentionally misspelled + * to test the redirection. + * + * Please do not correct the apparent typos. + * + * @return array[] + */ + public function data_redirect_guess_404_permalink_post_types() { + return array( + 'single string formatted post type' => array( + 'original_url' => '/?name=sample-pag&post_type=page', + 'expected' => '/sample-page/', + ), + 'single array formatted post type' => array( + 'original_url' => '/?name=sample-pag&post_type[]=page', + 'expected' => '/sample-page/', + ), + 'multiple array formatted post type' => array( + 'original_url' => '/?name=sample-pag&post_type[]=page&post_type[]=post', + 'expected' => '/sample-page/', + ), + 'do not redirect to private post type' => array( + 'original_url' => '/?name=private-cpt-po&post_type[]=wp_tests_private', + 'expected' => '/?name=private-cpt-po&post_type[]=wp_tests_private', + ), + ); } /**