{"id":364676,"date":"2026-09-09T01:48:48","date_gmt":"2026-09-09T01:48:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/watrix-bot-guard\/"},"modified":"2026-09-09T01:48:13","modified_gmt":"2026-09-09T01:48:13","slug":"watrix-bot-guard","status":"publish","type":"plugin","link":"https:\/\/en-au.wordpress.org\/plugins\/watrix-bot-guard\/","author":13819045,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.4.1","stable_tag":"1.4.1","tested":"7.1","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Watrix Bot Guard","header_author":"WATRIX\u5408\u540c\u4f1a\u793e","header_description":"Log automated traffic with four kinds of rules - path flood, 404 burst, trap URL and bad User-Agent - then rate-limit and block the offending IPs. Records first so you can see the real data before blocking anyone.","assets_banners_color":"9e9d9b","last_updated":"2026-09-09 01:48:13","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/watrix.co.jp\/products","header_author_uri":"https:\/\/watrix.co.jp","rating":0,"author_block_rating":0,"active_installs":0,"downloads":51,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.4.1":{"tag":"1.4.1","author":"watrix","date":"2026-09-09 01:48:13","revision":3687464}},"upgrade_notice":{"1.3.0":"<p>Metadata and packaging only. No change to how rules are evaluated.<\/p>","1.2.0":"<p>Internal prefix change. Your settings, log and block list are migrated automatically on the first page load after the update.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3687464,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3687464,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3687464,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3687464,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.4.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3687464,"resolution":"1","location":"assets","locale":"","width":1440,"height":1180},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3687464,"resolution":"2","location":"assets","locale":"","width":1440,"height":700},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3687464,"resolution":"3","location":"assets","locale":"","width":1440,"height":900},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3687464,"resolution":"4","location":"assets","locale":"","width":1440,"height":980},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3687464,"resolution":"5","location":"assets","locale":"","width":1440,"height":1000}},"screenshots":{"1":"Overview: per-rule, per-IP, per-path and per-user-agent breakdown of the last 7 days. \/ \u6982\u8981\u753b\u9762\u3002\u30eb\u30fc\u30eb\u5225\u30fbIP\u5225\u30fb\u30d1\u30b9\u5225\u30fbUser-Agent\u5225\u306e\u96c6\u8a08\u3002","2":"Rules: the four built-in rules, each with its own paths, threshold and action. \/ \u30eb\u30fc\u30eb\u753b\u9762\u30024\u7a2e\u306e\u6a19\u6e96\u30eb\u30fc\u30eb\u3002","3":"Access log: filter by IP, by rule, or by whether the request was blocked. \/ \u30a2\u30af\u30bb\u30b9\u30ed\u30b0\u3002IP\u30fb\u30eb\u30fc\u30eb\u30fb\u906e\u65ad\u6709\u7121\u3067\u7d5e\u308a\u8fbc\u307f\u3002","4":"Server-side blocking: ready-to-paste .htaccess and nginx snippets for the blocked IPs. \/ \u30b5\u30fc\u30d0\u30fc\u5074\u3067\u906e\u65ad\u3002.htaccess \/ nginx \u7528\u30b9\u30cb\u30da\u30c3\u30c8\u3002","5":"Settings: mode switch, exclusions, bad user-agent signatures, trap URL, notifications. \/ \u8a2d\u5b9a\u753b\u9762\u3002\u30e2\u30fc\u30c9\u30fb\u9664\u5916\u30fb\u7f72\u540d\u30fb\u7f60URL\u30fb\u901a\u77e5\u3002"}},"plugin_section":[],"plugin_tags":[2359,1174,171765,600,599],"plugin_category":[54],"plugin_contributors":[268210],"plugin_business_model":[],"class_list":["post-364676","plugin","type-plugin","status-publish","hentry","plugin_tags-bot","plugin_tags-firewall","plugin_tags-rate-limit","plugin_tags-security","plugin_tags-spam","plugin_category-security-and-spam-protection","plugin_contributors-watrix","plugin_committers-watrix"],"banners":{"banner":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/banner-772x250.png?rev=3687464","banner_2x":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/banner-1544x500.png?rev=3687464","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/icon-128x128.png?rev=3687464","icon_2x":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/icon-256x256.png?rev=3687464","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/screenshot-1.png?rev=3687464","caption":"Overview: per-rule, per-IP, per-path and per-user-agent breakdown of the last 7 days. \/ \u6982\u8981\u753b\u9762\u3002\u30eb\u30fc\u30eb\u5225\u30fbIP\u5225\u30fb\u30d1\u30b9\u5225\u30fbUser-Agent\u5225\u306e\u96c6\u8a08\u3002"},{"src":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/screenshot-2.png?rev=3687464","caption":"Rules: the four built-in rules, each with its own paths, threshold and action. \/ \u30eb\u30fc\u30eb\u753b\u9762\u30024\u7a2e\u306e\u6a19\u6e96\u30eb\u30fc\u30eb\u3002"},{"src":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/screenshot-3.png?rev=3687464","caption":"Access log: filter by IP, by rule, or by whether the request was blocked. \/ \u30a2\u30af\u30bb\u30b9\u30ed\u30b0\u3002IP\u30fb\u30eb\u30fc\u30eb\u30fb\u906e\u65ad\u6709\u7121\u3067\u7d5e\u308a\u8fbc\u307f\u3002"},{"src":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/screenshot-4.png?rev=3687464","caption":"Server-side blocking: ready-to-paste .htaccess and nginx snippets for the blocked IPs. \/ \u30b5\u30fc\u30d0\u30fc\u5074\u3067\u906e\u65ad\u3002.htaccess \/ nginx \u7528\u30b9\u30cb\u30da\u30c3\u30c8\u3002"},{"src":"https:\/\/ps.w.org\/watrix-bot-guard\/assets\/screenshot-5.png?rev=3687464","caption":"Settings: mode switch, exclusions, bad user-agent signatures, trap URL, notifications. \/ \u8a2d\u5b9a\u753b\u9762\u3002\u30e2\u30fc\u30c9\u30fb\u9664\u5916\u30fb\u7f72\u540d\u30fb\u7f60URL\u30fb\u901a\u77e5\u3002"}],"raw_content":"<!--section=description-->\n<p>Pages that hold a single form \u2013 a contact page, a quote request, a download gate \u2013 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.<\/p>\n\n<p>Watrix Bot Guard catches the source of that traffic with <strong>four kinds of rules<\/strong> and lets you decide how to deal with it:<\/p>\n\n<ul>\n<li><strong>Path flood<\/strong> \u2013 the same IP hitting a specific path (e.g. <code>\/contact\/<\/code>) too many times in a short window<\/li>\n<li><strong>404 burst<\/strong> \u2013 vulnerability scanners walking through hundreds of non-existent URLs<\/li>\n<li><strong>Trap URL<\/strong> \u2013 a hidden link that is disallowed in <code>robots.txt<\/code>; only bots that ignore it will ever follow it<\/li>\n<li><strong>Bad User-Agent<\/strong> \u2013 empty user agents and signatures of scanners, headless browsers and HTTP libraries<\/li>\n<\/ul>\n\n<p>Rules can be added, edited and disabled individually, each with its own paths, threshold, action and block duration.<\/p>\n\n<h4>Record first, block later<\/h4>\n\n<p>Right after activation the plugin runs in <strong>log-only mode<\/strong>: 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 <strong>enforce mode<\/strong> \u2013 or take the generated <code>.htaccess<\/code> \/ nginx snippet and block those IPs in front of PHP.<\/p>\n\n<h4>What else is included<\/h4>\n\n<ul>\n<li>Verified crawler exclusion \u2013 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<\/li>\n<li>Allow list with CIDR and IPv6 support for your own office and your client's office<\/li>\n<li>Optional grouping by subnet (\/24 for IPv4, \/64 for IPv6)<\/li>\n<li>Early blocking \u2013 already-blocked IPs are stopped on <code>init<\/code>, before the main query runs<\/li>\n<li>Dashboard with per-rule, per-IP, per-path and per-user-agent breakdowns of the last 7 days<\/li>\n<li>Access log with filters and CSV export<\/li>\n<li>Manual block list<\/li>\n<li>Server-side snippets: Apache <code>.htaccess<\/code>, nginx <code>deny<\/code>, and a plain IP list for your analytics tool's internal-traffic filter<\/li>\n<li>Settings export \/ import as JSON to roll the same configuration out to other sites<\/li>\n<li>WP-CLI: <code>wp bot-guard top | blocks | block | unblock | mode | export | settings | cleanup<\/code><\/li>\n<li>Optional e-mail \/ webhook notification when a new IP is auto-blocked (throttled to one per hour)<\/li>\n<li>Daily cleanup of expired blocks and of log rows older than the retention period<\/li>\n<\/ul>\n\n<h4>What it deliberately does not do<\/h4>\n\n<ul>\n<li>Login protection and two-factor authentication \u2013 there are dedicated plugins for that<\/li>\n<li>Country blocking \u2013 it would require bundling a GeoIP database<\/li>\n<\/ul>\n\n<h4>Privacy<\/h4>\n\n<p>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.<\/p>\n\n<p>The verified-crawler check performs DNS lookups (reverse and forward) against the visitor's IP. Results are cached for 12 hours.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin folder to <code>\/wp-content\/plugins\/<\/code> or install it from the Plugins screen.<\/li>\n<li>Activate it.<\/li>\n<li>Go to <strong>Bot Guard \u2192 Rules<\/strong> and adjust the target path of the \"path flood\" rule to match your site (the default is <code>\/contact\/<\/code>).<\/li>\n<li>Leave the mode on <strong>log only<\/strong> for a few days.<\/li>\n<li>Check <strong>Bot Guard \u2192 Overview<\/strong>. If the traffic is concentrated on a few IPs, copy the snippet from <strong>Server-side blocking<\/strong> into your server configuration. If it is spread out, switch the mode to <strong>enforce<\/strong> in Settings.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"will%20it%20block%20real%20visitors%3F\"><h3>Will it block real visitors?<\/h3><\/dt>\n<dd><p>Not in log-only mode \u2013 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 <code>curl<\/code> or a similar tool, add its IP to the allow list or remove that signature from the bad user-agent list.<\/p><\/dd>\n<dt id=\"which%20ip%20address%20does%20it%20use%3F\"><h3>Which IP address does it use?<\/h3><\/dt>\n<dd><p>REMOTE_ADDR by default. Only switch to <code>CF-Connecting-IP<\/code> or <code>X-Forwarded-For<\/code> if your site actually sits behind Cloudflare or another reverse proxy \u2013 those headers can be forged by clients otherwise.<\/p><\/dd>\n<dt id=\"does%20it%20reduce%20server%20load%3F\"><h3>Does it reduce server load?<\/h3><\/dt>\n<dd><p>Blocking happens inside WordPress, so a blocked request still reaches PHP (but stops on <code>init<\/code>, before the query). To keep the load off entirely, paste the generated <code>.htaccess<\/code> or nginx snippet into your server configuration.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20page%20caching%3F\"><h3>Does it work with page caching?<\/h3><\/dt>\n<dd><p>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.<\/p><\/dd>\n<dt id=\"can%20i%20use%20it%20in%20japanese%3F\"><h3>Can I use it in Japanese?<\/h3><\/dt>\n<dd><p>The admin interface is currently written in Japanese and is fully translatable through the <code>watrix-bot-guard<\/code> text domain.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>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.<\/li>\n<li>Rule path patterns, signatures and other multi-line settings are sanitized line by line with sanitize_text_field() before they are stored.<\/li>\n<li>Fixed the Plugin URI, which pointed at a page that did not exist.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>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.<\/li>\n<li>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.<\/li>\n<li>New setting under Settings &gt; Exclusions to turn the exemption off, with a table showing which ranges have been fetched.<\/li>\n<li>New command <code>wp bot-guard ai<\/code> to show the status, <code>--refresh<\/code> to fetch now, and <code>--check=&lt;ip&gt; --ua=&lt;user-agent&gt;<\/code> to test a single request.<\/li>\n<li>Fixed: percent-encoded paths were mangled in the log and in path rules. A URL such as <code>\/product\/%E6%A5%B5hepa\/<\/code> was recorded as <code>\/product\/-\/<\/code>, so non-ASCII slugs could not be logged or matched correctly. Paths are now decoded before they are stored and compared.<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>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.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>First release submitted to the WordPress.org plugin directory.<\/li>\n<li>Plugin headers, LICENSE and file layout aligned with the other Watrix plugins.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Prefix changed from <code>wag_<\/code> to <code>wxag_<\/code> to comply with the WordPress.org guidelines. Existing options and tables are migrated automatically.<\/li>\n<li>readme.txt and plugin header prepared for the WordPress.org directory.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Redesigned around rules: path flood, 404 burst, trap URL, bad user-agent.<\/li>\n<li>Fake-crawler blocking, subnet grouping, early blocking on <code>init<\/code>.<\/li>\n<li>Server-side snippets, settings export\/import, WP-CLI commands.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release: log and rate-limit repeated hits on specific paths.<\/li>\n<\/ul>","raw_excerpt":"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.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/364676","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=364676"}],"author":[{"embeddable":true,"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/watrix"}],"wp:attachment":[{"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=364676"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=364676"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=364676"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=364676"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=364676"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/en-au.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=364676"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}