How to customize login page with custom login fields in Drupal 9 & 10

Here we are discussing about how to customize default login page of drupal for making users to easily login. For example instead of providing user name and password  we can allow users to provide their phone number and login to their account.Here we are discussing how to achieve this by altering login form.

Here we are adding an additional phone number field in Configuration -> under People  Account settings → select Manage fields tab.

Add a plain text field mobile number.

Now  you can see new mobile number field in user register form. Make this field as mandatory filed. 

Next we are going to override our login page with only phone number field for login as below.

We are going to alter form fields fields and handlers in our custom module *.module file in below hook.

function dn_login_form_alter(&$form, FormStateInterface $formState, $form_id) {
 
   if ($form_id == 'user_login_form'){
   }
}

Here dn_login is our custom module. In If condition we are checking whether current form is login form or not.  If it it login form we have to implement below actions.

  •  Remove username and password fields from the form.
  •  Remove existing validations and submit handlers.
  • Add mobile number field into login form array.
  •  Implement our custom validation and submit handlers.

Step1 -Remove username and password fields from the form

Remove username and password fields using unset function.

unset($form[‘name’]);

unset($form[‘pass’]);

Step – 2 Remove existing validations and submit handlers

We have to remove existing validations in login form using unset as below.

unset($form[“#validate”]);

Also unset submit handlers as below.

unset($form[‘#submit’][0]);

Step – 3 Add mobile number field into login form array

Add below field to the form array.

$form['mobilenumber'] = [
            '#type' => 'tel',
            '#title' => t('Mobile Number'),
            '#description' => t('Enter the Mobilenumber'),
            '#required' => TRUE,
            '#maxlength' => 60,
            '#attributes' => ['class' => ['mobile-number-login']],
            '#size' => 60,
            '#weight' => -49,
        ];


So finally hook_form_alter will look like this.

 Implement our custom validation and submit handlers 

We are adding below functions for validation and submit handler.

function dn_login_form_alter(&$form, FormStateInterface $formState, $form_id) {
   
    if ($form_id == 'user_login_form'){
      

    //$flood_config = \Drupal::service('config.factory')->getEditable('user.flood');
     
            unset($form['#submit'][0]);
            unset($form['name']);
            unset($form["#validate"]);
            unset($form['pass']);
            $form['#validate'][] = 'validateMobile';
            $form['actions']['submit']['#submit'][] = 'phone_login_callback';
            $form['mobilenumber'] = [
            '#type' => 'tel',
            '#title' => t('Mobile Number'),
            '#description' => t('Enter the Mobilenumber'),
            '#required' => TRUE,
            '#maxlength' => 60,
            '#attributes' => ['class' => ['mobile-number-login']],
            '#size' => 60,
            '#weight' => -49,
        ];
    }
}


$form[‘#validate’][] = ‘validateMobile’;

$form[‘actions’][‘submit’][‘#submit’][] = ‘phone_login_callback’;

Before implementing validation and submit handlers we have to get username of registered members by passing mobile number.we need this in many places. So we are creating a generic function that will retrieve username as below.

function getNameFromPhone($mobileno){


 $users = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties(['field_mobile_number' => $mobileno]);
 $user = $users ? reset($users) : FALSE;
  
   if ($user) {
     return $user->getAccountName();
   }else{


     return FALSE;
   }


}

If user is present, the above function will return account name. Otherwise return false.

For validation we have to implement validateMobile function.

In this function we have to check phone number field is empty, check for phone number associated with any registered user or not, also we need to check if user already registered, check check whether user is blocked or not. If user account is blocked we should not allow the user to login.

So validateMobile function will look like below.

function validateMobile(array &$form, FormStateInterface $form_state) {


   if($form_state->isValueEmpty('mobilenumber')){
      $form_state->setErrorByName('mobilenumber', 'Enter Mobile number');
      return;
     
   }


   if(!(getNameFromPhone($form_state->getValue('mobilenumber')))){


     $form_state->setErrorByName('mobilenumber', 'Mobile number Not Registered');


     return;
    
  }


 if(getNameFromPhone($form_state->getValue('mobilenumber'))){
   if (!$form_state->isValueEmpty('mobilenumber') && user_is_blocked(getNameFromPhone($form_state->getValue('mobilenumber')))) {
     // Blocked in user administration.
     $form_state->setErrorByName('mobilenumber', 'The user with phone number  %mobilenumber has not been activated or is blocked.', ['%mobilenumber' => $form_state->getValue('mobilenumber')]);
   
   }
 }


}

Here user_is_blocked functions will return true if user is blocked.

In  phone_login_callback submit handler function we are implementing  successful login and redirection to user admin page.

user_login_finalize($account) is used to login the account.
Complete implementation of phone_login_callback provided below.

function phone_login_callback(&$form, FormStateInterface $form_state) {
 
$mobile = $form_state->getValue('mobilenumber');
 if ($form_state->getErrors()) {
 
   unset($form['#prefix']);
   unset($form['#suffix']);
   $form['status_messages'] = [
     '#type' => 'status_messages',
     '#weight' => -10,
   ];
   $form_state->setRebuild();
 
 }else{
  
   $users = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties(['field_mobile_number' => $mobile]);
    $user = $users ? reset($users) : FALSE;
  
   if ($user) {
     $form_state->setValue('name', $user->getAccountName());
     $account = user_load_by_name($user->getAccountName());
     user_login_finalize($account);
   
   }else{
     
      $form_state->setRebuild();
      $form_state->setErrorByName('mobilenumber', 'User doesnot exist');
      return;


   }
  
 }




}

You can download the complete source code of dn_login module here.

Please note:  Allowing user to login with one field will create security issues. Also we are removing blocking of more than 5 failed attempts ie. Flood controls are removed here.

Get Free E-book
Get a free Ebook on Drupal 8 -theme tutorial
I agree to have my personal information transfered to MailChimp ( more information )
if you like this article Buy me a Coffee this will be an ispiration for me to write articles like this.

You may also like...