管理画面におけるエラーメッセージの表示

以下今書いているある本の下書きなんですけど、つっこみどころがあればぜひ。

WordPressには、admin_noticesというフックが用意されており、このフックを使用するとエラーメッセージなどを管理画面で表示することができます。

https://codex.wordpress.org/Plugin_API/Action_Reference/admin_notices

それほど難しいものではないので、この章でこれまでに作ってきたプラグインで入力チェックを行い、エラーメッセージを出力してみましょう。

<?php
/*
Plugin Name: My Admin
*/

add_action( 'admin_menu', 'my_admin_menu' );

function my_admin_menu() {

    add_options_page(
        __('My Submenu', 'my-custom-admin'),
        __('My Submenu', 'my-custom-admin'),
        'manage_options',
        'my-submenu',
        'my_submenu'
    );
}

function my_submenu() {
?>
<div class="wrap">
<h2>My Submenu</h2>

<form id="my-submenu-form" method="post">
    <?php wp_nonce_field( 'my-nonce-key', 'my-submenu' ); ?>

    <p><?php _e( 'E-mail Address', 'my-custom-admin' ); ?>:
        <input type="text" name="my-data"
            value="<?php echo esc_attr( get_option( 'my-data' ) ); ?>"></p>
    <p><input type="submit"
            value="<?php esc_attr( _e( 'Save', 'my-custom-admin' ) ); ?>"
            class="button button-primary button-large"></p>
</form>

</div>
<?php
}

add_action( 'admin_init', 'my_admin_init' );

function my_admin_init()
{
    if ( isset( $_POST['my-submenu'] ) && $_POST['my-submenu'] ){
        if ( check_admin_referer( 'my-nonce-key', 'my-submenu' ) ){

            if ( isset($_POST['my-data']) && $_POST['my-data'] ) {
                update_option( 'my-data', trim( $_POST['my-data'] ) );
            } else {
                update_option( 'my-data', '' );
            }

            wp_safe_redirect( menu_page_url( ‘my-submenu’, false ) );
        }
    }
}

上のソースは、前の節までに作ったプラグインのソースです。

ここまで、このプラグインの管理画面では単純なテキストを入力し保存するだけのものでしたが、今回は例としてメールアドレスを入力し保存するためのものに修正していきます。

メールアドレスの入力を促すテキストを追加する

今回作っているプラグインはあくまでもサンプルなので、この作業は不要かもしれませんが、通常のテキストからメールアドレスを入力してもらうように変更するため、テキストフィールドの前に<?php _e( 'E-mail Address', 'my-custom-admin' ); ?>:といった具合にメールアドレスの入力を促すためのテキストを追加します。

function my_submenu() {
?>
<div class="wrap">
<h2>My Submenu</h2>

<form id="my-submenu-form" method="post">
    <?php wp_nonce_field( 'my-nonce-key', 'my-submenu' ); ?>

    <p><?php _e( 'E-mail Address', 'my-custom-admin' ); ?>:
        <input type="text" name="my-data"
            value="<?php echo esc_attr( get_option( 'my-data' ) ); ?>"></p>
    <p><input type="submit"
            value="<?php esc_attr( _e( 'Save', 'my-custom-admin' ) ); ?>"
            class="button button-primary button-large"></p>
</form>

</div>
<?php
}

_e()はこれまでにも述べてきましたが、国際化のための関数で、プラグインに翻訳ファイルを添付することで日本語等のメッセージに翻訳されます。

送信されたデータがメールアドレスであるかどうかを検証する

次にadmin_initで実行していた保存処理のところに、送信された値がメールアドレスかどうかをチェックするための処理を記述します。

add_action( 'admin_init', 'my_admin_init' );

function my_admin_init()
{
    if ( isset( $_POST['my-submenu'] ) && $_POST['my-submenu'] ){
        if ( check_admin_referer( 'my-nonce-key', 'my-submenu' ) ){
            $e = new WP_Error();
            if ( isset($_POST['my-data']) && $_POST['my-data'] ) {
                if ( is_email( trim( $_POST['my-data'] ) ) ) {
                    update_option( 'my-data', trim( $_POST['my-data'] ) );
                } else {
                    $e->add(
                        'error',
                        __( 'Please enter a valid email address.',
                                'my-custom-admin' )
                    );
                    set_transient( 'my-custom-admin-errors',
                            $e->get_error_messages(), 10 );
                }
            } else {
                update_option( 'my-data', '' );
            }

            wp_safe_redirect( menu_page_url( ‘my-submenu’, false ) );
        }
    }
}

では追加した行を順に解説していきます。

まず、以下のようにWP_ErrorクラスでWordPressのエラーオブジェクトを生成しています。

$e = new WP_Error();

このように、あらかじめエラーオブジェクトを作っておくことで、後々の入力チェックの結果を追加していくことができます。

エラーオブジェクトに関する詳しいことは「エラー処理」の章で解説していますので、ここでは決まり文句程度に覚えておきましょう。

次に、送信されたデータがメールアドレスかどうかをチェックするために条件分岐を追加したのが以下の行です。

if ( is_email( trim( $_POST['my-data'] ) ) ) {
    update_option( 'my-data', trim( $_POST['my-data'] ) );
} else {
    $e->add(
        'error',
        __( 'Please enter a valid email address.', 'my-custom-admin' )
    );
    set_transient( 'my-custom-admin-errors',
            $e->get_error_messages(), 10 );
}

まず、WordPressのis_email()関数で、送信されたデータがメールアドレスであるかどうかをチェックしています。

メールアドレスのフォーマットは非常に複雑で正規表現を自力で実装するのは大変です。ここは素直にWordPressにあらかじめある関数を使用することをおすすめします。

もし送信されたデータがメールアドレスではない場合は、WP_Errorクラスのadd()メソッドを使用して、エラーメッセージを格納しています。

$e->add( 'Error',
        __( 'Please enter a valid email address.', 'my-custom-admin' ) );

add()メソッドの第一引数はエラーコードで、今回の例では特に使用していませんが、大きなフォーム等でエラーの内容を分類したい際などに使用するもので、多くの場合ユーザーに見せるよりも内部的に使用するものです。

第二引数はユーザーに表示するためのエラーメッセージで、例のごとく国際化するための__()関数を使用しています。

このadd()メソッドは複数回実行することで、複数のエラーメッセージを格納し、get_error_messages()メソッドを使用して以下のように配列で取り出すことができます。

$e = new WP_Error();

$e->add( 'error', '郵便番号を入力してください。' );
$e->add( 'error', '電話番号を入力してください。' );
$e->add( 'error', '氏名を入力してください。' );

var_dump( get_error_messages() ); // 3つのエラーメッセージを配列で取得

今回作っているプラグインはサンプルソースとしてシンプルにするためにひとつの入力フィールドしか用意していませんが、実際に使用する際には上の例のように$e->add()を何度も使用してエラーメッセージを追加し、$e->get_error_messages()で配列で取得して処理するのが一般的だと言えます。

以下の行は入力チェックの結果取得されたエラーを一時データに保存するための処理です。

set_transient( 'my-custom-admin-errors', $e->get_error_messages(), 10 );

このset_transient()関数は、これまでにも紹介してきたOptions APIと非常によく似た機能を持つ関数ですが、Options APIとは違い有効期限を秒単位で設定することができます。

この例では、my-custom-admin-errorsというキーにエラーメッセージの配列を有効期限10秒で保存しており、10秒を超えると削除され、エラーメッセージが表示されなくなります。

このようにすることで、フォーム送信後にwp_redirect()関数でリダイレクトされてもエラーメッセージが表示されるようにしています。

エラーメッセージを表示する

前述しましたが、エラーメッセージ等のメッセージを管理画面で表示するにはadmin_noticesフックを使用します。

エラーメッセージの表示例
エラーメッセージの表示例

まず、以下のようにadmin_noticesフックにコールバック関数を指定して下さい。

add_action( 'admin_notices', 'my_admin_notices' );

次に指定したコールバック関数my_admin_notices()内でエラーメッセージを表示するためのHTMLを生成していきます。

function my_admin_notices() {
?>
    <?php if ( $messages = get_transient( 'my-custom-admin-errors' ) ): ?>
    <div class="error">
        <ul>
            <?php foreach( $messages as $message ): ?>
                <li><?php echo esc_html($message); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
    <?php endif; ?>
<?php

}

set_transient()で保存したデータはget_transient()に同じキーを指定することで取得することができます。

先ほどset_transient()の有効期限で、10秒を指定したので、一定時間が経過してからページをリロードするとエラーメッセージが表示されなくなることがお分かりいただけると思います。

HTMLに出力を行う際には、esc_html()関数などで確実にエスケープを行うように心がけて下さい。

エスケープ方法については、「WordPressのセキュリティ」の章で詳しく解説しています。

エラーメッセージの表示スタイルについて

上の例では、エラーメッセージを囲む<div />というボックスにerrorというクラス属性が指定されています。

<div class="error">
    <ul>
        <?php foreach( $messages as $message ): ?>
            <li><?php echo esc_html($message); ?></li>
        <?php endforeach; ?>
    </ul>
</div>

これは、エラーを表示する部分でWordPressであらかじめ用意されているデザインを適用するためのクラスで、errorupdatedの2つが用意されています。

divのclass属性をupdatedに変更した例
divのclass属性をupdatedに変更した例

上の図は<div class="error">の部分を<div class="updated">に変更した時の表示サンプルです。

ご覧になると分かる通りadmin_noticesフックは単純にエラーメッセージだけでなく、ユーザーへの通知等にも使用できますので、臨機応変に使い分けていくといいと思います。

今回サンプルとして開発したプラグイン

長々と説明しましたが、出来上がったサンプルは意外とシンプルです。

最後にできあがったプラグイン全体のソースを掲載しておきますので、ぜひ参考にしてみてください。

<?php
/*
Plugin Name: My Admin
*/

add_action( 'admin_menu', 'my_admin_menu' );

function my_admin_menu() {

    add_options_page(
        __('My Submenu', 'my-custom-admin'),
        __('My Submenu', 'my-custom-admin'),
        'manage_options',
        'my-submenu',
        'my_submenu'
    );
}

function my_submenu() {
?>
<div class="wrap">
<h2>My Submenu</h2>

<form id="my-submenu-form" method="post">
    <?php wp_nonce_field( 'my-nonce-key', 'my-submenu' ); ?>

    <p><?php _e( 'E-mail Address', 'my-custom-admin' ); ?>:
        <input type="text" name="my-data" 
            value="<?php echo esc_attr( get_option( 'my-data' ) ); ?>"></p>
    <p><input type="submit" 
            value="<?php esc_attr( _e( 'Save', 'my-custom-admin' ) ); ?>"
            class="button button-primary button-large"></p>
</form>

</div>
<?php
}

add_action( 'admin_init', 'my_admin_init' );

function my_admin_init()
{
    if ( isset( $_POST['my-submenu'] ) && $_POST['my-submenu'] ){
        if ( check_admin_referer( 'my-nonce-key', 'my-submenu' ) ){
            $e = new WP_Error();
            if ( isset($_POST['my-data']) && $_POST['my-data'] ) {
                if ( is_email( trim( $_POST['my-data'] ) ) ) {
                    update_option( 'my-data', trim( $_POST['my-data'] ) );
                } else {
                    $e->add(
                        'error',
                        __( 'Please enter a valid email address.',
                                'my-custom-admin' )
                    );
                    set_transient( 'my-custom-admin-errors',
                            $e->get_error_messages(), 10 );
                }
            } else {
                update_option( 'my-data', '' );
            }

            wp_safe_redirect( menu_page_url( ‘my-submenu’, false ) );
        }
    }
}

add_action( 'admin_notices', 'my_admin_notices' );

function my_admin_notices() {
?>
    <?php if ( $messages = get_transient( 'my-custom-admin-errors' ) ): ?>
    <div class="updated">
        <ul>
            <?php foreach( $messages as $message ): ?>
                <li><?php echo esc_html($message); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
    <?php endif; ?>
<?php

}