From 1a39a00dfd317f6adb92c25741dae6cab18902ab Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Sat, 21 May 2016 17:26:55 +0000 Subject: [PATCH] Cache queries in `get_page_by_path()`. Props spacedmonkey. Fixes #36711. git-svn-id: https://develop.svn.wordpress.org/trunk@37479 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/post.php | 21 ++++ tests/phpunit/tests/post/getPageByPath.php | 119 +++++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 1920e84f9a..ceaa1d96a8 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -4231,6 +4231,24 @@ function get_page( $page, $output = OBJECT, $filter = 'raw') { function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) { global $wpdb; + $last_changed = wp_cache_get( 'last_changed', 'posts' ); + if ( false === $last_changed ) { + $last_changed = microtime(); + wp_cache_set( 'last_changed', $last_changed, 'posts' ); + } + + $hash = md5( $page_path . serialize( $post_type ) ); + $cache_key = "get_page_by_path:$hash:$last_changed"; + $cached = wp_cache_get( $cache_key, 'posts' ); + if ( false !== $cached ) { + // Special case: '0' is a bad `$page_path`. + if ( '0' === $cached || 0 === $cached ) { + return; + } else { + return get_post( $cached ); + } + } + $page_path = rawurlencode(urldecode($page_path)); $page_path = str_replace('%2F', '/', $page_path); $page_path = str_replace('%20', ' ', $page_path); @@ -4285,6 +4303,9 @@ function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) { } } + // We cache misses as well as hits. + wp_cache_set( $cache_key, $foundid, 'posts' ); + if ( $foundid ) { return get_post( $foundid, $output ); } diff --git a/tests/phpunit/tests/post/getPageByPath.php b/tests/phpunit/tests/post/getPageByPath.php index 7bd3610ce2..01271bcaa2 100644 --- a/tests/phpunit/tests/post/getPageByPath.php +++ b/tests/phpunit/tests/post/getPageByPath.php @@ -123,4 +123,123 @@ class Tests_Post_GetPageByPath extends WP_UnitTestCase { $this->assertNull( $found ); } + + /** + * @ticket 36711 + */ + public function test_should_hit_cache() { + global $wpdb; + + $page = self::factory()->post->create( array( + 'post_type' => 'page', + 'post_name' => 'foo', + ) ); + + // Prime cache. + $found = get_page_by_path( 'foo' ); + $this->assertSame( $page, $found->ID ); + + $num_queries = $wpdb->num_queries; + + $found = get_page_by_path( 'foo' ); + $this->assertSame( $page, $found->ID ); + $this->assertSame( $num_queries, $wpdb->num_queries ); + } + + /** + * @ticket 36711 + */ + public function test_bad_path_should_be_cached() { + global $wpdb; + + // Prime cache. + $found = get_page_by_path( 'foo' ); + $this->assertNull( $found ); + + $num_queries = $wpdb->num_queries; + + $found = get_page_by_path( 'foo' ); + $this->assertNull( $found ); + $this->assertSame( $num_queries, $wpdb->num_queries ); + } + + /** + * @ticket 36711 + */ + public function test_bad_path_served_from_cache_should_not_fall_back_on_current_post() { + global $wpdb, $post; + + // Fake the global. + $post = self::factory()->post->create_and_get(); + + // Prime cache. + $found = get_page_by_path( 'foo' ); + $this->assertNull( $found ); + + $num_queries = $wpdb->num_queries; + + $found = get_page_by_path( 'foo' ); + $this->assertNull( $found ); + $this->assertSame( $num_queries, $wpdb->num_queries ); + + unset( $post ); + } + + /** + * @ticket 36711 + */ + public function test_cache_should_not_match_post_in_different_post_type_with_same_path() { + global $wpdb; + + register_post_type( 'wptests_pt' ); + + $p1 = self::factory()->post->create( array( + 'post_type' => 'page', + 'post_name' => 'foo', + ) ); + + $p2 = self::factory()->post->create( array( + 'post_type' => 'wptests_pt', + 'post_name' => 'foo', + ) ); + + // Prime cache for the page. + $found = get_page_by_path( 'foo' ); + $this->assertSame( $p1, $found->ID ); + + $num_queries = $wpdb->num_queries; + + $found = get_page_by_path( 'foo', OBJECT, 'wptests_pt' ); + $this->assertSame( $p2, $found->ID ); + $num_queries++; + $this->assertSame( $num_queries, $wpdb->num_queries ); + } + + /** + * @ticket 36711 + */ + public function test_cache_should_be_invalidated_when_post_name_is_edited() { + global $wpdb; + + $page = self::factory()->post->create( array( + 'post_type' => 'page', + 'post_name' => 'foo', + ) ); + + // Prime cache. + $found = get_page_by_path( 'foo' ); + $this->assertSame( $page, $found->ID ); + + wp_update_post( array( + 'ID' => $page, + 'post_name' => 'bar', + ) ); + + $num_queries = $wpdb->num_queries; + + $found = get_page_by_path( 'bar' ); + $this->assertSame( $page, $found->ID ); + $num_queries++; + $this->assertSame( $num_queries, $wpdb->num_queries ); + } }