Members-Only Posts and Pages With Role Choice
Adds a "Members only" box to the post and page editor; restricted content shows a login prompt to visitors and to roles you did not tick, and stays out of search and feeds for them.
Opens WPIDE on
Code
// Post types that get the box.
$wpide_mo_post_types = array( 'post', 'page' );
$wpide_mo_can_view = function ( $post_id ) {
if ( ! get_post_meta( $post_id, '_wpide_members_only', true ) ) {
return true;
}
if ( ! is_user_logged_in() ) {
return false;
}
$roles = (array) get_post_meta( $post_id, '_wpide_members_roles', true );
$roles = array_filter( $roles );
return ! $roles || array_intersect( $roles, (array) wp_get_current_user()->roles ) || current_user_can( 'edit_post', $post_id );
};
add_action( 'add_meta_boxes', function () use ( $wpide_mo_post_types ) {
add_meta_box( 'wpide-members-only', 'Members only', function ( $post ) {
$roles = array_filter( (array) get_post_meta( $post->ID, '_wpide_members_roles', true ) );
wp_nonce_field( 'wpide_members_only', 'wpide_members_only_nonce' );
printf( '<p><label><input type="checkbox" name="wpide_members_only" value="1" %s> Only logged-in members can read this</label></p><p>Limit to these roles (optional):</p>', checked( (bool) get_post_meta( $post->ID, '_wpide_members_only', true ), true, false ) );
foreach ( wp_roles()->role_names as $role => $name ) {
printf( '<label style="display:block"><input type="checkbox" name="wpide_members_roles[]" value="%1$s" %2$s> %3$s</label>', esc_attr( $role ), checked( in_array( $role, $roles, true ), true, false ), esc_html( translate_user_role( $name ) ) );
}
}, $wpide_mo_post_types, 'side' );
} );
add_action( 'save_post', function ( $post_id ) {
if ( ! isset( $_POST['wpide_members_only_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['wpide_members_only_nonce'] ), 'wpide_members_only' ) ) {
return;
}
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
if ( empty( $_POST['wpide_members_only'] ) ) {
delete_post_meta( $post_id, '_wpide_members_only' );
delete_post_meta( $post_id, '_wpide_members_roles' );
return;
}
$roles = isset( $_POST['wpide_members_roles'] ) ? array_map( 'sanitize_key', (array) wp_unslash( $_POST['wpide_members_roles'] ) ) : array();
update_post_meta( $post_id, '_wpide_members_only', 1 );
update_post_meta( $post_id, '_wpide_members_roles', array_values( array_intersect( $roles, array_keys( wp_roles()->role_names ) ) ) );
} );
$wpide_mo_message = function () {
$login = wp_login_url( get_permalink() );
if ( is_user_logged_in() ) {
return '<div class="wpide-members-only"><p>This content is not available with your current membership.</p></div>';
}
$html = '<div class="wpide-members-only"><p>This content is for members. <a href="' . esc_url( $login ) . '">Log in</a>';
if ( get_option( 'users_can_register' ) ) {
$html .= ' or <a href="' . esc_url( wp_registration_url() ) . '">create a free account</a>';
}
return $html . ' to keep reading.</p></div>';
};
add_filter( 'the_content', function ( $content ) use ( $wpide_mo_can_view, $wpide_mo_message ) {
$post = get_post();
return ( $post && ! $wpide_mo_can_view( $post->ID ) ) ? $wpide_mo_message() : $content;
}, 1 );
add_filter( 'get_the_excerpt', function ( $excerpt, $post ) use ( $wpide_mo_can_view ) {
return ( $post && ! $wpide_mo_can_view( $post->ID ) ) ? '' : $excerpt;
}, 10, 2 );
// Keep restricted items out of search results and feeds for visitors.
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || is_user_logged_in() || ! $query->is_main_query() || ! ( $query->is_search() || $query->is_feed() ) ) {
return;
}
$meta = (array) $query->get( 'meta_query' );
$meta[] = array( 'key' => '_wpide_members_only', 'compare' => 'NOT EXISTS' );
$query->set( 'meta_query', $meta );
} );
Notes
Tick no roles to allow every logged-in user. Titles stay public; only the content and excerpt are hidden. Works in the block and classic editors.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.