11

I know how to add a Walker to a custom menu created by the theme (menu named primary in this example), but how can I target a menu thats created in a widget with the default wordpress custom menu widget?

if ( has_nav_menu( 'primary' ) ) {

$args = array(
    'menu' => 'main-menu',
    'menu_id' => 'main-menu',
    'theme_location' => 'primary',
    'depth' => 0,
    'container' => false,
    'menu_class' => 'nav',
    'walker' => new Myprefix_Walker_Nav_Menu(),
    'echo' => 0
);

$nav = wp_nav_menu( $args );

}

4 Answers 4

15

If you look at implementation of WP_Nav_Menu_Widget class you will see the following code:

function widget($args, $instance) {
    // Get menu
    $nav_menu = ! empty( $instance['nav_menu'] ) ? wp_get_nav_menu_object( $instance['nav_menu'] ) : false;

    if ( !$nav_menu )
        return;

    $instance['title'] = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );

    echo $args['before_widget'];

    if ( !empty($instance['title']) )
        echo $args['before_title'] . $instance['title'] . $args['after_title'];

    wp_nav_menu( array( 'fallback_cb' => '', 'menu' => $nav_menu ) );

    echo $args['after_widget'];
}

It means that there is no any chance to hook a menu. So you need to take a look at wp_nav_menu function implementation, where you can find following lines of code:

$defaults = array(
  'menu' => '',
  'container' => 'div',
  'container_class' => '',
  'container_id' => '',
  'menu_class' => 'menu',
  'menu_id' => '',
  'echo' => true,
  'fallback_cb' => 'wp_page_menu',
  'before' => '',
  'after' => '',
  'link_before' => '',
  'link_after' => '',
  'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  'depth' => 0,
  'walker' => '',
  'theme_location' => ''
);

$args = wp_parse_args( $args, $defaults );
$args = apply_filters( 'wp_nav_menu_args', $args );
$args = (object) $args;

Here you can see that all arguments passed to the wp_nav_menu function could be replaced. So what you need is to create your own hook handler which will add your walker to a navigation menu. It could be simple as:

function myplugin_custom_walker( $args ) {
    return array_merge( $args, array(
        'walker' => new My_Custom_Walker(),
        // another setting go here ... 
    ) );
}
add_filter( 'wp_nav_menu_args', 'myplugin_custom_walker' );
3
  • this is great thank you. Looks like this makes the default for all menus. Am I right to assume that when i use this i am stuck with all menus having this walker? because i tryed 'walker' => new Walker_Nav_Menu() in the arguments of my specific menu to override it again to become the wordpress default walker for just one menu, but sadly this don't works.
    – amy
    Jun 1, 2012 at 16:57
  • @amy yes it will be default for all menus. Jun 1, 2012 at 17:01
  • @amy you can include code to examine the args. Then put an if conditional whether you apply the walker or not.
    – Wayne
    Mar 7, 2013 at 13:59
5

Expanding on @Eugene's answer, if you want to limit this to a specific menu, just check the term ID of the menu:

function custom_nav_args($args){
$menu = $args['menu'];
    if($menu->term_id === 17)  /* replace term_id with menu id, or use $menu->name to do it by menu name*/
    {
        $args['walker'] = new My_Custom_Walker();
    }
    return $args;
}
add_filter('wp_nav_menu_args', 'custom_nav_args');
1
  • How would we filter by sidebar id? Mar 3, 2016 at 19:33
2

This is an alternative to targeting a menu by term_id and I thought it might be of use to someone as a way of modifying several menus without having to look up their ids.

By adding print_r($args) to a filter, I noticed that $args['menu'] is a string for menus in predefined theme locations and WP_Term_Object for a custom menu widget in a sidebar.

I used this to target menus by slug and add a class to their container. A number of menus can be targeted by including a common string in their slugs. Note: menu slug comes from the array key in register_nav_menus().

function my_menu_thingy( $args ) {
  if( is_object($args['menu']) && strpos($args['menu']->{slug},'my-common-string') !== false ) {
    $args['walker'] = new My_Custom_Walker();
  }
  return $args;
}
add_filter( 'wp_nav_menu_args', 'my_menu_thingy' );

For a single menu you would just need to check that $args['menu']->{slug} == 'your-slug' instead of the strpos() bit above.

2

You can add a custom walker to a nav menu created in a widget using the widget_nav_menu_args filter added in wordpress 4.2.0. It accepts four arguments (see wp-includes/widgets/class-wp-nav-menu-widget.php). But to add only a custom walker you just need to use the first argument, the same way you use the wp_nav_menu_args filter.

    add_filter('wp_nav_menu_args', 'my_args'); //for menus
    add_filter('widget_nav_menu_args', 'my_args'); //for menus in widgets
    function my_args($args) { //$args is only argument needed to add custom walker
       return array_merge( $args, array(
          'walker' => new My_Custom_Walker(),
       ) );
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.