ログイン中ならログイン画面を飛ばす:login_init で管理画面へ転送する

管理画面
広告WordPress・PHP を学べる本

Amazonのアソシエイトとして、WordPress functions.phpは適格販売により収入を得ています。

ログインしているのに、フォームがもう一度出る

ブックマークしておいたログインの URL を開くと、すでにログインしているのに、WordPress はログインのフォームをもう一度出します。そのたびにユーザー名とパスワードを入力し直していました。タブをたくさん開いていると、どのサイトにログイン済みなのかも分かりにくくなります。

ログインしているなら、フォームを出さずに管理画面へ進んでくれれば手間が減ります。そこで、ログイン中にログインの画面を開いたときだけ、管理画面へ転送する小さなファイルを作り、テーマの functions.php から読み込むようにしました。

転送する場面と、しない場面

ログインの画面(wp-login.php)は、ログインのほかにも、ログアウトやパスワードの再設定などで使われます。ログイン中ならいつでも転送する作りにすると、ログアウトのリンクまで管理画面に戻されてしまうので、転送する場面をしぼりました。

場面 動き
ログイン中に、ログインの画面を開いた(GET) 管理画面へ転送する
ログインしていない 今までどおりフォームを出す
フォームを送ったとき(POST) 今までどおり
ログアウト(action=logout) 今までどおり
パスワードを忘れた(action=lostpassword) 今までどおり
再ログインを求められたとき(reauth) 今までどおり
編集画面でセッションが切れたときの小さなログイン窓(interim-login) 今までどおり

interim-login は、記事の編集中にログインの有効期限が切れたとき、画面の上に出る小さなログイン窓のことです。ここで転送してしまうと、窓の中に管理画面が出てしまい、編集の途中の画面に戻れなくなるので、何もしないようにしています。

作ったファイル

ファイルはテーマのフォルダの中の functions フォルダに置き、functions.php の初めのほうで require_once で読み込んでいます。

/wp-content/themes/(テーマのフォルダ)/functions/login-logged-in-redirect.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

function my_login_redirect_if_logged_in() {
    if ( ! is_user_logged_in() ) {
        return;
    }
    if ( 'GET' !== ( isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( (string) $_SERVER['REQUEST_METHOD'] ) : 'GET' ) ) {
        return;
    }
    $action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : 'login';
    if ( 'login' !== $action ) {
        return;
    }
    if ( ! empty( $_REQUEST['reauth'] ) || ! empty( $_REQUEST['interim-login'] ) ) {
        return;
    }
    $to = admin_url();
    if ( ! empty( $_REQUEST['redirect_to'] ) ) {
        $to = wp_validate_redirect( esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ), admin_url() );
    }
    wp_safe_redirect( $to );
    exit;
}
add_action( 'login_init', 'my_login_redirect_if_logged_in', 1 );
書き方 役目
add_action( 'login_init', …, 1 ) ログインの画面の処理の初めに動かす。優先度を 1 にして、ほかの処理より先に見る
is_user_logged_in() ログインしていない人には何もしない
'GET' !== … 画面を開いただけのときに限る。フォームの送信(POST)は今までどおり WordPress に任せる
$action が login のときだけ ログアウトやパスワードの再設定など、ほかの action のときは転送しない。action がないときは login として扱う
reauth・interim-login 再ログインを求められたときと、編集画面の小さなログイン窓では何もしない
wp_validate_redirect( …, admin_url() ) redirect_to が同じサイトの URL のときだけそこへ。外のサイトの URL なら管理画面にする
wp_safe_redirect() と exit 転送したら、そのあとの処理(フォームの表示)を動かさない

functions.php からは、次の 1 行で読み込んでいます。

/wp-content/themes/(テーマのフォルダ)/functions.php(読み込む行)
require_once dirname( __FILE__ ) . '/functions/login-logged-in-redirect.php';

redirect_to をそのまま使わない

管理画面の中のページを開こうとしてログインの画面に回されたときは、URL に redirect_to が付いていて、ログインのあとにそのページへ戻れるようになっています。ログイン中ならそのページへ直接移すのが自然なのですが、redirect_to は URL に書かれた値なので、だれでも好きな値を入力できます。

そのまま転送に使うと、外のサイトへ飛ばすリンクを作られるおそれがあるため、wp_validate_redirect() で同じサイトの URL かを確認し、だめなときは管理画面のトップにしています。転送は wp_redirect() ではなく wp_safe_redirect() を使い、ここでも許可されたホストの URL だけに限っています。

ログインの URL を変えていても同じように効く

SiteGuard などのプラグインでログインの URL を変えている場合も、変えた URL の中では wp-login.php が動いています。login_init は wp-login.php の処理の中で呼ばれるので、変えた URL から開いたときにも、同じように転送されます。ログインしていない人には何も変えないので、変えたログインの URL や、プラグインで付けたログインの画面の設定はそのままです。

確認した結果

多くのサイトにこのファイルを設置して、ブラウザで次のことを確認しました。

確認したこと 結果
ログイン中に、ログインの URL を開く 管理画面へ移った
ログアウトした状態で、ログインの URL を開く フォームが出た
管理画面のログアウトのリンクを押す 今までどおりログアウトできた

あわせて、作業環境の WordPress を読み込む検証用スクリプトから、この関数を場面ごとに呼んで、転送するかどうかを一覧にしました。転送は wp_redirect のフィルターで止め、行き先だけを出しています。

場面 結果
ログインしていない・GET フォームのまま
ログイン中・GET /wp-admin/ へ
ログイン中・POST フォームのまま
ログイン中・action=logout そのまま(ログアウトの処理へ)
ログイン中・action=lostpassword そのまま
ログイン中・reauth=1 フォームのまま
ログイン中・interim-login=1 フォームのまま
ログイン中・redirect_to が同じサイトの編集画面 /wp-admin/edit.php へ
ログイン中・redirect_to が外のサイト /wp-admin/ へ(外へは飛ばない)

気をつけること

  • テーマに追加しているので、テーマを切り替えると効かなくなります。どのテーマでも使いたいときは、同じ中身をプラグインにする方法もあります(今回は試していません)
  • ページのキャッシュを使っているサイトでは、ログインの画面がキャッシュされていないかを先に確認しておきます。ログイン中かどうかで動きが変わる画面なので、キャッシュされると正しく動きません
  • 転送する場面を増やすときは、ログアウトや再ログインの画面が今までどおり出るかを、あわせて確認します

まとめ

設置したサイトでは、ブックマークしているログインの URL を、ログイン中のタブとログアウトしたタブの両方で 1 回ずつ開きます。ログインの URL を変えているサイトは、変えた URL でも同じように開いて確認します。

参考