Drupal: Combining the Login and Registration Forms

It’s easy to take Drupal’s built-in user management features for granted… out of the box, you can configure your site to allow user registrations, reset forgotten passwords, and handle user logins. We had a use case where we wanted to combine the login and registration forms into a single landing page for anonymous users, to encourage users without an account to sign up with a single click rather than hiding the registration form behind another link.

There are many ways to skin a cat in Drupal, and the more familiar you get with the way Drupal and its many contributed modules work you start to realize that it’s possible to do things like set up a combination login/registration screen with little if any custom coding.

Here’s what we did (Your mileage may vary - on some sites it may not be appropriate to use executable PHP blocks, but our permission scheme accomodated it nicely):

  1. Create a new block (Admin > Build > Block > Add Block). Set the input format to PHP Code, and give it the following contents, which will display the standard user login form:

    <?php  print drupal_get_form('user_login');  ?> 
  2. Create another new PHP Code block for the registration form:
    <?php  print drupal_get_form('user_register');  ?> 
  3. Install the Panels module, and add a new Panel using the two column layout.

  4. Put the login form block in the left column and the registration form block in the right column. Give the panel a path like myapp/register- it’s very important that the second part of the path contain the word register. (More on that in a moment) Save the panel.

  5. Go to Administer > Site Configuration > Error Reporting and set the default 403 (Access Denied) error page to the path of the Panel you just created. This means that whenever an anonymous user encounters a page requiring authentication, they will get the login/registration form instead of the somewhat rude, default “Access Denied” error.

And that’s it. Zero custom code required, and we had our combination login/registration screen ready to go. We did choose to write a small module implementing hook_form_alter() to streamline the forms a little bit, making fields shorter, eliminating some of the field descriptions, and adding a link to the password reset form. Combined with some CSS styling, the result is pretty sharp:

So, why does the Panel’s path have to have two items, the second one always being “register”? The answer is in the core user.module file, in the _user_edit_validate() function:

<?php
// Validate the username:
if (user_access('change own username') || user_access('administer users') || arg(1) == 'register') {
if ($error = user_validate_name($edit['name'])) {
form_set_error('name', $error);
}
else if (db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid, $edit['name'])) > 0) {
form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name'])));
}
else if (drupal_is_denied('user', $edit['name'])) {
form_set_error('name', t('The name %name has been denied access.', array('%name' => $edit['name'])));
}
}
?>

This chunk of code is responsible for making sure a submitted user name isn’t already taken, and the only way it gets called when the user_register form is submitted is if arg(1) is “register”, as is the case when signing up from the standard /user/register path. If you give your combination login/register panel a path whose second item is not “register”, it will still work, but the system won’t catch duplicate user name requests, resulting in the behavior reported at http://drupal.org/node/148525.

Love your post. I'm sure

Love your post. I'm sure i'll include this code into my drupal websites. Cheers.

Hi, although this article

Hi,

although this article is way old is there a way to avoid the loop? users cannot register to my site with both, the login field and registration, enabled. it simply reloads the page.

thanks!

I think you ought to be able

I think you ought to be able to use hook_menu_alter to do this. Use hook_menu_alter to de-register four of the URLS (clear your cache after you install your module or it won't work). Then generate a new callback function for the URL you require to keep. You can register this in hook_menu_alter as well. From there, make your callback call and return both of the forms (the login and registration page).

Thanks for the detailed steps

Andy, thanks for the tips! I'm helping my wife with her drupal site and your instructions really came in handy. She's planning to setup a private membership area with it and I was just figuring how to deal with the login issue. Please keep up the great work!

I've subscribed to your blog :)

_user_edit_validate() and the path

Looks like the requirement for the path's arg(1) to be 'register' is no longer in effect (as of Drupal 6.12 at least, maybe earlier).

Thanks!

This works great without panels

As Chris Burgess points out, arg(1) is no longer needing to be 'register' for Drupal 6.14 and simply using drupal_get_form('user_login') and drupal_get_form('user_register'), without Panels, takes care of things nicely for us so far.

thanks for the article and comments

Redirect Loop

For some reason I cannot get it to work, does anybody have any idea how to solve the problem with the redirect loop? As long as you do not put both forms together on one page, everything works great, but once you enable both of them you get this "redirect loop" error... I really have no idea what to do...

Anybody??

Redirect problem possibly because...

I wonder if all these redirect loop issues are down to line 1241 (Drupal 6.14) which is as follows:


// If we are already logged on, go to the user page instead.
if ($user->uid) {
drupal_goto('user/'. $user->uid);
}

combined with (when you drupal_get_form for both login and registration forms) line 2399 which is as follows:


// If we aren't admin but already logged on, go to the user page instead.
if (!$admin && $user->uid) {
drupal_goto('user/'. $user->uid);
}

Is it possible that these error loops are occurring because the user is already logged in? The very act of calling both forms is possibly trying to redirect (drupal_goto) already logged in users twice to 'user/userid'? Just wondered if this might be the case? If so, a simple 'if' statement of :


if ($user->uid == 0){
...drupal_get_forms...
}

would probably resolve this?

Missing the obvious?

"This great but I think you are ignoring the fact that the 403 page is required for when the user is not allowed to access some part of the site .. eg non-administrative user trying to access /admin. In that case presenting a login form when 1. they are already logged in and 2. really should be seeing an access denied message is not such a good idea."

I don't think this is missing the obvious. Access denied messages aren't a bad idea. That doesn't even make sense. It shows the user they aren't allowed to do that.

--Jack Bristoll

"There are many ways to skin

"There are many ways to skin a cat in Drupal, and the more familiar you get with the way Drupal and its many contributed modules work you start to realize that it’s possible to do things like set up a combination login/registration screen with little if any custom coding." So true.. thats what makes it great.. Thanks for sharing your code! Kate

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd><p><div> <br><img>
  • Lines and paragraphs break automatically.

More information about formatting options

Verification
This question is for testing whether you are a human visitor and to prevent automated spam submissions.