From a5001396adb087a264255f51da3c5d1e9bd87c2b Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Sat, 1 Jul 2017 11:24:26 +0000 Subject: [PATCH] Introduce `$comment_count` param for `WP_Query`. This parameter allows querying for posts with a specific value of `comment_count`. It is also possible to query for posts that match a `comment_count` comparison by passing an array with 'value' and 'compare' operators (eg `array( 'compare' => '>', 'value' => 5 )`). Props ramon fincken. Fixes #28399. git-svn-id: https://develop.svn.wordpress.org/trunk@40978 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-query.php | 29 ++ tests/phpunit/tests/query/commentCount.php | 354 +++++++++++++++++++++ 2 files changed, 383 insertions(+) create mode 100644 tests/phpunit/tests/query/commentCount.php diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 169bb2e388..518e5638b6 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -641,6 +641,7 @@ class WP_Query { * Introduced the `$comment_status` and `$ping_status` parameters. * Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts. * @since 4.6.0 Added 'post_name__in' support for `$orderby`. Introduced the `$lazy_load_term_meta` argument. + * @since 4.9.0 Introduced the `$comment_count` parameter. * @access public * * @param string|array $query { @@ -657,6 +658,10 @@ class WP_Query { * @type array $category__in An array of category IDs (OR in, no children). * @type array $category__not_in An array of category IDs (NOT in). * @type string $category_name Use category slug (not name, this or any children). + * @type array|int $comment_count Filter results by comment count. Provide an integer to match + * comment count exactly. Provide an array with integer 'value' + * and 'compare' operator ('=', '!=', '>', '>=', '<', '<=' ) to + * compare against comment_count in a specific way. * @type string $comment_status Comment status. * @type int $comments_per_page The number of comments to return per page. * Default 'comments_per_page' option. @@ -2140,6 +2145,30 @@ class WP_Query { $whichauthor .= " AND ({$wpdb->posts}.post_author = " . absint($q['author']) . ')'; } + // Matching by comment count. + if ( isset( $q['comment_count'] ) ) { + // Numeric comment count is converted to array format. + if ( is_numeric( $q['comment_count'] ) ) { + $q['comment_count'] = array( + 'value' => intval( $q['comment_count'] ), + ); + } + + if ( isset( $q['comment_count']['value'] ) ) { + $q['comment_count'] = array_merge( array( + 'compare' => '=', + ), $q['comment_count'] ); + + // Fallback for invalid compare operators is '='. + $compare_operators = array( '=', '!=', '>', '>=', '<', '<=' ); + if ( ! in_array( $q['comment_count']['compare'], $compare_operators, true ) ) { + $q['comment_count']['compare'] = '='; + } + + $where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_count {$q['comment_count']['compare']} %d", $q['comment_count']['value'] ); + } + } + // MIME-Type stuff for attachment browsing if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] ) { diff --git a/tests/phpunit/tests/query/commentCount.php b/tests/phpunit/tests/query/commentCount.php new file mode 100644 index 0000000000..b918a7f634 --- /dev/null +++ b/tests/phpunit/tests/query/commentCount.php @@ -0,0 +1,354 @@ +q ); + $this->q = new WP_Query(); + } + + public function tearDown() { + parent::tearDown(); + unset( $this->q ); + } + + public static function wpSetUpBeforeClass( $factory ) { + $post_id = self::factory()->post->create( array( 'post_content' => 1 . rand_str() . ' about', 'post_type' => self::$post_type ) ); + self::$post_ids[1][] = $post_id; + self::factory()->comment->create( array( 'comment_post_ID' => $post_id ) ); + + $post_id = self::factory()->post->create( array( 'post_content' => 1 . rand_str() . ' about', 'post_type' => self::$post_type ) ); + self::$post_ids[4][] = $post_id; + for ( $i = 0; $i < 4; $i++ ) { + self::factory()->comment->create( array( 'comment_post_ID' => $post_id ) ); + } + + $post_id = self::factory()->post->create( array( 'post_content' => 1 . rand_str() . ' about', 'post_type' => self::$post_type ) ); + self::$post_ids[5][] = $post_id; + for ( $i = 0; $i < 5; $i++ ) { + self::factory()->comment->create( array( 'comment_post_ID' => $post_id ) ); + } + + $post_id = self::factory()->post->create( array( 'post_content' => 1 . rand_str() . ' about', 'post_type' => self::$post_type ) ); + self::$post_ids[5][] = $post_id; + for ( $i = 0; $i < 5; $i++ ) { + self::factory()->comment->create( array( 'comment_post_ID' => $post_id ) ); + } + } + + private function helper_get_found_post_ids() { + return wp_list_pluck( $this->q->posts, 'ID' ); + } + + public function test_operator_equals() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 4, + 'compare' => '=', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = self::$post_ids[4]; + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_operator_greater_than() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 4, + 'compare' => '>', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = self::$post_ids[5]; + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_operator_greater_than_no_results() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 6, + 'compare' => '>', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + + $this->assertEqualSets( $found_post_ids, $expected ); + } + public function test_operator_less_than() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 6, + 'compare' => '<', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + foreach ( self::$post_ids[1] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[4] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[5] as $expected_id ) { + $expected[] = $expected_id; + } + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_operator_less_than_no_results() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 1, + 'compare' => '<', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + + public function test_operator_not_equal() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 15, + 'compare' => '!=', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + foreach ( self::$post_ids[1] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[4] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[5] as $expected_id ) { + $expected[] = $expected_id; + } + + $this->assertEqualSets( $found_post_ids, $expected ); + + } + public function test_operator_equal_or_greater_than() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 4, + 'compare' => '>=', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + foreach ( self::$post_ids[4] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[5] as $expected_id ) { + $expected[] = $expected_id; + } + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_operator_equal_or_greater_than_no_results() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 7, + 'compare' => '>=', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_operator_equal_or_less_than() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 4, + 'compare' => '<=', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + foreach ( self::$post_ids[1] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[4] as $expected_id ) { + $expected[] = $expected_id; + } + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_operator_equal_or_less_than_no_results() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 0, + 'compare' => '<=', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_invalid_operator_should_fall_back_on_equals() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 5, + 'compare' => '@', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + foreach ( self::$post_ids[5] as $expected_id ) { + $expected[] = $expected_id; + } + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_wrong_count_no_results() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 'abc', + 'compare' => '=', + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_no_operator_no_results() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => array( + 'value' => 5, + ), + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = self::$post_ids[5]; + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_empty_non_numeric_string_should_be_ignored() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => '', + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = array(); + foreach ( self::$post_ids[1] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[4] as $expected_id ) { + $expected[] = $expected_id; + } + foreach ( self::$post_ids[5] as $expected_id ) { + $expected[] = $expected_id; + } + + $this->assertEqualSets( $found_post_ids, $expected ); + } + + public function test_simple_count() { + $args = array( + 'post_type' => self::$post_type, + 'posts_per_page' => -1, + 'comment_count' => 5, + ); + $this->q->query( $args ); + + $found_post_ids = $this->helper_get_found_post_ids(); + + $expected = self::$post_ids[5]; + + $this->assertEqualSets( $found_post_ids, $expected ); + } +} +