wp_nav_menu – Submenü dynamisch an beliebigen Menüpunkt hängen

Schaf mit zwei Lämmern
foto von julian hochgesang

Es sind gerne mal die kleinen Dinge, die einem am meisten Kopfzerbrechen bereiten. Im Fallbeispiel gabe es einen Inhaltstypen für Stellenangebote, der immer mal wieder über eine Importfunktion neu befüllt wird. Dem übergeordnet war eine Seite, mitten im Hauptmenü, und hier sollten automatisch die grade aktuellen Stellenangebote in einem Untermenü gelistet sein.

Ein Item hinten dran hängen, dafür kann man gut den wp_get_nav_menu_items filter bemühen, der die Menüpunkte als String zurückgibt. Doch wir wollten ja einen Menüpunkt irgendwo in der Mitte ansprechen.

Wegen eines Punkts den ganzen Walker umschreiben…? Dafür müsste ich mich auch um den Menüaufruf kümmern, damit der weiß, welchen Walker er nehmen muss. Über den wp_nav_menu_objects filter ein paar stdClass-Elemente dynamisch hinzufügen? Das wird spätestens dann zum Problem, wenn der post-status eines Items überprüft wird, oder sich herausstellt, dass das stdClass-Element keine WP_Post-Instanz ist.

Und woran erkennt man eigentlich „seinen“ Menüpunkt? …

Menüpunkt auffindbar machen

Klar hat jeder Menüpunkt seine individuelle ID. Doch je nach Umgebung (Wirkbetriebs-, Test- oder Entwicklungsumgebung) unterschied sich diese. So entschied ich mich für ein Datum, das sich durch eine Eingabe festlegen lässt. Der gesuchte Menüpunkt bekommt daher eine CSS-Klasse. Das macht man in den Design-Einstellungen unter Menü, lässt sich dort Ansicht anpassen anzeigen, und wählt unter Erweiterte Menüeigenschaften anzeigen mit einem Häkchen CSS-Klassen aus. Ansicht anpassen wieder schließen.

menu eigenschaften erweitert
Eingabefeld für CSS-Klassen bei Menüpunkten hinzufügen

Nun ins Menü der Wahl gehen, in unserem Beispiel ist es das Hauptmenü (primary). Dem Menüpunkt eine Klasse geben (zum Beispiel „karriere“).

menue punkt klasse festlegen

Das Menü speichern, und ggf. im Quellcode vergewissern, dass die Klasse vorhanden ist.

menue klasse pruefen
Mit „Element untersuchen“ prüfen, ob die Klasse für das Menüelement vorhanden ist

Das Jobmenü anlegen

Für den Fall, dass es keine Jobs gibt, soll die Funktion false zurückgeben. Der Hauptmenüpunkt soll ja nur zum Parent werden, wenn da wirklich was kommt.

function my_prefix_get_jobs_menu() {

    $args = array(
		'post_status'    => 'publish',
		'post_type'      => 'job',
		'fields'         => 'ids'
	);
    $items = get_posts( $args );

    if ( $items ) {
        $submenu = '<ul class="sub-menu">';
        foreach( $items as $post_id ) {
            $submenu .= sprintf( '<li class="menu-item"><a class="menu-link" href="%s">%s</a></li>', esc_url( get_permalink($post_id) ), esc_html( get_the_title($post_id) ) );
        }
        $submenu .= '</ul>';
        return $submenu;
    } 

    return false;
}

Das Untermenü anhängen

Statt einen neuen Walker zu schreiben, nutzen wir den Filter im Output der start_el-Funktion im original-Walker_Nav_Menu.

function my_prefix_menu_item_custom_output( $item_output, $item, $depth, $args ) {

    if ( $args->theme_location != 'primary' ) return $item_output;
 
    if ( empty( $item->classes ) || !in_array( 'karriere', $item->classes ) ) {
        return $item_output;
    }

    $item_output .= my_prefix_get_jobs_menu();
 
    return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'my_prefix_menu_item_custom_output', 10, 4 );

Die Elternklasse hinzufügen (optional)

Unser Menüpunkt hat von Natur aus ja keine Untermenüpunkte, daher fehlt ihm die entsprechende Klasse, vor der die meisten Menüs Hauptmenüpunkte kennzeichnen, sodass man auf einen Blick erkennt, dass darunter noch was kommt.

Im letzten Schritt wird dem Menüpunkt eine menu-item-has-children-Klasse hinzugefügt (die Klasse kann je nach Theme abweichen, daher vorher im Quellcode nachsehen, welche CSS-Klasse Elternelemente im Menü auszeichnet).

dynamisches sub menu
Kontrollblick ins DOM

Dieser Schritt ist optional, und in erster Linie kosmetischer Natur. Da der Link ja bereits eine eindeutig wiederzuerkennende Klasse hat, könnte er auch direkt danach via CSS angesprochen werden. In unserem Fall verwendet das Parent-Theme seinen eigenen Walker, und fügt allen Eltern-Elementen einen Dropdown-Bedienungs-Button für Mobiles hinzu. Durch das Hinzufügen der Klasse über den wp_nav_menu_objects-Filter bekam auch „unser“ Element alles, womit auch die anderen Eltern ausgestattet sind.

function my_prefix_add_menu_parent_class( $items, $args ) {

    if ( $args->theme_location != 'primary' || false === my_prefix_get_jobs_menu() ) return $items;

     foreach ( $items as &$item ) {
        
        if ( in_array( 'karriere', $item->classes ) ) {
            $item->classes[] = 'menu-item-has-children';
        }
    }
   
    return $items;
}
add_filter( 'wp_nav_menu_objects', 'my_prefix_add_menu_parent_class', 10, 3 );

Das geht mit allen Inhaltstypen die veröffentlicht sind, aber auch Kategorien, und sofern erwünscht, natürlich auch unter mehreren Menüpunkten, mit einer jeweils individuellen CSS-Klasse.

Bitte Kommentarfunktion nicht für Supportanfragen nutzen. Dem kann hier nicht entsprochen werden. Die Angabe einer E-Mail-Adresse und eines Namens ist nicht erforderlich. Einen (Spitz)-Namen zu nennen wäre aber doch nett.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Hinweis: Sowohl angegebener Name als auch E-Mail-Adresse (beides ist optional, dafür werden alle Kommentare vor Veröffentlichung geprüft) werden dauerhaft gespeichert. Du kannst jeder Zeit die Löschung Deiner Daten oder / und Kommentare einfordern, direkt über dieses Formular (wird nicht veröffentlicht, und im Anschluss gelöscht), und ich werde das umgehend erledigen. – Mit hinterlassenen Kommentaren hinterlegte IP-Adressen werden nach zwei Monaten automatisch gelöscht

publicly queryable