At the very end of the development cycle in Drupal 6 (around RC2), a few menu paths were changed to prevent edge-case naming from causing problems, see #204415: Creating content types 'add', 'theme', 'list' (and possibly others) causes various problems. These changes ended with the following renamings:

Content type configuration:
D5: admin/content/types/[node-type]
D6: admin/content/node-type/[node-type]

Menu configuration:
D5: admin/build/menu/[menu-name]
D6: admin/build/menu-customize/[menu-name]

A recap of the problem in an example scenario (scenario 1):
- The path "admin/build/types" is the path for listing node types.
- The user creates a new content type called "fields".
- Now the user enables CCK, which makes the path "admin/build/types/fields". One path is going to win and the user won't be able to access either the field listing screen or the configuration screen for the "fields" content type.

Another possible scenario with similar effects (scenario 2):
- The path "admin/build/types" is the current path for listing node types.
- The user creates a new content type called "add".
- Now the user is unable to add new content types because "admin/build/types/add" is the configuration screen for the "add" content types.

So I can see why this solution was reached (just rename the paths and we don't have the problem), but I think that the inconvenience of the URL change outweigh the benefits of allowing a user to use any name they desire. This problem mostly affects node types, since menu already prefixes "menu-" to the front of any user-entered names, preventing the problem almost entirely there. Unless a module were to make a path like "admin/build/menu/menu-[something]", it won't have a problem at all.

The solution I'm proposing is to restore consistency in our paths by implementing blacklists against existing menu paths. I know this was proposed once before, since that's what was put in place in Drupal 5 to prevent this problem for basic words. A blacklist already exists in Drupal 6 for the keys "theme" and "0". This patch makes the change that the list is not "hard-coded", but instead based on the existing entries in the menu system. When the user is creating a content type (scenario 2) we just check against the current list of paths that are reserved by other modules.

However this does not solve the first scenario, where a user creates a content type like "fields", then enables CCK later. In such a situation CCK would implement a hook_requirements to prevent the module from being enabled if there is a conflicting name.

function content_requirements($phase) {
  $requirements = array();
  // Ensure translations don't break at install time
  $t = get_t();

  if ($phase == 'install') {
    $types = node_type_get_types();
    if (isset($types['fields'])) {
      $requirements['cck'] = array(
        'title' => $t('CCK'),
        'description' => $t('Content requires the path "fields", but there is already a content type with this name. Please rename this content type before enabling Content module.'),
        'severity' => REQUIREMENT_ERROR,
      );
    }
  }

  return $requirements;
}

All things considered, the amount of work and code required to prevent this problem seems like it is worth the benefit of having consistent URLs.

This originated from the discussions in #483614: Better breadcrumbs for callbacks, dynamic paths, tabs and #180861: Customize Menu page doesn't show menu path / breadcrumb in Nav Block, and it *does* correct a problem with the breadcrumbs, but the reasoning for this patch is based on the correction of our URLs, not to fix one of the problems with the breadcrumb, which is being handled separately.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

quicksketch’s picture

FileSize
38.41 KB

Here's a patch with simplified logic per chx's advice. We loose the ability to get a list of reserved words, but it's much much more efficient. Considering that the list will only be 5 or 6 words total, it seems overwhelming and unnecessary to provide the end-user with that much information.

pwolanin’s picture

Status: Needs review » Needs work

This is not robust, since we rely on each contrib module to implement this hook_requirements correctly?

pwolanin’s picture

It would be preferable to add an intermediate path, e.g.:

admin/content/node-type/[node-type] becomes: admin/build/types/edit/[node-type]

I would support this in very strong preference to trying to handle a blacklist by any of the mechanisms suggested. Note, this might mean we'd need to increase MENU_MAX_PARTS to 8, but as far as I know we have not seen any performance issues from that query to make me think that we could not risk increasing by up to 2x the number of strings we are matching against.

quicksketch’s picture

Well after a full text search of the contrib repository, I found what I needed to see: several modules implementing paths that I wouldn't have expected. Here's a list of the paths at admin/build/types/x and the modules that define them:

fields (content.module)
export (content_copy.module)
import (content_copy.module)
conditional (conditional_fields.module)
template (contemplate.module)
cleanup (content_type_cleanup.module)
deploy (deploy.module)
nodeaccess (node_acccess.module)
nodeformtemplate (nodeformtemplate.module)
profile (content_profile.module)
hide-all-imagefields (imgthemer.module)

Which is more than I would have expected, and some at likely places for node type names such as "template" and "profile". Considering these modules would clearly run into problems, I'll abandon my attempt a pure blacklist approach.

So let's visit the idea of admin/build/types/edit/[node-type]. Views module (which also tried the blacklist approach in D5) uses the following paths:

admin/build/views/edit/[view-name]
admin/build/views/delete/[view-name]
admin/build/views/clone/[view-name]
admin/build/views/export/[view-name]

This makes a lot of sense because a path like admin/build/views/edit/[view-name]/delete seems like a contradiction in meaning, so it's best to move anything that's not "editing" (or displayed as a tab) to a new item.

In our situation with node types, we'd probably have a mix of paths such as this:

admin/build/types/delete/[type-name]
admin/build/types/export/[type-name]
admin/build/types/edit/[type-name] (as default tab)
admin/build/types/edit/[type-name]/fields (as a tab)
admin/build/types/edit/[type-name]/fivestar (as a tab)
admin/build/types/edit/[type-name]/template (as a tab)

This has the added benefit of placing the delete and export callbacks under a "real" menu path (not containing wildcards) so the breadcrumb continues to function. That won't make a difference ultimately if #483614: Better breadcrumbs for callbacks, dynamic paths, tabs is completed, but it's a little bonus.

quicksketch’s picture

Status: Needs work » Needs review
FileSize
37.39 KB

This patch now makes significantly fewer (and hopefully less controversial) changes.

- Renames "admin/build/node-type/*" to "admin/build/types/edit/*"
- Renames "admin/build/node-type/%/delete" to "admin/build/types/delete/%"

- Renames "admin/build/menu" to "admin/build/menus"
- Renames "admin/build/menu-customize/*" to "admin/build/menus/customize/*"

- Increases the MENU_MAX_PARTS from 7 to 8, since CCK will be pushing this limit with a path like admin/build/types/edit/%/fields/%/edit

pwolanin’s picture

So, I like this better than the prior approach, but it still kind of breaks the usual Drupal pattern for path construction and it seems the patterns are different for node type vs. menu links. You need somethign for node types liej 'customize' here for menus.
For example:

admin/build/type/manage/[type-name]/delete 
admin/build/type/manage/[type-name]/export
admin/build/type/manage/[type-name] (as default tab)
admin/build/type/manage/[type-name]/edit (default local task)
admin/build/type/manage/[type-name]/fields (as a tab)
admin/build/type/manage/[type-name]/fivestar (as a tab)
admin/build/type/manage/[type-name]/template (as a tab)

Why did you make the change menu -> menus?

The common pattern is to use the singular 'node', 'user', 'comment'

quicksketch’s picture

The common pattern is to use the singular 'node', 'user', 'comment'

We're currently not consistent at all. Consider the following plural URLs: "types", "modules", "reports", "settings", "actions", "formats", "updates". This is part of an effort to increase consistency in our URLs (at least within the admin section). And it's hard to even express how annoying "admin/build/block" (singular) is compared to our plural "admin/build/types".

admin/build/type/manage/[type-name]/delete

I'd be okay with this change, except I'd prefer not to make "admin/build/type" singular. Is "manage" what we want for node types or was that just a possible suggestion?

drewish’s picture

subscribing.

quicksketch’s picture

The menu path increase has been split off into #514172: Increase Max Router Parts.

Status: Needs review » Needs work

The last submitted patch failed testing.

mlncn’s picture

Issue tags: +D7DX

Subscribing and bumping, let's do this for D7! Will review if rerolled.

becw’s picture

Issue tags: -D7DX

I heartily endorse this effort.

  • Fixing node type settings page paths to be below the node type listing page (admin/structure/types) can address breadcrumb issues as well (ie, on a node type settings page, there is no breadcrumb to go back to the listing of all node types)--partially dependent on 483614
  • Inconsistent pluralization of menu paths make it harder to navigate via URL, which is a serious usability issue for developers and administrators (regardless of the many users who "don't see" the URL bar)
becw’s picture

Issue tags: +D7DX

oops, knocked that D7DX tag off by accident.

sun’s picture

Status: Needs work » Needs review
FileSize
24.06 KB

New patch from scratch using '/manage' as the new, common pattern for both instances.

Renaming 'types' to 'type' is a different issue.

Likewise, using proper dynamic menu arguments for content types is also a different issue. The current node_menu() implementation registers all sub-items for every content type as separate menu router items/links - a total waste of resources.

joshmiller’s picture

Did a quick code review... pretty straightforward changes that, IMO, actually bring a little more sanity to the drupal URLs. One minor nitpick and the rest is RTBC.

+++ modules/node/content_types.inc	8 Sep 2009 22:27:08 -0000
@@ -446,5 +446,4 @@ function node_type_delete_confirm_submit
-  return;

I'm not sure I understand why we are removing this "return;"?

+++ modules/node/node.module	8 Sep 2009 22:27:22 -0000
@@ -92,13 +92,13 @@ function node_help($path, $arg) {
     case 'admin/structure/types/add':
       return '<p>' . t('Each piece of content is of a specific content type. Each <em>content type</em> can have different fields, behaviors, and permissions assigned to it.') . '</p>';
 
-    case 'admin/structure/node-type/' . $arg[3] . '/fields':
+    case 'admin/structure/types/manage/' . $arg[3] . '/fields':

I like this consistency with "/structure/types/[action]"

I'm on crack. Are you, too?

sun’s picture

FileSize
23.22 KB

Thanks - that first hunk was caused by my initial pass, where I also renamed 'types' to 'type' for consistency, but then figured out it's total scope creep for this issue. And, btw, return; without anything is always the same as just skipping it -- the return value is NULL.

joshmiller’s picture

Status: Needs review » Reviewed & tested by the community

sun,

It applies to HEAD, the approach has been debated and I think you've found a sane way to handle it, and have removed at least one line from core that didn't need to be there.

RTBC.

Josh

sun’s picture

Issue tags: +API clean-up

Introducing a new tag for feature freeze: API clean-up.

pwolanin’s picture

Issue tags: -API clean-up

is there an API change?

sun’s picture

Issue tags: +API clean-up

I'd say so, yes. If a contributed module registering menu router paths below those items is ported to D7 now, it will break after this patch lands.

Anyway, I thought about "feature freeze", "API clean-up", and some other issue tag terms and went with "API clean-up", lacking a better idea.

We can certainly rename that term. Has been applied to many clean-up issues in the queue now to provide a solid overview of things we really need to fix before releasing.

webchick’s picture

Status: Reviewed & tested by the community » Needs review

I'd like to see quicksketch give this a final thumbs-up, since this was his baby.

wmostrey’s picture

He can't RTBC his own patch, can he? Either way, I also say it's good to go.

sun’s picture

Status: Needs review » Reviewed & tested by the community

The patch is based on the approach suggested by pwolanin in #6, which quicksketch already confirmed in #7.

quicksketch’s picture

The url "manage" is fine with me, it's probably better than "edit". While this makes for a longer path, it *does* fix breadcrumbs slightly, which will probably be the only thing we have time for in the D7 release cycle. RTBC + 1.

Dries’s picture

Why was 'manage' chosen over 'edit'? It would seem to me that consistently using 'edit' is more predictable and hence easier to navigate the site using the address bar. Curious.

quicksketch’s picture

Why was 'manage' chosen over 'edit'?

With "edit" you ended up with URLs such as "admin/build/menu/edit/[menu-name]/delete" and "admin/build/menu/edit/[menu-name]/edit". Even though usually you'll only see "admin/build/menu/edit/[menu-name]", the word "manage" will be universally applicable in similar situations and won't create a URL that contains both the words "edit" and "delete". My original patch used "edit", but I agree with these reasons which caused sun to change it to "manage" later.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Thanks -- that makes sense. Committed to CVS HEAD.

Pasqualle’s picture

nice patch. for remaining path issues check the SQL query in #220407: Fix collisions in admin menu

sun’s picture

Heya!

Is it possible that we can also remove that menu name munging due to this clean-up now?

function menu_edit_menu_submit($form, &$form_state) {
  $menu = $form_state['values'];
  $path = 'admin/structure/menu/manage/';
  if ($form['#insert']) {
    // Add 'menu-' to the menu name to help avoid name-space conflicts.
    $menu['menu_name'] = 'menu-' . $menu['menu_name'];

Or what kind of name-space conflicts are meant here?

Status: Fixed » Closed (fixed)
Issue tags: -D7DX, -API clean-up

Automatically closed -- issue fixed for 2 weeks with no activity.