How to automatically block WordPress bot spam without a plugin

If you have a WordPress site that allows comments without registering, your trash will likely be filled with hundreds of spam comments that you will need to deal with. Here are a few relatively simple steps to help almost completely eliminate this problem.

This will require editing your functions.php file and style.css file. For these changes to be persistent across theme updates, you should create a child theme, and create additional functions.php and style.css files.

Spambots have two highly predictable behaviors that we can use to detect and then block their comments:

  1. They often post comments directly via the WordPress comment REST API endpoint. This is a very efficient way to post a comment, and spambots are all about efficiency.
  2. They (almost) always fill in the URL field. The point of spam is usually to sell something, and that works best when a URL can be added to a comment. Very few people click on these links, but spammers know that search engines scan content and index the links, so spambots try to craft messages that will get their URLs into search results.

Blocking comments that directly use the REST API will prevent spambots from posting comments without first coming to the comment form on the post. This makes it more complicated for a bot to create a comment, without making it hard for your human readers.

To block direct comment creation via the REST API, add a hidden form field with a unique value that is only added in the comment form, and is absent from the REST API data. This unique field and value is called a nonce, and WordPress has functions to easily create this value for you and embed it in a comment.

Most people who comment do not have URLs, or they don’t care enough to fill in the URL field. As a result, you could disable the URL field to discourage spambots from trying to create a comment, but is not guaranteed to prevent spambots from creating comments. Instead, leave the URL field enabled and make it invisible to human readers through CSS. This tricks the spambots into filling out the URL field, since they don’t read web pages the way humans see them. You can then block any comments that have the URL field filled in, because you know the comment was not created by a human.

To hide hide the URL field from human eyes, but leave it enabled for bots to fill out, add a file called style.css to your child theme directory, with the following css:

p.comment-form-url {
   position: absolute;
   left: -9000px;
}

This will put the URL field far beyond the left-hand edge of the screen.

To create and embed the nonce into your comment form, add the following function and action to your child theme’s functions.php:

// Generate nonce for comment
function add_nonce_field_to_comment_form() {
    wp_nonce_field('comment_form_nonce_field');
}

// Add nonce to comment form
add_action('comment_form', 'add_nonce_field_to_comment_form');

To check for the nonce, and to check if the URL field has been filled in, add the following function to your child theme’s functions.php:

// Check nonce field validity and spambot completion of URL
function check_spam_nonce_field_on_comment_form() {
    if (!wp_verify_nonce($_REQUEST['_wpnonce'], 'comment_form_nonce_field')) {
        die('Nonce check failed, killing request');
    }
    if (!empty( $_POST['url'] ))
        wp_die( 'Thank you for your comment. It has been dealt with accordingly', 'Thank you', [ 'response' => 403, 'exit' => true ] );
}

Finally, you need to add an action to execute this function before a comment is saved:

// Add nonce and spam check to comment form post
add_action('pre_comment_on_post', 'check_spam_nonce_field_on_comment_form');

Once these changes are saved, you should notice a big drop in the number of spam comments that you receive, and you won’t have to review and empty your comment trash as often. Human visitors (and some persistent spammers) will still be able to create comments without noticing any difference.

Leave a Reply

Your email address will not be published. Required fields are marked *