I’ve build quite a few custom login-forms in WordPress. There are, as always, a lot of ways to realize that, but nearly all the clients I worked with, had similar requirements: On the one hand they wanted to preserve the usual WordPress login-form to let administrators, editors and authors sign in into wp-admin. On the other hand they wanted another usergroup to sign in into their site via a fully customized WordPress login-screen, to download protected documents or whatever.
Customized WordPress login-form
Generally the problem is solved fairly easy, using the WordPress-API. You can print out a standard login-form by using wp_login_form wherever in your theme you want it. There is even a way to specify the page, the user should be redirected to after a successful login. Here an example, redirecting you to the home page:
<?php
wp_login_form( array(
'redirect' => get_bloginfo('url'),
'form_id' => 'sign-in',
'label_log_in' => __( 'Sign in' ),
) );
?>
If you need to adjust the HTML-output, you can build your own sign in form markup by saving a file named searchform.php in your theme folder. Than you are just a few stylesheet-rules away from your customized form, with working login.
Handling login-fails
The problems begin when you fail to login, because writing in a wrong username and/or password doesn’t redirect you to your customized form, it redirects you to the wp-admin site. Since the signing-in user is not supposed to login to wp-admin, this redirect doesn’t make any sense. But again we find a straight forward solution in the WordPress-API. Add these lines to your functions.php:
function custom_login_failed( $username ) {
$referrer = $_SERVER['HTTP_REFERER'];
if ( !empty($referrer) && !strstr($referrer,'wp-login') && !strstr($referrer,'wp-admin') ) {
// redirect to your login page, you might want to add a parameter login_failed
// to show an error message or something like that
wp_redirect( ... );
exit;
}
}
add_action( 'wp_login_failed', 'custom_login_failed' );
You might think that’s all, but not so fast …
Handling empty logins
There is yet another way to get redirected to the wp-admin login form, and that is when you just don’t enter anything. Submit the form with an empty username and password field and you are on wp-admin again. That is because the wp_authenticate function, which handles redirection ignores empty_username and empty_password as error codes and that is why our wp_login_failed action never fires. The solution is to change these error codes, if the user logs in from another site than wp-admin or wp-login.php. This is done by the following filter function (note the filter priority, which is important here).
function custom_authenticate( $user, $username, $password ) {
if ( is_wp_error( $user ) && isset( $_SERVER[ 'HTTP_REFERER' ] ) && !strpos( $_SERVER[ 'HTTP_REFERER' ], 'wp-admin' ) && !strpos( $_SERVER[ 'HTTP_REFERER' ], 'wp-login.php' ) ) {
$referrer = $_SERVER[ 'HTTP_REFERER' ];
foreach ( $user->errors as $key => $error ) {
if ( in_array( $key, array( 'empty_password', 'empty_username') ) ) {
unset( $user->errors[ $key ] );
$user->errors[ 'custom_'.$key ] = $error;
}
}
}
return $user;
}
add_filter('authenticate','custom_authenticate', 31, 3);
Other ways?
I know of one alternative to the above code: Since wp_authenticate is a plugable function, you could simply overwrite it. But this you only can do with a plugin, so you have to add a plugin to your site and activate it, which I think is a bit more hassle.
Is there another way you know of? Please let me know in the comments.