フリーランスでWeb制作をしている矢野です。
今回は、ポートフォリオ作品「おうちで、わんこと。」(訪問型ペットシッターサービスの架空クライアントサイト)で、Contact Form 7のようなプラグインを使わずに自作したお問い合わせフォームについて書きます。
なぜプラグインを使わずに自作したか
WordPressのお問い合わせフォームといえば、Contact Form 7やWPFormsのようなプラグインを入れるのが定番だと思います。
ただ、今回のようにページ数の少ない小規模サイトでは、フォーム1つのためにプラグインを追加すると、その分の管理画面の複雑さや将来的なアップデート対応、プラグイン間の競合リスクが増えてしまいます。
送信処理自体はシンプルなメール送信なので、今回はテーマのfunctions.phpに直接処理を書いて自作することにしました。
admin_postフックで送信処理を受け止める
自作フォームの送信先には、WordPressが用意しているadmin-post.phpという仕組みを使います。
add_action( 'admin_post_nopriv_wanko_to_contact', 'wanko_to_handle_contact_form' );
add_action( 'admin_post_wanko_to_contact', 'wanko_to_handle_contact_form' );
admin_post_{action名}はログイン済みユーザーからの送信、admin_post_nopriv_{action名}は未ログイン(一般の訪問者)からの送信を受け止めるフックです。
一般公開のお問い合わせフォームなので、訪問者はほぼ確実に未ログイン状態のため、この2つを両方登録しておく必要があります。
フォーム側は、送信先をadmin-post.phpにして、actionという名前の隠しフィールドにwanko_to_contactという値を入れておくだけです。
nonceでCSRF対策をする
フォーム処理を自作する以上、CSRF(クロスサイトリクエストフォージェリ)対策は自分で入れる必要があります。
WordPressにはwp_nonce_field()とwp_verify_nonce()という、これ専用の仕組みが用意されています。
function wanko_to_handle_contact_form() {
if ( ! isset( $_POST['wanko_to_contact_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wanko_to_contact_nonce'] ) ), 'wanko_to_contact' ) ) {
wp_safe_redirect( add_query_arg( 'contact', 'error', home_url( '/#contact' ) ) );
exit;
}
// ...
}
フォーム表示時にwp_nonce_field( 'wanko_to_contact', 'wanko_to_contact_nonce' )でトークンを埋め込んでおき、送信処理の一番最初でこのトークンを検証しています。
検証に失敗した場合は、内容を処理せずにそのままフォームへリダイレクトして終了させています。
ハニーポットで簡易的なスパム対策をする
nonce検証だけでも多少のスパム対策にはなりますが、今回はもう一段階、ハニーポットという手法も入れました。
// ハニーポット(ボット対策)。人間には見えない項目に入力があればスパムとみなす。
if ( ! empty( $_POST['wanko_to_contact_website'] ) ) {
wp_safe_redirect( add_query_arg( 'contact', 'success', home_url( '/#contact' ) ) );
exit;
}
これは、CSSで画面上には見えないようにした入力欄をフォームにこっそり用意しておき、そこに何か入力されていたら人間ではなくボットによる自動送信だとみなす、という手法です。
人間の訪問者には見えないので普通に使う分には空欄のまま送信され、機械的にフォーム項目を全部埋めて送信してくるタイプのスパムボットだけが引っかかる仕組みです。
見た目上は成功したように見せかけつつ実際にはメールを送らずに処理を打ち切っている点がポイントで、スパムボット側に「失敗した」と気づかれて別の回避策を試されるのを防ぐ意図もあります。
メール送信と結果の受け渡し
nonceとハニーポットのチェックを抜けたら、あとは各項目をサニタイズしたうえでwp_mail()で管理者宛にメールを送るだけです。
$sent = wp_mail( get_option( 'admin_email' ), '【おうちで、わんこと。】お問い合わせ', $body, array( 'Reply-To: ' . $email ) );
wp_safe_redirect( add_query_arg( 'contact', $sent ? 'success' : 'error', home_url( '/#contact' ) ) );
exit;
admin-post.phpはリダイレクトで処理を終えるのが基本の流れなので、送信結果を?contact=successのようなクエリパラメータに乗せてフォームのページへ戻し、フロント側でその値を見て成功・失敗メッセージを出し分けています。
まとめ
今回は、小規模サイトのお問い合わせフォームをプラグインなしで自作し、admin-post.phpフックでの受け口作り、nonceによるCSRF対策、ハニーポットによる簡易スパム対策を実装した話を書きました。
大掛かりなプラグインを入れなくても、WordPress標準の仕組みだけで最低限のセキュリティを備えたフォームは十分作れると感じています。
同じように小規模サイトでフォームだけのためにプラグインを増やすのに迷っている方の参考になればうれしいです。