I have an html structure that requires customization of the wp_nav_menu
code.
This is the html I need to generate:
<ul class="main-nav">
<li class="item">
<a href="http://example.com/?p=123" class="title">Title</a>
<a href="http://example.com/?p=123" class="desc">Description</a>
<ul class="sub-menu">
<li class="item">
<a href="http://example.com/?p=123" class="title">Title</a>
<a href="http://example.com/?p=123" class="desc">Description</a>
</li>
</ul>
</li>
<li class="item">
<a href="http://example.com/?p=123" class="title">Title</a>
<a href="http://example.com/?p=123" class="desc">Description</a>
</li>
</ul>
I am currently using wp_get_nav_menu_items
to get all the items from my menu as an array.
Right now I am able to generate the above html without the sub-menus using the following code:
<?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' ) );
foreach ( $menuitems as $item ):
$id = get_post_meta( $item->ID, '_menu_item_object_id', true );
$page = get_page( $id );
$link = get_page_link( $id ); ?>
<li class="item">
<a href="<?php echo $link; ?>" class="title">
<?php echo $page->post_title; ?>
</a>
<a href="<?php echo $link; ?>" class="desc">
<?php echo $page->post_excerpt; ?>
</a>
</li>
<?php endforeach; ?>
I would have generated the menu using the wp_nav_menu
function but I still need the description shown using $page->post_excerpt
.
I've found that there is a property for each item called $item->menu_item_parent
which gives the ID of the parent menu item.
How would I generate the sub-menu in my foreach
loop?
Or is there a really simple way using wp_nav_menu
which Google forgot to mention?
For anyone who tackles something similar here's my solution:
Quick code example on a gist
Here's the code on a github gist for anyone who wants to get in on the copy paste action.
TL;DR
TL;DR Loop over list, drill down if there's a sub menu, close if we reach the end of the sub menu and menu.
Complete Code explanation
Firstly get the menu items as a flat array:
Then iterate over the array of the menu items:
Write the first parent item
<li>
:Check that this items' parent id matches the stored parent id:
Start sub-menu
<ul>
and set$submenu
flag to true for later referance:Write the sub-menu item:
If the next item does not have the same parent id and we have a sub-menu declared then close the sub-menu
<ul>
Again, if the next item in the array does not have the same parent id close the
<li>
Your best bet is to make your own Walker class to tailor the output to your needs. Something like this:
And then call it like so:
Everything before and after the GET THE EXCERPT marker in my example was a direct copy of the start_el function in wp-includes/nav-menu-template.php. My example uses WP_Query to determine if the post/page has an excerpt, and places the excerpt in between span tags after the link title.
An idea would be to make the span tags appear only upon hover, which can be done using CSS.
More information on Walkers here:
WP Nav Menu Codex
Using The Walker Class
Another Decent Example Using the Walker Class