A few notes on how to restrict access to content in WordPress, both for anonymous visitors and logged-in visitors with a specific user role, by using wp_safe_redirect()
.
What
When you want to hide some of your content, for example posts in a certain category, a page, a particular Custom Post Type, you can use the wp_safe_redirect()
function. This does not allow for showing a teaser on the page, since visitors will never see the page, and I don’t think the following is a good solution for a full-fledged membership site.
This solution might be good though for a temporary lockdown of a site, or very simple membership sites.
How
Basically, it’s this: check which page is being called, check if the user is logged in, redirect if necessary.
add_action( 'template_redirect', 'bw_restrict_content');
function bw_restrict_content(){
if( ( is_singular( array( 'my-cpt-1', 'my-cpt-2' ) ) || is_page('my-page') ) && !is_user_logged_in() ) {
nocache_headers();
wp_safe_redirect( home_url() );
exit;
}
}
I’m redirecting within the site, so I’m using wp_safe_redirect()
instead of wp_redirect()
, but choose the later if you want to redirect to a different site altogether. And I’m redirecting them to home in this case, because the site I’m using this on does not have an open registration, but you can redirect to any old URL.
The nocache_header()
function is called, as kZeni mentions on the WP reference page for this function, so that the redirect isn’t cached and users will actually see the restricted content once they log in, instead of still being automatically redirected.
You can use this with any number of conditional tags, such as is_category(), is_feed() and I’ve used it with is_author() and is_search() for example.
If you want to check for a specific user role, you can check for capabilities. For example, want to hide posts with the category “premium” from not-logged-in visitors and logged-in subscribers?
add_action( 'template_redirect', 'bw_hide_premium' );
function bw_hide_premium(){
if( (!is_user_logged_in() || !current_user_can( 'edit_posts' ) ) && ( is_category( 'premium' ) || in_category( 'premium' ) ) ){
nocache_header();
wp_safe_redirect( home_url() );
exit;
}
}
Snippets like this should not be the functions.php file, in my opinion, because they remain true, regardless of the theme I’m using. A site-specific plugin would make more sense, but I usually end up tweaking snippets like this regularly, so I like something a bit more accessible: the Code Snippets plugin.
I am also using a plugin to control which items are visible in the site navigation: User Menus. Once you’ve activated it, all necessary options can be found in the standard WordPress menus and menu items.
For any posts, pages, CPT that should only be visible to Administrators en Editors, I just set them to Private. If it’s something I want to add to site navigation (usually a page), I will publish first, then add to a menu, then set to Private, and then I hide the menu item from everyone with the User Menus plugin settings.
Where
An answer on WordPress StackExchange by bynicolas.
Thoughts
I used to use a plugin for this: Restrict User Access. I still might on occasion, I like it, it does enough and not too much. But on my last project, just turning the plugin on removed the CPT from the author archive pages and, well, it was too much hassle to fix that.
I tried another plugin that showed promise: Control Content. Sadly, it didn’t work at all, though it seemed sympathetically lightweight and unobtrusive. One of the nice options it has is that you can very easily hide widgets as well, something Restrict User Access lacks, and which was the one thing that actually worked for me. Control Content also led me to the User Menus plugin, since it’s from the same plugin authors, but this one actually works and is really easy to use. Beautiful plugin.