Hervorheben von wp_nav_menu () Vorfahrklasse ohne Kinder in der Navigationsstruktur?

30

( Hinweis für Moderatoren: Wurde ursprünglich mit "wp_nav_menu Vorfahrklasse ohne untergeordnete Elemente in der Navigationsstruktur" betitelt.)

Ich habe einen wp_nav_menuin meinem Header, der drei Seiten enthielt. Wenn ich mich auf einer dieser Seiten libefinde, erhält die Seite, die diese Seite im Menü enthält, die Klasse .current_page_item. Diese drei Seiten haben Vorlagen, und diese Vorlagen enthalten benutzerdefinierte Abfragen, um alle Beiträge eines bestimmten Inhaltstyps abzurufen. Tatsächlich sind die wahrgenommenen "Kinder" dieser Top-Level-Seite keine Kinder, sondern nur ein Inhaltstyp, den ich mithilfe einer Vorlage mit dieser Top-Level-Seite verknüpft habe.

Ich möchte, dass die Menüelemente der obersten Ebene eine 'current-ancestor'Klasse erhalten, wenn der Benutzer eine einzelne Seite eines bestimmten Beitragstyps durchsucht, der wiederum dieser Seite nur in einer benutzerdefinierten Abfrage in der Vorlagendatei zugeordnet ist.

Hoffe das macht Sinn - wenn nicht, lass es mich wissen, wo ich dich verloren habe! Sehr dankbar für jede Hilfe.

- Auf Besonderheiten hin bearbeitet: Ich habe zum Beispiel eine statische Seite namens Workshops , die eine Vorlage verwendet. Seine Schnecke sind Werkstätten . Die Vorlage enthält eine benutzerdefinierte Funktion get_posts und eine Schleife, in der alle Posts eines benutzerdefinierten Inhaltstyps namens workshops abgerufen und angezeigt werden . Wenn ich auf einen der Titel dieser Workshops klicke, werde ich zum vollständigen Inhalt dieses Inhaltsstücks weitergeleitet. Die Permalink-Struktur des benutzerdefinierten Beitragstyps ist auf workshops / postname festgelegtWie der Benutzer sieht, sind diese Inhalte untergeordnete Elemente der Seite "Workshops". In Wirklichkeit handelt es sich jedoch nur um einen Inhaltstyp, der nichts mit der Seite zu tun hat. Es ist diese Lücke, die ich effektiv im Menü schließen muss, um den Menüpunkt "Workshops" hervorzuheben, wenn ich Inhalte vom Typ "Workshop" durchsuche.

Ich hoffe wieder, das macht Sinn, ich glaube, ich habe in einem Absatz über 20 Mal 'Workshop' gesagt!

Gavin
quelle
@Gavin - Können Sie noch ein paar Details zu dem hinzufügen, was Sie erreichen möchten? Es ist einfacher, eine Antwort in konkreten Begriffen zu schreiben, als wenn wir versuchen, dies abstrakt zu tun. Auch wenn Sie Ihre URL-Struktur in Bezug auf diese erklären könnten, wäre es hilfreich.
MikeSchinkel 18.10.10
1
@Gavin - Das hilft. Ihre oberste Menüoption ist also eine Liste von Workshops unter "Workshops" mit einem Pfad von /workshops/und wenn sich ein Benutzer auf einer Workshop-Seite befindet (dh /workshops/example-workshop/) möchten Sie, dass dem Menüpunkt "Workshops" die Klasse current_page_itemzugewiesen wird, richtig?
MikeSchinkel
wp_nav_menu () macht die aktuelle Menü-Vorfahrenklasse verfügbar
Daniel Sachs

Antworten:

29

Es gibt eine einfachere Lösung. Vergessen Sie, Seiten für jeden Beitragstyp zu erstellen, damit Sie über Navigationselemente verfügen können, da WP, wie Sie gelernt haben, nicht erkennen kann, dass die benutzerdefinierten Typen, die Sie durchsuchen, mit dieser Seite zusammenhängen.

Erstellen Sie stattdessen einen benutzerdefinierten Link unter Darstellung-> Menüs. Geben Sie einfach die URL ein, die Ihren benutzerdefinierten Typ zurückgibt, und geben Sie ihr eine Bezeichnung. Drücken Sie dann auf "Zum Menü hinzufügen".

http://example.com/workshops/

oder non-pretty-permalinks:

http://example.com/?post_type=workshops

Dies allein erstellt einfach eine Navigationsschaltfläche, die alle Beiträge mit diesem benutzerdefinierten Beitragstyp anzeigt und die aktuelle Menüelementklasse hinzufügt, wenn Sie auf dieses Navigationselement geklickt haben. Die Navigationsklasse wird jedoch noch nicht hinzugefügt Andere URL als diese

Sobald es erstellt ist, gehen Sie in die Konfiguration für dieses neue Element und geben Sie den Slug des benutzerdefinierten Beitragstyps in das Feld "Titelattribut" ein (Sie können auch das Beschreibungsfeld verwenden, das jedoch in den Optionen des Administratorbildschirms ausgeblendet ist standardmäßig).

Jetzt müssen Sie den nav_menu_css_classFilter einbinden (der für jedes Navigationselement ausgelöst wird) und prüfen, ob der angezeigte Inhalt dem in Ihrem benutzerdefinierten Navigationselement angegebenen Beitragstyp entspricht:

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
    $post_type = get_query_var('post_type');
    if ($item->attr_title != '' && $item->attr_title == $post_type) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}

In diesem Fall überprüfen wir, ob der Inhalt des Felds Titelattribut nicht leer ist und mit dem aktuell abgefragten post_type übereinstimmt. In diesem Fall fügen wir die aktuelle Menüelementklasse zu ihrem Klassenarray hinzu und geben das geänderte Array zurück.

Sie können dies so ändern, dass es einfach mit dem Titel des Navigationselements übereinstimmt. Wenn Sie das Navigationselement jedoch aus irgendeinem Grund anders als die einfache Überschrift des Beitragstyps benennen möchten, erhalten Sie diese Flexibilität, wenn Sie das Feld Titelattribut oder Beschreibung verwenden.

Jedes Mal, wenn Sie ein einzelnes Element (oder möglicherweise sogar Archivlisten) eines Beitragstyps anzeigen, der mit einem Navigationsmenüelement übereinstimmt, wird diesem Element die CSS-Klasse current-menu-item zugewiesen, damit Ihre Hervorhebung funktioniert.

Keine Seiten oder Seitenvorlagen erforderlich ;-) Die URL-Abfrage sorgt dafür, dass die richtigen Beiträge abgerufen werden. Ihre Schleifenvorlage kümmert sich um die Anzeige der Abfrageausgabe. Diese Funktion erkennt, was angezeigt wird, und fügt die CSS-Klasse hinzu.

BONUS

Sie können den Prozess mithilfe wp_update_nav_menu_itemvon sogar automatisieren , indem Sie Menüelemente für alle Ihre Beitragstypen automatisch generieren lassen. In diesem Beispiel müssen Sie zuerst $menu_iddas Navigationsmenü abrufen, zu dem diese Elemente hinzugefügt werden sollen.

$types = get_post_types( array( 'exclude_from_search' => false, '_builtin' => false  ), 'objects' );
foreach ($types as $type) {
    wp_update_nav_menu_item( $menu_id, 0, array(
        'menu-item-type' => 'custom',
        'menu-item-title' => $type->labels->name,
        'menu-item-url' => get_bloginfo('url') . '/?post_type=' . $type->rewrite['slug'],
        'menu-item-attr-title' => $type->rewrite['slug'],
        'menu-item-status' => 'publish'
        )
    );
}
somatisch
quelle
Das ist das Zeug! Ich verwende nur Seitenvorlagen, da die Layouts für diese Seiten recht komplex sind und nicht nur die Seiten auflisten. Ich kann den von Ihnen angegebenen Filter jedoch weiterhin zum Überprüfen der Seiten-ID verwenden. Die Art dieses Themas besteht darin, dass Sie mit den Themenoptionen Seiten abgleichen können ('home' ist diese Seite, 'about' ist diese Seite usw.), damit dies perfekt funktioniert. Vielen Dank für die (unglaublich ausführliche) Hilfe!
Gavin
Ich musste das current_page_parentaus dem Navigationselement entfernen, das mein Blog war - aber ansonsten funktionierte es. thx
pkyeck
das hat bei mir nicht geklappt, da $item->attr_titleder titel rausgezogen wurde und ich den titel in großbuchstaben geschrieben habe. Also habe ich das Attribut auf geändert $item->post_nameund jetzt funktioniert es gut für mich.
Honk31
Ich habe versucht, den Code für mein Thema zum Laufen zu bringen, kann ihn aber nicht zum Laufen bringen. Es wird keine Klasse auf mein übergeordnetes Element im Menü angewendet, wenn ich mich im benutzerdefinierten Beitragstyp befinde portfolio. Ich habe den obigen Code verwendet. Woran kann das liegen?
Casper
4

anstatt zu verwenden

$ post_type = get_query_var ('post_type');

Vielleicht möchten Sie versuchen:

$ post_type = get_post_type ();

Da manchmal der Beitragstyp nicht in der Abfragevariable festgelegt ist. Dies ist der Fall für den Standard-Beitragstyp "Beitrag". Wenn Sie also einen Beitrag markieren möchten, der auf einer Auflistungsseite aufgelistet wurde, müssen Sie diesen verwenden. get_very_var () gibt nur eine leere Zeichenfolge für nicht benutzerdefinierte Beitragstypen zurück.

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
    $post_type = get_post_type();
    if ($item->attr_title != '' && $item->attr_title == $post_type) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}
Eric
quelle
2

@Somatic - das ist fantastisch! Ich habe Ihren Code ein wenig geändert, damit er auch für eine bestimmte Taxonomie funktioniert (die ich nur für den zugehörigen post_type verwende). Die Idee ist, das Title-Attribut des Menüelements zu verwenden, um sowohl den Namen des post_type als auch den Namen der Taxonomie zu speichern, die durch ein Semikolon getrennt und dann von der Funktion aufgelöst werden.

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {

    # get Query Vars
    $post_type = get_query_var('post_type');  
    $taxonomy = get_query_var('taxonomy');

    # get and parse Title attribute of Menu item
    $title = $item->attr_title; // menu item Title attribute, as post_type;taxonomy
    $title_array = explode(";", $title);
    $title_posttype = $title_array[0];
    $title_taxonomy = $title_array[1];

    # add class if needed
    if ($title != '' && ($title_posttype == $post_type || $title_taxonomy == $taxonomy)) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}
tzeldin88
quelle
2

Hier meine Lösung, wenn Sie mit wp_list_pages arbeiten möchten.

füge dies in deine functions.php ein

add_filter('page_css_class', 'my_page_css_class', 10, 2);
function my_page_css_class($css_class, $page){
    $post_type = get_post_type();
    if($post_type != "page"){
        $parent_page = get_option('page_for_custom_post_type-'.$post_type);
        if($page->ID == $parent_page)
            $css_class[] = 'current_page_parent';
    }
    return $css_class;
}

Nun fügen Sie einfach in wp_options Tabelle eine neue Zeile mit einem option_name von page_for_custom_post_type-xxxx und einem option_value mit der Seite-ID u verbinden möchten.

Vielleicht haben Sie erkannt, dass es bereits eine Option namens page_for_posts gibt . Wenn Sie nur einen benutzerdefinierten Beitragstyp haben, können Sie Ihre Seite in der Dropdown-Liste auf /wp-admin/options-reading.php einstellen, und die Navigation stellt die aktuelle Seite korrekt ein.

Ich denke, WordPress Core sollte diesen Abschnitt mit einem Dropdown für jeden registrierten Beitragstyp erweitern.

Temo
quelle
2

Ich beschloss, bei den Seiten zu bleiben und den Namen der Seitenvorlage als Klasse für das Navigationselement zu verwenden. Auf diese Weise kann ich vermeiden, dass das title-Attribut unübersichtlich wird, was mir bei einigen anderen Lösungen nicht gefallen hat.

add_filter('nav_menu_css_class', 'mbudm_add_page_type_to_menu', 10, 2 );
//If a menu item is a page then add the template name to it as a css class 
function mbudm_add_page_type_to_menu($classes, $item) {
    if($item->object == 'page'){
        $template_name = get_post_meta( $item->object_id, '_wp_page_template', true );
        $new_class =str_replace(".php","",$template_name);
        array_push($classes, $new_class);
        return $classes;
    }   
}

Ich habe auch Body-Klassen zu header.php hinzugefügt

<body <?php body_class(); ?>>

Schließlich erfordert diese Lösung einige zusätzliche CSS, um den ausgewählten / aktiven Status auf Ihre Navigationsmenüelemente anzuwenden. Ich verwende es, um Taxonomiearchive und benutzerdefinierte Beitragstypen, die mit der Seite zusammenhängen, als untergeordnete Elemente dieser Seite anzuzeigen:

/* selected states - include sub pages for anything related to products */
#nav-main li.current-menu-item a,
body.single-mbudm_product #nav-main li.lp_products a,
body.tax-mbudm_product_category #nav-main li.lp_products a,
#nav-main li.current_page_parent a{color:#c00;}
Steve
quelle
Dies gab mir den folgenden Fehler: Warning: join() [function.join]: Invalid arguments passed in /home/path/to/wp-includes/nav-menu-template.php on line 76 Irgendeine Idee, was hier passiert ist?
Jeff K.
Oh ich glaube ich sehe was passiert. Dies liegt daran, dass Sie $ classes in der if-Anweisung zurückgeben. Einfach nach return $classesdraußen gehen und danach ifscheint der obige Fehler behoben zu sein.
Jeff K.
1

@Somatic - Großartiger Code! Ich habe selbst eine Änderung vorgenommen. Ich wollte das Title-Attribut für den beabsichtigten Zweck beibehalten, also platzierte ich stattdessen den Slug "Benutzerdefinierter Beitragstyp" in den erweiterten Menüeigenschaften "Link Relationship" (XFN), die Sie in den Bildschirmoptionen aktivieren können. ich veränderte

if ($item->attr_title != '' && $item->attr_title == $post_type) {

und änderte es zu

if ($item->xfn != '' && $item->xfn == $post_type) {
user8899
quelle
0

Gute Arbeit, Somatic.

Leider verstehe ich nicht, wie Sie Ihre benutzerdefinierten Beitragstypen auf einer Seite so auflisten können, wie Sie es erklären. Wenn ich eine page-portfolio.php nicht verwende und sie einer Seite hinzufüge, erhalte ich nur eine 404-Seite.

Wenn ich es wie Gavin tue, habe ich deine Funktion ein wenig verändert, um auch "current_page_parent" von der Blog-Seite wie dieser zu entfernen.

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2);
function current_type_nav_class($css_class, $item) {
$post_type = get_query_var('post_type');

if (get_post_type()=='portfolio') {
    $current_value = "current_page_parent"; 
    $css_class = array_filter($css_class, function ($element) use ($current_value) { return ($element != $current_value); } );
}

if ($item->attr_title != '' && $item->attr_title == $post_type) {       
    array_push($css_class, 'current_page_parent');
};
return $css_class;

}

Vayu
quelle