输出自定义Bootstrap结构的wordpress多级菜单
wordpress 2025年8月3日 29
「即插即用」的Bootstrap5多级菜单 Walker,特点:
支持无限级子菜单;
在后台菜单里给一级菜单项勾选CSS类has-mega即可触发mega下拉;
没有has-mega时走普通dropdown;
输出结构完全符合 Bootstrap5的 navbar-nav / dropdown-menu / row / col 规范;
自带最精简的 CSS,放主题或子主题即可。
一、把 Walker 扔进functions.php(或单独文件 require)
/**
* Bootstrap 5 Mega/Normal Menu Walker
*/
class BS5_Mega_Walker extends Walker_Nav_Menu {
// 开始一级菜单 <li>
public function start_lvl( &$output, $depth = 0, $args = null ) {
$indent = str_repeat( "\t", $depth );
// 当前父级 item 对象
$parent = $args->has_children ? $args->walker->items[ $args->db_id ] : null;
$is_mega = $parent && in_array( 'has-mega', (array) $parent->classes, true );
if ( $depth === 0 && $is_mega ) {
// mega 容器:dropdown-menu + row
$output .= "\n$indent<div class=\"dropdown-menu mega-menu p-3\"><div class=\"row\">\n";
} else {
// 普通下拉
$output .= "\n$indent<ul class=\"dropdown-menu\">\n";
}
}
// 结束一级菜单 </li>
public function end_lvl( &$output, $depth = 0, $args = null ) {
$indent = str_repeat( "\t", $depth );
$parent = $args->has_children ? $args->walker->items[ $args->db_id ] : null;
$is_mega = $parent && in_array( 'has-mega', (array) $parent->classes, true );
if ( $depth === 0 && $is_mega ) {
$output .= "$indent</div></div>\n";
} else {
$output .= "$indent</ul>\n";
}
}
// <li> 开始
public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$classes = empty( $item->classes ) ? [] : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
// 是否 mega 父级
$is_mega_parent = $depth === 0 && in_array( 'has-mega', $classes, true );
// 子级元素在 mega 里用 col 包裹
if ( $depth === 1 && $is_mega_parent ) {
$output .= $indent . '<div class="col-sm-6 col-lg-3 mb-3">';
} elseif ( $depth >= 1 ) {
// 普通子菜单 li
$output .= $indent . '<li class="dropdown-item">';
} else {
// 顶层 li
$classes[] = 'nav-item';
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$output .= $indent . '<li' . $class_names . '>';
}
// 链接属性
$atts = [];
$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 );
// 标签
$link_tag = ( $depth >= 1 && ! $is_mega_parent ) ? 'span' : 'a';
$item_output = $args->before;
$item_output .= '<' . $link_tag . $attributes . ' class="' .
( $depth === 0 ? 'nav-link' : '' ) .
( $depth === 0 && $args->walker->has_children ? ' dropdown-toggle' : '' ) .
'" data-bs-toggle="' . ( $depth === 0 && $args->walker->has_children ? 'dropdown' : '' ) . '">';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= '</' . $link_tag . '>';
$item_output .= $args->after;
// 子级在 mega 里的结束标签
if ( $depth === 1 && $is_mega_parent ) {
$item_output .= '</div>';
}
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
// </li> 结束
public function end_el( &$output, $item, $depth = 0, $args = null ) {
$is_mega_parent = $depth === 0 && in_array( 'has-mega', (array) $item->classes, true );
if ( $depth === 1 && $is_mega_parent ) {
// 已在 start_el 里闭合,这里什么都不做
} elseif ( $depth >= 1 ) {
$output .= "</li>\n";
} else {
$output .= "</li>\n";
}
}
}
二、前台调用示例
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="<?php echo home_url(); ?>">Brand</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mainNav">
<?php
wp_nav_menu( [
'theme_location' => 'primary',
'container' => false,
'menu_class' => 'navbar-nav me-auto mb-2 mb-lg-0',
'fallback_cb' => false,
'walker' => new BS5_Mega_Walker(),
'depth' => 0,
] );
?>
</div>
</div>
</nav>
三、最简CSS(放在主题或子主题)
/* 让 mega-menu 宽度与 container 对齐 */
@media (min-width: 992px) {
.navbar .dropdown-menu.mega-menu {
left: 0;
right: 0;
width: 100%;
margin-top: 0;
}
}
实现功能:
给一级菜单项加 CSS 类 has-mega → 自动变 mega;
没加就是普通 dropdown;
无限级子菜单均可正常工作。