Retain #anchors during path alias -> normal path saving
| Project: | Drupal |
| Version: | 7.x-dev |
| Component: | menu system |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | active |
It is often desirable to create a menu item that links to a particular place on a page, e.g. /node/xx#name
In the menu system the # character is translated into %2523 and the link fails.
There is a hack, documented at http://drupal.org/node/106821, whereby you can specify a complete url to avoid this translation. This is an inelegant workaround and not a solution as it leads to management problems when the base url is not constant throughout the life of a site (e.g. when migrating between test/live sites or when it runs concurrently on two domains: xx.com, xx.co.uk).
I can't see any reason why the # character cannot be escaped. It doesn't pose any security threat and only users with admin privileges can define menu paths.

#1
Named anchors are a standard part of the URL scheme. So not properly handling them in the menu system is a bug, IMO.
The attached patch allows admins to add custom menu items with relative URLs and anchor fragments.
(Also, I’ve updated the above handbook page to show a better workaround then having to enter full URLs.)
#2
Tweaks like this will not work afaik, since normal menu paths can contain the # character.
If we want to change the menu system to support fragments and/or query strings, this needs to be added properly, without introducing forbidden characters in the menu paths.
This could mean that you enter menu paths in urlencoded form (i.e; what this patch tries to do) in the UI, but that would need to be integrated cleanly with the current unencoded, module-generated paths.
#3
The path_redirect module adds an extra field in for named anchors
_____________ # _____________
or similar. That makes the distinction pretty clear, not sure how it stores it though.
#4
From section 3.3 of RFC 3986 (Uniform Resource Identifier (URI): Generic Syntax):
So the # and ? characters, according to the RFC, are already forbidden in the path. Right now, Drupal encodes all characters in the path (including the #), but I can’t think of any real-world examples of using an encoded # in the path of a URL.
Steven, the above patch doesn’t change the way Drupal handles url encoding. You would still enter URLs in unencoded form. It just splits the path at the first # and puts the parts back in $item->path and $item->fragment.
#5
I'm not talking about URL path components, but about Drupal menu paths. They are not the same.
#6
As for a real world example... any search that includes a # in the keyword box.
#7
Any progress on this lately?? Was there a group consensus reached on a course of action??
#8
I've needed this for a very long time and am amazed it's still not possible. This is a pretty basic thing to want to do in a web site. The example I need it for right now is a political candidate's bio page with targets to each section (why I'm running, voice of the voters, etc.). I'd like to not have to break the bio up into three pages simply because the menu won;t let me use targets.
#9
Anchors are necessary. We using them to separate paragraphs in a long article. As I create my own theme, I do not have any problems to insert a simple
str_replace, but the time I used for the search.I cannot imagine, why an url cannot have an anchor in the menu system. It is like an article without a title.
#10
It's crazy not to support this.
I have lots of pages with a
<a name='top'></a>at the top and a<a href='#top'>Top</a>at the bottom.I can't do this in Drupal.
In v5.x, I hacked the url and menu_path_is_external functions so it worked, by just adding:
if(strpos($path, '#') === 0) return $path;as the first line in each of the functions, but in 6.x, the changes to the menu system break that simple hack.
#11
Can we revive this thread? There seems to be a consensus that enabling # and ? in the menu system does make sense (I just wanted to link to a Drupal page like "my/url?page=2", which is not allowed unless you specify the FQDN). Can some developer look at this, please?
Thanks,
Stephan
#12
I believe this is fixed in 6.x.
#13
Automatically closed -- issue fixed for two weeks with no activity.
#14
i have 6 and i am having the same prob. i dont think its fixed yet. anyone figure this out yet?
mike
#15
Yeah, this seems kind of strange. What about the fairly usual case where a menu item should point to something with a url redirect after in the form of: ?destination=
At the moment in Drupal 5 (haven't tested 6) it wont work. In many other modules and situations we can specify a destination in the url, why not in a menu item?
#16
I don't think this was fixed in 6.
Relative paths using named anchor links in menu items do not work. The menu system won't accept them as a valid path.
#17
@Ryan - if you really think this needs to be re-open, please more details of how you'd solve this. For example, we might think about a feature where a menu link could use <current> the same way it uses (at the moment) <front>
#18
I realize the menu navigation is attached at the hip with hook_menu and the page serving mechanisms of Drupal, and that the needs of this cannot be ignored when requesting an issue that seems to relate to only adding menu items to the tree, not defining paths in the first place. My question is, is it really practical for hash symbols to be used in paths, and should this character become a non-eligible character altogether for the purposes of Drupal?
Assuming we must have hashes in paths without them being links to anchors (ie, encoded), how about:
- another column in the menu_links table (fragment)
- another field for fragment in menu_edit_item form, or some means of denoting a fragment (eg. "node/123bottom")
This would let everything else (# symbols and the rest) be properly encoded, and fragments could be built into the links when the menus are build.
I may not have the insight to suggest such radical changes to Drupal core at this point, though.
#19
@Ryan - for Drupal 6, anchors should already work for "normal" links. I thought the only issue to be addressed here was named anchors for the current page.
#20
To my knowledge, with the exception of comment #17, this issue has been regarding menu items containing named anchors, WITH Drupal paths as well. Being able to leave the pre-anchor part of the path blank to have it always apply to the current page would be a bonus, IMHO.
Example: When adding a menu item with a path "buy#1", I get the following response:
The path 'buy' is either invalid or you do not have access to it.#21
um, then I would expect you get the same error message inserting a link with the path "buy", right?
I can add a link to the path "node/4#hello" and it works fine.
#22
Interesting.
For me, "buy" was an alias to node/40. Normally, when entering an alias to a menu item path, it replaces it with the node/# equivalent and notifies the user of the change, but in this case it says the "buy#1" path is not valid.
The menu item accepted a path of node/40#1 and the menu item ends up being buy#1 which is great.
Does anyone know, is this by design? And if so, should something be added to the description of the menu path field specifying this feature/limitation?
#23
hmm, accepting aliases at all was added late, so this may indeeed be a bug - please investigate and refocus the issue.
#24
I can confirm I have what looks like the same issue as Ryan, where the named anchor will work only if referencing it via node name, but not the alias.
#25
I agree with pwolanin (#19 and #23), the only issue left 6.x is anchor for path aliases.
And while fixing this I also think there are some thought to put in path menu items consiting only of an anchor (starting with #) which should "point" to the current path. I don't think a "link" (working like ) is useful, it is possible to just check if the path starts with # and if it does just use the specified path as the link (as it would do with an external link), then for browsers the link would be a relative link to an anchor on the current page.
#26
When you add a menu item for node/1#anchor - does the path get aliased when you view it in the menu?
#27
Yes it does get aliased and the anchor is working. Then, maybe it needs to be documented, although I know that this "translation" would certainly occur it didn't come to my mind to do it this way. Thanks for the solution.
Seeing that I am not the only one who thought that using directly the alias with an anchor, and not the nid, maybe it would not be such a bad idea to offer both solution for anchors.
Lastly, that leaves us with the feature request, the "relative anchor" I talked about before, maybe we should create a feature request for this ?
#28
OK, marking this back to active and bumping to 7.x. I can see two issues here here:
1. allowing a menu item with only a fragment, i.e. #anchor
2. When drupal_get_normal_path is called as part of the menu item validation, if the alias has an anchor appended, ignore this, then add it back to the normal path (so alias#anchor gets split to alias + #anchor which eventually gets saved as node/1#anchor).
I'm not sure how the first one should work - which use cases are there for having the same #anchor on every page a menu might show up on? #2 sounds like a decent usability improvement to me.
#29
About 1., an example would be "skip links" to improve accessibility. At the top of the page you offer links which point to named anchors like "#content" (if you have a named anchor or even an element with id called "content") and it will help people using a screenreader to skipping all the navigation links (for example). They will reach the content way more quickly. Of course this can be done directly in the page.tpl, but then you loose all the menu features. For example the ability to translate those. Well, it is possible to make this last part (transaltion) with the t() function and the interface translation system too.
If it is implemented, I doubt it would require much more efforts than it took to support external links... but with that kind of paths the "#" should not be encoded otherwise it will just not work of course.
Another problem we would run into is that the link_path field would be empty in the menu_links table since fragments (anchors) are stored in the options field, if I understood how it works, so after all the " <current>" placeholder wouldn't be such a bad idea. It could also be useful with querystring (which is stored in the same field, options) instead of anchor, the principle is the same for both (we would just need to respect the order, ?query=string#anchor (and not the opposite).
About 2., I would also see it as usability improvement more than a real "bug fix" (well, the feature is here, it just does not work as I expected, but it works), thus I changed the category. I think that your reasoning is right about how it should be done, it makes perfect sense since it basically how it works right now with not aliased paths (according to what I read this afternoon, so I might not have catched the whole picture but that's my understanding).
#30
I left it as a bug, because usability issues are bugs ;) It either needs more documentation there, or the behaviour should be changed.
#31
Hi Guys,
Just to echo a few points that people have already made, about why this is important.
In terms of accessibility, a "skip to content" link is extremely useful for blind users (using screen readers) as it gives them the ability to skip through all of your links and go straight to your main content. Here I would usually use
<a href="#maincontent">Skip to content</a>but when this is published in a drupal menu the '#' becomes encoded as '%23' (don't quote me on that exact encode!)
The sooner this is sorted, the sooner I can stop worrying about hard coding in this skip links into my page.tpl.php file! I'm sure many of you feel the same.
Just thought I'd add a comment anyway!
Garry
#32
This sounds like a new feature - we have a <front> special symbol now - maybe we need something like a <current> tag to make clear the intent?
#33
As far as I can see there's two issues:
1. If you save a normal path with a fragment, this is handled fine in the menu. When you enter a path alias, drupal_get_normal_path() doesn't validate it as an alias, so you can't save it. Since the end result would be the same, this seems like a UI inconsistency to me and it's clearly caused some confusion. (I haven't tested this, going on the reports above).
2. Being able to enter a fragment for the current path.
<current>sounds like a reasonable way to do that. Although I can't think of a situation where you'd want to add anything other than a #fragment for the current path, so maybe just validation of the string might work?These seem like different issues to me, so I've split current path handling to a new issue #325533: Allow <current>#fragment as a menu path
#34
About 2., the only other occasion I see would be adding a querystring (as I said previously)... the use of it would also be limited but might still be useful, it can be handy to pass a parameter to the current page (i.e. like offering a link to the same page with a parameter telling the user does not have Javascript... indeed very limited, not that many other examples come to my mind right now ;)), but as I said it should not take that much more time to implement since it is done exactly the same way for #fragment and querystring (stored in options field in the menu_links table). The
<current>would make it possible to handle both, as it is already done with<front>.#35
@catch - thanks for clarifying and splitting the 2 issues.
#36
For those who really want to append an anchor, etc, in D6 to the current page, I suggest you'll need to implement/use a trivial module that implements hook_translated_menu_link_alter(). If I get bored I'll write it in the mini module section of the handbook.
#37
I would like to create a menu item (using the admin interface) in a menu, say secondary-links, with the "Menu Link Title" as "Top" and the "Path" as "#top".
It would generate
<a href="#top">Top</a>as the menu item. In this way, every page can have a "Top" link that works as expected.
But this is not possible today.
This seems to be linked to this whole discussion.
I've tried to raise this seemingly simple issue before, but have not gotten anything resembling a reasonable solution.
So, I thought I'd try posting this issue in this thread for you consideration.
Thanks,
Mitch