Студия разработки сайтов и приложений

Netspark.ru

Заметки и разработки

Drupal

User login block на продвинутых костылях

Как известно, всеми любимый блок логина в Друпале не появляется на страницах регистрации и восстановления пароля (user/register и user/password соотвественно). Объясняется это бессмысленное, на мой взгляд, ограничение обычным usability. В коде user.module, в котором оно реализовано, так и написано:

// For usability's sake, avoid showing two login forms on one page.
if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
  $block['subject'] = t('User login');
  $block['content'] = drupal_get_form('user_login_block');
}

(это функция user_block_view)

Написано, правда, про то что не надо показывать две формы логина на одной странице, но паровозом к этому цепляется и регистрация с восстановлением.

А что если бы мы хотели избавиться от ограничения? Придется добавить немного костылей.

Противникам патчей ядра дальше читать не нужно.

Значит, давайте отменим ограничение. Да, для этого нужно изменить код модуля user, и — да, это нехорошо. Но, блин, бывают ситуации, когда прямо очень надо.
Просто перепишем этот кусочек кода:

if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)) && (arg(1) != 'password') && (arg(1) != 'register'))) {
  $block['subject'] = t('User login');
  $block['content'] = drupal_get_form('user_login_block');
}

upd: Как верно подсказывают в комментах, если нет никаких веских причин сохранить именно оригинальный блок логина, можно просто создать свой блок. Но пусть и хак тут останется тоже, на всякий случай.

В принципе, это всё — блок авторизации теперь будет появляться на страницах регистрации и восстановления пароля. Однако если мы попробуем воспользоваться формой на этих страницах, то увидим что нас после логина снова редиректит на регистрацию/восстановление, даже если мы установили что-нибудь вроде Login Redirect. Это, конечно, неправильно.

Происходит так потому, что блок логина у себя в #action сохраняет параметр destination. Подставим небольшие костыли, теперь уже полностью drupal-way:

function mymodule_form_user_login_block_alter(&$form, &$form_state, $form_id) {
  if ((arg(0) == 'user') && ((arg(1) == 'register') || (arg(1) == 'password'))) {
    $action = explode('?', $form['#action']);
    $form['#action'] = $action[0] . '?destination=';
  }
} //mymodule_form_user_login_alter

То есть мы просто отрезаем query вместе с destination для страниц user/register и user/password.

Теперь блок на этих страницах работает гораздо лучше. Напоследок вспомним, что у нас еще может быть установлен замечательный модуль HybridAuth. На его логику наши костыли не подействуют, придется подставить более продвинутые. Вспомним, что в модуле HybridAuth есть настройка адреса переадресации после входа. И эта настройка принимает токены. Добавим токен, который отдает модулю HybridAuth для переадресации путь на главную страницу, если вход происходит со страниц user/register и user/password, и на текущую страницу во всех остальных случаях:


function mymodule_token_info() {
  $tokens['hybridauth_redirect_path'] = array(
    'name' => t("Hybridauth redirect path"),
    'description' => t("Path user will be redirected to when entering via HybridAuth."),
  );
  return array(
    'tokens' => array('site' => $tokens),
  );
} //mymodule_token_info

function mymodule_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $replacements = array();
  if ($type == 'site') {
    foreach ($tokens as $name => $original) {
      if ($name == 'hybridauth_redirect_path') {
        //у hybridauth своя логика логина, поэтому адрес страницы входа надо вытаскивать из реферера
        $referer = explode('/', $_SERVER['HTTP_REFERER']);
        $arg1 = array_pop($referer);
        $arg0 = array_pop($referer);
        if (($arg0 == 'user') && (($arg1 == 'register') || ($arg1 == 'password'))) {
          $replacements[$original] = '';
        } else {
          global $base_url;
          $path = str_replace($base_url . '/', '', $_SERVER['HTTP_REFERER']);
          if (drupal_valid_path($path)) { //check path just in case
            $replacements[$original] = $path;
          } else {
            $replacements[$original] = '';
          }
        }
      }
    }
  }
  return $replacements;
} //mymodule_tokens

Теперь и вход через HybridAuth тоже будет работать как надо со страниц регистрации/восстановления пароля.

Комментарии