Must-Have Captcha Documentation
Current Version: 0.1.9
Text Domain: mhcaptcha
Must-Have Captcha is an intelligent form protection solution for WordPress that distinguishes real humans from bots based on natural browsing behavior—without annoying puzzles, image selections, or checkboxes.
Unlike cloud-based captcha services, all protection happens on your server. No data sharing with third parties, and full GDPR compliance out of the box.
Protect WordPress comments, Contact Form 7, WooCommerce checkout, user registrations, login pages, and more—all while tracking suspicious submissions with detailed logging to help you identify spam patterns and replay legitimate requests that were mistakenly blocked.
How it works
The frontend script collects lightweight interaction signals and stores a signed cookie. On POST, the server computes a score and compares it to the threshold:
- Signals: user behavior, like mouse move and site interactions
- Content analysis: POST field patterns, URLs, shorteners, spam keywords/phrases, capitalization, repetition
- Cloud rules: Tor exits, RBL CIDR ranges, IP whitelist with CIDR
- Cookie format: base64EncodedJson|sha256Signature tied to user agent
- Thresholds: Basic 15, Normal 30, Strict 60; adjustable per context via
mhcaptcha/threshold
Getting Started
Choose the right plan
Must-Have Captcha is an intelligent form protection plugin based on real human interactions. There are 2 available plans:
Single plan
You can use Must-Have Captcha with the Single plan for 1 WordPress site. It's perfect if you have a single site or want to test the plugin's capabilities.
Unlimited plan
We created the Unlimited plan for freelancers and agencies who manage multiple sites. This plan can be used on unlimited sites, perfect for protecting forms across all your WordPress installations.
Install Must-Have Captcha
- Login to My account on musthaveplugins.com
- Download the Must-Have Captcha installer from the Must-Have Captcha box
- Login to your WordPress admin where you would like to install Must-Have Captcha
- Go to Plugins > Add new and click to upload plugin
- Select the downloaded ZIP file (must-have-captcha.zip) and click to install
- Activate the plugin - it works immediately with default settings
Configuration
Must-Have Captcha works automatically after installation with no configuration required. However, you can fine-tune the protection to suit your site's needs from the plugin settings page in WordPress admin.
Protection Level
Choose how strict the plugin should be when blocking suspicious submissions by adjusting the threshold setting:
- Basic: Basic bot protection without affecting legitimate users, best for personal blogs and low-traffic websites
- Normal: Balanced protection that blocks most automated attacks, ideal for business websites and community sites
- Strict: Maximum protection against sophisticated bots and spam, recommended for e-commerce sites and websites with high spam traffic
Under the hood, the selected option stores a numeric threshold (15, 30, or 60) and the frontend compares every request's trust score against this value via the mhcaptcha/threshold filter.
Logged In Users
When enabled, the plugin will skip captcha validation for logged-in users. This is useful for sites where users have already been verified through the registration process.
The checkbox maps to the disable_for_logged_in option stored via AJAX updates and is respected during trust checks in the frontend logic.
Summary Reports
Configure how often Must-Have Captcha emails a summary of blocked requests. The available options are Daily, Weekly, Monthly, or Disabled.
Changing this setting updates the summary_frequency option and automatically schedules or stops cron jobs that trigger the summary sender.
The summary email includes request counts by type and top IPs collected since the last report before resetting the window.
Expiry
Determine how long to keep blocked requests in the database for review. Options range from 1 day to keeping forever:
- 1 day: Minimal storage period, saves database space but gives less time to review blocked submissions
- 1 week: Short-term storage that works for most sites to review blocked requests
- 1 month: Standard setting for sites with moderate traffic that need more time to review
- 1 year: Long-term storage for thorough analysis of blocked submissions
- Keep forever: Never delete blocked requests, maximum ability to review all blocked submissions
The expiry value is stored in the expiry option and enforced by the scheduled cleanup job.
Custom 403 Page
When enabled, you can select a WordPress page to display when submissions are blocked.
The frontend checks both the custom_403_enabled flag and the selected page ID when rendering the blocked template.
Custom Rules
Create custom protection rules to whitelist specific URLs or IP addresses:
- Type: URL or IP address
- Value: The URL pattern or IP address (supports CIDR notation for IP ranges)
- Protection Level: How strictly to apply protection to this rule
- Note: Optional information to remember why you created the rule
Rules are stored as an option and processed sequentially during request validation. The frontend checks rules by order priority and applies the first matching rule's protection level.
Protection Levels for Custom Rules
When creating custom rules, you can choose from these protection levels:
- Never Block: Always allow requests, regardless of suspicion level (whitelist)
- Basic: Block only highly suspicious requests (threshold: 15)
- Normal: Apply balanced protection (threshold: 30)
- Strict: Maximum protection against bots (threshold: 60)
- Block & Ignore: Always block but don't store in the blocked requests database
- No Logging: Use the global protection level but do not log blocked requests
Blocked Requests
The Blocked Requests dashboard shows all submissions that have been blocked by the plugin. For each blocked request, you can view:
- URL: The page where the submission was attempted
- Type: The form type that was blocked (comment, contact form, registration, etc.)
- IP: The visitor's IP address
- Score: The trustability score assigned (lower scores indicate more suspicious behavior)
- User Agent: Information about the browser and device used
- Date: When the submission was blocked
- Form Data: The actual content of the blocked submission (with sensitive data masked)
- Request Headers: HTTP headers sent with the submission request
You can filter, sort, and search through blocked requests to identify patterns of spam attacks or find legitimate submissions that were incorrectly blocked.
License Management
Connect your site to activate your Must-Have Captcha license. Once connected, the plugin will receive automatic updates and access to cloud-based protection rules.
If you need to move your license to a different site, you can disconnect it from the settings page and reconnect it on your new installation.
Replaying Blocked Requests
One of Must-Have Captcha's unique features is the ability to replay blocked submissions that were mistakenly flagged as spam:
- Go to the Blocked Requests tab in the plugin dashboard
- Click "View Details" on any blocked submission
- Review the submission content to ensure it's legitimate
- Click "Accept" to process the submission as if it was just submitted
This feature ensures you never lose legitimate form submissions due to false positives, particularly useful for contact forms, orders, or registrations from real users who might have triggered protection rules.
Note: Requests containing masked sensitive data (like passwords, credit card numbers, etc.) cannot be replayed because sensitive data is not stored for security reasons.
Available Filters
Customize Must-Have Captcha's behavior using these developer hooks:
mhcaptcha/threshold
Modify the captcha threshold for specific pages, post types, or conditions:
// Modify the captcha threshold based on page context
add_filter('mhcaptcha/threshold', function($threshold) {
if (defined('DOING_AJAX') && $_POST['action'] == 'my-whitelisted-ajax-action'){
return 15; // Basic protection for whitelisted AJAX action
}
return $threshold; // Default for everything else
});
mhcaptcha/score
Fine-tune the scoring system for specific user groups or contexts:
// Customize captcha scoring logic
add_filter('mhcaptcha/score', function($score, $cookie_value) {
// Add points for specific countries by Cloudflare country id
if (isset($_SERVER['HTTP_CF_IPCOUNTRY']) && $_SERVER['HTTP_CF_IPCOUNTRY'] == 'DE') {
$score += 10; // Add points for visitors from trusted countries
}
return $score;
}, 10, 2);
Bypass Strategies
Recommended ways to bypass protection for trusted scenarios:
- Custom Rules: Add a URL rule with protection set to Never Block to always allow specific endpoints.
- Threshold Filter: Lower or disable threshold in context via
mhcaptcha/threshold(e.g., return-PHP_INT_MAXfor whitelisted AJAX). - Request Types Whitelist: Server-side rules can whitelist specific URLs; when matched, the plugin forces validity internally.
- Loopback/Admin: WordPress loopback requests and admin users are automatically trusted.
mhcaptcha/store_blocked_request
Control whether blocked requests should be stored in the database:
// Prevent storing certain blocked requests
add_filter('mhcaptcha/store_blocked_request', function($store_request) {
// Don't store blocked requests from specific URLs
if (strpos($_SERVER['REQUEST_URI'], '/high-volume-form/') !== false) {
return false; // Don't store these blocked requests
}
return $store_request; // Default behavior for other requests
});
mhcaptcha/blocked_status_header
Customize the HTTP status code sent when a request is blocked:
// Change the HTTP status code for blocked requests
add_filter('mhcaptcha/blocked_status_header', function($status_code) {
// Use 429 (Too Many Requests) instead of 403 (Forbidden)
return 429;
});
mhcaptcha/default_score
Modify the default score assigned to requests:
// Change the default score
add_filter('mhcaptcha/default_score', function($default_score) {
// Set a more lenient default score
return 15;
});
mhcaptcha/cloud_rules
Customize the cloud rules used for IP-based filtering:
// Modify cloud rules
add_filter('mhcaptcha/cloud_rules', function($rules) {
// Add custom IPs to the whitelist
if (!isset($rules['whitelist'])) {
$rules['whitelist'] = array();
}
// Add your office IP range to whitelist
$rules['whitelist'][] = '203.0.113.0/24';
return $rules;
});
mhcaptcha/get_template
Customize the HTML templates used by the plugin:
// Add a custom message to the blocked template
add_filter('mhcaptcha/get_template', function($template_html, $template_name) {
// Only modify the blocked template
if ($template_name === 'blocked') {
// Simply add a message at the end of the template
$template_html .= '<div class="custom-message">If you believe this is an error, please contact us.</div>';
}
return $template_html;
}, 10, 2);
mhcaptcha/get_svg
Customize SVG icons used in the plugin interface:
// Customize SVG icons
add_filter('mhcaptcha/get_svg', function($svg, $file) {
// Replace the lock icon with a custom version
if ($file === 'lock') {
return '<svg><!-- Your custom SVG code here --></svg>';
}
return $svg;
}, 10, 2);
mhcaptcha/request_type
Customize how request types are detected and categorized:
// Customize request type detection
add_filter('mhcaptcha/request_type', function($type, $post_data, $url, $headers) {
// Identify a custom form submission
if (isset($post_data['my_custom_form_id'])) {
return 'custom_form';
}
return $type;
}, 10, 4);
mhcaptcha/api_request_args
Customize API request arguments when communicating with the Must-Have Captcha API:
// Customize API request arguments
add_filter('mhcaptcha/api_request_args', function($args) {
// Increase timeout for API requests
$args['timeout'] = 30;
return $args;
});
mhcaptcha/sensitive_input_patterns
Define patterns for sensitive data that should be masked in stored requests:
// Add custom sensitive data patterns
add_filter('mhcaptcha/sensitive_input_patterns', function($patterns) {
// Add pattern for custom sensitive field
$patterns[] = '/ssn\\d*|social.*security/i';
return $patterns;
});
mhcaptcha/custom_rules
Programmatically add or modify custom rules:
// Add custom rules programmatically
add_filter('mhcaptcha/custom_rules', function($rules) {
// Add a rule to whitelist specific API endpoint
$rules[] = array(
'type' => 'url',
'value' => '/wp-json/custom-api/',
'protection' => 'none', // No protection for this endpoint
'order' => 5, // High priority
'note' => 'API Whitelist - Added programmatically'
);
return $rules;
});
mhcaptcha/option/{key}
Filter the value of any option when retrieved via mhcaptcha_get_option(). Replace {key} with the option name:
// Modify option values when retrieved
add_filter('mhcaptcha/option/threshold', function($value) {
// Force a specific threshold for certain conditions
if (defined('MY_SPECIAL_MODE')) {
return 60; // Always use strict mode
}
return $value;
});
mhcaptcha/option/not_set/{key}
Filter the default value when an option is not set. Replace {key} with the option name:
// Provide custom defaults for unset options
add_filter('mhcaptcha/option/not_set/threshold', function($default) {
// Use custom default threshold
return 45;
});
mhcaptcha/update_option/{key}
Filter option values before they are saved. Replace {key} with the option name:
// Validate or modify values before saving
add_filter('mhcaptcha/update_option/threshold', function($value) {
// Ensure threshold is within acceptable range
return max(10, min(100, intval($value)));
});
Request Types
Requests are classified using JSON rules fetched from the API and cached in the mhcaptcha_request_types option. Detection considers URL, POST data, headers, and credentials.
Detection Flow
- Rules source: API via
MH_Captcha_Api::update_request_rules(); stored in options. - Matching: URL/POST/headers/credentials rules with optional conditions.
- Caching: URL-based caching for performance.
- Labels: Human-friendly labels registered from rules.
- Filter: Fallback filter
mhcaptcha/request_typecan override the detected type.
Whitelisting by Rules
Whitelist rules in the JSON mark requests as valid. Internally, the plugin reduces the threshold to allow the request to pass.
Available Actions
Must-Have Captcha provides action hooks that you can use to extend functionality:
mhcaptcha/send_daily_summary
This action is triggered when the daily summary report is scheduled to be sent. You can hook into this to perform additional tasks when summaries are generated:
// Hook into the daily summary generation
add_action('mhcaptcha/send_daily_summary', function() {
// Perform additional tasks when daily summaries are sent
// For example, log summary generation to a custom log
error_log('Must-Have Captcha daily summary generated at ' . date('Y-m-d H:i:s'));
});
mhcaptcha/send_weekly_summary
Similar to the daily summary action, but triggered for weekly summary reports:
// Hook into the weekly summary generation
add_action('mhcaptcha/send_weekly_summary', function() {
// Perform additional tasks when weekly summaries are sent
});
mhcaptcha/send_monthly_summary
Triggered when monthly summary reports are generated:
// Hook into the monthly summary generation
add_action('mhcaptcha/send_monthly_summary', function() {
// Perform additional tasks when monthly summaries are sent
});
mhcaptcha/option/{key}/updated
This action fires when a specific option is updated via mhcaptcha_update_option(). Replace {key} with the option name:
// Hook into specific option updates
add_action('mhcaptcha/option/threshold/updated', function($value) {
// Perform tasks when threshold is changed
error_log('Protection level changed to: ' . $value);
});
mhcaptcha/option/updated
This action fires when any option is updated, providing both the key and value:
// Hook into all option updates
add_action('mhcaptcha/option/updated', function($key, $value) {
// Perform tasks when any option changes
error_log('Option ' . $key . ' was updated to: ' . $value);
}, 10, 2);
mhcaptcha/uninstall
This action runs during the plugin uninstallation process. You can hook into it to clean up any custom data or settings you've added:
// Clean up custom data during uninstallation
add_action('mhcaptcha/uninstall', function() {
// Remove any custom options or database entries you've created
delete_option('my_custom_mhcaptcha_setting');
});
Cron Jobs
Scheduled Events
- mhcaptcha_daily_cleanup: Deletes expired blocked requests based on
expiryoption. - mhcaptcha_daily_rules_update: Updates request type and cloud rules from API.
- Summary senders:
mhcaptcha/send_daily_summary,mhcaptcha/send_weekly_summary,mhcaptcha/send_monthly_summaryscheduled based onsummary_frequency.
Compatibility Features
Must-Have Captcha includes several compatibility features to ensure it works well with other plugins and server environments:
WordPress Loopback Request Detection
The plugin automatically detects and allows WordPress loopback requests (when WordPress makes HTTP requests to itself). This prevents the plugin from blocking important internal WordPress functionality like:
- Site Health checks
- Auto-updates
- Post previews
- REST API internal calls
This is handled by adding a special header to all WordPress HTTP requests and checking for this header when processing incoming requests.
Cross-Server Headers Compatibility
Must-Have Captcha includes a custom implementation of get_all_headers() that works reliably across different server environments, including:
- Apache with mod_php
- Nginx with PHP-FPM
- CGI/FastCGI environments
- Various hosting configurations
This ensures consistent behavior regardless of your server setup.
Must-Have Cookie Compatibility
If you're also using the Must-Have Cookie plugin for GDPR/cookie compliance, Must-Have Captcha automatically registers its cookies as "essential" so they continue to function even when a visitor hasn't accepted cookies. This ensures your forms remain protected while complying with privacy regulations.
Cookies & Privacy
The plugin stores a signed, tamper-resistant interaction cookie. Name is derived from site host (e.g., __abcdef), and contents are hashed with user agent. No data is sent to third parties; updates and rules are fetched from Must‑Have Plugins API using minimal headers.
With Must‑Have Cookie installed, the captcha cookie is marked as essential via the mhcookie/purpose filter to keep protection active before consent.
Changelog
0.1.9 – 2025.11.19.
[IMPROVE] Minor bugfixes
0.1.8 – 2025.11.02.
[IMPROVE] Improve scoring system
0.1.7 – 2025.08.08.
[FIX] Minor bugfixes
[IMPROVE] Human spam detection
0.1.6 – 2025.05.24.
[IMPROVE] Improve detection system
[IMPROVE] Improve dashboard resource usage
0.1.5 – 2025.05.13.
[IMPROVE] Auto whitelist
0.1.4 – 2025.05.06.
[FIX] Minor bugfixes
0.1.3 – 2025.04.25.
Initial public beta release