Eliminate spam with a custom honeypot

A custom honeypot is a simple and effective way to eliminate spam. If a hidden field in your form is filled in, you can be fairly confident the submission is spam.

WPForms does include a built-in honeypot, but now that the plugin is used on millions of sites, most spam bots have been updated to identify and skip the WPForms field with a name of hp.

Your custom honeypot is different. It’s unique to your form and looks like any other field to a bot. I have pretty much eliminated spam on my contact form with a custom honeypot.


First, come up with a unique CSS class name you’ll use to identify your honeypot field. Make it something unique to your site (ie: not honeypot). If your class is my-fancy-field, add this to your theme’s stylesheet to hide that field.

.wpforms-container .my-fancy-field {
	display: none;
}

Create a field in your form and add your custom class to it.

Add the following code to your theme’s functions.php file or a Core Functionality plugin. If this field is ever filled in, the submission will be marked as spam and have a honeypot message of “[Custom honeypot]”.

Make sure you update the $honeypot_class variable at the top to use your custom class name.

/**
* WPForms Custom Honeypot
*
* @author Bill Erickson
* @link http://www.billerickson.net/eliminate-spam-with-a-custom-honeypot/
*
* @param string $honeypot, empty if not spam, honeypot text is used in WPForms Log
* @param array $fields
* @param array $entry
* @param array $form_data
*/
function be_wpforms_custom_honeypot( $honeypot, $fields, $entry, $form_data ) {
	$honeypot_class = 'my-fancy-field';

	$honey_field = false;
	foreach( $form_data['fields'] as $form_field ) {
		if( false !== strpos( $form_field['css'], $honeypot_class ) ) {
			$honey_field = absint( $form_field['id'] );
		}
	}

	if( !empty( $entry['fields'][$honey_field] ) ) {
		$honeypot = 'Custom honeypot';
	}

	return $honeypot;

}
add_filter( 'wpforms_process_honeypot', 'be_wpforms_custom_honeypot', 10, 4 );

Logging

You can also enable logging so you can see if the honeypot is working. Every time a spam entry is submitted, this will create a post in the wpforms_log post type with the honeypot message and the full submission.

I recommend only logging this data temporarily because you don’t want to fill up your database with a bunch of unimportant spam messages.

First, update the wpforms_logging option to log spam:

/**
 * Enable logging of spam
 *
 */
add_action( 'init', function() {
	$debug = get_option( 'wpforms_logging' );
	if( empty( $debug ) || ! in_array( 'spam', $debug ) )
		update_option( 'wpforms_logging', [ 'spam' ] );
});

Use this code to make the WPForms Log post type visible. You can then access it in WPForms > Logs.

/**
 * Make log visible
 *
 */
add_filter( 'wpforms_log_cpt', function( $args ) {
	$args['show_ui'] = true;
	unset( $args['capability_type'] );
	return $args;
});

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. Hans Schuijff says

    Hi Bill,

    Thanks for this useful tip. I use Gravity Forms at the moment, but could probably add something like this there too.

    There seems a small error in the second snippet, since it now checks for an empty array that also not contains “spam”, so perhaps you meant !empty( $debug ) in the first part?

    Cheers,
    Hans

    • Bill Erickson says

      You’re right, there is an error in the last snippet. That should be an OR statement, not an AND statement.

      The code should say “if the wpforms_logging option is empty, or if doesn’t contain spam, update the option to log only spam”.

      • Bill Erickson says

        WPForms also has its own honeypot built-in. The problem is that Gravity Forms and WPForms are used on so many websites that spam bots have been programmed to identify their honeypots and not fill them in.

        The approach outlined above lets you create a honeypot that spam bots aren’t already aware of. It’s unique to your site, so you don’t have to worry about them identifying the class or ID of the field and skipping it.

        This general approach could easily be applied to Gravity Forms using their gform_entry_is_spam filter.

  2. Chris Wathen says

    Hey Bill,

    I just found a typo in your second snippet. When you call out the variable in line 17, you have $honeypost_class instead of $honeypot_class.

    Take care,
    Chris

  3. David says

    Hi Bill,

    I used a custom form in my word press site, but wanted to know how could I use this code in a custom form, not a WP plug in.

    • Bill Erickson says

      You could use the general concept – hide a field with CSS, and if it is filled in, reject that message as spam. But the actual code above will only work with WPForms.

  4. G Pellikaan says

    Didn’t work quite as aspected, until I changed my ‘fancy-field’ from text to name field, and also kept the label. Spambots just didn’t fill the hidden textfields, but a name field, O boy!

    • Bill Erickson says

      I think the general concept could work, but I’m not familiar with the hooks & filters in WooCommerce so can’t provide an example of the code you would use. You might try asking a developer that specializes in WooCommerce.

  5. Ross says

    Thanks for taking the time to share this Bill. I went through the steps you listed but somehow for me the Logs item is not listed on wp-admin under wp forms in comparison to your example.

    • Bill Erickson says

      Make sure you go to WPForms > Tools and enable logs. I think they changed the UI a bit since I last wrote this. You might check with WPForms support if you’re still having issues.