You can’t do it using simple for
/foreach
loops. This is an excellent example where a recursion can help:
function get_categories_list( $parent, $use_toggle = true ) {
$result = "";
$categories = get_categories( array ( 'parent' => $parent ) );
if ($categories) {
foreach ($categories as $category) {
$name = $category->name;
// HERE THE RECURSION IS USED TO GET SUBCATEGORIES TREE
$children = get_categories_list( $category->cat_ID );
if ($children) {
// category has children, use expandable style
if ( $use_toggle ) {
$result .= "<li><a data-toggle=\"collapse\" href=\"#${name}\" role=\"button\" aria-expanded=\"false\" aria-controls=\"${name}\">${name}<i class=\"fas fa-angle-down float-right mt-2\"></i></a><ul class=\"collapse show\" id=\"${name}\">" . $children . "</ul></li>";
} else {
// root categories level, simplified style without toggle
$result .= "<li>${name}<ul>" . $children . "</ul></li>";
}
} else {
// category hasn't any children, use endpoint style
$result .= '<li><a href="' . get_category_link( $category->cat_ID ) . "\">${name}<span class=\"float-right\">(" . $category->count . ')</span></a></li>';
}
}
}
return $result;
}
// list categories from root level ( parent = 0 ), no toggle at root level ( $use_toggle = false )
echo '<ul>', get_categories_list( 0, false ), '</ul>';