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_lvl
and end_lvl
you 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_el
function 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_el
function:
if($depth !== 0) { return; }
That way you skip execution of code for items that are not in the first level.