From 5edec1d792b159fe2462e2624c491113ee287e7b Mon Sep 17 00:00:00 2001 From: Andrew Nacin Date: Tue, 4 Mar 2014 03:08:54 +0000 Subject: [PATCH] Don't default to current user for capability checks when dealing with a post without an author (post_author = 0). Undoes [12053]. While it risks breakage, this is a far safer and saner default for these situations. props danielbachhuber. fixes #27020. git-svn-id: https://develop.svn.wordpress.org/trunk@27390 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/capabilities.php | 49 +++++++++-------------- tests/phpunit/tests/user/capabilities.php | 27 +++++++++++++ tests/phpunit/tests/user/mapMetaCap.php | 14 +++++++ 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php index 4bdc28cc95..89e854b7a1 100644 --- a/src/wp-includes/capabilities.php +++ b/src/wp-includes/capabilities.php @@ -1071,20 +1071,15 @@ function map_meta_cap( $cap, $user_id ) { break; } - $post_author_id = $post->post_author; - - // If no author set yet, default to current user for cap checks. - if ( ! $post_author_id ) - $post_author_id = $user_id; - - // If the user is the author... - if ( $user_id == $post_author_id ) { + // If the post author is set and the user is the author... + if ( $post->post_author && $user_id == $post->post_author ) { // If the post is published... if ( 'publish' == $post->post_status ) { $caps[] = $post_type->cap->delete_published_posts; } elseif ( 'trash' == $post->post_status ) { - if ('publish' == get_post_meta($post->ID, '_wp_trash_meta_status', true) ) + if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) { $caps[] = $post_type->cap->delete_published_posts; + } } else { // If the post is draft... $caps[] = $post_type->cap->delete_posts; @@ -1093,10 +1088,11 @@ function map_meta_cap( $cap, $user_id ) { // The user is trying to edit someone else's post. $caps[] = $post_type->cap->delete_others_posts; // The post is published, extra cap required. - if ( 'publish' == $post->post_status ) + if ( 'publish' == $post->post_status ) { $caps[] = $post_type->cap->delete_published_posts; - elseif ( 'private' == $post->post_status ) + } elseif ( 'private' == $post->post_status ) { $caps[] = $post_type->cap->delete_private_posts; + } } break; // edit_post breaks down to edit_posts, edit_published_posts, or @@ -1121,20 +1117,15 @@ function map_meta_cap( $cap, $user_id ) { break; } - $post_author_id = $post->post_author; - - // If no author set yet, default to current user for cap checks. - if ( ! $post_author_id ) - $post_author_id = $user_id; - - // If the user is the author... - if ( $user_id == $post_author_id ) { + // If the post author is set and the user is the author... + if ( $post->post_author && $user_id == $post->post_author ) { // If the post is published... if ( 'publish' == $post->post_status ) { $caps[] = $post_type->cap->edit_published_posts; } elseif ( 'trash' == $post->post_status ) { - if ('publish' == get_post_meta($post->ID, '_wp_trash_meta_status', true) ) + if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) { $caps[] = $post_type->cap->edit_published_posts; + } } else { // If the post is draft... $caps[] = $post_type->cap->edit_posts; @@ -1143,10 +1134,11 @@ function map_meta_cap( $cap, $user_id ) { // The user is trying to edit someone else's post. $caps[] = $post_type->cap->edit_others_posts; // The post is published, extra cap required. - if ( 'publish' == $post->post_status ) + if ( 'publish' == $post->post_status ) { $caps[] = $post_type->cap->edit_published_posts; - elseif ( 'private' == $post->post_status ) + } elseif ( 'private' == $post->post_status ) { $caps[] = $post_type->cap->edit_private_posts; + } } break; case 'read_post': @@ -1173,18 +1165,13 @@ function map_meta_cap( $cap, $user_id ) { break; } - $post_author_id = $post->post_author; - - // If no author set yet, default to current user for cap checks. - if ( ! $post_author_id ) - $post_author_id = $user_id; - - if ( $user_id == $post_author_id ) + if ( $post->post_author && $user_id == $post->post_author ) { $caps[] = $post_type->cap->read; - elseif ( $status_obj->private ) + } elseif ( $status_obj->private ) { $caps[] = $post_type->cap->read_private_posts; - else + } else { $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); + } break; case 'publish_post': $post = get_post( $args[0] ); diff --git a/tests/phpunit/tests/user/capabilities.php b/tests/phpunit/tests/user/capabilities.php index c120824a59..ad50d64f3c 100644 --- a/tests/phpunit/tests/user/capabilities.php +++ b/tests/phpunit/tests/user/capabilities.php @@ -524,6 +524,33 @@ class Tests_User_Capabilities extends WP_UnitTestCase { } } + function authorless_post_statuses() { + return array( array( 'draft' ), array( 'private' ), array( 'publish' ) ); + } + + /** + * @ticket 27020 + * @dataProvider authorless_post_statuses + */ + function test_authorless_post( $status ) { + // Make a post without an author + $post = $this->factory->post->create( array( 'post_author' => 0, 'post_type' => 'post', 'post_status' => $status ) ); + + // Add an editor and contributor + $editor = $this->factory->user->create_and_get( array( 'role' => 'editor' ) ); + $contributor = $this->factory->user->create_and_get( array( 'role' => 'contributor' ) ); + + // editor can edit, view, and trash + $this->assertTrue( $editor->has_cap( 'edit_post', $post ) ); + $this->assertTrue( $editor->has_cap( 'delete_post', $post ) ); + $this->assertTrue( $editor->has_cap( 'read_post', $post ) ); + + // a contributor cannot (except read a published post) + $this->assertFalse( $contributor->has_cap( 'edit_post', $post ) ); + $this->assertFalse( $contributor->has_cap( 'delete_post', $post ) ); + $this->assertEquals( $status === 'publish', $contributor->has_cap( 'read_post', $post ) ); + } + /** * @ticket 16714 */ diff --git a/tests/phpunit/tests/user/mapMetaCap.php b/tests/phpunit/tests/user/mapMetaCap.php index 43ee079e70..33b7f00d59 100644 --- a/tests/phpunit/tests/user/mapMetaCap.php +++ b/tests/phpunit/tests/user/mapMetaCap.php @@ -232,4 +232,18 @@ class Tests_User_MapMetaCap extends WP_UnitTestCase { $this->assertEquals( array( 'update_core' ), map_meta_cap( 'update_core', $this->user_id ) ); $this->assertEquals( array( 'edit_plugins' ), map_meta_cap( 'edit_plugins', $this->user_id ) ); } + + /** + * Test a post without an author. + * + * @ticket 27020 + */ + function test_authorless_posts_capabilties() { + $post_id = $this->factory->post->create( array( 'post_author' => 0, 'post_type' => 'post', 'post_status' => 'publish' ) ); + $editor = $this->factory->user->create( array( 'role' => 'editor' ) ); + + $this->assertEquals( array( 'edit_others_posts', 'edit_published_posts' ), map_meta_cap( 'edit_post', $editor, $post_id ) ); + $this->assertEquals( array( 'delete_others_posts', 'delete_published_posts' ), map_meta_cap( 'delete_post', $editor, $post_id ) ); + + } }