Trick Drupal 6 to Allow Links to Relative, Non-Drupal Paths

// September 28th, 2010 // Programming, Web Development //

For some reason, when using “clean urls” Drupal 6 seems to think you can only have two kinds of links: Internal to Drupal or external links. This means that if you have something not part of Drupal installed on the same site, you would have to use the full URL to link to it.

For example, say you have a Drupal website called www.somedrupal6site.com and a non-Drupal page called just_some_page.php that you would like to be in the main navigation. So you try adding it to through the Drupal menu manager and you end up with this fun little error:
The path is either invalid or you do not have access to it.

So how do you fix it? Well if you’re okay with putting in full URLs, then you can put: http://www.somedrupal6site.com/just_some_page.php as the path. Drupal will recognize that as an external URL and it’s good to go.

Unfortunately this isn’t always a viable solution. The site I was working on when this problem arose used multiple domains and CCK to differentiate content for each domain. They were technically separate sites with a lot of common data, which is why they used the same Drupal installation. At this point, I couldn’t just put the absolute URL, because there were 4 different absolute URLs instead of 1.

ToastJam’s Solution

In my searching for an answer on Google and in the Drupal forums, I came across a solution by someone called “ToastJam”. The idea was to create a dummy node with an URL alias matching the file. Drupal therefore thought the path existed, but due to the settings specified in .htaccess, the specific file got priority over Drupal and thus this node was never loaded. For most, this solution probably works, but I decided against it due to a few slight issues that I could foresee it causing:

  • If the node was “published” it could potentially show up in local search results, rss feeds, sitemaps or any of the several modules that were also involved with the site. I really didn’t want to have to go through every single module to make sure there wasn’t any undesired behavior.
  • Regardless of whether or not the content node is “published”, it’s still a node that shows up under the content management system. Since the site I was working on was for a client’s use and not mine, I didn’t want to risk them getting confused and me having to try to explain why the node exists, but is never used.

My Solution

The logic for my solution is that a site’s main navigation seldom changes. A client is less likely to go messing around the menu system than they are with content nodes, so I figured that if I could just set the URL once and leave it alone, things would probably be okay.

Initially I started looking for a hook function that would allow me to override the existing functionality, but short of doing a copy, paste and manipulation of the existing menu module, it wasn’t going to work this way.

Realizing that Drupal permits external URLs, I decided I wanted to trick Drupal into thinking a relative path was an external URL long enough to set the alias. I don’t like to get into the habit of manipulating Drupal’s core code, but figuring it was just a temporary thing, I proceeded.

In the includes/menu.inc file I found the following function:

  1. /**
  2.  * Returns TRUE if a path is external (e.g. http://example.com).
  3.  */
  4. function menu_path_is_external($path) {
  5.   $colonpos = strpos($path, ‘:’);
  6.   return $colonpos !== FALSE && !preg_match(‘![/?#]!’, substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path);
  7. }

Since I wanted to trick Drupal into thinking the path I was going to be providing was an external link, I commented out the existing code and modified it to always return TRUE.

  1. /**
  2.  * Returns TRUE if a path is external (e.g. http://example.com).
  3.  */
  4. function menu_path_is_external($path) {
  5.      return TRUE;
  6. //  $colonpos = strpos($path, ‘:’);
  7. //  return $colonpos !== FALSE && !preg_match(‘![/?#]!’, substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path);
  8. }

Then I went back into the Menu system and added my URL again, this time successfully. After adding the link, I reverted the function in includes/menu.inc back to what it was originally. If I ever have to modify this link at some point in the future, or create another internal link not part of Drupal, I can simply repeat the process as necessary.

For illustration purposes, you can see it in action at somedrupal6site.com.

Have comments, questions or a better solution? Let me know below.

David Stinemetze is the Lead Developer and Director of Social Media for San Antonio Web Design, SEO and Hosting firm, Internet Direct.
Website | Facebook | Twitter

/* Facebook */

to “Trick Drupal 6 to Allow Links to Relative, Non-Drupal Paths”

  1. Chris says:

    This was tremendously helpful. I was going down a number of other paths to try and solve this, but this is easy and straightforward. Thanks!

  2. Jason says:

    Will this work on setting a link to a file (ie a pdf file) using a relative path?

  3. Jediknight304 says:

    Does this work for Drupal 7?
    I tried “Edit Menu Link” and editing the “Path” field to say
    some_other_page
    /some_other_page
    ../some_other_page
    but it just puts those after the ?q=
    and gets “Page Not Found”

  4. Frederico says:

    Thanks! You saved me!!! Can a module or a function in template.php be written to do this?

    • Frederico says:

      Nevermind. I just read your comments about the hook function…

      • It’s no problem. You can technically write a new module for it. I just didn’t want to waste that much time on it. If you want to adapt it as a module, by all means go for it. I just didn’t want to worry about WordPress changing their menu system and then having a module that was out-of-date.

Leave a Reply