WordPress三级菜单Custom Walker修改:每2个菜单项分组包裹
嘿,针对你要给WordPress三级菜单每2个<li>包裹新容器的需求,我特意写了一个定制的Walker类,完全只作用在第三级菜单上,不会干扰其他层级的结构。下面是具体实现和细节说明:
自定义Walker类代码
class Custom_Three_Level_Walker extends Walker_Nav_Menu { // 跟踪当前菜单深度 private $current_depth = 0; // 统计三级菜单的项目数量 private $level_3_count = 0; // 标记是否有未闭合的分组容器 private $open_group = false; // 开始菜单层级时触发(比如进入子菜单<ul>) public function start_lvl( &$output, $depth = 0, $args = null ) { $this->current_depth = $depth; // 进入三级菜单时重置计数器和容器标记 if ( $depth === 2 ) { // WordPress菜单深度从0开始,第三级对应depth=2 $this->level_3_count = 0; $this->open_group = false; } // 保留默认的子菜单结构 $indent = str_repeat("\t", $depth); $output .= "\n$indent<ul class=\"sub-menu\">\n"; } // 结束菜单层级时触发(比如闭合子菜单</ul>) public function end_lvl( &$output, $depth = 0, $args = null ) { $this->current_depth = $depth; // 三级菜单结束时,检查是否有未闭合的分组容器(处理奇数个菜单项的情况) if ( $depth === 2 && $this->open_group ) { $output .= "\t\t</div>\n"; $this->open_group = false; } // 保留默认的子菜单闭合逻辑 $indent = str_repeat("\t", $depth); $output .= "$indent</ul>\n"; } // 开始单个菜单项时触发 public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) { $indent = ( $depth ) ? str_repeat( "\t", $depth ) : ''; // 只对第三级菜单做分组处理 if ( $depth === 2 ) { $this->level_3_count++; // 每第1、3、5...个项目开启新容器 if ( $this->level_3_count % 2 === 1 ) { $output .= "\t\t<div class=\"menu-group\">\n"; $this->open_group = true; } // 增加缩进让HTML结构更整洁 $indent .= "\t"; } // 保留WordPress默认的菜单项结构生成逻辑 $classes = empty( $item->classes ) ? array() : (array) $item->classes; $classes[] = 'menu-item-' . $item->ID; $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) ); $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : ''; $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth ); $id = $id ? ' id="' . esc_attr( $id ) . '"' : ''; $output .= $indent . '<li' . $id . $class_names . '>'; $atts = array(); $atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : ''; $atts['target'] = ! empty( $item->target ) ? $item->target : ''; $atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : ''; $atts['href'] = ! empty( $item->url ) ? $item->url : ''; $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth ); $attributes = ''; foreach ( $atts as $attr => $value ) { if ( ! empty( $value ) ) { $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value ); $attributes .= ' ' . $attr . '="' . $value . '"'; } } $title = apply_filters( 'the_title', $item->title, $item->ID ); $title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth ); $item_output = $args->before; $item_output .= '<a'. $attributes .'>'; $item_output .= $args->link_before . $title . $args->link_after; $item_output .= '</a>'; $item_output .= $args->after; $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); } // 结束单个菜单项时触发 public function end_el( &$output, $item, $depth = 0, $args = null ) { $output .= "</li>\n"; // 只对第三级菜单处理容器闭合 if ( $depth === 2 ) { // 每第2、4、6...个项目闭合容器 if ( $this->level_3_count % 2 === 0 ) { $output .= "\t\t</div>\n"; $this->open_group = false; } } } }
核心逻辑说明
- 我们继承了WordPress原生的
Walker_Nav_Menu类,只修改需要定制的部分,保留其他层级的默认菜单结构 - 通过
current_depth精准锁定第三级菜单(depth=2),确保分组逻辑不会影响一级、二级菜单 - 用
level_3_count统计三级菜单项数量,实现每2个项目自动包裹容器 open_group标记专门处理奇数个菜单项的情况,避免菜单结束时留下未闭合的HTML标签
如何使用
在调用wp_nav_menu函数时,指定walker参数为我们的自定义类即可:
wp_nav_menu( array( 'theme_location' => 'your-primary-menu', // 替换成你的菜单位置标识 'walker' => new Custom_Three_Level_Walker(), ) );
可选CSS美化示例
你可以给新容器加样式优化展示效果,比如让每组菜单项并排显示:
.menu-group { display: flex; gap: 1.5rem; margin-bottom: 1rem; } .menu-group .menu-item { flex: 1; }
内容的提问来源于stack exchange,提问作者June
相关产品推荐
相关产品推荐

