wordpress菜单结构自定义的完整代码

下面给出一份「从零开始」自定义 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 就怎么写。