- This topic is empty.
- AuthorPosts
-
August 13, 2012 at 1:37 am #9518
hitautodestruct
ParticipantI 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 usingwp_nav_menu
which Google forgot to mention?August 13, 2012 at 2:11 am #9523maiorano84
ParticipantYour best bet is to make your own Walker class to tailor the output to your needs. Something like this:
class Excerpt_Walker extends Walker_Nav_Menu { function start_el(&$output, $item, $depth, $args) { global $wp_query; $indent = ( $depth ) ? str_repeat( "\t", $depth ) : ''; $class_names = $value = ''; $classes = empty( $item->classes ) ? array() : (array) $item->classes; $classes[] = 'menu-item-' . $item->ID; $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) ); $class_names = ' class="' . esc_attr( $class_names ) . '"'; $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args ); $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : ''; $output .= $indent . '<li' . $id . $value . $class_names .'>'; $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : ''; $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : ''; $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : ''; $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : ''; $item_output = $args->before; $item_output .= '<a'. $attributes .'>'; $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after; /*GET THE EXCERPT*/ $q = new WP_Query(array('post__in'=>$item->object_id)); if($q->have_posts()) : while($q->have_posts()) : $q->the_post(); $item_output .= '<span class="menu-excerpt">'.get_the_excerpt().'</span>'; endwhile;endif; /*****************/ $item_output .= '</a>'; $item_output .= $args->after; $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); } }
And then call it like so:
<?php wp_nav_menu(array('walker' => new Excerpt_Walker())); ?>
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:
August 14, 2012 at 8:18 am #9524hitautodestruct
ParticipantFor 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:
<?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' ) ); ?>
Then iterate over the array of the menu items:
<nav> <ul class="main-nav"> <?php $count = 0; $submenu = false; foreach( $menuitems as $item ): // set up title and url $title = $item->title; $link = $item->url; // 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; ?>
Write the first parent item
<li>
:<li class="item"> <a href="<?php echo $link; ?>" class="title"> <?php echo $title; ?> </a> <?php endif; ?>
Check that this items’ parent id matches the stored parent id:
<?php if ( $parent_id == $item->menu_item_parent ): ?>
Start sub-menu
<ul>
and set$submenu
flag to true for later referance:<?php if ( !$submenu ): $submenu = true; ?> <ul class="sub-menu"> <?php endif; ?>
Write the sub-menu item:
<li class="item"> <a href="<?php echo $link; ?>" class="title"><?php echo $title; ?></a> </li>
If the next item does not have the same parent id and we have a sub-menu declared then close the sub-menu
<ul>
<?php if ( $menuitems[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ): ?> </ul> <?php $submenu = false; endif; ?> <?php endif; ?>
Again, if the next item in the array does not have the same parent id close the
<li>
<?php if ( $menuitems[ $count + 1 ]->menu_item_parent != $parent_id ): ?> </li> <?php $submenu = false; endif; ?> <?php $count++; endforeach; ?> </ul> </nav>
March 28, 2017 at 6:12 am #9519gajendra-patel
Participant//Just set your variable and apply.. for sub menu <ul> <?php $activeclass = ''; $activeclass1=''; $count=0; $submenu = FALSE; foreach ( $primaryNav as $navItem ) { $activeclass = ''; if($navItem->object_id == $getid){ $activeclass = 'class="live-act"'; } if (!$navItem->menu_item_parent ){ $parent_id = $navItem->ID; echo '<li><a href="'.$navItem->url.'" '.$activeclass.' title="'.$navItem->title.'">'.$navItem->title.'</a>'; } ?> <?php if ( $parent_id == $navItem->menu_item_parent ) { ?> <?php if ( !$submenu ): $submenu = true; ?> <ul> <?php endif; ?> <li> <a href="<?php echo $navItem->url; ?>" class="title"><?php echo $navItem->title; ?></a> </li> <?php if ( $primaryNav[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ){ ?> </ul> <?php $submenu = false; } ?> <?php } if ( $primaryNav[ $count + 1 ]->menu_item_parent != $parent_id ){ ?> </li> <?php $submenu = false; } ?> <?php $count++; ?> <?php } ?> </ul>
July 29, 2021 at 9:50 am #9520haroon-hayat
ParticipantComplete Code explanation…..
First Create two below two functions in functions.php file
function get_menu_id( $location ){ //get all the location.... $locations =get_nav_menu_locations(); //get object id by location..... $menu_id = $locations[$location]; return !empty($menu_id) ? $menu_id : ''; } function get_child_menu_items($menu_array , $parent_id){ $child_menu = []; if(!empty($menu_array) && is_array($menu_array)){ foreach($menu_array as $menu){ if( intval($menu->menu_item_parent) === $parent_id){ array_push($child_menu , $menu); } } } return $child_menu; }
then
$menu_name = 'menu_name'; $location = get_nav_menu_locations(); $menu = wp_get_nav_menu_object($location[$menu_name]); $menuitems = wp_get_nav_menu_items( $menu->term_id); $header_menu_id = get_menu_id('primary-menu'); $header_menus = wp_get_nav_menu_items($header_menu_id);
now this is my html and php code….
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <?php if(!empty($header_menus) && is_array($header_menus)){ ?> <ul class="navbar-nav ml-auto"> <?php foreach($header_menus as $menu_item){ if(!$menu_item->menu_item_parent){ //checking the item are parent? $child_menu_items = get_child_menu_items($header_menus, $menu_item->ID); $has_children = !empty($child_menu_items) && is_array($child_menu_items); if(! $has_children){ ?> <li class="nav-item"> <a class="nav-link" href="<?php echo esc_url($menu_item -> url); ?>"> <?php echo esc_html($menu_item->title); ?></a> </li> <?php }else{ ?> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="<?php echo esc_url($menu_item -> url); ?>" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <?php echo esc_html($menu_item->title); ?> </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <?php foreach($child_menu_items as $child){ ?> <a class="dropdown-item" href="<?php echo esc_url($child->url); ?>" > <?php echo esc_html($child->title); ?></a> <?php } ?> </div> </li> <?php } } } ?> </ul> <?php } ?>
October 7, 2021 at 3:28 am #9521anish-rai
ParticipantPleae try this. It works for me.
<?php $menuLocations = get_nav_menu_locations(); $menuID = $menuLocations['primary']; $menu = wp_get_nav_menu_object($menuLocations['primary']); $menuitems = wp_get_nav_menu_items($menu->term_id, array('order' => 'DESC')); $ParentArray = array(); $count = 0; $submenu = false; foreach ($menuitems as $menu_item) { $link = $menu_item->url; $title = $menu_item->title; if ($menu_item->menu_item_parent == 0 ) { $parent_id = $menu_item->ID; echo '<li class="main-li dropmenu"><a href="' .$menu_item->url . '">'.$menu_item->title .'</a>'; } if ($parent_id == $menu_item->menu_item_parent ) { if (!$submenu ) { $submenu = true; echo '<ul class="level1">'; } echo '<li><a href="'.$link.'">'.$title.'</a></li>'; if ($menuitems[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ) { echo '</ul>'; $submenu = false; } } if ($menuitems[ $count + 1 ]->menu_item_parent != $parent_id ) { echo '</li>'; $submenu = false; } $count++; } ?>
October 14, 2021 at 7:05 am #9522marsellus
ParticipantIf your theme uses
has_nav_menu('<menu-name>')
in theheader
orfooter.php
(for example), you can go toAppearance > Menus
and select which menu or sub-menu to configure. - AuthorPosts
- You must be logged in to reply to this topic.