What this plugin does
Event calendars generate an enormous URL space. Every calendar view can be combined with almost any date, and each view renders “previous” and “next” links — so a crawler can walk forward and backward through dates indefinitely. Each of those is a distinct, usually empty, dynamic page that fires PHP and queries the database. The result is wasted bandwidth, high server load, and crawl budget spent on pages with no real content.
Calendar Crawl Guard supports both The Events Calendar and the All-in-One Event Calendar (Timely). It intercepts these requests early in the WordPress request lifecycle — before the main database query runs — and applies one of three responses:
- 301 redirect for alternate-but-equivalent paths that have a clear canonical target (duplicate query strings, alternate presentation views, recurring-event instance permalinks).
- 410 Gone (or 404) for the infinite date tree — calendar dates outside a sensible window. 410 tells crawlers to drop the URL and stop revisiting.
- 403 Forbidden (optional) for known bad bots, matched by user-agent.
It also feeds indexing authority to your canonical pages using canonical tags and noindex hints on non-primary views, and can add targeted robots.txt rules for feeds and filter parameters.
Supported calendars
Both calendars are detected automatically; the matching rules run only for whichever is active. Each calendar’s native views are normalized to a common vocabulary so one set of settings governs both:
| Normalized view | The Events Calendar | All-in-One Event Calendar | Handling |
|---|---|---|---|
| month | month | month | date-checked |
| day | day | oneday | date-checked |
| week | week | week | date-checked |
| list | list / upcoming / past | agenda | primary (kept) |
| photo | photo | posterboard | redirected to primary |
| map | map | stream | redirected to primary |
For the All-in-One Event Calendar the date is taken from exact_date or derived from the month_offset / week_offset / oneday_offset navigation parameters, so deep forward/backward navigation falls outside the window and is rejected.
Setup steps
- Make sure The Events Calendar or the All-in-One Event Calendar is installed and active.
- Go to Settings → Calendar Crawl Guard.
- Confirm the canonical window (default: current month, ±6 months). Dates outside this window are rejected.
- Review which views are kept, redirected, and date-checked. The defaults are sensible for most sites.
- Use the Test a URL tool on the settings page to confirm the verdict for any calendar URL before going live.
- Enable the plugin (the master switch) and watch your server logs / analytics for the drop in crawler hits.
Recommended: keep a page cache (Varnish, NGINX FastCGI cache, or a caching plugin) in front of the site, and leave “Send cache headers on rejected responses” enabled so repeat bot hits are served from cache without ever touching PHP.
Configuration reference
| Setting | Default | What it controls |
|---|---|---|
| Enable crawl guard | On | Master switch. When off, no requests are intercepted. |
| Canonical window (months) | 6 | How many months before and after the current month stay crawlable. Calendar dates outside this range are rejected. |
| Skip logged-in users | On | Never intercept requests from logged-in users so editors can browse freely. |
| Date-checked views | month, day, week | Views that map to a specific date and are subject to the canonical window. |
| Out-of-window response | 410 Gone | Status returned for dates outside the window. 410, 404, or 301 to the archive. |
| Redirected views | photo, map | Alternate presentation views that 301 to the primary (list) view of the same scope. |
| Strip duplicate query strings | On | 301-redirects URLs carrying the Tribe Bar / view filter parameters to a clean canonical URL (only when pretty permalinks are active). |
| Redirect recurring instances | On | 301-redirects per-date and /all/ recurring-event permalinks to the base event. |
| Allow iCal feeds | On | When off, iCal / Outlook feed URLs are rejected. When on, feeds are allowed and (optionally) disallowed in robots.txt. |
| Block bad user agents (403) | Off | Optional. Returns 403 for requests whose user-agent matches your block list. |
| Add canonical tags | On | Outputs a rel=canonical link on kept event archive views (skipped if Yoast or Rank Math is managing canonicals). |
| Noindex non-primary views | On | Adds a noindex hint to kept-but-secondary views (dated month/day/week, paginated pages) via The Events Calendar’s own filter. |
| robots.txt rules | On | Appends Disallow rules for feeds and filter parameters to the virtual robots.txt. |
| Send cache headers on rejects | On | Adds Cache-Control / Expires headers to 301 / 404 / 410 / 403 responses so a front cache can serve repeats. |
| Cache TTL (seconds) | 3600 | Lifetime for the cache headers above. |
| Enable logging | Off | Records intercepted requests to a database table for review. Adds a write per intercept — leave off during heavy bot storms unless you need the data. |
Troubleshooting
A page I want indexed is being rejected
Use the Test a URL tool to see the verdict and the reason. Widen the canonical window, remove the relevant view from the “date-checked” or “redirected” lists, or switch the out-of-window response to a 301 so authority is preserved.
I see a redirect loop
The engine never redirects a URL to itself, but if you have another redirect plugin or server rule touching the same paths, disable one of them. Confirm your primary (list) view URL resolves to a 200.
Redirects are not consolidating in Google Search Console
Make sure you have not also disallowed those URLs in robots.txt — a disallowed URL can never be crawled, so the 301/410 is never seen. Reserve robots.txt rules for feeds and filter parameters only.
Logged-in editing is being interrupted
Keep “Skip logged-in users” enabled.
FAQ
Will this slow my site down?
The opposite. Rejected requests exit before the main query and template render, so they cost far less than a normal page load. With cache headers enabled, repeat hits are served from your cache.
Why 410 instead of 404 for old dates?
410 Gone is a permanent signal: crawlers drop the URL and stop revisiting. 404 invites them to try again later.
Does it touch single event pages?
No — single events have real content and are always allowed. Only recurring-event instance permalinks (a specific date, or /all/) are redirected to the base event, and only if you enable that option.
Does it work with query-string (plain) permalinks?
Yes. Date-window rejection still applies. Query-string canonicalization is skipped when pretty permalinks are off, because in that mode the query string is the canonical URL.
WP-CLI
For bulk checking and boundary verification, the plugin registers a ccg command group:
wp ccg test <url>...— run one or more URLs through the same decision engine the live hook uses. Accepts--file=<path>(or--file=-for STDIN),--only=allow,redirect,reject, and--format=table|csv|json|count.wp ccg scan— generate month views across a range of offsets and report each verdict, so you can see exactly where the canonical window flips from allow to reject. Accepts--provider=tec|ai1ec,--months=<n>,--base=<url>, and--format.wp ccg providers— list the calendars detected on the site.
Example: wp ccg test --file=urls.txt --only=reject --format=csv exports just the URLs that would be terminated.
Support
Built and maintained by Web321 Marketing Ltd.
Web: web321.co
Email: shawn@web321.co
Phone: (250) 661-4834
Saanichton, BC, Canada
If this plugin saved your server some grief, you can support development with a donation.

