5

According to the docs of wp_nav_menu we can specify our own walker function. They suggest to copy the default one and modify it as needed. But to be honest, it is a bit too complicated for the to understand.

Could you please provide a minimal example of a custom menu walker?

Say, without sub menu items, without wrapping container, without all the classes applied by the default walker. Only one class, the .current-menu-item is important, of course. Also a way to specify the HTML element of menu items may be included.

  • Depends on what you mean with minimal. This is probably hard to beat. – fuxia Sep 1 '13 at 9:07
  • @toscho That is very useful. I just need to add the .current-menu-item class because the active page must be highlighted. – danijar Sep 1 '13 at 9:14
6

You could create a very simple walker, like this one. To detect the current item, inspect $item->current. It is TRUE for the current item only.

I wouldn’t add a class, but deactivate the useless link completely, because it doesn’t have to be clickable anyway.

Example:

class One_Line_Walker extends Walker
{
    public function walk( $elements, $max_depth )
    {
        $list = array ();

        foreach ( $elements as $item )
        {
            if ( $item->current )
                $list[] = "<b title='You are here'>$item->title</b>";
            else
                $list[] = "<a href='$item->url'>$item->title</a>";
        }

        return join( "\n", $list );
    }
}

In your theme use the walker like this:

wp_nav_menu(
    array (
        'theme_location'  => 'your_theme_location',
        'walker'          => new One_Line_Walker,
        'container'       => '',
        'items_wrap' => '<p>%3$s</p>',
        'depth'           => 1
    )
);

See my post about items_wrap for an explanation of <p>%3$s</p>.

2

Most time you only need to hook into the Walker::walk() method, for such cases, a Callback_Walker can do it which allows you to register a callback for it.

If you make use of closures and a modern PHP version (>= 5.4) you can get some of the benefits of Closure::bind():

class Callback_Walker extends Walker {
    private $callback = $callback;

    public static function create( $callback ) {
        return new self( $callback );
    }

    public function __construct( $callback, $bindClosure = TRUE ) {
        $this->callback = $callback;        
        if ( $bindClosure and $callback instanceof Closure ) {
            Closure::bind( $callback, $this, __CLASS__ )
        }
    }

    function walk( $elements, $max_depth ) {
        return $this->callback 
               ? call_user_func( $this->callback, $elements, $max_depth )
               : parent::walk( $elements, $max_depth );
    }
}

This alone does nothing so far, but blatantly copying the example by @toscho, this is how it could be used:

wp_nav_menu(
    array (
        'theme_location' => 'your_theme_location',
        'walker'         => Callback_Walker::create( function( $elements, $max_depth ) 
        {
            $list = array();

            foreach ( $elements as $item )
            {
                $list[] = $item->current
                    ? "<b title='You are here'>{$item->title}</b>"
                    : "<a href='{$item->url}'>{$item->title}</a>";
            }

            return join( "\n", $list );
        } ),
        'container'      => '',
        'items_wrap'     => '<p>%3$s</p>',
        'depth'          => 1
    )
);

I hope he may excuse ;)

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.