shahid
shahid

Reputation: 544

WP grandchild categories in nested ul li

This code works fine and list all parent, child and grandchild categories The code shows bootstrap toggle on parents and it works fine.

I need the grandchildren be be shown into another level ul li and the toggle should be on children that contain grandchildren

<ul>   
 <?php 
  $get_parent_cats = array(
      'parent' => '0' //get top level categories only
  ); 
  
  $all_categories = get_categories( $get_parent_cats );//get parent categories 
  
  foreach( $all_categories as $single_category ){
      //for each category, get the ID
      $catID = $single_category->cat_ID;
  
      echo '<li><a data-toggle="collapse" href="#' . $single_category->name . '" role="button" aria-expanded="false" aria-controls="' . $single_category->name . '">' . $single_category->name . '<i class="fas fa-angle-down float-right mt-2"></i></a>'; //category name & link
      
      $get_children_cats = array(
          'child_of' => $catID //get children of this parent using the catID variable from earlier
      );
  
      $child_cats = get_categories( $get_children_cats );//get children of parent category
      echo '<ul class="collapse show" id="' . $single_category->name . '">';
          foreach( $child_cats as $child_cat ){
              //for each child category, get the ID
              $childID = $child_cat->cat_ID;
  
              //for each child category, give us the link and name
              echo '<li><a href=" ' . get_category_link( $childID ) . ' ">' . $child_cat->name . '<span class="float-right">('.$child_cat->count.')</span></a>';
  
               
          }
      echo '</ul></li>';
  } //end of categories logic ?>
</ul>

Result of above code

<ul>
<li>
  <a data-toggle="collapse" href="#DISPENSERS" role="button" aria-expanded="false" aria-controls="DISPENSERS">Parent1<i class="fas fa-angle-down float-right mt-2"></i></a>
    <ul class="collapse show" id="DISPENSERS">
        <li>Child</li>
        <li>Child</li>
        <li>GrandChild</li>
    </ul>
</li>
<li>
   <a data-toggle="collapse" href="#VULLING" role="button" aria-expanded="false" aria-controls="VULLING">Parent2<i class="fas fa-angle-down float-right mt-2"></i></a>
    <ul class="collapse show" id="VULLING">
        <li>Child</li>
        <li>GrandChild</li>
        <li>Child</li>
    </ul>
</li>

Requirements

<ul>
<li>Parent1
    <ul>
        <li>Child</li>
        <li> <a data-toggle="collapse" href="#DISPENSERS" role="button" aria-expanded="false" aria-controls="DISPENSERS">Child<i class="fas fa-angle-down float-right mt-2"></i></a>
        <ul class="collapse show" id="DISPENSERS">
           <li>
              <li>GrandChild</li>
              <li>GrandChild</li>
           </li>
        <ul>
        <li>Child</li>
    </ul>
</li>

Upvotes: 0

Views: 152

Answers (1)

FluffyKitten
FluffyKitten

Reputation: 14312

There are 2 main changes you need to get this working:

1. Get only the direct children of the category instead of all children.

You are passing child_of to get_categories for the children... this will get all children. To get only the direct children, use get_categories( "parent=".$parentID ); instead.

2. Because this will only give you one level of children, you need to call get_categories again for each child.

The working code for this is below. There are commented with each step numbered so you can see what I changed.

<ul>   
<?php 
    $all_categories = get_categories( array('parent' => '0') );//get top level categories only
    
    foreach( $all_categories as $single_category ){
        echo '<li>' . $single_category->name; 

        // 1. GET THE DIRECT CHILDREN OF THE PARENT CATEGORY
        $child_cats = get_categories( "parent=".$single_category->cat_ID);

        if ($child_cats){
            echo '<ul>';
    
            foreach( $child_cats as $child_cat ){
                //for each child category, get the ID
                $childID = $child_cat->cat_ID;

                // 2. GET THE DIRECT GRANDCHILDREN OF THE CHILD CATEGORY
                $grandchild_cats = get_categories( "parent=".$childID);

                // 3. IF THERE ARE GRANDCHILDREN, SHOW THEM IN A COLLAPSABLE LIST
                if ($grandchild_cats){
                    echo '<li><a data-toggle="collapse" href="#' . $child_cat->slug . '" role="button" aria-expanded="true" aria-controls="' . $child_cat->slug . '">' . $child_cat->name . '<i class="fas fa-angle-down float-right mt-2"></i></a>'; //category name & link
    
                    echo '<ul class="collapse show" id="' . $child_cat->slug . '">';
                    foreach( $grandchild_cats as $grandchild_cat ){
                        $grandchildID = $grandchild_cat->cat_ID;
                        //for each child category, give us the link and name
                        echo '<li><a href=" ' . get_category_link( $grandchildID ) . ' ">' . $grandchild_cat->name . '<span class="float-right">('.$grandchild_cat->count.')</span></a></li>';
                    }
                    echo '</ul></li>';
                }
                else{
                    // 4. IF THERE ARE NO GRANDCHILDREN, JUST SHOW THE CHILD AS A LINK TO THE CATEGORY
                    echo '<li><a href=" ' . get_category_link( $childID ) . ' ">' . $child_cat->name . '<span class="float-right">('.$grandchild_cat->count.')</span></a></li>';
                }
            }
            echo '</ul></li>';
    
        }// end if child_cats
        echo '</li>';
    } //end of categories loop ?>
</ul>

3. Getting Great-Grandchildren

If you needed to get more levels of children (e.g. great-grandchildren, great-great-grandchildren etc) You can create a recursive function that will keep calling itself to get the children's children until there are no more children.

I don't know where you would put the toggle in this case, but the recursive function has an argument for the current level, so you could use it to check and change the display as required.

Working Code

The code is commented below with each step numbered so you can see what I changed.

<ul>   
<?php 
    $all_categories = get_categories( array('parent' => '0') );//get top level categories only
    
    foreach( $all_categories as $single_category ){     
        echo '<li>' . $single_category->name;

         // 1. CALL OUR RECURSIVE FUNCTION TO LOOK FOR CHILDREN OF THIS CATEGORY
        showChildCategories($single_category->cat_ID, $single_category->name, 1);
        
        echo '</li>';
    } //end of categories logic ?>
</ul>


<?php
function showChildCategories($parentID, $ul_id, $current_level){

   // 2. GET THE DIRECT CHILDREN OF THE PARENT CATEGORY
    $child_cats = get_categories( "parent=".$parentID);

   // 3. IF THERE ARE NO CHILDREN, THEN DON'T CONTINUE
    if (!$child_cats) return; 
    
   // 4. DISPLAY THE CHILDREN (This is the code you were already using to show  the children)
    echo '<ul id="' . $ul_id . '">';
    foreach( $child_cats as $child_cat ){
        //for each child category, get the ID
        $childID = $child_cat->cat_ID;
        //for each child category, give us the link and name
        echo '<li><a href=" ' . get_category_link( $childID ) . ' ">' . $child_cat->name . '<span>('.$child_cat->count.')</span></a>';
        
         // 5. CALL OUR RECURSIVE FUNCTION TO LOOK FOR CHILDREN OF THIS CATEGORY
        showChildCategories($childID, $child_cat->name, $current_level+1);
    }
    echo '</ul></li>';
}
?>

Upvotes: 1

Related Questions