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.



git-svn-id: https://develop.svn.wordpress.org/trunk@57645 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Peter Wilson 2024-02-16 23:32:48 +00:00
parent 9485fde409
commit 96de28cc29
2 changed files with 80 additions and 14 deletions

View File

@ -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 ) ) . "')" );

View File

@ -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',
),
);
}
/**