From 504deb52fce61046959c816aeb9d646fc86eac0c Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Thu, 17 Sep 2015 20:00:31 +0000 Subject: [PATCH] Lazy-load comment meta on single post pages. [34268] introduced cache priming for commentmeta, enabled by default. To ensure performance on single post pages - where commentmeta is most likely to cause performance issues - we disable up-front cache-priming. Instead, we prime commentmeta caches for all comments in the loop the first time `get_comment_meta()` is called on the page. Props bradt, dd32, wonderboymusic, boonebgorges. Fixes #16894. git-svn-id: https://develop.svn.wordpress.org/trunk@34270 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/comment-functions.php | 24 ++++++++ src/wp-includes/comment-template.php | 1 + src/wp-includes/default-filters.php | 1 + tests/phpunit/tests/comment/metaCache.php | 69 ++++++++--------------- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/wp-includes/comment-functions.php b/src/wp-includes/comment-functions.php index 1f8f54f92a..f0807b1763 100644 --- a/src/wp-includes/comment-functions.php +++ b/src/wp-includes/comment-functions.php @@ -2376,6 +2376,30 @@ function update_comment_cache( $comments, $update_meta_cache = true ) { } } +/** + * Lazy load comment meta when inside of a `WP_Query` loop. + * + * @since 4.4.0 + * + * @param null $check The `$check` param passed from the 'pre_comment_metadata' hook. + * @param int $comment_id ID of the comment whose metadata is being cached. + * @return null In order not to short-circuit `get_metadata()`. + */ +function wp_lazyload_comment_meta( $check, $comment_id ) { + global $wp_query; + + if ( ! empty( $wp_query->comments ) ) { + // Don't use `wp_list_pluck()` to avoid by-reference manipulation. + $comment_ids = array(); + foreach ( $wp_query->comments as $comment ) { + $comment_ids[] = $comment->comment_ID; + } + update_meta_cache( 'comment', $comment_ids ); + } + + return $check; +} + // // Internal // diff --git a/src/wp-includes/comment-template.php b/src/wp-includes/comment-template.php index 016b515d78..af375c533f 100644 --- a/src/wp-includes/comment-template.php +++ b/src/wp-includes/comment-template.php @@ -1211,6 +1211,7 @@ function comments_template( $file = '/comments.php', $separate_comments = false 'orderby' => 'comment_date_gmt', 'status' => 'approve', 'post_id' => $post->ID, + 'update_comment_meta_cache' => false, // We lazy-load comment meta for performance. ); if ( $user_ID ) { diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index f9fd9c47c9..e9ddc47161 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -200,6 +200,7 @@ add_filter( 'nav_menu_meta_box_object', '_wp_nav_menu_meta_box_object' ); add_filter( 'pingback_ping_source_uri', 'pingback_ping_source_uri' ); add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' ); add_filter( 'title_save_pre', 'trim' ); +add_filter( 'get_comment_metadata', 'wp_lazyload_comment_meta', 10, 2 ); add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 ); diff --git a/tests/phpunit/tests/comment/metaCache.php b/tests/phpunit/tests/comment/metaCache.php index 6cc0f0bd85..ff7de36b92 100644 --- a/tests/phpunit/tests/comment/metaCache.php +++ b/tests/phpunit/tests/comment/metaCache.php @@ -81,61 +81,38 @@ class Tests_Comment_Meta_Cache extends WP_UnitTestCase { $this->assertSame( $num_queries + 3, $wpdb->num_queries ); } - public function test_comment_meta_cache() { - $post_id = $this->factory->post->create( array( - 'post_status' => 'publish' - ) ); + /** + * @ticket 16894 + */ + public function test_comment_meta_should_be_lazy_loaded_for_all_comments_in_comments_template() { + global $wpdb; - $comment_ids = $this->factory->comment->create_post_comments( $post_id, 10 ); + $p = $this->factory->post->create( array( 'post_status' => 'publish' ) ); + $comment_ids = $this->factory->comment->create_post_comments( $p, 3 ); foreach ( $comment_ids as $cid ) { update_comment_meta( $cid, 'sauce', 'fire' ); } - $post = get_post( $post_id ); + $this->go_to( get_permalink( $p ) ); - $this->assertEquals( $post->comment_count, count( $comment_ids ) ); + if ( have_posts() ) { + while ( have_posts() ) { + the_post(); - $this->go_to( get_permalink( $post_id ) ); + // Load comments with `comments_template()`. + $cform = get_echo( 'comments_template' ); - $this->assertTrue( is_single() ); - $this->assertTrue( have_posts() ); + // First request will hit the database. + $num_queries = $wpdb->num_queries; + get_comment_meta( $comment_ids[0], 'sauce' ); + $this->assertSame( $num_queries + 1, $wpdb->num_queries ); - global $wp_query; - - while ( have_posts() ) { - the_post(); - - $comment_args = array( - 'order' => 'ASC', - 'orderby' => 'comment_date_gmt', - 'status' => 'approve', - 'post_id' => get_the_ID(), - ); - - $comments = get_comments( $comment_args ); - - // This is beyond awful - $wp_query->comments = $comments; - - wp_list_comments( array( - 'echo' => false, - 'callback' => array( $this, '_comment_callback' ) - ) ); + // Second and third requests should be in cache. + get_comment_meta( $comment_ids[1], 'sauce' ); + get_comment_meta( $comment_ids[2], 'sauce' ); + $this->assertSame( $num_queries + 1, $wpdb->num_queries ); + } } } - - public function _comment_callback( $comment ) { - global $wpdb; - - get_comment_meta( $comment->comment_ID, 'sauce' ); - - if ( 0 === $this->i ) { - $this->queries = $wpdb->num_queries; - } else { - $this->assertEquals( $this->queries, $wpdb->num_queries ); - } - - $this->i++; - } -} \ No newline at end of file +}