Adicionando a primeira / última classe CSS aos menus

15

isso é possível, sem hacks javascript? como isso:

<ul class="my_menu">
  <li class="first"> ... </li>
  <li> ... </li>
  <li> ... </li>
  <li class"with_sub"> ... 
    <ul class="my_menu_sub">
      <li class="first"> ... </li>
      <li> ... </li>
      <li> ... </li>
      <li class="last"> ... </li>
    </ul>
  </li>
  <li> ... </li>
  <li> ... </li>
  <li class="last"> ... </li>
</ul>
Alex
fonte
1
o que há de errado com o uso de javascript? é a funcionalidade principal para a qual servem? Ou poderia ser visto como um aprimoramento progressivo?
Mild Fuzz

Respostas:

14

Uma abordagem melhor e mais simples:

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

add_filter('wp_nav_menu_objects', 'add_first_and_last');
Ismaelj
fonte
1
Agradável e simples. Eu gosto disso!
Jonathan Wold
Vejo que esse código funciona para menus de navegação personalizados (vi que funcionava em um widget de menu personalizado), mas não está funcionando no mesmo menu usado na barra de navegação principal (testada no Twenty Eleven). Deveria ser? ou seria um código diferente? ou apenas um filtro diferente? Obrigado!
Evan Mattson
2
Isso funcionará para o menu de nível único, mas pode não ser para um menu mais complexo, porque neste momento é uma matriz com todos os itens, não os de nível superior.
Rarst 26/08/12
6

Aqui está um snippet aproximado que cuida da modificação da saída do menu e da adição da primeira / última à primeira e da última classe (o externo ulnão é aplicado nesse estágio, portanto, não conta). Nota - requer PHP5 parastrripos()

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

Estou um pouco preso em como fazê-lo lidar com listas aninhadas, mas você deve começar pelo menos.

Rarst
fonte
6

Aqui está uma função para adicionar apenas a primeira / a última classe aos itens de menu pai. Para a maioria dos estilos CSS, isso é tudo o que é necessário.

function nav_menu_add_classes( $items, $args ) {
    //Add first item class
    $items[1]->classes[] = 'menu-item-first';

    //Add last item class
    $i = count($items);
    while($items[$i]->menu_item_parent != 0 && $i > 0) {
        $i--;
    }
    $items[$i]->classes[] = 'menu-item-last';

    return $items;
}
add_filter( 'wp_nav_menu_objects', 'nav_menu_add_classes', 10, 2 );
Chaoix
fonte
1
Exatamente o que eu estava procurando. obrigado. é uma espécie de surpreender wp_nav_menu não faz isso automaticamente
yitwail
Concordo. Eu acredito que houve um pedido de recurso no bugtracker do Wordpress por um tempo, mas nada aconteceu. Pelo menos os filtros adequados existem para que possamos adicionar essas classes;).
Chaoix 7/11
1
Obrigado. Estava procurando o balcão, que poderia ser usado no menu walker. sua resposta permite isso. Acabamos de adicionar $ item-> number = $ i; e peguei no passeador. Obrigado!!!
BasTaller
5

Saiba mais sobre a nova API de menus no wordpress 3. Você pode atribuir a qualquer elemento sua própria classe manualmente. Além disso, uma vez dominado, torna os menus uma alegria para editar.

Fuzz leve
fonte
2
Esse seria o caminho a seguir: basta abrir a tela do menu de navegação no administrador e adicionar uma classe ao primeiro e ao último itens. Obviamente, se o usuário mover esses itens de menu, as classes precisarão ser redesignadas, mas essa é a resposta mais válida / melhor (porque não há código envolvido).
T31os
5

Se você possui menus aninhados

function add_first_and_last($items) {
    // first class on parent most level
    $items[1]->classes[] = 'first';
    // separate parents and children
    $parents = $children = array();
    foreach($items as $k => $item){
        if($item->menu_item_parent == '0'){
            $parents[] = $k;
        } else {
            $children[$item->menu_item_parent] = $k;
        }
    }
    // last class on parent most level
    $last = end(array_keys($parents));
    foreach ($parents as $k => $parent) {
        if ($k == $last) {
            $items[$parent]->classes[] = 'last';
        }
    }
    // last class on children levels
    foreach($children as $child){
        $items[$child]->classes[] = 'last';
    }
    // first class on children levels
    $r_items = array_reverse($items, true);
    foreach($r_items as $k => $item){
        if($item->menu_item_parent !== '0'){
            $children[$item->menu_item_parent] = $k;
        }
    }
    foreach($children as $child){
        $items[$child]->classes[] = 'first';
    }
    return $items;
}
add_filter('wp_nav_menu_objects', 'add_first_and_last');

Eu gosto da simplicidade da resposta de Ismaelj, mas é preciso haver mais se você quiser classes de submenu.

brent
fonte
2

Se você não precisar de suporte para o IE8 ou inferior, não esqueça que também pode usar CSS puro:

.my_menu > :first-child,
.my_menu > :last-child {
    /* some styles */
}

O suporte ao navegador jQuery é ainda melhor, mas parece que você está tentando evitar isso.

mrwweb
fonte
Eu estou usando isso, porque última criança é agora suportado pelo IE 9 também, e eu não me importo mais tanto sobre o IE 8, 7 ..
Alex
2

Aqui está um código melhor para adicionar a primeira e a última classes de itens de menu que incluem suporte para submenus aninhados.

add_filter( 'wp_nav_menu_objects', 'tgm_filter_menu_class', 10, 2 );
/**
 * Filters the first and last nav menu objects in your menus
 * to add custom classes.
 *
 * This also supports nested menus.
 *
 * @since 1.0.0
 *
 * @param array $objects An array of nav menu objects
 * @param object $args Nav menu object args
 * @return object $objects Amended array of nav menu objects with new class
 */
function tgm_filter_menu_class( $objects, $args ) {

    // Add first/last classes to nested menu items
    $ids        = array();
    $parent_ids = array();
    $top_ids    = array();
    foreach ( $objects as $i => $object ) {
        // If there is no menu item parent, store the ID and skip over the object
        if ( 0 == $object->menu_item_parent ) {
            $top_ids[$i] = $object;
            continue;
        }

        // Add first item class to nested menus
        if ( ! in_array( $object->menu_item_parent, $ids ) ) {
            $objects[$i]->classes[] = 'first-menu-item';
            $ids[]          = $object->menu_item_parent;
        }

        // If we have just added the first menu item class, skip over adding the ID
        if ( in_array( 'first-menu-item', $object->classes ) )
            continue;

        // Store the menu parent IDs in an array
        $parent_ids[$i] = $object->menu_item_parent;
    }

    // Remove any duplicate values and pull out the last menu item
    $sanitized_parent_ids = array_unique( array_reverse( $parent_ids, true ) );

    // Loop through the IDs and add the last menu item class to the appropriate objects
    foreach ( $sanitized_parent_ids as $i => $id )
        $objects[$i]->classes[] = 'last-menu-item';

    // Finish it off by adding classes to the top level menu items
    $objects[1]->classes[] = 'first-menu-item'; // We can be assured 1 will be the first item in the menu :-)
    $objects[end( array_keys( $top_ids ) )]->classes[] = 'last-menu-item';

    // Return the menu objects
    return $objects;

}

Você pode encontrar a essência aqui e o tutorial associado aqui .

Thomas
fonte
0

E se:

 ul li:last-child{
     // do something with the last li
 }

e talvez alguns http://selectivizr.com/

sou
fonte
Isso classificaria a primeira <li>de todas as listas não ordenadas do site, não apenas no menu. Também é substancialmente idêntica a esta resposta wordpress.stackexchange.com/a/63128/9844
mrwweb
Desculpe, pseudo-código.
am
0

CSS puro, funciona para mim. Isso funcionará com os submenus também

ul.nav>li:last-of-type a
Dan Green-Leipciger
fonte
apenas no IE9 e superior, o que exclui praticamente tudo o que faço :)
Milo