function hook_user_login($account) {
        return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
        }
    }

this is not work.

Can anyone help me?

Comments

angelsprite’s picture

You could use header() provide by PHP. Howerver you can only do it in the top of your document cause if there was an output you will not be able to use header().

RealDream’s picture

hook_form_alter() not good for conditional redirection after login.

$_GET['destination']='your/path';
not work

$GLOBALS['destination'] = 'your/path'
not work

Drupal 7:

function mymodule_user_login(&$edit, $account){
$edit['redirect'] = 'node/123';
}

Drupal 8: there is no &$edit parameter

function mymodule_user_login($account){
}

How can conditional redirect after login, when no edit parameter in Drupal 8?

Jaypan’s picture

You could use header() provide by PHP. Howerver you can only do it in the top of your document cause if there was an output you will not be able to use header().

Not in Drupal. There are other mechanisms present (though D8 being new, we are obviously having troubles finding it). You should never use header() in Drupal.

Tobias Xy’s picture

I tried to get this working, but wasn't very successful...
I added a new submit handler to the user login form (no problem here) and there I added a redirection target:

$form_state['redirect'] = 'nice/path';

But it didn't work...

So I took a look on the code and the result was:
The functions were called like this: drupal_form_submit > drupal_process_form > drupal_redirect_form
drupal_redirect_form returned a RedirectResponse object to drupal_process_form
drupal_process_form returned it to drupal_form_submit and
drupal_form_submit ignored it!

Maybe it's a Bug! I'm going to investigate further...

Edit: I created a bug report: #2070339: drupal_form_submit ignores return value of drupal_process_form

Btw: The return value of hook_user_login is also ignored.

Peter Muusers’s picture

Has anyone found a way to redirect a user after login in D8?

I also thought that the RedirectReponse way would work just like RealDream..., but it seems like it's got no effect at all...

exlin’s picture

I had success using Symfonys RedirectResponse. For some reason $form_state['redirect] didn't work but kept redirecting to system information front page.

function hook_user_login($account) {
  // We want to redirect user on login.
  $response = new RedirectResponse("mypath");
  $response->send();
  return;
}
anumathew’s picture

Thank you exlin, its worked for me..:)

echoz’s picture

In Drupal 8.0.2 this returns a 500 server error.
PHP Fatal error: Class 'RedirectResponse' not found ...

Anyone have updated code that works? Sadly the Login Destination module doesn't seem to be ready.

Edit: Found solution at: http://drupal.stackexchange.com/questions/146185/how-to-create-a-redirec...

This worked for me:

function mod_user_login($account) {
  $url = "/";
  $response = new Symfony\Component\HttpFoundation\RedirectResponse($url);
  $response->send();
  return;
}
Peter Majmesku’s picture

The redirect takes 6-7 seconds on my system. That's too slow for a modern website. I've posted some more explanation in my issue at https://www.drupal.org/node/2655732#comment-10781558. Isn't there really a faster redirect method by "the Drupal way" than with this slow RedirectResponse() object?

benellefimostfa’s picture

I have developed a little module to redirect user after login or register ... with a configuration page .. https://www.drupal.org/sandbox/benellefimostfa/2676602
ps: he still on sandbox you can get it with "git clone --branch 8.x-1.x benellefimostfa@git.drupal.org:sandbox/benellefimostfa/2676602.git user_redirect"

aangel’s picture

I used the login redirect, sending the user to "<front>" and this module worked for me.

However, I then dug a little deeper and found that Login Redirect has already been ported to D8 but it's still just in an issue (i.e. no official release):
https://www.drupal.org/node/2254787

Haven't tried it but you may want to join forces.

yogeshchaugule8’s picture

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('custom.redirect_callback');
}
?>

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.

To redirect to Site Front Page, use '<front>' as argument inside \Drupal::url(), check Page Redirection on Drupal 8 for more details.

weboide’s picture

This method is probably the best solution so far. The potential problem of redirecting using the other method with `hook_user_login` is when the user is trying to reset their password, he will not be able to get to the password edit page. user_login_finalize() (which triggers hook_user_login's) is called in UserPasswordResetForm::submitForm().
The above will only apply on the actual user_login submit action.

colorfield’s picture

Nice solution @yogeshchaugule8.
Performances can also be improved by implementing hook_form_FORM_ID_alter() instead of the global hook_form_alter().
The code will look like this on modulename.module.

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_FORM_ID_alter().
 */
function [MODULENAME]_form_user_login_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Alter login form and add own custom submit handler.
  $form['#submit'][] = '_[MODULENAME]_user_login_form_submit';
}

/**
 * Custom submit handler for login form.
 */
function _[MODULENAME]_user_login_form_submit($form, FormStateInterface $form_state) {
  // Set redirect to login form.
  $form_state->setRedirect('custom.redirect_callback');
}
edwinbsmith’s picture

Tried using the above code, which seemed to work fine, except that I am always redirected to `/node` after being logged in.

I tried using a customer route, and then I tried to use the examples listed here: https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Form!FormBuilder....

It looks like the response is including some HTML in its content, which is maybe triggering a Twig_Error_Runtime exception, and so falling back to the default path? I think it's returning a 403 error as well.

Anybody know what would be causing this? Looking at the trace, it seems to be interacting with just default Drupal system modules.

GeraldNDA’s picture

You can go to /admin/config/system/site-information to edit it. Or you can edit the configuration entity directly to edit it i.e.
\Drupal::config('system.site')->get('page.front'). If you leave it blank it will take every user to the user/login or their own user page when going to ''

proxiss’s picture

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 like this:

    $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 Feike

pallavi_c’s picture

Hi, you can find the module here: https://www.drupal.org/project/user_default_page

akishankar’s picture

I am using a custom submit handler and conditionally set users active or blocked. I am using the redirection to user page for active users in the submit handlers, but not sure why the user is not getting the logged in access and the redirection lands user to the login page. Below is the code:

function module_custom_submit(&$form, FormStateInterface $form_state) {
 $redirect_url = Url::fromRoute('user.page');
  if(!empty($user_status) && $user_status == "active") {
    $account->activate();
    $form_state->setRedirectUrl($redirect_url);
  }
}

I expect that on successful registration, if I set the user to active, the user should be able to access the user page.
Any help would be highly appreciated.

yogeshchaugule8’s picture

@akishankar, You can check if immediate login is available (after registration) in your site (in admin => config => people => account settings (settings to check "Who can register accounts?", "Require e-mail verification when a visitor creates an account.")). If not, user session is not started and because of which users are getting redirected to login page as user profile page is accessible only to logged in users unless granted to anonymous users. In this case, you'll need to programmatically initiate user session before redirecting him to user profile page.

jptreen’s picture

Rules is in alpha right now for D8, so you may well want to use one of the solutions above as of the time I'm writing this, but in case anyone is still having this problem in the future, please note that you can use the Rules module to add this redirect. You won't have to write any code either, which is usually a plus. :)

jbguerraz’s picture

If you need to check something on $account prior the redirect (and you don't want to assume the login form is used => like if one use simplesaml or such external auth) you could use the hook_user_login and the request_stack service in such a way :

function hook_user_login($account)  {
  \Drupal::service('request_stack')->getCurrentRequest()->query->set('destination', \Drupal::url('the.route.to.redirect.to'));
}
bendev’s picture

pay attention not to break the password reset process with the hook_login ! ...

StuartL’s picture

I was using Drupal Rules to redirect after login which was working well until updating to Drupal 8.4.0. After updating the password reset process is getting redirected after clicking 'Log In', meaning it is broken. I am not able to get it to work using a custom module.

Any ideas here?

The code I have tried is:

function mymodule_user_login(\Drupal\user\UserInterface $account) {
  // Default login destination to the dashboard.
  $current_request = \Drupal::service('request_stack')->getCurrentRequest();
  $destination = $current_request->query->get('destination');
  echo '<script>alert('.$destination.');</script>';
  if (!$destination) {
    if (!preg_match('.*\/user\/[0-9]*\/[a-z,A-Z,0-9,?,=,\-,_]*',$destination)) {
      $current_request->query->set(
        'destination',
        '/member-dashboard'
      );
    }
  }
}
flyke’s picture

I confirm above method working.

If you want to redirect to the frontpage after logging in:

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_FORM_ID_alter().
 */
function MYMODULE_form_user_login_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    // Alter login form and add own custom submit handler.
    $form['#submit'][] = '_MYMODULE_user_login_form_submit';
}

/**
 * Custom submit handler for login form.
 */
function _MYMODULE_user_login_form_submit($form, FormStateInterface $form_state) {
    $form_state->setRedirect('<front>');
}
dongtian’s picture

it worked perfectly

coetzw03’s picture

This code worked perfectly for me.

imen ch’s picture

I have to redirect the home page to user/login when i do it on config/system/site-information (replace /node by /user/login)
when the user is login in it redirect to user/uid, i have to redirect to the front page after logging in. but it doest't woek with the config u have changed! what should i do it my case?

griffincox’s picture

Please forgive my ignorance, but where should I put this code?

GeraldNDA’s picture

module_name.module where module_name is the name of your custom module to add this functionality.

candelas’s picture

Hello @flyke for your code

It works with front, but if I try a different page (/node/xx or http://example.org/node/xx) I get this error. Can you give to me any tip on way, please? Thanks :)

The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">Symfony\Component\Routing\Exception\RouteNotFoundException</em>: Route 'http://example.org/node/68' does not exist. in <em class="placeholder">Drupal\Core\Routing\RouteProvider-&gt;getRouteByName()</em> (line <em class="placeholder">202</em> of <em class="placeholder">core/lib/Drupal/Core/Routing/RouteProvider.php</em>). 
<pre> class="backtrace">Drupal\Core\Routing\UrlGenerator-&gt;getRoute(&#039;http://example.org/node/68&#039;) (Line: 271)
Drupal\Core\Routing\UrlGenerator-&gt;generateFromRoute(&#039;http://example.org/node/68&#039;, Array, Array, 1) (Line: 105)
Drupal\Core\Render\MetadataBubblingUrlGenerator-&gt;generateFromRoute('http://example.org/node/68', Array, Array, ) (Line: 753)
Drupal\Core\Url-&gt;toString() (Line: 130)
Drupal\Core\Form\FormSubmitter-&gt;redirectForm(Object) (Line: 77)
Drupal\Core\Form\FormSubmitter-&gt;doSubmitForm(Array, Object) (Line: 589)
Drupal\Core\Form\FormBuilder-&gt;processForm(&#039;user_login_form&#039;, Array, Object) (Line: 318)
Drupal\Core\Form\FormBuilder-&gt;buildForm(&#039;user_login_form&#039;, Object) (Line: 74)
Drupal\Core\Controller\FormController-&gt;getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-&gt;Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer-&gt;executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-&gt;wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-&gt;Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel-&gt;handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel-&gt;handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session-&gt;handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle-&gt;handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache-&gt;pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache-&gt;handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware-&gt;handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware-&gt;handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel-&gt;handle(Object, 1, 1) (Line: 666)
Drupal\Core\DrupalKernel-&gt;handle(Object) (Line: 19)

</pre>

//trying to answer one question for each one that i make.
//this way, drupal will be more friendly and strong

candelas’s picture

Hello

I found the solution. Just in case anybody needs it :)
 

/**
 * Implements hook_form_FORM_ID_alter().
 */
function YOURMODULE_form_user_login_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    // Alter login form and add own custom submit handler.
    $form['#submit'][] = 'YOURMODULE_user_login_form_submit';
}

/**
 * Custom submit handler for login form.
 */
function YOURMODULE_user_login_form_submit($form, FormStateInterface $form_state) {
  // $form_state->setRedirect('<front>');
  $options = ['absolute' => TRUE];
  //CHANGE NODE_NUMBER FOR THE NID YOU NEED
  $url = \Drupal\Core\Url::fromRoute('entity.node.canonical', ['node' => NODE_NUMBER], $options);


  // 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'));
  }
}

//trying to answer one question for each one that i make.
//this way, drupal will be more friendly and strong

parkhillrecords’s picture

I downloaded and installed the Login Destination module (dev release for D8) and it seems to work just fine.  I'm surprised this is not in core.

ElusiveMind’s picture

The current dev build of Login Destination breaks your site when you enable it (as of 6/1/18). So that is not a solution

sajosh’s picture

How about just "/user/login?destination=/your-destination"?  It works for me.

I'm also looking in to using Rules to redirect

https://www.drupal.org/node/298506

But with a twist ... record which landing page the user registered onto the site with.  This way I know which users are interested in what topics, initially.  This part I have to figure out yet.

colorfield’s picture

Just gave a test to Rules 3.0-alpha2 with Drupal 8.5.x, it does not conflict neither with password reset nor with set destination (e.g. redirect when the user meets a 403, with /user/login?destination=whatever).

Rules configuration: React on event: User has logged in, Action: Page redirect.

karolus’s picture

I would second some of the other comments-the Rules module does this quite easily, and offers a lot of flexibility. As a benefit, the UI is fairly straightforward.

piridium’s picture

How about setting up a custom login/logout-link in a twig-template (e.g. page.html.twig) like this:

{% if not logged_in %}
  <a href="/user/login?destination={{ path('<current>') }}">Login</a>
{% else %}
  <a href="/user/logout?destination={{ path('<current>') }}">Logout</a>
{% endif %}

Replace {{ path('<current>') }} with a / to redirect to the front-page.

labboy0276’s picture

This works on a couple different sites we have built in D8.



use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * Implements hook_user_login().
 */
function YOUR_MODULE_user_login($account) {
  $response = new RedirectResponse('/PATH');
  $response->send();
}

You can use what ever URL logic in that Redirect Response.  

A second way is to create an Event Subscriber (will always log people to their destination even if they are already logged in) like this:

In your_module.services.yml put:

services:
  YOUR_MODULE.event_subscriber:
    class: Drupal\YOUR_MODULE\EventSubscriber\UserRedirectSubscriber
    arguments: ['@path.matcher', '@current_user']
    tags:
      - {name: event_subscriber}

Then create the EventSubscriber

<?php

namespace Drupal\YOUR_MODULE\EventSubscriber;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Session\AccountInterface;

/**
 * Class UserRedirectSubscriber.
 *
 * @package Drupal\YOUR_MODULE\EventSubscriber
 */
class UserRedirectSubscriber implements EventSubscriberInterface {

  /**
   * The path matcher.
   *
   * @var \Drupal\Core\Path\PathMatcherInterface
   */
  protected $pathMatcher;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * Constructs a new Redirect404Subscriber.
   *
   * @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
   *   The path matcher service.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   Current user.
   */
  public function __construct(PathMatcherInterface $path_matcher, AccountInterface $current_user) {
    $this->pathMatcher = $path_matcher;
    $this->currentUser = $current_user;
  }

  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = ['initData'];
    return $events;
  }

  /**
   * Manage the redirect logic.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
   *   Managed event.
   */
  public function initData(GetResponseEvent $event) {

    // Make sure front page module is not run when using cli (drush).
    // Make sure front page module does not run when installing Drupal either.
    if (PHP_SAPI === 'cli' || drupal_installation_attempted()) {
      return;
    }

    // Don't run when site is in maintenance mode.
    if (\Drupal::state()->get('system.maintenance_mode')) {
      return;
    }

    // Ignore non index.php requests (like cron).
    if (!empty($_SERVER['SCRIPT_FILENAME']) && realpath(DRUPAL_ROOT . '/index.php') != realpath($_SERVER['SCRIPT_FILENAME'])) {
      return;
    }

    // Send to proper page if logged in.
    if ($this->pathMatcher->isFrontPage() && !$this->currentUser->isAnonymous()) {
      $event->setResponse(new RedirectResponse('/YOUR_PATH'));
    }
  }

}

John Ouellet
Sales Engineering Manager
https://thinktandem.io/

GeraldNDA’s picture

Maybe it'd be nice to wrap this up in a module. Seems like an atrocious amount of work for a deceivingly simple task ...

cri2mars’s picture

thanks for the tip labboy, the simple one (without EventSubscriber)

it works perfectly combined with secure login

abhishek0116’s picture

Hi labboy thanks for the above info.

I have used the first method to redirect the users to corresponding form after login successfully. But I want an exception for it. I want the first time users who are coming from their email links to reset their passwords to not get redirected to form instead allow them to set their pwd and after that redirect them to form. How can this be achieved.   

labboy0276’s picture

Alan D's comment below look correct for answering this question.  

John Ouellet
Sales Engineering Manager
https://thinktandem.io/

Alan D.’s picture

Seems to work nicely when we've used this without any recorded issues. This example checks both the route and user role to conditionally redirect.

use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;

/**
 * Implements hook_user_login().
 */
function greenacorn_user_login(AccountInterface $account) {
  $roles = $account->getRoles();
  // user.reset.login == reset
  // user.login == login
  $route_name = \Drupal::routeMatch()->getRouteName();
  if ($route_name != 'user.reset.login' && in_array('client', $roles)) {
    $destination = Url::fromUserInput('/my-issues')->toString();
    \Drupal::service('request_stack')->getCurrentRequest()->query->set('destination', $destination);
  }
}
abhishek0116’s picture

The above code works. This helped a lot. Thanks Davison.

hzakaryan’s picture

nazeer_mohamed’s picture

Please try 

$response = new RedirectResponse("path_to_go");
  $response->send();
nehajn’s picture

 /**

 * Implements hook_user_login()

 */

use Symfony\Component\HttpFoundation\RedirectResponse;

use Drupal\Core\Url;

function player_user_login($account) {  

   $current_user = \Drupal::currentUser();   

   $uid = $current_user->id(); 

   $user =  user_load($uid);

   $roles = $user->getRoles();

   if(in_array('player', $roles)){

      $url = \Drupal::url("custom_page.home", ['uid' => $uid]);

      $response = new RedirectResponse($url);   

      $response->send();

      return;

   }     

         

   

}
Alan D.’s picture

Was there a reason that you load the user rather than just using the wrapper?

   $uid = $current_user->id();
   $user =  user_load($uid);
   $roles = $user->getRoles();

Note small API change from 8.6.x

hook_user_login(\Drupal\user\UserInterface $account)