Search code examples
phphtmlarraysmultidimensional-arrayhtml-lists

Convert an array of objects into an unordered HTML list with nested list items


I have a flat array full of navigation menu items in WP. Each item knows its parent, but none of them seem to know if they have children.

            Array
(
    [0] => stdClass Object
        (
            [ID] => 22
            [menu_item_parent] => 0
        )
    [1] => stdClass Object
        (
            [ID] => 108
            [menu_item_parent] => 22
        )
    [2] => stdClass Object
        (
            [ID] => 117
            [menu_item_parent] => 108
        )
    [3] => stdClass Object
        (
            [ID] => 118
            [menu_item_parent] => 108
        )
    [4] => stdClass Object
        (
            [ID] => 106
            [menu_item_parent] => 22
        )
    [5] => stdClass Object
        (
            [ID] => 119
            [menu_item_parent] => 106
        )
    [6] => stdClass Object
        (
            [ID] => 120
            [menu_item_parent] => 106
        )
    [7] => stdClass Object
        (
            [ID] => 23
            [menu_item_parent] => 0
        )
)

I've tried approaching it with conditional logic a few different ways (and each time hard-coding values which isn't ideal), but I keep coding myself into a mess. How can I iterate over the array to produce a result like this?

<ul>
    <li>22
        <ul class="child">
            <li>108
                <ul class="grandchild">
                    <li>117</li>
                    <li>118</li>
                </ul>
            </li>
            <li>106
                <ul class="grandchild">
                    <li>119</li>
                    <li>120</li>
                </ul>
            </li>           
        </ul>
    </li>
    <li>23</li>
</ul>

Solution

  • I ended up doing it like this:

    <?php 
    $items = wp_get_nav_menu_items('primary'); // original flat array
    foreach ($items as $item) {
        $pages[$item->menu_item_parent][] = $item; // create new array
    }
    foreach ($pages[0] as $parent) {
        if (isset($pages[$parent->ID])) { // if page has children
            echo '<li>'.$parent->ID;
            echo '<ul class="children">';
            foreach ($pages[$parent->ID] as $child) {
                if (isset($pages[$child->ID])) { // child has children
                    echo '<li>'.$child->ID;
                    echo '<ul class="grandchildren">';
                    foreach ($pages[$child->ID] as $grandchild) {
                        echo '<li>'.$grandchild->ID.'</li>';
                    }
                    echo '</ul></li>';
                } else {
                    echo '<li>'.$child->ID.'</li>'; // child has no children
                }
            }
            echo '</ul></li>';
        } else { // page has no children
            echo '<li>'.$parent->ID.'</li>';
        }
    }
    ?>