Verificar nombre de usuario correcto en formulario de inicio de sesión personalizado
He utilizado el tutorial de Jeff Star para crear mi propio formulario de inicio de sesión personalizado http://digwp.com/2010/12/login-register-password-code/. Funciona muy bien, pero tengo un problema. En el formulario de restablecimiento de contraseña, si alguien ingresa su nombre de usuario incorrectamente (de modo que no se verifica), son redirigidos a la página predeterminada wp-login.php?action=lostpassword con el mensaje de error.
¿Hay alguna manera de redirigir a mi propia página de error?
¡Gracias!

El código que publicó en ese tutorial (muy bueno por cierto) envía el formulario al módulo integrado de "restablecer contraseña" que redirige a login.php en caso de error, pero puedes modificarlo y crear tu propia versión basada en el original y agregarla a la página de plantilla, cambia:
<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('Nombre de usuario o 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('Restablecer mi contraseña'); ?>" class="user-submit" tabindex="1002" />
<?php $reset = $_GET['reset']; if($reset == true) { echo '<p>Se enviará un mensaje a tu dirección de correo electrónico.</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>
por:
<form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>" class="wp-user-form">
<div class="username">
<label for="user_login" class="hide"><?php _e('Nombre de usuario o 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('Restablecer mi contraseña'); ?>" class="user-submit" tabindex="1002" />
<?php
if (isset($_POST['reset_pass']))
{
global $wpdb;
$username = trim($_POST['user_login']);
$user_exists = false;
if (username_exists($username))
{
$user_exists = true;
$user_data = get_userdatabylogin($username);
} elseif (email_exists($username))
{
$user_exists = true;
$user = get_user_by_email($username);
} else
{
$error[] = '<p>' . __('¡Nombre de usuario o Email no encontrado, inténtalo de nuevo!') . '</p>';
}
if ($user_exists)
{
$user_login = $user->user_login;
$user_email = $user->user_email;
// Generar algo aleatorio para la contraseña... md5 del tiempo actual con una sal aleatoria
$key = substr(md5(uniqid(microtime())), 0, 8);
// Insertar el nuevo pass md5 en la base de datos
$wpdb->query("UPDATE $wpdb->users SET user_activation_key = '$key' WHERE user_login = '$user_login'");
//crear mensaje de email
$message = __('Alguien ha solicitado restablecer la contraseña para el siguiente sitio y nombre de usuario.') . "\r\n\r\n";
$message .= get_option('siteurl') . "\r\n\r\n";
$message .= sprintf(__('Nombre de usuario: %s'), $user_login) . "\r\n\r\n";
$message .= __('Para restablecer tu contraseña visita la siguiente dirección, de lo contrario ignora este email y no pasará nada.') . "\r\n\r\n";
$message .= get_option('siteurl') . "/wp-login.php?action=rp&key=$key\r\n";
//enviar mensaje de email
if (FALSE == wp_mail($user_email, sprintf(__('[%s] Restablecimiento de contraseña'), get_option('blogname')), $message))
$error[] = '<p>' . __('El correo electrónico no pudo ser enviado.') . "<br />\n" . __('Posible razón: tu servidor puede tener deshabilitada la función mail()...') . '</p>';
}
if (count($error) > 0)
{
foreach ($error as $e)
{
echo $e . '<br/>';
}
} else
{
echo '<p>' . __('Se enviará un mensaje a tu dirección de correo electrónico.') . '</p>';
}
}
?>
<input type="hidden" name="reset_pass" value="1" />
<input type="hidden" name="user-cookie" value="1" />
</div>
</form>

Ok, he logrado que esto funcione muy bien, con solo algunos cambios. Había un par de errores de sintaxis y el generador de clave md5 no funcionaba, así que tomé el de wp-login.php. Solo tengo un problema ahora. Cuando alguien hace clic en el enlace del correo para crear una nueva contraseña, son redirigidos al formulario por defecto, así que ahora necesito crear un formulario para eso también.

@pippin: el código del generador de clave md5 aquí es el de wp-login.php, y en cuanto a la redirección intenta agregar &redirect_to=$_SERVER['REQUEST_URI']
al enlace en el correo que envías.

Mi enlace ahora se ve así $message .= get_option('siteurl') . "/wp-login.php?action=rp&key=$key&login=$user_login&redirect_to=$_SERVER['REQUEST_URI']\r\n";
, pero lo extraño es que cuando agrego el &redirect, el mensaje no se envía... Además, ¿no necesitaré crear un nuevo formulario para que el usuario ingrese su nueva contraseña y demás?

Sí, lo olvidé, necesitarías crear tu propio formulario para restablecer la contraseña y probablemente reemplazar el enlace que se envía al usuario por la URL actual, y basándote en la clave verificar si es el usuario y mostrarle el formulario.

línea 17 get_user_by('login', $user_login);
ya que get_userdatabylogin
ha quedado obsoleto...

Me doy cuenta de que esta respuesta es bastante antigua, no estoy muy seguro de su fiabilidad. Supongo que debería funcionar, pero preferiría no meter mano al SQL ya que podría cambiar en el futuro. Por otro lado, no encuentro detalles sobre alternativas.

Aquí está una versión actualizada del código de @bainternet con los errores de sintaxis corregidos, la sugerencia de @Val y el generador de claves de wp-login.php 3.4.2:
global $wpdb;
$username = trim($_POST['user_login']);
$user_exists = false;
// Primero verificar por nombre de usuario
if ( username_exists( $username ) ){
$user_exists = true;
$user = get_user_by('login', $username);
}
// Luego, por dirección de correo electrónico
elseif( email_exists($username) ){
$user_exists = true;
$user = get_user_by_email($username);
}else{
$error[] = '<p>'.__('Nombre de usuario o correo electrónico no encontrado, ¡inténtalo de nuevo!').'</p>';
}
if ($user_exists){
$user_login = $user->user_login;
$user_email = $user->user_email;
$key = $wpdb->get_var($wpdb->prepare("SELECT user_activation_key FROM $wpdb->users WHERE user_login = %s", $user_login));
if ( empty($key) ) {
// Generar algo aleatorio para la clave...
$key = wp_generate_password(20, false);
do_action('retrieve_password_key', $user_login, $key);
// Ahora insertar la nueva clave md5 en la base de datos
$wpdb->update($wpdb->users, array('user_activation_key' => $key), array('user_login' => $user_login));
}
//crear mensaje de correo electrónico
$message = __('Alguien ha solicitado restablecer la contraseña para el siguiente sitio y nombre de usuario.') . "\r\n\r\n";
$message .= get_option('siteurl') . "\r\n\r\n";
$message .= sprintf(__('Nombre de usuario: %s'), $user_login) . "\r\n\r\n";
$message .= __('Para restablecer tu contraseña visita la siguiente dirección, de lo contrario ignora este correo y no sucederá nada.') . "\r\n\r\n";
$message .= network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . "&redirect_to=".urlencode(get_option('siteurl'))."\r\n";
//enviar mensaje de correo electrónico
if (FALSE == wp_mail($user_email, sprintf(__('[%s] Restablecimiento de contraseña'), get_option('blogname')), $message))
$error[] = '<p>' . __('El correo electrónico no pudo ser enviado.') . "<br />\n" . __('Posible razón: tu servidor puede tener deshabilitada la función mail()...') . '</p>';
}
if (count($error) > 0 ){
foreach($error as $e){
echo $e . "<br/>";
}
}else{
echo '<p>'.__('Se enviará un mensaje a tu dirección de correo electrónico.').'</p>';
}

Todavía estaba teniendo problemas con que la clave de restablecimiento no funcionaba correctamente, el enlace en el correo electrónico me redirigía a la página estándar de restablecimiento de contraseña con el parámetro URL indicando un problema con la clave, así que seguí más de cerca el archivo wp-login.php e incluí el objeto $wp_hasher, esto solucionó el problema y ahora el restablecimiento de contraseña en el correo electrónico funciona
if (($_SERVER['REQUEST_METHOD'] === (string) 'POST') && (isset($_POST['reset_pass']))) {
// Acceder a propiedades globales
global $wpdb, $wp_hasher;
// Variables
$error_pass_reset = array();
$username = (string) trim($_POST['user_login']);
$user_exists = (bool) false;
// ---- USUARIO O EMAIL EXISTE ---- //
if (username_exists($username)) {
$user_exists = (bool) true;
$user = (object) get_user_by('login', $username);
} // end if
else if (email_exists($username)) {
$user_exists = (bool) true;
$user = (object) get_user_by('email', $username);
} // end else if
else {
$error_pass_reset[] = '<p>No se encontró el nombre de usuario o correo electrónico, por favor intente nuevamente.</p>';
} // end else
// ---- EL USUARIO EXISTE ---- //
if ($user_exists === (bool) true) {
// Variables
$user_login = (string) $user -> user_login;
$user_email = (string) $user -> user_email;
// Generar clave de restablecimiento de contraseña
if (empty($key)) {
$key = (string) wp_generate_password(20, false);
do_action('retrieve_password_key', $user_login, $key);
// Crear el objeto $wp_hasher
if (empty($wp_hasher)) {
require_once(ABSPATH . WPINC . '/class-phpass.php');
$wp_hasher = new PasswordHash(8, true);
}
// Restablecer clave con hasher aplicado (MD5 tiene salida de cadena)
$hashed = (string) time() . ':' . $wp_hasher -> HashPassword($key);
// Insertar la nueva clave en la base de datos
$wpdb -> update(
$wpdb -> users,
array(
'user_activation_key' => $hashed
),
array(
'user_login' => $user_login
)
);
} // end if
// Mensaje de correo electrónico
$message = (string)
'Alguien solicitó que se restablezca la contraseña para la siguiente cuenta:' . "\r\n\r\n" .
get_option('siteurl') . "\r\n\r\n" .
'Nombre de usuario: ' . $user_login . "\r\n\r\n" .
'Si esto fue un error, simplemente ignore este correo electrónico y no pasará nada.' . "\r\n\r\n" .
'Para restablecer su contraseña, visite la siguiente dirección:' . "\r\n\r\n" .
get_option('siteurl') . '/wp-login.php?action=rp&key=' . $key . '&login=' . $user_login . "\r\n";
// Enviar correo electrónico
if ((bool) false === wp_mail($user_email, get_option('blogname') . ' Restablecimiento de Contraseña', $message)) {
$error_pass_reset[] = '<p>El correo electrónico no pudo ser enviado en este momento.</p>' . "\n";
} // end if
} // end if
// Enviar el correo electrónico de restablecimiento de contraseña
do_action('login_form', 'resetpass');
} // end if (($_SERVER['REQUEST_METHOD'] === (string) 'POST') && (isset($_POST['reset_pass'])))
