I did my my own login form with custom functionality that is on /login url. Now I would like to restrict acces to default /user url in order to prevent logging in the old way.

I have a lot of different functionality in this form, so I though it is better to built it all from scratch instead of altering something. And I don't like the word in the /user, since in our language it sounds similar to some word that is not appropriate here.

I've tried to add /user item to hook_menu and define the same callback as /login item has.

I was hoping it could redirect users to new login form, but it had no effect.

What is the right way of doing this?


Since user is already defined as menu item from a module, you cannot use hook_menu() to alter it, but you need to use hook_menu_alter(). Since user is used for the currently logged-in user, it probably a bad idea to redirect them to login.

As said from Mołot in his comment, the correct way of altering the login process is altering the login form, and add new validation handlers. This is similarly to what the OpenID module in Drupal core does.

function openid_form_user_login_alter(&$form, &$form_state) {
  _openid_user_login_form_alter($form, $form_state);

function openid_form_user_login_block_alter(&$form, &$form_state) {
  _openid_user_login_form_alter($form, $form_state);

function _openid_user_login_form_alter(&$form, &$form_state) {
  $form ['#attached']['css'][] = drupal_get_path('module', 'openid') . '/openid.css';
  $form ['#attached']['js'][] = drupal_get_path('module', 'openid') . '/openid.js';
  $form ['#attached']['library'][] = array('system', 'jquery.cookie');
  if (!empty($form_state ['input']['openid_identifier'])) {
    $form ['name']['#required'] = FALSE;
    $form ['pass']['#required'] = FALSE;
    unset($form ['#submit']);
    $form ['#validate'] = array('openid_login_validate');

  $items = array();
  $items [] = array(
    'data' => l(t('Log in using OpenID'), '#openid-login', array('external' => TRUE)),
    'class' => array('openid-link'),
  $items [] = array(
    'data' => l(t('Cancel OpenID login'), '#', array('external' => TRUE)),
    'class' => array('user-link'),

  $form ['openid_links'] = array(
    '#theme' => 'item_list',
    '#items' => $items,
    '#attributes' => array('class' => array('openid-links')),
    '#weight' => 1,

  $form ['links']['#weight'] = 2;

  $form ['openid_identifier'] = array(
    '#type' => 'textfield',
    '#title' => t('Log in using OpenID'),
    '#size' => $form ['name']['#size'],
    '#maxlength' => 255,
    '#weight' => -1,
    '#description' => l(t('What is OpenID?'), 'http://openid.net/', array('external' => TRUE)),
  $form ['openid.return_to'] = array('#type' => 'hidden', '#value' => url('openid/authenticate', array('absolute' => TRUE, 'query' => user_login_destination())));
  • Beat me to it, use the hook_menu_alter instead of hook_menu. function hook_menu_alter(&$items) { Global $user; $items ['user']['access callback'] = ($user->uid != 0); } And yes, that should be a callback function so it does not get cached. Aug 28 '15 at 17:39
  • Thx, I will use hook_menu_alter. Btw. in "/login" page I'm redirecting to another page if user is logged in, so no need to worry about redirecting from /user to /login even if user is logged in :)
    – Incredible
    Aug 29 '15 at 0:36

You could use the Rules module for this. Here is the rule you'd need for it (in Rules export format, just use copy/paste to import it in your own setup):

{ "rules_redirect_user_path_to_login_path" : {
    "LABEL" : "Redirect user path to login path",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "ON" : { "init" : [] },
    "IF" : [
      { "text_matches" : {
          "text" : [ "site:current-page:path" ],
          "match" : "user",
          "operation" : "starts"
    "DO" : [
      { "drupal_message" : { "message" : "Sorry, this path (= /user) is no longer in use, you will be redirected automatically to its corresponding path (= /login)" } },
      { "redirect" : { "url" : "login" } }

Whenever such redirect actually happens, the user will also receive an informational message like so:

Sorry, this path (= /user) is no longer in use, you will be redirected automatically to its corresponding path (= /login)

If you don't want such message to appear, then just delete the line containing drupal_message in the exported rule above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.