diff --git a/src/wp-includes/class-wp-comment-query.php b/src/wp-includes/class-wp-comment-query.php index 787e769506..0b2ce72b82 100644 --- a/src/wp-includes/class-wp-comment-query.php +++ b/src/wp-includes/class-wp-comment-query.php @@ -34,6 +34,15 @@ class WP_Comment_Query { */ public $meta_query = false; + /** + * Metadata query clauses. + * + * @since 4.4.0 + * @access protected + * @var array + */ + protected $meta_query_clauses; + /** * Date query container * @@ -261,8 +270,6 @@ class WP_Comment_Query { public function get_comments() { global $wpdb; - $groupby = ''; - $this->parse_query(); // Parse meta query @@ -281,7 +288,7 @@ class WP_Comment_Query { // Reparse query vars, in case they were modified in a 'pre_get_comments' callback. $this->meta_query->parse_query_vars( $this->query_vars ); if ( ! empty( $this->meta_query->queries ) ) { - $meta_query_clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this ); + $this->meta_query_clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this ); } // $args can include anything. Only use the args defined in the query_var_defaults to compute the key. @@ -291,13 +298,66 @@ class WP_Comment_Query { $last_changed = microtime(); wp_cache_set( 'last_changed', $last_changed, 'comment' ); } - $cache_key = "get_comments:$key:$last_changed"; + $cache_key = "get_comment_ids:$key:$last_changed"; - if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) { - $this->comments = $cache; + $comment_ids = wp_cache_get( $cache_key, 'comment' ); + if ( false === $comment_ids ) { + $comment_ids = $this->get_comment_ids(); + wp_cache_add( $cache_key, $comment_ids, 'comment' ); + } + + // If querying for a count only, there's nothing more to do. + if ( $this->query_vars['count'] ) { + // $comment_ids is actually a count in this case. + return intval( $comment_ids ); + } + + $comment_ids = array_map( 'intval', $comment_ids ); + + if ( 'ids' == $this->query_vars['fields'] ) { + $this->comments = $comment_ids; return $this->comments; } + _prime_comment_caches( $comment_ids, $this->query_vars['update_comment_meta_cache'] ); + + // Fetch full comment objects from the primed cache. + $_comments = array(); + foreach ( $comment_ids as $comment_id ) { + if ( $_comment = wp_cache_get( $comment_id, 'comment' ) ) { + $_comments[] = $_comment; + } + } + + /** + * Filter the comment query results. + * + * @since 3.1.0 + * + * @param array $results An array of comments. + * @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference. + */ + $_comments = apply_filters_ref_array( 'the_comments', array( $_comments, &$this ) ); + + // Convert to WP_Comment instances + $comments = array_map( 'get_comment', $_comments ); + + $this->comments = $comments; + return $this->comments; + } + + /** + * Used internally to get a list of comment IDs matching the query vars. + * + * @since 4.4.0 + * @access protected + * + * @global wpdb $wpdb + */ + protected function get_comment_ids() { + global $wpdb; + + $groupby = ''; $where = array(); // Assemble clauses related to 'comment_approved'. @@ -471,14 +531,7 @@ class WP_Comment_Query { if ( $this->query_vars['count'] ) { $fields = 'COUNT(*)'; } else { - switch ( strtolower( $this->query_vars['fields'] ) ) { - case 'ids': - $fields = "$wpdb->comments.comment_ID"; - break; - default: - $fields = "*"; - break; - } + $fields = "$wpdb->comments.comment_ID"; } $join = ''; @@ -625,11 +678,11 @@ class WP_Comment_Query { $join = "JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID"; } - if ( ! empty( $meta_query_clauses ) ) { - $join .= $meta_query_clauses['join']; + if ( ! empty( $this->meta_query_clauses ) ) { + $join .= $this->meta_query_clauses['join']; // Strip leading 'AND'. - $where[] = preg_replace( '/^\s*AND\s*/', '', $meta_query_clauses['where'] ); + $where[] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] ); if ( ! $this->query_vars['count'] ) { $groupby = "{$wpdb->comments}.comment_ID"; @@ -677,35 +730,11 @@ class WP_Comment_Query { $this->request = "SELECT $fields FROM $wpdb->comments $join $where $groupby $orderby $limits"; if ( $this->query_vars['count'] ) { - return $wpdb->get_var( $this->request ); + return intval( $wpdb->get_var( $this->request ) ); + } else { + $comment_ids = $wpdb->get_col( $this->request ); + return array_map( 'intval', $comment_ids ); } - - if ( 'ids' == $this->query_vars['fields'] ) { - $this->comments = $wpdb->get_col( $this->request ); - return array_map( 'intval', $this->comments ); - } - - $results = $wpdb->get_results( $this->request ); - /** - * Filter the comment query results. - * - * @since 3.1.0 - * - * @param array $results An array of comments. - * @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference. - */ - $_comments = apply_filters_ref_array( 'the_comments', array( $results, &$this ) ); - - // Convert to WP_Comment instances - $comments = array_map( 'get_comment', $_comments ); - - wp_cache_add( $cache_key, $comments, 'comment' ); - if ( '*' === $fields ) { - update_comment_cache( $comments, $this->query_vars['update_comment_meta_cache'] ); - } - - $this->comments = $comments; - return $this->comments; } /** diff --git a/src/wp-includes/comment-functions.php b/src/wp-includes/comment-functions.php index f0807b1763..50d6d3662b 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 ) { } } +/** + * Adds any comments from the given IDs to the cache that do not already exist in cache. + * + * @since 4.4.0 + * @access private + * + * @see update_comment_cache() + * + * @global wpdb $wpdb + * + * @param array $comment_ids Array of comment IDs. + * @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true. + */ +function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) { + global $wpdb; + + $non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' ); + if ( !empty( $non_cached_ids ) ) { + $fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) ); + + update_comment_cache( $fresh_comments, $update_meta_cache ); + } +} + /** * Lazy load comment meta when inside of a `WP_Query` loop. * diff --git a/tests/phpunit/tests/comment/metaCache.php b/tests/phpunit/tests/comment/metaCache.php index ff7de36b92..edec8b8598 100644 --- a/tests/phpunit/tests/comment/metaCache.php +++ b/tests/phpunit/tests/comment/metaCache.php @@ -17,6 +17,9 @@ class Tests_Comment_Meta_Cache extends WP_UnitTestCase { update_comment_meta( $cid, 'foo', 'bar' ); } + // Clear comment cache, just in case. + clean_comment_cache( $comment_ids ); + $q = new WP_Comment_Query( array( 'post_ID' => $p, ) ); @@ -42,6 +45,9 @@ class Tests_Comment_Meta_Cache extends WP_UnitTestCase { update_comment_meta( $cid, 'foo', 'bar' ); } + // Clear comment cache, just in case. + clean_comment_cache( $comment_ids ); + $q = new WP_Comment_Query( array( 'post_ID' => $p, 'update_comment_meta_cache' => true, diff --git a/tests/phpunit/tests/comment/query.php b/tests/phpunit/tests/comment/query.php index cecf92cf0a..73ab4aa196 100644 --- a/tests/phpunit/tests/comment/query.php +++ b/tests/phpunit/tests/comment/query.php @@ -1667,6 +1667,7 @@ class Tests_Comment_Query extends WP_UnitTestCase { $q1 = new WP_Comment_Query(); $q1->query( array( 'post_id' => $p, + 'fields' => 'ids', ) ); $num_queries = $wpdb->num_queries; @@ -1674,6 +1675,7 @@ class Tests_Comment_Query extends WP_UnitTestCase { $q2 = new WP_Comment_Query(); $q2->query( array( 'post_id' => $p, + 'fields' => 'ids', 'foo' => 'bar', ) );