#597994: Fatal error: Call to undefined function uc_price() in ...www/sites/all/modules/ubercart/uc_order/uc_order.module on line 1438 is the latest of a variety of issues I've seen related to the fact that menu_breadcrumb does some of its work in hook_init().

The patch in #275622: Doesn't work for Views pages is a good improvement, and admittedly I thought it was sufficient (glancing at the menu_get_item() code, I'm a bit surprised that it causes problems), but I've always been a little confused as to the reason for not just doing everything at the preprocess_page stage. On the face of it, breadcrumbs are purely a theme-level feature, after all.

My worry is that it was originally done purely to get in ahead of template_preprocess_page(), which calls drupal_get_breadcrumb(); and consequently causes the active trail to be established using the currently-selected menu (and statically cached, with no way of re-generating it, sadly).

but we can easily deal to that issue in hook_theme_registry_alter(&$registry) with something like array_unshift($registry['page']['preprocess functions'], 'menu_breadcrumb_set_active_menu_name');

So is there a good reason for using hook_init()? (is it simply that other modules out there are also triggering the active trail generation too early?), or should we look seriously at shifting all of this code?

(Or potentially make it a configurable option as to when this code is run?)

Comments

xurizaemon’s picture

Thanks for opening this ticket, jweowu. I suspect you're right - looking at the issue queue, I got the same impression.

Without doing the huge amount of debugging required to investigate all those issues, it looks like half the menu_breadcrumb issue queue could be a result of that single piece of code in hook_init().

I'm happy to try your suggested solution and see if it fixes those other issues. I can't speak to why it was put there. I don't expect we'll find out from the original author, as s/he doesn't appear to have been active in this area in some time.

jweowu’s picture

I was looking at one of the recently-updated book issues, and I think I just realised why hook_init() was used for this module.

#595282: Menu weights gives us control over whether menu_breadcrumb will choose the book's own menu, but it can't stop book_nodeapi($node, 'view', FALSE, TRUE) from calling menu_set_active_menu_name().

If our menu selection happens in menu_breadcrumb_init() then book.module subsequently over-rides the menu selection, and unfortunately it also calls menu_set_active_trail() at that point.

menu_set_active_trail() is a pain. You can hand it a trail to use, but there's no way to ask it to generate one after it's been set once, so if you simply want it to generate the active trail for your chosen menu, you either have to be the first one to trigger menu_set_active_trail(), or you have to duplicate its code elsewhere (book.module has book_build_active_trail() for this purpose).

As it is now, with menu_breadcrumb doing all its work in hook_init(), our breadcrumbs are generated based on the menu we want before hook_nodeapi() ever runs.

If we defer the breadcrumb generation to preprocess_page, then the active trail for book pages will be changed by book_nodeapi() before we generate the breadcrumb.

The flip side is that we get an incorrect breadcrumb in other circumstances if we don't defer to page preprocessing (see #275622: Doesn't work for Views pages).

I'm not sure there's a clean solution to this.

The hacky approach that comes to mind is:

  1. Duplicate the necessary parts of menu_set_active_trail(). Let's call our version menu_breadcrumb_get_active_trail().
  2. Move our code from hook_init into preprocess_page, as discussed.
  3. Find our menu name, as usual.
  4. Call menu_get_active_menu_name() to find out what the currently-selected menu name is.
  5. If it is anything other than 'navigation', assume that something else has probably generated the active trail. (Alternatively, simply inspect menu_get_active_trail() and look for the 'menu_name', but I don't know if that would work in all circumstances). I'm not aware of a way to simply establish if there is an active trail, without causing it to be set in the instance where there wasn't.
  6. Call menu_set_active_menu_name() with our menu name.
  7. If we do need to regenerate the active trail, call menu_set_active_trail(menu_breadcrumb_get_active_trail())
  8. Continue as normal with drupal_get_breadcrumb(), etc...

menu_set_active_trail() probably won't change in core, so duplicating it mightn't be such an awful thing, but I'm hoping someone can improve upon this, because it seems pretty gross to me.

(Updates to core to facilitate the checks and over-rides that we want would be much better, but what are the chances of that happening?)

jweowu’s picture

As a footnote, I was just investigating the report that menu_get_item() in menu_breadcrumb_init() causes problems.

Firstly, menu_get_item() statically caches its result, so two calls with no arguments and no intervening change to $_GET['q'] will not cause any processing of note to occur.

hook_init() is invoked as the very last step of the bootstrap process in _drupal_bootstrap_full()

Immediately after that, index.php calls menu_execute_active_handler() which potentially calls menu_rebuild(); and then immediately calls menu_get_item().

So the places where problems with this call could possibly occur seem to be isolated to:

1. Any hook_init() running later than menu_breadcrumb_init()
2. Situations where menu_rebuild(); was needed.

That possibly means that an increased weight for menu_breadcrumb could be used as a workaround for whatever is going on. That's also pretty hacky and unreliable, though.

edit: Issue described in more detail here: #342131: Use of hook_init() causes problems for modules with autoloading URL arguments (note comment #2)

xurizaemon’s picture

Issue summary: View changes
Status: Active » Closed (outdated)

Cleaning up issue queue. Closing all D6 issues.

If you believe this issue still applies to a supported version, feel free to re-open it. That would be a great time to check if the issue contains clear steps for reproducing the bug!

Thanks and sorry for any inconvenience.