This working code seems to be the typical solution to this problem.
It takes a multi-dimensional array that holds categories and their subcategories (with no implied limitation on how many levels deep it goes) and creates an HTML unordered list from it, echoing it out onto the page from inside a recursive function.
Sub-levels are traversed by passing the value for each array element's 'children' key to array_walk() recursively, from inside the original callback function named _category_list()_.
How can this method of output be modified so that all HTML code would exist in the template, outside the function?
Here's the rundown of the code:
This multi-dimensional array holds the multi-level category tree.
Important keys to use in the HTML are 'category_id', 'name', and 'children'. Other keys have been purged from the array below for simplicity sake, but if they are useful they are: 'parent_id' and 'level' (starting with level 1).
<?php
// the array containing the tree
$categories = array (
'category_id' => '2',
'name' => 'Top Category Name',
'children' => array (
0 => array (
'category_id' => '188',
'name' => 'Category Name',
'children' => array (
0 => array (
'category_id' => '159',
'name' => 'Category Name',
'children' => array (),
),
1 => array (
'category_id' => '160',
'name' => 'Category Name',
'children' => array (),
),
2 => array (
'category_id' => '166',
'name' => 'Category Name',
'children' => array (),
),
),
),
1 => array (
'category_id' => '4',
'name' => 'Category Name',
'children' => array (
0 => array (
'category_id' => '141',
'name' => 'Category Name',
'children' => array (),
),
1 => array (
'category_id' => '142',
'name' => 'Category Name',
'children' => array (),
),
),
),
),
)
?>
.
This next function produces the majority of the HTML output, but it locks the HTML inside itself.
However, instead of echoing it right from the function, I'm looking for a way to pass this data back to the view template in a manner that is friendly for designers to customize.
<?php
// separate the HTML from this function,
// passing $v to the view template for handling
function category_list($v, $k){
switch ($k) {
case 'category_id':
echo "<li id="$v">";
break;
case 'name':
echo "$v";
break;
case 'children':
if(count($v) > 0){
echo "<ul>";
foreach($v as $k=>$v)
array_walk($v, 'category_list');
echo "</ul>";
}
echo "</li>";
break;
}
}
?>
.
The next block of code is the current template html/php with the call to traverse the first level of the array via array_walk() and referencing the recursive function above. The function itself then handles the recursion and iteration of deeper categories with 1 or more child. Of course, this is the typical approach.
This code should have all HTML tags, rather than just the outer tags.
<ul>
<?php array_walk($tree,'category_list'); ?>
</ul>
.
The Ideal Solution:
The end goal here is to find a way for template designers to create their ideal navigation structure without having to create or modify the recursion function (which isn't accessible), nor require use of a foreach loop for each level of the multi-dimensional array. The solution should not be tied to any specific depth limitations.
Examples of HTML customizations could range from placing additional attributes inside the ul/li tags, or even wrapping new tags around the output text, such as span tags, which are commonly used in navigations to achieve a sliding-doors effect with CSS. So I think the appropriate solution will need to support those case scenarios at a minimum.
Iterating through the array from the template using array_walk() would still be okay, as long as it can be used in such a way that the callback function passes the desired vars back to the template for use with the designer's HTML.
Ideally, if array_walk_recursive() knew how many levels deep its iterator actually is, I think this feat would be much easier to solve. But unless someone knows a workaround to that issue, the solution may be different entirely.
I also want to avoid using javascript methods of building the tree. And if there's a way to avoid using the switch, I'm open to suggestions there too.