=== MJ Studios Captcha Protection ===
Contributors: mrnbdyyy
Tags: captcha, anti-spam, spam, woocommerce, contact form
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.1.5
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Invisible spam protection that runs entirely on your own server. A free reCAPTCHA alternative with no puzzles and no cookies.

== Description ==

Most captchas stop spam by making your visitors do the work. Tick the box, then pick out every traffic light anyway. MJ Studios Captcha Protection hands that job to the visitor's browser, so people just fill in your form and press send.

As soon as someone starts using a protected form, their browser works through a small proof-of-work calculation in the background. On most devices it takes about a second, usually while the person is still typing. Bots that post straight to your forms never run it, so they arrive without a valid answer and get turned away.

All of it happens on your own server. The plugin never talks to Google, Cloudflare or anyone else, and it sets no cookies. There's no account to create and no API key to paste in. It's free.

We made it for the client sites we build and look after at MJ Studios. Now you can use it on yours.

= A drop-in replacement for reCAPTCHA =

If your site uses Google reCAPTCHA, hCaptcha or Cloudflare Turnstile today, this plugin does the same job without loading anything from outside your site. Switch the old captcha off, activate this one, and the forms below are protected straight away. You don't have to edit a single form.

= Works with the forms you already have =

* WordPress login, registration and lost password
* Comments
* WooCommerce login, registration and lost password
* WooCommerce classic checkout (off by default, one tick to turn it on)
* Elementor Pro forms
* Contact Form 7
* WPForms
* Any other form, using the `[mjscp_captcha]` shortcode and `mjscp_verify()`

Protection is on with sensible defaults from the moment you activate it.

= What your visitors notice =

Ideally, nothing.

* Nothing loads until someone interacts with a form, so your page speed stays where it was.
* The widget stays hidden and only appears if verification fails.
* If someone presses submit before the answer is ready, the form waits a moment and then sends itself.
* Each answer works once. The widget then fetches a fresh challenge, so AJAX forms can be sent again without a page reload.
* The work runs in Web Workers using the browser's built-in crypto, with a pure JavaScript fallback for older browsers and sites on plain HTTP.
* Page caching is fine, because challenges are fetched fresh when a form is used.

= Extra checks behind the scenes =

* A hidden honeypot field that only bots fill in
* A minimum time on the form, because nobody writes a message in half a second
* A spam score that counts links in messages and notices requests with missing browser headers
* Automatic IP blocking after repeated failures (by default, 5 failures in an hour earns a 24 hour block)
* An allowlist for single IPs and IPv4 ranges
* Support for Cloudflare and other proxies, so blocks land on the real visitor IP

You can't lock yourself out. Login forms ignore IP blocks, and an IP an administrator has used is never blocked automatically.

= See what it stopped =

The Overview screen shows how your forms held up over the last 7, 14 or 30 days. You get totals compared with the period before, a daily chart you can hover for each day's numbers, the block rate, the IPs that failed most and a breakdown by form and by reason.

The Activity screen lists every check, newest first, and you can filter it by result, form or IP. Blocked IPs have their own screen, where you can block an address for a day, a week, a month or for good, and lift a block again.

The admin screens are part of the plugin and load nothing from outside your site, so they open quickly. They work with JavaScript switched off too.

= Privacy =

The plugin was designed with privacy laws such as the GDPR in mind.

* It sets no cookies and stores nothing in the visitor's browser.
* It makes no requests to outside services, so visitor data stays on your server.
* The verification log keeps the IP address, browser user agent, form name and result for 30 days by default. You can shorten that to one day or switch the log off.
* It remembers the last 20 IP addresses your administrators used, only so it never blocks them.
* It adds suggested wording for your privacy policy under Settings > Privacy.
* Deleting the plugin removes its tables and settings, unless you choose to keep them.

Whether your site meets the GDPR depends on far more than one plugin, so that part is still yours to check. This plugin's share of it is small and easy to explain in your privacy policy.

= External services =

None. This plugin does not connect to any third-party service.

= Trademarks =

Google reCAPTCHA, hCaptcha, Cloudflare Turnstile, WooCommerce, Elementor, Contact Form 7 and WPForms are trademarks of their owners. This plugin is not affiliated with or endorsed by any of them.

== Installation ==

1. In your WordPress admin, go to Plugins > Add New, search for "MJ Studios Captcha Protection" and click Install Now. You can also upload the zip under Plugins > Add New > Upload Plugin.
2. Activate it.
3. Go to Captcha Protection > Settings and choose which forms to protect. The defaults suit most sites.

If your site sits behind Cloudflare or another proxy, set "Visitor IP source" so blocking uses the real visitor IP.

== Frequently Asked Questions ==

= Can it replace Google reCAPTCHA? =

Yes, for the forms listed above. Turn your reCAPTCHA plugin off, activate this one, and those forms are protected. Leaving both on means your visitors still get the reCAPTCHA check, which defeats the point.

= Is it really free? =

Yes. Every feature on this page is included, with no limit on forms or submissions and no sign-up.

= Does it help with the GDPR? =

It's built to collect as little as possible. Nothing leaves your server, and the only log is a short one you can cut down further or switch off. Many site owners rely on legitimate interest for this kind of security log (Recital 49 of the GDPR mentions network security). Your own setup decides that, so check with whoever handles privacy for your site.

= Does it work with page caching? =

Yes. Challenges come fresh from a REST endpoint when a visitor uses a form, so cached pages are fine.

= My site is behind Cloudflare. Do I need to change anything? =

One setting. Set "Visitor IP source" to CF-Connecting-IP. Otherwise every visitor looks like a Cloudflare server, and blocking would hit Cloudflare's IPs instead of the spammer's.

= What if a visitor has JavaScript turned off? =

Protected forms need JavaScript to produce an answer, so submissions without one are rejected.

= How can I see it working? =

Add `?mjscp_debug=1` to any page URL to show the widget and its status. Every verification also shows up on the Activity screen.

= How do I protect my own custom form? =

Place `[mjscp_captcha]` inside the form, or `echo mjscp_widget();` in PHP. When you process the form, call `mjscp_verify()`. It returns `true` or a `WP_Error`.

= Can I lock myself out? =

No. Login forms ignore IP blocks, and IPs that administrators have used are never blocked automatically. You still need a valid answer and the right password to log in.

= What happens to blocking if I switch the log off? =

Automatic blocking counts failures from the log, so it stops too. Manual blocks and the allowlist keep working.

= Does it support the WooCommerce block checkout? =

Not yet. The classic checkout is supported and is off by default.

= Will it slow down older phones? =

On medium difficulty most devices finish in about a second, usually while the visitor is still typing. Choose Low difficulty for the lightest load.

== Developer hooks ==

* `mjscp_form_enabled` (filter): enable or disable a form key.
* `mjscp_pre_check` (filter): short-circuit verification.
* `mjscp_score` (filter): adjust the spam score.
* `mjscp_error_message` (filter): change the message shown on failure.
* `mjscp_is_allowlisted` (filter): allowlist an IP programmatically.
* `mjscp_auto_attach_selectors` (filter): attach the widget to extra forms by CSS selector.
* `mjscp_max_number` (filter): fine-tune difficulty.
* `mjscp_checked` (action): runs after each verification.

== Screenshots ==

1. Overview: totals against the previous period, a daily chart and the block rate.
2. Activity: every check, with filters and the details of each one.
3. Settings: a switch for each form, showing whether its plugin is active.
4. Blocked IPs: block an address by hand or lift a block.

== Changelog ==

= 1.1.5 =
* Settings: forms from plugins that aren't active now show as off and locked, with a note that they start once you activate the plugin. Your choice is kept until then.
* The test view you get with ?mjscp_debug=1 now says what visitors actually see, so Invisible mode no longer looks like a visible status line.

= 1.1.4 =
* Removed the Plugin URI header, which pointed to the same page as Author URI.

= 1.1.3 =
* Corrected the contributor username in the readme.

= 1.1.2 =
* Activity now marks rows from an IP you've already blocked with "IP blocked" instead of offering to block it again.
* Fixed the missing space between the two cards on the Blocked IPs screen.

= 1.1.1 =
* Rewrote the database queries behind the Overview and Activity screens and the uninstall routine, so Plugin Check now reports no warnings.
* The screens show the same data as before, and uninstalling still removes data only when Clean uninstall is on.

= 1.1.0 =
* New admin design with four screens: Overview, Activity, Blocked IPs and Settings.
* Overview compares totals with the previous period and adds a daily chart you can hover, the block rate and the IPs that failed most.
* New Activity screen with filters, pages and the full details of each check.
* Settings show whether each form's plugin is active, and a save bar appears when you change something.
* Block an IP for 24 hours, 7 days, 30 days or permanently.
* One-click fix for sites behind Cloudflare.
* Tested with WordPress 7.1 and PHP 7.4 to 8.5.

= 1.0.0 =
* First public release.

== Upgrade Notice ==

= 1.1.5 =
Clearer Settings for forms from plugins you don't use, and a labelled test view. Your settings stay as they are.

= 1.1.4 =
A plugin header correction only. Nothing changes on your site.

= 1.1.3 =
A readme correction only. Nothing changes on your site.

= 1.1.2 =
Two small fixes to the admin screens. Your settings and log stay as they are.

= 1.1.1 =
A small fix to the database queries in the admin screens and the uninstall routine. Your settings and log stay as they are.

= 1.1.0 =
A redesigned admin with a new Activity screen. Your settings stay as they are.

= 1.0.0 =
First public release.
