menus - wp_nav_menu() | Outputting my own custom code using built in features

admin2025-06-03  1

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.

Share Improve this question edited Feb 20, 2019 at 13:02 fuxia 107k39 gold badges255 silver badges461 bronze badges asked Feb 20, 2019 at 12:31 Jason Is My NameJason Is My Name 3782 gold badges7 silver badges21 bronze badges 2
  • Sure, it's possible. At a glance there are at least three solutions: 1) Custom Walker_Nav_Menu class (actually, only one it's method)' ; 2) preg_replace(); 3) jQuery. – Max Yudin Commented Feb 20, 2019 at 12:46
  • Thats great news, are you able to guide me through the walker set up - please? – Jason Is My Name Commented Feb 20, 2019 at 13:00
Add a comment  | 

1 Answer 1

Reset to default 1

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.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1748884733a314527.html

最新回复(0)