在每个ul.子菜单的最后<li>中添加一个.last类

时间:2012-04-14 作者:Andrew

我看过很多关于如何添加firstlast 类添加到WordPress菜单,但在我的示例中,我想添加last 初始化到WP生成的子菜单中的最后一个li。以下是我希望以最简单的形式实现的目标。

<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>
这是我目前拥有的,它只向父菜单项添加第一个和最后一个类。这能适应吗?

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\');
为此,我想坚持使用php,而不使用任何一种:last-child (希望它在ie7和8中工作)或jQuery。

3 个回复
最合适的回答,由SO网友:Stephen Harris 整理而成

将以下内容放入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 );
    }
}
用法wp_nav_menu 如果要添加“last”类,请在上面指定walker:

wp_nav_menu( array(\'theme_location\'=>\'primary\',\'walker\' => new SH_Last_Walker(),\'depth\' => 0) ); 
theme_locationdepth 你可以随心所欲,重要的是walker 属性

旁白可以改进此代码-通过取消设置$children_elements[$parent_id] 调用时使用数组,并检查何时使用到最后一个元素(即仅包含一个元素)。我想wp_list_filter 在这里很合适。这可能不会提高效率,但可能更整洁。

此外,您还可以对父字段和id字段进行硬编码-我这样做不是为了便于移植。下面的类可以扩展Walker类提供的任何扩展(页面列表、类别列表等)。

SO网友:Adam

jQuery看起来像这样;

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

} );
但是关于PHP,请看一下Rarst提供的这个答案HERE 看看这是否对你有帮助。

从上面的链接更新Rart解决方案是否有效,代码片段是;

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;
}
输出给了我这样的东西;

<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>
这意味着你可以ul ul li 元素通过CSS选择器成功。

SO网友:Norcross

需要考虑的是:虽然IE7和IE8不支持最后一个孩子,但他们支持第一个孩子。因此,根据您需要对最后一项应用不同的CSS,您可以反转它。

此外,FWIW,默认情况下,您的主题已经在其他区域使用jQuery(例如,注释部分),因此这将是一个更快更干净的选项。

结束