搜索全站
主题 11 分钟阅读

lumen-mimangfei 主题菜单与导航配置详解:菜单位置、二级菜单、移动端菜单

菜单注册了却不显示、二级菜单展开不了、移动端点了没反应?本文讲清 register_nav_menus 到 wp_nav_menu 的完整链路,给出二级菜单与移动端菜单的可复用代码。

U
UFO_PF 2025-09-07 · 阅读 11 分钟
lu 主题
阅读提示
本文约 4,329 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:三个菜单问题,几乎每个站都会遇到一遍

第一,主题文档说支持”主导航”,你在后台建好了菜单、勾了位置,前台却纹丝不动;第二,二级菜单建好了,鼠标移上去就是不展开;第三,电脑上一切正常,手机上汉堡按钮点了完全没反应,或者菜单展开后盖住了内容、点不动链接。

这三个问题的成因完全不同:第一个是”菜单位置”没对上,第二个多半是 CSS 与菜单层级不匹配,第三个通常是 JS 依赖或层叠上下文的问题。lumen-mimangfei 主题的导航由 register_nav_menus() 注册位置、wp_nav_menu() 输出,弄清楚这条链路,问题就好定位了。

原理分析:从注册到输出的完整链路

菜单位置(theme_location)由主题在 after_setup_theme 里用 register_nav_menus() 声明,只是”占位符”,本身不包含任何菜单项。菜单项数据存在数据库里:菜单本身是 nav_menu 分类法下的 term,菜单项是 nav_menu_item 类型的 post,两者通过 wp_term_relationships 关联。

输出时 wp_nav_menu() 根据 theme_location 找到被分配的菜单,取菜单项后用 Walker_Nav_Menu 递归生成 <ul><li> 结构。depth 参数控制递归层数,但层级上限还受主题 CSS 约束——很多主题只写了 .sub-menu 两级样式,你把 depth 放开也看不到第三级。

移动端菜单通常不是 PHP 的问题,而是缺一段切换逻辑:主题输出一个按钮和一个容器,靠 JS 切换 class,再用 CSS 控制显示。若这段 JS 在 jQuery 之前加载,或者被缓存插件合并压缩出错,点击就没反应。

现象 大概率原因
菜单完全不显示 theme_location 拼写不一致 / 该位置未分配菜单
显示成所有页面列表 未分配菜单,走了 fallback_cb 的 wp_page_menu
二级菜单不展开 缺少 .sub-menu 的定位与 hover/focus 样式
移动端点击无反应 切换 JS 未加载、报错,或被缓存的旧版本覆盖
登录后菜单不更新 页面缓存把未登录态的 HTML 缓存了

保姆级实操

  1. 确认菜单位置名称:在主题里搜索 register_nav_menus,记下数组键名(如 primary、footer),这是 theme_location 要填的值,不是显示名。
  2. 后台建菜单并分配:外观 → 菜单,新建菜单后务必在”显示位置”勾选对应位置并保存。
  3. 建二级菜单:在菜单结构里把子项向右拖动一格即可,WordPress 本身不限制层级。
  4. 输出时显式声明参数:把 container、menu_class、depth、fallback_cb 写清楚,尤其 fallback_cb 设成 false 可以避免”未分配时静默显示页面列表”。
  5. 移动端加切换逻辑:给导航容器加一个按钮,用原生 JS 切换 aria 属性与 class,不依赖 jQuery,减少出错面。
  6. 补 CSS:二级菜单用 position:absolute + focus-within 保证键盘与触屏可达;移动端用媒体查询切换为抽屉式。
  7. 清缓存验证:改完菜单先清页面缓存,并在无痕窗口里确认登录/未登录两种状态。
<?php
// 1) 注册菜单位置(注意键名才是 theme_location)
add_action( 'after_setup_theme', 'mimangfei_register_menus' );
function mimangfei_register_menus() {
    register_nav_menus( array(
        'primary' => __( '主导航', 'lumen-mimangfei' ),
        'footer'  => __( '页脚导航', 'lumen-mimangfei' ),
    ) );
}

// 2) 输出主导航,避免未分配时回退成页面列表
wp_nav_menu( array(
    'theme_location' => 'primary',
    'container'      => 'nav',
    'container_id'   => 'site-navigation',
    'menu_class'     => 'primary-menu',
    'depth'          => 2,
    'fallback_cb'    => false,
) );
<?php
// 给当前菜单项追加 aria-current,方便 CSS 高亮与无障碍
add_filter( 'nav_menu_item_attributes', 'mimangfei_menu_item_attrs', 10, 2 );
function mimangfei_menu_item_attrs( $atts, $item ) {
    if ( ! empty( $item->current ) ) {
        $atts['aria-current'] = 'page';
    }
    if ( ! empty( $atts['class'] ) ) {
        $atts['class'] .= ' menu-item-custom';
    }
    return $atts;
}
/* 二级菜单:定位 + hover 与键盘可达 */
.primary-menu .sub-menu {
    position: absolute;
    left: 0;
    top: 100%;
    min-width: 180px;
    background: #fff;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .12);
    opacity: 0;
    visibility: hidden;
    transition: opacity .18s ease;
    z-index: 50;
}
.primary-menu li {
    position: relative;
}
.primary-menu li:hover > .sub-menu,
.primary-menu li:focus-within > .sub-menu {
    opacity: 1;
    visibility: visible;
}
/* 移动端抽屉 */
@media ( max-width: 782px ) {
    #site-navigation .primary-menu {
        display: none;
    }
    #site-navigation.is-open .primary-menu {
        display: block;
    }
    .primary-menu .sub-menu {
        position: static;
        opacity: 1;
        visibility: visible;
        box-shadow: none;
    }
}
// 原生 JS 切换,不依赖 jQuery
document.addEventListener( 'DOMContentLoaded', function () {
    const nav  = document.getElementById( 'site-navigation' );
    const btn  = document.querySelector( '.menu-toggle' );
    if ( ! nav || ! btn ) {
        return;
    }
    btn.addEventListener( 'click', function () {
        const open = nav.classList.toggle( 'is-open' );
        btn.setAttribute( 'aria-expanded', open ? 'true' : 'false' );
    } );
} );

常见踩坑

  • theme_location 填的是显示名(”主导航”)而不是键名(primary),匹配失败。
  • 忘了在后台”显示位置”勾选,前台走了 fallback_cb 默认输出全部页面,看起来像”菜单自己乱了”。
  • 二级菜单父项没有 position: relative,子菜单跑到页面左上角。
  • 移动端切换 JS 依赖 jQuery 但脚本排队顺序在前,控制台报 $ is not defined。
  • 案例:某站改了菜单名称后,前台导航突然变成”首页、关于我们、联系我们……”一长串。原因是菜单被重命名后与位置的绑定丢失,fallback_cb 默认调用 wp_page_menu 兜底。把 fallback_cb 设为 false 并重新分配位置后恢复正常,也避免了以后再出现这种”静默兜底”。
  • 菜单展开层被其他元素的 z-index 盖住,看起来像没反应。
  • 开了页面缓存后,登录用户看到的仍是未登录态菜单(”登录/注册”一直显示)。

总结

排查顺序固定为:位置键名 → 后台是否分配 → depth 与 CSS 是否匹配 → 移动端 JS 是否加载 → 缓存是否干扰。判断标准是”未分配菜单时应当什么都不显示”,把 fallback_cb 设为 false 能立刻暴露问题。行动清单:① 统一位置键名;② 显式声明 depth;③ 移动端用原生 JS 减少依赖;④ 二级菜单加 focus-within;⑤ 缓存插件排除登录用户。相关延伸可看 lumen-mimangfei 主题首页布局、lumen-mimangfei 主题移动端显示问题 与 WordPress 主题自定义 JS 添加。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。