Currently our breadcrumbs are very inconsistent when visiting any page that is either A) a wildcard URL or B) a MENU_CALLBACK type of item. There's been many work-arounds the current breadcrumb problem, including introducing the wildly inconsistent urls of "admin/build/node-type/x" and "admin/build/menu-customize". This patch restores reasonable URLs to these paths, now "admin/build/types/x" (as it was in Drupal 5) and "admin/build/types/menus" (note the pluralization for consistency with the "types" plural form). Of course "admin/build/block" should be fixed too, but block module's code was otherwise unaffected by the breadcrumb changes, so I figured that'd be best left for a separate issue.

This patch makes breadcrumbs work automatically for all MENU_CALLBACK items, meaning you don't need to have items show up in the normal menu display in order for the breadcrumb to work correctly. This most notably solves problems with the content type configuration and within the menu item configuration, and preemptively solves the exact same issue we're about to have with #371374: Add ImageCache UI Core when configuring image presets.

Note that because of the change from admin/build/node-type to admin/build/types, the CCK contrib module will most definitely need to be updated also. Though it'll be a bit of work to update, the great thing is that it's no longer necessary to make manual entry for every single content type and field. Currently CCK loops through all these types and fields and makes a separate entry for each one. Presumably this is because the breadcrumb didn't use to work with dynamic paths, and it was the only way to make it work properly without worse hacks. Now with this patch CCK can define a single menu entry for all types and all fields, reducing the overall size of the menu registry.

Also note: there's 1 failure right now in this patch because the "reset" link on menu items does not work properly (it always sends items to the "navigation" menu regardless of the module setting). This is a pre-existing bug that SimpleTest does not properly catch, this patch just exposes the problem.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

quicksketch’s picture

Oh I meant to include some example URLs that are fixed with this change. Compare the breadcrumb before and after applying this patch. On some forms the breadcrumb is entirely empty (only including the "Home" link), and on others it's just missing a few items in the middle of the path.

node/[nid]/delete
admin/build/node-type/[node-type]/delete (now admin/build/types/[node-type]/delete)

admin/build/menu/item/[mlid]/edit (now admin/build/menus/[menu-name]/[mlid])
admin/build/menu/item/[mlid]/delete (now admin/build/menus/[menu-name]/[mlid]/delete)
admin/build/menu/item/[mlid]/reset (now admin/build/menus/[menu-name]/[mlid]/reset)

I'm sure there are more paths than this fixed, especially within contrib modules that have deep configuration such as ImageCache, Flag, and Organic Groups.

webchick’s picture

I wish I could subscribe to this twice! The inconsistent node type paths are absolutely maddening.

webchick’s picture

+      // link.      $query = db_select('menu_links', 'ml');

Oopsie. :)

This will need looking at by chx and Peter, of course. But I find the resulting code much easier to read.

chx’s picture

The patch is unreviewable without -p.

webchick’s picture

Re-rolled with -p.

Damien Tournoud’s picture

One thing that bumps on me:

+    // Replace wildcards in the active trail map using the current path.
+    if (!empty($item['in_active_trail'])) {
+      $args = arg();
+      foreach ($map as $index => $part) {
+        if ($part == '%') {
+          $map[$index] = $args[$index];
+        }
+      }
+    }

This probably needs to use the to_args() magic.

chx’s picture

This patch ties _menu_link_translate to arg(). If you look around in menu.inc you will see that such ties are VERY few. menu_get_item will default to $_GET['q'] if not give a path -- and what will you do if you do pass in a path? This is not acceptable.

chx’s picture

We need to think over what we want from menu API and likely write more docs... let's brainstorm more here. This is a LOT deeper than just adjusting breadcrumbs.

pwolanin’s picture

Um, parts of this are "won't fix". We changed the menu paths for damn good reason - otherwise you hsve to blacklist all possible core and contrib paths from being menu names. I.e. it's fragile and likely to break in bad ways.

quicksketch’s picture

We changed the menu paths for damn good reason - otherwise you hsve to blacklist all possible core and contrib paths from being menu names.

As far as I can tell, we changed the menu paths because of a limitation in the menu system that made breadcrumbs not work once underneath a MENU_LOCAL_TASK. I'm not sure what you mean by "blacklist all possible core and contrib paths from being menu names". This patch would drastically *reduce* the number of menu entries. Right now CCK for example loops through ALL the fields for ALL types and manually makes an entry for each one. The new approach would replace these entries with a much simplified, single menu handlers: admin/build/content/types/%node_type/fields/%field.

I'm working on a reroll since we're going to run into this breadcrumb/path problem all over again in the ImageCache UI.

quicksketch’s picture

Status: Needs work » Needs review
FileSize
44.01 KB

This patch ties _menu_link_translate to arg().

_menu_link_translate() is oddly central to the loading of menu items and checking access control. _menu_link_translate() actually sets the $item['access'] flag, so unless we move the swapping of % wildcards up higher in the callback chain, it seems like the most appropriate place to put such logic. The use of arg() is only applicable when the item being checked is a page that the user is actively visiting, so it seems like this should have minimal side-effect on any other functionality.

Here's a patch that should pass tests, since (surpise!) SimpleTest was correct in that I had broken something in the previous patch. I still think the test is slightly flawed, but it adequately caught the problem caused by the changes. This patch also makes some code cleanup to be more DNTNG-friendly.

I'm still looking into Damien's suggestion in #6, since I'm not really sure how that to_arg() magic works.

I've marked this patch "needs review" so that testing bot can have a crack at it.

Status: Needs review » Needs work

The last submitted patch failed testing.

quicksketch’s picture

The patch above totally breaks book.module breadcrumbs it seems. Back to the code...

quicksketch’s picture

Status: Needs work » Needs review
FileSize
47.55 KB

New version, even less code than before. More docs on the menu_tree_data() function. This patch should work with book.module in addition to supporting the dynamic paths such as admin/build/types/%/delete. Let's see what testing bot thinks of this one.

This version also (hopefully) addresses the problem of _menu_link_translate being tied to arg(). Now an "active_map" property is passed down in menu items that are in the active trail.

Status: Needs review » Needs work

The last submitted patch failed testing.

quicksketch’s picture

Status: Needs work » Needs review
FileSize
48.53 KB

Updating for a missed "node-type" URL that caused the above test to fail.

pwolanin’s picture

Status: Needs review » Needs work

This must not be committed -- the choice of node-type and menu-custom as being distinct from e.g. menu was deliberate and important for the menu system worrking correct when various contrib modules are enabled.

moshe weitzman’s picture

I tested this out and the breadcrumbs are much much more predictable and helpful with this patch. I really hope the menu maintainers and quicksketch find a way to make improvements here without introducing bugs. I am really OK with tossing features from the menu system if that means more code and UX sanity.

chx’s picture

You want to save the original_map from menu_get_item into $item['original_map'] and pass that around. Using arg() breaks internal redirect.

pwolanin’s picture

basically I have to be able to add a node type or menu with a name that's the same as a core tab path and not have that break. We cannot blacklist all possible paths (imagine I want to add an adminstrative View, or my module creates a new menu that can be managed via the menu module UI).

Our conclusion for D6 that any attempt to blacklist a list of known paths is fundamentally fragile to the point of being a bug.

We can and should figure out how to make breadcrumbs work better - I had some code to fix this for node types, but it was too late for D6 code freeze. One possibility is using hook_menu_link_alter().

quicksketch’s picture

Title: Better breadcrumbs, kill node-type and menu-customize URLs » Better breadcrumbs for callbacks and dynamic paths

I've split off the menu-customize/node-type re-naming to #508570: Restore URL consistency for node types and menus, so we can reconsider that particular change without affecting the menu.inc changes done here. I'll re-roll with the applicable changes only, though it won't correct items like "menu-customize" from being dropped from the breadcrumb.

quicksketch’s picture

Status: Needs work » Needs review
FileSize
12.7 KB

Here's a patch for testing which implements the excellent suggestion from chx to use $item['original_path'] rather than arg(). It strips out all the menu path changes (meaning items are still dropped from the breadcrumb when editing content types or menus), but maintains an increased functionality when working with items that are underneath dynamic paths.

Status: Needs review » Needs work

The last submitted patch failed testing.

quicksketch’s picture

Status: Needs work » Needs review
FileSize
12.09 KB

Hmm, I think I got a test bot with notices enabled or something. Anyway, here's another version that correctly uses db_or() to match DBTNG best practices.

Status: Needs review » Needs work

The last submitted patch failed testing.

quicksketch’s picture

Status: Needs work » Needs review
FileSize
12.04 KB

Notice cleanup.

Status: Needs review » Needs work

The last submitted patch failed testing.

quicksketch’s picture

Status: Needs work » Needs review
FileSize
15.75 KB

Arg, okay now fixes all the notices hopefully.

After some investigation, it seems that having the $item['original_path'] available also makes breadcrumbs within tabs a piece of cake. This patch abstracts this % to value replacement, since now it looks like we're doing this exact task in 4 different places in menu.inc.

quicksketch’s picture

Title: Better breadcrumbs for callbacks and dynamic paths » Better breadcrumbs for callbacks, dynamic paths, tabs
Category: task » bug
Priority: Normal » Critical
FileSize
25.82 KB

Now with tests for breadcrumbs. I'm moving this to a bug report since breadcrumbs clearly are very broken, we just didn't have any tests previously to prove so. There's no way we can ship another version of Drupal with breadcrumbs in their current state, plus this issue is blocking #371374: Add ImageCache UI Core.

sun’s picture

amc’s picture

Issue tags: +breadcrumbs

Tagging.

pwolanin’s picture

I don't understand the purpose of this:

+    // Ensure that the parent is not a hidden menu entry when reseting items.
+    if (isset($item['reset'])) {
+      $query->condition('hidden', 0, '>=');
+    }

(also a typo in the comment)

There are some APi changes it seems - passing an array of items instead of a query result (more or less the same thing anyhow w/ DBTNG) but are those needed for this fix? I certainly think that's the right way to go for D7 in general, but not sure they shoudl be part of this patch.

quicksketch’s picture

The API change to _menu_tree_data() is mostly because I couldn't figure out for the life of me how the current function works (the whole, "we're one loop behind, pop off and return the previous..."), and I needed to make the change there to include hidden items in the tree. Since I needed to rewrite the function, I figured it would be a good opportunity to correct the arguments that are passed into it.

The "reset" check prevents the Menu module "reset" functionality from re-parenting a menu link to a hidden item that is not in the interface. Basically when ordering menu items through the interface, you have to assign parents that visibly exist in the menu (MENU_NORMAL_ITEM), but when building the links off of the menu router, Drupal allows any type of link to be a parent so that breadcrumbs can be built properly. The particular problem I had was with the "user/logout" and "user/login" links. Because the path at "user" is NOT a MENU_NORMAL_ITEM (it's a callback), if you used "Reset" on the link through the Menu UI, it would end up being parented to the MENU_CALLBACK. While this might actually be correct when it comes to the breadcrumb, it was a strange thing to have happen in the UI, since it would indent the "Logout" link since the "user" item was it's parent, but the "user" item was not visible. There might be a better way to solve this than special casing for this the menu.module UI, especially since the "reset" functionality is broken anyway (it will always shove all links into the "navigation" menu, regardless of where the link was originally defined).

pwolanin’s picture

Argh where did this code come from (it's not from the patch)?

     $item = is_object($item) ? get_object_vars($item) : $item;

That should be removed from D7 - links should be only ever exist as arrays (by design) to avoid this sort of stupid casting.

pwolanin’s picture

looks like debug code in the patch:

-hidden = TRUE
+;hidden = TRUE

I'd remove the 'reset' bit that sounds like a different issue.

Also, if you think that part (or all) of this is bugfix material that we should backport to D6, it would be better not to change the API signature this much

quicksketch’s picture

The get_object_vars() call looks like it was added #320510: [DBTNG] revamp menu.inc with DBTNG syntax. I'm not sure if my changes make it unnecessary or not.

The hidden change is definitely a bug in the patch. I don't think a backport to D6 would be wise, since this fundamentally changes the way link structures are built, even if we didn't change the function signatures.

I'd like to remove the "reset" exception, but that would consequently break our (already not-quite functioning) reset test. We might need to fix that first, though fixing the way "reset" works could take a significant effort, since it really needs to be completely rethought. The current approach to reset doesn't work at all, other than to move the link to the navigation menu at the root level.

pwolanin’s picture

Well, let's remove the object_get_vars.

I'm not totally satisified with the code changes - for example, we shoudl be smart enough not to need to pass in the plid.

pwolanin’s picture

Status: Needs review » Needs work
quicksketch’s picture

Assigned: quicksketch » Unassigned
FileSize
25.32 KB

This patch removes the unnecessary ;hidden=TRUE

I'm giving up on this issue for a least a while. The feedback here is driving me insane.

quicksketch’s picture

Okay, per a classic webchick-calming down and some inner reflection, here's what I'd like to have happen on this issue.

I'm stuck from continuing further on this issue because I don't know how to fix things any further (within the scope of this issue). I set out to "fix the breadcrumbs" by solving the following:

- The breadcrumb should maintain a true "hierarchy" that is reflected by every link the user clicks into the site. Steps within the hierarchy are not skipped, nor does a step suddenly disappear when it was present on the previous page.

- The breadcrumb stays even if you are on a tab, or a sub-tab of a page. This applies not only to admin pages, but also to book nodes or other trees whose breadcrumb mirrors the URL path.

- The breadcrumb is present (and accurate) for all confirmation pages. It should contain all the pages that it took to get to the confirmation form.

So that's what I've set out to do, and it does seem to be working. I've added additional tests to make sure that all these cases work and hopefully don't become broken again.

Now we need to decide, what else needs to be done to fix breadcrumbs? There are other problems that we're running into, such as object_get_vars() call and the "reset" link functionality being fundamentally broken. However, I'd really, really just like to get breadcrumbs "fixed" and move on. These problems are not directly caused nor affected by this patch, and it seems they should be left to followups. If there's a *better* way of handling the "reset" problem, I'd like to know what that is (I've tried several already), but the current approach is the best I can think of.

I need to know if the fundamental approach I'm using is even close to correct. This patch is essentially allowing both dynamic paths such as "node/%/edit" and explicit paths such as "node/10" to reference each other as necessary to get a full parentage. Previously "node/%/edit" (which is not in the menu tree) didn't even try to check against an explicit path like "node/10". Now it tries to match on explicit paths first and the falling back to dynamic ones by adding an extra condition to the "IN ()" SQL statement we're using (it's already using an IN statement because we're also matching on ). In addition it includes MENU_CALLBACK items when building up parentage, so they are included in the breadcrumb. Other than those specific changes, the rest of the code is just being updated to make those two things possible.

drewish’s picture

subscribing.

pwolanin’s picture

there seems to be some possible overlap with #509584: APi fixes for menu_tree_data() including depth param, or maybe we should just roll that proposed change in if we are already reworking those menu functions.

There was already a TODO in the code about brorken active trail with wildcard callback paths.

I'm not sure my comment above is right wrt not actually requiring plid, however this implementation of function menu_tree_data() will be dramatically less efficient, since it will repeatedly iterate over every link in the menu and essentially throws away the information we got by ordering by the p1...p9 columns. The existing D7 implementaiton may be faulty this way also, since it's no longer pulling results out of a resource. Possibly we shoudl do an array_reverse() and array_pop() instead of foreach.

quicksketch’s picture

this implementation of function menu_tree_data() will be dramatically less efficient, since it will repeatedly iterate over every link in the menu and essentially throws away the information we got by ordering by the p1...p9 columns.

To clarify, it seems that our current implementation uses foreach() over a database result object. Normally each call to foreach() would "rewind" the result set and start from the beginning, but our implementation does not do this for DB compatibility (according to Crell). So our rewind function does nothing at all (from includes/database/prefetch.inc):

  public function rewind() {
    // Nothing to do: our DatabaseStatement can't be rewound.
  }

So what we need to do to keep the same efficiency is put an array_pop/_shift() in our loop to keep this same efficiency, but be much more clear about what's actually happening here.

sun’s picture

Issue tags: +API clean-up

Tagging.

sun’s picture

Interestingly, Damien and me came up with a similar solution over in #576290: Breadcrumbs don't work for dynamic paths & local tasks after we had a very long analysis + debugging session in IRC.

sun.core’s picture

Breadcrumbs are still horribly broken in HEAD, will try to review this ASAP.

sun.core’s picture

Status: Needs work » Closed (duplicate)

Meh, last follow-up was meant for #576290: Breadcrumbs don't work for dynamic paths & local tasks

Now officially marking as duplicate.

gryffindor426’s picture

Status: Closed (duplicate) » Needs review
Issue tags: -breadcrumbs, -API clean-up

drupal_menu_breadcrumbs.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +breadcrumbs, +API clean-up

The last submitted patch, drupal_menu_paths.patch, failed testing.

mr.baileys’s picture

Status: Needs work » Closed (duplicate)

This was marked as a duplicate of #576290: Breadcrumbs don't work for dynamic paths & local tasks in #49 so should not be re-opened (unless you feel it is not a duplicate, in which case please provide some arguments as to why this is not a dupe)