For version 2.1.0. This is the comprehensive guide; see pbj-access-control-INSTALL-AND-USAGE.md for the quick-start version.
Four related jobs, each independently switchable:
Since 2.1.0 the gate is airtight: restricted page content is also blanked in the REST API and oEmbed, excluded from search results, marked noindex, and blocked responses are never stored by page caches.
Edit any Page → sidebar meta box Access Restriction → tick Restrict this page to logged-in users only → Update.
What logged-out visitors then get: your restricted message with HTTP 403 at the page's URL; no trace of the content in site search; nothing in the REST API (.../wp-json/wp/v2/pages/... shows empty content marked "protected"); no oEmbed preview; noindex for crawlers.
What they do NOT get protection from: uploaded files. Images and PDFs linked from a restricted page are served directly by the web server and stay reachable by direct URL. Don't put secret documents in the media library expecting this plugin to guard them.
Only Pages have the checkbox by default. A developer can extend restriction to other post types with the pbj_access_control_post_types filter.
Settings → Access Control:
Typical wholesale/trade setup: both toggles on, approval required (section 5), so a new trade customer registers → you vet and approve → they log in and see the store.
Settings → Access Control → the editor at the bottom. Full WYSIWYG: headings, links, images. The default is a "Members Only" box linking to sign-in/registration (it picks the WooCommerce My Account URL automatically when Woo is active). Reset message to default restores it at any time.
Notes: <style> tags and stylesheet links are stripped on save (styling comes from the built-in card design); the message is shown for both restricted pages and gated Woo pages — write it generically enough for both.
Prefer a login redirect instead of a message page? A developer one-liner sends logged-out visitors to wp-login with a return-to-page redirect: add_filter( 'pbj_access_control_login_redirect', '__return_true' );
Settings → Access Control → Require admin approval for new registrations.
The flow: someone registers → their account is created but flagged pending → they cannot log in ("Your account is pending approval") → you (and any addresses on the notification list) get an email with their username, email, registration time, IP address, and detected city/region/country → you approve or deny.
Three ways to act:
What approval/denial does: Approve clears the flag and emails the user "your account has been approved" with a login link. Deny deletes the account (confirmation prompt in the admin UI). There's no "reject but keep" state — deny is delete.
Reading the IP/location column: it's an audit aid, not a guarantee — VPN users show their exit location, and on sites not behind a proxy the value is what the client claimed. A signup with no location + free-mail address + gibberish username is your classic bot pattern.
Notification recipients: comma-separated list; empty = the site admin email. Invalid addresses are silently dropped.
Turning approval on with existing pending users: the flag is set at registration time, so only signups made while the toggle is on are held. Existing users are never affected.
They stack cleanly and are designed to run together:
In a private/incognito window (logged out):
https://yoursite.com/wp-json/wp/v2/pages/<id> → "content":{"rendered":"","protected":true}.A member sees the "Members Only" page while logged in. A stale cached copy from before 2.1.0 — purge your page cache once; 2.1.0 marks all blocked responses uncacheable.
Restricted content appears in Google. It was indexed before restriction. The page now serves 403 + noindex to crawlers, so it will drop out; request removal in Search Console to speed it up.
Registration form unreachable with Woo blocking on. Both toggles must be on: the plugin's "Allow access to registration page" AND WooCommerce's "Allow customers to create an account on the My account page".
No approval emails. Test wp_mail delivery generally (password-reset email is a quick check); then check the recipients field. Consider an SMTP plugin if the host's mail is unreliable.
Approve link says nothing / expired notice. Email links live ~24h. Use Users → PBJ User Approvals.
Pending user complains they can't log in. Working as intended — approve them, or turn approval off if you didn't mean to hold registrations.
Locked myself out of a restricted page while logged out. Just log in — admins see everything. The restriction never applies to logged-in users.
IP column empty or wrong. Private/unresolvable IPs, ip-api.com unreachable (2-second timeout), or a VPN. It's best-effort audit data.
Registrant IPs are stored as user meta and, when no proxy geo header is available, sent to ip-api.com (third-party, plain-HTTP) for city/region/country resolution, cached 24h. Mention signup IP collection in your privacy policy if that's relevant to your jurisdiction.
| Thing | Value |
| Settings screen | Settings → Access Control |
| Approvals screen | Users → PBJ User Approvals |
| Restricted-response status | HTTP 403 (+ noindex, uncacheable) |
| Per-page toggle | "Access Restriction" meta box on Pages |
| Deny = | account deleted (confirm prompt) |
| Approval email links | expire ~24h |
| File/media protection | none — pages only |
| Option name | pbj_access_control_options |
| Filters | pbj_access_control_post_types, pbj_access_control_login_redirect |