Warning message

Documentation is currently being migrated into the new system. Some pages might be temporarily missing, and some guides might appear empty. Thank you for your patience while we are improving Drupal.org documentation.

HowTos

Create a custom User Registration form with FAPI D7

Last updated on
1 November 2016

There are many reasons to create a custom User Registration form in Drupal, so I won't get into the "Why?" of it. This isn't a tutorial about necessarily how to use FAPI, but rather a particular way to accomplish something with FAPI. I assume when writing this that you understand hook_form() and the basics of putting your own module together.

Essentially we start with FAPI and hook_form() to build out the form itself in our module:

hook_form()

function foo_user_register_form($form, &$form_state){
	$form['name'] = array(
		'#title' => 'username',
		'#description' => 'choose a username',
		'#type' => 'textfield',
		'#required' => TRUE,
	);
	$form['mail'] = array(
		'#title' => 'email',
		'#description' => 'enter a valid email address',
		'#type' => 'textfield',
		'#required' => TRUE,
	);
        $form['submit'] = array(
		'#type' => 'submit',
		'#value' => t('Save'),
	);

The username and email are all that are specifically required to create the account, other fields created with Field UI can be added in at will. You could even call them something different if you wanted, here in the hook_form().

The real magic of saving the user happens in the submit handler of your module, which utilizes user_save().

Submit Handler

function foo_user_register_form_submit($form, &$form_state){
	$edit = array(
	      'name' => $form_state['values']['name'], 
	      'pass' => user_password(),
	      'mail' => $form_state['values']['mail'],
	      'init' => $form_state['values']['mail'], 
	      'status' => 1, 
	      'access' => REQUEST_TIME,
	);
	user_save(drupal_anonymous_user(), $edit);
}

The user_password() function generates a random string to be stored as the user's password.

Adding additional fields to the submit handler

Let's say that we added some custom fields "First Name" (field_fname) and "Last Name" (field_lname) to our users via the UI in d7. We can represent that in our form any way we want to because the key of the $edit array (in our submit handler) is what matters.

function foo_user_register_form($form, &$form_state){
	$form['name'] = array(
		'#title' => 'username',
		'#description' => 'choose a username',
		'#type' => 'textfield',
		'#required' => TRUE,
	);
	$form['mail'] = array(
		'#title' => 'email',
		'#description' => 'enter a valid email address',
		'#type' => 'textfield',
		'#required' => TRUE,
	);
        $form['field_fname'] = array(
		'#title' => 'First Name',
		'#type' => 'textfield',
	);
        $form['field_lname'] = array(
		'#title' => 'Last Name',
		'#type' => 'textfield',
	);
        $form['submit'] = array(
		'#type' => 'submit',
		'#value' => t('Save'),
	);

In Drupal 6 we had a 'data' key in the new user array, in Drupal 7 it's been deprecated. To add these fields programmatically when saving a user we add them to our submit handler like so:

function foo_user_register_form_submit($form, &$form_state){
	$edit = array(
	      'name' => $form_state['values']['name'], 
	      'pass' => user_password(),
	      'mail' => $form_state['values']['mail'],
	      'init' => $form_state['values']['mail'], 
	      'status' => 1, 
	      'access' => REQUEST_TIME,
              'field_fname' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['field_fname']))),
	      'field_lname' => array(LANGUAGE_NONE => array(array('value' => $form_state['values']['field_lname']))),
	);
	user_save(drupal_anonymous_user(), $edit);
}

If you happen to be fond of adding fieldsets to your forms with FAPI (probably to make use of #states or something) and you slap your extra fields in one, you do not need to have to actually mention that fieldset in the submit handler.

$form_state['values']['fieldset_name']['field_fname']

vs.

$form_state['values']['field_fname']

If you add the fieldset in betwixt the ['values'] and ['field_name'] in the submit handler, you'll get a NULL value in the database for that field.

Saving roles

In my form I decided I would let users choose their own roles. I created a field of #type "select" and used the role names I created as options. In the submit handler I added $roles as an empty variable and set it within if() statements based on the $form_state['value'] of my field.

$roles = '';
	if($form_state['values']['user_kind'] == 'A User Role'){
		$roles = array('1' => 'A User Role');
	}
	elseif($form_state['values']['user_kind'] == 'A Different Role'){
		$roles = array('2' => 'A Different Role');
	}

Keep in mind that the key must match the value in the database. After this simply add the following to the $edit array:

        'roles' => $roles,

Set up notification email.

In drupal 6 there was drupal_mail_send() which was great. Drupal 7 took that away and left us with what is, in my opinion, a too complicated function called drupal_mail(). I opted to use php's mail() instead.

In the hook_form() I added a checkbox:

$form['send_message'] = array(
		'#type' => 'checkbox',
		'#title' => t('Notify user of new account via email.'),
		'#description' => 'If left unchecked, a message will not be sent.',
		'#default_value' => 1,
	);

At the end of the submit function I tacked on the setup for a notification:

$to = $form_state['values']['mail'];
	$subject = 'New account created';
	$headers = "From: something@somewhere.org\nContent-type: text/html";
	$body = 'A new user account has been created for you at Something.org.
 Your login details are as follows:
Username: '.$form_state['values']['name'].'
 Password: '.$form_state['values']['password'].'

 Please login to Something.org and change your password.
'; if($form_state['values']['send_message'] == 1){ mail($to,$subject,$body,$headers); }

It's really important that your headers use new lines "\n" between each other, and I also discovered that it didn't really work unless $headers value was in double quotes.