Joshua David Nelson

Bullshit Free WordPress Development

  • Services
  • Code
  • About
  • Contact

Limit Navigation Sub-Menu Rendering Levels in WordPress

May 29, 2015 by Joshua Nelson

The WordPress menu interface is a great way to manipulate navigation menus on your site. If you’re building a theme, however, you may find yourself wanting to limit the number of available sub-menu depths without removing the sub-menu items themselves.

You can style your way around it (styling .sub-menu .sub-menu to act differently than .sub-menu), you can use the wp_nav_menu function’s depth argument to limit the depth, or you can use a custom Walker to force the output to match.

However, if your situation is such that the styling won’t work well and you want to limit navigation sub-menu depth, but not remove any menu items on lower depths (this happens with the depth argument in wp_nav_menu), then the third option is the way to go: create a custom walker.

<?php
/**
* Limit the number of sub-menu levels outputted.
*
* Removes the ul wrapper on any sub-menus beyond the 2nd level.
*
* @author Joshua David Nelson, [email protected]
*/
// Add menu walker to primary menu
add_filter( 'wp_nav_menu_args', 'jdn_primary_menu_args' );
function jdn_primary_menu_args( $args ) {
if( isset( $args['theme_location'] ) && 'primary' == $args['theme_location'] ) { // change based on the location
$walker = new JDN_Primary_Nav_Walker;
$args['walker'] = $walker;
}
return $args;
}
// Custom Walker
class JDN_Primary_Nav_Walker extends Walker_Nav_Menu {
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
// Remove 'menu-item-has-children' class from elements beyond the second depth level
if( $depth > 1 && isset( $item->classes ) && is_array( $item->classes ) && ( $key = array_search( 'menu-item-has-children', $item->classes ) ) !== false ) {
unset( $item->classes[ $key ] );
}
parent::start_el( $output, $item, $depth, $args );
}
// Starting of a sub-menu
function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
if( $depth < 2 ) {
$output .= "\n$indent<ul class='sub-menu'>\n"; // The default wrap
} elseif( $depth >= 2 ) {
$output .= "\n$indent\n"; // no sub menu wrap
}
}
// End of a sub-menu
function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
if( $depth < 2 ) {
$output .= "$indent</ul>\n"; // the default wrap end
} elseif( $depth >= 2 ) {
$output .= "\n$indent\n"; // no wrap
}
}
}
view raw limit-sub-menu-level-wp.php hosted with ❤ by GitHub

This removes all sub-menu wraps on sub-menus beyond the second level.

Featured image via Flickr CC, by Basheer Tome

Filed Under: Intermediate, WordPress Tutorials Tagged With: nav walker, navigation menu

Discussion

  1. krisna says

    December 23, 2015 at 16:11

    can you tell me, how steps to use

    thanks

    • Joshua Nelson says

      January 5, 2016 at 10:00

      Krisna,

      The Walker is called in the jdn_primary_menu_args function. The key thing here is the name of the menu, which is typically theme-specific. In this example 'primary' is the name of the menu location this Walker is applied to in the theme. Change that accordingly for your theme.

      For the Walker:

      1. The start_el runs at the start of the list item. This this case, it’s looking at any item with a depth over 1 that has a class menu-item-has-children and removing that class.
      2. The start_lvl is where the sub-menu wrapper ul element is applied. The Walker adds this, like the typical default, but in this case only on any sub-menu with a depth under 2 (so only one level of sub-menus is allowed), otherwise it adds the normal $indent value without the sub-menu wrap.
      3. The end_lvl does something similiar, but it fires at the end and either adds the closing tag or the default $indent value.

      Hope that helps!

      Thanks,
      Joshua

  • Twitter
  • RSS Feed URL

About Me

I'm a WordPress Engineer. I build sleek, custom websites with WordPress and Genesis.

See my services and my recent work.

Contact me to get your project started.

Gravity Forms Plugin for WordPress Fastest WordPress Hosting

Recent Posts

  • Using Font Awesome Icons for WooCommerce Grid / List Toggle
  • Disable Blog: WordPress Gone Blog-less
  • Category (Taxonomy) Dropdown Filtered By Post Type
  • Weather in WordPress with Dark Sky
  • Fixing Your Deprecated Widget Constructors in WordPress 4.3
  • Twitter
  • RSS Feed URL
  • Code Snippets
  • My Plugins
  • Make a Payment

© Joshua David Nelson | Hand-Forged | WordPress + Genesis | Terms of Service | Legal | Contact