1

I would like to add a 'link_before' control for a wp_nav_menu(), like that:

if ( strpos( $args->link_before, 'checkbox' ) == true ) {
    $args->link_before = '<input id="toggle' . $item->ID . '" type="checkbox" /> <label for="toggle' . $item->ID . '">';
}

To use the "checkbox before the link" trick in some menu.

How can I do that? Is it possible with "functions.php?

1

The best way to customize a navigation menu is to use a custom 'walker' function.. Here are the steps how to achieve the customization that you want!

  1. Create a "wp-custom-nav-walker.php" file in your theme directory for a new custom 'walker' class.
  2. Extend the Walker_Nav_Menu class and copy the class' function that you want to modify and override it in the new class, such like this:

    <?php
    class WP_Custom_Nav_Walker extends Walker_Nav_Menu {
    
    /**
     * Start the element output.
     *
     * @see Walker::start_el()
     *
     * @since 3.0.0
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $item   Menu item data object.
     * @param int    $depth  Depth of menu item. Used for padding.
     * @param array  $args   An array of arguments. @see wp_nav_menu()
     * @param int    $id     Current item ID.
     */
    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[] = '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' . $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        : '';
    
        /**
         * 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 .'>';
        /** This filter is documented in wp-includes/post-template.php */
    
    
        // YOUR ADDED CONTROL STARTS HERE!!
        if ( $args->link_before === 'checkbox' ) {
            $item_output .= '<input id="toggle' . $item->ID . '" type="checkbox" /> <label for="toggle' . $item->ID . '">';
        }
        $item_output .= apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
        // YOUR ADDED CONTROL ENDS HERE!!
    
    
        $item_output .= '</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 );
    }
    
    }
    
  3. Include the "wp-custom-nav-walker.php" file in your "functions.php" file:

    // Register Custom Navigation Walker
    require get_template_directory() . '/wp-custom-nav-walker.php';
    // OR
    require_once('wp-custom-nav-walker.php');
    
  4. And use it like this:

    // Primary navigation menu.
    wp_nav_menu( array(
        'menu_class'     => 'nav-menu',
        'theme_location' => 'primary',
        'link_before'    => 'checkbox',
        'walker'         => new WP_Custom_Nav_Walker(),
    ) );
    

For more info you can check the wp_nav_menu() code reference.

2
  • I did it! but I have some problem. I got some fatal error becuse it look for the file in my parent theme and not in the child. (no suitable wrapper could be found ) However, I try to put the file on the directory it expect, but the code doesn't work. In the original file this code work perfectly!
    – laura
    Aug 7 '15 at 15:20
  • @user3686751 If your theme is using a custom 'walker' function then you need to extend that walker class instead of Walker_Nav_Menu. For more info look at this answer. Aug 7 '15 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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