From fdeed90e77b9ad3f1de7246c9e23450a4878322c Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Fri, 18 Dec 2015 17:43:46 +0000 Subject: [PATCH] Ensure `get_terms()` results are unique when using 'meta_query'. The introduction of 'meta_query' to `get_terms()` in 4.4 made it possible for `get_terms()` to erroneously return duplicate results. To address the issue, we add the `DISTINCT` keyword to the SQL query when a 'meta_query' parameter has been provided. Props @jadpm. Fixes #35137. git-svn-id: https://develop.svn.wordpress.org/trunk@36003 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/taxonomy.php | 7 +++++-- tests/phpunit/tests/term/getTerms.php | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 84cc91af8f..42164528fc 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -1353,12 +1353,14 @@ function get_terms( $taxonomies, $args = '' ) { // Meta query support. $join = ''; + $distinct = ''; if ( ! empty( $args['meta_query'] ) ) { $mquery = new WP_Meta_Query( $args['meta_query'] ); $mq_sql = $mquery->get_sql( 'term', 't', 'term_id' ); $join .= $mq_sql['join']; $where .= $mq_sql['where']; + $distinct .= "DISTINCT"; } $selects = array(); @@ -1408,7 +1410,7 @@ function get_terms( $taxonomies, $args = '' ) { $join .= " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"; - $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' ); + $pieces = array( 'fields', 'join', 'where', 'distinct', 'orderby', 'order', 'limits' ); /** * Filter the terms query SQL clauses. @@ -1424,11 +1426,12 @@ function get_terms( $taxonomies, $args = '' ) { $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : ''; $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : ''; $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : ''; + $distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : ''; $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : ''; $order = isset( $clauses[ 'order' ] ) ? $clauses[ 'order' ] : ''; $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : ''; - $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"; + $query = "SELECT $distinct $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"; // $args can be anything. Only use the args defined in defaults to compute the key. $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $query ); diff --git a/tests/phpunit/tests/term/getTerms.php b/tests/phpunit/tests/term/getTerms.php index f3e9316301..bcd348586b 100644 --- a/tests/phpunit/tests/term/getTerms.php +++ b/tests/phpunit/tests/term/getTerms.php @@ -1570,6 +1570,30 @@ class Tests_Term_getTerms extends WP_UnitTestCase { $this->assertEqualSets( array( $terms[0], $terms[1] ), $found ); } + /** + * @ticket 35137 + */ + public function test_meta_query_should_not_return_duplicates() { + register_taxonomy( 'wptests_tax', 'post' ); + $terms = self::factory()->term->create_many( 1, array( 'taxonomy' => 'wptests_tax' ) ); + add_term_meta( $terms[0], 'foo', 'bar' ); + add_term_meta( $terms[0], 'foo', 'ber' ); + + $found = get_terms( 'wptests_tax', array( + 'hide_empty' => false, + 'meta_query' => array( + array( + 'key' => 'foo', + 'value' => 'bur', + 'compare' => '!=', + ), + ), + 'fields' => 'ids', + ) ); + + $this->assertEqualSets( array( $terms[0] ), $found ); + } + /** * @ticket 14162 */