PBJ.TECH — WordPress Plugins

PBJ Geo Viewer — User Guide

Version 1.2.0 · pbj.tech/wordpress-plugins

PBJ Geo Viewer — Complete User Guide

For version 1.1.0. This is the comprehensive guide; see pbj-geo-viewer-INSTALL-AND-USAGE.md for the quick-start version.

1. What this plugin does (and doesn't)

PBJ Geo Viewer makes your site view-only for visitors outside the countries you choose. It never hides content: every page renders fully for every visitor and every search engine, identical HTML worldwide. What it gates is interactivity — buying, submitting forms, commenting, signing in, and registering.

It does NOT: hide pages, redirect visitors away, block whole countries from reading, slow down crawlers, or affect logged-in administrators and editors in any way.

Why view-only instead of a hard block? Search engines and AI crawlers index your full site regardless of where they crawl from; blocked-region visitors can still read, share, and link to you; and you never lose SEO standing over a regional restriction.

2. The mental model

Every request is classified in this order:

  1. Crawler/bot? Always fully allowed (Google, Bing, social preview bots, AI crawlers — ~30 known signatures). They see the normal page.
  2. Admin or editor logged in? IP on the allowlist? Fully allowed.
  3. Country detected? Via Cloudflare's header when present, other CDN headers, or a cached ip-api.com lookup.
  4. Country unknown? Treated as blocked (safe default) unless you enable fail-open.
  5. Country vs. your list, per mode: Allowlist = only listed countries get full access. Blocklist = listed countries are view-only, everyone else full access.

"Blocked" visitors get the same page plus: a dismissable banner (optional), inline "Not available in your region" notices where buy buttons would be (optional), disabled/hidden interactive controls, and server-side rejection (HTTP 451) of anything that slips through.

3. Every setting, explained

Settings → Geo Viewer:

Mode. Allowlist ("only these countries may interact") suits a local business that only sells domestically — pick your country and done. Blocklist ("everyone except these") suits a global store excluding specific regions.

Countries. Multi-select with a type-to-filter box. Hold Ctrl/Cmd to select several. The list is what Mode interprets.

What to block — four independent toggles:

Visitor notice. The site-wide banner (bottom of page, dismissable, stays dismissed 24h) and/or inline notices at the point of blocked features. Both texts are editable. Recommendation: keep both on — silent dead buttons frustrate people; a clear "not available in your region" doesn't.

Admin IP allowlist. IPs or CIDR ranges (one per line) that are treated as fully allowed regardless of country — the whole site behaves normally for them. Use it for your office/home IPs and for testing. This is a full-site exemption.

Login username allowlist (new in 1.1.0). Usernames or emails that may sign in from blocked regions. Administrator and editor accounts are always allowed automatically, so this list is only needed for other roles (a customer, a shop manager abroad). This is a login-only exemption — it doesn't un-block forms or checkout for them until they're logged in with a role that's exempt.

Geo cache (minutes). How long an IP→country answer from ip-api.com is remembered (default 24h). Cloudflare-header detection is instant and never cached. Lower it only when testing.

When country is unknown. Leave unchecked (recommended): undetectable visitors are view-only. Checking it lets them through — only safe if literally every request reaches you through Cloudflare.

Diagnostics panel. Shows your current IP, detected country, whether the Cloudflare header is present, and the verdict the plugin would apply to you. Check this first whenever something seems wrong.

4. Logins, admins, and travel

Since 1.1.0 the login page is never blocked. What happens instead:

5. Recipes

US-only local business: Mode = Allowlist, Countries = United States, all four blocks on, both notices on. Done — this is the default.

Global store, excluding two countries: Mode = Blocklist, select the two countries, blocks on as needed.

Let a specific overseas customer order: add their username to the Login username allowlist so they can sign in — then either give their account the edit_posts capability (full exemption) or, cleaner, add their IP to the IP allowlist.

Marketing site with no store: turn off the WooCommerce toggle (it's inert without Woo anyway), keep forms/comments/registration blocks on to kill regional form spam.

Temporarily test as blocked: remove your IP from the allowlist, open a private window, and send a fake country: curl -sI -H "CF-IPCountry: RU" https://yoursite.com/ | grep -i x-pbj-geo. Re-add your IP after.

6. Verifying it works

7. Troubleshooting

"I'm blocked on my own site." Check Diagnostics: are you logged in as admin/editor? Is your IP on the allowlist? Is your country detected correctly? If country shows (unknown) and fail-open is off, that's the fail-closed default doing its job — fix detection (see next) or allowlist your IP.

Country shows (unknown) for everyone. No Cloudflare header (site not proxied) and ip-api.com unreachable/rate-limited. Options: put the site behind Cloudflare (best), raise the geo cache so successful lookups persist longer, or as a last resort enable fail-open.

Wrong country detected. If behind a VPN/proxy, the detected country follows the exit node — that's correct behavior. If your host injects stale geo headers, disable header trust with add_filter( 'pbj_geo_viewer_trust_proxy_headers', '__return_false' );.

Allowed visitors see dead buy buttons. Pre-1.1.0 this could be cache poisoning; 1.1.0 prevents it. If you still see it, the page was cached before the upgrade — purge your page cache once.

A form still submits from a blocked region. Which plugin? The endpoint interceptor catches admin-post.php, the comment endpoint, and known REST routes; a form plugin with a custom REST namespace needs its route added (developer task — see the code explainer, "Add a form-plugin integration").

Legit user abroad can't log in. Add their username/email to the Login username allowlist.

ip-api rate limiting (free tier ~45 req/min). Only affects sites not behind Cloudflare with lots of new IPs. The 24h cache plus bot exemption keeps normal sites far under the limit.

8. Privacy note

When the Cloudflare header isn't available, visitor IPs are sent to ip-api.com (a third-party, plain-HTTP free service) for country resolution, and results are cached in your database for the configured window. If that's a compliance concern, run behind Cloudflare (no external lookups happen when the header is present) or disable the site's use of the plugin for EU traffic per your counsel's advice.

9. Quick reference

ThingValue
Settings screenSettings → Geo Viewer
Diagnostic headerX-PBJ-Geo (disable: pbj_geo_viewer_diagnostic_header filter)
Blocked-response statusHTTP 451
Full-site exemptionslogged-in admin/editor, IP allowlist, bots
Login-only exemptionusername allowlist (+ admins/editors automatically)
Unknown countryblocked by default (fail_open_on_unknown to change)
Option namepbj_geo_viewer_settings
Filterspbj_geo_viewer_trust_proxy_headers, pbj_geo_viewer_diagnostic_header, pbj_geo_viewer_login_allowed