Mettre en surbrillance wp_nav_menu () Classe d'ancêtre sans enfants dans la structure de navigation?

30

( Note des modérateurs: elle était initialement intitulée "wp_nav_menu Ancestor class without children in navigation structure")

J'ai un wp_nav_menuen-tête qui contient trois pages. Quand je suis sur l'une de ces pages, le licontenant cette page dans le menu obtient la classe .current_page_item. Ces trois pages ont des modèles et ces modèles contiennent des requêtes personnalisées pour obtenir toutes les publications d'un certain type de contenu. En effet, les "enfants" perçus de cette page de niveau supérieur ne sont pas réellement des enfants, ils sont simplement d'un type de contenu que j'ai associé à cette page de niveau supérieur à l'aide d'un modèle.

J'aimerais que les éléments de menu de niveau supérieur obtiennent une 'current-ancestor'classe lorsque l'utilisateur parcourt une seule page d'un type de message spécifique, encore une fois, associé à cette page uniquement dans une requête personnalisée dans le fichier de modèle.

J'espère que cela a du sens - sinon, faites-moi savoir où je vous ai perdu! J'apprécie beaucoup toute aide.

- Modifié pour les détails: Par exemple, j'ai une page statique appelée Ateliers qui utilise un modèle. Sa limace est des ateliers . Le modèle possède une fonction get_posts personnalisée et une boucle à l'intérieur, qui extrait et affiche tous les messages d'un type de contenu personnalisé appelé ateliers . Si je clique sur l'un des titres de ces ateliers, je suis amené au contenu complet de ce morceau de contenu. La structure de permalien du type de message personnalisé est définie sur workshops / postname, de sorte que l'utilisateur le voit, ces éléments de contenu sont des enfants de la page Ateliers, alors qu'en réalité ils sont tous d'un type de contenu mais sans rapport avec la page. C'est cette lacune que je dois combler efficacement dans le menu, en mettant en évidence l'élément de menu «Ateliers» lors de la navigation dans le contenu de type «atelier».

Encore une fois, j'espère que cela a du sens, je pense que j'ai dit «atelier» plus de 20 fois dans un paragraphe!

Gavin
la source
@Gavin - Pouvez-vous inclure quelques détails supplémentaires sur ce que vous essayez d'accomplir. Il est plus facile d'écrire une réponse en termes concrets que si nous essayons de le faire dans l'abstrait. De plus, si vous pouviez expliquer votre structure d'URL liée à ces derniers, il serait utile.
MikeSchinkel du
1
@Gavin - Cela aide. Donc, votre option de menu de niveau supérieur est une liste d'ateliers dans "Ateliers" avec un chemin d'accès /workshops/et lorsqu'un utilisateur se trouve sur une page d'atelier (c'est-à-dire /workshops/example-workshop/) vous voulez que l' élément de menu "Ateliers" ait la classe current_page_itemassignée, n'est-ce pas?
MikeSchinkel
wp_nav_menu () expose la classe des ancêtres du menu actuel
Daniel Sachs

Réponses:

29

Il existe une solution plus simple. Oubliez la création de pages pour chaque type de publication afin que vous puissiez avoir des éléments de navigation, car comme vous l'avez appris, WP n'a aucun moyen de reconnaître que les types personnalisés que vous parcourez sont liés à cette page.

Créez plutôt un lien personnalisé dans Apparence-> Menus. Mettez simplement l'URL qui renverra votre type personnalisé et donnez-lui une étiquette, puis appuyez sur "Ajouter au menu".

http://example.com/workshops/

ou non-jolis permaliens:

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

cela seul créera simplement un bouton de navigation qui affiche toutes les publications avec ce type de publication personnalisé, et ajoutera également la classe d'élément de menu en cours lorsque vous aurez cliqué sur cet élément de navigation - mais il n'ajoutera pas encore la classe de navigation sur aucune URL autre que celle-ci

Ensuite, une fois qu'il est créé, accédez à la configuration de ce nouvel élément et entrez le slug du type de publication personnalisé dans le champ "Attribut de titre" (vous pouvez également utiliser le champ de description, mais celui-ci est masqué dans les options de l'écran d'administration par défaut).

Maintenant, vous devez accrocher le nav_menu_css_class filtre (qui se déclenche pour chaque élément de navigation) et vérifier si le contenu affiché est du type de message indiqué dans votre élément de navigation personnalisé:

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

Dans ce cas, nous allons vérifier que le contenu du champ Attribut de titre n'est pas vide et s'il correspond au post_type actuel interrogé. Si c'est le cas, nous ajoutons la classe d'élément de menu en cours à son tableau de classes, puis retournons le tableau modifié.

Vous pouvez le modifier pour qu'il corresponde simplement au titre de l'élément de navigation, mais si, pour une raison quelconque, vous souhaitez titrer l'élément de navigation différemment du slug ordinaire du type de publication, l'utilisation du champ Attribut de titre ou Description vous donne cette flexibilité.

Maintenant, chaque fois que vous consultez un seul élément (ou probablement même des listes d'archives) d'un type de publication qui correspond à un élément du menu nav, cet élément se verra attribuer l'élément de menu actuel de la classe CSS afin que votre mise en évidence fonctionne.

Aucune page ou modèle de page nécessaire ;-) La requête URL se charge de récupérer les bons messages. Votre modèle de boucle prend soin d'afficher la sortie de la requête. Cette fonction prend soin de reconnaître ce qui est affiché et d'ajouter la classe CSS.

PRIME

Vous pouvez même automatiser le processus en utilisant wp_update_nav_menu_itemdes éléments de menu générés automatiquement pour tous vos types de publication. Pour cet exemple, vous devez d'abord avoir récupéré le $menu_idmenu de navigation auquel vous souhaitez ajouter ces éléments.

$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'
        )
    );
}
somatique
la source
C'est le truc! J'utilise des modèles de page uniquement parce que les mises en page sont assez complexes pour ces pages et ne font pas que répertorier les pages, mais je peux toujours utiliser le filtre que vous avez fourni pour vérifier l'ID de la page. La nature de ce thème est que les options de thème vous permettent de faire correspondre les pages ('home' est cette page, 'about' est cette page, etc.), donc cela devrait fonctionner parfaitement. Merci pour l'aide (incroyablement détaillée)!
Gavin
j'ai dû retirer le current_page_parentde l'élément de navigation qui était mon blog - mais sinon cela a fonctionné. thx
pkyeck
cela ne fonctionnait pas pour moi, car j'ai $item->attr_titleretiré le TITRE, et j'ai écrit le titre en majuscules. j'ai donc changé l'attribut en $item->post_nameet maintenant ça marche bien pour moi.
honk31
J'ai essayé de faire fonctionner le code pour mon thème, mais je ne peux pas le faire fonctionner. Il n'y aura aucune classe appliquée à mon élément parent dans le menu, lorsque je suis sur le type de publication personnalisé portfolio. J'ai utilisé le code ci-dessus. Quel peut être le problème?
Casper
4

à la place d'utiliser

$ post_type = get_query_var ('post_type');

Vous voudrez peut-être essayer:

$ post_type = get_post_type ();

Comme parfois le type de publication n'est pas défini dans la requête var. C'est le cas pour le post_type par défaut de "post", donc si vous voulez mettre en surbrillance un post qui a été répertorié à partir d'une page de liste, vous devrez l'utiliser. get_very_var () renvoie simplement une chaîne vide pour les types de publication qui ne sont pas personnalisés.

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
la source
2

@Somatic - c'est fantastique! J'ai un peu modifié votre code afin qu'il fonctionne également pour une taxonomie spécifique (que j'utilise uniquement pour le post_type associé). L'idée est d'utiliser l'attribut Title de l'élément de menu pour stocker à la fois le nom du post_type ET le nom de la taxonomie, séparés par un point-virgule, puis éclatés par la fonction.

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
la source
2

Voici ma solution si vous souhaitez travailler avec wp_list_pages.

ajoutez ceci dans votre functions.php

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

Maintenant, ajoutez simplement dans la table wp_options une nouvelle ligne avec un option_name de page_for_custom_post_type-xxxx et une option_value avec l' ID de page que vous souhaitez connecter.

Vous avez peut-être reconnu qu'il existe déjà une option appelée page_for_posts . Si vous n'avez qu'un seul type de message personnalisé, vous pouvez définir votre page sur /wp-admin/options-reading.php dans la liste déroulante et la navigation définira correctement la page actuelle.

Je pense que WordPress Core devrait étendre cette section avec une liste déroulante pour chaque type de message enregistré.

Temo
la source
2

J'ai décidé de m'en tenir aux pages et d'utiliser le nom du modèle de page en tant que classe sur l'élément de navigation. Cela me permet d'éviter d'encombrer l'attribut title que je n'aimais pas dans certaines des autres solutions.

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

J'ai également ajouté des classes de corps à header.php

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

Enfin, cette solution nécessite quelques CSS supplémentaires pour appliquer l'état sélectionné / actif à vos éléments de menu de navigation. Je l'utilise pour afficher les archives de taxonomie et les types de messages personnalisés liés à la page en tant qu'enfants de cette page:

/* 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
la source
Cela m'a donné l'erreur suivante: Warning: join() [function.join]: Invalid arguments passed in /home/path/to/wp-includes/nav-menu-template.php on line 76 une idée de ce qui s'est passé ici?
Jeff K.
Oh je pense que je vois ce qui se passe. C'est parce que vous retournez $ classes dans l'instruction if. Déplacer simplementreturn $classes extérieur et après cela ifsemble résoudre l'erreur ci-dessus.
Jeff K.
1

@Somatic - Great code! J'ai fait un changement moi-même. Je voulais conserver l'attribut de titre pour sa destination, j'ai donc placé le slug Custom Post Type dans les propriétés de menu avancées de la relation de lien (XFN) que vous pouvez activer dans les options d'écran. j'ai modifié

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

et l'a changé en

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

Beau travail somatique.

Malheureusement, je ne sais pas comment vous pouvez répertorier vos types de messages personnalisés dans une page comme vous l'expliquez. Si je n'utilise pas de page-portfolio.php et que je ne l'ajoute pas à une page, tout ce que j'obtiens c'est 404 page.

Si j'aime Gavin, j'ai modifié votre fonction pour supprimer également le "current_page_parent" de la page de blog comme celle-ci.

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
la source