How to get submenu items from a WordPress menu based on parent or sibling

The menu builder in WordPress is great, however quite often I find myself needing to create a secondary menu on pages, containing just a subset of the menu. In my case the rules are simple: when viewing a top level page we want to list all child pages nested beneath it. When viewing a second level page, we want to list all sibling pages nested under the same parent. We could just use wp_list_pages and filter by a parent, but it won’t match the structure designed in the menu builder, which defeats the purpose of using it.

Surprisingly there’s little information or working solutions to this problem, so I’ve put together the following code which does exactly what we want. You can view a demo of the code (and all combinations of options) on the demo page here: http://wp-sub-menu-demo.christianvarga.com/.

Update

I originally wrote a function that generated the menu manually, however Thomas Dexter kindly pointed out a method that uses wp_nav_menu, which adds the correct wp classes and allows us to use custom walkers and the like. Using his code and the hook provided by mac joost on Stack Overflow, I modified it to work based purely on the menu structure (irrelevant of page structure). So all you need to do is drop this in your functions.php file.

Then you can display it in your theme using wp_nav_menu (just like you normally would), but also passing in a sub_menu flag to activate the custom sub_menu function:

If you’re just using the default location as above, you’ll need to ensure that your custom menu is set as the primary navigation menu. You can do this in the Appearance > Menus section, under the Manage Locations tab. Otherwise, if you’ve registered a custom menu location, ensure that the menu is set properly in the Menus section, and point the theme_location parameter in your call to the name of the custom location.

Also, using the hook like this allows you to easily control the display of nested children using the depth parameter (as opposed to my original function which only listed direct descendants and required convoluted code to fix).

By default, if you have many nested levels, this code will filter the menu by the absolute top level parent. If you want the menu to drill down dynamically by filtering the menu based on the direct parent, pass a “direct_parent” => true flag to the wp_nav_menu call.

If you want to include the parent/root element in the menu, you can pass in a “show_parent” => true flag to display the root level item as well.

Enjoy.

If this post has helped you out, feel free to consider throwing a small donation my way.

  • vicky

    superb tutorial …………

  • kiki

    This is exactly what I’m looking for however…. What if there is a sub-submenu? This code doesn’t display it. Ideas?

    • levymetal

      Annoyingly WordPress doesn’t provide a nested array of objects from the wp_get_nav_menu_items function, unless there’s a newer function I’m not aware of (and that’s possible). Anyway, using my code, you need to add another loop inside the loop that prints the list, which loops through every item, checks if it’s parent is the current sub-item, and if so displays it. I wrote a gist here: https://gist.github.com/levymetal/5375456. However, when viewing a sub-sub page (or should we say 3rd level page), it won’t display the second level menu any more. This can be fixed, but I’m not sure how you wanted it to work. If it’s not quite right, give it a crack and see if you can update it to work better for your situation. And if you have any troubles feel free to write back here :)

  • Dave Loodts

    Super super super !

  • Marcel

    Just saved my day! Works great, also the sub-submenu part works just like I need it. Can’t believe this functionality isn’t build in…

  • Thomas Dexter

    Hi Christian – I’ve found a much more elegant solution which still uses the wp_nav_menu so you can use custom walkers and other benefits of nav menu.. It’s work awesome for my subpages to list only their children and grandchildren etc… in their secondary menus. Check it out: http://stackoverflow.com/a/7713875/786094

    Using that filter, I’ve also added to my header.php:

    if ($post->post_parent) {
    $ancestors=get_post_ancestors($post->ID);
    $root=count($ancestors)-1;
    $topparent = $ancestors[$root];
    } else {
    $topparent = $post->ID;
    }

    And then call the menu like so:

    wp_nav_menu( array(
    ‘theme_location’ => ‘primary’,
    ‘menu_class’ => ‘nav’,
    ‘depth’ => 3,
    ‘fallback_cb’ => false,
    ‘walker’ => new The_Bootstrap_Nav_Walker,
    ‘start_in’ => $topparent
    ) );

    • http://christianvarga.com/ Christian Varga

      Thanks for the comment, that’s a pretty nice solution and it works much when the menu has more than 2 levels. However, putting that initialiser code into the header is hardly elegant; you’d be much better off creating a custom function to get your $topparent value, or just putting that code straight into your custom walker (and pass it a flag instead of a start_in value).

    • http://christianvarga.com/ Christian Varga

      Thomas, I took a good look into your code and I liked the concept of using wp_nav_menu a lot more than my original code that was building the menu manually. However, I noticed that your code relies on the page structure to match the menu structure, which isn’t always desirable (using post ancestors etc). Also, if you drill-down into nested pages, your code list all items under the top level parent, instead of the direct parent. This may or may not be desired behaviour, but in my case I wanted the menu constantly filtered as you drill-down into nested pages.

      So having said that, I’ve updated my post with a new function that combines your concept, the code from Stack Overflow, and my method of filtering by the menu structure instead of the page structure. I find this to be a much better way of building the custom menu.

      Thanks for the code!

  • http://twitter.com/NickMcElligott Nick McElligott

    This is great stuff! Thanks a bunch!

  • Eric

    God Bless You!!!!

  • Scott Lee

    Dude, thanks for the excellent snippet!
    One question though; if the current page doesn’t have any sub-menu items it displays an empty . Is there anyway to test if the current page have any sub-menu items? And if not, do something else.

    • http://christianvarga.com/ Christian Varga

      Which method are you using? I’ve edited my original function with a line that you can uncomment to stop the output of the ul (I also changed the initialisation of the current_menu_id to null instead of 0). If you’re using the nav_menu hook method, there doesn’t appear to be a flag to suppress the menu wrapper if it’s empty, but I found a comment here which helped me write this: https://gist.github.com/levymetal/5547605#file-page2-php. It’s slightly ugly but will get the job done. You might want to move the code into functions.php so you can call it anywhere.

      • Scott Lee

        Dude…freaking brilliant. Thank you so much!

  • omniscient

    Great tutorial,
    Though when in drop the updated code in my functions and the hook in my header.php file, my menu disappears. Would be open to input from anyone.

    • http://christianvarga.com/ Christian Varga

      How is the menu created in the menu builder? Is it the primary menu, or have you created a secondary menu? What theme are you using, and what’s your version of WordPress?

  • omniscient

    wordpress 3.5.1 The theme (which is circles by theme smack) is using the wp_nav_menu and only supports one menu. The reason im editing is when i introduce a second level to the menu, the menu option is not styled and stays on the 1st level and flickers in chrome. you can see it here: http://hopskip.us/fairhopesmiles/.
    Thanks for responding!

    • http://christianvarga.com/ Christian Varga

      I think you may have misunderstood the purpose of my plugin; it’s only use is to display a secondary menu on a page, containing all children under that page. It is not designed as any kind of replacement for the main navigation.

      Your flickering issue has nothing to do with the menu, and all to do with the CSS. The menu is positioned absolutely, and the content is overlapping the menu, and has a higher z-index. Either remove the rev_slider_home_slider shortcode that isn’t working to push the menu back up to it’s correct position and stop the overlap, position the menu relatively, or add the following CSS to ensure the menu always has a higher z-index than the content: .menu-primary-container { z-index: 999 }

      • omniscient

        will do… thanks guy

      • omniscient

        do you have any suggested reading on adding a 2nd level menu option to wp_nav_menu on a theme that does not support it?

        • http://christianvarga.com/ Christian Varga

          Are you familiar with using CSS? I haven’t seen any articles on your specific problem, but you just need to edit the CSS, find the styles that correspond to the second level items, and apply the same styles to the third level items, which should be pretty straight forward. I’d recommend heading over to Stack Overflow if you have any problems with that. Either way, you should not need to use my code at all – it’s just a CSS problem.

          • omniscient

            I am familiar with CSS, and that does help. Thanks for your time.

  • dills

    This code is GREAT … but I have one issue.

    If my navigation is like this:

    About Us
    – About Us Subnav 1
    –About Us Tertiary 1
    –About Us Tertiary 2
    –About Us Tertiary 3
    -About Us Subnav 2
    -About Us Subnav 3

    If I am on any of the tertiary pages, I get no context. I can only see the Tertiary pages, but I need to also be able to see the parent page and its siblings (so also see Subnav 1, Subnav 2, Subnav 3).

    Thanks!

    • http://christianvarga.com/ Christian Varga

      Yeah that makes sense, I designed it to be able to drill down when sub-menu items are being viewed. What have you tried so far? You’ll probably want to backtrack the root_id to a higher level parent (rather than just the direct parent); there’s a comment below by Thomas Dexter describing one such method, although it relies on the page structure (not the menu structure) which could potentially cause problems.

      • Lightb

        Such a great filter for wp_nav_menu. However, i need it to work as dills have stated.

        Where should i backtrack the root_id and how? Would really appreciate your help!

        • http://christianvarga.com/ Christian Varga

          Have you tried experimenting with the code provided by Thomas Dexter? There’s a link to it in my previous comment, or you can just scroll down to take a look. It’s not perfect because it uses the page’s ancestors (not the menu item ancestors), but for 99% of cases this should be fine. but I haven’t looked into the feasibility of using the menu builder to do this, and unfortunately I’m absolutely swamped and I just don’t have any time to look into developing a solution for it right now.

          • Lightb

            Ok! It was the code from Thomas Dexter that i use. I really need it to work with menu item ancestors. I think i’m going to use a walker to get the desired effect instead. Thank you anyway!

          • http://christianvarga.com/ Christian Varga

            My code has been updated to address this issue, check my gist for the latest version here: https://gist.github.com/levymetal/5547605#file-functions-php

  • ftejada

    Thank you Christian Varga by the solution , I solved this issue using jquery because I had the same problem like dlls. I hope to help someone else.

    var xdump = $(‘.current-menu-ancestor’).html();

    $(‘#tofill’).html(xdump );

    • http://christianvarga.com/ Christian Varga

      Looks like this is a common problem. Personally, I believe it’s more semantic to generate the menu properly in the first place, but for all intents and purposes your code will work for the end user. Don’t forget to wrap it in the jQuery ready function. I might look into modifying my function so it can work either way.

  • rich

    Howdy,

    I have a menu like the following:

    Desitinations
    – south africa
    – south africa overview
    – itinerary options
    – another page
    – another page
    -nambia
    – nambia overview
    – itinerary options
    – another page
    – another page
    – kenya
    – kenya overview
    – itinerary options
    – another page
    – another page

    The overview page in each section is actually just the top level repeated. e.g. if you click south africa you are taken to the overview page. All countries are listed down the side of the page, then in a sub menu appearing in another part of the page I woudl like to display the children (overview,itinerary options, other pages)

    Using the code above appears perfectly on the itinerary options page, however it doesn’t work on the country landing page. Essentially I want to ensure on the parent page the children pages are shown including the overview link, and on the children pages the siblings are shown with the overview link.

    Hopefully that made sense!
    Any insight would be greatly appreciated,
    thanks in advance,
    Rich

    • http://christianvarga.com/ Christian Varga

      Rich, the problem is that your top level country pages are nested under Destinations, so as far as WordPress is concerned Nambia or Kenya aren’t root menu elements. And that’s what my function filters parent/child pages by. I could add a flag to function to solve your problem, but it’s just going to cause feature bloat.

      But thanks to WordPress’ menu builder, it isn’t too hard to find a work-around to your problem. You could build another separate menu just for the countries using the countries as root level elements. For example: http://i.imgur.com/eMLG4hF.png. Then, assuming you’re using the nav_menu hook version of my code (the second snippet in my post), you can generate a submenu using the new menu you created in the menu builder.

      wp_nav_menu( array(
      ‘menu’ => ‘destinations’,
      ‘sub_menu’ => true
      ) );

      I tried it out and it worked for me, but let me know if you have any issues.

      • rich

        Thank you for your reply, Christian.

        I see the problem! I have tried to find a work around and am very close! I have tried your suggestion too so I have that as a back up just in case I can’t get the other way going.

        Thanks again, mate.

        Rich

  • Pingback: Can someone please help me modify this sub-menu filter to always start from the 'ultimate' or 'top' parent? | Question and Answer

  • Martin

    Hi Christian,

    i´ve got one question. Is it easy to modify the code to get something similar to this?

    menu item 1
    — submenu 1
    — submenu 2
    — submenu 3
    menu item 2
    menu item 3

    Would be great if you could help me out.

    • http://christianvarga.com/ Christian Varga

      If you aren’t filtering the menu by a parent, you should just be able to use wp_nav_menu normally without any additional hooks at all.

      If that doesn’t work, perhaps you can elaborate on the problem and what you’ve tried to far / explain what you need in a little more detail.

      • Martin

        Sorry for my bad explanation. Everything works fine at the moment. But the Problem is that i use it like

        true, ‘menu_class’ => ‘nav sub_menu’, ‘container’ => false)); ?>

        and so i get

        menu item 1
        menu item 2
        menu item 3

        submenu 1 (dependent on menu item1)
        submenu 2 (dependent on menu item1)
        submenu 3 (dependent on menu item1)

        and not the first layout.

        • http://christianvarga.com/ Christian Varga

          Did you try the suggestion in my previous reply? What happens if you don’t pass the sub_menu argument to your call to wp_nav_menu?

          I’m still not clear on the problem. Instead of trying to describe it, it’s much easier if you’re able to demonstrate the problem. Can you set up a demo that demonstrates the problem?

  • http://www.markdejong.com Mark de Jong

    Thanks a lot for this great solution. I’d like to have a third level navigation based on the children of the 1st level menu items. Is that possible? You mentioned looping with the loop, but 2nd level items then not displaying anymore. Any way to have them shown still?
    I’m thinking of creating a separate widget to display the 3rd level menu items in the sidebar when on a 2nd level menu item.

    • http://christianvarga.com/ Christian Varga

      Have you tried using the “direct_parent” => true flag in your call to wp_nav_menu? I’ve got a little description about it at the bottom of the post. If you use this flag the menu will be filtered by the parent one level above the current level. You might want to have 2 menus like you suggested, a sub menu that doesn’t use the direct_parent flag, and a sub-sub menu that does use it.

      If that doesn’t work, can you make a dummy menu with some dummy output so I can understand exactly what you’re trying to do?

      • http://www.markdejong.com Mark de Jong

        Thanks for the tip. I will try it as soon as I get back to the code. Will let you know if it doesn’t work. Hopefully it does, though.

      • http://www.markdejong.com Mark de Jong

        Hi Christian,

        I’ve tried your solution and applied the “direct_parent” => true flag to the call of my second level menu, and created a widget with a third level menu. Though on the third level menu there’s no luck in showing the third level. It’s only showing the second level menu tree including the third level inside.

        I basically want to create something like this: http://d.pr/i/QX7F
        Instead it’s showing up like this: http://d.pr/i/x78I

        I’ve basically taken your code completely identical with my secondary and third level menu functions looking like this:

        function erc_secondary_nav() {
        wp_nav_menu(array(
        ‘theme_location’ => ‘header-menu’,
        ‘container_class’ => ‘secondary_menu clearfix row’,
        ‘menu_class’ => ‘clearfix’,
        ‘fallback_cb’ => ”,
        ‘container’ => ‘div’,
        ‘link_before’ => ”,
        ‘link_after’ => ”,
        ‘items_wrap’ => ‘%3$s’,
        ‘sub_menu’ => true,
        ‘depth’ => 1,
        ‘direct_parent’ => true
        ));
        }

        function erc_thirdlevel_nav() {
        wp_nav_menu(array(
        ‘theme_location’ => ‘header-menu’,
        ‘container_class’ => ‘thirdlevel_menu clearfix row’,
        ‘menu_class’ => ‘clearfix’,
        ‘fallback_cb’ => ”,
        ‘container’ => ‘div’,
        ‘link_before’ => ”,
        ‘link_after’ => ”,
        ‘items_wrap’ => ‘%3$s’,
        ‘sub_menu’ => true
        ));
        }

        • http://christianvarga.com/ Christian Varga

          Yeah I can see what you mean now, and my function is specifically designed to display a sub menu based on the current level in view, not a submenu based on the next level down. For your sidebar menu, you’ll need to modify my function to exclude the current level from the tree, so it only shows the third level.

          I can see a solution, but i prefer helping people figure it out rather than just posting a working answer. The offending code is on line 15 of my function. You’ll either need to create a new function to display your submenu, or pass it a new flag, because changes you make to this line will affect your second level nav menu.

          Give it a shot and see how you go.

          • http://www.markdejong.com Mark de Jong

            I had to abandon this plan since the client went for a different approach. I will try getting this running, though. Since it might still prove useful for future purpose.

  • MK

    Perfect solution

  • MK

    Hi Christian, Thank you for sharing this very useful solution. It works great for tertiary level navigation.

    Please could you help me with a small issue.

    I constructed my tertiary level menu using WordPress Menu under Appearance.

    I display my top level navigation on the top of the page on the header. And I display my secondary and tertiary level menu on my left sidebar which changes based on the top menu selected.

    However, the sidebar menu disappears everytime I click a “single post” page from a taxonomy listing page. I need to retain my left sidebar menu even when I’m on a “Single post” page.

    Please could you help me solve this issue.

    Any help would be much appreciated.

    Thank you very much.

    • Oskar Schmid

      Maybe something like that works …

      // find the current menu item
      foreach ( $sorted_menu_items as $menu_item ) {
      if ( $menu_item->current ) {
      // set the root id based on whether the current menu item has a parent or not
      $root_id = ( $menu_item->menu_item_parent ) ? $menu_item->menu_item_parent : $menu_item->ID;
      break;
      } elseif ( $menu_item->current_item_parent ) {
      $root_id = $menu_item->ID;
      break;
      } elseif ( $menu_item->current_item_ancestor ) {
      $root_id = $menu_item->ID;
      break;
      }
      }

      • imanerd

        I’m having the same problem with the single news pages (single.php). I can’t seem to get it to display the same menu that is on the main news page. Otherwise this is great!

        • imanerd

          Never mind…I got it working. This is what I added:

          elseif ( is_single() ) {
          $root_id = 125;
          break;
          }

  • Tim

    Love your work! I was in the middle of fudging around with wp_list_pages when I realised I needed to get sub menu items from the structure of wp_nav_menu and voila! I found this post :)

  • julian

    works like a dream !!!! thank you… you saved my life..

  • halox80 .

    THANK YOU SO MUCH CHRISTIAN!!! I’m so following your website now >:)

  • murph

    Dude, you are the King of the World! Thanks heaps

  • Mithun

    how to display only sub menu

    • http://christianvarga.com/ Christian Varga

      Could you elaborate on your problem and desired solution?

  • Tristan

    Hi Christian,

    Thanks for sharing this man.

    I’ve inserted the code into my functions.php, called wp_nav_menu exactly as shown with ‘sub_menu’ => true, however it’s still creating a standard nav menu with all level one and all level two pages listed, regardless of which page I’m on.

    I have registered two other menus (for header and footer) that I’m using. This sub-page menu will go in the sidebar. Do I need to register a new menu for this, or should it work by default?

    Cheers

    • http://christianvarga.com/ Christian Varga

      Tristan, it should work by default without you having to create another menu. Have you got your site set up on a staging server where I could have a look to see what’s going on?

      • Tristan

        Sorry just on a localhost setup. This is the nav tree I’m getting, regardless of the page, or whether I use ‘sub_menu’ => true:

        Home
        Clients
        – Services
        – Client Showcase
        – Resources
        Candidates
        – Services
        – Candidate Showcase
        – Resources
        About Us
        – Our History
        – Our Expertise
        – Our Team
        – Contact Us

        Does the page ‘order’ set in the WP page options make any difference?

        I’ve tried removing all other functions (including other menu registrations and calls) and still no luck.

        The code has been copied and pasted exactly as above.

        Currently running WP 3.6.1

        Thanks for any suggestions!

        • http://christianvarga.com/ Christian Varga

          I’ve had a play around with this and I think I might have found the issue. You need to ensure that your custom menu is set as the primary navigation menu. If you log into WP admin, and go to Appearance > Menus, click on the Manage Locations tab, the Navigation Menu should be set to the custom menu you created (and not left blank). Give this a go and see if it works.

          • Tristan

            Thanks heaps for your time and the extra info man – much appreciated. To clarify my setup, I have two menu areas registered, and I have one custom menu in WP admin that I’ve applied to both of these – called “Top Level Menu”. I’m using this just to display parent pages in the header and footer. Under manage locations I have both locations set to “Top Level Menu”.

            I then have the submenu in the sidebar. I’ve just tried setting ‘fallback_cb’ => false to see if the sub_menu option is working (but incorrectly) or if it’s not working and falling back to the default menu – now no menu shows.

            By the way, do I need to include the sub pages in my custom menu “Top Level Menu” for this to work, or should it just work by default based on page structure?

            Thanks

          • Tristan

            OK, apologies man I misunderstood the process. I’ve got it working now. I registered a new menu location for the sidebar, and created a new menu with all pages in WP admin and set it to this sidebar location, where the wp_nav_menu with ‘sub_menu’=> true is called. All working nicely!

            I got off track because I thought the code would alter the default wp_page_menu structure to only display sub-pages, rather than displaying sub-pages from a custom menu.

            Thanks again for all your help!

          • http://christianvarga.com/ Christian Varga

            Yeah it actually pulls the pages from the menu, one of my older functions pulled it from the page structure itself, but this caused issues with custom ordering and the like (aka, it would default to alphabetical ordering) so I rebuilt it to work purely off the structure designed in the menu builder. So yeah, you do need to have a menu with all the pages in it (and nested properly) to work. I was just assuming you had built one menu for to use for everything, which was a bad assumption to make!

            Glad you got it working in the end!

  • James

    Hi Christian,

    First off, what a great solution! I got rid of my old clunky walker menu setup.

    My question is, is there any way to have a page show in multiple sub menus? My setup is like this:

    Parent Item 1
    – Sub Item A
    – Sub Item B
    – Sub Item C
    Parent Item 2
    – Sub Item A
    – Sub Item D
    – Sub Item E

    So, with your solution currently, if I click on Sub Item A under Parent Item 1, it shows me the proper sub menu for Parent Item 1. However if I click on Sub Item A under Parent Item 2, it still shows me the sub menu for Parent Item 1. Is there a way to get around this or do I just need to have two different pages?

    If you have any questions, please let me know.

    Thanks so much,

    James

    • http://christianvarga.com/ Christian Varga

      Very interesting find! I’m going to assume that it has something to do with the call to `$menu_item->menu_item_parent`. If the same page is assigned under 2 different menu items, WP probably just picks the first menu item as the parent. I’ll have to check the core to confirm. Perhaps a workaround could be to create a custom menu item (using Links instead of Pages), and link to the page manually for ‘Sub Item A’ under ‘Parent Item 2′. That way you wouldn’t have to create a duplicate page.

      • James

        Thanks for the reply Christian, I was thinking creating a Custom Menu Item would be a good way to get the menus to display properly, which it does. However, as soon as a user clicks on the custom link in Parent Item 2 (e.g. /parent-item-1/sub-item-a/) they are brought to that page and are shown the Parent Item 1 menu (which makes total sense). This however presents a bit of a usability issue in my case, since I’m essentially trying to create a common page which appears in multiple menus, as it is relevant, but I’m hoping not to have to create multiple pages as that’d be a hassle to update (basically it’s like a Schedule page that has a bunch of content).

        As your menu functions currently makes complete sense (and is correct in doing so), I think essentially what I need to find/create is something that says “if on Parent Item 2 and you click Sub Item A, then display the Parent Item 2 menu”.

      • James

        So I found something interesting, when you try to make a custom link from, for example, Sub Item A under Parent Item 1 to Sub Menu A under Parent Item 2 (which is where the actual page link is) your function still displays the menu for Parent Item 1. It’s not until I specify a different URL other than Sub Item A (e.g. I just tested with ‘#’) that the menu for Parent item 2 is displayed when on the Sub Item A page.

      • James

        New breakthrough: while specifying the same URL in my custom link URL gave me issues with displaying the menu, if you change it ever so slightly, it will work.

        So, this is how my WordPress menu was displayed before:

        Parent Item 1
        – Sub Menu A custom url= /parent-item-2/sub-menu-a/

        Parent Item 2
        – Sub Menu A page= /parent-item-2/sub-menu-a/

        But when you clicked on Sub Menu A under Parent Item 2, the menu for Parent Item 1 displayed, so I did this:

        Parent Item 1
        – Sub Menu A custom url= /parent-item-1/sub-menu-a/ (note the change to 1)

        Parent Item 2
        – Sub Menu A page= /parent-item-2/sub-menu-a/

        So while technically the Sub Menu A has a parent of Parent Item 2, specifying the parent-item-1 in the URL for the custom link still resolves to the correct page and forces the menu to display correctly.

        • http://christianvarga.com/ Christian Varga

          Nice find! I’m sure that this is going to help a a lot of people searching for this exact problem – appears you’re the first person to solve it properly!

  • Attila

    Hi Christian,

    This is great, thank you for sharing!

    One question:
    I am trying to add a class name to the first li item in the list, after the list is sorted

    However, putting $sorted_menu_items[1]->classes[] = ‘first'; before the return part adds a new empty li instead of append a class to the first one

    I’m trying to figure out where in the code I could append the classname
    Any pointers would be much appreciated

    Thank you,
    Attila

    • http://christianvarga.com/ Christian Varga

      Your code doesn’t work because the sorted array is an associative array; index 0 isn’t necessarily the first item after it’s been sorted (or might not even be in the array depending on the menu structure). When trying to edit data like this, try a print_r() on it first to check the structure of your data first. To get the first item in the array, you can use reset like so: `reset($sorted_menu_items)->classes[] = ‘first';`. Having said that, a ‘first’ class is very redundant when you have pseudo-selectors in CSS like `:first-child` which are supported in every browser and IE7+.

      • Attila

        Thanks!

        I tried print_r, but I did’nt figure out it was an associative array. Now it makes sense.
        Thanks a lot for your help!

  • Jani Krunniniva

    Hi,

    That is really good example but I’m wondering could that can same solution do with just a simply css.
    By default wp_nav_menu is showing all the content with children. There is some classes where you can point if you want to show selected menus + children.

    // by default hide all submenus (children)
    .menu-item-object-page ul {
    display:none;
    }
    // show childrens
    .current-menu-item ul {
    display:block;
    }

    ofc if you go thru menus with code it gives some more options to do :)

    -jani-

  • Jani Krunniniva

    Hi,

    That is really good example but I’m wondering could that can same solution do with just a simply css.

    By default wp_nav_menu is showing all the content with children. There is some classes where you can point if you want to show selected menus + children.

    // by default hide all submenus (children)
    #sidemenu ul .menu-item-object-page ul,
    #sidemenu ul .current-menu-parent ul {
    display:none;
    }

    // show childrens
    #sidemenu ul .current-menu-item ul,
    #sidemenu ul .current-menu-parent ul {
    display:block;
    }

    ofc if you go thru menus with code it gives some more options to do :)

    -jani-

    • http://christianvarga.com/ Christian Varga

      I didn’t even think of this, you make a really good point so thanks for sharing! I noticed your CSS doesn’t quite do what my function does; it still shows the name of the current page as the first menu item, and it still shows all the sibling pages of the menu item parent. The latter is easier to fix, you just need to filter by LIs instead of ULs and add a few more selectors. The former is more of a hack by forcing the very first anchor in the first LI to be display: none. Click here to view the changes I made to your CSS to make it work for me. This particular snippet of CSS does solve my problem, but everyone seems to have different requirements so this CSS isn’t really a one-fits-all solution. Usually I’d be all for CSS-only solutions, but in this case I’d prefer to generate the required menu on the server.

  • Xavi

    Christian,

    Thanks guy. I was looking for soething like that. I’m pretty new to WordPress costumization so It has helped me a lot your post. Just one single question. Is any way to retieve the name of the parent menu? I would like to display on the secondary menu with the menu subset a “title” with the parent menu name. I don’t know how to get it. Thanks !

    • http://christianvarga.com/ Christian Varga

      Unfortunately there doesn’t appear to be a function that allows you to get the details of a menu item using it’s ID (not that I can find anyway). So this makes your job harder. Most likely you’ll have to do it manually, which would involve getting the menu items using wp_get_nav_menu_items, then looping through every menu item until it matches the required ID (eg, from $item->menu_item_parent).

  • Abrar

    Hi. Need a help for creating 2SUB MENUS.
    FOR EXAMPLE:
    – Home
    – About Me
    -My Past

    -When I Was Born

    -My Present

    -My Future

    • http://christianvarga.com/ Christian Varga

      Abrar, if your theme doesn’t support a third-level menu, my blog isn’t the place to discuss it. Your question is not related to my blog post, so to keep this thread relevant, please either contact the author of your theme or post a question on StackOverflow.

      • Abrar

        thank you

  • alisontaylorbc

    This post was VERY helpful to me. Thanks so much, Christian! I was able to use it to create a ‘walker’ that will display the nth level submenu and its parent menu item, whenever the site visitor is on any of the nth level pages or their parent page. I was really struggling with this till I found your post.

    • http://christianvarga.com/ Christian Varga

      Thanks for your comment Alison, really glad my code helped you out!

  • kimdcottrell

    This is amazing. Thanks! It’s exactly what I needed for a project I’m working on.

  • David

    Love the idea of this – it is exactly what I need…but sadly it isn’t working for me. When I use wp_nav_menu() it returns a list of the menu items (all the menu items) as expected, when I do it with the sub_menu => true flag, it also returns all the menu items – except it doesn’t use the menu names from Appearance->Menu, it uses the page titles instead. So I have two problems here, firstly I can’t seem to narrow the list of submenu items to only the submenus of a particular parent, and the fact that it is displaying the page titles rather than the menu item names.

    • http://christianvarga.com/ Christian Varga

      Hi David, it’s unfortunate that you’re having this problem – but as it stands I’ll need a little more information to be able to help you out. The plugin does work (I just tested on 3.7.1), and it uses the title specified in the menu builder. In fact if you take a look at the plugin code, you’ll see it doesn’t do anything to the title; it merely filters the results already provided by wp_nav_menu. This means that something else in your setup is affecting the output. Are you sure the menu you created is set as the Primary Menu? If it’s not the primary menu (and you don’t want it to be), you need to register a custom menu location (in functions.php), apply the location to your menu, and target it using the theme_location parameter in your call to wp_nav_menu. If that doesn’t work, you might have a plugin affecting the output, try disabling all plugins or testing on a clean installation.

      • frank

        Hy Christian , How can i add the parent page tittle to top of this menu? Please Help me

        • http://christianvarga.com/ Christian Varga

          Frank, there are plenty of results for “WordPress get parent page title” in google, so this doesn’t seem like the type of question I need to address. Is there a specific problem you’re having?

          • Frank

            No i use your function and i have pages like this

            page whit out child ( i dont want page Title)
            page whith child ( here i want to display the page Title)
            – child page ( here i want to display the parent page Title)
            – child page ( here i want to display the parent page Title)
            – child page ( here i want to display the parent page Title)
            page whit out child ( i dont want page Title)

          • Frank

            Sorry if i not was clear But i want to ad the title of the parent pege just where this menu apear

          • Frank

            Tanks i solved
            post_parent)
            $children = wp_list_pages(“title_li=&child_of=”.$post->post_parent.”&echo=0″);
            else
            $children = wp_list_pages(“title_li=&child_of=”.$post->ID.”&echo=0″);
            if ($children) { ?>
            post_parent); echo $parent_title;?>

            ‘cawpc_main_menu’,
            ‘sub_menu’ => true
            ) );
            ?>

          • http://christianvarga.com/ Christian Varga

            Ok, and what have you tried to solve this problem yourself?

  • Dave

    Christian,

    Beautiful code, brother, thanks a lot!!!!

    Dave

  • Pankaj Sankhla

    Thanks it very easy to use thank you very much

  • Frank

    Here is the solution if you want to a above this menu the parent page title

    post_parent)
    $children = wp_list_pages(“title_li=&child_of=”.$post->post_parent.”&echo=0″);
    else
    $children = wp_list_pages(“title_li=&child_of=”.$post->ID.”&echo=0″);
    if ($children) { ?>
    post_parent); echo $parent_title;?>

    ‘cawpc_main_menu’,
    ‘sub_menu’ => true
    ) );
    ?>

  • Frank

    post_parent)
    $children = wp_list_pages(“title_li=&child_of=”.$post->post_parent.”&echo=0″);
    else
    $children = wp_list_pages(“title_li=&child_of=”.$post->ID.”&echo=0″);
    if ($children) { ?>
    post_parent); echo $parent_title;?>

    ‘cawpc_main_menu’,
    ‘sub_menu’ => true
    ) );
    ?>

  • Frank

    post_parent)
    $children = wp_list_pages("title_li=&child_of=".$post->post_parent."&echo=0");
    else
    $children = wp_list_pages("title_li=&child_of=".$post->ID."&echo=0");
    if ($children) { ?>
    post_parent); echo $parent_title;?>

    'cawpc_main_menu',
    'sub_menu' => true
    ) );
    ?>

  • Pingback: How to Make a WordPress Automatic Submenu With Genesis | Assonance

  • Mark

    This solution is simpler. It’s from http://codex.wordpress.org/Function_Reference/wp_list_pages. The only modification I did is add a “[0]” to
    “$children = wp_list_pages(“title_li=&child_of=”.$ancestors.”&echo=0″);”

    if(!$post->post_parent){
    // will display the subpages of this top level page
    $children = wp_list_pages(“title_li=&child_of=”.$post->ID.”&echo=0″);
    } else{
    if($post->ancestors) {
    // now you can get the the top ID of this page
    // wp is putting the ids DESC, thats why the top level ID is the last one
    $ancestors = get_post_ancestors($post->ID);
    $children = wp_list_pages(“title_li=&child_of=”.$ancestors[0].”&echo=0″);
    }
    }
    if ($children) {
    echo $children;
    }

    • http://christianvarga.com/ Christian Varga

      Mark, if you read my post you’ll see that wp_list_pages doesn’t generate a menu based on the structure you design in the menu builder. I made a very clear point to specify this in the first paragraph. Your solution will not order the menu properly, nor will it even show the right items if you build a custom menu. Please make sure you read & understand an article before commenting on it with an incorrect solution.

  • abdul

    Nice Article. :)

  • Andrew

    Hi! First off, Thanks so much for this. This is working great!

    I had a quick question you might be able to help me with. I have investigated this, and the inspiration from the StackOverflow article you posted as well, but can’t seem to come up with a good solution.

    I want to display the submenu, as well as its direct parent item (but not its parent’s siblings).

    Consider this menu structure:

    Home
    About us
    — Board of Directors
    — — board member A
    — — board member B
    — Solutions
    — — Solution 1
    — — Solution 2

    When I am on the “Board of Directors” page, with your above code, I get the branch:

    board member A
    board member B

    Which is 99.99% of what I want. I was curious if it is possible to also include the parent of this branch, so that the output would be:

    Board of Directors
    — board member A
    — board member B

    I get very close with the version supplied on stackoverflow, when I use $this_post->parent_post->parent_post, as that gives me the grandparent of ‘this’ node, which I was hoping would snip itself, and only show its children. The downside is that I end up with something like (which makes sense):

    Board of Directors
    — board member A
    — board member B
    Solutions
    — Solution 1
    — Solution 2

    So I would like to exclude the Solutions branch from being all together (unless, of course, I am on the solutions page).

    It seems I am so close to solving this issue, but I can’t seem to get it right.

    If all else fails, I will try to use the SO version, and yank the unwanted items from the DOM with JS, or hide them with CSS (both solutions I would prefer to avoid).

    Any help would be welcome! Thanks!

    • http://christianvarga.com/ Christian Varga

      Hey Andrew, I’d personally echo the correct page title above the menu in the theme instead of using wp_nav_menu. Having said that, if you do want to use wp_nav_menu to do it all, you could change the else statement on line 43 to something like this: else if ( ! in_array( $item->ID, $menu_item_parents ) ) {, which would continue to filter the menu like it currently does, except it will skip removing the parent item from the tree. It needs to be done this way because as you’ve already noticed, if you try filtering by the parent, you’ll actually end up with all of the parent’s siblings (and their children) as well.

      • Andrew

        Beauty!
        Works just as I want it to!

        I needed this subtle nuance from wp_nav_menu because the nav title and the page title differ slightly from time to time.

        Thanks so much for your help!

  • Jonathan

    YES! So rarely can you just drop code in a template, hit refresh, & it work. Thank you!

  • Matthew Lee

    Thank you! This was exactly what I was looking for. Surprising this is not built into wordpress

  • Toby

    Great bit of code.

  • http://www.clisho.com Ghali El Andaloussi

    hi i have the same problem in my website http://www.clisho.com/dante/

    how i can change the code for when you click on corporate profile you go to the page and the submenu stay open

    please some help

    • http://christianvarga.com/ Christian Varga

      Technically this isn’t really the “same” problem as you’ve already got a submenu there, and I don’t even think you’re using my code. You just need the submenu to stay open when the link is activated.

      Unfortunately whatever menu script you’re using is setting the display property using javascript, which is bad practice and also means the only way to override it with CSS is to use !important (and I *hate* !important). But if you put the following code into your stylesheet, it will work:

      .current-menu-item .sub-menu.sub { display: block !important; }

  • http://www.clisho.com Ghali El Andaloussi

    do i put it like this or i need to change something
    because i try it and the probleme when i stay hover on corporate after the submenu close
    can you help me ?
    gracias

    • http://christianvarga.com/ Christian Varga

      I would recommend heading over to stackoverflow.com and asking a question there. I’m quite full with work right now so I don’t really have the time to go into your website and fix all the problems with it for free.

  • Joe

    Hey Christian,

    thanks for sharing – works great! I just want to do something that i could not find in the discussion.

    I want to display the submenu wrappers only if the submenu exists. It seems like i can’t do it with has_nav_menu() because it checks for primary-menu that always exists.

    Is there another way to check if there actually is a submenu or to define the wrappers within the functions.php?

    I need to wrap it like that:

    ‘menu_order’, ‘menu_class’ => ‘nav’, ‘theme_location’ => ‘primary-menu’, ‘sub_menu’ => true) ); ?>

    Thanks again for sharing that simple solution.

    Best
    Joe

    • http://christianvarga.com/ Christian Varga

      Actually you can define the wrappers in your call to wp_nav_menu using the ‘items_wrap’ parameter (docs). For example, add this to your call to wp_nav_menu instead of defining the wrapper outside of the call: ‘items_wrap’ => ‘%3$s’

  • henricakesson

    Great piece of code! Just one question… I have a third level on my menu, and I want my submenu to be shown for these pages too.

    So my page is like this:

    Marknad
    – Sponsorer
    – – Huvudsponsorer

    The menu appears both on “Marknad” which is parent page, and it appears on “Sponsorer”, but when I click my way to “Huvudsponsorer” the menu goes away.
    Can you solve this with some code of yours? If you can make this work your god man.

    Anyway, thanks for a very good piece of code!

    • http://christianvarga.com/ Christian Varga

      Hey mate, the code definitely works for an infinite number of sub-levels. Are you sure that Huvudsponsorer is using the same page template that makes the call to the menu? Or have you modified your call to wp_nav_menu() in any way (eg, depth parameter)? I’ve created a demo to show how the different options affect the output, but as you can see, the nested pages still display the menu: http://wp-sub-menu-demo.christianvarga.com/. You might need to try and isolate the problem by disabling any plugins and trying the code on a different theme (in case the theme is modifying the menu in any way).

      • henricakesson

        Thanks for the reply. What I need is something like this:
        “Marknad” is visible on all top levels, and always. This is first menu-item.

        Then under “Marknad” I have “Sponsorer” that is a child to “Marknad”. And under “Sponsorer” I have childs like “Huvudsponsorer” and “Centrala Sponsorer”. When I’m on this level I still want to have the parent meny available. So Marknad is still visible, but the menu with “Sponsorer” dissapear. That second level should be visible on all childs.

        Have I make myself more clear or am I unclear or just stupid? :) I can paste a livesite where I use the code and you can see the problem yourself maybe. :)

        • http://christianvarga.com/ Christian Varga

          Did you check the demo I linked you to? From your description, I still believe that my code already does exactly what you want. However, I don’t understand what you mean by “So Marknad is still visible, but the menu with “Sponsorer” dissapear”. That doesn’t make sense. Perhaps instead of trying to explain what you want the menu to look like with words, just show me the exact structure you expect to see on each page.

          • henricakesson

            Hi! Check this page: http://khk.se.turbo.i8t.com/marknad/

            Everything works fine if you click around on the different pages, but if you click on “Våra sponsorer” and then in the sidebar go to a child of this page, the menu will disappear.

            Should I structure my menu in menusettings diffrent?

          • http://christianvarga.com/ Christian Varga

            Hey mate, unfortunately I’m still not sure what the problem is. The menu in the sidebar does not disappear when I click on any of the children pages of Våra sponsorer. Have you already managed to fix the problem?

          • henricakesson

            Hi! Yes I managed to fix the problem myself. Probably my own fault from the start. The code I ended up using was this: ‘primary’, ‘sub_menu’ => true, ‘show_parent’ => true, ‘show_parent’ => true)); ?>

          • http://christianvarga.com/ Christian Varga

            Ah ok, glad you got it sorted. Just after I read your post I decided to make a demo because it’s not obvious what all the different options do until you actually test them out yourself. But the demo I made doesn’t really explain it very well either. I’ll work on it to see if I can make everything a little more clear :)

  • Orezhon

    Hello Christian,
    great job, but I have a problem:
    wp_nav_menu (array (‘theme_location’ => ‘primary’, ‘sub_menu’ => true)); work correctly in the category but does not work (not visible) in the post pages, can you help?

    • http://christianvarga.com/ Christian Varga

      By “post pages” do you mean posts or pages? This function is specifically designed to work with the structure designed in the menu builder. If your post or page doesn’t exist in the menu, then this function won’t display anything. It will only display items that exist in the menu. This function is designed for use with nested pages, not for posts. If you wanted this menu to work for posts, you’d have to add each post to the menu, which is very redundant and not dynamic at all. If you are trying to display post categories and posts, have a look into wp_list_categories() instead.

      • Orezhon

        sorry, I think I have not explained well

        I have a menu with 2 levels (parents and children), and I split the menu in two different divs in two different positions. The first menu has only parent pages, the second menu displays all the children of the category in which we are now.

        When I go to the page I would like the children of the menu is visible but disappears

        • http://christianvarga.com/ Christian Varga

          To be honest, no amount of explaining will help me understand the problem you’re having. Without seeing your code, it’s virtually impossible for me to be able to diagnose and fix the problem. There are literally thousands of factors that could be causing this to happen, assuming you’re using my code in the way it was intended (which is unclear anyway). The only way I can help is for you to provide me with full access to your codebase on a working demo of the site. Without access there’s simply no way I’ll ever be able to figure out your problem.

          • Orezhon

            I put your function in function.php

            In header.php i have:

            ‘primary’, ‘depth’ => ‘1’) ); ?>

            ‘primary’,’sub_menu’ => true, ‘menu_class’ => ‘sub-menu’) ); ?>

            Works: In index.php i see only main menu

            Works: In category.php i see two menu main and secondary (see only subcategories from parent selected)

            Don’t Work: In page.php , i see only main menu but don’t see secondary menu.

            Your script works like this? I can send you the template?

          • http://christianvarga.com/ Christian Varga

            Everything in my previous message still stands. Think of it like this: your car has broken down and you call up the mechanic to ask him what’s wrong. When he asks you for information, the only information you give him is that the car has an engine. Sure, the mechanic could then spend 10 hours describing every single one of the thousands of problems that could possibly cause the car to stop working, but that’s not an efficient use of his time when he could just take a look at the car and find the problem within 10 minutes.

            Showing me the code you use to call the menu is like saying the car has an engine. That call obviously works for me and hundreds of other people, so it’s not where the problem lies (and yes, it does work on page.php, check out the demo: http://wp-sub-menu-demo.christianvarga.com/)
            Sending me your page template is like sending me the cars manual. That’s not going to help me figure out the problem either.

            Please don’t take offence to this, but I did not write this blog article to then spend hours upon hours of my time diagnosing bugs on other peoples websites for free in the most difficult way possible. I am happy to help, but I need you to help me as well. I need you to be respectful of my time and provide me with everything I need to diagnose the bug, so that I don’t have to spend hours trying to work out every possible option in my head.

            The only way I can help is if you set up a demo site and give me access to both the codebase and wp-admin.

  • Jeremy

    I don’t know if you have stumbled on this before or not, but if you are using the Advanced Navigation Menu plugin, in conjunction with this script you can sometimes run into an issue where you get an empty li at the beginning of your outputted sub menu.

    I found that this is because Advanced Navigation Menu also has an add_filter hook for ‘wp_nav_menu_objects’. It is using the same priority level as your code, but seems to trigger afterwards. I didn’t delve into it much further to determine why it adds the blank li, but by bumping your filter hook up to 100 instead of 10 it fires afterwards and seems to resolve the issue.

    Hope this helps someone out there.

    Cheers

    • http://christianvarga.com/ Christian Varga

      Thanks for commenting Jeremy, if you don’t mind I’ll add this information into the next edit just to make sure that people see it if they come across the same problem.

      • Jeremy

        Yeah, go for it. Glad to help.

  • Fatimah

    I found this widget https://wordpress.org/plugins/advanced-menu-widget/ really useful for this purpose. Very easy to use too

  • Rask

    Hey Christian, thank you for your snippet, it helped me greatly. I have a little issue though: I want to show the parent page menu item as well. This works with the show_parent => true setting, but I need the parent and the children elements on the same level. Not sure if I worded this correctly, I want an with elements, be it the parent or child and no other sub-navigation . Basically children elements should become siblings to the parent. Is there a way to do this?

    Thanks in advance

    • http://christianvarga.com/ Christian Varga

      The thing about my script is that it’s simply a filter for wp_nav_menu; it doesn’t change the structure of wp_nav_menu nor does it allow you to change the structure. It is merely filtering the items that wp_nav_menu displays; wp_nav_menu is still handling the output.

      In your case I’m not quite sure how you’d go about it, but your first step would be looking at how to flatten wp_nav_menu. If you take a look at the docs (click here), it says that by passing in a depth parameter of -1 it will display the results in a flat list. I have not tried this out myself, but it’s a good place to start.

      Alternatively, if the only problem you have is styling, you could simply use CSS to style both the ULs and LIs the same, which would make it look exactly the same as a flat list.

      • Rask

        Ok, thank you for your quick answer, I’m going to look into these.

      • Rask

        Just wanted to let you, and the others know that the depth => -1 wp_nav_menu setting indeed worked, so thank you again for your help.

        • http://christianvarga.com/ Christian Varga

          Good to know!

  • simondls

    THANKYOU!!!!

    This saved me so much time… I’ve been coding individual custom wordpress menus for each area of the website…. DUHHHH!

  • Sergio Garcia

    Great post Christian. A clean and beautiful solution.

  • Sam Spade

    Thanks

  • Pingback: How to Make a WordPress Automatic Submenu With Genesis – Tech Tabby

  • Mark Nielsen

    Thanks so much for this. I use this functionality on so many of my sites I decided to make a plugin for it today. Your code’s given me nearly my whole plugin, so I’ve just sent you a virtual beer. I’ll post back with the plugin details in the future if I can polish it off and make it fit for public consumption. Thanks again!

  • http://www.safiweb.co.ke Safiweb Interactive

    Thank you for the code! it just saved me in a project I was handling.

  • CoolZero Infinity

    Thank you very much Christian! It really helped :-)

  • Oliver

    Thank you so much for this code. I hope WordPress will implement similar feature to their wp_nav_menu.

  • Maciej Dejewski

    Question: is there a way to use your method to get those menu items as objects instead of printing them on screen? Or maybe I can use the walker with wp_get_nav_menu_items with few modifications? (to be honest, I didn’t have the energy to look into native wp_nav_menu function and to try to modify it’s behaviour – I did solve my problem, getting current menu item children as objects in a different way, by filtering all menu items array based on current menu item id – i think it’s pretty much same as walker, just run in different order). Does walker approach bring any extra benefits then my method?
    … and as Oliver posted .. it’ seems wierd to me that with all functionality WordPress offers it doesn’t have methods to select items placed as one of combinations appearance menu allows as to build (using menu is much simpler then using parent dropdown for every item, + it combines different post types).

    • http://christianvarga.com/ Christian Varga

      I originally wrote a function that generated the menu manually, probably similar to what you’ve developed yourself: https://gist.github.com/levymetal/5375456. Although I don’t know exactly what it is that you need to do, I’d chance a guess and say it probably is possible with a custom walker.

      The real benefit of my hooked approach is that I can post the code online and people can use it straight away without any modification. Because it hooks into wp_nav_menu_objects, it can be used with wp_nav_menu (which every theme uses to generate a menu), and even works with a custom walker. My original approach of generating the menu manually didn’t hook into wp_nav_menu so the classes were all wrong, the html output was different, and it couldn’t be filtered with any of the options avaialble to wp_nav_menu. So it wasn’t really a plug-n-play solution like my hooked approach. But if it’s for your own personal project then there’s little difference. If what you’ve written works then there’s no real need to change it.

  • U.s. Man Awan

    cant get help .. i want to make sub menu under nav-menu but i can’t .how i can make ?

  • theperlwalker

    Thanks a lot for this great work Christian ;-).
    I have only one trivial question, is there an easy way to avoid the parent menu? Only show the current level you are in.

    Again, thanks for the code :)

    • http://christianvarga.com/ Christian Varga

      Did you try adding the “direct_parent” => true flag to your call to wp_nav_menu? Check out the demo and scroll down to the second last example, I’m pretty sure that’s what you’re after. http://wp-sub-menu-demo.christianvarga.com/locations/australasia/australia/

      • theperlwalker

        Sorry, I didnt, and I thought i read trough it all looking for an option like that!
        Thanks again!

        • http://christianvarga.com/ Christian Varga

          Awesome, it’s a pretty long post and easy to miss as I didn’t put it in a code snippet. Also my explanation of what it does isn’t that clear either. Glad it worked for you!

  • robmaurizi

    This code’s a lifesaver and is being integrated into 2 projects I’m working on right now… Great bit of work all around!

    Question: Is there any way you can think of that I can pass a parent page or (or even menu item) ID to this function to get back that sub-menu? The trouble I’m having is with custom post type single templates that APPEAR to be children of a page in my menu. But because the post isn’t in the menu, the sub-menu isn’t generated.

    I’m thinking if there’s a way to force the function to think it’s on a given page (the parent page in this question), it can generate that sub-menu. Basically spoofing the $root_id or something, but I’m having trouble following exactly where or how that would need to happen.

    Thanks!
    -Rob

    • robmaurizi

      Huzzah! After a little digging and tinkering, I came up with a solution. I put this before the final loop through the sorted_items array on line 35 of your example above. Simply pass a parent_id argument to the menu to force a sub_menu of a given page. Note, that it’s the Page ID (which you’re more likely to have available) than the Menu Item ID (which is just the DB row ID for that post). This would work for anyone looking to keep a menu up on posts, etc., where WP falls out of the menu.

      Enjoy!
      -Rob


      if (isset($args->parent_id)) {
      // $args->parent_id is the ID of the page whose submenu we want...
      $_parent = 0;
      $_sorted_copy = $sorted_menu_items;

      foreach($_sorted_copy as $key=>$item) {

      if ($item->object_id == $args->parent_id) {

      // this is the top level.. save this value for a moment.
      $_parent = $item->ID;
      break;

      }
      }

      foreach($_sorted_copy as $key=>$item) {

      if ($item->menu_item_parent != $_parent) {
      // this item doesnt belong to the parent, so dump it
      unset($_sorted_copy[$key]);
      }

      }

      return $_sorted_copy;

      }

      • http://christianvarga.com/ Christian Varga

        Rob, thanks so much for your kind donation and posting your solution here. I’m pretty sure there have been other people looking to do what you wanted to do, so I have no doubt that this will be of use to others as well. Cheers!