From d27f272247a40b1c3b183dbac9b30f8fe5c883af Mon Sep 17 00:00:00 2001 From: nacin Date: Thu, 21 Oct 2010 14:40:04 +0000 Subject: [PATCH] Rough first pass on map_meta_cap for custom post types. see #14122. git-svn-id: http://svn.automattic.com/wordpress/trunk@15890 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/capabilities.php | 125 ++++++++--------------------------- wp-includes/post.php | 56 ++++++++++++++-- 2 files changed, 77 insertions(+), 104 deletions(-) diff --git a/wp-includes/capabilities.php b/wp-includes/capabilities.php index ed03be6be..be2b3e7d2 100644 --- a/wp-includes/capabilities.php +++ b/wp-includes/capabilities.php @@ -817,11 +817,12 @@ function map_meta_cap( $cap, $user_id ) { $caps[] = 'edit_users'; // Explicit due to primitive fall through break; case 'delete_post': + case 'delete_page': $author_data = get_userdata( $user_id ); //echo "post ID: {$args[0]}
"; $post = get_post( $args[0] ); $post_type = get_post_type_object( $post->post_type ); - if ( $post_type && 'post' != $post_type->capability_type ) { + if ( 'delete_post' == $cap && $post_type && 'post' != $post_type->capability_type && ! $post_type->map_meta_cap ) { $args = array_merge( array( $post_type->cap->delete_post, $user_id ), $args ); return call_user_func_array( 'map_meta_cap', $args ); } @@ -837,69 +838,34 @@ function map_meta_cap( $cap, $user_id ) { if ( is_object( $post_author_data ) && $user_id == $post_author_data->ID ) { // If the post is published... if ( 'publish' == $post->post_status ) { - $caps[] = 'delete_published_posts'; + $caps[] = $post_type->cap->delete_published_posts; } elseif ( 'trash' == $post->post_status ) { if ('publish' == get_post_meta($post->ID, '_wp_trash_meta_status', true) ) - $caps[] = 'delete_published_posts'; + $caps[] = $post_type->cap->delete_published_posts; } else { // If the post is draft... - $caps[] = 'delete_posts'; + $caps[] = $post_type->cap->delete_posts; } } else { // The user is trying to edit someone else's post. - $caps[] = 'delete_others_posts'; + $caps[] = $post_type->cap->delete_others_posts; // The post is published, extra cap required. if ( 'publish' == $post->post_status ) - $caps[] = 'delete_published_posts'; + $caps[] = $post_type->cap->delete_published_posts; elseif ( 'private' == $post->post_status ) - $caps[] = 'delete_private_posts'; - } - break; - case 'delete_page': - $author_data = get_userdata( $user_id ); - //echo "post ID: {$args[0]}
"; - $page = get_page( $args[0] ); - $page_author_data = get_userdata( $page->post_author ); - //echo "current user id : $user_id, page author id: " . $page_author_data->ID . "
"; - // If the user is the author... - - if ('' != $page->post_author) { - $page_author_data = get_userdata( $page->post_author ); - } else { - //No author set yet so default to current user for cap checks - $page_author_data = $author_data; - } - - if ( is_object( $page_author_data ) && $user_id == $page_author_data->ID ) { - // If the page is published... - if ( $page->post_status == 'publish' ) { - $caps[] = 'delete_published_pages'; - } elseif ( 'trash' == $page->post_status ) { - if ('publish' == get_post_meta($page->ID, '_wp_trash_meta_status', true) ) - $caps[] = 'delete_published_pages'; - } else { - // If the page is draft... - $caps[] = 'delete_pages'; - } - } else { - // The user is trying to edit someone else's page. - $caps[] = 'delete_others_pages'; - // The page is published, extra cap required. - if ( $page->post_status == 'publish' ) - $caps[] = 'delete_published_pages'; - elseif ( $page->post_status == 'private' ) - $caps[] = 'delete_private_pages'; + $caps[] = $post_type->cap->delete_private_posts; } break; // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts case 'edit_post': + case 'edit_page': $author_data = get_userdata( $user_id ); //echo "post ID: {$args[0]}
"; $post = get_post( $args[0] ); $post_type = get_post_type_object( $post->post_type ); - if ( $post_type && 'post' != $post_type->capability_type ) { + if ( 'edit_post' == $cap && $post_type && 'post' != $post_type->capability_type && ! $post_type->map_meta_cap ) { $args = array_merge( array( $post_type->cap->edit_post, $user_id ), $args ); return call_user_func_array( 'map_meta_cap', $args ); } @@ -909,86 +875,44 @@ function map_meta_cap( $cap, $user_id ) { if ( is_object( $post_author_data ) && $user_id == $post_author_data->ID ) { // If the post is published... if ( 'publish' == $post->post_status ) { - $caps[] = 'edit_published_posts'; + $caps[] = $post_type->cap->edit_published_posts; } elseif ( 'trash' == $post->post_status ) { if ('publish' == get_post_meta($post->ID, '_wp_trash_meta_status', true) ) - $caps[] = 'edit_published_posts'; + $caps[] = $post_type->cap->edit_published_posts; } else { // If the post is draft... - $caps[] = 'edit_posts'; + $caps[] = $post_type->cap->edit_posts; } } else { // The user is trying to edit someone else's post. - $caps[] = 'edit_others_posts'; + $caps[] = $post_type->cap->edit_others_posts; // The post is published, extra cap required. if ( 'publish' == $post->post_status ) - $caps[] = 'edit_published_posts'; + $caps[] = $post_type->cap->edit_published_posts; elseif ( 'private' == $post->post_status ) - $caps[] = 'edit_private_posts'; - } - break; - case 'edit_page': - $author_data = get_userdata( $user_id ); - //echo "post ID: {$args[0]}
"; - $page = get_page( $args[0] ); - $page_author_data = get_userdata( $page->post_author ); - //echo "current user id : $user_id, page author id: " . $page_author_data->ID . "
"; - // If the user is the author... - if ( is_object( $page_author_data ) && $user_id == $page_author_data->ID ) { - // If the page is published... - if ( 'publish' == $page->post_status ) { - $caps[] = 'edit_published_pages'; - } elseif ( 'trash' == $page->post_status ) { - if ('publish' == get_post_meta($page->ID, '_wp_trash_meta_status', true) ) - $caps[] = 'edit_published_pages'; - } else { - // If the page is draft... - $caps[] = 'edit_pages'; - } - } else { - // The user is trying to edit someone else's page. - $caps[] = 'edit_others_pages'; - // The page is published, extra cap required. - if ( 'publish' == $page->post_status ) - $caps[] = 'edit_published_pages'; - elseif ( 'private' == $page->post_status ) - $caps[] = 'edit_private_pages'; + $caps[] = $post_type->cap->edit_private_posts; } break; case 'read_post': + case 'read_page': $post = get_post( $args[0] ); $post_type = get_post_type_object( $post->post_type ); - if ( $post_type && 'post' != $post_type->capability_type ) { + if ( 'read_post' == $cap && $post_type && 'post' != $post_type->capability_type && ! $post_type->map_meta_cap ) { $args = array_merge( array( $post_type->cap->read_post, $user_id ), $args ); return call_user_func_array( 'map_meta_cap', $args ); } if ( 'private' != $post->post_status ) { - $caps[] = 'read'; + $caps[] = $post_type->cap->read; break; } $author_data = get_userdata( $user_id ); $post_author_data = get_userdata( $post->post_author ); if ( is_object( $post_author_data ) && $user_id == $post_author_data->ID ) - $caps[] = 'read'; + $caps[] = $post_type->cap->read; else - $caps[] = 'read_private_posts'; - break; - case 'read_page': - $page = get_page( $args[0] ); - - if ( 'private' != $page->post_status ) { - $caps[] = 'read'; - break; - } - - $author_data = get_userdata( $user_id ); - $page_author_data = get_userdata( $page->post_author ); - if ( is_object( $page_author_data ) && $user_id == $page_author_data->ID ) - $caps[] = 'read'; - else - $caps[] = 'read_private_pages'; + $caps[] = $post_type->cap->read_private_posts; break; case 'edit_comment': $comment = get_comment( $args[0] ); @@ -1050,6 +974,13 @@ function map_meta_cap( $cap, $user_id ) { $caps[] = $cap; break; default: + // Handle meta capabilities for custom post types. + $post_type_meta_caps = _post_type_meta_capabilities(); + if ( isset( $post_type_meta_caps[ $cap ] ) ) { + $args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args ); + return call_user_func_array( 'map_meta_cap', $args ); + } + // If no meta caps match, return the original cap. $caps[] = $cap; } diff --git a/wp-includes/post.php b/wp-includes/post.php index 9ba61f647..03707f7b8 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -20,6 +20,7 @@ function create_initial_post_types() { '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */ 'capability_type' => 'post', + 'map_meta_cap' => true, 'hierarchical' => false, 'rewrite' => false, 'query_var' => false, @@ -31,6 +32,7 @@ function create_initial_post_types() { '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */ 'capability_type' => 'page', + 'map_meta_cap' => true, 'hierarchical' => true, 'rewrite' => false, 'query_var' => false, @@ -836,7 +838,8 @@ function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) * - menu_position - The position in the menu order the post type should appear. Defaults to the bottom. * - menu_icon - The url to the icon to be used for this menu. Defaults to use the posts icon. * - capability_type - The post type to use for checking read, edit, and delete capabilities. Defaults to "post". - * - capabilities - Array of capabilities for this post type. You can see accepted values in {@link get_post_type_capabilities()}. By default the capability_type is used to construct capabilities. + * - capabilities - Array of capabilities for this post type. You can see accepted values in {@link get_post_type_capabilities()}. By default the capability_type is used as a base to construct capabilities. + * - map_meta_cap - Whether to use the internal default meta capability handling. Defaults to false. * - hierarchical - Whether the post type is hierarchical. Defaults to false. * - supports - An alias for calling add_post_type_support() directly. See add_post_type_support() for Documentation. Defaults to none. * - register_meta_box_cb - Provide a callback function that will be called when setting up the meta boxes for the edit form. Do remove_meta_box() and add_meta_box() calls in the callback. @@ -866,7 +869,8 @@ function register_post_type($post_type, $args = array()) { // Args prefixed with an underscore are reserved for internal use. $defaults = array( 'labels' => array(), 'description' => '', 'publicly_queryable' => null, 'exclude_from_search' => null, - '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'capability_type' => 'post', 'capabilities' => array(), 'hierarchical' => false, + 'capability_type' => 'post', 'capabilities' => array(), 'map_meta_cap' => false, + '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'hierarchical' => false, 'public' => false, 'rewrite' => true, 'query_var' => true, 'supports' => array(), 'register_meta_box_cb' => null, 'taxonomies' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null, 'permalink_epmask' => EP_PERMALINK, 'can_export' => true, 'show_in_nav_menus' => null, 'show_in_menu' => null, @@ -978,22 +982,60 @@ function register_post_type($post_type, $args = array()) { * - read_private_posts - The capability that controls reading private posts. Defaults to "read_private . $capability_type . s" (read_private_posts). * - delete_post - The meta capability that controls deleting a particular object of this post type. Defaults to "delete_ . $capability_type" (delete_post). * + * @see map_meta_cap() * @since 3.0.0 + * * @param object $args * @return object object with all the capabilities as member variables */ function get_post_type_capabilities( $args ) { - $defaults = array( + global $_post_type_meta_capabilities; + + $default_capabilities = array( + // Meta capabilities are generally mapped to primitive capabilities depending on the context + // (which would be the post being edited/deleted/read), instead of granted to users or roles: 'edit_post' => 'edit_' . $args->capability_type, + 'read_post' => 'read_' . $args->capability_type, + 'delete_post' => 'delete_' . $args->capability_type, + // Primitive capabilities that are used outside of map_meta_cap(): 'edit_posts' => 'edit_' . $args->capability_type . 's', 'edit_others_posts' => 'edit_others_' . $args->capability_type . 's', 'publish_posts' => 'publish_' . $args->capability_type . 's', - 'read_post' => 'read_' . $args->capability_type, 'read_private_posts' => 'read_private_' . $args->capability_type . 's', - 'delete_post' => 'delete_' . $args->capability_type, ); - $labels = array_merge( $defaults, $args->capabilities ); - return (object) $labels; + // Primitive capabilities that are used within map_meta_cap(): + if ( $args->map_meta_cap ) { + $default_capabilities_for_mapping = array( + 'read' => 'read', + 'delete_posts' => 'delete_' . $args->capability_type . 's', + 'delete_private_posts' => 'delete_private_' . $args->capability_type . 's', + 'delete_published_posts' => 'delete_published_' . $args->capability_type . 's', + 'delete_others_posts' => 'delete_others_' . $args->capability_type . 's', + 'edit_private_posts' => 'edit_private_' . $args->capability_type . 's', + 'edit_published_posts' => 'edit_published_' . $args->capability_type . 's', + ); + $default_capabilities = array_merge( $default_capabilities, $default_capabilities_for_mapping ); + } + $capabilities = array_merge( $default_capabilities, $args->capabilities ); + if ( $args->map_meta_cap ) + _post_type_meta_capabilities( $capabilities ); + return (object) $capabilities; +} + +/** + * Stores or returns a list of post type meta caps for map_meta_cap(). + * + * @since 3.1.0 + * @access private + */ +function _post_type_meta_capabilities( $capabilities = null ) { + static $meta_caps = array(); + if ( null === $capabilities ) + return $meta_caps; + foreach ( $capabilities as $core => $custom ) { + if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) ) + $meta_caps[ $custom ] = $core; + } } /**