How can I prevent a writer from being able to edit an article that has been scheduled?

In the old WordPress that I had, the writer (a type of user that could not publish) was, after an article was schedule, unable to go back to the article and edit it. But now in WordPress 8.1 they (the writers) are able to go back and edit a schedule article. Is there a way to stop this?

writer = contributor

Related posts

2 comments

  1. Me, like @fischi think that filter 'user_has_cap' is the best choiche for the pourpose, however, I think that is better to the work, regardless the $_GET post or action: WordPress check the meta cabability on a per-post basis, using an additional argument.

    In few words, when filtering 'user_has_cap' for a meta capability (see https://codex.wordpress.org/Function_Reference/map_meta_cap) we have access to the post ID, and using it we can prevent an user edit or delete a specific post.

    add_filter( 'user_has_cap', 'no_edit_prending_for_contrib', 9999, 3 );
    
    function no_edit_prending_for_contrib ( $allcaps, $caps, $args ) {
      // an arry of action we want to prevent
      $prevent = array('edit_posts', 'delete_posts');
    
      // we are not checking for edit a post, do nothing
      if ( ! array_intersect( $prevent, (array) $caps ) ) return $allcaps; 
    
      // we are not checking for a specific post, do nothing
      if ( ! isset( $args[2] ) || ! is_numeric( $args[2] ) ) return $allcaps;
    
      // the user has the capability to edit published posts, do nothing
      if ( array_key_exists( 'edit_published_posts', (array) $allcaps ) ) return $allcaps;
    
      // if the post is not a future one, do nothing
      if ( get_post_status( $args[2] ) !== 'future' ) return $allcaps;
    
      // if we are here we have to prevent user to edit or delete post
      if ( isset($allcaps['edit_posts']) ) unset($allcaps['edit_posts']);
      if ( isset($allcaps['delete_posts']) ) unset($allcaps['delete_posts']);
      return $allcaps;
    }
    

    Using this code the contributors will be still able to see the pending posts, but in read only way, just like the posts published by other users.

  2. Whew, that one was hard to solve 😉 However, the thing is, you have to dig deep here.

    The function current_user_can() uses a lot of different functions afterwars, but you can filter user_has_cap, which basically checks if the logged in user has a specific capability (duh).

    As contributors are allowed (by default) to edit posts with a status other than publish (please correct me if I am wrong, i did not check for trash), and also the capabilites are checked multiple times while loading the admin screen, we have to check a few different things before returning an error:

    • Can the user edit_posts in the first place?`
    • Is the status of the post to be edited future?
    • Does the user want to edit the post or create a new one, and is a post set by the url? (probably the least important due to the post status).

    The (almost) solution

    If no post (by $_GET['post']) is set, the filter can continue without restriction.

    Afterwards, you have to check if the post_status is indeed future, if the action (by $_GET['action']) is really ‘edit’, and, of course, if the current user is allowed to edit in the first place.

    add_filter( 'user_has_cap', 'f711_restrict_editing_future', 1, 3 );
    
    function f711_restrict_editing_future ( $allcaps, $cap, $args ) {
        // check if a post ist set
        if ( !isset( $_GET['post'] ) ) return $allcaps;
        // get the post
        $thispost = get_post( (int) $_GET['post'] );
        // check everything else
        if ( $cap[0] == 'edit_posts' && $thispost->post_status == 'future' && $_GET['action'] == 'edit' && $allcaps['contributor'] == 1 ) {
            wp_die( 'post is scheduled' );
        }
        return $allcaps;
    }
    

    The Problems

    This function to filter your user role just checks at the time the user wants to edit the future post. You may have to filter the lists of the posts too – to avoid displaying the link to the post in the first place.

    The second issue is, this solution depends on the user having the role of the contributor. You may have to adjust these settings as well, if you want to have a general solution for this problem.

    However, to anser your question – with this function you prevent contributors to edit future posts

    Not the most elegant way, but I hope you get the twist 🙂

Comments are closed.