19

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?

0

18 Answers 18

24

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'));
  }
}
5
  • 4
    As described by @kiamlaluno, one can also use $form_state->setRedirect('mymodule.dashboard); Jan 6, 2017 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, 2017 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, 2017 at 21:41
  • 1
    I don't understand what's happening in the else here? Maintaining an existing redirect?
    – user1359
    Oct 12, 2018 at 15:14
  • 2
    you have to use use Drupal\Core\Url; to make it working correctly Oct 24, 2018 at 9:13
18

Redirecting users after they log in 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 log in, 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.

16

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().

7
  • 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, 2017 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, 2017 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, 2017 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, 2017 at 22:16
  • 4
    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, 2018 at 13:51
13

there are couple of solutions to do this: if you want to do it in your custom module:

Solution 1: use a custom form submit hander

/**
 * Implements hook_form_alter().
 */
function YOUR_MODULE_NAME_form_alter(&$form, \Drupal\Core\Form\FormStateInterface\FormStateInterface $form_state, $form_id) {
   if ($form_id == 'user_login_form') {
      $form['#submit'][] = 'myredirect_submit_handler';
   }
}

/**
 * Custom submit handler for login form.
 */
function myredirect_submit_handler($form, FormStateInterface $form_state) {
    $url = Url::fromRoute('YOUR_ROUTE_MACHINE_NAME');
    $form_state->setRedirectUrl($url);
}

Solution 2: ( which I noticed it's not working on drupal > 8.3)

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;
}

Solution 3:

you can use Rules module, create "redirection action" after "user logged in" triggered

Solution 4:

Use one of the following contirb modules

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

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

4
  • A good elegant solution, worked for me in Drupal 8.1. May 2, 2016 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, 2016 at 14:19
  • 2
    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, 2018 at 1:29
  • login_destination is solid, quite customizable and works like a charm wth Drupal 9.5 Nov 11, 2023 at 19:00
8

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.
2
  • 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 Aug 30, 2018 at 18:08
  • 1
    Rules messes up the login system when the site has redirect to a page after user logs in. Beware Mar 1, 2019 at 10:52
8

In D8 and later, 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.

4
  • 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, 2017 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, 2018 at 13:52
  • @hansfn, this issue is fixed. Nov 10, 2021 at 11:09
  • Then I'll remove my downvote (if I'm allowed to).
    – hansfn
    Nov 10, 2021 at 11:32
7

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.

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.

3

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();
  }
}
2
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

2

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

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
  • 2
    Good answer for D7, but this question is tagged D8, and there's no Drupal 8 version of Logintoboggan yet. Jan 17, 2019 at 14:43
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;
}
0

​I was working on a way to get around the other things that depend on hook_user_login because many other options are breaking in the newer versions of 8. Some other re-direct modules do a lot of leg-work that is either no longer relevant and/or just out-right hogging resources. I put together this simple logic into a custom module for handling the login processes:

function hook_user_login( UserInterface $account ) {
  // Doing checks to see if the login is from an HTML origin or not.
  // Could be from RESTful request to logins
  $request = \Drupal::request();
  if ($request->getRequestFormat() !== 'html') {
    // default
    return;
  }

  // Get the destination to see where the login request is going.
  // This is useful to check for interactions from user creations.
  $destination = $request->query->get('destination');

  // Check the destination. If the destination will result in a re-direct 
  // to your homepage (here statically defined, but could be programmatic)
  // then you can force re-direct to a different page. This is the URL defined
  // in config > system > basic site settings.
  if ($destination && $destination === '/whatever-homepage-uri-is') {
    // Regular login, send to alternate welcome page
    $response = new RedirectResponse('/welcome');
    $response->send();
    exit;
  }

  // default
  return;
}

I have been using this successfully with Drupal 8.8.3 and it does not break my REST login requests from another module I built, re-directs correctly for new account creations, and then re-directs to a different page on a regular site login.

0

Or you simply use a one in all module Url Redirect https://www.drupal.org/project/url_redirect for both the D.7 and D8 distributions

0

User redirect is another option in Drupal(8/9) to redirect the user after login or logout.

This module covers wider approach where multiple roles are assigned to different users.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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