2

So I am just now learning and playing with custom walkers and I came across this really helpful Stack Overflow question. So I implemented the answer in that answer and added this to my functions.php of my theme (which btw is an underscores theme if that helps)

class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
  function start_el ( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    // Copy all the start_el code from source, and modify
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;
        /**      * Filter the CSS class(es) applied to a menu item's list item element.
         * @since 3.0.0
         * @since 4.1.0 The `$depth` parameter was added.
         * @param array  $classes The CSS classes that are applied to the menu item's `<li>` element.
         * @param object $item    The current menu item.
         * @param array  $args    An array of {@see wp_nav_menu()} arguments.
         * @param int    $depth   Depth of menu item. Used for padding.      */
        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
        /**      * Filter the ID applied to a menu item's list item element.
         * @since 3.0.1
         * @since 4.1.0 The `$depth` parameter was added.
         * @param string $menu_id The ID that is applied to the menu item's `<li>` element.
         * @param object $item    The current menu item.
         * @param array  $args    An array of {@see wp_nav_menu()} arguments.
         * @param int    $depth   Depth of menu item. Used for padding.      */
        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
        $output .= $indent . '<li class="menu-item">';
        $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        : '';
        /**      * Filter the HTML attributes applied to a menu item's anchor element.
         *
         * @since 3.6.0
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param array $atts {
         *     The HTML attributes applied to the menu item's `<a>` element, empty strings are ignored.
         *
         *     @type string $title  Title attribute.
         *     @type string $target Target attribute.
         *     @type string $rel    The rel attribute.
         *     @type string $href   The href attribute.
         * }
         * @param object $item  The current menu item.
         * @param array  $args  An array of {@see wp_nav_menu()} arguments.
         * @param int    $depth Depth of menu item. Used for padding.        */
        $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 .'><canvas ' . $id . '>';
        /** 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 .= '</canvas></a>';
        $item_output .= $args->after;
        /**      * Filter a menu item's starting output.
         * The menu item's starting output only includes `$args->before`, the opening `<a>`,
         * the menu item's title, the closing `</a>`, and `$args->after`. Currently, there is
         * no filter for modifying the opening and closing `<li>` for a menu item.
         *
         * @since 3.0.0
         *
         * @param string $item_output The menu item's starting HTML output.
         * @param object $item        Menu item data object.
         * @param int    $depth       Depth of menu item. Used for padding.
         * @param array  $args        An array of {@see wp_nav_menu()} arguments.        */
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
    /**  * Ends the element output, if needed.
     * @see Walker::end_el()
     * @since 3.0.0
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $item   Page data object. Not used.
     * @param int    $depth  Depth of page. Not Used.
     * @param array  $args   An array of arguments. @see wp_nav_menu()   */ 
    //end pasted code
  }
  function end_el( &$output, $item, $depth = 0, $args = array() ) {
    // Copy all the end_el code from source, and modify 
    $output .= "</li>\n";   
    //end pasted code
  }

Then I changed my wp_nav_menu in the header.php to:

wp_nav_menu( array( 'theme_location' => 'primary', 
'menu_id' => 'primary-menu', 'walker' => new Custom_Walker_Nav_Menu ) );

The issue is is that the HTML is now structured like I want, however when the custom walker is implemented the anchor tags lose the text between them (which is the title of the page) and their href attribute, so they're no longer a link to the page I need them to go to.

I feel like maybe it's something involving the $attributes array but I'm not sure how to go about fixing it.

Any assistance is appreciated!

8
  • I really can't figure this out. I just don't get why whenever this is set up the same exact way in Walker_nav_menu (without the canvas element inside the anchors that is of course) it outputs the anchors href tag and the title of the page to the nav bar correctly. But it's doing neither of those things. Commented Oct 11, 2015 at 22:41
  • 2
    A direct copy/paste of your walker code works for me- href, id, and titles are populated correctly when I view source.
    – Milo
    Commented Oct 11, 2015 at 23:01
  • Weird, and are you using _s @Milo? Commented Oct 11, 2015 at 23:20
  • I am not, it's a very minimal custom theme- no nav menu related filters hooked.
    – Milo
    Commented Oct 11, 2015 at 23:24
  • Okay, so is there somewhere where I can find some of these filters and see if commenting them out will help? Commented Oct 11, 2015 at 23:27

1 Answer 1

1

This looks like just a misunderstanding about the canvas element - if a browser supports canvas, any elements you place inside a canvas simply won't display, i.e. they're fallback elements for browsers that don't support the canvas element. (That inlcudes text nodes)

I looked through the script and it looks fine - except for stuff being placed inside a canvas. links should be something like: Link Title

And you can manipulate the canvas positioning through css/javascript depending on what you're doing with them.

1
  • Thanks for your answer Benjamin. I considered that and tried to remove the canvas element from the custom walker class. It didn't work. Neither did copying the PHP exactly (without any modification) from nav-menu-template.php. I've tried moving around the $attributes array and playing around with any filters in that script that might be affecting it but with no success. I have begun implementing a JavaScript solution for this that is very successful but I also reported this as a bug to the _s developers for anyone who wants to make a custom walker class in the future. Commented Oct 15, 2015 at 13:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.