10

I am trying to add some ARIA related stuff to the wp_nav_menu function. I use a custom walker class for this purpose:

class Walker_Nav_Menu_With_Aria extends Walker_Nav_Menu {
        function start_lvl( &$output, $depth = 0, $args = array() ) {
                $indent = str_repeat("\t", $depth);
                $output .= "\n$indent<ul class=\"sub-menu\" role=\"group\">\n";
        }

        function end_lvl( &$output, $depth = 0, $args = array() ) {
                $indent = str_repeat("\t", $depth);
                $output .= "$indent</ul>\n";
        }

        function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
                $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_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

                $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
                $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

                // Add attributes for <li>
                $li_attributes  = ' role="treeitem"';
                $li_attributes .= ' aria-expanded="false"';

                $output .= $indent . '<li' . $id . $value . $class_names . $li_attributes .'>';

                $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        ) .'"' : '';

                // Add attributes for <a>
                $attributes .= $depth == 0 ? ' tabindex="0"' : ' tabindex="-1"';

                $item_output = $args->before;
                $item_output .= '<a'. $attributes .'>';
                $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
                $item_output .= '</a>';
                $item_output .= $args->after;

                $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
        }

        function end_el( &$output, $item, $depth = 0, $args = array() ) {
                $output .= "</li>\n";
        }
}

I just copy-pasted the original Walker_Nav_Menu class and added stuff, but I am getting errors because the $args variable treated like an object is really an array. But the really weird thing is that this error persists, even if I pass in the original walker like this:

wp_nav_menu( array(
    'theme_location' => 'main-nav',
    'walker'         => new Walker_Nav_Menu,
) );

These are the error messages I get:

NOTICE: TRYING TO GET PROPERTY OF NON-OBJECT IN /USERS/RUDOLF/SITES/LOCALHOST/WP/WP-INCLUDES/NAV-MENU-TEMPLATE.PHP ON LINE 88
NOTICE: TRYING TO GET PROPERTY OF NON-OBJECT IN /USERS/RUDOLF/SITES/LOCALHOST/WP/WP-INCLUDES/NAV-MENU-TEMPLATE.PHP ON LINE 90
NOTICE: TRYING TO GET PROPERTY OF NON-OBJECT IN /USERS/RUDOLF/SITES/LOCALHOST/WP/WP-INCLUDES/NAV-MENU-TEMPLATE.PHP ON LINE 90
NOTICE: TRYING TO GET PROPERTY OF NON-OBJECT IN /USERS/RUDOLF/SITES/LOCALHOST/WP/WP-INCLUDES/NAV-MENU-TEMPLATE.PHP ON LINE 92

The lines look like this (In the original file!):

(88) $item_output = $args->before;
(89) $item_output .= '<a'. $attributes .'>';
(90) $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
(91) $item_output .= '</a>';
(92) $item_output .= $args->after;
8
  • Do you get error if not passing walker at all? Arguments should be object, I think that that is what inline docs say and what wp_nav_menu() passes.
    – Rarst
    Commented Jun 16, 2013 at 15:02
  • No, if I just use the default wp_nav_menu() function without a walker, it works perfectly. Yeah, but why is it an array then? I even var_dump'ed it, no object.
    – Rudolf
    Commented Jun 16, 2013 at 15:26
  • I am not sure what is going on then, because passing new Walker_Nav_Menu should behave identically to not passing walker. Is anything else going on, any plugins hooking into / manipulating menu functionality?
    – Rarst
    Commented Jun 16, 2013 at 15:27
  • I just did some additional testing, and I'm sure this is a WordPress bug. In my case, the nav menu I used wasn't assigned in the backend. Therefore the list pages fallback was used, it seems that then the args variable is an array. I will trace this to the source now, then tell you what I found.
    – Rudolf
    Commented Jun 16, 2013 at 15:40
  • If I correctly assign a menu, it works!
    – Rudolf
    Commented Jun 16, 2013 at 15:40

2 Answers 2

21

I get this error when there are no menus defined or no menus set for the location at Appearance->Menus. When that occurs wp_nav_menu uses a page walker fallback.

  1. The fallback (default) for wp_nav_menu is wp_walker_page
  2. which uses wp_page_menu
  3. which uses wp_list_pages
  4. which uses walk_page_tree
  5. which uses Walker_Page not Walker_Nav_Menu.

And apparently the two walkers are not compatible. I don't know why it doesn't fail gracefully. That seems like a bug to me.

With a menu set at wp-admin->Appearance->Menus, your code works.

You can avoid the error by checking to see that there is a menu assigned to the location before trying to use the location.

$locations = get_nav_menu_locations();
if (0 !== $locations['main-nav']) {
  wp_nav_menu( array(
      'theme_location' => 'main-nav',
      'walker'         => new Walker_Nav_Menu_With_Aria,
  ) );
}

Or, if you'd prefer less antihistamine addled code ( thanks @Rarst ):

if (has_nav_menu('primary')) {
  wp_nav_menu( array(
      'theme_location' => 'primary',
      'walker'         => new Walker_Nav_Menu_With_Aria,
  ) );
}
5
  • Fallback is only used when all else fails to display pages. If menu works properly items are walked with walk_nav_menu_tree() which does use Walker_Nav_Menu by default.
    – Rarst
    Commented Jun 16, 2013 at 14:57
  • Nice update! Didn't occur to me wrong function might be grabbing the walker (that's meh). Also there is has_nav_menu() for that check.
    – Rarst
    Commented Jun 16, 2013 at 15:34
  • That is exactly what I just wanted to post :D The nav menu $args are converted to an object in wp-includes/nav-menu-template.php on line 145 by the wp_nav_menu() function. The wp_page_menu() function which is used as a fallback doesn't do that, but instead just passes the array to the Walker from the nav menu which needs the object. If you just add a $args = (object) $args on the top of the start_el function of the Walker class, you can fix this. Where would be the right place to report this to the WordPress team?
    – Rudolf
    Commented Jun 16, 2013 at 15:57
  • @Rudolf core bugs should be reported at core.trac.wordpress.org
    – Rarst
    Commented Jun 16, 2013 at 16:00
  • The WP_Post object that is passed as $item is different, too (Because of this, the pages have no names and the list just consists of empty <li> elements). Some serious refactoring would be needed to make these two walkers compatible.
    – Rudolf
    Commented Jun 16, 2013 at 16:04
0

use below code to repair :

add_filter( 'wp_get_nav_menu_object', 'override_wp_get_nav_menu_object', 10, 2 );
function override_wp_get_nav_menu_object( $menu_obj, $menu ) {

    if ( ! is_object( $menu_obj ) ) {
        $menu_obj = (object) array( 'name' => '' );
    }

    return $menu_obj;
}

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.