I have created (more so WordPress has) using this:
<?php
wp_nav_menu( array(
'theme_location' => 'primary-menu',
'menu_id' => 'primary-menu'
) );
?>
It outputs this:
<div id="primary-menu" class="menu">
<ul aria-expanded="false" class=" nav-menu">
<li class="page_item page-item-35"><a href="/">Blog</a></li>
<li class="page_item page-item-86 current_page_item"><a href="/">Home</a></li>
</ul>
</div>
I require it to output like this (with the link separate to the text with a custom class applied):
<div id="primary-menu" class="menu">
<ul aria-expanded="false" class=" nav-menu">
<li class="page_item page-item-35"><a class="box-link" href="/"></a>Blog</li>
<li class="page_item page-item-86 current_page_item"><a class="box-link" href="/"></a>Home</li>
</ul>
</div>
I feel like this should be possible. Please don't mark as duplicate and send me somewhere else as this is not covered whereby you want to separate the link from the text. I think I have read an article where I am able to apply a custom class though.
Thanks for looking, J.
I have created (more so WordPress has) using this:
<?php
wp_nav_menu( array(
'theme_location' => 'primary-menu',
'menu_id' => 'primary-menu'
) );
?>
It outputs this:
<div id="primary-menu" class="menu">
<ul aria-expanded="false" class=" nav-menu">
<li class="page_item page-item-35"><a href="http://example.uk/blog/">Blog</a></li>
<li class="page_item page-item-86 current_page_item"><a href="http://example.uk/">Home</a></li>
</ul>
</div>
I require it to output like this (with the link separate to the text with a custom class applied):
<div id="primary-menu" class="menu">
<ul aria-expanded="false" class=" nav-menu">
<li class="page_item page-item-35"><a class="box-link" href="http://example.uk/blog/"></a>Blog</li>
<li class="page_item page-item-86 current_page_item"><a class="box-link" href="http://example.uk/"></a>Home</li>
</ul>
</div>
I feel like this should be possible. Please don't mark as duplicate and send me somewhere else as this is not covered whereby you want to separate the link from the text. I think I have read an article where I am able to apply a custom class though.
Thanks for looking, J.
The construction of the nav menu links is controlled by the start_el()
method of the Walker_Nav_Menu
class. It's possible to change its behaviour by extending Walker_Nav_Menu
to a new class, and replacing the start_el()
method with your own. You can then use your new walker by setting the walker
argument of wp_nav_menu()
.
So the first step would be to create a new class (let's call it Box_Link_Walker
), and the copy the entirety of start_el()
method of the Walker_Nav_Menu
into it (I have removed all the inline documentation of the original method to save space in this answer):
class Box_Link_Walker extends Walker_Nav_Menu {
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;
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $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 .= $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 : '';
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$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 . '"';
}
}
$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 .'>';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
The only bits we need to worry about are this section:
$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 : '';
Where you just need to add a line that will add the box-link
class to the anchor element:
$atts['class'] = 'box-link';
And this section:
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
Which just needs to be rearranged to move the title outside of the anchor element:
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= '</a>';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= $args->after;
Now you can apply this new markup to your menu by setting the walker
argument of wp_nav_menu()
:
wp_nav_menu( array(
'theme_location' => 'primary-menu',
'menu_id' => 'primary-menu',
'walker' => new Box_Link_Walker(),
) );
That out of the way, I feel I should point out that structuring your links this way is bad for accessibility, as to screen readers - and search engine robots, for that matter - the link won't appear to have a label. I would advise against implementing this. Whatever CSS effect you're trying to apply is almost certainly possible without breaking the links' accessibility.
Walker_Nav_Menu
class (actually, only one it's method)' ; 2)preg_replace()
; 3) jQuery. – Max Yudin Commented Feb 20, 2019 at 12:46