Adicione uma última classe ao último li em cada ul.sub-menu

4

Eu vi um monte de código sobre como adicionar uma classe first e last a um menu WordPress, mas no meu exemplo eu gostaria de adicionar uma classe last ao último li no sub -menu que o WP gera. Aqui está o que eu gostaria de alcançar em sua forma mais simples.

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

E aqui está o que eu tenho atualmente, que adiciona as primeiras e últimas classes apenas aos itens de menu pai. Isso poderia ser adaptado?

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');

Eu gostaria de ficar com php para isso e não usar :last-child (quer que funcione em ie7 & 8) ou jQuery.

    
por Andrew 14.04.2012 / 12:11

3 respostas

4

Coloque o seguinte no seu 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 );
    }
}

Uso

Onde você usa wp_nav_menu e deseja que a última classe seja adicionada, especifique o walker acima:

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

theme_location e depth podem ser o que você quiser, a parte importante é o atributo walker .

Observações secundárias

Esse código pode ser melhorado - potencialmente, desmarcando cada elemento na matriz $children_elements[$parent_id] quando ele é chamado e verificando quando está no último elemento (ou seja, quando ele contém apenas um elemento). Eu acho que wp_list_filter seria adequado aqui. Isso pode não melhorar a eficiência, mas pode ser mais puro.

Além disso, você pode codificar os campos pai e id - eu não fiz isso para portabilidade. A classe seguinte poderia estender qualquer uma das extensões fornecidas da Classe Walker (listas de páginas, listas de categorias, etc.).

    
por Stephen Harris 14.04.2012 / 13:32
3

O jQuery seria algo como isto;

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

} );

Mas quanto ao PHP, por favor dê uma olhada nesta resposta fornecida por Rarst AQUI e veja se isso ajuda você em tudo.

UPDATE

A solução

Rart 'do link acima faz o trabalho de fato e o snippet de código é;

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

A saída me deu algo assim:

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

O que significa que você pode estilizar seu elemento ul ul li por meio de seletores CSS com êxito.

    
por userabuser 14.04.2012 / 12:24
2

algo a considerar: enquanto o IE7 e o IE8 não suportam o último filho, eles suportam o primeiro filho. então, dependendo do CSS que você precisa aplicar de forma diferente ao último item, você pode reverter isso.

também, FWIW, seu tema já está usando o jQuery em outras áreas por padrão (seção de comentários, por exemplo), de modo que seria uma opção mais rápida e mais limpa.

    
por Norcross 14.04.2012 / 15:01