Errore "Trying to get property of non-object" con Custom Walker per wp_nav_menu

16 giu 2013, 16:07:29
Visualizzazioni: 18.5K
Voti: 10

Sto cercando di aggiungere alcune funzionalità ARIA alla funzione wp_nav_menu. Uso una classe custom walker per questo scopo:

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

                // Aggiungi attributi per <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        ) .'"' : '';

                // Aggiungi attributi per <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";
        }
}

Ho semplicemente copiato e incollato la classe originale Walker_Nav_Menu e aggiunto delle modifiche, ma ottengo errori perché la variabile $args viene trattata come un oggetto quando in realtà è un array. La cosa strana è che questo errore persiste anche se passo il walker originale in questo modo:

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

Questi sono i messaggi di errore che ottengo:

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

Le righe in questione sono queste (nel file originale!):

(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
Commenti

Ricevi un errore se non passi affatto il walker? Gli argomenti dovrebbero essere un oggetto, penso che sia ciò che dicono i documenti inline e ciò che passa wp_nav_menu().

Rarst Rarst
16 giu 2013 18:02:38

No, se uso semplicemente la funzione predefinita wp_nav_menu() senza un walker, funziona perfettamente. Sì, ma allora perché è un array? Ho persino fatto var_dump, nessun oggetto.

Rudolf Rudolf
16 giu 2013 18:26:16

Non sono sicuro di cosa stia succedendo, perché passare new Walker_Nav_Menu dovrebbe comportarsi esattamente come non passare un walker. C'è qualcos'altro che sta accadendo, qualche plugin che aggancia o manipola la funzionalità del menu?

Rarst Rarst
16 giu 2013 18:27:39

Ho appena eseguito ulteriori test e sono sicuro che si tratti di un bug di WordPress. Nel mio caso, il menu di navigazione che ho utilizzato non era assegnato nel backend. Pertanto è stato utilizzato il fallback delle pagine elencate, sembra che in quel caso la variabile args sia un array. Ora traccerò questo problema alla fonte, poi ti dirò cosa ho scoperto.

Rudolf Rudolf
16 giu 2013 18:40:24

Se assegno correttamente un menu, funziona!

Rudolf Rudolf
16 giu 2013 18:40:42

Inizialmente non avevo visto la risposta qui sotto, guarda lì per la soluzione.

Rudolf Rudolf
16 giu 2013 18:59:11

Ho provato if(wp_nav_menu()) e il codice funziona.

User User
1 set 2015 09:59:09

Ti rendi conto che questa domanda ha due anni? :D Ma ho creato un ticket qui: https://core.trac.wordpress.org/ticket/24587 Non è ancora stato risolto però, quindi sentiti libero di discuterne lì!

Rudolf Rudolf
1 set 2015 17:15:05
Mostra i restanti 3 commenti
Tutte le risposte alla domanda 2
5
21

Ricevo questo errore quando non sono definiti menu o nessun menu è impostato per la posizione in Aspetto->Menu. Quando ciò accade, wp_nav_menu utilizza un fallback con page walker.

  1. Il fallback (predefinito) per wp_nav_menu è wp_walker_page
  2. che utilizza wp_page_menu
  3. che utilizza wp_list_pages
  4. che utilizza walk_page_tree
  5. che utilizza Walker_Page e non Walker_Nav_Menu.

E apparentemente i due walker non sono compatibili. Non so perché non fallisca in modo elegante. Mi sembra un bug.

Con un menu impostato in wp-admin->Aspetto->Menu, il tuo codice funziona.

Puoi evitare l'errore verificando che ci sia un menu assegnato alla posizione prima di provare a utilizzarla.

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

Oppure, se preferisci un codice meno "antistaminico" (grazie @Rarst):

if (has_nav_menu('primary')) {
  wp_nav_menu( array(
      'theme_location' => 'primary',
      'walker'         => new Walker_Nav_Menu_With_Aria,
  ) );
}
16 giu 2013 17:05:02
Commenti

Il fallback viene utilizzato solo quando tutto il resto fallisce nel visualizzare le pagine. Se il menu funziona correttamente, gli elementi vengono attraversati con walk_nav_menu_tree() che utilizza Walker_Nav_Menu di default.

Rarst Rarst
16 giu 2013 17:57:40

Ottimo aggiornamento! Non mi era venuto in mente che la funzione sbagliata potesse prendere il walker (è un po' meh). Inoltre c'è has_nav_menu() per quel controllo.

Rarst Rarst
16 giu 2013 18:34:35

È esattamente quello che stavo per postare :D Gli $args del menu di navigazione vengono convertiti in un oggetto in wp-includes/nav-menu-template.php alla riga 145 dalla funzione wp_nav_menu(). La funzione wp_page_menu() che viene usata come fallback non fa questo, ma passa semplicemente l'array al Walker del menu di navigazione che invece ha bisogno dell'oggetto.

Se aggiungi semplicemente un $args = (object) $args all'inizio della funzione start_el della classe Walker, puoi risolvere il problema. Quale sarebbe il posto giusto per segnalare questo al team di WordPress?

Rudolf Rudolf
16 giu 2013 18:57:34

I bug del core dovrebbero essere segnalati su http://core.trac.wordpress.org/

Rarst Rarst
16 giu 2013 19:00:40

L'oggetto WP_Post che viene passato come $item è diverso (Per questo motivo, le pagine non hanno nomi e la lista consiste solo di elementi <li> vuoti). Sarebbe necessario un serio refactoring per rendere questi due walker compatibili.

Rudolf Rudolf
16 giu 2013 19:04:43
0

utilizza il codice seguente per riparare:

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;
}
21 ago 2017 03:37:06