phpwordpresswp-nav-walkerwp-nav-menu-item

Current level navigation in Wordpress


I have a 3 level navigation:

Home
   > submenu1
       >> sub3       
   > submenu
       >> sub4       
       >> sub5       // current page
About
   > about2
       >> sub6       
   > about3
       >> sub7       

I am trying to get each navigation level separately,

With the example nav above, being on the sub5 page, I would need

Current 1st level nav: Home

Current parallel 2nd level nav: submenu1, submenu (who are both under Home)

Current parallel 3rd level nav: sub4, sub5 (who are menu under submenu)

I will need to modify the elements and styles of the menu and will need to work with menu items in php, such as:

$menu_name = 'topnav';
if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) ) {
$menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);

foreach ( (array) $menu_items as $key => $menu_item ) {
    $title = $menu_item->title;
    $url = $menu_item->url;
    [...]

Please help getting the navigation layers separately to show up as explained above.

I got the 1st and 3rd level working, but can't get the current parallel 2nd level nav to show up correctly.

Thanks.

Current Code: 2nd nav works:

<?php
$menu_name = 'topnav';
if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) ) {

    $menu = wp_get_nav_menu_object( $locations[ $menu_name ] );

    $menu_items = wp_get_nav_menu_items( $menu->term_id );

    // Convert Objects to Arrays, Enables us to use Array Filter
    $json  = json_encode($menu_items);
    $menu_items = json_decode($json, true);

    // Current Page
    $child = get_the_id();


    $current_level = array_filter( $menu_items, function($v, $k) use ($child) {
    return $v['object_id'] == $child;
    }, ARRAY_FILTER_USE_BOTH );

    $current_level_keys = array_keys($current_level);
    $parent = $current_level[$current_level_keys[0]]['menu_item_parent'];

    if( !empty( $parent ) )
    {
    $current_level_items = array_filter( $menu_items, function($v, $k) use ($parent)  {
        return $v['menu_item_parent'] == $parent;
    }, ARRAY_FILTER_USE_BOTH );
    } else {
    $current_level_items = $current_level[$current_level_keys[0]];
    }

    //echo '1:';
    //echo '<pre>';
    //print_r($current_level_items);
    //echo '</pre>';

    //foreach ($current_level_items as $k => $v) {
    //  echo '<li><a href="#">'.$v['title'].'</a></li>';
    //}

    $parent_level = array_filter( $menu_items, function($v, $k) use ($parent) {
    return $v['ID'] == $parent;
    }, ARRAY_FILTER_USE_BOTH );

    $parent_level_keys = array_keys($parent_level);
    $grand_parent = $parent_level[$parent_level_keys[0]]['menu_item_parent'];

    if( !empty( $grand_parent ) )
    {
    $parent_level_items = array_filter( $menu_items, function($v, $k) use ($grand_parent)  {
        return $v['menu_item_parent'] == $grand_parent;
    }, ARRAY_FILTER_USE_BOTH );
    } else {
    $parent_level_items = $parent_level[$parent_level_keys[0]];
    }

    //echo '2:';
    //echo '<pre>';
    //print_r($parent_level_items);
    //echo '</pre>';
    //foreach ($parent_level_items as $k => $v) {
    //echo '<li><a href="#">'.$v['title'].'</a></li>';
    //}

    $grand_parent_level = array_filter( $menu_items, function($v, $k) use ($grand_parent) {
    return $v['ID'] == $grand_parent;
    }, ARRAY_FILTER_USE_BOTH );

    $grand_parent_level_keys = array_keys($grand_parent_level);
    $great_grand_parent = $grand_parent_level[$grand_parent_level_keys[0]];

    if( !empty( $parent ) ) {
        if( !empty( $great_grand_parent ) ) {
        echo '<li class="custom-page-title">'.$great_grand_parent['title'].'</li>';
        if (is_array($parent_level_items)) {
            foreach ($parent_level_items as $k => $v) {
                echo '<li><a href="'.$v['url'].'">'.$v['title'].'</a></li>';
            }
        }
        } else {
        echo '<li class="custom-page-title">'.$parent_level_items['title'].'</li>';
        if (is_array($current_level_items)) {
            foreach ($current_level_items as $k => $v) {
                echo '<li><a href="'.$v['url'].'">'.$v['title'].'</a></li>';
            }
        }
        }
    }
    //echo '3:';
    //echo '<pre>';
    //print_r($great_grand_parent);
    //echo '</pre>';

}
?>

However if there are duplicate (3rd level) pages in the menu, this script only takes the first parent... Could it be the last or the real parent (from url path maybe?)

Duplicate page in menu issue:

Home
   > submenu1
       >> sub3
   > submenu
       >> sub4       
       >> sub5       // current page
About
   > about2
       >> sub6       
   > about3
       >> sub7
       >> sub5       // duplicate page

When visiting the duplicate page (sub5), the parent returned is the first one (Home > submenu), when it should be (About > about3)

Please help getting this fixed...


Solution

  • Edit:

    To address the duplicate situation you have to add a line of code. You can add one of the below lines based on the parent chain you want to select. I am also adding these lines in the actual code to show you where they go.

    // Get First Parent Chain
    $current_level = array_values(array_slice($current_level, 0, 1));
    
    // Get Last Parent Chain
    $current_level = array_values(array_slice($current_level, -1, 1));
    

    Original Answer: ( Also updated with the above lines )

    This code will give you all levels items, it is written for only three levels as per your requirements but you can use the logic and reiterate the code to as many levels as needed, or better yet write up something recursive.

    $menu_name = 'topnav';
    if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) ) {
    
        $menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
    
        $menu_items = wp_get_nav_menu_items( $menu->term_id );
    
        // Convert Objects to Arrays, Enables us to use Array Filter
        $json  = json_encode($menu_items);
        $menu_items = json_decode($json, true);
    
        // Current Page
        $child = get_the_id();
    
    
        $current_level = array_filter( $menu_items, function($v, $k) use ($child) {
            return $v['object_id'] == $child;
        }, ARRAY_FILTER_USE_BOTH );
    
        // Get First Parent Chain ( Uncomment below line if you want to use this )
        //$current_level = array_values(array_slice($current_level, 0, 1));
    
        // Get Last Parent Chain ( Uncomment below line if you want to use this )
        //$current_level = array_values(array_slice($current_level, -1, 1));
    
    
        $current_level_keys = array_keys($current_level);
        $parent = $current_level[$current_level_keys[0]]['menu_item_parent'];
    
        if( !empty( $parent ) )
        {
            $current_level_items = array_filter( $menu_items, function($v, $k) use ($parent)  {
                return $v['menu_item_parent'] == $parent;
            }, ARRAY_FILTER_USE_BOTH );
        } else {
            $current_level_items = $current_level[$current_level_keys[0]];
        }
    
        echo '<pre>';
        print_r($current_level_items);
        echo '</pre>';
    
        $parent_level = array_filter( $menu_items, function($v, $k) use ($parent) {
            return $v['ID'] == $parent;
        }, ARRAY_FILTER_USE_BOTH );
    
        $parent_level_keys = array_keys($parent_level);
        $grand_parent = $parent_level[$parent_level_keys[0]]['menu_item_parent'];
    
        if( !empty( $grand_parent ) )
        {
            $parent_level_items = array_filter( $menu_items, function($v, $k) use ($grand_parent)  {
                return $v['menu_item_parent'] == $grand_parent;
            }, ARRAY_FILTER_USE_BOTH );
        } else {
            $parent_level_items = $parent_level[$parent_level_keys[0]];
        }
    
        echo '<pre>';
        print_r($parent_level_items);
        echo '</pre>';
    
        $grand_parent_level = array_filter( $menu_items, function($v, $k) use ($grand_parent) {
            return $v['ID'] == $grand_parent;
        }, ARRAY_FILTER_USE_BOTH );
    
        $grand_parent_level_keys = array_keys($grand_parent_level);
        $great_grand_parent = $grand_parent_level[$grand_parent_level_keys[0]];
    
        echo '<pre>';
        print_r($great_grand_parent);
        echo '</pre>';
    
    }
    

    I have tried to write it as self explanatory, but if you have any questions i will be happy to help.