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

  • What post_status do the posts have, after they were scheduled? Are they future?
    – fischi
    Mar 4 '14 at 22:30
  • Yes, they are set as future when the Editor selects schedule.
    – jnbdz
    Mar 4 '14 at 22:37
  • Maybe I could just use a filter to remove all the posts that have statuses I don't want them to see. If this is the only solution what filter or action should I use?
    – jnbdz
    Mar 4 '14 at 23:13

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.

  • 1
    Yeah, your solution works much better than mine, as it also disables the links to the posts to be edited. Very nice going just removing the capabilities in this special call to edit a post. Perfect @G.M.!
    – fischi
    Mar 5 '14 at 0:48

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 :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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