How to Make your WordPress site for Members Only
Updated 12/2014
I was putting together a site in WordPress and needed to make it so only logged in users could view posts. In addition, only users logged in could download/view images and documents uploaded through the media library (wp-content/uploads/).
Redirect visitors to login page
First part is easy. Just add this to functions.php:
// Redirect users who are not logged in... function login_redirect() { // Current Page global $pagenow; // Check if user is not logged in and not on the wp-login page if(!is_user_logged_in() && $pagenow != 'wp-login.php' ) auth_redirect(); } add_action( 'wp', 'login_redirect' );
Visitors are now directed to the default WordPress login page. The default login page is bleak and not attractive to someone happening onto the site. You could add a logo to it using a plugin or you could use the Theme My Login plugin and make it match the site. The Theme My Login plugin also takes care of redirecting users to a page outside the normal WordPress admin. One issue that arises is that we now have 4-5 pages (login, logout, forgot password, register, etc…) created by the Theme My Login plugin that need be visible without logging in. We need to go back to our login_redirect() function and whitelist those pages from auth_redirect().
// Redirect users who are not logged in... function login_redirect() { // Current page and post obj global $pagenow, $post; // Theme My Login pages $post_ids = array(111, 222, 333, 444); // Check if user is not logged in and not on the wp-login page if(!is_user_logged_in() && $pagenow != 'wp-login.php' && !in_array($post->ID,$post_ids) ) auth_redirect(); } add_action( 'wp', 'login_redirect' );
Now we have an array of post IDs that are whitelisted from auth_redirect().
Select Page/Post visibility with custom meta field
Of course keeping track of post IDs via manual code updates can be tedious. A better way is to just add a custom meta field that allow you select if the page requires a login or not. Advanced Custom Fields is a fantastic plugin that we can use to create that custom meta field.
Create a new field group and call it something like Page Visibility. Fill in the other settings something like:
- Field Label: This page is visible to
- Field Name: visibility
- Field Type: Select
- Required?: Yes
- Choices:
- logged_in : Logged in Users
- public : Anyone (Public)
- Default Value: logged_in
- Location
- Post Type equal to Page
- Options
- Position: Side
New lets go back to the login_redirect function and make some changes. We run a query to find all posts that are set to public. Then we loop through then and add the post IDs to the array of post IDs we want to whitelist.
// Redirect users who are not logged in... function login_redirect() { // Current page and post obj global $pagenow, $post; // get public pages $args = array( 'post_type' => 'page', 'meta_query' => array( array( 'key' => 'visibility', 'value' => 'public', 'compare' => '=', ), ), 'posts_per_page' => '-1' ); $posts = get_posts($args); $post_ids = array(); foreach ($posts as $_post) { $post_ids[] += $_post->ID; } // Check if user is not logged in and not on the wp-login page if(!is_user_logged_in() && $pagenow != 'wp-login.php' && !in_array($post->ID,$post_ids) ) auth_redirect(); } add_action( 'wp', 'login_redirect' );
Restrict media library uploads to logged in users
I found a great piece of code on StackExchange by Hakre: http://wordpress.stackexchange.com/a/37743
This code uses .htaccess to redirect all files in wp-content/uploads/ through a php file that verifies they are logged in before serving the file request.
One thing I ran into is that if you have any images/files on those pages that are whitelisted (or in the header/footer) they will also be blocked also. To get around that I added a small whitelist array of images to the top of dl-file.php.
require_once('wp-load.php'); global $pagenow; // whitelist images $whitelist = array('image01.jpg', 'image02.png'); $logo = get_option('options_logo'); $logo = wp_get_attachment_image_src($logo, 'full'); $whitelist[] = basename($logo[0]); is_user_logged_in() || in_array(basename($_SERVER['REQUEST_URI']), $whitelist) || auth_redirect(); list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL);
Note: If you are using Nginx you will need to create a custom vhost file that tells Nginx to pass through whichever files you don’t want it to cache.
Tags: authentication, php, uploads, wordpress
Categorized in: Code
Posted on February 16, 2014
Comments are closed here.