WordPress 的导航菜单系统足够强大,但在很多项目中,默认的输出方式无法满足设计要求。比如你需要给菜单项添加图标、输出特定位置的条件判断、渲染复杂的自定义下拉结构,或者根据用户登录状态显示不同的菜单项。这些需求都可以通过一个强大的工具来实现:Walker 类。

Walker 类是 WordPress 中用于递归遍历树状结构(如菜单、评论、分类层级)的一个抽象类。对于菜单来说,默认的 Walker_Nav_Menu 类负责将菜单项转换成 HTML。要自定义菜单的输出,你需要创建一个继承 Walker_Nav_Menu 的 Walker 类,并重写它的几个关键方法:

  • start_lvl():开始一个子菜单(<ul>)时调用

  • end_lvl():结束一个子菜单时调用

  • start_el():开始一个菜单项(<li>)时调用

  • end_el():结束一个菜单项时调用

最简单的自定义 Walker:给每个菜单项添加图标

假设你的每个菜单项都有一个自定义字段“菜单图标”,通过 wp_nav_menu 的 'items_wrap' 无法做到给每个项单独加图标,但 Walker 可以:

class Icon_Nav_Walker extends Walker_Nav_Menu {
    public function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) {
        $icon = get_post_meta($item->ID, 'menu_icon', true);
        $icon_html = $icon ? '<i class="' . esc_attr($icon) . '"></i> ' : '';
        
        $output .= '<li class="' . implode(' ', $item->classes) . '">';
        $output .= '<a href="' . $item->url . '">';
        $output .= $icon_html;
        $output .= $item->title;
        $output .= '</a>';
    }
}

然后在 wp_nav_menu 中调用这个 Walker:

wp_nav_menu(array(
    'theme_location' => 'primary',
    'walker' => new Icon_Nav_Walker()
));

更高级的 Walker:实现多级 Mega Menu

Mega Menu(巨幅菜单)需要为顶层菜单项的特殊子菜单渲染自定义布局,而不是标准的 <ul><li> 列表。你可以在 start_el 方法中判断当前菜单项是否为特定 ID,然后输出不同的 HTML:

class Mega_Menu_Walker extends Walker_Nav_Menu {
    public function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) {
        if ($depth == 0 && $item->ID == 123) { // 假设 ID 为 123 的菜单项需要 Mega Menu
            $output .= '<li class="mega-menu-item">';
            $output .= '<a href="' . $item->url . '">' . $item->title . '</a>';
            $output .= '<div class="mega-menu-content">';
            $output .= '这里可以放复杂内容,比如最近文章、产品分类、Banner 图片等';
            $output .= '</div>';
            // 注意:子菜单的标准渲染会被跳过
            return;
        }
        parent::start_el($output, $item, $depth, $args, $id);
    }
}

条件显示菜单项:根据登录状态、用户角色显示不同内容

wp_nav_menu 默认没有条件显示的功能,但你可以通过过滤菜单项列表来实现。钩子是 wp_nav_menu_objects,它在菜单对象数组生成后、HTML 渲染前被调用:

add_filter('wp_nav_menu_objects', 'conditional_menu_items', 10, 2);
function conditional_menu_items($items, $args) {
    if ($args->theme_location != 'primary') {
        return $items;
    }
    
    foreach ($items as $key => $item) {
        // 如果菜单项标题是“登录”,并且用户已经登录,则删除该项
        if ($item->title == '登录' && is_user_logged_in()) {
            unset($items[$key]);
        }
        // 如果菜单项标题是“个人中心”,并且用户未登录,则删除
        if ($item->title == '个人中心' && !is_user_logged_in()) {
            unset($items[$key]);
        }
        // 根据角色显示:只有管理员可以看到“后台仪表盘”菜单项
        if ($item->title == '后台仪表盘' && !current_user_can('manage_options')) {
            unset($items[$key]);
        }
    }
    
    return $items;
}

给菜单项增加额外字段

默认情况下,WordPress 菜单管理界面只有导航标签、链接关系、描述、打开方式等几个字段。如果你想增加一个“图标”输入框或“副标题”字段,需要用 wp_setup_nav_menu_item 和 wp_update_nav_menu_item 钩子来扩展。核心步骤:

  1. 在菜单管理界面添加自定义字段(通过 wp_nav_menu_item_custom_fields 钩子)。

  2. 保存字段值到 postmeta(通过 wp_update_nav_menu_item)。

  3. 在前端 Walker 中读取并输出。

有了这些技巧,你几乎可以随心所欲地控制菜单的输出方式,无论设计稿多么复杂,WordPress 的菜单系统都能应对。