Score:0

Change default user tab

it flag
MMT

After logging in, users would be redirected to their user profile page. I have added a new tab, My dashboard using hook_menu(). Everything functions well.

After the users log in, I would like they are redirected to My dashboard, but I can't make it work.

I tried with in two ways, which both have the same problem.

First I tried with this code.

function mymodule_menu() {
  $items['user/%user/dashboard'] = array(
    'title' => t('My dashboard'),
    'page callback' => 'mymodule_dashboard',
    'page arguments' => array(1),
    'access callback' => TRUE,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -20, 
  );
  
  return $items;
}

function mymenu_menu_alter(&$items) {
  $items['user/%user/view'] = array(
    'type' => MENU_LOCAL_TASK,
  );
  
  return $items;
}

Then, I tried with the following code.

function mymodule_menu_alter(&$items) {
  $items['user/%user/dashboard'] = array(
    'title' => t('My dashboard'),
    'page callback' => 'mymodule_dashboard',
    'page arguments' => array(1),
    'access callback' => TRUE,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -20, 
  );

  $items['user/%user/view'] = array(
    'type' => MENU_LOCAL_TASK,
  );
  
  return $items;
}

I also cleared the cache.

The problem is that after login, the View tab disappears as tab, "My Dashboard" is the active tab, but it has the content of the previous View tab.

screenshot

The URL after the login is https://example.com/users/myusername1, which isn't the dashboard URL. When I click between the tabs, the My dashboard keeps this wrong URL and displays the content of the *View tab.

I tried a few variations between hook_menu() and hook_menu_alter(), but I can't make it work.

How can I have My dashboard and its own content displayed as the default tab after login?

apaderno avatar
us flag
`hook_menu_alter()` doesn't need to return any value. That's not the reason for the code not to work, though.
it flag
MMT
Thank you apaderno, Without pretending to be an expert, what I'm reading here is that hook_menu_alter actually takes one paramter https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_menu_alter/7.x Anyway this is a side detail, as even with or without the problem is still there. Any other ideas would be welcomed
Score:0
us flag

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,
  );
Score:0
de flag

You need a combination of hook_user_login() (called after the user logs in) and drupal_goto() (redirects the user). I haven't worked with D7 for a few years, but going off memory you should be able to do something like this:

function hook_user_login(&$edit, $account) {
  drupal_goto('user/' . $account['id'] . '/dashboard');
  drupal_exit();
}
it flag
MMT
Thank you Jaypan. I tried it but it does not solve the problem. The issue is that after I login the url is not the .../dashboard, but instead it is site.com/users/username8169 . Once I type the correct url manually site.com/user/8169 then it is working fine. But how to get the user after login to reach the .../dashboard page? It's also strange that the View tab disappeared.
Jaypan avatar
de flag
Ok, sorry I misunderstood your problem. I changed the answer altogether.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.