diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 9535b4e902..e5816580d1 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -1657,18 +1657,29 @@ function get_terms( $taxonomies, $args = '' ) { */ $args = apply_filters( 'get_terms_args', $args, $taxonomies ); + // Avoid the query if the queried parent/child_of term has no descendants. $child_of = $args['child_of']; + $parent = $args['parent']; + if ( $child_of ) { - $hierarchy = _get_term_hierarchy( reset( $taxonomies ) ); - if ( ! isset( $hierarchy[ $child_of ] ) ) { - return $empty_array; - } + $_parent = $child_of; + } elseif ( $parent ) { + $_parent = $parent; + } else { + $_parent = false; } - $parent = $args['parent']; - if ( $parent ) { - $hierarchy = _get_term_hierarchy( reset( $taxonomies ) ); - if ( ! isset( $hierarchy[ $parent ] ) ) { + if ( $_parent ) { + $in_hierarchy = false; + foreach ( $taxonomies as $_tax ) { + $hierarchy = _get_term_hierarchy( $_tax ); + + if ( isset( $hierarchy[ $_parent ] ) ) { + $in_hierarchy = true; + } + } + + if ( ! $in_hierarchy ) { return $empty_array; } } @@ -1942,9 +1953,11 @@ function get_terms( $taxonomies, $args = '' ) { } if ( $child_of ) { - $children = _get_term_hierarchy( reset( $taxonomies ) ); - if ( ! empty( $children ) ) { - $terms = _get_term_children( $child_of, $terms, reset( $taxonomies ) ); + foreach ( $taxonomies as $_tax ) { + $children = _get_term_hierarchy( $_tax ); + if ( ! empty( $children ) ) { + $terms = _get_term_children( $child_of, $terms, $_tax ); + } } } diff --git a/tests/phpunit/tests/term/getTerms.php b/tests/phpunit/tests/term/getTerms.php index b8ea31e9b2..625d0657a0 100644 --- a/tests/phpunit/tests/term/getTerms.php +++ b/tests/phpunit/tests/term/getTerms.php @@ -376,6 +376,47 @@ class Tests_Term_getTerms extends WP_UnitTestCase { $this->assertEquals( 1, count( $terms ) ); } + /** + * @ticket 31118 + */ + public function test_child_of_should_skip_query_when_specified_parent_is_not_found_in_hierarchy_cache() { + global $wpdb; + + register_taxonomy( 'wptests_tax', 'post', array( 'hierarchical' => true, ) ); + + $terms = $this->factory->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) ); + + $num_queries = $wpdb->num_queries; + + $found = get_terms( 'wptests_tax', array( + 'hide_empty' => false, + 'child_of' => $terms[0], + ) ); + + $this->assertEmpty( $found ); + $this->assertSame( $num_queries, $wpdb->num_queries ); + } + + /** + * @ticket 31118 + */ + public function test_child_of_should_respect_multiple_taxonomies() { + register_taxonomy( 'wptests_tax1', 'post', array( 'hierarchical' => true ) ); + register_taxonomy( 'wptests_tax2', 'post', array( 'hierarchical' => true ) ); + + $t1 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax1' ) ); + $t2 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax2' ) ); + $t3 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax2', 'parent' => $t2 ) ); + + $found = get_terms( array( 'wptests_tax1', 'wptests_tax2' ), array( + 'fields' => 'ids', + 'hide_empty' => false, + 'child_of' => $t2, + ) ); + + $this->assertEqualSets( array( $t3 ), $found ); + } + /** * @ticket 27123 */ @@ -1156,6 +1197,47 @@ class Tests_Term_getTerms extends WP_UnitTestCase { $this->assertEqualSets( $expected, $actual ); } + /** + * @ticket 31118 + */ + public function test_parent_should_skip_query_when_specified_parent_is_not_found_in_hierarchy_cache() { + global $wpdb; + + register_taxonomy( 'wptests_tax', 'post', array( 'hierarchical' => true, ) ); + + $terms = $this->factory->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) ); + + $num_queries = $wpdb->num_queries; + + $found = get_terms( 'wptests_tax', array( + 'hide_empty' => false, + 'parent' => $terms[0], + ) ); + + $this->assertEmpty( $found ); + $this->assertSame( $num_queries, $wpdb->num_queries ); + } + + /** + * @ticket 31118 + */ + public function test_parent_should_respect_multiple_taxonomies() { + register_taxonomy( 'wptests_tax1', 'post', array( 'hierarchical' => true ) ); + register_taxonomy( 'wptests_tax2', 'post', array( 'hierarchical' => true ) ); + + $t1 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax1' ) ); + $t2 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax2' ) ); + $t3 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax2', 'parent' => $t2 ) ); + + $found = get_terms( array( 'wptests_tax1', 'wptests_tax2' ), array( + 'fields' => 'ids', + 'hide_empty' => false, + 'parent' => $t2, + ) ); + + $this->assertEqualSets( array( $t3 ), $found ); + } + public function test_hierarchical_false_parent_should_override_child_of() { $initial_terms = $this->create_hierarchical_terms();