diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index d1cc69d96ca49..65b35289a9a21 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -738,6 +738,8 @@ public function get_terms() { $order = isset( $clauses['order'] ) ? $clauses['order'] : ''; $limits = isset( $clauses['limits'] ) ? $clauses['limits'] : ''; + $fields_is_filtered = implode( ', ', $selects ) !== $fields; + if ( $where ) { $where = "WHERE $where"; } @@ -782,7 +784,7 @@ public function get_terms() { $cache = array_map( 'intval', $cache ); } elseif ( 'count' !== $_fields ) { if ( ( 'all_with_object_id' === $_fields && ! empty( $args['object_ids'] ) ) - || ( 'all' === $_fields && $args['pad_counts'] ) + || ( 'all' === $_fields && $args['pad_counts'] || $fields_is_filtered ) ) { $term_ids = wp_list_pluck( $cache, 'term_id' ); } else { @@ -884,6 +886,8 @@ public function get_terms() { $object->count = $term->count; $term_cache[] = $object; } + } elseif ( $fields_is_filtered ) { + $term_cache = $term_objects; } else { $term_cache = wp_list_pluck( $term_objects, 'term_id' ); } diff --git a/tests/phpunit/tests/term/query.php b/tests/phpunit/tests/term/query.php index 0e118a3c169a4..682e86a8dfced 100644 --- a/tests/phpunit/tests/term/query.php +++ b/tests/phpunit/tests/term/query.php @@ -698,6 +698,106 @@ public function test_query_should_return_zero_for_field_as_count_and_child_of_se $this->assertSame( 0, $q->query( $args ) ); } + /** + * If fields have filtered, cached results should work. + * + * @ticket 58116 + * @group cache + */ + public function test_query_filter_fields() { + $post_id = self::factory()->post->create(); + register_taxonomy( 'wptests_tax', 'post' ); + + $term_id = self::factory()->term->create( + array( + 'taxonomy' => 'wptests_tax', + ) + ); + wp_set_object_terms( $post_id, array( $term_id ), 'wptests_tax' ); + $post_draft_id = self::factory()->post->create( array( 'post_type' => 'draft' ) ); + wp_set_object_terms( $post_draft_id, array( $term_id ), 'wptests_tax' ); + + add_filter( 'terms_clauses', array( $this, 'filter_fields_terms_clauses' ), 10, 3 ); + + $args = array( + 'taxonomy' => 'wptests_tax', + 'hide_empty' => false, + 'post_type' => 'post', + 'post_status' => 'publish', + ); + + $q1 = new WP_Term_Query(); + $terms1 = $q1->query( $args ); + $q2 = new WP_Term_Query(); + $terms2 = $q2->query( $args ); + $this->assertSameSets( wp_list_pluck( $terms1, 'term_id' ), wp_list_pluck( $terms2, 'term_id' ), 'Term IDs are expected to match' ); + $this->assertSameSets( wp_list_pluck( $terms1, 'count' ), wp_list_pluck( $terms2, 'count' ), 'Term counts are expected to match' ); + } + + /** + * Filter `terms_clauses` to change the field requested. The filter is from example code given in #58116. + */ + public function filter_fields_terms_clauses( $clauses, $taxonomies, $args ) { + global $wpdb; + + // Set to query specific posts types if set. + if ( ! empty( $args['post_type'] ) ) { + $clauses['fields'] = 'DISTINCT t.term_id, tt.term_taxonomy_id, tt.taxonomy, tt.description, tt.parent, COUNT(p.post_type) AS count'; + $clauses['join'] .= ' LEFT JOIN ' . $wpdb->term_relationships . ' AS r ON r.term_taxonomy_id = tt.term_taxonomy_id LEFT JOIN ' . $wpdb->posts . ' AS p ON p.ID = r.object_id'; + $clauses['where'] .= " AND (p.post_type = '" . $args['post_type'] . "' OR p.post_type IS NULL)"; + $clauses['orderby'] = 'GROUP BY t.term_id ' . $clauses['orderby']; + } + + // Set to query posts with specific status. + if ( ! empty( $args['post_status'] ) ) { + $clauses['where'] .= " AND (p.post_status = '" . $args['post_status'] . "')"; + } + return $clauses; + } + + /** + * If fields have filtered, cached results should work. + * + * @ticket 58116 + * @group cache + */ + public function test_query_filter_select_fields() { + $post_id = self::factory()->post->create(); + register_taxonomy( 'wptests_tax', 'post' ); + + $term_id = self::factory()->term->create( + array( + 'taxonomy' => 'wptests_tax', + ) + ); + wp_set_object_terms( $post_id, array( $term_id ), 'wptests_tax' ); + $post_draft_id = self::factory()->post->create( array( 'post_type' => 'draft' ) ); + wp_set_object_terms( $post_draft_id, array( $term_id ), 'wptests_tax' ); + + add_filter( 'get_terms_fields', array( $this, 'filter_get_terms_fields' ) ); + + $args = array( + 'taxonomy' => 'wptests_tax', + 'hide_empty' => false, + 'post_type' => 'post', + 'post_status' => 'publish', + ); + + $q1 = new WP_Term_Query(); + $terms1 = $q1->query( $args ); + $q2 = new WP_Term_Query(); + $terms2 = $q2->query( $args ); + $this->assertSameSets( wp_list_pluck( $terms1, 'term_id' ), wp_list_pluck( $terms2, 'term_id' ), 'Term IDs are expected to match' ); + $this->assertSameSets( wp_list_pluck( $terms1, 'parent' ), wp_list_pluck( $terms2, 'parent' ), 'Term parent are expected to match' ); + } + + /** + * Filter `get_terms_fields` to change the field requested. + */ + public function filter_get_terms_fields( $select ) { + return array( 't.term_id', 'tt.parent' ); + } + /** * The terms property should be an empty array for fields not as count and parent set. *