2
votes

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...

1
Can you please share your code you used for getting 1st and 3rd level ?shazyriver
Can you please explain visually the case you are talking about ? Just like you did at the start of your post.shazyriver
Just added a visual as per requested.Luc Laverdure
It won't work like this. You should not have duplicates, if you really need the duplicates then you will have to pick one parent chain either the first or the last.shazyriver
The best way to handle this is to not have duplicates at all. Because duplicates can't be allowed for what you are trying to do. Think for a second, both chains are valid for one item. How to pick one, and there should not be multiple paths styled. System does not know which path you are traversing, unless we look into referrers which becomes a long story.shazyriver

1 Answers

2
votes

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.