【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 );

ここではこのフィルターにでスパムコメントの判定をおこない、スパムの場合に処理を中止するようにします。

スパムコメントの特徴

次に「どのようにしてスパムコメントをはじくか」を考えるために、スパムコメントというのはどのような特徴をもっているか、を考えます。みなさんが今までに受け取ったスパムコメントを思い出してもらうとわかると思いますが、ブログの運営者にとってのスパムコメントの多くには何かしらのリンクが含まれています。このリンクはスパムコメントの投稿者が、ブログの運営者や(サイト上にコメントが公開された場合に)サイトを訪れる閲覧者に踏んで欲しいリンクです。逆に言えば、リンクが何も貼られていないようなスパムコメントはほとんどありません。ということは「どのようにしてスパムコメントをはじくか」、言い換えれば「どのようにしてコメントがスパムだと判定するか」の最も簡単な方法は、「コメント本文に URL が含まれているかどうか」をみる、ということになります。

これは極めて素朴な実装のため、スパムではないコメントについてもコメント本文に URL が含まれていれば弾かれてしまいます。ですが一般的なブログサイトを考えると、コメント本文にどうしても URL が必要となるような状況の方が少数派だと考えられますので、素朴な実装としてはこれで十分だと思います。またお問い合わせフォームなどを設置している場合、コメントと同様に「問い合わせ内容に URL が含まれていればはじく」というような実装も多くの場合有効だと思います。

スパムコメントが送られたらデータベースに入れる前にはじく

preprocess_comment フィルターにフックさせ、コメント本文に URL が含まれていれば wp_die で処理を中止する、ということをすれば目的は達成されます。コードにすると以下のようになります。

<?php

add_action(
    'preprocess_comment',
    function( array $commentdata ) {
        preg_match( '/https?:\/\//', $commentdata['comment_content'], $matches );
        if ( count( $matches ) > 0 ) {
            wp_die( 'Spam comments are not allowed by owner.' );
        }
    }
);

preprocess_comment

    $commentdata = apply_filters( 'preprocess_comment', $commentdata );

というようにフィルターフックですが、上記コードでは add_action を呼び出しています。もしここで「なぜ add_filter じゃないのか?」と思った方は、【WordPress入門】アクションフックとフィルターフックを使いこなそう でアクション/フィルターフックに関する理解を深めてください。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です