web-dev-qa-db-fra.com

Ajouter une classe .last au dernier <li> dans chaque ul.sous-menu

J'ai vu beaucoup de code sur la façon d'ajouter une classe first et last à un menu WordPress, mais dans mon cas, j'aimerais ajouter une classe last à la dernière li du sous-menu qui WP génère. Voici ce que je voudrais réaliser sous sa forme la plus simple.

<ul>
    <li>Menu item one</li>
    <li class="has-sub-menu">Menu item two
        <ul class="sub-menu">
            <li>Sub menu item one</li>
            <li>Sub menu item two</li>
            <li class="last">Sub menu item three</li>
        </ul>
    </li>
    <li>Menu item three</li>
</ul>

Et voici ce que j'ai actuellement, qui ajoute la première et la dernière classe uniquement aux éléments de menu parent. Cela pourrait-il être adapté?

function add_first_and_last($items) {
    $items[1]->classes[] = 'first';
    $items[count($items)]->classes[] = 'last';
    return $items;
}

add_filter('wp_nav_menu_objects', 'add_first_and_last');

Je voudrais rester avec php pour cela et ne pas utiliser ni :last-child (le veux que cela fonctionne dans ie7 & 8) ni jQuery.

4
Andrew

Mettez ce qui suit dans votre functions.php

class SH_Last_Walker extends Walker_Nav_Menu{

   function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {

        $id_field = $this->db_fields['id'];

       //If the current element has children, add class 'sub-menu'
       if( isset($children_elements[$element->$id_field]) ) { 
            $classes = empty( $element->classes ) ? array() : (array) $element->classes;
            $classes[] = 'has-sub-menu';
            $element->classes =$classes;
       }
        // We don't want to do anything at the 'top level'.
        if( 0 == $depth )
            return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );

        //Get the siblings of the current element
        $parent_id_field = $this->db_fields['parent'];      
        $parent_id = $element->$parent_id_field;
        $siblings = $children_elements[ $parent_id ] ;

        //No Siblings?? 
        if( ! is_array($siblings) )
            return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );

        //Get the 'last' of the siblings.
        $last_child = array_pop($siblings);
        $id_field = $this->db_fields['id'];

            //If current element is the last of the siblings, add class 'last'
        if( $element->$id_field == $last_child->$id_field ){
            $classes = empty( $element->classes ) ? array() : (array) $element->classes;
            $classes[] = 'last';
            $element->classes =$classes;
        }

        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }
}

Usage

Si vous utilisez wp_nav_menu et que vous souhaitez ajouter la "dernière" classe, spécifiez le randonneur ci-dessus:

wp_nav_menu( array('theme_location'=>'primary','walker' => new SH_Last_Walker(),'depth' => 0) ); 

theme_location et depth peuvent être ce que vous voulez, la partie importante est l'attribut walker.

Remarques latérales

Ce code peut être amélioré - éventuellement en dé-définissant chaque élément du tableau $children_elements[$parent_id] lorsqu’il est appelé et en vérifiant qu’il ne reste plus que le dernier élément (c’est-à-dire s’il ne contient qu’un élément). Je pense que wp_list_filter conviendrait ici. Cela pourrait ne pas améliorer l'efficacité, mais pourrait être plus ordonné.

En outre, vous pouvez coder en dur les champs parent et id. Je ne l’ai pas fait pour des raisons de portabilité. La classe suivante pourrait être en mesure d'étendre n'importe laquelle des extensions fournies de la classe Walker (listes de pages, listes de catégories, etc.).

4
Stephen Harris

Le jQuery ressemblerait à quelque chose comme ça;

jQuery(document).ready( function($) {
    $('.sub-menu > li:last-child').addClass('last-item');

} );

Mais comme pour le PHP, jetez un coup d’œil à cette réponse fournie par Rarst ICI et voyez si cela vous aide vraiment.

METTRE À JOUR

La solution de Rart à partir du lien ci-dessus fonctionne-t-elle réellement et l'extrait de code est;

add_filter( 'wp_nav_menu_items', 'first_last_class' );

function first_last_class( $items ) {

    $first = strpos( $items, 'class=' );

    if( false !== $first )
         $items = substr_replace( $items, 'first ', $first+7, 0 );

    $last = strripos( $items, 'class=');

    if( false !== $last )
         $items = substr_replace( $items, 'last ', $last+7, 0 );

    return $items;
}

La sortie m'a donné quelque chose comme ça;

<ul>
    <li class="first">Menu item one</li>
    <li>Menu item two
        <ul class="sub-menu">
            <li class="first">Sub menu item one</li>
            <li>Sub menu item two</li>
            <li class="last">Sub menu item three</li>
        </ul>
    </li>
    <li class="last">Menu item three</li>
</ul>

Cela signifie que vous pouvez styliser votre élément ul ul li avec les sélecteurs CSS avec succès.

3
userabuser

quelque chose à considérer: bien que IE7 et IE8 ne supportent pas le dernier-enfant, ils soutiennent le premier-enfant. ainsi, selon le type de CSS à appliquer différemment au dernier élément, vous pouvez l’inverser.

de plus, FWIW, votre thème utilise déjà jQuery dans d'autres zones par défaut (section de commentaire, par exemple), ce qui en ferait une option plus rapide et plus propre.

2
Norcross