Walker class: Problems with understanding how walk() method can be called without error

I am struggling with understanding how WordPress uses the Walker class. In particular, I don’t understand the walk() method (I think).

First, let me explain what I understood:

When calling wp_nav_menu(), it’s possible to add an array as argument, containing infos/options such as depth, container, theme location, walker to use and so on.

Inside wp_nav_menu(), these arguments are merged witch default values. The resulting array (later cast to object) called $args.

Inside wp_nav_menu(), walk_nav_menu_tree() is called, receiving $sorted_menu_items, $args->depth and $args as arguments.

Until that point I am able to understand what is happening, but inside walk_nav_menu_tree(), the Walker class is instantiated, and this is where I can’t follow along anymore.

After instantiation, the walk() method of the Walker used is called.

According to its signature, walk() accepts two arguments: $elements and $max_depth.

But in walk_nav_menu_tree(), walk() gets passed only one argument called $args, which is an array containing the arguments passed to walk_nav_menu_tree(), which are actually $items(= $sorted_menu_items), $depth (= $args->depth), $r (= $args).

As if this isn’t confusing enough already, at the beginning of the walk() method, there is this line:

$args = array_slice(func_get_args(), 2);

What happens here is using func_get_args(), all arguments passed to the method are gathered into an array, from which then the first two parts are omitted, which leaves us with $args only containing a the contents of a third argument that is not visible in the method signature.

Now, how can this work at all – as I pointed out walk() is called only with one argument, so how can $elements and $max_depth be left out, without resulting in an error?

1 Answer
1

Per comments, it’s called with call_user_func_array, so the 1st 2 elements get assigned to the declared arguments $elements and $max_depth, leaving the third element ($r which is the original $args) to be assigned via array_slice to $args. Eg

function wpse172812( $elements, $max_depth ) {
    $args = array_slice(func_get_args(), 2);
    error_log("elements=$elements, max_depth=$max_depth, args=" . print_r( $args, true ));
    // elements=arg1, max_depth=arg2,
    // args=Array ( [0] => Array ( [menu] => my_id [menu_class] => my_class ) )
}
$args = array( 'arg1', 'arg2', array( 'menu' => 'my_id', 'menu_class' => 'my_class' ) );
call_user_func_array( 'wpse172812', $args );

Leave a Comment