标签: wordpress菜单

  • 为不同的wordpress页面调用不同的顶部菜单

    下面给出 4 种在 WordPress 里“让不同页面(或不同模板、不同文章类型)调用不同顶部菜单”的常用做法,从最轻量到最灵活依次排列。你可以按自己熟悉程度与项目复杂度任选其一,也可以组合使用。

    一、纯后台设置:利用「菜单位置 + 条件挂钩」(无需写代码,适合只有 2-3 套菜单的小站点)

    在「外观 → 菜单」里把菜单 A 设为 primary,菜单 B 设为 secondary(多主题可能叫 top / header / mobile 等)。

    安装插件「Conditional Menus」(免费,无设置页)。

    进入「外观 → 菜单 → Manage Locations」标签页,你会看到每个菜单位置右侧多了一个 «Conditional Menu» 下拉框。

    给 primary 位置先选「菜单 B」

    点击 «+ Conditions»,在弹窗里勾选

    – 首页:Home

    – 某分类:Category → Products

    – 某页面:Page → Contact

    保存即可。

    逻辑:插件会在 wp_nav_menu_args 钩子内,按你设定的条件实时把菜单 slug 换掉,性能影响几乎为 0,且升级主题不会丢。

    二、主题自带「页面级菜单」字段(部分商业主题/页面构建器已集成,最直观)

    编辑页面 → 找到「Page Settings / Theme Options」面板 → 下拉「Custom Header Menu」。

    选想要的菜单 → 更新。

    主题作者在 header.php(或相应模板)里已预埋代码,大致如下:

    $custom_menu = get_post_meta( $post->ID, '_custom_top_menu', true );
    wp_nav_menu( array(
        'menu'            => $custom_menu ? $custom_custom : 'primary',
        'container'       => 'nav',
        'container_class' => 'top-nav'
    ) );

    如果你用的主题没这功能,可以自己把上面代码放进 header.php,再配合下文「三」的高级做法,把 _custom_top_menu 做成下拉选单即可。

    三、在子主题里用 filter 动态替换(推荐,代码量极少、可控、可版本管理)

    给 functions.php 加一段:

    /**
     * 根据不同条件返回不同菜单
     * @param array $args  wp_nav_menu 原始参数
     * @return array
     */
    function my_conditional_nav_menu( $args ) {
        // 只动 primary 位置,其它位置原样返回
        if ( 'primary' !== $args['theme_location'] ) {
            return $args;
        }
    
        // 1. 首页单独菜单
        if ( is_front_page() ) {
            $args['menu'] = 'home-menu';   // 菜单别名(slug)
        }
        // 2.「产品」分类及其下属文章
        elseif ( is_tax( 'product_cat' ) || is_singular( 'product' ) ) {
            $args['menu'] = 'product-menu';
        }
        // 3. ID 为 42 的页面
        elseif ( is_page( 42 ) ) {
            $args['menu'] = 'landing-menu';
        }
        // 4. 默认 fallback
        else {
            $args['menu'] = 'primary-menu';
        }
    
        return $args;
    }
    add_filter( 'wp_nav_menu_args', 'my_conditional_nav_menu' );

    把需要的菜单先建好,记下「菜单别名」填到代码里即可。

    性能:只在调用 wp_nav_menu() 时触发一次过滤,几乎无额外查询。

    维护:升级主题只要子主题还在就安全;换主题也只需把 ‘primary’ 改成新主题的 location 名称。

    四、完全自定义:新建 Page Template + 新 Menu Location (适合「同一站点不同频道」型项目,如 官网/B2B/B2C 三合一)

    注册新菜单位置(functions.php):

    add_action( 'after_setup_theme', function () {
        register_nav_menus( array(
            'primary'      => '主站菜单',
            'corporate'    => '企业频道菜单',
            'shop'         => '商城频道菜单',
        ) );
    } );

    新建页面模板 template-corporate.php,在文件头部声明:

    <?php
    /**
     * Template Name: 企业频道
     */
    get_header( 'corporate' );   // 自动加载 header-corporate.php

    复制一份 header-corporate.php,把里面的

    wp_nav_menu( array( 'theme_location' => 'corporate' ) );

    换成刚注册的 corporate 位置。

    4. 后台「外观 → 菜单」里给 corporate 位置分配菜单;发布页面时选「企业频道」模板即可。

    5. 优势:每套频道可以有独立的 header/footer/sidebar,菜单只是其中一部分;后期还可以配独立样式表与脚本。

    常见坑 & 调试技巧

    缓存:用了页面缓存插件(WP Rocket、LiteSpeed Cache)记得把「菜单」从缓存中排除,或给不同页面打不同缓存标签。

    多语言:WPML/Polylang 会给每种语言生成独立菜单,记得在条件判断里加 ICL_LANGUAGE_CODE 或 pll_current_language()。

    移动端:检查主题是否对「Mobile Menu」另外写了 walker,必要时把上面的 filter 同样应用到 mobile 位置。

    菜单找不到:确认填的是「菜单别名」而不是标题;别名在「外观 → 菜单 → 编辑」里展开「菜单设置」可见。

    一句话总结

    只想「某几个页面换个菜单」→ 装 Conditional Menus 最快;

    想代码干净、可 Git 管理 → 用子主题 + wp_nav_menu_args filter;

    要做「多频道」大站 → 注册新菜单位置 + 多套 header 模板最清晰。

    照着上面 4 种方案任选其一,10 分钟内就能把「不同页面不同顶部菜单」跑通。

  • 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 就怎么写。