8

I have a large number of users with Editor Capabilities that help to go through the post submissions. This is my current setup for this role:

Editor Capabilities

As you can see, they are allowed to edit_posts and edit_others_posts but they cannot edit_published_posts. This means that they can edit posts that are in Draft and Pending status.

Now, I want to restrict them to only be able to edit pending posts. So, they won't have the ability to touch draft posts (unless if they are the author of the post). Unfortunately there is no capability like edit_pending_posts... there should be.

How do I solve this?

1 Answer 1

5

This is actually not hard. To add a new capability, call WP_Roles->add_cap(). You have to do this just once, because it will be stored in the database. So we use a plugin activation hook.

Note to other readers: All of the following code is plugin territory.

register_activation_hook( __FILE__, 'epp_add_cap' );

/**
 * Add new capability to "editor" role.
 *
 * @wp-hook "activate_" . __FILE__
 * @return  void
 */
function epp_add_cap()
{
    global $wp_roles;

    if ( ! isset( $wp_roles ) )
        $wp_roles = new WP_Roles;

    $wp_roles->add_cap( 'editor', 'edit_pending_posts' );
}

Now we have to filter all calls for …

current_user_can( $post_type_object->cap->edit_post, $post->ID );

… because that is how WordPress checks if an user can edit a post. Internally, this will be mapped to the edit_others_posts capability for other authors posts.

So we have to filter user_has_cap and look into our new edit_pending_posts capability when some wants to use the edit_post capability.

I have included delete_post too, because this also a kind of an edit.

Sound complicated, but it is really simple:

add_filter( 'user_has_cap', 'epp_filter_cap', 10, 3 );

/**
 * Allow editing others pending posts only with "edit_pending_posts" capability.
 * Administrators can still edit those posts.
 *
 * @wp-hook user_has_cap
 * @param   array $allcaps All the capabilities of the user
 * @param   array $caps    [0] Required capability ('edit_others_posts')
 * @param   array $args    [0] Requested capability
 *                         [1] User ID
 *                         [2] Post ID
 * @return  array
 */
function epp_filter_cap( $allcaps, $caps, $args )
{
    // Not our capability
    if ( ( 'edit_post' !== $args[0] && 'delete_post' !== $args[0] )
        or empty ( $allcaps['edit_pending_posts'] )
    )
        return $allcaps;

    $post = get_post( $args[2] );


    // Let users edit their own posts
    if ( (int) $args[1] === (int) $post->post_author
        and in_array(
            $post->post_status,
            array ( 'draft', 'pending', 'auto-draft' )
        )
    )
    {
        $allcaps[ $caps[0] ] = TRUE;
    }
    elseif ( 'pending' !== $post->post_status )
    { // Not our post status
        $allcaps[ $caps[0] ] = FALSE;
    }

    return $allcaps;
}
8
  • I made tests and ran into a few issues. Firstly, I had edit_posts and edit_others_posts on with the new edit_pending_posts. I tried just having edit_pending_posts on without the other two and the post menu did not appear. When testing this, I found that I could add a new post, but couldn't save the draft (You are not allowed to edit this post notice). Did you test to save your own post in this role? Editing pending posts are fine.
    – Christine Cooper
    Commented Apr 16, 2013 at 18:41
  • @ChristineCooper This happened because $post->post_author is passed as a string, but $args[1] as an integer. Sometimes. Stupid WordPress! I fixed it by casting both to integers. And I allowed editors to edit their own published posts. If you don’t want that, remove the return line in the block after // Let users edit their own posts.
    – fuxia
    Commented Apr 16, 2013 at 18:58
  • Got it! One issue remains. I tested your updated code and it worked fine! However I do not want to allow the editors to edit their published posts so I removed that return $allcaps; line and the same permission issue appears with the saving of draft. Why?
    – Christine Cooper
    Commented Apr 16, 2013 at 19:12
  • Just to confirm, you were referring to remove the return line under $allcaps[ $caps[0] ] = TRUE;? Very odd that I am experiencing this, it doesn't make sense logically that it shouldn't work for me if it does for you, here is my setup: i.imgur.com/X3bv9rH.png
    – Christine Cooper
    Commented Apr 16, 2013 at 19:23
  • 1
    Try the plugin Members.
    – fuxia
    Commented Apr 16, 2013 at 19:52

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.