I have a menu in the WordPress backend that looks like this:
What we do
Solutions
Solution 1
Solution 2
Services
Service 1
Contact
Items What we do and Contact are top level links and I only want these level 1 links to show in my main header.
As such, I created a custom walker to achieve this:
<?php
class simple_header extends Walker_Nav_Menu{
/*
* start_lvl : Responsible for start of a new level, such as <ul>
* end_lvl : Responsible for end of a level, such as </ul>
* start_el : Responsible for start of inner element, such as <li>
* end_el : Responsible for end of inner element, such as <\li>
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
}
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
}
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = $item->ID;
$class_names = 'header__nav-menu-li';
if (in_array('current-menu-item', $classes)) {
$class_names .= ' header__nav-menu-li--active';
}
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
if ($depth === 0) {
$output .= $indent . '<li data-test' . $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 : '';
// New
if ($depth === 0) {
$atts['class'] = 'header__nav-menu-anchor link-header';
}
if (in_array('current-menu-item', $item->classes)) {
$atts['class'] .= ' link-header--active';
}
$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 . '"';
}
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
/** This filter is documented in wp-includes/post-template.php */
$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 );
}
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
if ($depth === 0) {
$output .= "</li>\n";
}
}
}
?>
However, with the above walker, it still prints out the child markup. The HTML looks like this:
<li class="header__nav-menu-li header__nav-menu-li--active">
<a href="#" class="header__nav-menu-anchor link-header link-header--active">What we do</a>
<a href="#">Solutions</a>
<a href="#">Services</a>
</li>
I have defined $depth === 0 in my walker, so unsure why it's printing child links?
Normally, at the
start_lvlandend_lvlyou would output<ul>and</ul>tags respectively to start and end a new list.Every item in your menu consists of an anchor tag wrapped inside a list item:
<li><a href="target-url">Target</a></li>In your code you only have an 'if' statement around the code that adds the list item tags to the output.
On the last line of your
start_elfunction you still add the anchor.Instead of wrapping an if statement around the parts where you want to output markup, my advice would be to add the following line of code as the first line of your
start_elfunction:if($depth !== 0) { return; }That way you skip execution of code for items that are not in the first level.