WordPress · 16 min read

How to stop WordPress spam comments without a pile of plugins

Spam comments were the first thing I fought on my first WordPress blog, and the pattern hasn’t really changed. Bots crawl the web looking for open wp-comments-post.php endpoints, paste in a link-stuffed comment, and move on to the next site. Your job is to make it expensive enough that they skip yours.

You don’t need a stack of plugins for this. Most WordPress spam is handled by three things: Akismet, a few Discussion settings, and stripping HTML from the comment form. The rest is diminishing returns.

Akismet, with discard enabled

Akismet ships with every WordPress install. It’s made by Automattic (where I work) and it catches most comment spam at the API level before the comment ever hits your database.

Akismet plugin page inside the WordPress admin

Setup is short:

  1. Sign up at akismet.com and grab an API key. The personal plan is free.
  2. Go to Plugins → Akismet in WordPress, paste the key, and save.
  3. Open Akismet’s settings and enable Silently discard the worst and most pervasive spam.

Akismet settings panel

That last option matters. Without it, Akismet still catches the obvious spam, but it dumps it into the Spam queue for you to eyeball. “Silently discard” throws away the worst of it automatically, so your queue only contains edge cases. On a busy blog, it’s the difference between scanning 50 spam comments a week and scanning 500.

Tune the Discussion settings

Settings → Discussion already has enough levers to handle a lot of spam without any code. The combination I use on every site I run:

WordPress Discussion settings screen

Block common spam keywords

The Comment Moderation and Disallowed Comment Keys boxes at the bottom of the Discussion screen let you list words or phrases that should trigger moderation or auto-rejection.

Disallowed keys configuration in Discussion settings

Instead of building a block list from scratch, look at whatever ends up in your own Spam queue for a week and pick out the recurring patterns, product names, pharmacy terms, gambling keywords, casino URLs, and so on. A short, actual list from your own site is better than a generic list you copied off someone else’s blog.

If you want a starting point, the WordPress community maintains a decent comment blacklist on GitHub that you can paste into Disallowed Comment Keys and then prune over time.

Strip HTML from comments

The main reason spammers bother posting comments is the anchor tag. Take HTML out of the comment body entirely and you remove most of the incentive:

add_filter( 'preprocess_comment', 'shameem_comment_post', 1 );
add_filter( 'comment_text', 'shameem_comment_display', 1 );
add_filter( 'comment_text_rss', 'shameem_comment_display', 1 );
add_filter( 'comment_excerpt', 'shameem_comment_display', 1 );

function shameem_comment_post( $incoming_comment ) {
    $incoming_comment['comment_content'] = htmlspecialchars( $incoming_comment['comment_content'] );
    $incoming_comment['comment_content'] = str_replace( "'", ''', $incoming_comment['comment_content'] );
    return $incoming_comment;
}

function shameem_comment_display( $comment_to_display ) {
    return str_replace( ''', "'", $comment_to_display );
}

The incoming filter escapes every comment as it’s saved. The display filter converts the single-quote placeholder back on output. Inline links stop working, which is the point.

Remove the URL field from the comment form

The URL field in the default comment form is the main thing bots are after, it gives them a clickable link back to their site. Remove it and most of the automated spam stops bothering:

add_filter( 'comment_form_default_fields', 'shameem_remove_url_field' );
function shameem_remove_url_field( $fields ) {
    if ( isset( $fields['url'] ) ) {
        unset( $fields['url'] );
    }
    return $fields;
}

Real commenters almost never miss this field. You can’t imagine how often they would’ve left a URL if the box had been there, because they almost never notice it’s gone.

Block off-site comment requests

A lot of comment spam doesn’t come through your actual comment form. Bots POST directly to wp-comments-post.php from their own scripts. You can block that at the .htaccess level by requiring the request to come from your own domain:

RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
RewriteCond %{HTTP_REFERER} !.*yourblog\.com.* [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]

Replace yourblog.com with your own domain. This bounces any POST to the comment endpoint that either doesn’t have a referrer header or has one from somewhere other than your site. It won’t catch a bot that forges headers correctly, but it catches the cheap ones, and the cheap ones are most of them.

Always take a backup before editing .htaccess. A typo in this file will break the whole site.

Block specific IPs when one bot gets aggressive

Every so often a single IP or small range will hammer you repeatedly. You can block specific IPs straight from Settings → Discussion → Disallowed Comment Keys (just paste the IP), or from .htaccess if you want to block all traffic, not just comments:

Order allow,deny
Deny from 88.136.129.110
Allow from all

Don’t over-invest in this. IPs rotate, ranges change, and if you’re getting enough traffic from a single IP that you need to block it at the server level, a WAF (Cloudflare, Sucuri) is a better tool than .htaccess.

Plugins, only if you need more

If Akismet plus the settings above plus the filters still leaves you with too much spam, the anti-spam plugins I’ve actually seen hold up over time are:

Stack one of these on top of Akismet only if you actually need it. Most blogs won’t.

Spam comments are an arms race. You won’t hit zero, but you can get it down to where you’re checking the Spam queue once a week out of habit and not because you have to.

Share:

Your Friday WooCommerce briefing

What changed this week, what broke, and what you should try. Plugin news, store fixes, and opinions. No fluff, no affiliate spam.

Sent every Friday. Unsubscribe in one click.

This blog is independent and ad-free. If a post saved you time or taught you something new, a coffee goes a long way.

Have thoughts, questions, or a different take? I'd love to hear from you.

Powered by Giscus · Sign in with GitHub to comment. · Privacy policy