Introduce 'childless' parameter to `get_terms()`.
This new parameter allows developers to limit queried terms to terminal nodes - ie, those without any descendants. As part of the improvement, some internal logic in `get_terms()` has been consolidated. Parameters that resolve to a NOT IN clause containing term IDs ('exclude', 'exclude_tree', and 'childless') are now parsed into a single "exclusions" array before the SQL clause is generated. Props theMikeD, horike. Fixes #29839. git-svn-id: https://develop.svn.wordpress.org/trunk@31275 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
02b3356750
commit
c67e5da8c9
|
@ -1547,7 +1547,7 @@ function get_term_to_edit( $id, $taxonomy ) {
|
||||||
* along with the $args array.
|
* along with the $args array.
|
||||||
*
|
*
|
||||||
* @since 2.3.0
|
* @since 2.3.0
|
||||||
* @since 4.2.0 Introduced 'name' parameter.
|
* @since 4.2.0 Introduced 'name' and 'childless' parameters.
|
||||||
*
|
*
|
||||||
* @global wpdb $wpdb WordPress database abstraction object.
|
* @global wpdb $wpdb WordPress database abstraction object.
|
||||||
*
|
*
|
||||||
|
@ -1595,6 +1595,8 @@ function get_term_to_edit( $id, $taxonomy ) {
|
||||||
* @type int $child_of Term ID to retrieve child terms of. If multiple taxonomies
|
* @type int $child_of Term ID to retrieve child terms of. If multiple taxonomies
|
||||||
* are passed, $child_of is ignored. Default 0.
|
* are passed, $child_of is ignored. Default 0.
|
||||||
* @type int|string $parent Parent term ID to retrieve direct-child terms of. Default empty.
|
* @type int|string $parent Parent term ID to retrieve direct-child terms of. Default empty.
|
||||||
|
* @type bool $childless True to limit results to terms that have no children. This parameter has
|
||||||
|
* no effect on non-hierarchical taxonomies. Default false.
|
||||||
* @type string $cache_domain Unique cache key to be produced when this query is stored in an
|
* @type string $cache_domain Unique cache key to be produced when this query is stored in an
|
||||||
* object cache. Default is 'core'.
|
* object cache. Default is 'core'.
|
||||||
* }
|
* }
|
||||||
|
@ -1619,7 +1621,7 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||||
|
|
||||||
$defaults = array('orderby' => 'name', 'order' => 'ASC',
|
$defaults = array('orderby' => 'name', 'order' => 'ASC',
|
||||||
'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(),
|
'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(),
|
||||||
'number' => '', 'fields' => 'all', 'name' => '', 'slug' => '', 'parent' => '',
|
'number' => '', 'fields' => 'all', 'name' => '', 'slug' => '', 'parent' => '', 'childless' => false,
|
||||||
'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '',
|
'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '',
|
||||||
'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' );
|
'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' );
|
||||||
$args = wp_parse_args( $args, $defaults );
|
$args = wp_parse_args( $args, $defaults );
|
||||||
|
@ -1638,6 +1640,7 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( 'all' == $args['get'] ) {
|
if ( 'all' == $args['get'] ) {
|
||||||
|
$args['childless'] = false;
|
||||||
$args['child_of'] = 0;
|
$args['child_of'] = 0;
|
||||||
$args['hide_empty'] = 0;
|
$args['hide_empty'] = 0;
|
||||||
$args['hierarchical'] = false;
|
$args['hierarchical'] = false;
|
||||||
|
@ -1754,6 +1757,7 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||||
$where .= $inclusions;
|
$where .= $inclusions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$exclusions = array();
|
||||||
if ( ! empty( $exclude_tree ) ) {
|
if ( ! empty( $exclude_tree ) ) {
|
||||||
$exclude_tree = wp_parse_id_list( $exclude_tree );
|
$exclude_tree = wp_parse_id_list( $exclude_tree );
|
||||||
$excluded_children = $exclude_tree;
|
$excluded_children = $exclude_tree;
|
||||||
|
@ -1763,22 +1767,24 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||||
(array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) )
|
(array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$exclusions = implode( ',', array_map( 'intval', $excluded_children ) );
|
$exclusions = array_merge( $excluded_children, $exclusions );
|
||||||
} else {
|
|
||||||
$exclusions = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! empty( $exclude ) ) {
|
if ( ! empty( $exclude ) ) {
|
||||||
$exterms = wp_parse_id_list( $exclude );
|
$exclusions = array_merge( wp_parse_id_list( $exclude ), $exclusions );
|
||||||
if ( empty( $exclusions ) ) {
|
}
|
||||||
$exclusions = implode( ',', $exterms );
|
|
||||||
} else {
|
// 'childless' terms are those without an entry in the flattened term hierarchy.
|
||||||
$exclusions .= ', ' . implode( ',', $exterms );
|
$childless = (bool) $args['childless'];
|
||||||
|
if ( $childless ) {
|
||||||
|
foreach ( $taxonomies as $_tax ) {
|
||||||
|
$term_hierarchy = _get_term_hierarchy( $_tax );
|
||||||
|
$exclusions = array_merge( array_keys( $term_hierarchy ), $exclusions );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! empty( $exclusions ) ) {
|
if ( ! empty( $exclusions ) ) {
|
||||||
$exclusions = ' AND t.term_id NOT IN (' . $exclusions . ')';
|
$exclusions = ' AND t.term_id NOT IN (' . implode( ',', array_map( 'intval', $exclusions ) ) . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -495,6 +495,121 @@ class Tests_Term_getTerms extends WP_UnitTestCase {
|
||||||
$this->assertEqualSets( array( $t3, $t1 ), $found );
|
$this->assertEqualSets( array( $t3, $t1 ), $found );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ticket 29839
|
||||||
|
*/
|
||||||
|
public function test_childless_should_return_all_terms_for_flat_hierarchy() {
|
||||||
|
// If run on a flat hierarchy it should return everything.
|
||||||
|
$flat_tax = 'countries';
|
||||||
|
register_taxonomy( $flat_tax, 'post', array( 'hierarchical' => false ) );
|
||||||
|
$australia = $this->factory->term->create( array( 'name' => 'Australia', 'taxonomy' => $flat_tax ) );
|
||||||
|
$china = $this->factory->term->create( array( 'name' => 'China', 'taxonomy' => $flat_tax ) );
|
||||||
|
$tanzania = $this->factory->term->create( array( 'name' => 'Tanzania', 'taxonomy' => $flat_tax ) );
|
||||||
|
|
||||||
|
$terms = get_terms( $flat_tax, array(
|
||||||
|
'childless' => true,
|
||||||
|
'hide_empty' => false,
|
||||||
|
'fields' => 'ids',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$expected = array( $australia, $china, $tanzania );
|
||||||
|
$this->assertEqualSets( $expected, $terms );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ticket 29839
|
||||||
|
*/
|
||||||
|
public function test_childless_hierarchical_taxonomy() {
|
||||||
|
$tax = 'location';
|
||||||
|
register_taxonomy( $tax, 'post', array( 'hierarchical' => true ) );
|
||||||
|
/*
|
||||||
|
Canada
|
||||||
|
Ontario
|
||||||
|
Ottawa
|
||||||
|
Nepean
|
||||||
|
Toronto
|
||||||
|
Quebec
|
||||||
|
Montreal
|
||||||
|
PEI
|
||||||
|
*/
|
||||||
|
// Level 1
|
||||||
|
$canada = $this->factory->term->create( array( 'name' => 'Canada', 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
// Level 2
|
||||||
|
$ontario = $this->factory->term->create( array( 'name' => 'Ontario', 'parent' => $canada, 'taxonomy' => $tax ) );
|
||||||
|
$quebec = $this->factory->term->create( array( 'name' => 'Quebec', 'parent' => $canada, 'taxonomy' => $tax ) );
|
||||||
|
$pei = $this->factory->term->create( array( 'name' => 'PEI', 'parent' => $canada, 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
// Level 3
|
||||||
|
$toronto = $this->factory->term->create( array( 'name' => 'Toronto', 'parent' => $ontario, 'taxonomy' => $tax ) );
|
||||||
|
$ottawa = $this->factory->term->create( array( 'name' => 'Ottawa', 'parent' => $ontario, 'taxonomy' => $tax ) );
|
||||||
|
$montreal = $this->factory->term->create( array( 'name' => 'Montreal', 'parent' => $quebec, 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
// Level 4
|
||||||
|
$nepean = $this->factory->term->create( array( 'name' => 'Nepean', 'parent' => $ottawa, 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
$terms = get_terms( $tax, array(
|
||||||
|
'childless' => true,
|
||||||
|
'hide_empty' => false,
|
||||||
|
'fields' => 'ids',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$this->assertEqualSets( array( $montreal, $nepean, $toronto, $pei ), $terms );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ticket 29839
|
||||||
|
*/
|
||||||
|
public function test_childless_hierarchical_taxonomy_used_with_child_of() {
|
||||||
|
$tax = 'location';
|
||||||
|
register_taxonomy( $tax, 'post', array( 'hierarchical' => true ) );
|
||||||
|
|
||||||
|
// Level 1
|
||||||
|
$canada = $this->factory->term->create( array( 'name' => 'Canada', 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
// Level 2
|
||||||
|
$ontario = $this->factory->term->create( array( 'name' => 'Ontario', 'parent' => $canada, 'taxonomy' => $tax ) );
|
||||||
|
$quebec = $this->factory->term->create( array( 'name' => 'Quebec', 'parent' => $canada, 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
// Level 3
|
||||||
|
$laval = $this->factory->term->create( array( 'name' => 'Laval', 'parent' => $quebec, 'taxonomy' => $tax ) );
|
||||||
|
$montreal = $this->factory->term->create( array( 'name' => 'Montreal', 'parent' => $quebec, 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
// Level 4
|
||||||
|
$dorval = $this->factory->term->create( array( 'name' => 'Dorval', 'parent' => $montreal, 'taxonomy' => $tax ) );
|
||||||
|
|
||||||
|
$terms = get_terms( $tax, array(
|
||||||
|
'childless' => true,
|
||||||
|
'child_of' => $quebec,
|
||||||
|
'hide_empty' => false,
|
||||||
|
'fields' => 'ids',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$this->assertEqualSets( array( $laval ), $terms );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ticket 29839
|
||||||
|
*/
|
||||||
|
public function test_childless_should_enforce_childless_status_for_all_queried_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_tax1', 'parent' => $t1 ) );
|
||||||
|
$t3 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax2' ) );
|
||||||
|
$t4 = $this->factory->term->create( array( 'taxonomy' => 'wptests_tax2', 'parent' => $t3 ) );
|
||||||
|
|
||||||
|
$found = get_terms( array( 'wptests_tax1', 'wptests_tax2' ), array(
|
||||||
|
'fields' => 'ids',
|
||||||
|
'hide_empty' => false,
|
||||||
|
'childless' => true,
|
||||||
|
) );
|
||||||
|
|
||||||
|
$this->assertEqualSets( array( $t2, $t4 ), $found );
|
||||||
|
}
|
||||||
|
|
||||||
public function test_get_terms_hierarchical_tax_hide_empty_false_fields_ids() {
|
public function test_get_terms_hierarchical_tax_hide_empty_false_fields_ids() {
|
||||||
// Set up a clean taxonomy.
|
// Set up a clean taxonomy.
|
||||||
$tax = 'hierarchical_fields';
|
$tax = 'hierarchical_fields';
|
||||||
|
|
Loading…
Reference in New Issue