Jetpack のお問い合わせフォーム、ブロックエディターからの操作が簡単で、サクッとフォームを作りたいとかの時は便利かなと思ってます。
ただメールフォームを設置するとスパムメールで問い合わせメールが埋もれてしまいます。
の導入を検討したのですが、そこまでコストかけるほどでも無さそうな感じだったので、サクッと自前でスパム判定機能を実装してみました。
実装
ソース読んでいくと、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_author | string | 投稿者名 |
| comment_author_email | string | 投稿者のメールアドレス |
| comment_author_url | string | 投稿者のURL |
| contact_form_subject | string | お問い合わせフォームの件名 |
| comment_author_ip | string | 投稿者のIPアドレス |
| comment_content | string | お問い合わせ内容 |
| contact_form_field_{$slug} | string | フォームで追加したフィールド |
| comment_type | string | フォームタイプ |
| user_ip | string | ユーザーのIPアドレス |
| user_agent | string | ユーザーエージェント |
| referrer | string | リファラーURL |
| blog | string | サイトURL |
| comment_date_gmt | string | 投稿日時(GMT) |
| REQUEST_URI | string | リクエストURI |
| HTTP_AUTHORIZATION | string | 認証情報 |
それなりに使えそうな情報がとれてますね。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 等も実装されるのでその辺使うといい感じにできるかもしれませんね。
