Changing the default tab shown for a page isn't the way to redirect users after they log in. It also works only when users are redirected to their user profile page after they log in. If they are redirected to a different page, altering the default tab for the /user/%user page won't achieve what you are trying to achieve.
To redirect users after they entered their credentials in the login form (whenever it's shown on the login page or in the login block) is to:
- Add a form submission handler to the login form
- In that submission handler, redirect users to the desired URL
function mymodule_form_user_login_alter(&$form, &$form_state) {
$form['#submit'][] = 'mymodule_user_login_submit';
}
function mymodule_user_login_submit($form, &$form_state) {
if (!empty($form_state['uid'])) {
// The user was successfully logged in.
// $form_state['uid'] is set by user_login_authenticate_validate() when the login credentials are correct.
$form_state['redirect'] = "user/{$form_state['uid']}/dashboard";
}
}
Since hook_user_login()
implementations are invoked from user_login_finalize()
, they aren't only invoked after users log in from the user interface; for example, they are invoked after a user followed the link to reset their password, which makes Drupal run user_pass_reset()
, the function that contains the following code.
if ($action == 'login') {
$user = $account;
user_login_finalize();
flood_clear_event('pass_reset_user', $account->uid);
watchdog('user', 'User %name used one-time login link at time %timestamp.', array(
'%name' => $account->name,
'%timestamp' => $timestamp,
));
drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
$token = drupal_random_key();
$_SESSION['pass_reset_' . $user->uid] = $token;
drupal_goto('user/' . $user->uid . '/edit', array(
'query' => array(
'pass-reset-token' => $token,
),
));
Calling drupal_goto()
inside hook_user_login()
interferes with that and other cases, and it doesn't allow Drupal to invoke all the hook_user_login()
implementations.
A hook_user_login()
implementation could set $edit['redirect']
to redirect the users.
function mymodule_user_login(&$edit, $account) {
if (is_array($edit)) {
$edit['redirect'] = "user/{$account->uid}/dashboard";
}
}
drupal_goto()
, called from drupal_process_form()
(via drupal_redirect_form()
) when a form is submitted without errors, uses the value of $_GET['destination']
when its value is not an external URL. To be sure users are redirect to the desired path, the implementation could be similar to the following one.
function mymodule_user_login(&$edit, $account) {
if (strpos(current_path(), 'user/reset/') !== 0) {
// Avoid redirecting users who reset their password.
$_GET['destination'] = "user/{$account->uid}/dashboard";
}
}
The code should also check it's not redirecting users in cases it should not, and verify it doesn't cause issues with other installed modules, for example the Two-factor Authentication (TFA) module. For this reason, I would avoid setting $_GET['destination']
and use one of the other solutions I described in this answer.
As for https://example.com/users/myusername1 appearing as URL, that is using a path alias. Modules that implement hook_menu()
don't need to worry about path aliases, as Drupal uses the path alias to find the page to show and calls the page callback associated to that page.
If then you need to change the default tab shown on user/%user, for different reasons, I would use code similar to the following one.
function mymodule_menu_alter(&$items) {
if (isset($items['user/%user'])) {
$items['user/%user/view'] = array(
'title' => 'View',
'type' => MENU_LOCAL_TASK,
'weight' => -10,
'page callback' => 'user_view_page',
'page arguments' => array(1),
'access callback' => 'user_view_access',
'access arguments' => array(1),
);
$items['user/%user'] = array(
'title' => 'My account',
'title callback' => 'user_page_title',
'title arguments' => array(1),
'page callback' => 'mymodule_dashboard',
'page arguments' => array(1),
'access callback' => 'user_view_access',
'access arguments' => array(1),
'menu_name' => 'navigation',
);
$items['user/%user/dashboard'] = array(
'title' => 'My dashboard',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -20,
);
}
}
The reason why $items['user/%user/dashboard']
contains few items is that a MENU_DEFAULT_LOCAL_TASK
menu item inherit page callback, page arguments, access callback, and access arguments from its parent menu item, in this case $items['user/%user']
.
This is described in the hook_menu()
documentation, and it's also the reason the following menu items, taken from Drupal core code, are defined in that way.
$items['node/%node'] = array(
'title callback' => 'node_page_title',
'title arguments' => array(1),
'page callback' => 'node_page_view',
'page arguments' => array(1),
'access callback' => 'node_access',
'access arguments' => array('view', 1),
);
$items['node/%node/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['admin/config/search/path'] = array(
'title' => 'URL aliases',
'description' => "Change your site's URL paths by aliasing them.",
'page callback' => 'path_admin_overview',
'access arguments' => array('administer url aliases'),
'weight' => -5,
'file' => 'path.admin.inc',
);
$items['admin/config/search/path/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['admin'] = array(
'title' => 'Administration',
'access arguments' => array('access administration pages'),
'page callback' => 'system_admin_menu_block_page',
'weight' => 9,
'menu_name' => 'management',
'file' => 'system.admin.inc',
);
$items['admin/tasks'] = array(
'title' => 'Tasks',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -20,
);