Allow Editors to edit pending posts but not draft ones

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

Read More

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_poststhere should be.

How do I solve this?

Related posts

Leave a Reply

1 comment

  1. 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;
    }