DiggingIntoWordPress

by Chris Coyier & Jeff Starr

Custom Login/Register/Password Code

Posted by on

In this DiW post, we transform three slices of code into a clean & stylish tabbed menu that visitors can use to login, register, and recover passwords from anywhere in your site. Too many features & details to explain up front, so check out the working demo to see the finished product. On the menu:

Default WordPress Login Page

Out of the box, WordPress uses wp-login.php for logging into the Admin, retrieving lost passwords, and registering for site membership. Each of these activities are handled on the same page, commonly referred to as the WordPress Login Page.

[ Screenshot: Default WordPress Login/Register Page ]
Yep, it’s the WordPress Login Page

As seen here, the Login Page shows the log-in form by default. Beneath the form are two links, “Register” and “Lost your password?”, which enable users to (yep, you guessed it) register and recover their password.

The cool thing about the Login Page is that the page doesn’t reload when either of these links are clicked. Instead, the form instantly changes from login to register or password to whatever. All three forms are included on the wp-login.php page and hidden/revealed as-needed using JavaScript. This “same-page” functionality is key to setting up our own custom login/register/password form elsewhere in our theme.

Moving the login/register/password form

While it’s not a good idea to move the entire wp-login.php file, it is possible to display the login/register/password forms anywhere in your theme. For example, putting the forms in your sidebar.php make it super-easy for visitors to register and login from anywhere in your site (here is an example). You could even create a WordPress page for each event: login, registration, and password-recovery pages that are customized/optimized in some really unique, bad-ass way.

The key to mobilizing the login forms is ensuring that they’ll work properly regardless of placement (before, after, or within the loop) in your theme template files. We also want to ensure that normal visitors who aren’t logged in see the forms, but logged-in users do not (or see alternate content).

Basically, it should work exactly like the default WordPress login functionality, but with one exception: instead of redirecting to the Admin Area (for log-ins) or to the Login Page (for registrations/password-recovery), we want the user to remain on the same page. This enables your guests to log-in, register, and reset passwords without leaving whatever page they happen to be visiting. Here’s the code to make it happen..

Custom WordPress template code

Here is the code to display the login/register/password form anywhere in your theme:

view as plain text

<div id="login-register-password">

	<?php global $user_ID, $user_identity; get_currentuserinfo(); if (!$user_ID) { ?>

	<ul class="tabs_login">
		<li class="active_login"><a href="#tab1_login">Login</a></li>
		<li><a href="#tab2_login">Register</a></li>
		<li><a href="#tab3_login">Forgot?</a></li>
	</ul>
	<div class="tab_container_login">
		<div id="tab1_login" class="tab_content_login">

			<?php $register = $_GET['register']; $reset = $_GET['reset']; if ($register == true) { ?>

			<h3>Success!</h3>
			<p>Check your email for the password and then return to log in.</p>

			<?php } elseif ($reset == true) { ?>

			<h3>Success!</h3>
			<p>Check your email to reset your password.</p>

			<?php } else { ?>

			<h3>Have an account?</h3>
			<p>Log in or sign up! It&rsquo;s fast &amp; <em>free!</em></p>

			<?php } ?>

			<form method="post" action="<?php bloginfo('url') ?>/wp-login.php" class="wp-user-form">
				<div class="username">
					<label for="user_login"><?php _e('Username'); ?>: </label>
					<input type="text" name="log" value="<?php echo esc_attr(stripslashes($user_login)); ?>" size="20" id="user_login" tabindex="11" />
				</div>
				<div class="password">
					<label for="user_pass"><?php _e('Password'); ?>: </label>
					<input type="password" name="pwd" value="" size="20" id="user_pass" tabindex="12" />
				</div>
				<div class="login_fields">
					<div class="rememberme">
						<label for="rememberme">
							<input type="checkbox" name="rememberme" value="forever" checked="checked" id="rememberme" tabindex="13" /> Remember me
						</label>
					</div>
					<?php do_action('login_form'); ?>
					<input type="submit" name="user-submit" value="<?php _e('Login'); ?>" tabindex="14" class="user-submit" />
					<input type="hidden" name="redirect_to" value="<?php echo $_SERVER['REQUEST_URI']; ?>" />
					<input type="hidden" name="user-cookie" value="1" />
				</div>
			</form>
		</div>
		<div id="tab2_login" class="tab_content_login" style="display:none;">
			<h3>Register for this site!</h3>
			<p>Sign up now for the good stuff.</p>
			<form method="post" action="<?php echo site_url('wp-login.php?action=register', 'login_post') ?>" class="wp-user-form">
				<div class="username">
					<label for="user_login"><?php _e('Username'); ?>: </label>
					<input type="text" name="user_login" value="<?php echo esc_attr(stripslashes($user_login)); ?>" size="20" id="user_login" tabindex="101" />
				</div>
				<div class="password">
					<label for="user_email"><?php _e('Your Email'); ?>: </label>
					<input type="text" name="user_email" value="<?php echo esc_attr(stripslashes($user_email)); ?>" size="25" id="user_email" tabindex="102" />
				</div>
				<div class="login_fields">
					<?php do_action('register_form'); ?>
					<input type="submit" name="user-submit" value="<?php _e('Sign up!'); ?>" class="user-submit" tabindex="103" />
					<?php $register = $_GET['register']; if($register == true) { echo '<p>Check your email for the password!</p>'; } ?>
					<input type="hidden" name="redirect_to" value="<?php echo $_SERVER['REQUEST_URI']; ?>?register=true" />
					<input type="hidden" name="user-cookie" value="1" />
				</div>
			</form>
		</div>
		<div id="tab3_login" class="tab_content_login" style="display:none;">
			<h3>Lose something?</h3>
			<p>Enter your username or email to reset your password.</p>
			<form method="post" action="<?php echo site_url('wp-login.php?action=lostpassword', 'login_post') ?>" class="wp-user-form">
				<div class="username">
					<label for="user_login" class="hide"><?php _e('Username or Email'); ?>: </label>
					<input type="text" name="user_login" value="" size="20" id="user_login" tabindex="1001" />
				</div>
				<div class="login_fields">
					<?php do_action('login_form', 'resetpass'); ?>
					<input type="submit" name="user-submit" value="<?php _e('Reset my password'); ?>" class="user-submit" tabindex="1002" />
					<?php $reset = $_GET['reset']; if($reset == true) { echo '<p>A message will be sent to your email address.</p>'; } ?>
					<input type="hidden" name="redirect_to" value="<?php echo $_SERVER['REQUEST_URI']; ?>?reset=true" />
					<input type="hidden" name="user-cookie" value="1" />
				</div>
			</form>
		</div>
	</div>

	<?php } else { // is logged in ?>

	<div class="sidebox">
		<h3>Welcome, <?php echo $user_identity; ?></h3>
		<div class="usericon">
			<?php global $userdata; get_currentuserinfo(); echo get_avatar($userdata->ID, 60); ?>

		</div>
		<div class="userinfo">
			<p>You&rsquo;re logged in as <strong><?php echo $user_identity; ?></strong></p>
			<p>
				<a href="<?php echo wp_logout_url('index.php'); ?>">Log out</a> | 
				<?php if (current_user_can('manage_options')) { 
					echo '<a href="' . admin_url() . '">' . __('Admin') . '</a>'; } else { 
					echo '<a href="' . admin_url() . 'profile.php">' . __('Profile') . '</a>'; } ?>

			</p>
		</div>
	</div>

	<?php } ?>

</div>

Okay, so here are the functional highlights for this hefty chunk of code:

  • Everything is wrapped with <div id="login-register-password"></div>
  • If the user is not logged in, the three forms are included in the markup
  • If the user is logged in, a simple welcome message is displayed
  • Success messages are displayed after both password recovery and registration
  • Each form submission sets a generic user-cookie
  • After login or registration, the script redirects the user to the same page
  • Only one form is shown at a time; JavaScript is used to show and hide forms

So if you just throw this thing into your sidebar.php file, you’ll see the login form and three links: login, register, and recover-password. The other two forms are included in the markup, but are hidden with CSS (display:none;). As-is, the three links won’t do anything because they require JavaScript to work. Once we sprinkle in some jQuery, the links will toggle the three different forms.

Implement and Demo

First let’s walk through using this code in your theme, and then we’ll check out a demo.

  1. Place the custom login code in your sidebar.php file, or some other location
  2. Grab the jQuery code (no-conflict mode) and include it in your footer.php file
  3. Include the CSS code in your theme’s style.css file, or wherever your styles are located

..and done. Once these three items are in place, upload everything to your server and check it out. Here is a demo showing this code used on a custom page within the loop.

Note that we have registration disabled here at DigWP.com, so the forms won’t be of much use other than to show how the tabs work and how the forms are styled. Here are some screenshots showing the “success” messages, and also the “logged-in” display.

[ Screenshot: Registration Success Message ]
Message displayed on successful registration

[ Screenshot: Password-Recovery Success Message ]
Message displayed on successful password-recovery

[ Screenshot: Logged-In View ]
Content displayed when user is logged into the site

Here again is the demo and here are the three resource files:

Customizing things

One of the main reasons why we like working with actual code instead of widgets or plugins is the ability to easily customize anything we want exactly how we want it. With this implementation, there are basically three things to customize: the jQuery, the custom login code, and the CSS. As with any code, there are countless ways to modify appearance and functionality, so hopefully you have something specific in mind, and are familiar enough with design to jump in and customize things. If not, no worries – here are some ideas to help get you started.

Customizing the login forms

As-is, the custom login forms redirect to the current page. To get any/all of the forms to redirect to a different page, locate and edit the following line of code:

<input type="hidden" name="redirect_to" value="<?php echo $_SERVER['REQUEST_URI']; ?>" />

There are three instances of this hidden input field, which WordPress uses to perform the redirect. The value returns the current URL, so that’s what needs changed for each form to redirect elsewhere.

Another useful modification involves customizing what the logged-in users see. Showing the gravatar and username is kind of neat, but there are tons of cool tricks to help ensure smooth user experience.

Customizing the jQuery

The jQuery used to show/hide the different login panels is actually pretty basic and is only used for toggling display states. I suppose there is a way to customize this, but it already handles additional menu items, so maybe you want to change the class names or optimize the script or something.

I do love to look at a nice slice of well-formatted jQuery, however, so I’ll further indulge myself by including the entire code snippet right here:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		$(".tab_content_login").hide();
		$("ul.tabs_login li:first").addClass("active_login").show();
		$(".tab_content_login:first").show();
		$("ul.tabs_login li").click(function() {
			$("ul.tabs_login li").removeClass("active_login");
			$(this).addClass("active_login");
			$(".tab_content_login").hide();
			var activeTab = $(this).find("a").attr("href");
			if ($.browser.msie) {$(activeTab).show();}
			else {$(activeTab).show();}
			return false;
		});
	});
</script>

A bit heavy-handed perhaps, but works great with no editing required ;)

Customizing the CSS

To get that fancy tabbed form menu looking all clean and rounded, much CSS is used. So instead of posting endless gobs of CSS, here is the code in plain text. As with any CSS, the best way to customize things is to open Firebug and start tweaking.

Just the links

One last trick: use this code to display links to the default WordPress login/registration page:

<ul>
	<?php wp_register(); ?>
	<li><?php wp_loginout(); ?></li>
	<?php wp_meta(); ?>
</ul>

Nothing to golf about, but I figured it was worth mentioning.

Wrap up

Using the code and techniques in this article, you can provide your readers with a login form anywhere on your site. This makes it easy for your users and visitors to login/logout, register for your site, and recover passwords without leaving their current page. The login code works great as-is or is easily transformed into a snazzily tabbed login menu using a sprinkle of CSS and a dash of jQuery.

Finally, one of the great things about WordPress is that there is always more than one way to set things up. So if you see a way to improve the code, please share with the community by leaving a comment. Thank you!

63 Responses

  1. Just what I was looking for thanks. Are you gong to have this in the new book update?

    • No plans to do so at this point, but we do have some new ideas/projects that may include this technique. Thanks for the idea ;)

  2. Great resource! Thanks for making it available.

    Does anyone know if this could/would work with WordPress MultiSite?

  3. Really nice writeup. This will be useful for some of my clients that run WordPress sites.

  4. The Tabs weren’t working for me.

    So I asked Denzel who suggested “changing $j to jQuery. There is nothing called $j.”

    The tabs work for me now.

    Thanks Denzel and digWP.

  5. Very cool! I wonder if it would be possible to allow users to use their Facebook account to login using WP-FB AutoConnect or another plugin?

  6. I copied the code into my single.php file. I see all the links but only the login works. The register does not work and so is the other. what else do I need to do? Please help me

    • Kennyboy7 December 18, 2010

      I’m suffering the same, tried the suggesation above of changing $j to $jQuery but still the same.

      This is a great idea and could really do with a fix cos I need to use this on site I have.

      Anyone got any ideas how to fix this prob ?

      • Kennyboy7 December 18, 2010

        Sorry my bad I should learn to read it’s not $jQuery to just need to remove $j and put jQuery instead.

        jQuery(document).ready(function() {
             jQuery(".tab_content_login").hide();
             jQuery("ul.tabs_login li:first").addClass("active_login").show();
             jQuery(".tab_content_login:first").show();
             jQuery("ul.tabs_login li").click(function() {
                  jQuery("ul.tabs_login li").removeClass("active_login");
                  jQuery(this).addClass("active_login");
                  jQuery(".tab_content_login").hide();
                  var activeTab = jQuery(this).find("a").attr("href");
                  if (jQuery.browser.msie) {jQuery(activeTab).show();}
                  else {jQuery(activeTab).show();}
                  return false;
             });
        });

        • thanks a lot … fixed it for me :)

        • Hi Kennyboy7!

          Thanks for the suggestion. It works for me after applying your Jquery codes. Prior, I used the n0-conflict code by Jeff but it didn’t work.
          Regards..

  7. Excellent and very useful I just wonder one thing though, is there some code we use to redirect the login to this page? for example if we put this in a a page template and set it up on /login can we stop users seeing the standard WordPress login screen and redirect it to the new one?

  8. hakanfolkesson December 17, 2010

    I don’t get this:

    if ($.browser.msie) {$(activeTab).show();}
    else {$(activeTab).show();}

    As far as understand it does the same in both cases…

    I also wonder about the practice of putting jQuery in the footer. Isn’t it better to have it in a separate file or in the header? That’s how I learnt it. I have seen some examples of Javascript or jQuery in the footer lately. Is that a new standard? I’d be very happy if someone could explain that.
    Thanks/Hakan

  9. The example code is vulnerable to XSS, because you echo out $_SERVER['REQUEST_URI'] directly without escaping, in several places

    See http://markjaquith.wordpress.com/2009/09/21/php-server-vars-not-safe-in-forms-or-links/

    For the same reason, I would probably also escape $user_identity.

    Another, minor, issue is that it might be preferable to code for E_STRICT. Like when you have

    $register = $_GET['register'];

    I would do

    if(isset($_GET['register'])) {
         $register = $_GET['register'];
    } else {
         $register = false;
    }

    But other then this, very nice method of user login/registration. And thanks for writing this.

    • Thanks Matthijs! I will update the code next available opportunity. Cheers :)

      • Hi Jeff,

        Thanks for this excellent write up – just what I needed!

        I’m curious if you’ve had the opportunity to update the code per Matthijs suggestions?

        I really want/need to use it but want to make sure all is as secure as possible for our use.

        I’m not a PHP guru (yet) so any help/advice you can offer is most welcome.

        Thanks in advance! – Alex

        PS – would it be useful/secure to use:

        php echo wp_login_url( get_permalink() );

        • Hi Jeff, Just thought I’d check once more on the XSS vulnerability mentioned by Matthijs and your offer to update the code.

          Thank you for your time! – Alex

  10. I think it would be easier to use if it will be a shortcode instead of a theme template.

    • I agree (without doing any research). Include as plugin that adds functionality using shortcodes. What are the drawbacks of this?

      re: “Customizing Things” – If want to customize then just customize the plugin code. This seems just as easy to me. Just have to watch that plugin updates don’t overwrite customizations. Heck maybe a well-designed plugin could allow input of custom code?

      (I’m writing a “reservation system” plugin that has custom login/password/register code that is added via shortcodes – wish I’d read this article a few months ago – great work!)

  11. thanks for sharing this useful post
    one question though: what’s the advantage of creating a custom page.
    if you have a multi-author blog then the guest authors and other authors will be shocked by seeing new a new page??

  12. What way do you suggest for error checking? unique username and email address check?

  13. this custom login page is great! the ordinary worpdress login is way to boring and somehow makes users feel uncomfortable with the registration process! i will be using this technique from now on! thanks for sharing!

  14. Perfect timing. I’m needing something like this for a project I’m thinking about.

  15. FutureHasNoBounds January 4, 2011

    Played with the custom login demo:

    http://digwp.com/custom-login-demo/

    Major Issue (needs fixing): when user enters details incorrectly the user get redirected to the original wordpress login form.

    • Yeah that’s because of another script we have in place here that overrides the demo script. The redirect is also customizable in the script.

      • FutureHasNoBounds January 5, 2011

        Are you able to provide a code snippet to prevent defaulting to original wordpress login form. This would be much appreciated.

  16. I have this working, but I can’t get it to display properly in Twenty Ten. This is probably a noob question, but what line in sidebar.php should I add the code? The widgets keep pushing up over it. Thanks for this btw

  17. @Scott
    Can you confirm if you’re using a child theme or just hacking twentyten? I have your answer.

    @Jeff Starr
    Hey this form thing is sublime. Nice follow-up discussion, too. So many issues.

    Guess what?

    Right now I’m putting the final polish on the ‘silver bullet’ for your form. I have it working as a template tag, a shortcode and a widget, all from the same plugin folder.

    Keep an eye on your inbox in about a week. ;)

  18. Wow thanks for the writeup, I would love to see another post that explains how to put the user profile section of wp-admin on the front end.

  19. Thanks Jeff
    can we make all users to use the custom instead of the wp-admin? like disabling access to the wp-admin. Or the best guard of preventing people to visit wp-admin is by htaccess password?

    hope somebody can help :)

  20. I am so lost I am in tears. I was trying to configure the dynamic content gallery now I can’t even get into the admin panel which has disappeared all together. I can’t post or edit. what is going on? Says I use WP version 3.4.0

  21. Wonderful article !

  22. Hi, My name is Sajib. I love this article but unfortunately, my jquary is not working. It’s saying syntax error in line 2. Could you please help me about this. This is the code that I add.

    In my header: <script type="text/javascript" src="/scripts/login.js">

    and here is the jquary code:

    jQuery(document).ready(function() {
    jQuery(".tab_content_login").hide();
    jQuery("ul.tabs_login li:first").addClass("active_login").show();
    jQuery(".tab_content_login:first").show();
    jQuery("ul.tabs_login li").click(function() {
    jQuery("ul.tabs_login li").removeClass("active_login");
    jQuery(this).addClass("active_login");
    jQuery(".tab_content_login").hide();
    var activeTab = jQuery(this).find("a").attr("href");
    if (jQuery.browser.msie) {jQuery(activeTab).show();}
    else {jQuery(activeTab).show();}
    return false;
    });
    });

    I would appreciate if you could take a look and let me know what I have to do?

    I have another question: My picture icon is showing outside of my wrapper. It’s not showing right side of blog reply. How do I control admin icon and change my own picture.

    Thanks
    Sajib

  23. Help with understanding tutorial that other noobs might find helpful.

    I see the following code in corresponding forms:

    Can original post explain, or someone in the know,
    A) what these code do? B) and if they point to other code, where can i locate them?

    Thanks heaps.

  24. sorry code must have got removed.

    do_action(‘login_form’)
    do_action(‘register_form’)

  25. Really good write up. thanks for sharing.

    Quick question – i’ve stripped this back to just the registration form and upon success everything is dandy. Upon failure (like username already in use) it redirects to the wp-login page with associated error. I can see where all that gets generated in core, but wonder how I can redirect this to the same page also, but with a different message. Is there a hook I can get hold of do you know? I basically want to keep the user on the form page all the time.

    Be great if you can shed any light – as I am sure this will be a golden tip if you do!!!

    Ryan

    • Searching the same for ages!!!! Some idea?

    • I am having the same problem. I’ve tried messing with all the redirect links in the script but haven’t been able to make it work.

    • i’m thinking only way is to create your own sign-on function based on the WP code of course.

      • Yeah, I ended up writing a custom function and submitting via ajax. I also created a custom set of validation checks (for existing user etc) and used jquery.validate on the signup form to create a dynamic form that didn’t subcumb to wp redirects etc. Can share code if anyone wants it.

        • Please share this. It sounds valuable to the rest of us!

        • Yes, please share – would be very helpful. Thanks!

        • Tried posting but it won’t commit – maybe comment is too long. I’ll post to my blog as soon as I can

        • Hi Ryan, where can we find your blog? Would love to know how you’ve got around this!

        • Also very interested in your solution. How do I find you blog?

    • Thanks so much. My only issue is the get it wrong redirect issue. Wondering Ryan you have a link to the solution you used?

  26. Thanks for this…working great on my site.

    A couple questions though:

    My tabs are different sizes so I need to be able to close them without clicking on another tab and have the tabs default back to tab 1.

    1) How can I add even a simple text link that will close the tab(s) and return them to tab 1 (default)?

    2) How do you make the tabs close by clicking outside of them and again returning to default state (tab 1)?

    I would like to implement both of these solutions. Any help would be appreciated.

    Thanks.

  27. I haven’t tried this yet, but when I do, an it works as expected then, it will be exactly what I’ve been looking for. Would definitely rather work with code than plug-ins, at least I then know exactly what is what, an is so much more customizable.

    Anyway thank you for the great post, an I’ll let you know how I get on.

  28. Great help! Thanks a lot but I have one small problem, when I login it redirects me to login.php instead of my front page. I have a static front page which I’m guessing is the problem, which setting do I change to get the redirect correct?

    • Use a login redirect plugin – easiest way to do it! There’s loads on the WP plugin site.

      • Didn’t work. Works great for the regular login page of WordPress, but when I try and login through the code above it still just sends me to a “Page Not Found” page.

  29. In the course of developing my own implementation of Jeff’s form, I discovered a subtle vulnerability in WP’s password reset process.

    ‘Username or E-mail?’

    Subscribers (of all capabilities) are not required to choose a display name that’s different from their user login name. So ‘anonymous troll’ plucks a username from your comments section and feeds it into the password reset form. Rinse, repeat, ad nauseam.

    Putting the server load issue to one side, this behaviour has mostly nuisance value. But there’s no denying the trolls are out there, and it’s a poor experience for your subscribers to get wads of emails in a day offering to reset their password when they didn’t request such a thing in the first place. Remember that, by default, no notification is sent to the blog admin when a password reset request is handled.

    With pre-emptive validation in place at the server we can make sure our form doesn’t expose this vulnerability, but it’s not bullet-proof because the problem exists in the WP back end (think: ‘/wp-admin/’).

    And should the punter’s problem escalate to ‘I forgot my registered email address too’, the question becomes ‘Do you really want such a maladroit signed up to your site in the first place?’

    Taking away the username option from the password reset dialogue isn’t a big deal if your blog has a contact form that your addled subscriber can use to explain the mess they’re in.

    You can see my implementation of Jeff’s Login/Register/LostPassword form running as a sidebar widget on my site; the link is in my name, above.

  30. Marcelo June 18, 2012

    Hi, i’m a total newbie user of WordPress, and i need some help, i need the original wordpress login with those changes, not inside a new page.

    Possible? What i have to do? Any chance to get this done? I can contract this from you?

    Regards…

  31. Stunning!!!!!
    Thanks a loto for sharing!
    You’re great!

Comments are closed. Contact us with any critical information. Thank you!

Code is poetry