How to Hide Pages from Non-Logged-In Users (SEO-Safe)

December 23, 2025
How to Hide Pages from Non-Logged-In Users (SEO-Safe)

How to Hide Pages from Non-Logged-In Users (SEO-Safe)

Sometimes you need “members-only” pages in WordPress without installing a full membership plugin:
download pages, internal docs, pricing pages for partners, or onboarding content.

The challenge is doing it in a way that is:

  • Secure (server-side access control, not just hiding UI)
  • SEO-safe (no accidental indexing of restricted pages)
  • Predictable (no redirect loops, no broken admin flows)

This article shows a clean, code-first implementation.

What “SEO-Safe” Means for Private Pages

If a page is truly private, you generally want:

  • Non-logged-in users cannot access the HTML
  • Search engines should not index the page
  • No “thin” public placeholder page competing in search

The safest pattern is:

  • Return a 401/403 (or redirect to login) for visitors
  • Send noindex headers/meta for restricted pages
  • Remove restricted pages from internal search and feeds

Approach Overview

We’ll implement three layers:

  • Access control (block the request early)
  • Index control (noindex for restricted URLs)
  • Discovery control (exclude from search/feed where appropriate)

1) Restrict Page Access for Non-Logged-In Users

Use template_redirect to block requests before the template loads.
This is reliable and works across themes.

Restrict Specific Pages by ID

<?php
add_action( 'template_redirect', function () {
  // Pages to restrict (IDs).
  $restricted_pages = array( 123, 456 );

  if ( ! is_page( $restricted_pages ) ) {
    return;
  }

  if ( is_user_logged_in() ) {
    return;
  }

  // Send visitors to login and return them back after login.
  $redirect = wp_login_url( get_permalink() );
  wp_safe_redirect( $redirect );
  exit;
} );

This pattern is “SEO-safe” only when you also prevent indexing (next section),
because redirects to login pages can still be discovered.

Return 403 Instead of Redirect (Stricter Control)

If you prefer not to redirect, you can return a 403 response.
This avoids indexing of placeholder/login content under the restricted URL.

<?php
add_action( 'template_redirect', function () {
  $restricted_pages = array( 123, 456 );

  if ( ! is_page( $restricted_pages ) ) {
    return;
  }

  if ( is_user_logged_in() ) {
    return;
  }

  status_header( 403 );
  nocache_headers();

  wp_die(
    esc_html__( 'You must be logged in to view this page.', 'default' ),
    esc_html__( 'Access denied', 'default' ),
    array( 'response' => 403 )
  );
} );

This is often the cleanest approach for true private content.

2) Add Noindex for Restricted Pages

Blocking access is not always enough for SEO hygiene.
Add noindex to prevent indexing if the URL is discovered.

Output Robots Meta for Restricted Pages

<?php
add_action( 'wp_head', function () {
  $restricted_pages = array( 123, 456 );

  if ( ! is_page( $restricted_pages ) ) {
    return;
  }

  echo '<meta name="robots" content="noindex, nofollow, noarchive">';
}, 1 );

This helps when:

  • A restricted URL is linked somewhere accidentally
  • A crawler reaches it while logged out

Also Send an X-Robots-Tag Header

Headers are harder to miss than HTML meta tags (and apply to non-HTML responses too).

<?php
add_action( 'send_headers', function () {
  $restricted_pages = array( 123, 456 );

  if ( ! is_page( $restricted_pages ) ) {
    return;
  }

  header( 'X-Robots-Tag: noindex, nofollow, noarchive', true );
}, 10 );

If you use full-page caching or a CDN, verify headers are not stripped.

3) Hide Restricted Pages from WordPress Search and Feeds

Even if the pages are blocked, it is better UX to remove them from on-site search and RSS.

Exclude from Search Results

<?php
add_action( 'pre_get_posts', function ( $query ) {
  if ( is_admin() ) {
    return;
  }

  if ( $query->is_main_query() && $query->is_search() ) {
    $restricted_pages = array( 123, 456 );
    $query->set( 'post__not_in', $restricted_pages );
  }
} );

Exclude from Feeds

<?php
add_action( 'pre_get_posts', function ( $query ) {
  if ( is_admin() ) {
    return;
  }

  if ( $query->is_main_query() && $query->is_feed() ) {
    $restricted_pages = array( 123, 456 );
    $query->set( 'post__not_in', $restricted_pages );
  }
} );

Make It Scalable: Use a Meta Flag Instead of Hardcoding IDs

Hardcoding IDs works for small sites, but it doesn’t scale.
A better approach is using a meta flag like _members_only.

Block Requests When _members_only = 1

<?php
add_action( 'template_redirect', function () {
  if ( ! is_singular() ) {
    return;
  }

  $post_id = get_queried_object_id();
  if ( ! $post_id ) {
    return;
  }

  $members_only = get_post_meta( $post_id, '_members_only', true );
  if ( (string) $members_only !== '1' ) {
    return;
  }

  if ( is_user_logged_in() ) {
    return;
  }

  // Choose either login redirect or 403.
  wp_safe_redirect( wp_login_url( get_permalink( $post_id ) ) );
  exit;
} );

Noindex for Flagged Content

<?php
add_action( 'send_headers', function () {
  if ( ! is_singular() ) {
    return;
  }

  $post_id = get_queried_object_id();
  if ( ! $post_id ) {
    return;
  }

  if ( (string) get_post_meta( $post_id, '_members_only', true ) !== '1' ) {
    return;
  }

  header( 'X-Robots-Tag: noindex, nofollow, noarchive', true );
}, 10 );

Optional: Keep Public Snippet, Hide the Rest (Safer for SEO Pages)

Sometimes you want the page indexed, but hide only a section (downloads, code blocks).
In that case, don’t restrict the whole page—restrict part of the content.

A simple pattern:

<?php
if ( is_user_logged_in() ) {
  echo '<p>Download: <a href="/file.zip">file.zip</a></p>';
} else {
  echo '<p>Log in to access downloads.</p>';
}

This avoids “private URL indexing” problems because the page remains legitimately public.

Common Mistakes to Avoid

  • Hiding content only with CSS or JavaScript (not secure)
  • Using a public placeholder page that gets indexed instead of the intended page
  • Redirecting everything to home (confusing UX and can create soft-404 patterns)
  • Forgetting to remove restricted URLs from internal search and feeds

Summary

  • Use template_redirect to block non-logged-in requests
  • Add noindex via meta and/or X-Robots-Tag for SEO hygiene
  • Exclude restricted pages from search and feeds
  • Scale with a meta flag (_members_only) instead of hardcoded IDs

With these layers, you can implement members-only pages in WordPress without a membership plugin,
while keeping the behavior secure and SEO-safe.

Avatar

Written by

satoshi

I’ve been building and customizing WordPress themes for over 10 years. In my free time, you’ll probably find me enjoying a good football match.