[wp-trac] [WordPress Trac] #30452: _wp_translate_postdata() aggressively checks current_user_can( $ptype->cap->edit_others_posts ) on update

WordPress Trac noreply at wordpress.org
Mon May 4 18:59:58 UTC 2015


#30452: _wp_translate_postdata() aggressively checks current_user_can(
$ptype->cap->edit_others_posts ) on update
-------------------------------+-----------------------------
 Reporter:  danielbachhuber    |       Owner:
     Type:  defect (bug)       |      Status:  new
 Priority:  normal             |   Milestone:  Future Release
Component:  Posts, Post Types  |     Version:
 Severity:  normal             |  Resolution:
 Keywords:  dev-feedback       |     Focuses:
-------------------------------+-----------------------------

Comment (by jeremyclarke):

 Okay after further investigation I now understand Daniel's original
 comment and can say I agree completely with his judgement. Since this
 apparently hasn't gained any traction I'll take a stab at re-explaning the
 problem to emphasize that the second check is probably unnecessary and
 completely destroys the usefulness of the edit_posts map_meta_cap system.

 '''The check for edit_posts works great and does what we need'''

 `_wp_translate_postdata` essentially starts with a check  for whether the
 current user is allowed to edit the post in question:

 `if ( $update && ! current_user_can( 'edit_post', $post_data['ID'] ) )
 {...}`

 This will run a barrage of permissions tests depending on context. Most
 importantly for this bug, `edit_post` includes a `map_meta_cap` for
 `edit_others_posts` which is run as-necessary if the editing user is not
 the "author" of the post.

 This is great! One check with tons of intelligence behind it that covers
 lots of ground. Even better, the `map_meta_cap` system allows plugins
 (like Edit Flow) to filter the outcome with the context of the `author_id`
 and `post_id`. In the case of Daniel and me this lets us delegate
 conditional `edit_others_posts` to author/contributor accounts if they
 meet some criteria in relation to particular posts (for me it's if they
 are subscribed to notifications on the post in Edit Flow).

 '''The second check for edit_others_posts is useless and breaks
 `map_meta_cap`'''

 For some reason (I can imagine many causes as this code matured) the
 author testing algorithm from the `edit_post` is duplicated in
 `_wp_translate_postdata` including testing if current user is the author.
 This is unnecessary because the test would have already been done in
 `edit_posts`.

 Just looking at the function you can see the many hints that the two
 stanzas are redundant: They both run `current_user_can`, they both branch
 for `post_type=page` and they both have 4 instances of the same error
 message ('You are not allowed to create posts as this user.')

 '''The big problem''' is that this second check provides no context for
 the `edit_others_posts` test:

 {{{
 if ( isset( $post_data['user_ID'] )
 && ( $post_data['post_author'] != $post_data['user_ID'] )
 && ! current_user_can( $ptype->cap->edit_others_posts ) ) {
 }}}

 This means that if a user doesn't explicitly have `edit_others_posts` they
 won't be able to save the post regardless of how the `map_meta_cap` value
 is filtered.

 '''The worst part is that it makes the UI horribly inconsistent'''

 This bug affects `_wp_translate_postdata()`, but that function isn't run
 ever time the `map_meta_cap` for the `edit_post` capability is checked,
 and it seems that in all the other cases `map_meta_cap` works correctly,
 this means some things work and others don't which is super confusing and
 can cause all kinds of bugs.

 Specifically, a user given conditional `edit_posts` privileges for a post
 is able to log in, view the post in the editor, change it's content and
 push the "Update" button to reload the page, but when they do so they get
 an error and all their changes are lost because saving the post triggers
 `_wp_translate_postdata()` which fails. This is totally unnacceptable,
 since it results in lost data and a frustration we can all relate to at
 having to rewrite your changes (potentially multiple times before you
 figure out that it's never going to work).

 It also means that many people trying to use `map_meta_cap` this way are
 likely to think it works when it really doesn't. We should be able to
 assume that if a user can see a post's edit screen they can edit it, but
 this bug completely breaks that logic. I found at least one other dev
 while searching who, like me, thought it was working and only realized
 later this bug was breaking things.


 '''At bare minimum the check for `edit_others_posts` should be replaced
 with a second `edit_posts` + `post_id` check'''

 I suspect that whole second stanza can be removed by reworking the
 function, but I don't know the effect of the `post_author_override`
 section between the two capability checks, so maybe we still need to to
 the second check.

 If so it should still be changed to match the first one:

 `current_user_can( 'edit_post', $post_data['ID'] )`

 This will have the desired effect of testing the case where the editing
 user is not the post author while still honoring the `map_meta_cap`
 filter.

--
Ticket URL: <https://core.trac.wordpress.org/ticket/30452#comment:4>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list