php create navigation menu from multidimensional array dynamically

17,455

Solution 1

Here is my solution:

<?php

function MakeMenu($items, $level = 0) {
    $ret = "";
    $indent = str_repeat(" ", $level * 2);
    $ret .= sprintf("%s<ul>\n", $indent);
    $indent = str_repeat(" ", ++$level * 2);
    foreach ($items as $item => $subitems) {
        if (!is_numeric($item)) {
            $ret .= sprintf("%s<li><a href=''>%s</a>", $indent, $item);
        }
        if (is_array($subitems)) {
            $ret .= "\n";
            $ret .= MakeMenu($subitems, $level + 1);
            $ret .= $indent;
        } else if (strcmp($item, $subitems)){
            $ret .= sprintf("%s<li><a href=''>%s</a>", $indent, $subitems);
        }
        $ret .= sprintf("</li>\n", $indent);
    }
    $indent = str_repeat(" ", --$level * 2);
    $ret .= sprintf("%s</ul>\n", $indent);
    return($ret);
}

$menu = Array(
            'home' => Array("sub-home1", "sub-home2"),
            'about' => Array("sub-about", "about2" => Array("sub-sub-about")),
            'staff' => Array("sub-staff1", "sub-staff2"),
            'contact' => "contact"
        );

print_r($menu);

echo MakeMenu($menu);

?>

Solution 2

Calvin's solution worked for me. Here's the edited version. We can use more nested loops to get sub - sub menu items.

echo '<ul>';
foreach ($menu as $parent) {

    echo '<li><a href="#">' . $parent . '</a>';

    if (is_array($parent)) {
        echo '<ul>';
            foreach ($parent as $children) {
                echo '<li><a href="#">' . $children . '</a>';
            }
        echo '</ul>';
    }

    echo '</li&gt';
}
echo '</ul>';

Solution 3

I think you can use recursion? Here is some pseudocode, not very familiar with php.

function toNavMenu(array A){
    for each element in A{
        echo "<li><a href=\"\">" + element.name + "</a>"
        if (element is an array){
            echo "<ul>"
            toNavMenu(element)
            echo "</ul>"
        }
        echo "</li>"
    }
}

Solution 4

I would probably slightly adapt the array to be something like the following:

Array(
    0 => Array(
        'title' => 'Home',
        'children' => Array()
    ),
    1 => Array(
        'title' => 'Parent',
        'children' => Array(
            0 => Array(
                'title' => 'Sub 1',
                'children' => Array(),
            ),
            1 => Array(
                'title' => 'Sub 2',
                'children' => Array(
                    0 => Array(
                        'title' => 'Sub sub 2-1',
                        'children' => Array(),
                    ),
                ),
            ),
        )
    )
) 

With a structure like this you could use recursion to build your menu HTML:

function buildMenu($menuArray)
{
    foreach ($menuArray as $node)
    {
        echo "<li><a href='#'/>" . $node['title'] . "</a>";
        if ( ! empty($node['children'])) {
            echo "<ul>";
            buildMenu($node['children']);
            echo "</ul>";
        }
        echo "</li>";
    }
}
Share:
17,455
klye_g
Author by

klye_g

Updated on June 04, 2022

Comments

  • klye_g
    klye_g almost 2 years

    I did research on this, and wasn't able to find an exact answer. Most of the questions/answers on here pertaining to this seem to be unfinished. If anyone knows of a finished solution similar to my question, please point me in that direction!

    Here is my array:

    Array
    (
    ['home'] => Array
        (
            [0] => sub-home1
            [1] => sub-home2
        )
    
    ['about'] => Array
        (
            [0] => sub-about
            ['about2'] => Array
                (
                    [0] => sub-sub-about
                )
    
        )
    
    ['staff'] => Array
        (
            [0] => sub-staff1
            [1] => sub-staff2
        )
    
    ['contact'] => contact
    )
    

    And here is what I would like to turn it into:

    <ul>
        <li><a href="">home<a/>
            <ul>
                <li><a href="">sub-home1</a></li>
                <li><a href="">sub-home2</a></li>
            </ul>
        </li>
        <li><a href="">about<a/>
            <ul>
                <li><a href="">sub-about</a></li>
                <li><a href="">about2</a>
                    <ul>
                        <li><a href="">sub-sub-about<a/></li>
                    </ul>
                </li>
            </ul>
        </li>
        <li><a href="">staff<a/>
            <ul>
                <li><a href="">sub-staff1</a></li>
                <li><a href="">sub-staff2</a></li>
            </ul>
        </li>
        <li><a href="">contact<a/></li>
    </ul>
    

    The array will be dynamically generated, but will have a limit of 3 levels ex: about->about2->sub-sub-about. I tried going off of this question: PHP/MySQL Navigation Menu but they didn't really seem to come to a conclusion? I am familiar with foreach's whiles and for loops but I just can't seem to wrap my head around this one.

    EDIT: Enzino, your code works!

    • Matt
      Matt almost 12 years
      I think what you need here is a recursive function that parses the arrays. Sorry I can't (off the top of my head) give an example, but this is DEFINITELY one case where recursion is necessary.
    • klye_g
      klye_g almost 12 years
      Yeah I'm trying to find a good example, not many out there!
    • Matt
      Matt almost 12 years
      You want to find a DFS (depth-first search) algorithm and implement it to output the list.
  • hoppa
    hoppa almost 12 years
    I fed the array to the function below (modified it first) and it works for me now. Please do note I only did a simple test. The rest of the programming is up to you :)
  • klye_g
    klye_g almost 12 years
    Duh sorry! Had it the other way
  • klye_g
    klye_g almost 12 years
    Enzino, see edit above. Your code is not putting the sub items under their appropriate "parents"
  • Admin
    Admin almost 12 years
    I've slightly modified the code; please try again and let me know if now it works as expected.
  • klye_g
    klye_g almost 12 years
    Thank you very much sir! I was on page 5 of google trying to find a good example. But your solution works. Now I have learned something new!
  • New Alexandria
    New Alexandria over 11 years
    consider offering a recursive method
  • Fabien Sa
    Fabien Sa over 10 years
    For information, to close an anchor it's </a> and not <a/>.