【WordPress入門】スパムコメントをはじくための素朴な実装を考える
WordPress でコメント欄を設置しているとスパムコメントが送られてくる、というのは WordPress でブログ等を運用していると誰しも経験したことがあるのではないかと思います。対処法としては Akismet Spam Protection のようなプラグインを利用することだと思いますが、Akismet は広告を配置したサイトや、ビジネスのプロモーションのためのサイトでは無料で利用することができません。そこでここではプラグインの利用なしに単純なスパムコメントを受け付けないようにする方法を紹介します。
WordPress でのコメント投稿の仕組み
WordPress で投稿にコメントすると、wp-comments-post.php
へ POST リクエストが送られます。AMP for WordPress で標準モードにしていると、wp-comments-post.php
へ JSON リクエストが送られます。wp-comments-post.php
では
<?php
// ...
$comment = wp_handle_comment_submission( wp_unslash( $_POST ) );
// ...
でコメントがデータベースに登録され、最後に
<?php
// ...
/**
* Filters the location URI to send the commenter after posting.
*
* @since 2.0.5
*
* @param string $location The 'redirect_to' URI sent via $_POST.
* @param WP_Comment $comment Comment object.
*/
$location = apply_filters( 'comment_post_redirect', $location, $comment );
wp_safe_redirect( $location );
exit;
でリダイレクト処理されます。
wp_handle_comment_submission
関数は wp-includes/comment.php
で定義されています。wp_handle_comment_submission
関数では
<?php
// ...
$comment_id = wp_new_comment( wp_slash( $commentdata ), true );
// ...
が呼ばれ、wp_new_comment
関数からは
<?php
// ...
$comment_ID = wp_insert_comment( $commentdata );
// ...
が呼ばれ、wp_insert_comment
関数内の
<?php
// ...
if ( ! $wpdb->insert( $wpdb->comments, $compacted ) ) {
return false;
}
// ...
によってデータベースに保存されます。
スパムコメントはデータベースに保存される前にはじきたいため、wp_insert_comment
が呼ばれる前にスパムコメントの判定を行う必要があります。コメントに関する情報がフックする関数にそのまま渡されるようなアクション/フィルターフックを探すと、wp_new_comment
関数内の preprocess_comment
フィルターが見つかります。
<?php
/**
* Filters a comment's data before it is sanitized and inserted into the database.
*
* @since 1.5.0
* @since 5.6.0 Comment data includes the `comment_agent` and `comment_author_IP` values.
*
* @param array $commentdata Comment data.
*/
$commentdata = apply_filters( 'preprocess_comment', $commentdata );
ここではこのフィルターにでスパムコメントの判定をおこない、スパムの場合に処理を中止するようにします。
スパムコメントの特徴
次に「どのようにしてスパムコメントをはじくか」を考えるために、スパムコメントというのはどのような特徴をもっているか、を考えます。スパムコメントの一番大きな特徴は、手動ではなく自動で送られている、という点です。つまり誰かがパソコンであなたのウェブサイトにアクセスしてスパムコメントを送信しているのではなく、ボットなどで様々なウェブサイトを巡回し、フォームが見つかればすべての項目を埋めてスパムコメントを送信する、ということをしています。ですので「どのようにしてスパムコメントをはじくか」、言い換えれば「どのようにしてコメントがスパムだと判定するか」の最も簡単な方法は、「人間がコメントフォームから送信する際には見えないような隠し入力フィールドを用意しておいて、そのフィールドが入力されていればスパムコメントとしてはじく」、ということになります。いわゆるハニーポットと呼ばれるものを設置する、ということです。
スパムコメントが送られたらデータベースに入れる前にはじく
まずはハニーポットを設置します。WordPress のコメントフォームであらかじめ用意されているフィールドの中で、comment_author_url
については多くの場合それほど重要ではないと思われますので、そのフィールドをハニーポットとして利用します。
デフォルトで用意されているコメントフォームのフィールドをカスタマイズするために comment_form_default_fields
というフィルターフックが用意されていますので、そこで url
フィールドを display:none
で非表示にしたフィールドに変更します。
<?php
/**
* URL を honeypot フィールドとして利用する.
*/
add_filter(
'comment_form_default_fields',
function( array $fields ) {
$fields['url'] = '<p class="comment-form-url" style="display:none"><input id="url" name="url" type="url" value=""></p>';
return $fields;
}
);
preprocess_comment
フィルターにフックさせ、非表示にした URL フィールドに何かが入力されていれば、wp_die
で処理を中止する、ということをすれば目的は達成されます。コードにすると以下のようになります。
<?php
add_action(
'preprocess_comment',
function( array $commentdata ) {
if ( '' === $commentdata['comment_author_url'] ) {
return $commentdata;
}
}
);
preprocess_comment
は
$commentdata = apply_filters( 'preprocess_comment', $commentdata );
というようにフィルターフックですが、上記コードでは add_action
を呼び出しています。もしここで「なぜ add_filter
じゃないのか?」と思った方は、【WordPress入門】アクションフックとフィルターフックを使いこなそう でアクション/フィルターフックに関する理解を深めてください。