如何通过wp_nav_menu的items_wrap参数修改菜单HTML结构?
解决方案:结合
items_wrap和自定义Walker实现 嘿,这个需求我刚好处理过,咱们一步步来拆解:直接用items_wrap参数可以移除外层的<ul>,但要把父级<li>转成<div>,就得配合自定义的Walker_Nav_Menu类了——wp_nav_menu自带的参数没法直接改菜单项的标签,得靠Walker来定制输出结构。
第一步:移除外层<ul>
默认的items_wrap参数是 <ul id="%1$s" class="%2$s">%3$s</ul>,其中%3$s是所有菜单项的内容。你只需要把它改成%3$s,就能去掉外层的<ul>容器:
wp_nav_menu(array( 'theme_location' => 'your-menu-location', // 替换成你的菜单位置 'items_wrap' => '%3$s', ));
第二步:把父级菜单项转成<div>
要实现父项从<li>变<div>,我们需要自定义一个Walker类,继承默认的Walker_Nav_Menu,重写start_el和end_el方法,判断当前菜单项是否是父级(带子菜单),然后切换标签:
class Custom_Menu_Walker extends Walker_Nav_Menu { // 处理菜单项的开始标签 function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) { // 判断当前项是否是带子菜单的父项 $is_parent = in_array('menu-item-has-children', $item->classes); // 父项用<div>,子项保持<li> $tag = $is_parent ? 'div' : 'li'; // 处理菜单项的类名和ID(保留WordPress默认的过滤逻辑) $classes = array_filter((array)$item->classes); $classes[] = 'menu-item-' . $item->ID; $class_names = join(' ', apply_filters('nav_menu_css_class', $classes, $item, $args, $depth)); $class_names = $class_names ? ' class="' . esc_attr($class_names) . '"' : ''; $id = apply_filters('nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth); $id = $id ? ' id="' . esc_attr($id) . '"' : ''; // 拼接开始标签 $output .= '<' . $tag . $id . $class_names . '>'; // 处理菜单项的链接和标题(保留默认逻辑) $atts = array( 'title' => $item->attr_title, 'target' => $item->target, 'rel' => $item->xfn, 'href' => $item->url, ); $atts = apply_filters('nav_menu_link_attributes', $atts, $item, $args, $depth); $attributes = ''; foreach ($atts as $attr => $value) { if (!empty($value)) { $value = ($attr === 'href') ? esc_url($value) : esc_attr($value); $attributes .= " $attr=\"$value\""; } } $item_output = $args->before; $item_output .= "<a$attributes>"; $item_output .= $args->link_before . apply_filters('the_title', $item->title, $item->ID) . $args->link_after; $item_output .= '</a>'; $item_output .= $args->after; $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args); } // 处理菜单项的结束标签,和开始标签对应 function end_el(&$output, $item, $depth = 0, $args = null) { $is_parent = in_array('menu-item-has-children', $item->classes); $tag = $is_parent ? 'div' : 'li'; $output .= "</$tag>\n"; } }
第三步:组合调用
把上面的Walker类放到你的主题functions.php里,然后调用wp_nav_menu时指定这个Walker:
wp_nav_menu(array( 'theme_location' => 'your-menu-location', // 替换成你的菜单位置 'items_wrap' => '%3$s', // 移除外层<ul> 'walker' => new Custom_Menu_Walker(), // 使用自定义Walker ));
额外说明
- WordPress会自动给带子菜单的菜单项添加
menu-item-has-children类,所以我们靠这个类来区分父项和子项。 - 如果需要调整子菜单的外层容器(比如把
<ul>改成<div>),可以重写Walker的start_lvl和end_lvl方法来实现。 - 测试的时候记得清空缓存,避免旧的菜单结构影响结果。
内容的提问来源于stack exchange,提问作者cup_of
相关产品推荐
相关产品推荐

