Drupal coder

url rewriting

Pathauto improvement: a better menu trail token for deep menus in Drupal

Pathauto is one of those modules that everyone blindly installs on each of his sites. It allows you to automatically create pretty urls for all your content based on some properties of that content. Pathauto uses the Token module to allow the user to define url patterns (using the admin interface) based on tokens.

On sites with a hierarchical menu a very popular pattern (token) used is the "menupath", which is basically results into a "url-ified" version of your breadcrumb. The menupath can become very long though in case you have a deep menu structure or have a few menu items that have very long titles. Since Pathauto cuts of the long paths after a certain length (configurable via "Maximum alias length"), a lot of urls (for items deep in the menu tree) might become very similar.

One of the most important reasons for having pretty urls is search engine optimisation (SEO). But in long urls the most relevant keywords for your page are at the end of your url.

A good compromise in this case is to use only the first two (or three) menu items at the beginning of your trail and the title of the page itself. Let's see how we can build a token that we can use for our Pathauto patterns that does this. We'll call it "short menupath".

April 12, 2010Drupal, pathauto, token, url rewriting

How to create URL aliases in Drupal without path module

Creating pretty urls or permanent links in Drupal is easy. Really easy. This functionality comes out of the box with the Path module. And by adding the contributed Pathauto module you can make your life easier by letting Drupal generate the pretty urls automatically based on some properties of your post (like the title).

But there's another way of doing this in Drupal. Drupal provides a mechanism in code by means of the custom_url_rewrite_inbound and custom_url_rewrite_outbound functions. Using these wisely may give you some performance gain. Let's see how you can use these.

February 02, 2010Drupal, performance, url rewriting

Lose the www part in your url

Some people really don't like the www part in urls. They prefer http://example.com over http://www.example.com. They want www.exampe.com redirected to example.com.

How can we manage this in Drupal? Well, we're going to rewrite urls, so it has to be via a Drupal path or via .htaccess.
We can't use a Drupal path in this case though because Drupal paths come in to play to late in the request flow.
So we have to use .htaccess. Drupal is delivered with a .htaccess file in the root which takes care of all the url writing mumbo jumbo, some url blocking for security etc. We'll have to edit this file.

Oops! We're hacking core. Which is always bad. A better place to add this solution is in you httpd.conf file (apache) or something. But let's assume that for these few lines, you want to adjust core.

Open your root .htaccess file and look for the following lines...

# Various rewrite rules.
<IfModule mod_rewrite.c>
  RewriteEngine on

Change this to the following...

# Various rewrite rules.
<IfModule mod_rewrite.c>
  RewriteEngine on
  
  RewriteBase /
  RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
  RewriteRule ^(.*) http://example.com/$1 [L,R=301]

Note that we're using the 301 http code. This says that we're doing a Permanent Redirect. Don't forget to do this!

April 10, 2008Drupal, url rewriting

Drupal module for using the same clean url for multiple languages

I am using the Drupal i18n module for content translation. Although it sometimes isn't as straight forward in usability as it should be, mostly there's a workaround for a specific problem.

I couldn't find one myself for a certain problem I was having with Drupal clean urls. So I decided to write a simple module for it myself.

On a typical site, you have pages like '/contact', '/help', '/faq', ... that you all want to share the same path for each language (like '/fr/contact', 'en/contact', 'nl/contact', ...). You also want to have a single access point like '/contact' that points to the right translation of that page depending on the current user language.

By default, this is not possible using the i18n module. At least, there's no great solution that I know off.

My workaround is the following. For each language I add the language prefix to the clean url. So when creating my page (or whatever other node type instance), I specify 'fr/contact' and 'en/contact' instead of '/contact'.
This works great for all language specific clean urls; 'fr/contact' points to the french version etc.

But I also want the language independent url, '/contact', to point to the translation of the page in the current language. For this, I had to write a simple module, from which the code is listed below.
This content checks all your clean urls and looks for urls that are prefixed with a language. Those urls get a menu item in the menu hook. This menu item triggers a callback which redirects the user to the page with the right translation. Problem solved!

The disadvantage of this solution is that the user isn't taken straight forward to the requested page, but is rather redirected to it. So the url changes ('/contact' becomes for example '/fr/contact'). Not a big problem for me though ;)

/**
 * Implementation of hook_menu().
 */
function multilingual_path_menu($may_cache) {
  $items = array();
  
  if (!$may_cache) {
  
    $sql = "SELECT DISTINCT SUBSTR(dst,4) as dst FROM {url_alias} WHERE ";
    $languages = i18n_supported_languages();
    foreach($languages as $key => $name) {
      $subsql[] = "dst LIKE '".$key."/%'";
    }
    $sql = $sql . implode(' OR ', $subsql);
    $result = db_query($sql);
    
    while($path = db_fetch_object($result)) {
      if(!drupal_lookup_path('source',$path->dst)) {
        $items[] = array(
          'path' => $path->dst,
          'title' => '',
          'callback' => 'multilingual_path_get_path',
          'access' => TRUE,
          'type' => MENU_CALLBACK
        );
      }
    }
  }

  return $items;
}

function multilingual_path_get_path() {
  drupal_goto($_GET['q']);
}

Drupal custom URL rewriting - Change the admin url to enhance security

The following tip can be used in multiple scenarios (being anywhere you need custom URL rewriting and want to do this without .htaccess), but I'll illustrate it for two specific purposes.

  1. At our company all urls beginning with /admin are blocked from outside by a firewall for content security reasons. This sucks, because Drupal administration is done on pages with a /admin url. So we need to find a way to rewrite all of the urls to something like /config (or something else).
  2. If someone knows your site is on Drupal, this gives him some knowledge on how the site is structured. For example does he know that all administration is done on /admin. To make it harder to guess this url, we want to rename it.

Both of these cases can be tackled by one hook (custom_url_rewrite) in Drupal that has to be specified in the settings.php file. You can find a descent explanation of how this hook works in the Drupal API.

In the following example I rewrite all admin urls to config (and vice versa).

function custom_url_rewrite($op, $result, $path) {

  if ($op == 'alias') {
    if (preg_match('|^admin(/{0,1}.*)|', $path, $matches)) {
      return 'config'. $matches[1];
    }
  }
  
  if ($op == 'source') {
    if (preg_match('|^config(/{0,1}.*)|', $path, $matches)) {
      return 'admin'. $matches[1];
    }
  }
  
  return $result;
  
}
March 10, 2008Drupal, security, url rewriting