So, I’ve been trying to write a plugin, and I need to use the 'nav_menu_link_attributes' filter. I tried adding the filter, but it didn’t respond – at all. That is, I made it die mid-process once the filter was called.

...
# in class definition

public function __construct() {
    add_filter('wp_nav_menu_objects',array($this,'filter_menuitem'));
}

public function filter_menuitem($attrs) {
    die('SUCCESS!!!');
}

...

I looked at the source for nav-menu-template.php to see what filters were called for what, and when. So, I tried using the following filters, one at a time, in the order they appear in the source; some worked, some didn’t respond at all:

function wp_nav_menu() {
  wp_nav_menu_args                   Responded
  pre_wp_nav_menu                    Responded
  wp_nav_menu_container_allowedtags  Did not respond - not a surprise
  wp_nav_menu_objects                Did not respond - should definitely have responded
  wp_nav_menu_items                  Did not respond - should definitely have responded
  wp_nav_menu                        Did not respond - should definitely have responded
}

The only catch that would’ve made sense was that the 'pre_wp_nav_menu' can be used to generate a custom menu, skipping the WP default method which calls the following filters. But I tried using 3 different themes, and wouldn’t expect that to be the case often, or even ever.

Am I missing something? Is this a WordPress bug? Is custom menu generation really that common?

Details:
WordPress 4.4.2
Tested Themes: Elegant Themes Divi 2.4.6.1, Twenty Thirteen, Twenty Fifteen
Plugins: Only my own, none of which use the 'pre_wp_nav_menu' filter

ANSWER:
So, on @Pieter Goosen’s answer, I looked in the source of the wp_nav_menu function, and found the 'wp_page_menu' filter which is called on the full HTML code (no newlines; includes wrappers) once it’s composed. For the context of what I’m doing it’s sufficient, and after hooking and testing it, I found it works!

I also found the 'wp_list_pages' filter works as well. Instead of the full HTML with all the tags, it only lists the <li> tags separated by newlines. No wrappers are included, not even the <ul> tag. I am skeptical, however, as to what else might be using this function. It may not be invoked only for the menu. Thus, to be safe, it might be better to stick with the 'wp_page_menu' filter.

1 Answer
1

This has to do with the fallback_cb argument in wp_nav_menu(). Most nav menus do not set this parameter, so the default value is used, which is wp_page_menu.

If you look at the source code of wp_nav_menu(), with no fallback_cb set (defualt wp_page_menu), you will see the following lines of code executes

if ( ( !$menu || is_wp_error($menu) || ( isset($menu_items) && empty($menu_items) && !$args->theme_location ) )
    && isset( $args->fallback_cb ) && $args->fallback_cb && is_callable( $args->fallback_cb ) )
        return call_user_func( $args->fallback_cb, (array) $args );

This code bails out and loads wp_page_menu(). This code executes after the pre_wp_nav_menu filter, that is why you see this filter executes. All filters after that few lines will not executes because wp_nav_menu() has now loaded wp_page_menu().

If you now test the filters inside wp_page_menu(), you will see that they fire as expected.

You can have a look at my answer here to see how I have used this to determine which filter to use

Leave a Reply

Your email address will not be published. Required fields are marked *