
How to Restrict Content Access in WordPress?
Not all content on a WordPress site should be visible to everyone. A course platform needs to hide lesson content from anyone who hasn't paid, an internal team site needs to keep certain pages away from public visitors entirely, and a blog running a paid newsletter needs a way to show a teaser to everyone while reserving the full article for subscribers. All of these are variations on the same problem: restricting content access based on who's logged in, and what they're allowed to see.
This guide covers three real patterns for restricting content in WordPress — full-page restriction, partial in-content restriction via a shortcode, and role-based gating — plus when it makes more sense to reach for a dedicated plugin instead of custom code.
Decide What Kind of Restriction You Actually Need
Before writing any code, it's worth being specific about the restriction:
- Whole-page restriction — an entire post or page is inaccessible unless the visitor is logged in (and possibly a specific role), like a members-only resource library.
- Partial content restriction — a page is publicly visible, but part of its content (the second half of an article, a download link) is hidden behind a login.
- Role-based restriction — content is visible to logged-in users generally, but only specific roles or capabilities can see certain parts, like an internal wiki where only Editors can see a "drafts" section.
Each maps to a different implementation, covered below.
Method 1: Restrict an Entire Post or Page
The cleanest way to gate a whole post is a template_redirect hook that checks a custom field before the page renders, sending unauthorized visitors somewhere else before any of the actual content loads:
add_action( 'template_redirect', 'tw_restrict_premium_posts' );
function tw_restrict_premium_posts() {
if ( ! is_singular( 'post' ) ) {
return;
}
$requires_membership = get_post_meta( get_the_ID(), 'tw_requires_membership', true );
if ( ! $requires_membership ) {
return; // Not a gated post — nothing to do.
}
if ( ! is_user_logged_in() ) {
wp_safe_redirect( wp_login_url( get_permalink() ) );
exit;
}
if ( ! current_user_can( 'read_premium_content' ) ) {
wp_safe_redirect( home_url( '/membership' ) );
exit;
}
}
template_redirect runs after WordPress has decided which post to display but before any template file starts outputting HTML, which makes it the correct hook for this — checking on the the_content filter instead would mean the page's header, sidebar, and other template parts have already rendered by the time you decide to block access.
wp_login_url( get_permalink() ) passes the current page as a redirect target, so the login screen sends the visitor straight back to the content they were trying to reach once they log in successfully — worth pairing with a custom login page if you want that experience to match the rest of your site's branding instead of the default WordPress login screen.
You'd toggle tw_requires_membership from a checkbox in a custom meta box, or set it automatically based on a category or product association, depending on how your site organizes gated content.
Method 2: Restrict Part of a Post's Content
For a page that should stay publicly visible with only some content hidden, a shortcode wrapping the protected section is more practical than blocking the whole page:
add_shortcode( 'restricted', 'tw_restricted_content_shortcode' );
function tw_restricted_content_shortcode( $atts, $content = null ) {
$atts = shortcode_atts(
[ 'role' => 'subscriber' ],
$atts,
'restricted'
);
if ( is_null( $content ) ) {
return '';
}
if ( ! is_user_logged_in() ) {
return tw_restricted_notice();
}
$user = wp_get_current_user();
if ( ! in_array( $atts['role'], (array) $user->roles, true ) && ! current_user_can( 'manage_options' ) ) {
return tw_restricted_notice();
}
return do_shortcode( $content );
}
function tw_restricted_notice() {
return sprintf(
'<p class="tw-restricted-notice">%s <a href="%s">%s</a></p>',
esc_html__( 'This content is available to members only.' ),
esc_url( wp_login_url( get_permalink() ) ),
esc_html__( 'Log in to continue.' )
);
}
An editor can now write [restricted role="subscriber"]...premium content...[/restricted] directly into a post, and anyone who doesn't qualify sees a login prompt instead of the wrapped content. Administrators are given a blanket pass via current_user_can( 'manage_options' ) so you can preview and edit gated content without logging out to test it.
Note that this hides content from rendering, not from ever leaving the server — the underlying post content, restricted section included, still exists in the database and REST API response unless you separately lock down the REST API for that post type. For genuinely sensitive content (not just content you want to gate as a UX/monetization choice), Method 1's full-page redirect is the safer pattern, since it stops the response before any content is generated at all.
Method 3: Role- or Capability-Based Restriction in Templates
Inside a template file, the simplest form of restriction is a direct capability check, using the same capabilities and roles covered elsewhere:
<?php if ( current_user_can( 'edit_posts' ) ) : ?>
<div class="tw-staff-notes">
<?php the_field( 'internal_notes' ); ?>
</div>
<?php endif; ?>
Prefer checking a capability (edit_posts) over a specific role name. If you do need to check role membership specifically rather than a capability, use $user->roles as shown in Method 2, but capability checks are more resilient to future role changes since they describe what someone can do, not the label attached to their account.
Method 4: Use a Dedicated Plugin for Anything Commerce-Related
Custom code is the right call for straightforward gating logic you fully control. The moment restriction is tied to payments, subscription tiers, drip-fed content schedules, or content bundles, a dedicated plugin handles far more edge cases correctly than a hand-rolled solution will:
- MemberPress — the most complete option for paid membership tiers, subscription billing, and content dripping.
- Restrict Content Pro — a lighter-weight, developer-friendly alternative with a cleaner codebase to extend.
- Paid Memberships Pro — free core plugin with a large add-on ecosystem for specific integrations.
These plugins register their own shortcodes and conditional tags (most follow the same [restricted]-style pattern shown above) and handle the parts that are genuinely hard to get right yourself: payment processor webhooks, failed-payment access revocation, and prorated plan changes. If you're building toward a full paid membership site rather than simple content gating, building a membership site with WordPress covers that setup end to end.
A Note on SEO for Restricted Content
Gated content still needs a public-facing presence for search engines to index, or it won't drive any traffic at all:
- Show a genuine excerpt or teaser to logged-out visitors rather than nothing — an empty page reads as thin content to search engines and gives visitors no reason to sign up.
- Avoid
noindex-ing an entire gated section unless you specifically don't want it discoverable via search at all; a teaser page that ranks and then prompts sign-up is usually better for growth than an invisible one. - Make sure your restriction logic runs after the page has rendered enough for the teaser and SEO meta tags to still be present — Method 1's
template_redirectcheck should generally only fire for content with zero public value, while Method 2's shortcode approach naturally keeps everything else on the page intact.
Frequently Asked Questions (FAQ) About Restricting Content in WordPress
No. A shortcode-based approach hides content from rendering in the normal page template, but the full post content typically still exists in the database and may be exposed through the REST API or a direct feed unless you separately restrict those. For genuinely sensitive information, use full-page restriction with a template_redirect check instead.
is_user_logged_in() only checks whether someone has an account and is logged in — it doesn't distinguish between roles. current_user_can() checks a specific capability, so use it whenever the restriction depends on who the user is, not just whether they're logged in at all.
Yes, but role alone usually isn't the right tool for multiple paid tiers — you'd typically pair a membership plugin (which tracks subscription status and tier as user meta or a custom table) with capability checks tied to that data, rather than creating a new WordPress role for every pricing tier.
By default, WordPress includes full post content in RSS feeds regardless of any front-end restriction logic you've added, since feeds are generated through a separate code path. You'll need to filter the_content_feed separately if gated content shouldn't appear there.
Only if you leave logged-out visitors with nothing to see. Showing a genuine teaser or excerpt publicly, with the full content gated behind login, is generally better for search visibility than a blank or heavily truncated page.
Yes — plugins like Restrict Content Pro, MemberPress, and even simpler free options handle content gating with settings screens and their own shortcodes, no PHP required. Custom code is worth it mainly when you need very specific logic a plugin's settings don't expose.
Only if your code explicitly allows it, as shown with the current_user_can( 'manage_options' ) check in Method 2. Without that check, even an Administrator would be blocked by role-specific restriction logic, which usually isn't what you want when previewing your own gated content.
Conclusion
Restricting content in WordPress comes down to picking the right layer for what you're actually protecting: template_redirect for entire pages that shouldn't be reachable at all, a wrapping shortcode for partial content on an otherwise public page, and straightforward current_user_can() checks inside templates for role-based visibility. All three build on the same login and capability system already built into WordPress core.
Once restriction needs grow into paid tiers, subscription billing, or drip-fed content schedules, that's the point to move from custom code to a dedicated plugin — the underlying concepts covered here are exactly what those plugins implement under the hood, just with a lot more edge cases handled for you.


