Well. It’s been a long time since I’ve written a post. I was busy learning Laravel… Currently, I am trying the framework by working on a CMS, and, again, I have arrived at the phase of menus. And by “menus”, I am refering to multi-level menus. In the past I have found ways to bypass this dilemma, but now my time allowed me to dive into it.
You will find a lot of answers about how to do it, best of which can be found on stackoverflow (http://stackoverflow.com/questions/2871861/how-to-build-unlimited-level-of-menu-through-php-and-mysql), but they seemed way too complicated (at least, for me), or they were killing the database by querying the table for each item (http://www.100scripts.com/article/35/PHP-Multi-Level-Menu.html).
So, how do you retrieve a multi-level menu from the database using PHP? I will not teach you how to connect to a database nor how to select from it, this not being the subject of this post.
I will assume that you will have a table that has at least the following columns: id, name, url, parent_id.
When you retrieve the menu items from the database, let’s presume the array will have the following structure:
$menu_items = array(
array(‘id’=>…, ‘parent_id’=>…, ‘name’=>…, ‘url’=>…),
array(‘id’=>…, ‘parent_id’=>…, ‘name’=>…, ‘url’=>…),
………..
);
Hope you get the idea…
In order to work with the array we will use a recursive function (a function that calls on itself) on the array and return the result.
Now, how do we build the multilevel menu?
I have it in two flavours:
1. A multi-dimensional array (if you’re working with a framework it would be nice to send the menu to the view as an array…)
function ordered_menu($array,$parent_id = 0) { $temp_array = array(); foreach($array as $element) { if($element['parent_id']==$parent_id) { $element['subs'] = ordered_menu($array,$element['id']); $temp_array[] = $element; } } return $temp_array; }
2. An <ul> list with sub-lists
function html_ordered_menu($array,$parent_id = 0) { $menu_html = '<ul>'; foreach($array as $element) { if($element['parent_id']==$parent_id) { $menu_html .= '<li><a href="'.$element['url'].'">'.$element['name'].'</a>'; $menu_html .= ordered_menu($array,$element['id']); $menu_html .= '</li>'; } } $menu_html .= '</ul>'; return $menu_html; }
As you can see, the function will receive an array and a parent id. Assuming you’ve set value 0 to the menu items that are on the first level, you can call the function with:
$array_menu_items = ordered_menu($menu_items,0); // for retrieving an array
$html_menu_items = html_ordered_menu($menu_items,0); // for retrieving a multi-list
From here on, the function should do its job, and return a nice ordered menu. Hope you liked it.
Great code, thank you. It’s very useful
Thank you.
Nice code! but html_ordered_menu throws Array to string conversion at line 9
Could you send me your code at avenir.ro@gmail.com?
that’s because on line 9 you call the previous function.
i thought you wanna call the function itself
so the code must be html_ordered_menu()
nice post. works well for me when i left the parameter blank.
but when i pass ‘where’ parameter on my function it give me nothing.
can you help me?
here is my code
https://gist.github.com/PetengDedet/912f09e5faa14cc97cdc#file-multilevel-menu-codeigniter
First of all… If you put it inside MY_Model, you need to pass the get_menu() function properties and not variables. Also, why do you have NULL as value for root elements? Why not 0? More on this, you can find in my comments on your gist.
Thank you for your attention.
it’s my mistake to give you wrong question.
i fix up my question on my Gist comment.
hope it will be clear one.
Great code!
Btw how to make an active menu when user visiting for certain pages?
Well… you can either use the CSS pseudo-element :active (…a:active {color: red;}…) or you can look inside the url of the link to see if the current page is the same as the link.
Very good tutorial, and for me so far, best tutorial about multi-leve menu topic. Thank you so much… Good Work
Thank you
Hi avenirer
Can you make Tut with your My_Model for Codeigniter?
Thanks