下面给出一份「从零开始」自定义 WordPress 菜单结构的完整示例,包含:
注册菜单位置
后台勾选「CSS 类」等选项
自定义 Walker 类,把默认的
结构完全拆成你想要的任何 HTML(示例用 Bootstrap 5 的 navbar 结构,你可以按需改)
在主题里调用
可选:把自定义 Walker 写成插件,方便换主题时复用
直接复制即可运行,代码里每一步都有中文注释。
一、注册菜单位置(functions.php 或插件主文件)
/** * 1. 注册菜单位置 */ add_action( 'after_setup_theme', 'my_register_menus' ); function my_register_menus() { register_nav_menus( array( 'primary' => '顶部主导航', 'footer' => '底部链接', ) ); }二、打开「CSS 类 / 链接关系 / 描述」等选项
/** * 2. 让菜单项支持 CSS 类、链接关系(XFN)、描述 */ add_filter( 'wp_nav_menu_args', 'my_nav_menu_args' ); function my_nav_menu_args( $args ) { // 只对前台主菜单生效,后台不影响 if ( ! is_admin() && isset( $args['theme_location'] ) && $args['theme_location'] === 'primary' ) { $args['depth'] = 3; // 支持三级菜单 $args['fallback_cb'] = false; // 没菜单时不 fallback 到 wp_page_menu } return $args; } // 打开后台「CSS 类」「描述」等面板 add_filter( 'wp_nav_menu_item_custom_fields', '__return_true' ); // 描述 add_filter( 'nav_menu_link_attributes', '__return_true' ); // 链接属性三、自定义 Walker 类(重点)
在主题根目录新建 class-walker-primary.php 并引入,或直接写在 functions.php 里。
/** * 3. 自定义 Walker:输出 Bootstrap 5 的 navbar * * 用法: * wp_nav_menu( array( * 'theme_location' => 'primary', * 'container' => 'div', * 'container_class' => 'collapse navbar-collapse', * 'container_id' => 'navbarNav', * 'menu_class' => 'navbar-nav ms-auto', * 'walker' => new Walker_Primary(), * ) ); */ if ( ! class_exists( 'Walker_Primary' ) ) : class Walker_Primary extends Walker_Nav_Menu { /** * 开始一级菜单 <ul> */ public function start_lvl( &$output, $depth = 0, $args = null ) { $indent = str_repeat( "\t", $depth ); $output .= "\n$indent<ul class=\"dropdown-menu\">\n"; } /** * 结束一级菜单 </ul> */ public function end_lvl( &$output, $depth = 0, $args = null ) { $indent = str_repeat( "\t", $depth ); $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() : (array) $item->classes; $classes[] = 'menu-item-' . $item->ID; // 判断是否有下拉 $has_children = in_array( 'menu-item-has-children', $classes, true ); if ( $has_children && $depth === 0 ) { $classes[] = 'dropdown'; } // 过滤并拼接类名 $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) ); $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : ''; // 拼接 li id $id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args ); $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 : ''; // 顶级且有子菜单时加 data-bs-toggle if ( $has_children && $depth === 0 ) { $atts['href'] = '#'; $atts['id'] = 'navbarDropdown' . $item->ID; $atts['role'] = 'button'; $atts['aria-expanded'] = 'false'; $atts['data-bs-toggle']= 'dropdown'; $atts['class'] = 'nav-link dropdown-toggle'; } else { $atts['class'] = $depth === 0 ? 'nav-link' : 'dropdown-item'; } $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args ); $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 ); // 描述(可选) $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 ); } /** * 结束单个菜单项 </li> */ public function end_el( &$output, $item, $depth = 0, $args = null ) { $output .= "</li>\n"; } } endif;四、在 header.php(或任意模板)调用
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container"> <a class="navbar-brand" href="<?php echo esc_url( home_url( '/' ) ); ?>">LOGO</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <?php wp_nav_menu( array( 'theme_location' => 'primary', 'container' => 'div', 'container_class' => 'collapse navbar-collapse', 'container_id' => 'navbarNav', 'menu_class' => 'navbar-nav ms-auto', 'depth' => 3, 'walker' => new Walker_Primary(), ) ); ?> </div> </nav>五、做成插件(可选)
新建文件夹 /wp-content/plugins/my-walker
在里面创建 my-walker.php,插件头如下:
<?php /** * Plugin Name: My Custom Nav Walker * Description: 自带 Bootstrap 5 的 nav walker,换主题也通用 * Version: 1.0 */ if ( ! defined( 'ABSPATH' ) ) exit; require_once plugin_dir_path( __FILE__ ) . 'class-walker-primary.php';把上面的 Walker_Primary 类放到同目录的 class-walker-primary.php
后台启用插件即可,任何主题都能直接 ‘walker’ => new Walker_Primary()。
六、常见微调
把 start_lvl 里的 dropdown-menu 换成你自己的类
把 start_el 里 $atts[‘class’] 的判断逻辑改成「第 2 级加 sub-item」等
想输出「箭头 svg / 图标字体」:在 $item_output 前后拼就行
想加「当前项高亮」:判断 $item->current 或 in_array( ‘current-menu-item’, $classes )
七、一键复制清单
functions.php 里放「注册菜单」+「后台面板」代码
新建 class-walker-primary.php 并引入
header.php 里用 wp_nav_menu() 调用
刷新后台 → 外观 → 菜单 → 勾选 CSS 类 / 描述 → 拖菜单 → 前台看效果
至此,WordPress 菜单结构完全由你掌控,想怎么写 HTML 就怎么写。
原文
http://wordpress.zj.cn/jiaocheng/45.html