WordPressのログイン画面のエラーメッセージを変更する

WordPressのwp-login.phpが吐き出すログインエラーメッセージは、親切心からなのか、「ユーザー名が違う」「パスワードが違う」という感じで、何が違うのか指摘してくれます。普通のブログなら別にいいのかもしれないけど、会員登録させるようなサイトの場合、そのユーザー名やメールアドレスがそのサイトに登録されてるっていう情報を与えてしまうことになり、それってセキュリティ的に良くないよね、最近の風潮に反してるよね、と感じたので、エラーメッセージを変更してみました。

WordPress 5.3で動作確認済み

#ログイン画面のエラーメッセージを変更
色々検索してみたけど、皆そんなことしようと思わないのか、情報があまりない。preg_matchでマッチングした場合にメッセージを置き換える、とかはちょっとしっくり来ない。
何かフィルタはないものかと思ってwp-login.phpを眺めていたところ、[wp_login_errors](https://developer.wordpress.org/reference/hooks/wp_login_errors/)というフィルタを発見。何だか使えそう。

というわけで、wp-login.phpの中身を参考に、こんな感じで書いてみた。

```php:functions.php
function custom_login_errors( $errors, $redirect_to ) {
    // メールアドレスが不正
    if( isset( $errors->errors[ 'invalid_email' ] ) ){
        $errors->remove( 'invalid_email' );
        $errors->add( 'invalid_email', 'ユーザー名 / メールアドレス、またはパスワードが違います。' );
   }

    // ユーザー名が不正
    if( isset( $errors->errors[ 'invalid_username' ] ) ){
        $errors->remove( 'invalid_username' );
        $errors->add( 'invalid_username', 'ユーザー名 / メールアドレス、またはパスワードが違います。' );
    }

    // パスワードが不正
    if( isset( $errors->errors[ 'incorrect_password' ] ) ){
        $errors->remove( 'incorrect_password' );
        $errors->add( 'incorrect_password', 'ユーザー名 / メールアドレス、またはパスワードが違います。' );
    }

    // ユーザー名が空
    if( isset( $errors->errors[ 'empty_username' ] ) ){
        $errors->remove( 'empty_username' );
        $errors->add( 'empty_username', 'ユーザー名、またはメールアドレスを入力してください。' );
    }

    // パスワードが空
    if( isset( $errors->errors[ 'empty_password' ] ) ){
        $errors->remove( 'empty_password' );
        $errors->add( 'empty_password', 'パスワードを入力してください。' );
    }

    // パスワード再設定用メール送信
    if( isset( $errors->errors[ 'confirm' ] ) ){
        $errors->remove( 'confirm' );
        $errors->add( 'confirm', 'パスワード再設定用のリンクをメールで送信しました。', 'message' );
    }

    return $errors;
}
add_filter( 'wp_login_errors', 'custom_login_errors', 10, 2 );
```

$errorsは[WP_Errorオブジェクト](https://codex.wordpress.org/Class_Reference/WP_Error)。
メッセージ部分を直接書き換えるメソッドは無さそうなので、一旦removeでそのエラーコードを持つエラーを削除してから、addメソッドで同じエラーコードのエラーを追加。

「メールアドレスが存在しない」「ユーザー名が存在しない」「パスワードが違う」場合に全て同じメッセージを返すことで、そのユーザー名のユーザーが存在しているかが第三者からは判別できないようになる。

```php
$errors->add( 'invalid_email', 'ユーザー名 / メールアドレス、またはパスワードが違います。' );
$errors->add( 'invalid_username', 'ユーザー名 / メールアドレス、またはパスワードが違います。'  );
$errors->add( 'incorrect_password', 'ユーザー名 / メールアドレス、またはパスワードが違います。' );
```

第3引数は追加データで、例えば、パスワード再設定用のリンクをメールで送信したときはエラーメッセージではないので、フロントで表示する段階でエラー表示とは違うHTMLが出力されてたりするわけなんだけど、それは第3引数をmessageとすると設定できる。

```php
$errors->add( 'confirm','パスワード再設定用のリンクをメールで送信しました。', 'message' );
```

#パスワード再設定フォームの処理を変更
wp-login.php?action=lostpasswordのパスワード再設定フォームもログインフォームと同じようにしたいんだけど、メッセージを変更しただけだとフォームを送信したときに

<b>ユーザー名 / メールアドレスが正しい場合→ログインフォームにリダイレクト</b>
<b>ユーザー名 / メールアドレスが間違っている場合→パスワード再設定フォームが再度表示される</b>

という処理になっているので、ユーザー名とメールアドレスが違う場合にも、ログインフォームにリダイレクトするようにするようにしたい。

wp-login.phpの中身を見てみると、どうやら[lost_password](https://developer.wordpress.org/reference/hooks/lost_password/)というアクションフックが使えそう。
ということでこんな風に書いてみた。

```php:functions.php
function custom_lost_password( $errors ) {
     // ユーザー名が空
    if( isset( $errors->errors[ 'empty_username' ] ) ){
        $errors->remove( 'empty_username' );
        $errors->add( 'empty_username', 'ユーザー名、またはメールアドレスを入力してください。' );
    }

    // メールアドレスやユーザーが見つからない
    if( isset( $errors->errors[ 'invalid_email' ] ) || isset( $errors->errors[ 'invalidcombo' ] ) ){
        wp_safe_redirect( 'wp-login.php?checkemail=confirm' );
        exit();
    }

    return $errors;
}
add_action( 'lost_password', 'custom_lost_password' );
```

$errorsはログインフォームと同じくWP_Errorオブジェクトなので、ユーザー名が空の場合は同じようにエラーメッセージを入れてあげればOK。

ユーザ名やメールアドレスが違う場合に飛ばす処理については、そもそも正しい場合はどんな風に飛ばしているのか確認してみると、wp_safe_redirectで飛ばしていた。

```php:wp-login.php（562行目付近）
$redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
wp_safe_redirect( $redirect_to );
exit();
```

なので、同じように飛ばす処理を書いてあげればOK。メッセージもエラーのない場合と同じものが出る。

```php
if( isset( $errors->errors[ 'invalid_email' ] ) || isset( $errors->errors[ 'invalidcombo' ] ) ){
    wp_safe_redirect( 'wp-login.php?checkemail=confirm' );
    exit();
}
```