Fail gracefully when checking mapped cap against unregistered post type.
Post type objects are reponsible for mapping their capabilities to core caps. As a result, when the post type is no longer registered, the caps are no longer mapped. This causes problems when a post is left in the database after the post type is no longer present, and WP does an 'edit_post' or other cap check against it: a PHP notice is thrown, and the cap check always fails. As a more graceful fallback, we map all post-type-dependent caps onto 'edit_others_posts', which allows highly privileged users to be able to access orphaned content (such as comments belonging to disabled post types), while minimizing the possibility of unintended privilege escalation. We also add a `_doing_it_wrong()` notice, so that developers and site administrators are aware that the cap mapping is failing in the absence of the registered post type. Props mitchoyoshitaka, DrewAPicture, imath, codeelite, boonebgorges, nofearinc, SergeyBiryukov, jorbin, dlh. Fixes #16956. git-svn-id: https://develop.svn.wordpress.org/trunk@34091 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
4fdfdb6078
commit
829ae5f4ce
@ -53,6 +53,12 @@ function map_meta_cap( $cap, $user_id ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$post_type = get_post_type_object( $post->post_type );
|
$post_type = get_post_type_object( $post->post_type );
|
||||||
|
if ( ! $post_type ) {
|
||||||
|
/* translators: 1: post type, 2: capability name */
|
||||||
|
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
|
||||||
|
$caps[] = 'edit_others_posts';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! $post_type->map_meta_cap ) {
|
if ( ! $post_type->map_meta_cap ) {
|
||||||
$caps[] = $post_type->cap->$cap;
|
$caps[] = $post_type->cap->$cap;
|
||||||
@ -101,6 +107,12 @@ function map_meta_cap( $cap, $user_id ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$post_type = get_post_type_object( $post->post_type );
|
$post_type = get_post_type_object( $post->post_type );
|
||||||
|
if ( ! $post_type ) {
|
||||||
|
/* translators: 1: post type, 2: capability name */
|
||||||
|
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
|
||||||
|
$caps[] = 'edit_others_posts';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! $post_type->map_meta_cap ) {
|
if ( ! $post_type->map_meta_cap ) {
|
||||||
$caps[] = $post_type->cap->$cap;
|
$caps[] = $post_type->cap->$cap;
|
||||||
@ -143,6 +155,12 @@ function map_meta_cap( $cap, $user_id ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$post_type = get_post_type_object( $post->post_type );
|
$post_type = get_post_type_object( $post->post_type );
|
||||||
|
if ( ! $post_type ) {
|
||||||
|
/* translators: 1: post type, 2: capability name */
|
||||||
|
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
|
||||||
|
$caps[] = 'edit_others_posts';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! $post_type->map_meta_cap ) {
|
if ( ! $post_type->map_meta_cap ) {
|
||||||
$caps[] = $post_type->cap->$cap;
|
$caps[] = $post_type->cap->$cap;
|
||||||
@ -169,6 +187,12 @@ function map_meta_cap( $cap, $user_id ) {
|
|||||||
case 'publish_post':
|
case 'publish_post':
|
||||||
$post = get_post( $args[0] );
|
$post = get_post( $args[0] );
|
||||||
$post_type = get_post_type_object( $post->post_type );
|
$post_type = get_post_type_object( $post->post_type );
|
||||||
|
if ( ! $post_type ) {
|
||||||
|
/* translators: 1: post type, 2: capability name */
|
||||||
|
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
|
||||||
|
$caps[] = 'edit_others_posts';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$caps[] = $post_type->cap->publish_posts;
|
$caps[] = $post_type->cap->publish_posts;
|
||||||
break;
|
break;
|
||||||
|
@ -994,4 +994,27 @@ class Tests_User_Capabilities extends WP_UnitTestCase {
|
|||||||
|
|
||||||
$this->assertFalse( current_user_can( 'edit_user', $super_admin->ID ) );
|
$this->assertFalse( current_user_can( 'edit_user', $super_admin->ID ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ticket 16956
|
||||||
|
*/
|
||||||
|
function test_require_edit_others_posts_if_post_type_doesnt_exist() {
|
||||||
|
register_post_type( 'existed' );
|
||||||
|
$post_id = $this->factory->post->create( array( 'post_type' => 'existed' ) );
|
||||||
|
_unregister_post_type( 'existed' );
|
||||||
|
|
||||||
|
$subscriber_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
|
||||||
|
$editor_id = $this->factory->user->create( array( 'role' => 'editor' ) );
|
||||||
|
|
||||||
|
$this->setExpectedIncorrectUsage( 'map_meta_cap' );
|
||||||
|
foreach ( array( 'delete_post', 'edit_post', 'read_post', 'publish_post' ) as $cap ) {
|
||||||
|
wp_set_current_user( $subscriber_id );
|
||||||
|
$this->assertSame( array( 'edit_others_posts' ), map_meta_cap( $cap, $subscriber_id, $post_id ) );
|
||||||
|
$this->assertFalse( current_user_can( $cap, $post_id ) );
|
||||||
|
|
||||||
|
wp_set_current_user( $editor_id );
|
||||||
|
$this->assertSame( array( 'edit_others_posts' ), map_meta_cap( $cap, $editor_id, $post_id ) );
|
||||||
|
$this->assertTrue( current_user_can( $cap, $post_id ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user