为 wordpress 写一个自定义的 nav walker
Writing a custom nav walker for wordpress
我正在尝试为我的自定义 wordpress 主题编写自定义导航菜单。
<ul class="MainMenu nav navbar-nav ">
<li class="has-megamenu">
<a href="#">MENU</a>
<div class="megamenu">
<ul class="container megamenu-background">
<li class="col-md-3 megamenu-column">
<h4>Column 1</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
<li class="col-md-3 megamenu-column">
<h4>Column 2</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
<li class="col-md-3 megamenu-column">
<h4>Column 3</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
<li class="col-md-3 megamenu-column">
<h4>Column 4</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
</ul>
</div>
</li>
<li class="dropdown"><a href="#">Contact</a></li>
<li class="dropdown"><a href="#">Our Story</a></li>
问题是如何编写这个结构walker
与其在 WordPress 管理员中将其构建为一个大菜单,我建议为 megamenu 中的每一列构建一个单独的菜单,然后再为联系人/关于/帐户链接构建一个菜单。我这样做的原因是因为您为每个 megamenu 列包含一个列标题,而 WordPress 管理菜单 UI 不包含向菜单中添加 non-link 项目的方法的盒子。添加 "Column Title" 内容 和 使其可编辑的最简单方法是制作单独的菜单,并使用菜单标题作为列标题。
对于functions.php:
<?php
// Register the menus
add_action( 'after_setup_theme', 'register_menus' );
function register_menus() {
register_nav_menu( 'megamenu1', __( 'Megamenu Column 1', 'theme-text-domain' ) );
register_nav_menu( 'megamenu2', __( 'Megamenu Column 2', 'theme-text-domain' ) );
register_nav_menu( 'megamenu3', __( 'Megamenu Column 3', 'theme-text-domain' ) );
register_nav_menu( 'megamenu4', __( 'Megamenu Column 4', 'theme-text-domain' ) );
register_nav_menu( 'support', __( 'Support Menu', 'theme-text-domain' ) );
}
// Add the menu title
add_filter( 'wp_nav_menu_items', [ $this, 'include_menu_title' ], 10, 2 );
function include_menu_title( $nav_items, $args ) {
if ( ! isset( $args->show_title ) || false === $args->show_title ) {
return $nav_items;
}
if ( $args->theme_location && ( $locations = get_nav_menu_locations() ) && isset( $locations[ $args->theme_location ] ) ) {
$menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
// Add the menu title. We add the UL element manually, because otherwise it would wrap AROUND the H4 later in execution of the wp_nav_menu function.
$nav_items = '<h4>' . $menu->name . '</h4><ul class="' . $args->menu_class . '">' . $nav_items . '</ul>';
}
return $nav_items;
}
// Add the dropdown class to support menu items.
add_filter('nav_menu_css_class', function($classes, $item, $args) {
if ( 'support' !== $args->theme_location ) {
return $classes;
}
$classes[] = 'dropdown';
return $classes;
}, 10, 3);
然后 header.php:
<ul class="MainMenu nav navbar-nav">
<li class="has-megamenu">
<a href="#">Megamenu</a>
<div class="megamenu">
<div class="container megamenu-background">
<?php
$common_args = [
'show_title' => true, // This is a custom arg used to indicate we want the title included.
'items_wrap' => '%3$s', // Remove the UL element. We'll add it back at the right place in the filter.
'container_class' => 'col-md-3 megamenu-column',
'menu_class' => 'vpm-menu-ul',
];
wp_nav_menu( array_merge( ['theme_location' => 'megamenu1'], $common_args ) );
wp_nav_menu( array_merge( ['theme_location' => 'megamenu2'], $common_args ) );
wp_nav_menu( array_merge( ['theme_location' => 'megamenu3'], $common_args ) );
wp_nav_menu( array_merge( ['theme_location' => 'megamenu4'], $common_args ) );
?>
</div>
</div>
</li>
<?php
wp_nav_menu([
'theme_location' => 'support',
'items_wrap' => '%3$s', // Remove the UL element.
'container' => false, // Remove the container div.
]);
?>
</ul>
这就是我使用 wordpress 设法解决这个问题的方法 walker_nav_menu
https://developer.wordpress.org/reference/classes/walker_nav_menu/
class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
/**
* Unique id for dropdowns
*/
public $submenu_unique_id = '';
/**
* Starts the list before the elements are added.
* @see Walker::start_lvl()
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = str_repeat( $t, $depth );
$before_start_lvl = '<div class="megamenu">';
if($depth==0){
$output .= "{$n}{$indent}{$before_start_lvl}<ul id=\"$this->submenu_unique_id\" class=\"container megamenu-background sub-menu dropdown-content\">{$n}";
}
else{
$output .= "{$n}{$indent}<ul id=\"$this->submenu_unique_id\" class=\"sub-menu dropdown-content\">{$n}";
}
}
/**
* Ends the list of after the elements are added.
* @see Walker::end_lvl()
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = str_repeat( $t, $depth );
$after_end_lvl = '</div>';
if($depth==0){
$output .= "$indent</ul>{$after_end_lvl}{$n}";
}
else{
$output .= "$indent</ul>{$n}";
}
}
/**
* @see Walker::start_el()
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = ( $depth ) ? str_repeat( $t, $depth ) : '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
// set active class for current nav menu item
if( $item->current == 1 ) {
$classes[] = 'active';
}
// set active class for current nav menu item parent
if( in_array( 'current-menu-parent' , $classes ) ) {
$classes[] = 'active';
}
/**
* Filters the arguments for a single nav menu item.
*/
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
// add a divider in dropdown menus
if ( strcasecmp( $item->attr_title, 'divider' ) == 0 && $depth === 1 ) {
$output .= $indent . '<li class="divider">';
} else if ( strcasecmp( $item->title, 'divider') == 0 && $depth === 1 ) {
$output .= $indent . '<li class="divider">';
} else {
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
//adding col-md-3 class to column
if( in_array('menu-item-has-children', $classes ) ) {
if( $depth === 1 ) {
$class_names = $class_names ? ' class="col-md-3 mega-menucolumn '.esc_attr( $class_names ) . '"' : '';
} else {
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
}
}else{
$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 .= $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 : '';
if( in_array('menu-item-has-children', $classes ) ) {
$atts['href'] = ' ';
$this->submenu_unique_id = 'dropdown-'.$item->ID;
} else {
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts['class'] = '';
}
$atts['class'] .= 'menu-item-link-class ';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
if( ! in_array( 'icon-only' , $classes ) ) {
$title = apply_filters( 'the_title', $item->title, $item->ID );
$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
// set icon on left side
if( !empty( $classes ) ) {
foreach ($classes as $class_name) {
if( strpos( $class_name , 'fa' ) !== FALSE ) {
$icon_name = explode( '-' , $class_name );
if( isset( $icon_name[1] ) && !empty( $icon_name[1] ) ) {
$item_output .= '<i class="fa fa-'.$icon_name[1].'" aria-hidden="true"></i> ';
}
}
}
}
$item_output .= $args->link_before . $title . $args->link_after;
if( in_array('menu-item-has-children', $classes) ){
if( $depth == 0 ) {
$item_output .= ' <i class="fa fa-bolt" aria-hidden="true"></i>';
}
}
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
/**
* Ends the element output, if needed.
*
*/
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$output .= "</li>{$n}";
}
} //
我正在尝试为我的自定义 wordpress 主题编写自定义导航菜单。
<ul class="MainMenu nav navbar-nav ">
<li class="has-megamenu">
<a href="#">MENU</a>
<div class="megamenu">
<ul class="container megamenu-background">
<li class="col-md-3 megamenu-column">
<h4>Column 1</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
<li class="col-md-3 megamenu-column">
<h4>Column 2</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
<li class="col-md-3 megamenu-column">
<h4>Column 3</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
<li class="col-md-3 megamenu-column">
<h4>Column 4</h4>
<ul class="main-menu-ul">
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
<li><a href="#">Menu Item</a></li>
</ul>
</li>
</ul>
</div>
</li>
<li class="dropdown"><a href="#">Contact</a></li>
<li class="dropdown"><a href="#">Our Story</a></li>
问题是如何编写这个结构walker
与其在 WordPress 管理员中将其构建为一个大菜单,我建议为 megamenu 中的每一列构建一个单独的菜单,然后再为联系人/关于/帐户链接构建一个菜单。我这样做的原因是因为您为每个 megamenu 列包含一个列标题,而 WordPress 管理菜单 UI 不包含向菜单中添加 non-link 项目的方法的盒子。添加 "Column Title" 内容 和 使其可编辑的最简单方法是制作单独的菜单,并使用菜单标题作为列标题。
对于functions.php:
<?php
// Register the menus
add_action( 'after_setup_theme', 'register_menus' );
function register_menus() {
register_nav_menu( 'megamenu1', __( 'Megamenu Column 1', 'theme-text-domain' ) );
register_nav_menu( 'megamenu2', __( 'Megamenu Column 2', 'theme-text-domain' ) );
register_nav_menu( 'megamenu3', __( 'Megamenu Column 3', 'theme-text-domain' ) );
register_nav_menu( 'megamenu4', __( 'Megamenu Column 4', 'theme-text-domain' ) );
register_nav_menu( 'support', __( 'Support Menu', 'theme-text-domain' ) );
}
// Add the menu title
add_filter( 'wp_nav_menu_items', [ $this, 'include_menu_title' ], 10, 2 );
function include_menu_title( $nav_items, $args ) {
if ( ! isset( $args->show_title ) || false === $args->show_title ) {
return $nav_items;
}
if ( $args->theme_location && ( $locations = get_nav_menu_locations() ) && isset( $locations[ $args->theme_location ] ) ) {
$menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
// Add the menu title. We add the UL element manually, because otherwise it would wrap AROUND the H4 later in execution of the wp_nav_menu function.
$nav_items = '<h4>' . $menu->name . '</h4><ul class="' . $args->menu_class . '">' . $nav_items . '</ul>';
}
return $nav_items;
}
// Add the dropdown class to support menu items.
add_filter('nav_menu_css_class', function($classes, $item, $args) {
if ( 'support' !== $args->theme_location ) {
return $classes;
}
$classes[] = 'dropdown';
return $classes;
}, 10, 3);
然后 header.php:
<ul class="MainMenu nav navbar-nav">
<li class="has-megamenu">
<a href="#">Megamenu</a>
<div class="megamenu">
<div class="container megamenu-background">
<?php
$common_args = [
'show_title' => true, // This is a custom arg used to indicate we want the title included.
'items_wrap' => '%3$s', // Remove the UL element. We'll add it back at the right place in the filter.
'container_class' => 'col-md-3 megamenu-column',
'menu_class' => 'vpm-menu-ul',
];
wp_nav_menu( array_merge( ['theme_location' => 'megamenu1'], $common_args ) );
wp_nav_menu( array_merge( ['theme_location' => 'megamenu2'], $common_args ) );
wp_nav_menu( array_merge( ['theme_location' => 'megamenu3'], $common_args ) );
wp_nav_menu( array_merge( ['theme_location' => 'megamenu4'], $common_args ) );
?>
</div>
</div>
</li>
<?php
wp_nav_menu([
'theme_location' => 'support',
'items_wrap' => '%3$s', // Remove the UL element.
'container' => false, // Remove the container div.
]);
?>
</ul>
这就是我使用 wordpress 设法解决这个问题的方法 walker_nav_menu
https://developer.wordpress.org/reference/classes/walker_nav_menu/
class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
/**
* Unique id for dropdowns
*/
public $submenu_unique_id = '';
/**
* Starts the list before the elements are added.
* @see Walker::start_lvl()
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = str_repeat( $t, $depth );
$before_start_lvl = '<div class="megamenu">';
if($depth==0){
$output .= "{$n}{$indent}{$before_start_lvl}<ul id=\"$this->submenu_unique_id\" class=\"container megamenu-background sub-menu dropdown-content\">{$n}";
}
else{
$output .= "{$n}{$indent}<ul id=\"$this->submenu_unique_id\" class=\"sub-menu dropdown-content\">{$n}";
}
}
/**
* Ends the list of after the elements are added.
* @see Walker::end_lvl()
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = str_repeat( $t, $depth );
$after_end_lvl = '</div>';
if($depth==0){
$output .= "$indent</ul>{$after_end_lvl}{$n}";
}
else{
$output .= "$indent</ul>{$n}";
}
}
/**
* @see Walker::start_el()
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = ( $depth ) ? str_repeat( $t, $depth ) : '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
// set active class for current nav menu item
if( $item->current == 1 ) {
$classes[] = 'active';
}
// set active class for current nav menu item parent
if( in_array( 'current-menu-parent' , $classes ) ) {
$classes[] = 'active';
}
/**
* Filters the arguments for a single nav menu item.
*/
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
// add a divider in dropdown menus
if ( strcasecmp( $item->attr_title, 'divider' ) == 0 && $depth === 1 ) {
$output .= $indent . '<li class="divider">';
} else if ( strcasecmp( $item->title, 'divider') == 0 && $depth === 1 ) {
$output .= $indent . '<li class="divider">';
} else {
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
//adding col-md-3 class to column
if( in_array('menu-item-has-children', $classes ) ) {
if( $depth === 1 ) {
$class_names = $class_names ? ' class="col-md-3 mega-menucolumn '.esc_attr( $class_names ) . '"' : '';
} else {
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
}
}else{
$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 .= $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 : '';
if( in_array('menu-item-has-children', $classes ) ) {
$atts['href'] = ' ';
$this->submenu_unique_id = 'dropdown-'.$item->ID;
} else {
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts['class'] = '';
}
$atts['class'] .= 'menu-item-link-class ';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
if( ! in_array( 'icon-only' , $classes ) ) {
$title = apply_filters( 'the_title', $item->title, $item->ID );
$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
// set icon on left side
if( !empty( $classes ) ) {
foreach ($classes as $class_name) {
if( strpos( $class_name , 'fa' ) !== FALSE ) {
$icon_name = explode( '-' , $class_name );
if( isset( $icon_name[1] ) && !empty( $icon_name[1] ) ) {
$item_output .= '<i class="fa fa-'.$icon_name[1].'" aria-hidden="true"></i> ';
}
}
}
}
$item_output .= $args->link_before . $title . $args->link_after;
if( in_array('menu-item-has-children', $classes) ){
if( $depth == 0 ) {
$item_output .= ' <i class="fa fa-bolt" aria-hidden="true"></i>';
}
}
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
/**
* Ends the element output, if needed.
*
*/
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$output .= "</li>{$n}";
}
} //