Extending WP-Members plugin: Add meta box for public/private

March 5th, 2012

About the Author: Dan

I’m Dan Smart, a 38 year old website developer, based in Swansea, UK. I have worked in the software development industry for over 15 years, with experience in web development, mobile handset development, and mobile networks. I work both on websites and web applications with systems such as Wordpress, Laravel, Backbone, Angular.js, node.js and mobile app development with PhoneGap, iOS, and Android. When I’m not developing websites and software, I am a keen runner, involved with mime performance group Innovo Physical Theatre, and also actively involved in my local church.

* Follow me on Twitter or contact me

I’ve been using the excellent WP-Members plugin, to extend the Swansea Community Church website, and have been pleased with its ability to offer all the membership/registration functionality that I need to add a membership section.

However there a couple of elements that I wanted to add to it to focus it for my needs.

  1. Firstly, to set a post as public or private (overriding the default ‘block all’ or ‘allow all’ settings), I needed to add a custom field to that post. This is fine for me as a developer, but as the admin of the site is not a developer, I wanted to make it more user friendly.
  2. Secondly, I want to be able to remove private posts from the loop (and this covers posts, podcasts, and things like the Recent Posts plugin, etc) when a visitor is not logged into the website, but then show everything to the logged-in user.

This blog article will address (1), and I’ll focus on (2) in a second post.

Existing Custom Fields

Currently the user has to add the following custom fields to make a post public or private:

  • ‘block’ with a value of true or ‘1’ to ensure that the post is blocked from non-logged in users.
  • ‘unblock’ with a value of true or ‘1’ to ensure that the post is visible to all users.

If a user does not set one of these values, the visibility will depend on the setting that they have set in the Settings -> WP Members screen, which if you don’t change any settings, defaults to block posts to non-logged in users.

Custom fields on their own (with no UI) have a couple of problems:

  1. It requires the user to remember the field name
  2. The user must remember the potential values for the field
  3. The user has to know how to view a post’s custom fields (as WordPress hides it by default)

I should point out that this is no fault of the plugin author, rather WordPress continues to add functionality and has made it very easy to add a user interface over custom fields.

Add Meta Box

The solution to this is to create a meta box that will set these fields in a more user friendly interface.

We will create a meta box that will allow the user to select one of three states:

  • Default – leave it as the settings
  • Public – force this post to be viewable to all (setting the ‘unblock’ field)
  • Private – force this post to be viewable only to logged in users (setting the ‘block’ field)

A set of radio buttons is the ideal solution for this – allowing users to choose only one option.

First we must hook into the ‘add_meta_boxes’ WordPress action. This fires when meta boxes are to be added to a post screen, and we pass it our function name that will draw the meta boxes.

  1. <?php
  3. add_action( 'add_meta_boxes', 'ds_members_addmetabox' );
  5. // backwards compatible (before WP 3.0)
  6. // add_action( 'admin_init', 'ds_members_addmetabox', 1 );
  7. /**
  8.  * Adds a box to the main column on the post type edit screens to allow users to select the visibility of their post
  9.  */
  10. function ds_members_addmetabox()
  11. {
  12.     // add the meta box to each post type
  13.     $post_types=get_post_types('','names');
  15.     foreach ($post_types as $post_type)
  16.     {
  17.         add_meta_box(
  18.             'ds_members_addblock_unblock_meta',
  19.             'Members',
  20.             'ds_members_addblock_unblock_meta',
  21.             $post_type,
  22.             'side',
  23.             'default'
  24.         );
  25.     }
  26. }
  27. ?>

We are using the add_meta_box function, passing it the id (arbitrary, but I normally set it to be the same as the callback function name), the title (‘Members’), our callback function name, the post type (more on this in a second), its position (on the side), and if it should appear at the top or the bottom (we’re happy with the default here).

We have to tell it which post type we are adding it to. Most examples add it to just ‘post’ and ‘page’, but what if your system is using custom post types (e.g. The Events Calendar uses an Event post type)? We can use the get_post_types() function to list out all the post types. We only care about the names of the post types so we call it with a second parameter of ‘names’ (so we can reduce the database query load).

We loop through the post types and add the meta box to each post type.

The meta box itself

Now we need to implement our meta box callback function. This is the one that outputs the meta box UI itself.

  1. <?php
  3. /**
  4.  * Display contents of post visibility meta box
  5.  */
  6. function ds_members_addblock_unblock_meta($post)
  7. {
  8.     $block = get_post_meta($post->ID, 'block', true);    // allows you to block a post if all posts are currently unblocked
  9.     $unblock = get_post_meta($post->ID, 'unblock', true); // allows you to unblock a post if all posts are currently blocked
  10.     $default = !($block || $unblock);    // default = whatever is currently set in the WP Member settings
  12. ?>
  13.     <p>Customise the visibility of this article for logged in users.</p>
  14.     <p><input type="radio" value="default" name="members_block_unblock" <?php echo ($default ? 'checked' : ''); ?>/> Default dependent on your default members settings</p>    
  15.     <p><input type="radio" value="public" name="members_block_unblock" <?php echo ($unblock ? 'checked' : ''); ?>/> Public visible to all users</p>    
  16.     <p><input type="radio" value="private" name="members_block_unblock" <?php echo ($block ? 'checked' : ''); ?>/> Private logged in members only</p>    
  17. <?php
  18. }
  19. ?>

Here we’re getting the meta box values. We first get the custom fields ‘block’ and ‘unblock’ using get_post_meta(). We decide if it’s got any of those fields set – if not, we know that the user is using just the ‘default’ setting.

Then we output the radio buttons, and set them to be ‘checked’ if the appropriate value has been set.

Saving the meta box

Now we need to be able to save the settings when the post type is saved. We use the ‘save_post’ action to save our custom fields:

  1. <?php
  3. add_action( 'save_post', 'ds_members_save_postmeta' );
  4. /**
  5. * Save the post visibility custom meta
  6. */
  7. function ds_members_save_postmeta($post_id)
  8. {
  9. // verify if this is an auto save routine.
  10. // If it is our form has not been submitted, so we dont want to do anything
  11. if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
  12. return;
  14. if (isset($_POST['members_block_unblock']))
  15. {
  16. $block_unblock = $_POST['members_block_unblock'];
  17. switch ($block_unblock)
  18. {
  19. case 'default':
  20. delete_post_meta($post_id, 'block');
  21. delete_post_meta($post_id, 'unblock');
  22. break;
  23. case 'private':
  24. update_post_meta($post_id, 'block', '1');
  25. delete_post_meta($post_id, 'unblock');
  26. break;
  27. case 'public':
  28. delete_post_meta($post_id, 'block');
  29. update_post_meta($post_id, 'unblock', '1');
  30. break;
  31. }
  32. }
  33. }
  35. ?>

First we do some default checking (you can also check a member’s capability and access level here, but I’ve left this out for clarity’s sake. See the add_meta_box example for more details).

Then we check whether our radio button field has been set in the $_POST array, and depending on the value that was set, we use update_post_meta() to set the value, and delete_post_meta() to delete the value that we do not want set (in case the user has changed their mind).


And that’s it, you’ve now got a nice user interface that less technical people can use to administer your membership-based website, allowing them to set posts to be public or private without knowing the details of how to set custom fields.

Let me know if this was useful to you, or if you have any comments. Check back in soon for the second part addressing the visibility of posts.

Switch to mobile version