Add CAPTCHA to WordPress Login and Comments Without a Plugin

A lightweight, practical alternative is implementing a custom PHP-based math CAPTCHA.

Many shared code snippets have a critical vulnerability: they store the correct answer in a plain-text hidden HTML field. This allows basic scraper bots to bypass the check by simply reading the page source.

Below is a safer approach that uses WordPress’s built-in cryptographic hashing to verify user answers without exposing them in the DOM.

The PHP Implementation

You can add this code to your theme’s functions.php file or using snippets plugin.


// 1️⃣ Add the Math CAPTCHA above the comment submit button
function dt_add_math_captcha_to_comments( $submit_field ) {
    // Bypass the check for logged-in users
    if ( is_user_logged_in() ) {
        return $submit_field;
    }

    // Generate two random integers
    $num1 = rand( 1, 9 );
    $num2 = rand( 1, 9 );
    $answer = $num1 + $num2;

    // Hash the expected answer to obscure it from DOM scrapers
    $hashed_answer = wp_hash( $answer, 'comment_captcha' );

    // Construct the CAPTCHA HTML
    $captcha_html = '<p class="dt-captcha-wrapper" style="margin-bottom: 15px;">
        <label for="dt_math_captcha"><strong>Anti-Spam:</strong> What is ' . $num1 . ' + ' . $num2 . '?</label><br>
        <input type="number" name="dt_math_captcha" id="dt_math_captcha" required style="width: 100px; padding: 5px;">
        <input type="hidden" name="dt_captcha_hash" value="' . esc_attr( $hashed_answer ) . '">
    </p>';

    // Append the CAPTCHA immediately before the submit button
    return $captcha_html . $submit_field;
}
add_filter( 'comment_form_submit_field', 'dt_add_math_captcha_to_comments' );

// 2️⃣ Verify the CAPTCHA before processing the comment
function dt_verify_math_captcha( $commentdata ) {
    // Bypass verification for logged-in users
    if ( is_user_logged_in() ) {
        return $commentdata;
    }

    // Verify the presence of the required POST variables
    if ( isset( $_POST['dt_math_captcha'] ) && isset( $_POST['dt_captcha_hash'] ) ) {
        
        $user_answer = intval( $_POST['dt_math_captcha'] );
        $expected_hash = $_POST['dt_captcha_hash'];

        // Hash the provided answer and strictly compare it to the stored hash
        if ( wp_hash( $user_answer, 'comment_captcha' ) !== $expected_hash ) {
            wp_die( '<strong>Error:</strong> Incorrect math answer. Please go back and try again.' );
        }

    } else {
        wp_die( '<strong>Error:</strong> CAPTCHA verification is required to submit a comment.' );
    }

    return $commentdata;
}
add_filter( 'preprocess_comment', 'dt_verify_math_captcha' );

Technical Considerations

1. Minimal Performance Impact

This validation runs entirely server-side in PHP. No external JavaScript or CSS is needed, keeping your frontend lightweight and Core Web Vitals unaffected.

2. Resilience Against Source-Code Scraping

The wp_hash() function hides the correct answer in the HTML. While advanced bots with headless browsers could still solve it visually, this stops most simple automated spam scripts.

3. Better User Experience (UX)

The <input type="number"> triggers a numeric keypad on mobile devices, making it easier for real users. Skipping the CAPTCHA for logged-in users prevents unnecessary friction for admins and authenticated visitors.

4. Cleaner Database

Preventing spam at the server level reduces unnecessary entries, keeping your comment database clean and efficient without third-party dependencies.

Leave a Reply

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