Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Generate a custom structure for Wordpress menus.

This gist is for showing an example of a custom wordpress menu.

If you want to get more from the menu item simply have a look at the $item object. i.e:

// Will return a large object with lots of props like title, url, description, id etc.
var_dump( $item );

This code works on Wordpress 4.1.1 as of 31st of March 2015

<?php
$menu_name = 'main_nav';
$locations = get_nav_menu_locations();
$menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
$menuitems = wp_get_nav_menu_items( $menu->term_id, array( 'order' => 'DESC' ) );
?>
<nav>
<ul class="main-nav">
<?php
$count = 0;
$submenu = false;
foreach( $menuitems as $item ):
$link = $item->url;
$title = $item->title;
// item does not have a parent so menu_item_parent equals 0 (false)
if ( !$item->menu_item_parent ):
// save this id for later comparison with sub-menu items
$parent_id = $item->ID;
?>
<li class="item">
<a href="<?php echo $link; ?>" class="title">
<?php echo $title; ?>
</a>
<?php endif; ?>
<?php if ( $parent_id == $item->menu_item_parent ): ?>
<?php if ( !$submenu ): $submenu = true; ?>
<ul class="sub-menu">
<?php endif; ?>
<li class="item">
<a href="<?php echo $link; ?>" class="title"><?php echo $title; ?></a>
</li>
<?php if ( $menuitems[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ): ?>
</ul>
<?php $submenu = false; endif; ?>
<?php endif; ?>
<?php if ( $menuitems[ $count + 1 ]->menu_item_parent != $parent_id ): ?>
</li>
<?php $submenu = false; endif; ?>
<?php $count++; endforeach; ?>
</ul>
</nav>
@dejavu18

This comment has been minimized.

Show comment Hide comment
@dejavu18

dejavu18 Aug 31, 2013

Hello.
Add a description menu ?

Hello.
Add a description menu ?

@theodorocaliari

This comment has been minimized.

Show comment Hide comment
@theodorocaliari

theodorocaliari Jan 6, 2014

Hi, before all, thanks for share your solution! Very apreciated!
Well, how can I add more 2 deep levels in sub menu? I tryed to copy and paste the fragment of 'ul.sub-menu' inside of the child 'li' but all is duplicated... =(

How can I do that? Please help me! Thanks!

Hi, before all, thanks for share your solution! Very apreciated!
Well, how can I add more 2 deep levels in sub menu? I tryed to copy and paste the fragment of 'ul.sub-menu' inside of the child 'li' but all is duplicated... =(

How can I do that? Please help me! Thanks!

@hitautodestruct

This comment has been minimized.

Show comment Hide comment
@hitautodestruct

hitautodestruct Feb 3, 2014

@theodorocaliari This code should drill down to any level sub menus.

Owner

hitautodestruct commented Feb 3, 2014

@theodorocaliari This code should drill down to any level sub menus.

@SpartakusMd

This comment has been minimized.

Show comment Hide comment
@SpartakusMd

SpartakusMd Apr 3, 2014

Hi. Your code is buggy. If you add a category to menu a error is shown. $page->post_title change with $item->title and $link = get_page_link( $id ) with $link = $item->url;. Also $page->post_excerpt won't exist.

Hi. Your code is buggy. If you add a category to menu a error is shown. $page->post_title change with $item->title and $link = get_page_link( $id ) with $link = $item->url;. Also $page->post_excerpt won't exist.

@karlhadwen

This comment has been minimized.

Show comment Hide comment
@karlhadwen

karlhadwen Nov 20, 2014

SpartakusMd is right. I have to add that you must also have an 'isset' on both '($menu_items[$count + 1]->menu_item_parent)' pieces of code, or you'll get a property of non-object error. Also on the first 'isset' since you're closing the '' tag, make sure you use an else statement to close the tag even if it isn't set, or else you'll be missing a closing tag. I also tested it to multiple levels but it doesn't go that far.

SpartakusMd is right. I have to add that you must also have an 'isset' on both '($menu_items[$count + 1]->menu_item_parent)' pieces of code, or you'll get a property of non-object error. Also on the first 'isset' since you're closing the '' tag, make sure you use an else statement to close the tag even if it isn't set, or else you'll be missing a closing tag. I also tested it to multiple levels but it doesn't go that far.

@beesmart

This comment has been minimized.

Show comment Hide comment
@beesmart

beesmart Dec 30, 2014

I've run into a problem this code, it works great until you need to add a 3rd level menu-item, at which point the html elements come undone and the child menu items don't show up. I've checked the code to see what could be causing this or what I could do to fix it but to no avail. I've posted a questions here:

http://wordpress.stackexchange.com/questions/173573/wp-custom-nav-menu-problem

If you have any advice/help I'd greatly appreciate it.

I've run into a problem this code, it works great until you need to add a 3rd level menu-item, at which point the html elements come undone and the child menu items don't show up. I've checked the code to see what could be causing this or what I could do to fix it but to no avail. I've posted a questions here:

http://wordpress.stackexchange.com/questions/173573/wp-custom-nav-menu-problem

If you have any advice/help I'd greatly appreciate it.

@mashro3na

This comment has been minimized.

Show comment Hide comment
@mashro3na

mashro3na Jan 3, 2015

its worked with me by change

$page = get_page( $id );
$link = get_page_link( $id );
to
$title = $item->title;
$url = $item->url;
$class = $item->classes[0];

good work you saved my day! Thank you.

its worked with me by change

$page = get_page( $id );
$link = get_page_link( $id );
to
$title = $item->title;
$url = $item->url;
$class = $item->classes[0];

good work you saved my day! Thank you.

@karlhadwen

This comment has been minimized.

Show comment Hide comment
@karlhadwen

karlhadwen Feb 22, 2015

@mashro3na can you elaborate? you can't just replace two variables. @hitautodestruct can you fix this?

@mashro3na can you elaborate? you can't just replace two variables. @hitautodestruct can you fix this?

@hitautodestruct

This comment has been minimized.

Show comment Hide comment
@hitautodestruct

hitautodestruct Mar 31, 2015

@karlhadwen Replaced in gist 😄

Owner

hitautodestruct commented Mar 31, 2015

@karlhadwen Replaced in gist 😄

@Valonix

This comment has been minimized.

Show comment Hide comment
@Valonix

Valonix Apr 21, 2015

if you add menu item like "LINK" you get a issue

Valonix commented Apr 21, 2015

if you add menu item like "LINK" you get a issue

@dmmarmol

This comment has been minimized.

Show comment Hide comment
@dmmarmol

dmmarmol Jun 8, 2015

@hitautodestruct I had the same issue that @theodorocaliari. I can't print more than one submenu list and I need to nest every <ul class="submenu"> inside a parent <li>, depending on how much submenu i have.

How can i evaluate the php( $parent_id == $item->menu_item_parent ) when the $item it has more than one parent element?

dmmarmol commented Jun 8, 2015

@hitautodestruct I had the same issue that @theodorocaliari. I can't print more than one submenu list and I need to nest every <ul class="submenu"> inside a parent <li>, depending on how much submenu i have.

How can i evaluate the php( $parent_id == $item->menu_item_parent ) when the $item it has more than one parent element?

@SimonBak

This comment has been minimized.

Show comment Hide comment
@SimonBak

SimonBak Sep 11, 2015

Hello,

Thanks for your nice work.
Do you have an idea if i ant to add a third level more ?
Thanks.

Hello,

Thanks for your nice work.
Do you have an idea if i ant to add a third level more ?
Thanks.

@gnowland

This comment has been minimized.

Show comment Hide comment
@gnowland

gnowland Oct 6, 2015

@beesmart, you're absolutely right, there's an error in the code.

Line 41 should be:

<?php if ( !isset($menu_items[ $count + 1 ]) || $menuitems[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ): ?>

and Line 47 should be:

<?php if ( !isset($menu_items[ $count + 1 ]) || $menuitems[ $count + 1 ]->menu_item_parent != $parent_id ): ?>

@hitautodestruct you may want to update this in the gist.

gnowland commented Oct 6, 2015

@beesmart, you're absolutely right, there's an error in the code.

Line 41 should be:

<?php if ( !isset($menu_items[ $count + 1 ]) || $menuitems[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ): ?>

and Line 47 should be:

<?php if ( !isset($menu_items[ $count + 1 ]) || $menuitems[ $count + 1 ]->menu_item_parent != $parent_id ): ?>

@hitautodestruct you may want to update this in the gist.

@loorlab

This comment has been minimized.

Show comment Hide comment
@loorlab

loorlab Oct 11, 2015

@gnowland & @hitautodestruct Thanks for your solutions !

loorlab commented Oct 11, 2015

@gnowland & @hitautodestruct Thanks for your solutions !

@thedgbrt

This comment has been minimized.

Show comment Hide comment
@thedgbrt

thedgbrt Dec 1, 2015

@gnowland there's an error in your correction, it should be $menuitems[ $count + 1 ] instead of $menu_items[ $count + 1 ]

thedgbrt commented Dec 1, 2015

@gnowland there's an error in your correction, it should be $menuitems[ $count + 1 ] instead of $menu_items[ $count + 1 ]

@michellomp

This comment has been minimized.

Show comment Hide comment
@michellomp

michellomp Feb 23, 2016

I made changes of @gnowland and @dagobertrenouf but the problem is the same i only get one level drop down menu
Does anybody succeed having multi level menu with this code

I made changes of @gnowland and @dagobertrenouf but the problem is the same i only get one level drop down menu
Does anybody succeed having multi level menu with this code

@wespiremedia

This comment has been minimized.

Show comment Hide comment
@wespiremedia

wespiremedia Jun 13, 2017

The problem is in the ( $parent_id == $item->menu_item_parent ) statements.

While looping a third level menu-item, the parent_id is the ID of the parent item (so second level), while the $parent_id is the top-parent ID.

We've solved this to change $parent_id to an array which contains all of the previous menu-item ID's.
After that, improve the statements with the in_array($item->menu_item_parent, $parent_id) function.

wespiremedia commented Jun 13, 2017

The problem is in the ( $parent_id == $item->menu_item_parent ) statements.

While looping a third level menu-item, the parent_id is the ID of the parent item (so second level), while the $parent_id is the top-parent ID.

We've solved this to change $parent_id to an array which contains all of the previous menu-item ID's.
After that, improve the statements with the in_array($item->menu_item_parent, $parent_id) function.

@tenold

This comment has been minimized.

Show comment Hide comment
@tenold

tenold Jan 23, 2018

I can't seem to figure out how to put a class (like .menu-item-has-children for example) on the li that has children. Any help?

tenold commented Jan 23, 2018

I can't seem to figure out how to put a class (like .menu-item-has-children for example) on the li that has children. Any help?

@enesaltuntas

This comment has been minimized.

Show comment Hide comment
@enesaltuntas

enesaltuntas Mar 31, 2018

Hi,

@hitautodestruct How can i get thee child menu items?

enesaltuntas commented Mar 31, 2018

Hi,

@hitautodestruct How can i get thee child menu items?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment