Contact Form 7でインテグレーションを使わず独自にgoogle reCAPTCHA V3を実装する方法

いただいた案件でwp_headやwp_footer関数を使わずに、WordPress内にContact Form 7を利用したフォーム付きページを作成する必要があり、
フォームのスパム対策のためにgoogle reCAPTCHA V3を利用しました。

実装するのにつまずいたポイントがあったので、実装方法をまとめました。

こちらの記事を参考にさせていただきました!感謝です!
Contact Form 7で独自にreCAPTCHA v3を用いる | WEBUTUBUTU
公式の手順→reCAPTCHA v3 | Google Developers

実装手順

1.サイトキーとシークレットキーを取得
2.HTMLファイルにreCAPTCHA用のコードを追加
3.WordPressのfunctions.phpにスパム判定するフックを上書き

上記手順となります。

ちなみに、この記事執筆時(2022年2月16日)の環境は以下です。

  • エックスサーバー(スタンダードプラン)
  • WordPress v5.9.0
  • Contact Form 7 v5.5.5

サイトキーとシークレットキーを取得

今回はすでに取得してあるものとしてほぼ端折ります。

管理画面はこちら→https://www.google.com/recaptcha/admin

reCAPTCHA管理画面へ行き、上部にあるv3 Admin Consoleをクリックで飛べます。

管理画面上部の+をクリックして、必要な情報を入力する。

ラベル:reCAPTCHAのラベル(サイトごとに変えたりするやつ)
reCAPTCHAタイプ:reCAPTCHA v3
ドメイン:reCAPTCHAを設置したいドメインを設定
オーナー:管理者。アラートを送信できる
利用条件に同意:同意してください

これで送信ボタン押せばサイトキーとシークレットキーが表示されます。

HTMLファイルにreCAPTCHA用のコードを追加

公式に載ってる通りでOKです。

<form action="" type="POST" id="contact_form">

<!-- フォーム内に設置 -->
<input type="hidden" name="_recaptcha_token" id="_recaptcha_token" value="">

</form>

<!-- スクリプト追加 -->
<script src="https://www.google.com/recaptcha/api.js?render=ここにサイトキーを入力"></script>

<script>
var $form = document.getElementById('contact_form'); // formタグのIDを指定
$form.addEventListener('submit', onClick);

function onClick(e) {
    e.preventDefault();
    grecaptcha.ready(function () {
        grecaptcha.execute('ここにサイトキーを入力', {
            action: 'submit'
        }).then(function (token) {
            // ここで生成されたtokenをサーバーサイドにPOSTする
            var recaptchaToken = document.getElementById('_recaptcha_token'); // hiddenタグのIDを指定。
            recaptchaToken.value = token;
            $form.submit();
        });
    });
}
</script>

これでフロント側はOKです。

WordPressのfunctions.phpにスパム判定するフックを上書き

まずは結論から。以下をfunctions.phpの最後の行に追加しましょう。

add_filter('wpcf7_spam', 'my_wpcf7_recaptcha_verify', 9, 1);

function my_wpcf7_recaptcha_verify($spam) {
  if ($spam) {
    return $spam;
  }

  if (empty($_POST['_recaptcha_token'])) {
    return true;
  }

  $token = trim( $_POST['_recaptcha_token'] );

  $secretKey = 'ここにシークレットキーを入力';
  $endpoint = 'https://www.google.com/recaptcha/api/siteverify';

  $request = array(
    'body' => array(
      'secret' => $secretKey,
      'response' => $token,
    ),
  );
  $response = wp_remote_post( esc_url_raw( $endpoint ), $request );

  if ( 200 != wp_remote_retrieve_response_code( $response ) ) {
    $spam = true;
  }


  $response_body = wp_remote_retrieve_body( $response );
  $response_body = json_decode( $response_body, true );

  $score = isset( $response_body['score'] ) ? $response_body['score'] : 0;

  if ($score < 0.7) {
    $spam = true;
  }

  return $spam;
}

ちなみにContact Form 7プラグインの中身を確認したところこんな実装になってました。

add_filter( 'wpcf7_spam', 'wpcf7_recaptcha_verify_response', 9, 2 );

function wpcf7_recaptcha_verify_response( $spam, $submission ) {
    if ( $spam ) {
        return $spam;
    }

    $service = WPCF7_RECAPTCHA::get_instance();

    if ( ! $service->is_active() ) {
        return $spam;
    }

    $token = isset( $_POST['_wpcf7_recaptcha_response'] )
        ? trim( $_POST['_wpcf7_recaptcha_response'] ) : '';

    if ( $service->verify( $token ) ) { // Human
        $spam = false;
    } else { // Bot
        $spam = true;

        if ( '' === $token ) {
            $submission->add_spam_log( array(
                'agent' => 'recaptcha',
                'reason' => __( 'reCAPTCHA response token is empty.', 'contact-form-7' ),
            ) );
        } else {
            $submission->add_spam_log( array(
                'agent' => 'recaptcha',
                'reason' => sprintf(
                    __( 'reCAPTCHA score (%1$.2f) is lower than the threshold (%2$.2f).', 'contact-form-7' ),
                    $service->get_last_score(),
                    $service->get_threshold()
                ),
            ) );
        }
    }

    return $spam;
}

18行目の $service->verify( $token ) でバックエンド側の処理が行われていました。

return true; がスパム扱いになるようです!
falseじゃないの!?って思ったので注意ですね!

ちなみにverify関数の中身を抜粋するとこんな感じでした。

public function verify( $token ) {
    $is_human = false;

    if ( empty( $token ) or ! $this->is_active() ) {
        return $is_human;
    }

    $endpoint = 'https://www.google.com/recaptcha/api/siteverify';

    $sitekey = $this->get_sitekey();
    $secret = $this->get_secret( $sitekey );

    $request = array(
        'body' => array(
            'secret' => $secret,
            'response' => $token,
        ),
    );

    $response = wp_remote_post( esc_url_raw( $endpoint ), $request );

    if ( 200 != wp_remote_retrieve_response_code( $response ) ) {
        if ( WP_DEBUG ) {
            $this->log( $endpoint, $request, $response );
        }

        return $is_human;
    }

    $response_body = wp_remote_retrieve_body( $response );
    $response_body = json_decode( $response_body, true );

    $this->last_score = $score = isset( $response_body['score'] )
        ? $response_body['score']
        : 0;

    $threshold = $this->get_threshold();
    $is_human = $threshold < $score;

    $is_human = apply_filters( 'wpcf7_recaptcha_verify_response',
        $is_human, $response_body );

    if ( $submission = WPCF7_Submission::get_instance() ) {
        $submission->recaptcha = array(
            'version' => '3.0',
            'threshold' => $threshold,
            'response' => $response_body,
        );
    }

    return $is_human;
}

まとめ

改めてgoogle reCAPTCHAの理解が深まり、Contact Form 7に関してもファイルを読み漁ったので理解が深まったのでいい機会になりました。

プラグインにある機能の一部を利用できてないことで予期せぬバグを生むリスクがあるので、基本的にはインテグレーションでreCAPTCHAは実装しましょう!

About Me

プロフィール画像

ユーキと申します。北海道恵庭市という札幌と新千歳空港の間でフリーランスのWebエンジニアとして活動してます。

当サイトのブログでは、主にWeb制作全般、フリーランス周りの情報など色々なノウハウや知識を載せています。
その他日々気になったこと、思ったことも書いてます。

お仕事の相談など何かありましたら、お問い合わせかツイッターのDMからお気軽にご連絡くださいませ。

お問い合わせはこちら

ツイッターはこちら

ポートフォリオはこちら

Latest Posts

Popular Posts

TOP