Erro "Tentando obter propriedade de não-objeto" com o Walker personalizado para wp_nav_menu

8

Estou tentando adicionar algumas coisas relacionadas à ARIA à função wp_nav_menu. Eu uso uma classe de caminhante personalizada para esse fim:

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";
        }
}

Eu apenas copiei e colei a classe Walker_Nav_Menu original e adicionei coisas, mas estou recebendo erros porque a variável $ args tratada como um objeto é realmente uma matriz. Mas o mais estranho é que esse erro persista, mesmo se eu passar no andador original assim:

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

Estas são as mensagens de erro que recebo:

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

As linhas são assim (no arquivo original!):

(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;
Rudolf
fonte
Você recebe um erro se não estiver passando pelo walker? Argumentos devem ser objetos, acho que é isso que os documentos inline dizem e o que wp_nav_menu()passa.
Rarst
Não, se eu apenas usar a wp_nav_menu()função padrão sem um andador, ela funcionará perfeitamente. Sim, mas por que é uma matriz então? Eu até o fiz var_dump, sem objeto.
Rudolf
Não sei ao certo o que está acontecendo, porque a passagem new Walker_Nav_Menudeve se comportar de maneira idêntica a não a passagem. Há mais alguma coisa acontecendo, algum plug-in ligado / manipulando a funcionalidade do menu?
Rarst
Acabei de fazer alguns testes adicionais e tenho certeza de que este é um bug do WordPress. No meu caso, o menu de navegação que usei não foi atribuído no back-end. Portanto, o fallback das páginas da lista foi usado, parece que a variável args é uma matriz. Vou rastrear isso até a fonte agora e depois contar o que encontrei.
Rudolf
Se eu atribuir corretamente um menu, ele funcionará!
Rudolf

Respostas:

18

Eu recebo esse erro quando não há menus definidos ou nenhum menu definido para o local em Appearance->Menus. Quando isso ocorre, wp_nav_menuusa um fallback de walker de página.

  1. O fallback (padrão) parawp_nav_menu éwp_walker_page
  2. que usa wp_page_menu
  3. que usa wp_list_pages
  4. que usa walk_page_tree
  5. que Walker_Pagenão usa Walker_Nav_Menu.

E aparentemente os dois caminhantes não são compatíveis. Não sei por que não falha graciosamente. Isso parece um bug para mim.

Com um menu definido em wp-admin->Appearance->Menus, seu código funciona.

Você pode evitar o erro verificando se há um menu atribuído ao local antes de tentar usá-lo.

$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,
  ) );
}

Ou, se você preferir um código menos anti-histamínico (obrigado @Rarst):

if (has_nav_menu('primary')) {
  wp_nav_menu( array(
      'theme_location' => 'primary',
      'walker'         => new Walker_Nav_Menu_With_Aria,
  ) );
}
s_ha_dum
fonte
O fallback é usado apenas quando tudo o resto falha ao exibir páginas. Se o menu funcionar corretamente, os itens serão percorridos com os walk_nav_menu_tree()quais será usado Walker_Nav_Menupor padrão.
Rarst
Boa atualização! Não me ocorreu que a função errada pode estar agarrando o andador (isso é meh). Também existe has_nav_menu()essa verificação.
Rarst
Isso é exatamente o que eu apenas queria postar: D O menu nav $argsé convertido em um objeto na wp-includes/nav-menu-template.phplinha 145 pela wp_nav_menu()função. A wp_page_menu()função usada como fallback não faz isso, mas apenas passa a matriz para o Walker no menu de navegação que precisa do objeto. Se você apenas adicionar um $args = (object) $argsna parte superior da start_elfunção da classe Walker, poderá corrigir isso. Onde seria o lugar certo para denunciar isso à equipe do WordPress?
Rudolf
@Rudolf erros fundamentais devem ser reportadas pelo core.trac.wordpress.org
Rarst
O WP_Postobjeto que é passado como $itemdiferente também (por causa disso, as páginas não têm nomes e a lista consiste apenas em <li>elementos vazios ). Seria necessária alguma refatoração séria para tornar esses dois caminhantes compatíveis.
Rudolf
0

use o código abaixo para reparar:

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;
}
hannanstd
fonte