Make WordPress Core

Changeset 34711


Ignore:
Timestamp:
09/30/2015 01:34:54 AM (9 years ago)
Author:
boonebgorges
Message:

Improve lazyloading of comment meta in WP_Query loops.

Lazy-loading logic is moved to a method on WP_Query. This makes it possible
for comment feeds to take advantage of metadata lazyloading, in addition to
comments loaded via comments_template().

This new technique parallels the termmeta lazyloading technique introduced in
[34704].

Fixes #34047.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/comment-functions.php

    r34661 r34711  
    24532453}
    24542454
    2455 /**
    2456  * Lazy load comment meta when inside of a `WP_Query` loop.
    2457  *
    2458  * @since 4.4.0
    2459  *
    2460  * @param null $check      The `$check` param passed from the 'pre_comment_metadata' hook.
    2461  * @param int  $comment_id ID of the comment whose metadata is being cached.
    2462  * @return null In order not to short-circuit `get_metadata()`.
    2463  */
    2464 function wp_lazyload_comment_meta( $check, $comment_id ) {
    2465     global $wp_query;
    2466 
    2467     if ( ! empty( $wp_query->comments ) ) {
    2468         // Don't use `wp_list_pluck()` to avoid by-reference manipulation.
    2469         $comment_ids = array();
    2470         foreach ( $wp_query->comments as $comment ) {
    2471             $comment_ids[] = $comment->comment_ID;
    2472         }
    2473         update_meta_cache( 'comment', $comment_ids );
    2474     }
    2475 
    2476     return $check;
    2477 }
    2478 
    24792455//
    24802456// Internal
  • trunk/src/wp-includes/comment-template.php

    r34669 r34711  
    13211321     */
    13221322    $wp_query->comments = apply_filters( 'comments_array', $comments_flat, $post->ID );
     1323
     1324    // Set up lazy-loading for comment metadata.
     1325    add_action( 'get_comment_metadata', array( $wp_query, 'lazyload_comment_meta' ), 10, 2 );
     1326
    13231327    $comments = &$wp_query->comments;
    13241328    $wp_query->comment_count = count($wp_query->comments);
  • trunk/src/wp-includes/default-filters.php

    r34704 r34711  
    201201add_filter( 'xmlrpc_pingback_error',    'xmlrpc_pingback_error'               );
    202202add_filter( 'title_save_pre',           'trim'                                );
    203 add_filter( 'get_comment_metadata',     'wp_lazyload_comment_meta',     10, 2 );
    204203
    205204add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 );
  • trunk/src/wp-includes/query.php

    r34704 r34711  
    13111311     */
    13121312    public $updated_term_meta_cache = false;
     1313
     1314    /**
     1315     * Whether the comment meta cache for matched posts has been primed.
     1316     *
     1317     * @since 4.4.0
     1318     * @access protected
     1319     * @var bool
     1320     */
     1321    public $updated_comment_meta_cache = false;
    13131322
    13141323    /**
     
    36833692        }
    36843693
     3694        // If comments have been fetched as part of the query, make sure comment meta lazy-loading is set up.
     3695        if ( ! empty( $this->comments ) ) {
     3696            add_action( 'get_comment_metadata', array( $this, 'lazyload_comment_meta' ), 10, 2 );
     3697        }
     3698
    36853699        if ( ! $q['suppress_filters'] ) {
    36863700            /**
     
    48174831        return $check;
    48184832    }
     4833
     4834    /**
     4835     * Lazy-load comment meta when inside of a `WP_Query` loop.
     4836     *
     4837     * This method is public so that it can be used as a filter callback. As a rule, there is no need to invoke it
     4838     * directly, from either inside or outside the `WP_Query` object.
     4839     *
     4840     * @since 4.4.0
     4841     *
     4842     * @param null $check      The `$check` param passed from the 'pre_comment_metadata' hook.
     4843     * @param int  $comment_id ID of the comment whose metadata is being cached.
     4844     * @return null In order not to short-circuit `get_metadata()`.
     4845     */
     4846    public function lazyload_comment_meta( $check, $comment_id ) {
     4847        /*
     4848         * We only do this once per `WP_Query` instance.
     4849         * Can't use `remove_action()` because of non-unique object hashes.
     4850         */
     4851        if ( $this->updated_comment_meta_cache ) {
     4852            return $check;
     4853        }
     4854
     4855        // Don't use `wp_list_pluck()` to avoid by-reference manipulation.
     4856        $comment_ids = array();
     4857        if ( is_array( $this->comments ) ) {
     4858            foreach ( $this->comments as $comment ) {
     4859                $comment_ids[] = $comment->comment_ID;
     4860            }
     4861        }
     4862
     4863        /*
     4864         * Only update the metadata cache for comments belonging to these posts if the comment_id passed
     4865         * to `get_comment_meta()` matches one of those comments. This prevents a single call to
     4866         * `get_comment_meta()` from priming metadata for all `WP_Query` objects.
     4867         */
     4868        if ( in_array( $comment_id, $comment_ids ) ) {
     4869            update_meta_cache( 'comment', $comment_ids );
     4870            $this->updated_comment_meta_cache = true;
     4871        } elseif ( empty( $comment_ids ) ) {
     4872            $this->updated_comment_meta_cache = true;
     4873        }
     4874
     4875        return $check;
     4876    }
    48194877}
    48204878
  • trunk/tests/phpunit/tests/comment/metaCache.php

    r34310 r34711  
    122122        }
    123123    }
     124
     125    /**
     126     * @group 34047
     127     */
     128    public function test_comment_meta_should_be_lazy_loaded_in_comment_feed_queries() {
     129        global $wpdb;
     130
     131        $posts = $this->factory->post->create_many( 2, array( 'post_status' => 'publish' ) );
     132
     133        $now = time();
     134        $comments = array();
     135        for ( $i = 0; $i < 5; $i++ ) {
     136            $comments[] = $this->factory->comment->create( array(
     137                'comment_post_ID' => $posts[0],
     138                'comment_date_gmt' => date( 'Y-m-d H:i:s', $now - ( 60 * $i ) ),
     139            ) );
     140        }
     141
     142        foreach ( $comments as $c ) {
     143            add_comment_meta( $c, 'foo', 'bar' );
     144        }
     145
     146        update_option( 'posts_per_rss', 3 );
     147
     148        $q = new WP_Query( array(
     149            'feed' => true,
     150            'withcomments' => true,
     151        ) );
     152
     153        // First comment will cause the cache to be primed.
     154        $num_queries = $wpdb->num_queries;
     155        $this->assertSame( 'bar', get_comment_meta( $comments[0], 'foo', 'bar' ) );
     156        $num_queries++;
     157        $this->assertSame( $num_queries, $wpdb->num_queries );
     158
     159        // Second comment from the results should not cause more queries.
     160        $this->assertSame( 'bar', get_comment_meta( $comments[1], 'foo', 'bar' ) );
     161        $this->assertSame( $num_queries, $wpdb->num_queries );
     162
     163        // A comment from outside the results will not be primed.
     164        $this->assertSame( 'bar', get_comment_meta( $comments[4], 'foo', 'bar' ) );
     165        $num_queries++;
     166        $this->assertSame( $num_queries, $wpdb->num_queries );
     167    }
     168
     169    /**
     170     * @group 34047
     171     */
     172    public function test_comment_meta_should_be_lazy_loaded_in_single_post_comment_feed_queries() {
     173        global $wpdb;
     174
     175        $posts = $this->factory->post->create_many( 2, array( 'post_status' => 'publish' ) );
     176
     177        $now = time();
     178        $comments = array();
     179        for ( $i = 0; $i < 5; $i++ ) {
     180            $comments[] = $this->factory->comment->create( array(
     181                'comment_post_ID' => $posts[0],
     182                'comment_date_gmt' => date( 'Y-m-d H:i:s', $now - ( 60 * $i ) ),
     183            ) );
     184        }
     185
     186        foreach ( $comments as $c ) {
     187            add_comment_meta( $c, 'foo', 'bar' );
     188        }
     189
     190        update_option( 'posts_per_rss', 3 );
     191
     192        $q = new WP_Query( array(
     193            'feed' => true,
     194            'withcomments' => true,
     195            'p' => $posts[0],
     196        ) );
     197
     198        // First comment will cause the cache to be primed.
     199        $num_queries = $wpdb->num_queries;
     200        $this->assertSame( 'bar', get_comment_meta( $comments[0], 'foo', 'bar' ) );
     201        $num_queries++;
     202        $this->assertSame( $num_queries, $wpdb->num_queries );
     203
     204        // Second comment from the results should not cause more queries.
     205        $this->assertSame( 'bar', get_comment_meta( $comments[1], 'foo', 'bar' ) );
     206        $this->assertSame( $num_queries, $wpdb->num_queries );
     207
     208        // A comment from outside the results will not be primed.
     209        $this->assertSame( 'bar', get_comment_meta( $comments[4], 'foo', 'bar' ) );
     210        $num_queries++;
     211        $this->assertSame( $num_queries, $wpdb->num_queries );
     212    }
    124213}
Note: See TracChangeset for help on using the changeset viewer.