Skip to content

Instantly share code, notes, and snippets.

@jshakes
Created October 30, 2012 16:42
Show Gist options
  • Save jshakes/3981416 to your computer and use it in GitHub Desktop.
Save jshakes/3981416 to your computer and use it in GitHub Desktop.
One-page WP password reset page (for themes with front-facing bespoke log-in)
<?php
/*
Lets you display a forgot/reset password page within your theme.
Eg, create a page called 'Forgot Password'; save this file as page-forgot-password.php
Adapted from code posted here: http://wordpress.stackexchange.com/questions/14692/check-for-correct-username-on-custom-login-form/14696#14696
*/
//First pull a bunch of functions from the native WP password reset file
/**
* Retrieves a user row based on password reset key and login
*
* @uses $wpdb WordPress Database object
*
* @param string $key Hash to validate sending user's password
* @param string $login The user login
* @return object|WP_Error User's database row on success, error object for invalid keys
*/
function check_password_reset_key($key, $login) {
global $wpdb;
$key = preg_replace('/[^a-z0-9]/i', '', $key);
if ( empty( $key ) || !is_string( $key ) )
return new WP_Error('invalid_key', __('Invalid key'));
if ( empty($login) || !is_string($login) )
return new WP_Error('invalid_key', __('Invalid key'));
$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s AND user_login = %s", $key, $login));
if ( empty( $user ) )
return new WP_Error('invalid_key', __('Invalid key'));
return $user;
}
/**
* Handles resetting the user's password.
*
* @param object $user The user
* @param string $new_pass New password for the user in plaintext
*/
function reset_password($user, $new_pass) {
do_action('password_reset', $user, $new_pass);
wp_set_password($new_pass, $user->ID);
wp_password_change_notification($user);
}
/*
Forgot password page. This page allows users to enter their username/email address to reset the password.
The reset password email redirects here, allowing the user to specify a new password.
It will also process the reset password form.
*/
$error = array();
if (isset($_POST['reset_pass'])){
global $wpdb;
$username = trim($_POST['user_login']);
$user_exists = false;
if ( username_exists( $username ) ){
$user_exists = true;
$user = get_user_by('login', $username);
}elseif ( email_exists($username) ){
$user_exists = true;
$user = get_user_by('email', $username);
}else{
$error[] = "Username or Email was not found";
}
if ($user_exists){
$user_login = $user->user_login;
$user_email = $user->user_email;
// Generate something ran for a password... md5'ing current time with a rand salt
$key = substr( md5( uniqid( microtime() ) ), 0, 8);
// Now insert the new pass md5'd into the db
$wpdb->query("UPDATE $wpdb->users SET user_activation_key = '$key' WHERE user_login = '$user_login'");
//create email message
$message = __('Someone has asked to reset the password for the following site and username.') . "\r\n\r\n";
$message .= get_option('siteurl') . "\r\n\r\n";
$message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
$message .= __('To reset your password visit the following address, otherwise just ignore this email and nothing will happen.') . "\r\n\r\n";
$message .= $_SERVER['REQUEST_URI']."?action=rp&key=$key&login=$user_login\r\n";
//send email meassage
if (FALSE == wp_mail($user_email, sprintf(__('[%s] Password Reset'), get_option('blogname')), $message)){
$error[] = '<p>' . __('The e-mail could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail() function...') . '</p>';
}
}
}
if(isset($_GET['key'], $_GET['login'])){
$user = check_password_reset_key($_GET['key'], $_GET['login']);
if(empty($user)){
$error[] = "Sorry, that appears to be an invalid or expired key. Please <a href=\"/forgot-password/\">re-request the password reset email</a> and follow the link therein.";
}
else{
if ( isset($_POST['pass1']) && $_POST['pass1'] != $_POST['pass2'] ) {
$error[] = "The passwords do not match";
} elseif ( isset($_POST['pass1']) && !empty($_POST['pass1']) ) {
reset_password($user, $_POST['pass1']);
$success = 1;
}
}
}
/* ---------------------- PAGE OUTPUT ---------------------- */
get_header();
/* The password was reset successfully */
if($success):
//Password reset message, eg. 'Thanks, your password has been reset. Click here to log in
/* The form was submitted successfully */
elseif(isset($_POST['reset_pass']) && empty($error)):
//Email sent message, eg. 'Thanks, a message will be sent to your email address with instructions to reset your password.'
/* User has returned from the email bearing a user key */
elseif(isset($_GET['key'], $_GET['login'])):
$key = $_GET['key'];
$login = $_GET['login'];
if(!empty($error)): //output errors if there are any ?>
<div class="warning">
<p>The following errors occurred:</p>
<ul>
<?php foreach($error as $e): ?>
<li><?php echo $e; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<!-- Password reset form -->
<form class="signup" name="loginform" id="loginform" method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>?action=resetpass&#038;key=<?php echo $key; ?>&#038;login=<?php echo $login; ?>">
<input type="hidden" id="user_login" value="<?php echo $login; ?>" autocomplete="off">
<fieldset>
<label for="pass1"><?php _e('New Password'); ?></label>
<input type="password" name="pass1" id="pass1" class="input" size="20" value="" autocomplete="off">
</fieldset>
<fieldset>
<label for="pass2"><?php _e('Confirm new Password'); ?></label>
<input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off">
</fieldset>
<fieldset class="last">
<input type="submit" name="user-submit" value="<?php _e('Reset my password'); ?>" class="user-submit" tabindex="1002" />
</fieldset>
</form>
<?php
/* Default state/show errors */
else:
if(!empty($error)): ?>
<div class="warning">
<p>The following errors occurred:</p>
<ul>
<?php foreach($error as $e): ?>
<li><?php echo $e; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<!-- Password reset form -->
<form class="signup" name="loginform" id="loginform" method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
<fieldset>
<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" />
</fieldset>
<fieldset class="last">
<?php do_action('login_form', 'resetpass'); ?>
<input type="hidden" name="reset_pass" value="1" />
<input type="submit" name="user-submit" value="<?php _e('Send password reset email'); ?>" class="user-submit" tabindex="1002" />
</fieldset>
</form>
<?php endif;
get_footer(); ?>
@JohannaHiQ
Copy link

Note: check_password_reset_key returns an error if the key and/or username does not match. It will never be empty! You need to test with is_wp_error instead of empty to make sure the check was successful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment