So I have this category structure
- Recipes
|-- Asian Food
|-- Chinese Food
|-- Japanese Food
|-- Taiwanese Food
|-- etc...
|-- European Food
|-- etc...
|-- American Food
|-- etc...
|-- etc...
- Articles
|-- News
|-- etc...
|-- Tutorial
|-- etc...
|-- Gossip
|-- etc...
If I have category Recipes (slug: recipes), how to get its direct children [Asian Food, European Food, American Food]?
And if I have category Asian Food (slug: asian-food), how to get [Chinese Food, Japanese Food, Taiwanese Food]?
This is what I tried.
function getChild ($slug) {
return get_terms('category', ['parent' => $slug]);
}
// $parentSlug = explode('/', trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/'))[0];
$parentSlug = 'recipes';
$children = getChild($parentSlug); // returns blank array
So I have this category structure
- Recipes
|-- Asian Food
|-- Chinese Food
|-- Japanese Food
|-- Taiwanese Food
|-- etc...
|-- European Food
|-- etc...
|-- American Food
|-- etc...
|-- etc...
- Articles
|-- News
|-- etc...
|-- Tutorial
|-- etc...
|-- Gossip
|-- etc...
If I have category Recipes (slug: recipes), how to get its direct children [Asian Food, European Food, American Food]?
And if I have category Asian Food (slug: asian-food), how to get [Chinese Food, Japanese Food, Taiwanese Food]?
This is what I tried.
function getChild ($slug) {
return get_terms('category', ['parent' => $slug]);
}
// $parentSlug = explode('/', trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/'))[0];
$parentSlug = 'recipes';
$children = getChild($parentSlug); // returns blank array
Share
Improve this question
asked May 4, 2020 at 9:57
Christhofer NataliusChristhofer Natalius
1034 bronze badges
1 Answer
Reset to default 2You may use get_term_children() to get children of a term but it return only ids so you could use get_term_by() to convert it to id
Approach 3
This method is based WP builtin on get_term_children() and _get_term_hierarchy() but converted to support slug. The whole set of functions are presented here for reference.
- Like builtin version, return unlimited number of children
- because it is based on builtin, cache system is also implemented
- cache clean up logic is also added
Please feel free to adjust and test before production use. Approach 3 outputs unlimited of children. If find any bugs or insufficient, please feel free to comment.
// this is based on WP Core, return the immediate 1 level of children
function get_term_children_in_slug( $term_slug, $taxonomy ) {
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
}
$term_data = _get_term_hierarchy_in_slug( $taxonomy );
$terms = $term_data['children'];
$term_slug_ids = $term_data['term_slug_ids'];
if ( ! isset( $term_slug_ids[ $term_slug ] ) ) {
return array();
}
if( ! isset( $terms[ $term_slug_ids[ $term_slug ] ] ) ) {
return array();
}
$children = $terms[ $term_slug_ids[ $term_slug ] ];
// find children of children
foreach ( (array) $terms[ $term_slug_ids[ $term_slug ] ] as $child_slug => $child_id ) {
if ( $term_slug === $child_slug ) {
continue;
}
if ( isset( $terms[ $term_slug_ids[ $child_slug ] ]) ) {
$children = array_merge( $children, get_term_children_in_slug( $child_slug, $taxonomy ) );
}
}
return $children;
}
// this is based on WP Core for get_term_children() but support slug instead
function _get_term_hierarchy_in_slug( $taxonomy ) {
if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
return array();
}
// WP Builtin with cache by saving to option, reduce performance hit
$children = get_option( "{$taxonomy}_children_slug" );
if ( is_array( $children ) ) {
return $children;
}
$children = array();
$terms = get_terms( 'category', array(
'hide_empty' => false,
// 'orderby' => 'id', // haven't used in test, optional
'fields' => 'all_with_object_id',
) );
$term_ids = []; // as cache to find out terms parent slug
$compare = [];
// all parents become level 1 id => level 2 id structure
foreach ( $terms as $key => $term ) {
$term_ids[ $term->slug ] = $term->term_id;
if ( $term->parent > 0 ) {
// $compare[ $term->slug ][] = $term->parent;
$children[ $term->parent ][$term->slug] = $term->term_id;
}
}
update_option( "{$taxonomy}_children_slug", $children );
// children for use, term ids for matching
return array(
'children' => $children,
'term_slug_ids' => $term_ids
);
}
// add clean up cache logic together with builtin clean up
add_action( 'clean_taxonomy_cache', 'custom_clean_up_term_cache' );
function custom_clean_up_term_cache( $taxonomy ) {
delete_option( "{$taxonomy}_children_slug" );
}
Approach 2 (Recommended method since it is the most simplest)
Asker combine get_term_by() in the first answer with get_categories() This method
- depends on args, could return either direct descendants or all children including grandchilren
Reference posts
// this method only return 1 level of immediate children
function get_term_children_in_slug_approach2( $term_slug ) {
$parent = get_term_by( 'slug', $term_slug, 'category' );
$term_slugs = (get_categories([
'taxonomy' => 'category',
'parent' => $parent->term_id,
'hide_empty' => false, // in the test, have no posts
]));
return $term_slugs;
}
// the following return children and grandchildren
function get_term_children_in_slug_approach2( $term_slug ) {
$parent = get_term_by( 'slug', $term_slug, 'category' );
$term_slugs = (get_categories([
'taxonomy' => 'category',
'child_of' => $parent->term_id,
'hide_empty' => false, // in the test, have no posts
]));
return $term_slugs;
}
Approach 1
Because the WP Builtin tools are IDs based, so using the builtin get_term_chilren() is not straightforward and need to do ID to slug searching.
- return the first immediate level of children
function getChild ( $slug ) {
$term = get_term_by( 'slug', $slug, 'category' );
$term_children = get_term_children( $term->term_id, 'category' );
// return a list of children id
if( $term_children ) {
return get_term_children( $term->term_id, 'category' );
}
return $term_children;
}
after you have got a list of children id, you can convert it back for a slug
// helper for retrieve slug from $term ID
function get_term_slug( $id ) {
$term = get_term_by( 'id', $id, 'category' );
// var_dump($term);
if( $term ) {
return $term->slug;
}
return $term;
}
// get a list of terms slug from term id
$term_slugs = [];
$term_children_ids = getChild( 'level1' ); // example
foreach ($term_children_ids as $key => $term_id) {
$term_slugs[] = get_term_slug( $term_id );
}