Make WordPress Core

Opened 14 years ago

Last modified 5 years ago

#14142 reopened defect (bug)

Custom Walker class for navigation menus

Reported by: denniswinter's profile dennis.winter Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 3.0
Component: Menus Keywords: needs-patch
Focuses: Cc:

Description

I have tried to extend the Walker_Nav_Menu class, I just needed to overwrite the start_el method. So i added "walker"=>"My_Walker" to wp_nav_menu, I've got an error message, that the method "walk" could not be accessed statically. After a short look at the code in "nav-menu-template", I realized that in the method "walk_nav_menu_tree" the object initializer "new" is missing.

My solution can be found in the attached file.

As you can see, I've just added a "new" in front of $r->walker

And it works

Attachments (1)

nav-menu-template.diff (572 bytes) - added by dennis.winter 14 years ago.
Diff file

Download all attachments as: .zip

Change History (14)

#1 @filosofo
14 years ago

"walker" should be an instantiated object, not a class name.

@dennis.winter
14 years ago

Diff file

#2 follow-up: @dennis.winter
14 years ago

Ok, then the documentation has to be changed! "(string) (optional) Custom walker to use" this implies a String has to be used!

#3 in reply to: ↑ 2 @filosofo
14 years ago

Replying to dennis.winter:

Ok, then the documentation has to be changed! "(string) (optional) Custom walker to use" this implies a String has to be used!

Where does it say this?

#5 @filosofo
14 years ago

  • Keywords has-patch removed
  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Severity changed from major to normal
  • Status changed from new to closed

The Codex is a wiki, so any logged-in user can edit it. I just changed it to say "object."

#6 @dennis.winter
14 years ago

Ah, ok, next time i will change it by myself ;) Thx

This ticket was mentioned in Slack in #core by nyordanov. View the logs.


8 years ago

#8 @westonruter
8 years ago

  • Keywords needs-patch added
  • Milestone set to Future Release
  • Resolution invalid deleted
  • Status changed from closed to reopened

Nav menus in the customizer can be previewed with selective refresh when the walker is JSON-serializable per https://make.wordpress.org/core/2015/07/29/fast-previewing-changes-to-menus-in-the-customizer/

The logic in \WP_Customize_Nav_Menus::filter_wp_nav_menu_args() allows selective refresh if walker is empty or a class string. If wp_nav_menu() is called with an instantiated walker object, this cannot be JSON-serialized, and so it cannot be selectively refreshed. Therefore, a string should be able to be passed in in addition to passing in a pre-instantiated object.

The patch in nav-menu-template.diff isn't quite right. It should do this instead:

- $walker = ( empty($r->walker) ) ? new Walker_Nav_Menu : $r->walker; 
+ $walker = $r->walker;
+ if ( ! empty( $r->walker ) && is_string( $r->walker ) ) { 
+     $walker = new $walker;
+ }

The phpdoc @param also need to be updated.

Last edited 8 years ago by westonruter (previous) (diff)

#10 @westonruter
7 years ago

  • Milestone changed from Future Release to 5.0

#11 @johnbillion
6 years ago

  • Milestone changed from 5.0 to 5.1

#12 @pento
6 years ago

  • Milestone changed from 5.1 to Future Release

This ticket needs testing and a decision.

#13 @saas
5 years ago

Custom walker won't be to utilize "Partial Refresh", if walker object is passed.

So after reading reviewing
https://github.com/WordPress/WordPress/blob/4f35907147df1afdc99143af3813604967807a40/wp-includes/class-wp-customize-nav-menus.php#L1369

I passed "Walker Class name as string" and it didn't worked either, was throwing

`
PHP Fatal error: Using $this when not in object context
`

Then I saw this post
https://wordpress.stackexchange.com/q/295461/8521

And in combination with passing walker as string and applying this filter solves my issue.

So patching this function
https://github.com/WordPress/WordPress/blob/7d74080b80bf0fee57de5f9c7137c9b4e31e3953/wp-includes/nav-menu-template.php#L576

as

function walk_nav_menu_tree( $items, $depth, $r ) {

  $walker = $r->walker;
  if ( ! empty( $r->walker ) && is_string( $r->walker ) ) {
      $walker = new $walker;
  } else {
      $walker = new Walker_Nav_Menu;
  }

  $args   = array( $items, $depth, $r );

  return call_user_func_array( array( $walker, 'walk' ), $args );
}

solves the issue.

Note: See TracTickets for help on using tickets.