Beschreibung der Menüpunkte? Benutzerdefinierter Walker für wp_nav_menu ()

104

Das normale Wordpress-Menü sieht folgendermaßen aus:

Startseite | Blog | Über uns | Kontakt

Aber ich habe viele Seiten mit Beschreibungen unter diesen Links gesehen:

Startseite | Unsere Blogs | Über uns | Kontakt
.... treffen Sie uns ... | lesen Sie mehr | grundlegende info | Kontakt Formular

Wie kann man das erreichen?

(Ich möchte, dass es die Kernfunktion für alle meine Themen ist, also bitte keine Plugins, ich möchte nur wissen, wie es gemacht wird.)

Wordpressor
quelle

Antworten:

115

Sie benötigen einen benutzerdefinierten Walker für das Navigationsmenü.

Grundsätzlich fügen Sie 'walker'den wp_nav_menu()Optionen einen Parameter hinzu und rufen eine Instanz einer erweiterten Klasse auf:

wp_nav_menu(
    array (
        'menu'            => 'main-menu',
        'container'       => FALSE,
        'container_id'    => FALSE,
        'menu_class'      => '',
        'menu_id'         => FALSE,
        'depth'           => 1,
        'walker'          => new Description_Walker
    )
);

Die Klasse Description_Walkererweitert Walker_Nav_Menuund ändert die start_el( &$output, $item, $depth, $args )zu suchende Funktion $item->description.

Ein einfaches Beispiel:

/**
 * Create HTML list of nav menu items.
 * Replacement for the native Walker, using the description.
 *
 * @see    https://wordpress.stackexchange.com/q/14037/
 * @author fuxia
 */
class Description_Walker extends Walker_Nav_Menu
{
    /**
     * Start the element output.
     *
     * @param  string $output Passed by reference. Used to append additional content.
     * @param  object $item   Menu item data object.
     * @param  int $depth     Depth of menu item. May be used for padding.
     * @param  array|object $args    Additional strings. Actually always an 
                                     instance of stdClass. But this is WordPress.
     * @return void
     */
    function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 )
    {
        $classes     = empty ( $item->classes ) ? array () : (array) $item->classes;

        $class_names = join(
            ' '
        ,   apply_filters(
                'nav_menu_css_class'
            ,   array_filter( $classes ), $item
            )
        );

        ! empty ( $class_names )
            and $class_names = ' class="'. esc_attr( $class_names ) . '"';

        $output .= "<li id='menu-item-$item->ID' $class_names>";

        $attributes  = '';

        ! empty( $item->attr_title )
            and $attributes .= ' title="'  . esc_attr( $item->attr_title ) .'"';
        ! empty( $item->target )
            and $attributes .= ' target="' . esc_attr( $item->target     ) .'"';
        ! empty( $item->xfn )
            and $attributes .= ' rel="'    . esc_attr( $item->xfn        ) .'"';
        ! empty( $item->url )
            and $attributes .= ' href="'   . esc_attr( $item->url        ) .'"';

        // insert description for top level elements only
        // you may change this
        $description = ( ! empty ( $item->description ) and 0 == $depth )
            ? '<small class="nav_desc">' . esc_attr( $item->description ) . '</small>' : '';

        $title = apply_filters( 'the_title', $item->title, $item->ID );

        $item_output = $args->before
            . "<a $attributes>"
            . $args->link_before
            . $title
            . '</a> '
            . $args->link_after
            . $description
            . $args->after;

        // Since $output is called by reference we don't need to return anything.
        $output .= apply_filters(
            'walker_nav_menu_start_el'
        ,   $item_output
        ,   $item
        ,   $depth
        ,   $args
        );
    }
}

Alternativ können Sie, wie @nevvermind kommentierte , alle Funktionen der übergeordneten Funktion erbenstart_el und die Beschreibung einfach an Folgendes anhängen$output :

function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) 
{
    parent::start_el( $output, $item, $depth, $args );
    $output .= sprintf( 
        '<i>%s</i>', 
        esc_html( $item->description ) 
    );
}

Beispielausgabe:

Bildbeschreibung hier eingeben

Aktivieren Sie nun das Beschreibungsfeld in wp-admin/nav-menus.php, um dieses Feld bearbeiten zu können. Wenn Sie nicht über WP verfügen, wird der gesamte Inhalt des Posts in den Papierkorb verschoben.

Bildbeschreibung hier eingeben

Weitere Lektüre:

Und das ist es.

fuxia
quelle
11
Wenn für Sie die Vererbung! = Schreiben Sie die gesamte Methode um, behalten Sie einfach den gleichen Namen und versuchen Sie public function start_el(&$output, $item, $depth, $args) { parent::start_el($output, $item, $depth, $args); $output .= sprintf('<i>%s</i>', esc_html($item->description)); }
Folgendes
2
@nevvermind Sie sollten zumindest prüfen, ob die Beschreibung Inhalt hat. ;) Die Position der Beschreibung in meinem Beispielcode ist nur der einfachste Weg, um die Lösung zu veranschaulichen. Wenn Sie die Beschreibung in den Anker erhalten müssen, Sie haben , um die ganze Funktion wieder aufzubauen.
fuxia
1
Ja, Sie müssten die ganze Methode schreiben, kein Zweifel, aber für Leute, die sie (sagen wir mal ...) anhängen müssen, könnte es ihnen einfach eine Menge Kopfschmerzen ersparen. Und das ist alles die Schuld von WP. Arrrgh!
nevvermind
Nizza, und ich habe es in dieser Antwort verwendet, indem ich ein wenig geändert habe. Vielleicht können Sie es verbessern, wenn ich etwas verpasst habe, danke.
Die Alpha
Was ich tatsächlich brauchte, war das wp_nav_menu , aber ich musste den 'container_class'-Parameter ändern, um für meinen speziellen Anwendungsfall zu funktionieren, in dem ich unter bestimmten Bedingungen das Hauptmenü gegen ein anderes ausgetauscht habe, aber die Klassen für CSS konsistent sein mussten.
D. Dan
33

Seit WordPress 3.0 benötigen Sie keinen benutzerdefinierten Walker mehr!

Dort befindet sich der walker_nav_menu_start_elFilter, siehe https://developer.wordpress.org/reference/hooks/walker_nav_menu_start_el/

Beispiel:

function add_description_to_menu($item_output, $item, $depth, $args) {
    if (strlen($item->description) > 0 ) {
        // append description after link
        $item_output .= sprintf('<span class="description">%s</span>', esc_html($item->description));

        // insert description as last item *in* link ($input_output ends with "</a>{$args->after}")
        //$item_output = substr($item_output, 0, -strlen("</a>{$args->after}")) . sprintf('<span class="description">%s</span >', esc_html($item->description)) . "</a>{$args->after}";
    }

    return $item_output;
}
add_filter('walker_nav_menu_start_el', 'add_description_to_menu', 10, 4);
Joost
quelle
1
Nett! Ich habe die Navi-Walker-Lösung von @toscho verwendet, diese ist jedoch viel sauberer und einfacher zu warten. Dies sollte die akzeptierte Antwort sein, eine viel bessere Vorgehensweise.
Neejoh
8

Dies ist nicht besser oder schlechter als andere Vorschläge; es ist einfach anders. Es ist auch kurz und süß.

Anstatt das Beschreibungsfeld wie von @toscho vorgeschlagen zu verwenden , können Sie das Feld "Titel" für jeden Menüeintrag mit dem gewünschten Text füllen und dann das folgende CSS verwenden:

.menu-item a:after { content: attr(title); }

Es wäre auch einfach, jQuery zum Anhängen zu verwenden, aber der Text ist so dekorativ, dass CSS angemessen erscheint.

mrwweb
quelle
2

Sie können auch ein <span>Element nach der Navigationsbezeichnung in Menüs schreiben und die displayEinstellung mithilfe der folgenden CSS-Regel ändern ( inlinestandardmäßig):

span {display:block}
Markus
quelle
2
Nun, es ist eine einfache und einfache Lösung, aber warum spansollte man sie verwenden, wenn man sie trotzdem blockieren lässt? xhtml / html4 nicht erlaubt im Inneren Links Blockelemente, html5 jedoch der Fall ist, so benutzen Sie einfach div, und keine Notwendigkeit für eine CSS!
James Mitch