13

I would like to redirect users after they log in. Is it possible to use hook_user_login() to make the redirection? How do I add the parameter for the redirection?

17 Answers 17

18

You need to alter the login form and add a submit handler which will take care of the redirection. You cannot use $form_state->setRedirectUrl() directly in the form alter, since it will be overwritten by UserForm::submitForm().

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mymodule_form_user_login_form_alter(&$form, FormStateInterface $form_state) {
  $form['#submit'][] = 'mymodule_user_login_submit';
}

/**
 * Form submission handler for user_login_form().
 *
 * Redirects the user to the dashboard after logging in.
 */
function mymodule_user_login_submit(&$form, FormStateInterface $form_state) {
  $url = Url::fromRoute('mymodule.dashboard');

  // Check if a destination was set, probably on an exception controller.
  // @see \Drupal\user\Form\UserLoginForm::submitForm()
  $request = \Drupal::service('request_stack')->getCurrentRequest();
  if (!$request->request->has('destination')) {
    $form_state->setRedirectUrl($url);
  }
  else {
    $request->query->set('destination', $request->request->get('destination'));
  }
}
  • 4
    As described by @kiamlaluno, one can also use $form_state->setRedirect('mymodule.dashboard); – Filipe Miguel Fonseca Jan 6 '17 at 6:57
  • 3
    Please explain users who follow this answer what mymodule.dashboard should/would do. How to change that to <front>, just for an example. Since user dashboard is the default redirect after login, this example here is useless. The new user do not know which parts to alter and how for his redirect. – nilsun Oct 21 '17 at 10:53
  • 1
    To redirect to the front page, you can use the example above but change the line that generates the $url object to $url = Url::fromUri('internal:/'); – oknate Nov 9 '17 at 21:41
  • 1
    I don't understand what's happening in the else here? Maintaining an existing redirect? – user1359 Oct 12 '18 at 15:14
  • 1
    you have to use use Drupal\Core\Url; to make it working correctly – Jignesh Rawal Oct 24 '18 at 9:13
15

Redirecting users after they login on a Drupal 8 site is not different from how it was done on Drupal 7, except the code needs to be adapted for Drupal 8.

In particular:

  • hook_user_login() is not used to redirect users after they login, simply for the fact that redirecting users in that hook would stop other hook_user_login() implementations from being invoked.
  • The correct way to redirect users is adding a form submission handler to the login form that uses code similar to the following one.

    $form_state->setRedirect('user.page');
    

    Notice that user.page is the routing name for the Drupal path where you want the user to be redirected.
    If you have an instance of the Drupal\Core\Url class, you could also use the following code.

    $form_state->setRedirectUrl($url);
    

    Keep in mind that the first method is preferable when you are redirecting users to a page in the same site they logged in; the second method is normally used to redirect users using an external URL.

12

you can use hook_user_login and try to redirect to yourpath

function yourmodule_user_login($account) {
  // We want to redirect user on login.
  $response = new RedirectResponse("yourpath");
  $response->send();
  return;
}

Also you can use Rules module, but there is NOT stable version for Drupal 8 yet.

  • A good elegant solution, worked for me in Drupal 8.1. – Alexei Rayu May 2 '16 at 9:55
  • 3
    I was getting ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION errors in certain circumstances with the above - I suggest replacing return; with exit;, to ensure the redirect - which sets headers - is the last thing to be executed. – user34185 Jul 14 '16 at 14:19
  • 1
    hook_user_login() is called before the submit handlers so this would prevent them from being called. Yogesh's answer below is a better way of doing this. – imclean Oct 1 '18 at 1:29
9

Bit late to the party but as per https://www.drupal.org/node/2068293#comment-11712455 you can set the destination in hook_user_login() to redirect at the end of the login processing.

i.e.

/**
 * Implements hook_user_login().
 */
function mymodule_user_login(\Drupal\user\UserInterface $account) {
  // Ignore password reset.
  $route_name = \Drupal::routeMatch()->getRouteName();
  if ($route_name !== 'user.reset.login') {
    // Do not interfere if a destination was already set.
    $current_request = \Drupal::service('request_stack')->getCurrentRequest();
    if (!$current_request->query->get('destination')) {
      // Default login destination to the dashboard.
      $current_request->query->set(
        'destination',
        \Drupal\Core\Url::fromRoute('mymodule.dashboard')->toString()
      );
    }
  }
}

Using FormState::setRedirect() as per the other answers will probably cover most people's use cases and is potentially the 'right' answer, however using the destination query param with hook_user_login means that any form submit* that logs in the user will redirect but without interference or prior knowledge of any other part of the form/request.

i.e. it will still work with a custom login form and using destination does not stop any other hooks (it is implemented by \Drupal\Core\EventSubscriber\RedirectResponseSubscriber at the end of response processing).

*Any form submit that invokes hook_user_login (user_login_finalize()) and does not manually call FormState::setResponse().

  • 1
    This has the advantage of working if authentication happens from something other than a login form. But does this interfere with other hook_user_login implementations from other modules? – Jonathan Jul 29 '17 at 18:34
  • 1
    @Jonathan No, it only sets the destination and doesn't do an early request->send() or anything (i.e. like d7 drupal_goto), it will allow all other hooks, form callbacks etc to run like normal before it is acted upon. This is just how the standard drupal login redirect does it. – Sut3kh Jul 30 '17 at 21:39
  • 1
    Please explain users who follow this answer what mymodule.dashboard should/would do. How to change that to <front>, just for an example. Since user dashboard is the default redirect after login, this example here is useless. The new user do not know which parts to alter and how for his redirect. – nilsun Oct 21 '17 at 10:54
  • 3
    @nilsun mymodule.dashboard is the route name and can be replaced with any route name (i.e. \Drupal\Core\Url::fromRoute('<front>')->toString() or \Drupal\Core\Url::fromRoute('entity.node.canonical', ['node' => 123])->toString()). For more information see drupal.org/docs/8/api/routing-system/routing-system-overview and api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Url.php/… – Sut3kh Dec 21 '17 at 22:16
  • 2
    This breaks password reset so I'm down-voting the answer. (Creating a form submission handler for user_login_form as suggested in another answer works.) – hansfn Nov 5 '18 at 13:51
7

You can simply do it by using Rules

React on: After user has logged in

  • Add action: Redirect >> then use a parameter or type your url.
  • 3
    The main caveat on this is that Rules is still in pre-release ALPHA for Drupal 8 so take care if you need stability on your website – Philippe Gilbert Aug 30 '18 at 18:08
  • 1
    Rules messes up the login system when the site has redirect to a page after user logs in. Beware – InspiredCoder Mar 1 at 10:52
6

You can also alter the user login form and add your own custom submit handler to set $form_state redirect, instead of directly redirecting user to your custom URL using hook_user_login.

<?php
/**
 * Implements hook_form_alter().
 */
function [MODULENAME]_form_alter(&$form, \Drupal\Core\Form\FormStateInterface\FormStateInterface $form_state, $form_id) {
  switch ($form_id) {
    // Alter login form and add own custom submit handler.
    case 'user_login_form':
      $form['#submit'][] = '_[MODULENAME]_user_login_form_submit';
      break;
  }
}

/**
 * Custom submit handler for login form.
 */
function _[MODULENAME]_user_login_form_submit($form, FormStateInterface $form_state) {
  // Set redirect to login form.
  $form_state->setRedirect('YOUR.MENU-ROUTER.NAME');
}

Adding it in $form_state redirect will make sure that the other submit handlers/login hooks get called.

Like Drupal7 we can't set $form_state['redirect'] directly, because $form_state is now class object. Checkout FormState::setRedirect() for further details.

6

In D8, you can use user default page module for this purpose.

This module allows you to customize the destination that a user is redirected to after logging in or logged out. You can customize by roles or individual users.

  • 1
    Works but it doesn't take in consideration password reset links, when the user uses the one time link to set their password it redirects them to the page you set in this module and not the user account. – Sorin Aug 24 '17 at 14:58
  • 1
    This module still breaks password reset so I'm down-voting the answer. See drupal.org/project/user_default_page/issues/2991916 (Creating a form submission handler for user_login_form as suggested in another answer works.) – hansfn Nov 5 '18 at 13:52
4

There is a simple module to do this which is compatible with Drupal 8. It is called User Default Page.

The module allows you to customize the destination that a user is redirected to after logging in or logged out. You can customize by roles or individual users. And customize configurable drupal messages for this actions.

3

hook_user_login() doesn't work for redirection, it's used if you want to do something with the user when he logs in. Fx core suggests users to set the local timezone if it's not set.

Instead you need to use hook_form_alter on all of the login forms and add a custom submit handler which sets the redirect on the form state object.

2

I am displaying the login form in my own controller. That way it's possible to manipulate the form (and so redirect the user after login) without the non-OO hooks:

$fb = $this->formBuilder();
$rc['top'] = ['#markup' => '<p>Willkommen im Kundenbereich von proreos. 
    Bitte melden Sie sich hier mit Ihrem
    Benutzernamen oder Ihrer Email Addresse an.</p>'];
$form = $fb->getForm("Drupal\user\Form\UserLoginForm");

$ug = $this->getUrlGenerator();
$redir = $ug->generateFromRoute('proreos.home', [], 
         ['query' => $this->getDestinationArray(), 'external' => FALSE]);
$form['#action'] = $redir;

$rc['login'] = $form;

return $rc;

Change the 'proreos.home' route to whatever destination you need.

Regards

Rainer

2

Simply add destination parameter to login url.
Example: http://example.com/user/login?destination=/my-page

If you doing it for 403 ( Access Denied ) pages use following module:
https://www.drupal.org/project/redirect_403_to_login_page

1

Use any of these modules:

https://www.drupal.org/project/login_redirect

OR

https://www.drupal.org/project/login_destination

Cheers

  • 4
    D8 version is not available. Question tag for D8 not for D7. – DRUPWAY Aug 19 '16 at 6:58
1

You can use logintoboggan module for redirection. It has other configuratrions which may be useful if you want other functionlaities like login using usernames.

  • 1
    Good answer for D7, but this question is tagged D8, and there's no Drupal 8 version of Logintoboggan yet. – Kelley Curry Jan 17 at 14:43
1

https://www.drupal.org/project/redirect

  1. Install the above module
  2. Add custom url path as the destination parameter in the url
  3. So, configure the above module to redirect from

    /user/login to /user/login?destination='CUSTOM_NODE_PATH'

    • Wanted to use r4032login module to allow authenticated users access the concerned page, when they copy/paste the url or use an hyperlink from word/excel for example.
    • Other 'login redirect' modules would override this functionality and would only allow users to land on a configured single page even when the destination parameters are included in the url
1

Another option specifically for this issue is a simple Drupal 8 contributed module: Redirect After Login. The module can be found here:

https://www.drupal.org/project/redirect_after_login

As the description shows, it is a simple, focused module that is covered by the Drupal security advisory policy.

1

/**
 * hook_user_login Redirect to English language whenever admin login
 **/
function modulename_user_login($account) {
  // We want to redirect user on login.
  $response = new Symfony\Component\HttpFoundation\RedirectResponse("/en/admin/config");
  $response->send();
  return;
}
1

I use the following snippet quite a lot so I thought I'd share it. You can add different redirects depending on which role the user has.

use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * Redirect on login.
 */
function MYMODULE_user_login($account) {
  $roles = $account->getRoles();
  if(in_array('webmaster', $roles)) {
    $response = new RedirectResponse('/admin/content');
    $response->send();
  }
}

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.