Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/wp-includes/canonical.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?php
/**
* Canonical API to handle WordPress Redirecting
Expand Down Expand Up @@ -1007,8 +1007,22 @@
$where .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) );
}

// 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 ) ) . "')" );
$query = "SELECT ID FROM $wpdb->posts WHERE $where AND post_status IN ('" . implode( "', '", esc_sql( $publicly_viewable_statuses ) ) . "')";

$key = md5( $query );
$last_changed = wp_cache_get_last_changed( 'posts' );
$cache_key = "redirect_guess_404_permalink:$key";
$cache = wp_cache_get_salted( $cache_key, 'post-queries', $last_changed );

if ( false !== $cache ) {
$post_id = $cache;
} else {
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$post_id = (int) $wpdb->get_var( $query );

// We cache misses as well as hits.
wp_cache_set_salted( $cache_key, $post_id, 'post-queries', $last_changed );
}

if ( ! $post_id ) {
return false;
Expand Down
115 changes: 115 additions & 0 deletions tests/phpunit/tests/canonical.php
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,121 @@ public function data_redirect_guess_404_permalink_post_types() {
);
}

/**
* @ticket 64250
*
* @covers ::redirect_guess_404_permalink
*/
public function test_redirect_guess_404_permalink_cache() {
$post = self::factory()->post->create(
array(
'post_title' => 'redirect-guess-404-permalink-cache',
)
);

$this->go_to( 'redirect-guess-404-permalink-cach' );

$first_run = redirect_guess_404_permalink();
$this->assertSame( get_permalink( $post ), $first_run, 'Did not guess the correct permalink on first run.' );

$num_queries = get_num_queries();
$second_run = redirect_guess_404_permalink();
$this->assertSame( $first_run, $second_run, 'Result changed between cached and uncached run.' );
$this->assertSame( $num_queries, get_num_queries(), 'A cached lookup performed an additional database query.' );
}

/**
* @ticket 64250
*
* @covers ::redirect_guess_404_permalink
*/
public function test_redirect_guess_404_permalink_cache_misses_are_cached() {
$this->go_to( 'redirect-guess-404-permalink-no-such-post' );

$this->assertFalse( redirect_guess_404_permalink(), 'Expected no match for a nonexistent slug.' );

$num_queries = get_num_queries();
$this->assertFalse( redirect_guess_404_permalink() );
$this->assertSame( $num_queries, get_num_queries(), 'A cached "not found" result performed an additional database query.' );
}

/**
* @ticket 64250
*
* @covers ::redirect_guess_404_permalink
*/
public function test_redirect_guess_404_permalink_cache_invalidated_on_new_matching_post() {
$this->go_to( 'redirect-guess-404-permalink-new-post' );

// Prime a "not found" cache entry.
$this->assertFalse( redirect_guess_404_permalink() );

$post = self::factory()->post->create(
array(
'post_title' => 'redirect-guess-404-permalink-new-post',
)
);

$num_queries = get_num_queries();
$this->assertSame( get_permalink( $post ), redirect_guess_404_permalink(), 'Newly created matching post was not found after cache invalidation.' );
$this->assertSame( 1, get_num_queries() - $num_queries, 'Expected exactly one new query after the posts cache was invalidated.' );
}

/**
* @ticket 64250
*
* @covers ::redirect_guess_404_permalink
*/
public function test_redirect_guess_404_permalink_cache_invalidated_on_post_delete() {
$post = self::factory()->post->create(
array(
'post_title' => 'redirect-guess-404-permalink-delete-me',
)
);

$this->go_to( 'redirect-guess-404-permalink-delete-m' );

$this->assertSame( get_permalink( $post ), redirect_guess_404_permalink() );

wp_delete_post( $post, true );

$num_queries = get_num_queries();
$this->assertFalse( redirect_guess_404_permalink(), 'Deleted post should no longer be guessed after cache invalidation.' );
$this->assertSame( 1, get_num_queries() - $num_queries, 'Expected exactly one new query after the posts cache was invalidated by deletion.' );
}

/**
* @ticket 64250
*
* @covers ::redirect_guess_404_permalink
*/
public function test_redirect_guess_404_permalink_cache_keys_do_not_collide() {
$post_post = self::factory()->post->create(
array(
'post_title' => 'redirect-guess-collision',
'post_type' => 'post',
)
);
$page_post = self::factory()->post->create(
array(
'post_title' => 'redirect-guess-collision',
'post_type' => 'page',
)
);

$this->go_to( '/?name=redirect-guess-collisio&post_type=post' );
$this->assertSame( get_permalink( $post_post ), redirect_guess_404_permalink() );

$this->go_to( '/?name=redirect-guess-collisio&post_type=page' );
$this->assertSame( get_permalink( $page_post ), redirect_guess_404_permalink(), 'Different post_type query var produced a colliding cached result.' );

// Re-run both to confirm both are independently cached and correct.
$this->go_to( '/?name=redirect-guess-collisio&post_type=post' );
$num_queries = get_num_queries();
$this->assertSame( get_permalink( $post_post ), redirect_guess_404_permalink() );
$this->assertSame( $num_queries, get_num_queries() );
}

/**
* @ticket 43745
*/
Expand Down
Loading