=== Watrix Bot Guard ===
Contributors: watrix
Tags: bot, spam, security, rate-limit, firewall
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.4.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Log automated traffic with four kinds of rules, then rate-limit and block the offending IPs. Record first, block once you have seen the real data.

== Description ==

Pages that hold a single form – a contact page, a quote request, a download gate – get hammered by scanners and spam bots. The first real damage is to your analytics: page views are inflated and you can no longer read what visitors actually do.

Watrix Bot Guard catches the source of that traffic with **four kinds of rules** and lets you decide how to deal with it:

* **Path flood** – the same IP hitting a specific path (e.g. `/contact/`) too many times in a short window
* **404 burst** – vulnerability scanners walking through hundreds of non-existent URLs
* **Trap URL** – a hidden link that is disallowed in `robots.txt`; only bots that ignore it will ever follow it
* **Bad User-Agent** – empty user agents and signatures of scanners, headless browsers and HTTP libraries

Rules can be added, edited and disabled individually, each with its own paths, threshold, action and block duration.

= Record first, block later =

Right after activation the plugin runs in **log-only mode**: every rule records what it sees and nobody is blocked. Look at the dashboard after a few days, see whether the traffic comes from a handful of IPs or is spread out, and only then switch to **enforce mode** – or take the generated `.htaccess` / nginx snippet and block those IPs in front of PHP.

= What else is included =

* Verified crawler exclusion – Googlebot, Bingbot, Applebot and others are let through only after a reverse-then-forward DNS check; a crawler that claims to be Googlebot but fails the check is treated as a fake and blocked
* Allow list with CIDR and IPv6 support for your own office and your client's office
* Optional grouping by subnet (/24 for IPv4, /64 for IPv6)
* Early blocking – already-blocked IPs are stopped on `init`, before the main query runs
* Dashboard with per-rule, per-IP, per-path and per-user-agent breakdowns of the last 7 days
* Access log with filters and CSV export
* Manual block list
* Server-side snippets: Apache `.htaccess`, nginx `deny`, and a plain IP list for your analytics tool's internal-traffic filter
* Settings export / import as JSON to roll the same configuration out to other sites
* WP-CLI: `wp bot-guard top | blocks | block | unblock | mode | export | settings | cleanup`
* Optional e-mail / webhook notification when a new IP is auto-blocked (throttled to one per hour)
* Daily cleanup of expired blocks and of log rows older than the retention period

= What it deliberately does not do =

* Login protection and two-factor authentication – there are dedicated plugins for that
* Country blocking – it would require bundling a GeoIP database

= Privacy =

The plugin stores the IP address, request path, user agent and referrer of requests that match a rule, in your own database, for the retention period you set (30 days by default). Nothing is sent to WATRIX or to any third party. If you configure a webhook URL, block notifications are sent to that URL and nowhere else. An optional "anonymize IP" setting masks the last octet before storing.

The verified-crawler check performs DNS lookups (reverse and forward) against the visitor's IP. Results are cached for 12 hours.

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/` or install it from the Plugins screen.
2. Activate it.
3. Go to **Bot Guard → Rules** and adjust the target path of the "path flood" rule to match your site (the default is `/contact/`).
4. Leave the mode on **log only** for a few days.
5. Check **Bot Guard → Overview**. If the traffic is concentrated on a few IPs, copy the snippet from **Server-side blocking** into your server configuration. If it is spread out, switch the mode to **enforce** in Settings.

== Frequently Asked Questions ==

= Will it block real visitors? =

Not in log-only mode – nothing is blocked at all. In enforce mode the default thresholds (20 hits on one page within 60 minutes, 30 404s within 10 minutes) are far beyond what a human does. Logged-in users and verified search-engine crawlers are excluded, and you can add your own IP ranges to the allow list. If your monitoring service fetches your site with `curl` or a similar tool, add its IP to the allow list or remove that signature from the bad user-agent list.

= Which IP address does it use? =

`REMOTE_ADDR` by default. Only switch to `CF-Connecting-IP` or `X-Forwarded-For` if your site actually sits behind Cloudflare or another reverse proxy – those headers can be forged by clients otherwise.

= Does it reduce server load? =

Blocking happens inside WordPress, so a blocked request still reaches PHP (but stops on `init`, before the query). To keep the load off entirely, paste the generated `.htaccess` or nginx snippet into your server configuration.

= Does it work with page caching? =

Rule evaluation runs on uncached requests only. Cached pages served by a caching plugin or CDN are never counted, so the plugin is most effective on pages that are not cached, such as forms.

= Can I use it in Japanese? =

The admin interface is currently written in Japanese and is fully translatable through the `watrix-bot-guard` text domain.

== Screenshots ==

1. Overview: per-rule, per-IP, per-path and per-user-agent breakdown of the last 7 days. / 概要画面。ルール別・IP別・パス別・User-Agent別の集計。
2. Rules: the four built-in rules, each with its own paths, threshold and action. / ルール画面。4種の標準ルール。
3. Access log: filter by IP, by rule, or by whether the request was blocked. / アクセスログ。IP・ルール・遮断有無で絞り込み。
4. Server-side blocking: ready-to-paste .htaccess and nginx snippets for the blocked IPs. / サーバー側で遮断。.htaccess / nginx 用スニペット。
5. Settings: mode switch, exclusions, bad user-agent signatures, trap URL, notifications. / 設定画面。モード・除外・署名・罠URL・通知。

== Changelog ==

= 1.4.1 =
* Removed the "Tested up to" header from the main plugin file. It now lives only in readme.txt, which is the supported place for it.
* Rule path patterns, signatures and other multi-line settings are sanitized line by line with sanitize_text_field() before they are stored.
* Fixed the Plugin URI, which pointed at a page that did not exist.

= 1.4.0 =
* AI assistants are no longer blocked. When someone asks ChatGPT, Claude or Perplexity a question and the answer cites your site, that visit is a referral - not an attack. Requests from ChatGPT-User, OAI-SearchBot, GPTBot, Claude-User, Claude-SearchBot, ClaudeBot, Perplexity-User and PerplexityBot are now exempt.
* Verification uses the source IP ranges each provider publishes, not the User-Agent alone, so the exemption cannot be claimed by spoofing a name. The lists refresh once a day. If a list cannot be fetched, the request is allowed through rather than blocked, so a network failure never costs you a referral.
* New setting under Settings > Exclusions to turn the exemption off, with a table showing which ranges have been fetched.
* New command `wp bot-guard ai` to show the status, `--refresh` to fetch now, and `--check=<ip> --ua=<user-agent>` to test a single request.
* Fixed: percent-encoded paths were mangled in the log and in path rules. A URL such as `/product/%E6%A5%B5hepa/` was recorded as `/product/-/`, so non-ASCII slugs could not be logged or matched correctly. Paths are now decoded before they are stored and compared.

= 1.3.1 =
* Fixed a fatal error that could take the whole site down when a class file was missing (for example during a partial update). The plugin now checks its own files first and disables only itself, showing an admin notice instead.

= 1.3.0 =
* First release submitted to the WordPress.org plugin directory.
* Plugin headers, LICENSE and file layout aligned with the other Watrix plugins.

= 1.2.0 =
* Prefix changed from `wag_` to `wxag_` to comply with the WordPress.org guidelines. Existing options and tables are migrated automatically.
* readme.txt and plugin header prepared for the WordPress.org directory.

= 1.1.0 =
* Redesigned around rules: path flood, 404 burst, trap URL, bad user-agent.
* Fake-crawler blocking, subnet grouping, early blocking on `init`.
* Server-side snippets, settings export/import, WP-CLI commands.

= 1.0.0 =
* Initial release: log and rate-limit repeated hits on specific paths.

== Upgrade Notice ==

= 1.3.0 =
Metadata and packaging only. No change to how rules are evaluated.

= 1.2.0 =
Internal prefix change. Your settings, log and block list are migrated automatically on the first page load after the update.
