Most WordPress sites are fully public by default, any visitor can browse any page without authentication. For membership sites, client preview environments, internal tools, company intranets, and staging sites you don’t want indexed or accessed publicly, restricting front-end access to logged-in users is a fundamental requirement. This snippet forces unauthenticated visitors to the login page while allowing a small set of public pages and WooCommerce commerce pages to remain accessible.
The Code
Add this to your functions.php or a site-specific plugin. It hooks into template_redirect, which fires after WordPress has determined what page is being requested but before any template is rendered. If the visitor is not logged in and no exception applies, they’re sent to the login page with a redirect_to parameter that brings them back to their intended destination after successful authentication.
The Exception Logic
The snippet allows three categories of requests through without authentication. First, logged-in users, the most important check, and the one that prevents infinite redirect loops. Second, 404 pages, unauthenticated visitors who land on a broken URL see the 404 page rather than being bounced to login, which is cleaner and more informative. Third, WooCommerce commerce pages, shop, cart, and checkout, are kept accessible so that guest checkout functionality continues to work if your store allows it.
The $public_slugs array allows specific pages by their URL slug. Privacy policy and terms of service pages are included by default because they may be required to be publicly accessible under GDPR and similar regulations. Add any other public-facing pages your site requires, a public landing page, an unsubscribe confirmation page, or a public documentation index.
The Redirect Destination
wp_login_url() returns the WordPress login URL and accepts an optional redirect_to argument, the URL to send the user after successful login. Passing the current REQUEST_URI means a user who tries to visit /members/dashboard/ gets redirected to login, and after logging in is sent directly to /members/dashboard/ rather than the WordPress admin or homepage. This significantly improves the user experience on sites where specific members have bookmarked internal pages.
Staging Environment Use
For staging environments, this snippet works well as a lightweight access gate, but note that search engine bots will also be redirected to the login page. Make sure your staging environment is either excluded from robots indexing through your server configuration or that the redirect itself prevents crawling. A 302 temporary redirect to the login page should prevent Googlebot from indexing staging content, but combining it with a robots.txt disallow or basic HTTP authentication at the server level is more reliable.
Performance
This snippet runs on every page request for unauthenticated users. The is_user_logged_in() check is lightweight, it’s a simple user session check, but the additional conditional checks add a small amount of overhead per request. On high-traffic public sites where only a portion of users need to be authenticated, consider server-level access control (HTTP Basic Auth) as a more efficient alternative.
add_action( 'template_redirect', function() {
// Allow these pages through without authentication
if (
is_user_logged_in() ||
is_404() ||
( function_exists( 'is_woocommerce' ) && ( is_woocommerce() || is_cart() || is_checkout() ) )
) {
return;
}
// Allow specific public pages by slug
$public_slugs = [ 'privacy-policy', 'terms-of-service' ];
if ( is_page( $public_slugs ) ) return;
// Redirect to login with a redirect_to parameter so users land back
// on the page they were trying to reach after logging in
$redirect_to = urlencode( $_SERVER['REQUEST_URI'] ?? '/' );
wp_redirect( wp_login_url( home_url( $_SERVER['REQUEST_URI'] ?? '/' ) ), 302 );
exit;
} );
