2026年11月12日

2026年11月12日

WordPress Members-Only Content: Require Login, Role-Based Access, Plugins

This article is a localized edition of the Japanese original. Read the Japanese original

WordPress makes every published post readable by anyone. To show some posts only to logged-in members, you either switch the output with code or use a membership plugin.

If you need to manage sign-ups, payments and expiration dates, a plugin is the better fit. If you already have members (users) and only want to show the full text to people who are logged in, a few dozen lines of code are enough.

The code in this article was tested in November 2026 on WordPress 7.1 (PHP 8.3).

Know the “leak paths” first

What people often miss when hiding content is that the text can be read from places other than the post page. WordPress also outputs post content here:

  • RSS feeds (/feed/)
  • The REST API (/wp-json/wp/v2/posts)
  • Excerpts on archives and search results

Switching the output with is_user_logged_in() inside a template only works on the post page; the full text can still be read from the feed and the REST API. The code below replaces the content with the the_content filter. WordPress passes feed content and REST API content (content.rendered) through this filter as well, so one piece of code hides all three.

Method 1: Make a category members-only

Posts in the "Members only" category (slug members-only) are replaced with a notice for visitors who are not logged in.

  1. Under "Posts" → "Categories", create a category with the slug members-only.
  2. Save the following code as wp-content/mu-plugins/members-only.php (create the mu-plugins folder if it doesn't exist). Files in this folder load without being activated.
  3. Assign the "Members only" category to the posts you want to restrict.
<?php
/**
 * Plugin Name: Members-only content
 */

// Whether the post is members-only (in the "members-only" category, or the checkbox is ticked)
function my_is_members_only( $post = null ) {
	$post = get_post( $post );
	if ( ! $post ) {
		return false;
	}
	if ( '1' === get_post_meta( $post->ID, '_my_members_only', true ) ) {
		return true;
	}
	return has_category( 'members-only', $post );
}

// Whether the visitor may view it (here: anyone who is logged in)
function my_can_view_members_content() {
	return is_user_logged_in();
}

// 1. Replace the content with a notice (works on the page, RSS feeds and the REST API)
add_filter( 'the_content', function ( $content ) {
	if ( my_can_view_members_content() || ! my_is_members_only() ) {
		return $content;
	}
	$login_url = wp_login_url( get_permalink() );
	return '<p>This post is for members only. <a href="' . esc_url( $login_url ) . '">Log in</a> to read the full text.</p>';
}, 1 );

// 2. Replace the excerpt as well (archives, search results, REST API excerpt)
add_filter( 'get_the_excerpt', function ( $excerpt, $post ) {
	if ( my_can_view_members_content() || ! my_is_members_only( $post ) ) {
		return $excerpt;
	}
	return 'This post is for members only.';
}, 20, 2 );

While logged out, open the post page, /feed/ and /wp-json/wp/v2/posts and confirm that the content shows the notice. When you log in, the full text appears. Logging in through the link in the notice brings you back to the original post.

Titles are not hidden. If you don't want the existence of members-only posts to show up in listings at all, consider the plugins in Method 3.

Method 2: Send the whole post page to the login screen

Instead of showing a notice, you can redirect visitors to the login screen as soon as they open the post. In addition to the Method 1 code, save the following file as wp-content/mu-plugins/members-redirect.php (it uses the functions from Method 1).

<?php
/**
 * Plugin Name: Require login for members-only posts
 */

// Send visitors who aren't logged in to the login screen when they open a members-only post
add_action( 'template_redirect', function () {
	if ( is_singular() && my_is_members_only( get_queried_object() ) && ! my_can_view_members_content() ) {
		wp_safe_redirect( wp_login_url( get_permalink( get_queried_object() ) ) );
		exit;
	}
} );

template_redirect runs only when a post page is displayed, so it has no effect on feeds or the REST API. Use it together with the the_content filter from Method 1.

Visitors who are not logged in, and search engines, receive a 302 redirect, so members-only posts stop appearing in search results.

Show posts only to paying members (with a custom capability)

With Method 1, anyone who is logged in can read the posts. To separate free members (Subscribers) from paying members, create a capability that only paying members have and check that.

Replace my_can_view_members_content() in the Method 1 code with the following.

<?php
// Create a "Premium member" role and a capability to read members-only posts (once created, they stay in the database)
add_action( 'init', function () {
	if ( get_role( 'premium_member' ) ) {
		return;
	}
	add_role( 'premium_member', 'Premium member', array(
		'read'                 => true,
		'read_members_content' => true,
	) );
	$admin = get_role( 'administrator' );
	if ( $admin ) {
		$admin->add_cap( 'read_members_content' );
	}
} );

// Whether the visitor may view it (only users with the read_members_content capability)
function my_can_view_members_content() {
	return current_user_can( 'read_members_content' );
}

"Premium member" now appears in the "Role" field on each user's edit screen under "Users". Premium members and administrators can read the full text, and Subscribers see the notice. Because the check uses a capability (read_members_content) rather than a role name, you can let more people read later just by adding the same capability to another role.

A role created with add_role() is saved in the database, so it remains even if you delete the code. When you no longer need it, move its users to another role and then run remove_role( 'premium_member' ) once to delete it.

Mark individual posts with a checkbox

To make posts members-only one by one from the post editor instead of using a category, add a checkbox. The Method 1 code already treats posts whose custom field _my_members_only is 1 as members-only, so adding the following file is all it takes. Save it as wp-content/mu-plugins/members-metabox.php.

<?php
/**
 * Plugin Name: Members-only checkbox
 */

// Show a checkbox on the post edit screen
add_action( 'add_meta_boxes', function () {
	add_meta_box( 'my_members_only', 'Members only', function ( $post ) {
		wp_nonce_field( 'my_members_only_save', 'my_members_only_nonce' );
		$checked = '1' === get_post_meta( $post->ID, '_my_members_only', true );
		echo '<label><input type="checkbox" name="my_members_only" value="1"' . checked( $checked, true, false ) . '> Make this post members-only</label>';
	}, 'post', 'side' );
} );

// Save it
add_action( 'save_post_post', function ( $post_id ) {
	if ( ! isset( $_POST['my_members_only_nonce'] )
		|| ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['my_members_only_nonce'] ) ), 'my_members_only_save' ) ) {
		return;
	}
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
		return;
	}
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return;
	}
	if ( ! empty( $_POST['my_members_only'] ) ) {
		update_post_meta( $post_id, '_my_members_only', '1' );
	} else {
		delete_post_meta( $post_id, '_my_members_only' );
	}
} );

Before writing the value, the save handler checks three things: the nonce (a token that prevents forged requests), autosave, and edit permission. If you skip any of them, someone could change the value with a crafted request.

In the block editor, this checkbox appears toward the bottom of the settings panel on the right.

Method 3: Use a membership plugin

If you need sign-up forms, membership fee payments, expiration dates and access by membership level, a plugin is faster to set up and easier to maintain. The main ones distributed on wordpress.org are listed below (as of November 2026).

Plugin Slug Best for
Members members Editing roles and capabilities, per-post access restrictions
Simple Membership simple-membership Membership levels, free and paid sign-ups, protecting posts and pages
Ultimate Member ultimate-member Registration, profiles, member directories and content restriction
Kadence Memberships restrict-content Membership levels, recurring payments and content restriction (formerly Restrict Content)

You can install any of them by searching for the name under "Plugins" → "Add Plugin". With WP-CLI, specify the slug, as in wp plugin install simple-membership --activate. MemberPress and WooCommerce Memberships are paid plugins that are not on wordpress.org; buy them on their official sites and install them by uploading the ZIP file.

Things to watch

  • Images and PDFs are not protected. The methods in this article hide post content. Files uploaded to the Media Library can be opened by anyone who knows the URL. If you distribute members-only documents, set up a plugin that protects files or a separate download mechanism.
  • Watch out for caching. With a page caching plugin, the full text shown to a logged-in user may be cached and served to others. Most caching plugins skip the cache for logged-in users, but after creating a members-only post, check in another browser while logged out that the content is hidden.
  • Titles appear in search results. WordPress site search also searches post content, so searching for a word in the content shows the members-only post's title in the results (the content itself is not shown).
  • How this differs from password protection. Password protection, which you can set per post, shares one password without user registration. If you want to control who can read on a per-member basis, use the methods in this article.

Related articles

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲