You are here

Users Creating Users in Drupal

Corey Pennycuff's picture

One of the biggest mistakes that I feel that Drupal has made is that it is difficult for non-administrators to create accounts for other users.  While at first blush this seems appropriate, there are many, many valid reasons that users should be able to create accounts on behalf of other people.  The problem is that, in all versions of Drupal (at least 5-8) there is a call to drupal_goto() inside the form generation function that is executed unless the user has the "administer users" permission.

This is bad!  I actually feel that this is a defect, in that the code should not perform a redirect when generating a form!  Returning nothing would be much preferred!

That being said, I have had 3 sites in as many months that needed the functionality of one individual (not an administrator) creating an account for another user.  The general method presented here is not without difficulty, as you may have to do other altering of the form in order to get it to do everything that you want it to, but the code shown here will provide the basic functionality.

Other Resources

Before we go too far into custom coding, it is worth noting that there are several modules that can do some of this functionality.  I do not want to muddy the waters here, though, so I will point you to a blog post by Lowell Montgomery that does precisely that.  For my implementations, however, none of these solutions were fitting, so I had to use custom code.

Realize what needs to be done

Drupal will only generate a user registration form if:

  1. The user is anonymous and the site's settings allow for anonymous users to register their own account.
  2. The user has the "administer users" permission.

Failing either of these two situations, the form will perform a redirect, and you will not be a happy camper!

Potential Solutions

We have three possible courses of actions:

  1. Write a custom registration form.
  2. Trick Drupal into thinking that we are an anonymous user and render the form.
  3. Trick Drupal into thinking that we have "administer users" permission and render the form.

Of these potential solutions, I did not want to write a custom registration form, due to factors beyond the scope of this post.  In short, it would have been A LOT of work!  I also could not go the route of anonymous user because of site settings (which also could have been worked around by more code, but that is another issue).  That leaves us with only one option: faking an administrator account.

Plan of Attack

For this to work, we must do a few things.  First, we will provide a place for our form to be generated, such as a block or a menu callback.  Second, we must spoof the administrator access temporarily, generate the form, then fix any problems we may have caused.

Menu Callback

For the example code given here, we assume that a module named CUSTOM has been created.

/**
 * Implements hook_menu().
 */
function CUSTOM_menu() {
  $items = array();
  $items['custom_registration'] = array(
    'title' => 'Add User Account',
    'page callback' => 'CUSTOM_user_registration',
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

You will probably want to provide your own access method for security.

Form Generation

/**
 * CUSTOM callback to generate a user registration form.
 */
function CUSTOM_user_registration() {
  global $user;
  // Retrieve the user permissions from drupal_static()
  $permissions = &drupal_static('user_access');
 
  // Keep a record of the state of this permission before we mess with it
  if (!isset($permissions[$user->uid]['administer users'])) {
    $cleanup = 'unset';
  }
  else {
    $cleanup = $permissions[$user->uid]['administer users'];
  }
 
  // Add the 'administer users' permission to the logged-in user
  $permissions[$user->uid]['administer users'] = TRUE;
 
  // Generate the form HTML normally
  $form = drupal_get_form('user_register_form');
 
  // Restore the user permissions to their default state
  if ($cleanup === 'unset') {
    unset($permissions[$user->uid]['administer users']);
  }
  else {
    $permissions[$user->uid]['administer users'] = $cleanup;
  }
 
  // Return the rendered HTML
  return $form;
}

The comments in the code describe what is happening quite well. The gist is that we temporarily grant the correct permission to the user, long enough to generate the form, then restore the permission to its original state. Be aware that, when drupal_get_form() is called, all of the hook_form_alter()'s will also be called, all while the user has the elevated permission. If you need additional functionality or alterations to the form, it is proper to add it in a hook_form_alter().

Conclusion

With a little bit of code is it absolutely possible to get custom functionality out of the user registration form. The major caveat, however, is that you are responsible to make sure that only the things that you intend to show are allowed in the form. The reward is ultimate and individual control over the user creation experience on your site, which may very well make or break your project!

Tags: