2

My Question is regarding User access control in wordpress

I have two user - admin (admin access) and user1(editor). My requirement is admin can do any modification in admin site. But user1 can only edit and update some pages and no access other access except assigned pages.

I have no idea how to implement this functionality so your help is required?

My working environment :

  1. wordpress v 3.2.1
  2. Theme is twenty ten

3 Answers 3

3

Very interesting question. It's a bit outside the scope of the typical rolls/capabilities functionality as it's more fine grained (unless I'm wrong -- very possible).

The first step would be to put some sort of way in that you can assign which posts a user can edit.

It makes the most sense to stick that the user's profile page. So you can hook into edit_user_profile, get all the pages on the site, and stick them in a multi select box. The code comments should explain the step by step a bit. edit_user_profile only shows up when editing other users' profiles.

<?php
add_action( 'edit_user_profile', 'wpse30211_user_profile' );
function wpse30211_user_profile( $user )
{
    // only show this on editor pages
    if( ! in_array( 'editor', $user->roles ) ) return;

    // get the pages.
    $pages = get_posts(
        array(
            'post_type'     => 'page',
            'numberposts'   => -1,
            'post_status'   => 'any',
        )
    );

    // Bail if we don't have pages.
    if( ! $pages ) return;

    // Which pages can our user edit?
    $allowed = get_user_meta( $user->ID, 'wpse30211_pages', true );
    if( ! is_array( $allowed ) || empty( $allowed ) ) $allowed = array();

    // nonce-i-fy things
    wp_nonce_field( 'wpse30211_nonce', 'wpse30211_nonce' );

    // section heading...
    echo '<h3>' . __( 'Grant this User permission to edit...' ) . '</h3>';
    echo '<select multiple="multiple" name="wpse30211[]">';
    echo '<option value="0">None</option>';
    foreach( $pages as $p )
    {
        // for use in checked() later...
        $selected = in_array( $p->ID, $allowed ) ? 'on' : 'off';
        echo '<option ' . selected( 'on', $selected, false ) . ' value="' . esc_attr( $p->ID ) . '">' . esc_html( $p->post_title ) . '</option>';
    }
    echo '</select>';
}

Next you need to save the extra data you added to peoples profile. To do that, you hook into edit_user_profile_update. Verify the nonce set in the above function, then check if the wpse30211 field is set and save the stuff with update_user_meta.

<?php
add_action( 'edit_user_profile_update', 'wpse30211_user_save' );
function wpse30211_user_save( $user_id )
{
    // verify our nonce
    if( ! isset( $_POST['wpse30211_nonce'] ) || ! wp_verify_nonce( $_POST['wpse30211_nonce'], 'wpse30211_nonce' ) )
        return;

    // make sure our fields are set
    if( ! isset( $_POST['wpse30211'] ) ) 
        return;

    $save = array();
    foreach( $_POST['wpse30211'] as $p )
    {
        $save[] = $p;
    }
    update_user_meta( $user_id, 'wpse30211_pages', $save );
}

Now the fun part: disallowing access to certain pages. To do that, you can hook into load-post.php, which fires when wp-admin/post.php, the post editing screen, is loaded. Grab the the post id being editted, check to make sure it's a page. Then, grab the current user with wp_get_current_user and get the pages they are allowed to edit with get_user_meta. If the current post ID isn't in the array of pages they're allowed to edit, call wp_die and kill the page.

<?php
add_action( 'load-post.php', 'wpse30211_kill_edit' );
function wpse30211_kill_edit()
{
    $post_id = isset( $_REQUEST['post'] ) ? absint( $_REQUEST['post'] ) : 0;
    if( ! $post_id ) return;

    // bail if this isn't a page
    if( 'page' !== get_post_type( $post_id ) ) return;

    $user = wp_get_current_user();
    $allowed = get_user_meta( $user->ID, 'wpse30211_pages', true );
    if( ! is_array( $allowed ) || empty( $allowed ) ) $allowed = array();

    // if the user can't edit this page, stop the loading...
    if( ! in_array( $post_id, $allowed ) )
    {
        wp_die( 
            __( 'User cannot edit this page' ),
            __( "You can't edit this post" ),
            array( 'response' => 403 )
        );
    }
}

Finally, you can hook into pre_update_post and stop that from updating of the user can't edit the page.

<?php
add_action( 'pre_post_update', 'wpse30211_stop_update' );
function wpse30211_stop_update( $post_id )
{
    // not a page? bail.
    if( 'page' !== get_post_type( $post_id ) ) return;

    $user = wp_get_current_user();
    $allowed = get_user_meta( $user->ID, 'wpse30211_pages', true );
    if( ! is_array( $allowed ) || empty( $allowed ) ) $allowed = array();

    if( ! in_array( $post_id, $allowed ) ) 
    {
        wp_die( 
            __( 'User cannot edit this page' ),
            __( "You can't edit this post" ),
            array( 'response' => 403 )
        );
    }
}

The above works, but I suspect there may be a way to do this a bit easier with WP's built in role & capabilities. Here's the whole thing as a plugin.

3
  • Thanks alot Christopher for such a nice explanation and code. I knew it this question is not for beginners and intermediate persons. I am glad that you took pain and give solution.
    – w3uiguru
    Commented Nov 14, 2011 at 8:04
  • wow @chrisguitarguy ... incredible solution... Im trying to impliment this but in a different way... In my case I want to use this to allow front end access to a specifica page or not... In other words if a user is assigned to a page or a post he can only see the posts he is assigned to, trying to figure out how to adapt this Greg - also a guitar guy Commented Feb 17, 2022 at 12:24
  • Honstly that's more of a use case for a membership plugin than something custom like this. But you could probably make it work by hooking into one of the filter around WP_Query to stop loading posts/pages/whatever on list pages and template_redirect to prevent loading single pages. Commented Feb 17, 2022 at 20:33
2

Ok, old question; but the solution lies already in the WP core. Unless you also want to prevent User1 from reading pages he has no editing privileges to. In which case you would need a role/access management system, such as the code in the accepted answer or plugins from the wordpress plugins directory.

If you only want to prevent editing: User1 set as Author (instead of Editor) will only be able to edit their own content. If you (as Admin) set User1 as the "Author" of the page or post you just created (usually at the bottom of the Edit screen), User1 will be able to edit it. You can create pages as Admin, and set author as "User1", granting User1 an editing access to the page.

Of course, like I said, this is irrelevant if you want to totally hide the other posts/pages from User1.

1

You can use a plugin like Justin Tadlock's Members or the Role Scoper plugin, with those you can customize all capabilities for the administrator as well as the editor roles (and any other roles for that matter). You can even define your own roles with capabilities.

1
  • Thanks Piet... with the help of plugins you suggested i accomplish my task.
    – w3uiguru
    Commented Nov 14, 2011 at 8:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.