Some drupal pain about "q=user"

In drupal, when you go to http://www.yoursite.com/?q=user you get redirected right away to http://www.yoursite.com/?q=user/777 (if 777 is your user id and if you are logged in). If you are not logged in, you see the login page.

My client wanted users to be redirected to http://www.yoursite.com/?q=user/me instead. How simple, right? WRONG!

Sometimes, (or often in Drupal) the simpliest thing end up being a nightmare.

I wrote a drupal module to handle this:

function foo_menu($may_cache) {
  if ($may_cache) {
    $items[] = array(
      'path' => 'user',
      'callback' => 'drupal_goto',
      'callback arguments' => array('user/me'),
    );
  }
  return $items;
}

I cleared my cache (thanks to the devel module) and I tried going to 'user'. Nope! I ended up on user/777 again.

I ended up figuring out why I was pulling my hear out doing this rather simple change. The problem was caused by the user.module which was doing something I did not expect.

As you know, the hook_menu($may_cache) is called twice. Once when you clear the cache and once for every request. When you clear the cache this hook is being called with TRUE as the $maycache parameters. You usually put menu items that can be cached (does not change dynamically). Most menu items can be cached. Some menu item like user/123/edit must load the node at run time before allowing you to see the content. But things like 'user' can be cached... so I thoughts.

The user module actually handle this two fold.

First:

  if ($may_cache) {
    $items[] = array('path' => 'user', 'title' => t('User account'),
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_login'),
      'access' => !$user->uid, 'type' => MENU_CALLBACK);
  }
  else {
     // ...
  }

This is cached ($may_cached is TRUE) and is only accessible to logged out users and will present you the login form.

then you've got this which is causing my head to spin:

  if ($may_cache) {
     // ...
  else {
    if ($_GET['q'] == 'user' && $user->uid) {
      drupal_goto('user/'. $user->uid);
    }
  }

The "else" code is executed at every request, before the final decision is made. And this is calling drupal_goto right there right then which simply exit and stop all other menu hooks from ever being called. This is cheating!!! :)

The only way to fix that without hacking the core is to create a module with a ligther weight (change the weight column in the system table for that module) and implement a hook_menu that will run the same code as above but redirect elsewhere.

function foo_menu($may_cache) {
  if (!$may_cache) {
    if ($_GET['q'] == 'user' && $GLOBALS['user']->uid) {
      drupal_goto('user/me');
    }
  }
  return $items;
}

This will only work if your custom module is executed BEFORE the user module.
More details on "How to update a module's weight": http://drupal.org/node/110238

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote>
  • You may post PHP code. You should include <?php ?> tags.
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]". PHP source code can also be enclosed in <?php ... ?> or <% ... %>.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options