1

I have a really hard time grasping the concept of creating a category tree. This is the criterias:

  • Create an parent/child HTML unordered list with unlimited depth
  • Remove all items with status = 0 and any children
  • Create URL e.g. /clothes/jeans
  • Optional: Generating breadcrumb

The closest solution I could find just made me more confused because I couldn't make them work:

Here is my array:

Array
(
    [0] => Array
        (
            [id] => 1
            [parent] => 0
            [status] => 2
            [slug] => clothes
            [title] => Clothes
        )
    [1] => Array
        (
            [id] => 2
            [parent] => 1
            [status] => 2
            [slug] => jeans
            [title] => Jeans
        )
    [2] => Array
        (
            [id] => 3
            [parent] => 1
            [status] => 2
            [slug] => dresses
            [title] => Dresses
        )
    [3] => Array
        (
            [id] => 4
            [parent] => 0
            [status] => 2
            [slug] => accessories
            [title] => Accessories
        )
    [4] => Array
        (
            [id] => 5
            [parent] => 4
            [status] => 2
            [slug] => bags
            [title] => Bags
        )
    [5] => Array
        (
            [id] => 6
            [parent] => 4
            [status] => 2
            [slug] => watches
            [title] => Watches
        )
    [6] => Array
        (
            [id] => 7
            [parent] => 6
            [status] => 2
            [slug] => rolex
            [title] => Rolex
        )
)

This is the Unordered list I want:

<ul>
    <li><a href="/clothes">Clothes</a>
        <ul>
            <li>
                <a href="/clothes/jeans">Clothes</a>
            </li>
            <li>
                <a href="/clothes/dresses">Clothes</a>
            </li>
        </ul>
    </li>
    <li><a href="/accessories">Accessories</a>
        <ul>
            <li>
                <a href="/accessories/bags">Bags</a>
            </li>
            <li>
                <a href="/accessories/watches">Watches</a>
                <ul>
                    <li>
                        <a href="/accessories/watches/rolex">Rolex</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>
Community
  • 1
  • 1
Cudos
  • 5,733
  • 11
  • 50
  • 77

2 Answers2

1

maybe a recursive function as this:

function filter_by_parent($parent_id,$ar){
    $retval=array();
    foreach($ar as $a){
        if($a['status']==0)
            continue;
        if($a['parent']==$parent_id)
            $retval[]=$a;
    }
    return $retval;
}

function print_list($parent, $level,$ar,$url_prefix) { 
    $children = filter_by_parent($parent,$ar);
    if(empty($children))
        return;

    echo "<ul>"; 
    foreach($children as $child){ 
        // indent and display the title of this child <br>  
        echo "<li>".$child['title']. "( {$url_prefix}{$child['slug']} )";

        print_list($child['id'], $level+1,$ar,$url_prefix.$child['slug'].'/'); 
        echo  "</li>";
    } 
    echo "</ul>";
}
print_list(0,0,$test,'/');

with your input, the result would be:

  • Clothes( /clothes )
  • -Jeans( /clothes/jeans )
  • -Dresses( /clothes/dresses )
  • Accessories( /accessories )
  • -Bags( /accessories/bags )
  • -Watches( /accessories/watches )

(it's an adapted version of this: Storing Hierarchical Data in a Database)

David Baker
  • 84
  • 13
Roberto
  • 2,206
  • 4
  • 24
  • 31
  • Very nice. Still, how do I get it into a Hierarchical
      ? Tried to figure out how to with no luck.
    – Cudos Nov 11 '12 at 16:53
  • I need to pass the output to a variable e.g. all lines with echo should go into $output. I tried to alter the code but with no luck :-( – Cudos Nov 11 '12 at 23:23
  • a) just concatenate a string in print_list function and return it (replace echo with $retval =....) b) use output buffering ob_start / ob_get_contents / ob_end_clean – Roberto Nov 12 '12 at 08:07
0

Okay , i got a solution for you with a recursive function. In case you are in a hurry , You can find the full code here.

Rest of this post is just an explanation how it works.

This is your array :

$arr = array
(
   0=> array
    (
         'id'  => 1,
         'parent'  => 0,
         'status'  => 2,
         'slug'  => 'clothes',
         'title'  => 'Clothes'
    ),
   1 =>array
    (
         'id'  => 2,
         'parent'  => 1,
         'status'  => 2,
         'slug'  => 'jeans',
         'title'  => 'Jeans'
    ),
   2=> array
    (
         'id'  => 3,
         'parent'  => 1,
         'status'  => 2,
         'slug'  => 'dresses',
         'title'  => 'Dresses'
    ),
    3=> array
    (
         'id'  => 4,
         'parent'  => 0,
         'status'  => 2,
         'slug'  => 'accessories',
         'title'  => 'Accessories'
    ),
    4 => array
    (
         'id'  => 5,
         'parent'  => 4,
         'status'  => 2,
         'slug'  => 'bags',
         'title'  => 'Bags'
    ),
    5 => array
    (
         'id'  => 6,
         'parent'  => 4,
         'status'  => 2,
         'slug'  => 'watches',
         'title'  => 'Watches'
    ),

    6 => array
    (
         'id'  => 7,
         'parent'  => 6,
         'status'  => 2,
         'slug'  => 'rolex',
         'title'  => 'Rolex'
    ) 

) ;

Next time you include an array in the question , be sure that it's ready to use in a php script so that people can directly play with that.

Now , at first i go through the array and established a connection between parents and there children . What i did is , if a element with id 1 has any children it , all of it's children will go into the arrays's index 1. Here is the part which did the trick for me.

$tree = array ();
foreach ($arr as $val) {
    $tree [ $val['parent'] ] [] = $val;

}

Pretty simple right ??? :)

This is the array it generates from your array after this processing :

array(4) {
  [0]=>
  array(2) {
    [0]=>
    array(5) {
      ["id"]=>
      int(1)
      ["parent"]=>
      int(0)
      ["status"]=>
      int(2)
      ["slug"]=>
      string(7) "clothes"
      ["title"]=>
      string(7) "Clothes"
    }
    [1]=>
    array(5) {
      ["id"]=>
      int(4)
      ["parent"]=>
      int(0)
      ["status"]=>
      int(2)
      ["slug"]=>
      string(11) "accessories"
      ["title"]=>
      string(11) "Accessories"
    }
  }
  [1]=>
  array(2) {
    [0]=>
    array(5) {
      ["id"]=>
      int(2)
      ["parent"]=>
      int(1)
      ["status"]=>
      int(2)
      ["slug"]=>
      string(5) "jeans"
      ["title"]=>
      string(5) "Jeans"
    }
    [1]=>
    array(5) {
      ["id"]=>
      int(3)
      ["parent"]=>
      int(1)
      ["status"]=>
      int(2)
      ["slug"]=>
      string(7) "dresses"
      ["title"]=>
      string(7) "Dresses"
    }
  }
  [4]=>
  array(2) {
    [0]=>
    array(5) {
      ["id"]=>
      int(5)
      ["parent"]=>
      int(4)
      ["status"]=>
      int(2)
      ["slug"]=>
      string(4) "bags"
      ["title"]=>
      string(4) "Bags"
    }
    [1]=>
    array(5) {
      ["id"]=>
      int(6)
      ["parent"]=>
      int(4)
      ["status"]=>
      int(2)
      ["slug"]=>
      string(7) "watches"
      ["title"]=>
      string(7) "Watches"
    }
  }
  [6]=>
  array(1) {
    [0]=>
    array(5) {
      ["id"]=>
      int(7)
      ["parent"]=>
      int(6)
      ["status"]=>
      int(2)
      ["slug"]=>
      string(5) "rolex"
      ["title"]=>
      string(5) "Rolex"
    }
  }
}

Now , the main parts come into the scenario. As any child can also be a parent of some children so the easiest solution is recursion. Here is the recursive part.

function traverser ($array ,$arr)  {


        if (! $arr)
            return;


    echo "<ul>" . "</br>";


    foreach ($arr as $var ) {
        echo "<li>" . "</br>";
        echo '<a href="/'.$var['slug'].'">'.$var['title'].'</a>';
        if (isset ($array [$var['id'] ]))
            traverser ($array , $array [$var['id'] ] ) ;

        echo "</li>";
    }


    echo "</ul>";

You can find the full code here.

Hope that helps . Happy coding.

MD. Sahib Bin Mahboob
  • 20,246
  • 2
  • 23
  • 45