Building a tree of links with arrays
My CMS‘s admin area has a lot of customisable features, so the navigation needs to be flexible.
Recently, the number of features grew to the point that I needed to implement a hierarchical menu structure, instead of the simple linear one that I had been using.
The script that I use (magicmenu – visible in action here) is an unobtrusive JavaScript which takes an list-tree of links, and converts it dynamically into drop-down menus.
The difficulty is in defining the tree, yet letting your validation scripts do this flexibly. Up until this point, I had drawn out the links immediately upon validating that the user had access to the link, but this is very difficult to do in a hierarchical manner
For example, consider this simple list:
Let’s say you have a user who does not have rights to edit user accounts in any way. In that case, a linear method would draw the Users
tree root, but it would not have any leaf nodes:
Ideally, the Users
root should not appear. By building the tree in an array beforehand, we can avoid that. Here is a bit of code that builds the above in an array format:
function addMenuItem(&$arr,$file,$nav){ if(ereg('>',$nav)){ $bits=explode(' > ',$nav); if(!isset($arr[$bits[0]]))$arr[$bits[0]]=array(); addMenuItem($arr[$bits[0]],$file,str_replace($bits[0].' > ','',$nav)); }else{ $arr[$nav]=$file; } } $arrayMenu=array(); addMenuItem($menuArray,'pages.php','Pages'); addMenuItem($menuArray,'user-accounts.php','Users > user accounts'); addMenuItem($menuArray,'user-groups.php','Users > user groups'); addMenuItem($menuArray,'user-admins.php','Users > admins'); addMenuItem($menuArray,'help.php','Help');
With the above, you do not need to pre-create the Users
root – just tell the function you want to create the sub-node, and it will do it for you.
To draw that out, you need one more function, and a line of code:
function drawMenu($menuArray){ $c=''; foreach($menuArray as $name=>$item){ $c.='<li>'; if(is_array($item)){ $c.='<a href="#">'.htmlspecialchars($name).'</a>'; $c.='<ul>'.drawMenu($item).'</ul>'; }else{ $c.='<a href="'.$item.'">'.htmlspecialchars($name).'</a>'; } $c.='</li>'; } return $c; } echo '<ul class="magicmenutop">'.drawMenu($menuArray).'</ul>';
This code will build a compact tree-list with just the bits that are required.