How to get subcategories from category slug?

You 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 );
}