Toro_Unit

フリーランスのフロントエンドエンジニア、WordPress エンジニアです

Jetpack のお問い合わせフォーム用の簡易的なスパムフィルターを作る

Categories:

Jetpack のお問い合わせフォーム、ブロックエディターからの操作が簡単で、サクッとフォームを作りたいとかの時は便利かなと思ってます。

ただメールフォームを設置するとスパムメールで問い合わせメールが埋もれてしまいます。

Akismet の導入を検討したのですが、そこまでコストかけるほどでも無さそうな感じだったので、サクッと自前でスパム判定機能を実装してみました。

実装

ソース読んでいくと、jetpack_contact_form_is_spam というフィルターフックがあるので、この辺使うと上手いこと出来そうです。

projects/packages/forms/src/contact-form/class-contact-form.php の2690 行あたりにそれっぽいコードがありました。

// Is it spam?
/** This filter is already documented in \Automattic\Jetpack\Forms\ContactForm\Admin */
$is_spam = apply_filters( 'jetpack_contact_form_is_spam', false, $akismet_values );
if ( is_wp_error( $is_spam ) ) { // WP_Error to abort
	return $is_spam; // abort
} elseif ( $is_spam === true ) {  // TRUE to flag a spam
	$spam = '***SPAM*** ';
}

スパムと判定するなら true をそうで無ければ、フィルターフックの第1引数を返してやれば良さげですが、第2引数 に渡されてるパラメーターがなんだか良く解りません。ドキュメントを調べましたが、あんまり情報が無かったので、デバッグしてみるとこんな感じのようです。

キー説明
comment_authorstring投稿者名
comment_author_emailstring投稿者のメールアドレス
comment_author_urlstring投稿者のURL
contact_form_subjectstringお問い合わせフォームの件名
comment_author_ipstring投稿者のIPアドレス
comment_contentstringお問い合わせ内容
contact_form_field_{$slug}stringフォームで追加したフィールド
comment_typestringフォームタイプ
user_ipstringユーザーのIPアドレス
user_agentstringユーザーエージェント
referrerstringリファラーURL
blogstringサイトURL
comment_date_gmtstring投稿日時(GMT)
REQUEST_URIstringリクエストURI
HTTP_AUTHORIZATIONstring認証情報

それなりに使えそうな情報がとれてますね。comment_author とかはこの辺で設定されているようです。フォームの項目によらず取得出来る値っぽいので使えそうです。TypeScript になれてしまった人間としては、これを探してくるのが結構骨が折れました。

投稿者名が数字だけだったり、日本語の問い合わせしか受け付けてないところで、英語の謎のメールが来るとかが大半だったので、それを弾く簡単なスパムフィルターを書いてみます。

<?php
class Anti_Spam_For_Jetpack_Form {

	public function __construct() {
		add_filter( 'jetpack_contact_form_is_spam', array( $this, 'is_spam' ), 10, 2 );
	}

	/**
	 * スパム判定
	 *
	 * @param bool  $is_spam スパムかどうか.
	 * @param array $values {
	 *     フォームから送信された値。
	 *
	 *     @type string $comment_author 投稿者名
	 *     @type string $comment_author_email 投稿者のメールアドレス
	 *     @type string $comment_author_url 投稿者のURL
	 *     @type string $contact_form_subject お問い合わせフォームの件名
	 *     @type string $comment_author_ip 投稿者のIPアドレス
	 *     @type string $comment_content お問い合わせ内容
	 *     @type string $contact_form_field_ 電話番号
	 *     @type string $comment_type フォームタイプ
	 *     @type string $user_ip ユーザーのIPアドレス
	 *     @type string $user_agent ユーザーエージェント
	 *     @type string $referrer リファラーURL
	 *     @type string $blog サイトURL
	 *     @type string $comment_date_gmt 投稿日時(GMT)
	 *     @type string $REQUEST_URI リクエストURI
	 *     @type string $HTTP_AUTHORIZATION 認証情報
	 * }
	 * @return bool
	 */
	
	public function is_spam( $is_spam, $values ): bool {

		if ( $is_spam ) {
			return true;
		}

		if ( ! $this->is_japanese_text( $values['comment_author'] ) ) {
			return true;
		}

		$comment_content = $values['comment_content'];
		if ( ! $this->is_japanese_text( $comment_content ) ) {
			return true;
		}

		return false;
	}

	/**
	 * 日本語を含むかどうかを判定する関数
	 *
	 * @param string $text 判定するテキスト.
	 *
	 * @return bool 日本語を含む場合は true、それ以外は false.
	 */
	public function is_japanese_text( $text ): bool {
		return preg_match( '/[\x{3040}-\x{309F}\x{30A0}-\x{30FF}\x{4E00}-\x{9FFF}]/u', $text ) === 1;
	}

is_japanese_text メソッドで、ひらがな、カタカナ、漢字が1文字でも含まれているかどうかというシンプルなロジックです。こんな簡単なモノでもそれなりに弾けています。

実際にはこれに加えて comment_content の中身をちゃんと検証して、NGワードを含むかどうかを検証させてます。この辺はサイトの要件で変わるのかなというところですが、

まとめ

jetpack_contact_form_is_spam を用いて簡単な実装でスパムフィルター書いてみました。

WordPress 7.0 で、wp_ai_client_prompt 等も実装されるのでその辺使うといい感じにできるかもしれませんね。