/** * Filters cap. * * @param type $capability_requested * @return string */ function wpcf_access_exceptions_check() { $args = func_get_args(); $capability_requested = $args[0][0]; $parse_args = $args[0][1]; $args = $args[0][2]; $found = wpcf_access_search_cap($capability_requested); // Allow filtering list($capability_requested, $parse_args, $args) = apply_filters('wpcf_access_exceptions', array($capability_requested, $parse_args, $args, $found)); switch ($capability_requested) { case 'edit_comment': $capability_requested = 'edit_posts'; $parse_args['caps'] = array('edit_published_posts', 'edit_comment'); break; case 'moderate_comments': $capability_requested = 'edit_others_posts'; $parse_args['caps'] = array('edit_published_posts', 'edit_comment'); break; // case 'delete_post': // case 'edit_post': // case 'delete_post': // case 'edit_post': default: // TODO Wachout for more! if (isset($args[1]) && isset($args[2])) { $user = get_userdata(intval($args[1])); $post_id = intval($args[2]); $post = get_post($post_id); if (!empty($user->ID) && !empty($post)) { $parse_args_clone = $parse_args; $args_clone = $args; // check post id is valid, avoid capabilities warning if (intval($post->ID) > 0) { $map = map_meta_cap($capability_requested, $user->ID, $post->ID); if (is_array($map) && !empty($map[0])) { foreach ($map as $cap) { $args_clone = array($cap); $result = wpcf_access_check($parse_args_clone['allcaps'], $map, $args_clone, false); if (!$result) { $parse_args['caps'] = array(); } } } } // Not sure why we didn't use this mapping before $capability_requested = wpcf_access_map_cap($capability_requested, $post_id); } if (WPCF_ACCESS_DEBUG) { global $wpcf_access; $wpcf_access->debug_hooks_with_args[$capability_requested][] = array('args' => $args); } } break; } return array($capability_requested, $parse_args, $args); }
function r21138_xmlrpc_edit_posts($caps, $cap, $user_id, $args) { if (!isset($args[0]) || isset($args[1]) && $args[1] === 'hotfixed') { return $caps; } foreach (get_post_types(array(), 'objects') as $post_type_object) { if ($cap === $post_type_object->cap->edit_posts) { return map_meta_cap($post_type_object->cap->edit_post, $user_id, $args[0], 'hotfixed'); } } return $caps; }
function _pp_flt_map_media_meta_cap($caps, $cap, $user_id, $args) { if (!empty($args[0])) { $post = is_object($args[0]) ? $args[0] : get_post($args[0]); if ($post && 'attachment' == $post->post_type) { if (!empty($post->post_parent)) { $post_status = get_post_status($post->ID); } elseif ('inherit' == $post->post_status) { $post_status = pp_get_option('unattached_files_private') ? 'private' : 'publish'; } else { $post_status = $post->post_status; } $post_type = get_post_type_object($post->post_type); $post_author_id = $post->post_author; $caps = array_diff($caps, (array) $cap); switch ($cap) { case 'read_post': case 'read_page': $status_obj = get_post_status_object($post_status); if ($status_obj->public || $status_obj->private && $user_id == $post_author_id) { $caps[] = $post_type->cap->read; break; } // If no author set yet, default to current user for cap checks. if (!$post_author_id) { $post_author_id = $user_id; } if ($status_obj->private) { $caps[] = $post_type->cap->read_private_posts; } else { $caps = map_meta_cap('edit_post', $user_id, $post->ID); } $caps = apply_filters('pp_map_attachment_read_caps', $caps, $post, $user_id); break; default: require_once dirname(__FILE__) . '/media-edit-metacap-workaround_pp.php'; $args = array_merge($args, compact('post', 'post_status', 'post_type', 'post_author_id')); $caps = _ppff_flt_map_media_edit_meta_cap($caps, $cap, $user_id, $args); } } } return $caps; }
/** * WP 3.5 This is fix for inserting to editor. * * New GUI checks if current use can 'edit_post' with certain ID * even if attachment is in question. * * Access logic requires that attachment in this case can be inserted * in parent post if user can edit parent post_type. * * @param type $null * @param type $parse_args * @return type */ function wpcf_access_files_override($null, $parse_args) { // To check if on media upload screen use // either basename($_SERVER['SCRIPT_NAME']) == 'async-upload.php' // or strpos($_SERVER['SCRIPT_NAME'], '/wp-admin/async-upload.php') !== false // Fix types upload if ($parse_args['cap'] == 'upload_files' && !isset($_REQUEST['action']) && isset($_POST['post_id']) && isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'], '/wp-admin/async-upload.php') !== false) { // This should be the end of a types image upload // temporarily set the $_REQUEST['action'] and process the same as send-attachment-to-editor $_REQUEST['action'] = 'types-end-image-upload'; } if ($parse_args['cap'] == 'upload_files' && isset($_REQUEST['fetch']) && isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'], '/wp-admin/async-upload.php') !== false) { // This should be the crunching part types image upload // We assume that if we got here then this request is ok. return wpcf_access_parse_caps(true, $parse_args); } // Fix ending to editor if (isset($_REQUEST['action'])) { $action = strval($_REQUEST['action']); switch ($action) { case 'send-attachment-to-editor': case 'types-end-image-upload': if ($_REQUEST['action'] == 'types-end-image-upload') { // remove the temporary action. unset($_REQUEST['action']); } $parent_id = intval($_POST['post_id']); // If user can edit parent post // than he can edit attachment too (at least in this case) $map = map_meta_cap($parse_args['cap'], get_current_user_id(), $parent_id); $result = wpcf_access_check($parse_args['allcaps'], $map, $parse_args['args'], false); if (!$result) { return wpcf_access_parse_caps(false, $parse_args); } else { return wpcf_access_parse_caps(true, $parse_args); } break; default: break; } } return $null; }
/** * Maps capability according to current user and post_id. * * @param type $parse_args * @param type $post_id * @return type */ function wpcf_access_map_cap($cap, $post_id) { $current_user = wp_get_current_user(); // do check for 0 post id if (intval($post_id) > 0) { $map = map_meta_cap($cap, $current_user->ID, $post_id); if (is_array($map) && !empty($map[0])) { return $map[0]; } } return $cap; }
/** * @ticket 16956 */ function test_require_edit_others_posts_if_post_type_doesnt_exist() { register_post_type('existed'); $post_id = self::factory()->post->create(array('post_type' => 'existed')); _unregister_post_type('existed'); $subscriber_id = self::$users['subscriber']->ID; $editor_id = self::$users['editor']->ID; $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)); } }
/** * Map meta capabilities to primitive capabilities. * * This does not actually compare whether the user ID has the actual capability, * just what the capability or capabilities are. Meta capability list value can * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post', * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'. * * @since 2.0.0 * * @param string $cap Capability name. * @param int $user_id User ID. * @return array Actual capabilities for meta capability. */ function map_meta_cap( $cap, $user_id ) { $args = array_slice( func_get_args(), 2 ); $caps = array(); switch ( $cap ) { case 'remove_user': $caps[] = 'remove_users'; break; case 'promote_user': $caps[] = 'promote_users'; break; case 'edit_user': case 'edit_users': // Allow user to edit itself if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] ) break; // If multisite these caps are allowed only for super admins. if ( is_multisite() && !is_super_admin( $user_id ) ) $caps[] = 'do_not_allow'; else $caps[] = 'edit_users'; // edit_user maps to edit_users. break; case 'delete_post': case 'delete_page': $post = get_post( $args[0] ); if ( 'revision' == $post->post_type ) { $post = get_post( $post->post_parent ); } $post_type = get_post_type_object( $post->post_type ); if ( ! $post_type->map_meta_cap ) { $caps[] = $post_type->cap->$cap; // Prior to 3.1 we would re-call map_meta_cap here. if ( 'delete_post' == $cap ) $cap = $post_type->cap->$cap; 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 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) ) $caps[] = $post_type->cap->delete_published_posts; } else { // If the post is draft... $caps[] = $post_type->cap->delete_posts; } } else { // 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 ) $caps[] = $post_type->cap->delete_published_posts; elseif ( 'private' == $post->post_status ) $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': $post = get_post( $args[0] ); if ( empty( $post ) ) break; if ( 'revision' == $post->post_type ) { $post = get_post( $post->post_parent ); } $post_type = get_post_type_object( $post->post_type ); if ( ! $post_type->map_meta_cap ) { $caps[] = $post_type->cap->$cap; // Prior to 3.1 we would re-call map_meta_cap here. if ( 'edit_post' == $cap ) $cap = $post_type->cap->$cap; 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 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) ) $caps[] = $post_type->cap->edit_published_posts; } else { // If the post is draft... $caps[] = $post_type->cap->edit_posts; } } else { // 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 ) $caps[] = $post_type->cap->edit_published_posts; elseif ( 'private' == $post->post_status ) $caps[] = $post_type->cap->edit_private_posts; } break; case 'read_post': case 'read_page': $post = get_post( $args[0] ); if ( 'revision' == $post->post_type ) { $post = get_post( $post->post_parent ); } $post_type = get_post_type_object( $post->post_type ); if ( ! $post_type->map_meta_cap ) { $caps[] = $post_type->cap->$cap; // Prior to 3.1 we would re-call map_meta_cap here. if ( 'read_post' == $cap ) $cap = $post_type->cap->$cap; break; } $status_obj = get_post_status_object( $post->post_status ); if ( $status_obj->public ) { $caps[] = $post_type->cap->read; 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 ) $caps[] = $post_type->cap->read; elseif ( $status_obj->private ) $caps[] = $post_type->cap->read_private_posts; else $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); break; case 'publish_post': $post = get_post( $args[0] ); $post_type = get_post_type_object( $post->post_type ); $caps[] = $post_type->cap->publish_posts; break; case 'edit_post_meta': case 'delete_post_meta': case 'add_post_meta': $post = get_post( $args[0] ); $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false; if ( $meta_key && has_filter( "auth_post_meta_{$meta_key}" ) ) { $allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps ); if ( ! $allowed ) $caps[] = $cap; } elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) { $caps[] = $cap; } break; case 'edit_comment': $comment = get_comment( $args[0] ); if ( empty( $comment ) ) break; $post = get_post( $comment->comment_post_ID ); $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); break; case 'unfiltered_upload': if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) ) ) $caps[] = $cap; else $caps[] = 'do_not_allow'; break; case 'unfiltered_html' : // Disallow unfiltered_html for all users, even admins and super admins. if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) $caps[] = 'do_not_allow'; elseif ( is_multisite() && ! is_super_admin( $user_id ) ) $caps[] = 'do_not_allow'; else $caps[] = $cap; break; case 'edit_files': case 'edit_plugins': case 'edit_themes': // Disallow the file editors. if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT ) $caps[] = 'do_not_allow'; elseif ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) $caps[] = 'do_not_allow'; elseif ( is_multisite() && ! is_super_admin( $user_id ) ) $caps[] = 'do_not_allow'; else $caps[] = $cap; break; case 'update_plugins': case 'delete_plugins': case 'install_plugins': case 'update_themes': case 'delete_themes': case 'install_themes': case 'update_core': // Disallow anything that creates, deletes, or updates core, plugin, or theme files. // Files in uploads are excepted. if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) $caps[] = 'do_not_allow'; elseif ( is_multisite() && ! is_super_admin( $user_id ) ) $caps[] = 'do_not_allow'; else $caps[] = $cap; break; case 'activate_plugins': $caps[] = $cap; if ( is_multisite() ) { // update_, install_, and delete_ are handled above with is_super_admin(). $menu_perms = get_site_option( 'menu_items', array() ); if ( empty( $menu_perms['plugins'] ) ) $caps[] = 'manage_network_plugins'; } break; case 'delete_user': case 'delete_users': // If multisite only super admins can delete users. if ( is_multisite() && ! is_super_admin( $user_id ) ) $caps[] = 'do_not_allow'; else $caps[] = 'delete_users'; // delete_user maps to delete_users. break; case 'create_users': if ( !is_multisite() ) $caps[] = $cap; elseif ( is_super_admin() || get_site_option( 'add_new_users' ) ) $caps[] = $cap; else $caps[] = 'do_not_allow'; break; case 'manage_links' : if ( get_option( 'link_manager_enabled' ) ) $caps[] = $cap; else $caps[] = 'do_not_allow'; 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; } return apply_filters('map_meta_cap', $caps, $cap, $user_id, $args); }
/** * @ticket 20488 */ function test_file_edit_caps_not_reliant_on_unfiltered_html_constant() { if ( defined( 'DISALLOW_FILE_MODS' ) || defined( 'DISALLOW_FILE_EDIT' ) ) $this->markTestSkipped('DISALLOW_FILE_MODS or DISALLOW_FILE_EDIT is defined.'); if ( defined( 'DISALLOW_UNFILTERED_HTML' ) ) { if ( ! DISALLOW_UNFILTERED_HTML ) $this->markTestSkipped( 'DISALLOW_UNFILTERED_HTML is defined.' ); } else { define( 'DISALLOW_UNFILTERED_HTML', true ); } $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 ) ); }
/** * Maps event capabilities * * @since 0.1.4 * * @link https://core.trac.wordpress.org/ticket/30991#comment:15 Bugs with mappings * * @param array $caps Capabilities for meta capability * @param string $cap Capability name * @param int $user_id User id * @param array $args Arguments * * @return array Actual capabilities for meta capability */ function wp_event_calendar_meta_caps($caps = array(), $cap = '', $user_id = 0, $args = array()) { // What capability is being checked? switch ($cap) { // Deleting case 'delete_event': $post = get_post($args[0]); if (!$post) { $caps[] = 'do_not_allow'; break; } if ('revision' == $post->post_type) { $post = get_post($post->post_parent); if (!$post) { $caps[] = 'do_not_allow'; break; } } // If the post author is set and the user is the author... if ((int) $user_id === $post->post_author) { // If the post is published or scheduled... if (in_array($post->post_status, array('publish', 'future'), true)) { $caps = array('delete_published_posts'); } elseif ('trash' === $post->post_status) { $status = get_post_meta($post->ID, '_wp_trash_meta_status', true); if (in_array($status, array('publish', 'future'), true)) { $caps = array('delete_published_posts'); } else { $caps = array('delete_posts'); } // If the post is draft... } else { $caps = array('delete_posts'); } // The user is trying to edit someone else's post. } else { $caps = array('delete_others_posts'); // The post is published or scheduled, extra cap required. if (in_array($post->post_status, array('publish', 'future'), true)) { $caps = array('delete_published_posts'); } elseif ('private' === $post->post_status) { $caps = array('delete_private_posts'); } } break; // Editing // Editing case 'edit_event': $post = get_post($args[0]); if (empty($post)) { $caps = array('do_not_allow'); break; } if ('revision' === $post->post_type) { $post = get_post($post->post_parent); if (empty($post)) { $caps = array('do_not_allow'); break; } } // If the post author is set and the user is the author... if ((int) $user_id === (int) $post->post_author) { // If the post is published or scheduled... if (in_array($post->post_status, array('publish', 'future'), true)) { $caps = array('edit_published_posts'); } elseif ('trash' === $post->post_status) { $status = get_post_meta($post->ID, '_wp_trash_meta_status', true); if (in_array($status, array('publish', 'future'), true)) { $caps = array('edit_published_posts'); } else { $caps = array('edit_posts'); } // If the post is draft... } else { $caps = array('edit_posts'); } // The user is trying to edit someone else's post. } else { $caps = array('edit_others_posts'); // The post is published or scheduled, extra cap required. if (in_array($post->post_status, array('publish', 'future'), true)) { $caps = array('edit_published_posts'); } elseif ('private' === $post->post_status) { $caps = array('edit_private_posts'); } } break; // Reading // Reading case 'read_event': $post = get_post($args[0]); if (empty($post)) { $caps = array('do_not_allow'); break; } if ('revision' == $post->post_type) { $post = get_post($post->post_parent); if (empty($post)) { $caps = 'do_not_allow'; break; } } $status_obj = get_post_status_object($post->post_status); if (true === $status_obj->public) { $caps = array('read'); break; } if ((int) $user_id === $post->post_author) { $caps = array('read'); } elseif (true === $status_obj->private) { $caps = array('read_private_posts'); } else { $caps = map_meta_cap('edit_post', $user_id, $post->ID); } break; // Remap // Remap case 'delete_events': $caps = array('delete_posts'); break; case 'delete_others_events': $caps = array('delete_others_events'); break; case 'create_events': case 'edit_events': case 'read_calendar': $caps = array('edit_posts'); break; case 'edit_others_events': $caps = array('edit_others_posts'); break; case 'publish_events': $caps = array('publish_posts'); break; } return apply_filters('wp_event_calendar_meta_caps', $caps, $cap, $user_id, $args); }
function draw_exceptions_ui($box, $args) { if (!isset($box['args'])) { return; } extract($box['args'], EXTR_SKIP); // $op extract($args, EXTR_SKIP); // $for_item_source, for_item_type, via_item_source global $wp_roles, $pp_current_user; $is_draft_post = false; if ('post' == $via_item_source) { if ('read' == $op) { global $post; $status_obj = get_post_status_object($post->post_status); if (!$status_obj || !$status_obj->public && !$status_obj->private) { $is_draft_post = true; } } $hierarchical = is_post_type_hierarchical($via_item_type); } else { $hierarchical = is_taxonomy_hierarchical($via_item_type); } if ($hierarchical = apply_filters('pp_do_assign_for_children_ui', $hierarchical, $via_item_type, $args)) { $type_obj = 'post' == $via_item_source ? get_post_type_object($via_item_type) : get_taxonomy($via_item_type); } $agent_types['wp_role'] = (object) array('labels' => (object) array('name' => __('WP Roles', 'pp'), 'singular_name' => __('WP Role', 'pp'))); $agent_types = apply_filters('pp_list_group_types', array_merge($agent_types, pp_get_group_types(array(), 'object'))); $agent_types['user'] = (object) array('labels' => (object) array('name' => __('Users'), 'singular_name' => __('User'))); //if ( ! $skip_user_validation && ! $pp_admin->user_can_admin_role($role_name, $item_id, $src_name, $object_type) ) // return; static $drew_itemroles_marker; if (empty($drew_itemroles_marker)) { echo "<input type='hidden' name='pp_post_exceptions' value='true' />"; $drew_itemroles_marker = true; } $current_exceptions = isset($this->data->current_exceptions[$for_item_type]) ? $this->data->current_exceptions[$for_item_type] : array(); // ========== OBJECT / TERM EXCEPTION DROPDOWNS ============ $toggle_agents = count($agent_types) > 1; if ($toggle_agents) { global $is_ID; $class_selected = 'agp-selected_agent agp-agent'; $class_unselected = 'agp-unselected_agent agp-agent'; $bottom_margin = !empty($is_IE) ? '-0.7em' : 0; $default_agent_type = 'wp_role'; echo "<div class='hide-if-not-js' style='margin:0 0 {$bottom_margin} 0'>" . "<ul class='pp-list_horiz' style='margin-bottom:-0.1em'>"; foreach ($agent_types as $agent_type => $gtype_obj) { $label = !empty($current_exceptions[$op][$agent_type]) ? sprintf(__('%1$s (%2$s)', 'pp'), $gtype_obj->labels->name, count($current_exceptions[$op][$agent_type])) : $gtype_obj->labels->name; $class = $default_agent_type == $agent_type ? "class='{$class_selected}'" : "class='{$class_unselected}'"; echo "<li {$class}><a href='javascript:void(0)' class='{$op}-{$for_item_type}-{$agent_type}'>" . $label . '</a></li>'; } echo '</ul></div>'; } $class = "class='pp-agents pp-exceptions'"; //need effective line break here if not IE echo "<div style='clear:both;margin:0 0 0.3em 0' {$class}>"; $pp_agents_ui = pp_init_agents_ui(); foreach (array_keys($agent_types) as $agent_type) { $hide_class = $toggle_agents && $agent_type != $default_agent_type ? ' class="hide-if-js"' : ''; echo "\r\n<div id='{$op}-{$for_item_type}-{$agent_type}' {$hide_class} style='overflow-x:auto'>"; $this->render->set_options($agent_type); // list all WP roles if ('wp_role' == $agent_type) { if (!isset($current_exceptions[$op][$agent_type])) { $current_exceptions[$op][$agent_type] = array(); } foreach ($this->data->agent_info['wp_role'] as $agent_id => $role) { if (in_array($role->metagroup_id, array('wp_anon', 'wp_all')) && !defined('PP_ALL_ANON_FULL_EXCEPTIONS') && ('read' != $op || pp_get_option('anonymous_unfiltered'))) { continue; } if (!isset($current_exceptions[$op][$agent_type][$agent_id])) { $current_exceptions[$op][$agent_type][$agent_id] = array(); } } if (!$is_draft_post && 'post' == $via_item_source && 'attachment' != $via_item_type && in_array($op, array('read', 'edit', 'delete'))) { $reqd_caps = map_meta_cap("{$op}_post", 0, $item_id); } else { $reqd_caps = false; } } global $wp_roles; ?> <table class="pp-item-exceptions-ui pp-exc-<?php echo $agent_type; ?> " style="width:100%"><tr> <?php if ('wp_role' != $agent_type) { ?> <td class="pp-select-exception-agents" style="display:none;"> <?php // Select Groups / Users UI echo '<div>'; echo '<div class="pp-agent-select">'; $args = array_merge($args, array('suppress_extra_prefix' => true, 'ajax_selection' => true, 'display_stored_selections' => false, 'create_dropdowns' => true, 'op' => $op, 'via_item_type' => $via_item_type)); $pp_agents_ui = pp_init_agents_ui(); $pp_agents_ui->agents_ui($agent_type, array(), "{$op}:{$for_item_type}:{$agent_type}", array(), $args); echo '</div>'; echo '</div>'; $colspan = 'colspan="2"'; ?> </td> <?php } else { $colspan = ''; // for html5 compliance } ?> <?php $any_stored = empty($current_exceptions[$op][$agent_type]) ? 0 : count($current_exceptions[$op][$agent_type]); ?> <td class="pp-current-item-exceptions" style="width:100%"> <div style="overflow:auto;max-height:325px"> <table <?php if (!$any_stored) { echo 'style="display:none"'; } ?> > <?php if ($hierarchical) { ?> <thead> <tr> <th></th> <th><?php printf(__('This %s', 'pp'), $type_obj->labels->singular_name); ?> </th> <th><?php if ($caption = apply_filters('pp_item_assign_for_children_caption', '', $via_item_type)) { printf($caption); } else { printf(__('Sub-%s', 'pp'), $type_obj->labels->name); } ?> </th> </tr> </thead> <?php } ?> <tbody> <?php // @todo: why is agent_id=0 in current_exceptions array? if ($any_stored) { if ('wp_role' == $agent_type) { foreach ($current_exceptions[$op][$agent_type] as $agent_id => $agent_exceptions) { if ($agent_id && isset($this->data->agent_info[$agent_type][$agent_id])) { $this->render->draw_row($agent_type, $agent_id, $current_exceptions[$op][$agent_type][$agent_id], $this->data->inclusions_active, $this->data->agent_info[$agent_type][$agent_id], compact('for_item_type', 'op', 'reqd_caps', 'hierarchical')); } } } else { foreach (array_keys($this->data->agent_info[$agent_type]) as $agent_id) { // order by agent name if ($agent_id && isset($current_exceptions[$op][$agent_type][$agent_id])) { $this->render->draw_row($agent_type, $agent_id, $current_exceptions[$op][$agent_type][$agent_id], $this->data->inclusions_active, $this->data->agent_info[$agent_type][$agent_id], compact('for_item_type', 'op', 'reqd_caps', 'hierarchical')); } } } } ?> </tbody> <tfoot<?php if ($any_stored < 2) { echo ' style="display:none;"'; } ?> > <?php $link_caption = 'wp_role' == $agent_type ? __('default all', 'pp') : __('clear all', 'pp'); ?> <tr> <td></td><td style="text-align:center"><a href="#clear-item-exc"><?php echo $link_caption; ?> </a></td> <?php if ($hierarchical) { ?> <td style="text-align:center"><a href="#clear-sub-exc"><?php echo $link_caption; ?> </a></td> <?php } ?> </tr> </tfoot> </table> </div> <?php if (!$any_stored) { ?> <div class="pp-no-exceptions"><?php _e('No access customizations stored.', 'pp'); ?> </div> <?php } ?> </td> </tr> <tr> <td class="pp-exception-actions" <?php echo $colspan; ?> > <?php if ('wp_role' != $agent_type) { ?> <a class="pp-select-exception-agents" href="#"><?php 'user' == $agent_type ? _e('select users', 'pp') : _e('select groups', 'pp'); ?> </a> <a class="pp-close-select-exception-agents" href="#" style="display:none;"><?php _e('close', 'pp'); ?> </a> <?php } if (pp_group_type_editable($agent_type) && pp_has_group_cap('pp_create_groups', 0, $agent_type)) { ?> • <a class="pp-create-exception-agent" href="admin.php?page=pp-group-new" target="_blank"><?php _e('create group', 'pp'); ?> </a> <?php } ?> </td> </tr> </table> </div> <?php } // end foreach group type caption echo '</div>'; // class pp-agents if ('read' == $op && pp_get_option('display_extension_hints') && ('attachment' == $for_item_type && !defined('PPFF_VERSION') || !defined('PPCE_VERSION'))) { require_once dirname(__FILE__) . '/item-exceptions-ui-hints_pp.php'; _ppc_item_ui_hints($for_item_type); } if ('term' == $via_item_source && in_array($op, array('read', 'edit'))) { $msg = __('To customize <strong>for a specific post status</strong>, edit the desired role / group / user permissions directly (Permissions > Groups or Users)', 'pp'); echo "<div class='pp-exc-notes'>{$msg}</div>"; } }
function _cr_user_can($reqd_caps, $object_id = 0, $user_id = 0, $meta_flags = array()) { // $meta_flags currently used for 'skip_revision_allowance', 'skip_any_object_check', 'skip_any_term_check', 'skip_id_generation', 'require_full_object_role' // For now, skip array_merge with defaults, for perf if ($user_id) { $user = new WP_User($user_id); } else { $user = wp_get_current_user(); } if (empty($user)) { return false; } $reqd_caps = (array) $reqd_caps; $check_caps = $reqd_caps; foreach ($check_caps as $cap_name) { if ($meta_caps = map_meta_cap($cap_name, $user->ID, $object_id)) { $reqd_caps = array_diff($reqd_caps, array($cap_name)); $reqd_caps = array_unique(array_merge($reqd_caps, $meta_caps)); } } if ('blog' === $object_id) { // legacy API support $meta_flags['skip_any_object_check'] = true; $meta_flags['skip_any_term_check'] = true; $meta_flags['skip_id_generation'] = true; } elseif (!$object_id) { $meta_flags['skip_id_generation'] = true; } if ($meta_flags) { // handle special case revisionary flag if (!empty($meta_flags['skip_revision_allowance'])) { if (defined('RVY_VERSION')) { global $revisionary; $revisionary->skip_revision_allowance = true; // this will affect the behavior of Role Scoper's user_has_cap filter } unset($meta_flags['skip_revision_allowance']); // no need to set this flag on cap_interceptor } // set temporary flags for use by our user_has_cap filter global $cap_interceptor; if (isset($cap_interceptor)) { foreach ($meta_flags as $flag => $value) { $cap_interceptor->{$flag} = $value; } } else { $meta_flags = array(); } } $capabilities = apply_filters('user_has_cap', $user->allcaps, $reqd_caps, array($reqd_caps, $user->ID, $object_id)); if ($meta_flags) { // clear temporary flags foreach ($meta_flags as $flag => $value) { $cap_interceptor->{$flag} = false; } } if (!empty($revisionary)) { $revisionary->skip_revision_allowance = false; } foreach ($reqd_caps as $cap_name) { if (empty($capabilities[$cap_name]) || !$capabilities[$cap_name]) { // if we're about to fail due to a missing create_child_pages cap, honor edit_pages cap as equivalent // TODO: abstract this with cap_defs property if ('create_child_pages' == $cap_name) { $alternate_cap_name = 'edit_pages'; $_args = array(array($alternate_cap_name), $user->ID, $object_id); $capabilities = apply_filters('user_has_cap', $user->allcaps, array($alternate_cap_name), $_args); if (empty($capabilities[$alternate_cap_name]) || !$capabilities[$alternate_cap_name]) { return false; } } else { return false; } } } return true; }
/** * 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)); }
function pp_map_meta_cap($cap_name, $user_id = 0, $post_id = 0, $args = array()) { if ($post_id) { return map_meta_cap($cap_name, $user_id, $post_id); } $defaults = array('is_author' => false, 'post_type' => '', 'status' => '', 'query_contexts' => array()); extract(array_merge($defaults, $args), EXTR_SKIP); global $current_user; if (!$post_type) { // sanity check return (array) $cap_name; } if (!$user_id) { $user_id = $current_user->ID; } // force desired status caps and others caps by passing a fake post into map_meta_cap $post_author = $is_author ? $user_id : -1; if (!$status) { $status = in_array($cap_name, array('read_post', 'read_page')) ? 'publish' : 'draft'; } elseif ('auto-draft' == $status) { $status = 'draft'; } $_post = (object) array('ID' => -1, 'post_type' => $post_type, 'post_status' => $status, 'filter' => 'raw', 'post_author' => $post_author, 'query_contexts' => $query_contexts); wp_cache_add(-1, $_post, 'posts'); // prevent querying for fake post $return = array_diff(map_meta_cap($cap_name, $user_id, $_post), array(null)); // post types which leave some basic cap properties undefined result in nulls wp_cache_delete(-1, 'posts'); return $return; }
/** * Test deleting posts page. * * @ticket 37580 */ function test_only_users_who_can_manage_options_can_delete_page_for_posts() { $post_id = self::factory()->post->create(array('post_type' => 'page', 'post_status' => 'publish')); update_option('page_for_posts', $post_id); $caps = map_meta_cap('delete_page', $this->user_id, $post_id); delete_option('page_for_posts'); $this->assertEquals(array('manage_options'), $caps); }
/** * Map meta capabilities to primitive capabilities. * * This does not actually compare whether the user ID has the actual capability, * just what the capability or capabilities are. Meta capability list value can * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post', * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'. * * @since 2.0.0 * * @global array $post_type_meta_caps Used to get post type meta capabilities. * * @param string $cap Capability name. * @param int $user_id User ID. * @param int $object_id Optional. ID of the specific object to check against if `$cap` is a "meta" cap. * "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used * by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts', * 'edit_others_posts', etc. The parameter is accessed via func_get_args(). * @return array Actual capabilities for meta capability. */ function map_meta_cap($cap, $user_id) { $args = array_slice(func_get_args(), 2); $caps = array(); switch ($cap) { case 'remove_user': // In multisite the user must be a super admin to remove themselves. if (isset($args[0]) && $user_id == $args[0] && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = 'remove_users'; } break; case 'promote_user': case 'add_users': $caps[] = 'promote_users'; break; case 'edit_user': case 'edit_users': // Allow user to edit itself if ('edit_user' == $cap && isset($args[0]) && $user_id == $args[0]) { break; } // In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin. if (is_multisite() && (!is_super_admin($user_id) && 'edit_user' === $cap && is_super_admin($args[0]) || !user_can($user_id, 'manage_network_users'))) { $caps[] = 'do_not_allow'; } else { $caps[] = 'edit_users'; // edit_user maps to edit_users. } break; case 'delete_post': case 'delete_page': $post = get_post($args[0]); if (!$post) { $caps[] = 'do_not_allow'; break; } if ('revision' == $post->post_type) { $post = get_post($post->post_parent); if (!$post) { $caps[] = 'do_not_allow'; break; } } if (get_option('page_for_posts') == $post->ID || get_option('page_on_front') == $post->ID) { $caps[] = 'manage_options'; break; } $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) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('delete_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } // 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 or scheduled... if (in_array($post->post_status, array('publish', 'future'), true)) { $caps[] = $post_type->cap->delete_published_posts; } elseif ('trash' == $post->post_status) { $status = get_post_meta($post->ID, '_wp_trash_meta_status', true); if (in_array($status, array('publish', 'future'), true)) { $caps[] = $post_type->cap->delete_published_posts; } else { $caps[] = $post_type->cap->delete_posts; } } else { // If the post is draft... $caps[] = $post_type->cap->delete_posts; } } else { // The user is trying to edit someone else's post. $caps[] = $post_type->cap->delete_others_posts; // The post is published or scheduled, extra cap required. if (in_array($post->post_status, array('publish', 'future'), true)) { $caps[] = $post_type->cap->delete_published_posts; } elseif ('private' == $post->post_status) { $caps[] = $post_type->cap->delete_private_posts; } } break; // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts case 'edit_post': case 'edit_page': $post = get_post($args[0]); if (!$post) { $caps[] = 'do_not_allow'; break; } if ('revision' == $post->post_type) { $post = get_post($post->post_parent); if (!$post) { $caps[] = 'do_not_allow'; break; } } $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) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('edit_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } // 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 or scheduled... if (in_array($post->post_status, array('publish', 'future'), true)) { $caps[] = $post_type->cap->edit_published_posts; } elseif ('trash' == $post->post_status) { $status = get_post_meta($post->ID, '_wp_trash_meta_status', true); if (in_array($status, array('publish', 'future'), true)) { $caps[] = $post_type->cap->edit_published_posts; } else { $caps[] = $post_type->cap->edit_posts; } } else { // If the post is draft... $caps[] = $post_type->cap->edit_posts; } } else { // The user is trying to edit someone else's post. $caps[] = $post_type->cap->edit_others_posts; // The post is published or scheduled, extra cap required. if (in_array($post->post_status, array('publish', 'future'), true)) { $caps[] = $post_type->cap->edit_published_posts; } elseif ('private' == $post->post_status) { $caps[] = $post_type->cap->edit_private_posts; } } break; case 'read_post': case 'read_page': $post = get_post($args[0]); if (!$post) { $caps[] = 'do_not_allow'; break; } if ('revision' == $post->post_type) { $post = get_post($post->post_parent); if (!$post) { $caps[] = 'do_not_allow'; break; } } $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) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('read_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } $status_obj = get_post_status_object($post->post_status); if ($status_obj->public) { $caps[] = $post_type->cap->read; break; } if ($post->post_author && $user_id == $post->post_author) { $caps[] = $post_type->cap->read; } elseif ($status_obj->private) { $caps[] = $post_type->cap->read_private_posts; } else { $caps = map_meta_cap('edit_post', $user_id, $post->ID); } break; case 'publish_post': $post = get_post($args[0]); if (!$post) { $caps[] = 'do_not_allow'; break; } $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; break; case 'edit_post_meta': case 'delete_post_meta': case 'add_post_meta': case 'edit_comment_meta': case 'delete_comment_meta': case 'add_comment_meta': case 'edit_term_meta': case 'delete_term_meta': case 'add_term_meta': case 'edit_user_meta': case 'delete_user_meta': case 'add_user_meta': list($_, $object_type, $_) = explode('_', $cap); $object_id = (int) $args[0]; switch ($object_type) { case 'post': $post = get_post($object_id); if (!$post) { break; } $sub_type = get_post_type($post); break; case 'comment': $comment = get_comment($object_id); if (!$comment) { break; } $sub_type = empty($comment->comment_type) ? 'comment' : $comment->comment_type; break; case 'term': $term = get_term($object_id); if (!$term) { break; } $sub_type = $term->taxonomy; break; case 'user': $user = get_user_by('id', $object_id); if (!$user) { break; } $sub_type = 'user'; break; } if (empty($sub_type)) { $caps[] = 'do_not_allow'; break; } $caps = map_meta_cap("edit_{$object_type}", $user_id, $object_id); $meta_key = isset($args[1]) ? $args[1] : false; $has_filter = has_filter("auth_{$object_type}_meta_{$meta_key}") || has_filter("auth_{$object_type}_{$sub_type}_meta_{$meta_key}"); if ($meta_key && $has_filter) { /** This filter is documented in wp-includes/meta.php */ $allowed = apply_filters("auth_{$object_type}_meta_{$meta_key}", false, $meta_key, $object_id, $user_id, $cap, $caps); /** This filter is documented in wp-includes/meta.php */ $allowed = apply_filters("auth_{$object_type}_{$sub_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps); if (!$allowed) { $caps[] = $cap; } } elseif ($meta_key && is_protected_meta($meta_key, $object_type)) { $caps[] = $cap; } break; case 'edit_comment': $comment = get_comment($args[0]); if (!$comment) { $caps[] = 'do_not_allow'; break; } $post = get_post($comment->comment_post_ID); /* * If the post doesn't exist, we have an orphaned comment. * Fall back to the edit_posts capability, instead. */ if ($post) { $caps = map_meta_cap('edit_post', $user_id, $post->ID); } else { $caps = map_meta_cap('edit_posts', $user_id); } break; case 'unfiltered_upload': if (defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && (!is_multisite() || is_super_admin($user_id))) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } break; case 'edit_css': case 'unfiltered_html': // Disallow unfiltered_html for all users, even admins and super admins. if (defined('DISALLOW_UNFILTERED_HTML') && DISALLOW_UNFILTERED_HTML) { $caps[] = 'do_not_allow'; } elseif (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = 'unfiltered_html'; } break; case 'edit_files': case 'edit_plugins': case 'edit_themes': // Disallow the file editors. if (defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT) { $caps[] = 'do_not_allow'; } elseif (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) { $caps[] = 'do_not_allow'; } elseif (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = $cap; } break; case 'update_plugins': case 'delete_plugins': case 'install_plugins': case 'upload_plugins': case 'update_themes': case 'delete_themes': case 'install_themes': case 'upload_themes': case 'update_core': // Disallow anything that creates, deletes, or updates core, plugin, or theme files. // Files in uploads are excepted. if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) { $caps[] = 'do_not_allow'; } elseif (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } elseif ('upload_themes' === $cap) { $caps[] = 'install_themes'; } elseif ('upload_plugins' === $cap) { $caps[] = 'install_plugins'; } else { $caps[] = $cap; } break; case 'activate_plugins': $caps[] = $cap; if (is_multisite()) { // update_, install_, and delete_ are handled above with is_super_admin(). $menu_perms = get_site_option('menu_items', array()); if (empty($menu_perms['plugins'])) { $caps[] = 'manage_network_plugins'; } } break; case 'delete_user': case 'delete_users': // If multisite only super admins can delete users. if (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = 'delete_users'; } // delete_user maps to delete_users. break; case 'create_users': if (!is_multisite()) { $caps[] = $cap; } elseif (is_super_admin($user_id) || get_site_option('add_new_users')) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } break; case 'manage_links': if (get_option('link_manager_enabled')) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } break; case 'customize': $caps[] = 'edit_theme_options'; break; case 'delete_site': if (is_multisite()) { $caps[] = 'manage_options'; } else { $caps[] = 'do_not_allow'; } break; case 'edit_term': case 'delete_term': case 'assign_term': $term_id = (int) $args[0]; $term = get_term($term_id); if (!$term || is_wp_error($term)) { $caps[] = 'do_not_allow'; break; } $tax = get_taxonomy($term->taxonomy); if (!$tax) { $caps[] = 'do_not_allow'; break; } if ('delete_term' === $cap && $term->term_id == get_option('default_' . $term->taxonomy)) { $caps[] = 'do_not_allow'; break; } $taxo_cap = $cap . 's'; $caps = map_meta_cap($tax->cap->{$taxo_cap}, $user_id, $term_id); break; case 'manage_post_tags': case 'edit_categories': case 'edit_post_tags': case 'delete_categories': case 'delete_post_tags': $caps[] = 'manage_categories'; break; case 'assign_categories': case 'assign_post_tags': $caps[] = 'edit_posts'; break; case 'create_sites': case 'delete_sites': case 'manage_network': case 'manage_sites': case 'manage_network_users': case 'manage_network_plugins': case 'manage_network_themes': case 'manage_network_options': $caps[] = $cap; break; default: // Handle meta capabilities for custom post types. global $post_type_meta_caps; 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; } /** * Filters a user's capabilities depending on specific context and/or privilege. * * @since 2.8.0 * * @param array $caps Returns the user's actual capabilities. * @param string $cap Capability name. * @param int $user_id The user ID. * @param array $args Adds the context to the cap. Typically the object ID. */ return apply_filters('map_meta_cap', $caps, $cap, $user_id, $args); }
/** * Map meta capabilities to primitive capabilities. * * This does not actually compare whether the user ID has the actual capability, * just what the capability or capabilities are. Meta capability list value can * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post', * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'. * * @since 2.0.0 * * @param string $cap Capability name. * @param int $user_id User ID. * @return array Actual capabilities for meta capability. */ function map_meta_cap($cap, $user_id) { $args = array_slice(func_get_args(), 2); $caps = array(); switch ($cap) { case 'remove_user': $caps[] = 'remove_users'; break; case 'promote_user': $caps[] = 'promote_users'; break; case 'edit_user': // Allow user to edit itself if (isset($args[0]) && $user_id == $args[0]) { break; } // Fall through // Fall through case 'edit_users': // If multisite these caps are allowed only for super admins. if (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = 'edit_users'; } // Explicit due to primitive fall through break; case 'delete_post': case 'delete_page': $author_data = get_userdata($user_id); $post = get_post($args[0]); if ('revision' == $post->post_type) { $post = get_post($post->post_parent); } $post_type = get_post_type_object($post->post_type); if (!$post_type->map_meta_cap) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('delete_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } if ('' != $post->post_author) { $post_author_data = get_userdata($post->post_author); } else { // No author set yet, so default to current user for cap checks. $post_author_data = $author_data; } // If the user is the author... if (is_object($post_author_data) && $user_id == $post_author_data->ID) { // 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)) { $caps[] = $post_type->cap->delete_published_posts; } } else { // If the post is draft... $caps[] = $post_type->cap->delete_posts; } } else { // 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) { $caps[] = $post_type->cap->delete_published_posts; } elseif ('private' == $post->post_status) { $caps[] = $post_type->cap->delete_private_posts; } } break; // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts // 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); $post = get_post($args[0]); if ('revision' == $post->post_type) { $post = get_post($post->post_parent); } $post_type = get_post_type_object($post->post_type); if (!$post_type->map_meta_cap) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('edit_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } if ('' != $post->post_author) { $post_author_data = get_userdata($post->post_author); } else { // No author set yet, so default to current user for cap checks. $post_author_data = $author_data; } //echo "current user id : $user_id, post author id: " . $post_author_data->ID . "<br />"; // If the user is the author... if (is_object($post_author_data) && $user_id == $post_author_data->ID) { // 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)) { $caps[] = $post_type->cap->edit_published_posts; } } else { // If the post is draft... $caps[] = $post_type->cap->edit_posts; } } else { // 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) { $caps[] = $post_type->cap->edit_published_posts; } elseif ('private' == $post->post_status) { $caps[] = $post_type->cap->edit_private_posts; } } break; case 'read_post': case 'read_page': $author_data = get_userdata($user_id); $post = get_post($args[0]); if ('revision' == $post->post_type) { $post = get_post($post->post_parent); } $post_type = get_post_type_object($post->post_type); if (!$post_type->map_meta_cap) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('read_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } $status_obj = get_post_status_object($post->post_status); if ($status_obj->public) { $caps[] = $post_type->cap->read; break; } if ('' != $post->post_author) { $post_author_data = get_userdata($post->post_author); } else { // No author set yet, so default to current user for cap checks. $post_author_data = $author_data; } if (is_object($post_author_data) && $user_id == $post_author_data->ID) { $caps[] = $post_type->cap->read; } elseif ($status_obj->private) { $caps[] = $post_type->cap->read_private_posts; } else { $caps = map_meta_cap('edit_post', $user_id, $post->ID); } break; case 'edit_post_meta': case 'delete_post_meta': case 'add_post_meta': $post = get_post($args[0]); $post_type_object = get_post_type_object($post->post_type); $caps = map_meta_cap($post_type_object->cap->edit_post, $user_id, $post->ID); $meta_key = isset($args[1]) ? $args[1] : false; if ($meta_key && has_filter("auth_post_meta_{$meta_key}")) { $allowed = apply_filters("auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps); if (!$allowed) { $caps[] = $cap; } } elseif ($meta_key && is_protected_meta($meta_key, 'post')) { $caps[] = $cap; } break; case 'edit_comment': $comment = get_comment($args[0]); $post = get_post($comment->comment_post_ID); $post_type_object = get_post_type_object($post->post_type); $caps = map_meta_cap($post_type_object->cap->edit_post, $user_id, $post->ID); break; case 'unfiltered_upload': if (defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && (!is_multisite() || is_super_admin($user_id))) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } break; case 'edit_files': case 'edit_plugins': case 'edit_themes': if (defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT) { $caps[] = 'do_not_allow'; break; } // Fall through if not DISALLOW_FILE_EDIT. // Fall through if not DISALLOW_FILE_EDIT. case 'update_plugins': case 'delete_plugins': case 'install_plugins': case 'update_themes': case 'delete_themes': case 'install_themes': case 'update_core': // Disallow anything that creates, deletes, or edits core, plugin, or theme files. // Files in uploads are excepted. if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) { $caps[] = 'do_not_allow'; break; } // Fall through if not DISALLOW_FILE_MODS. // Fall through if not DISALLOW_FILE_MODS. case 'unfiltered_html': // Disallow unfiltered_html for all users, even admins and super admins. if (defined('DISALLOW_UNFILTERED_HTML') && DISALLOW_UNFILTERED_HTML) { $caps[] = 'do_not_allow'; break; } // Fall through if not DISALLOW_UNFILTERED_HTML // Fall through if not DISALLOW_UNFILTERED_HTML case 'delete_user': case 'delete_users': // If multisite these caps are allowed only for super admins. if (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { if ('delete_user' == $cap) { $cap = 'delete_users'; } $caps[] = $cap; } break; case 'create_users': if (!is_multisite()) { $caps[] = $cap; } elseif (is_super_admin() || get_site_option('add_new_users')) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } 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; } return apply_filters('map_meta_cap', $caps, $cap, $user_id, $args); }
/** * Map meta capabilities to primitive capabilities. * * This does not actually compare whether the user ID has the actual capability, * just what the capability or capabilities are. Meta capability list value can * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post', * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'. * * @since 2.0.0 * * @param string $cap Capability name. * @param int $user_id User ID. * @return array Actual capabilities for meta capability. */ function map_meta_cap($cap, $user_id) { $args = array_slice(func_get_args(), 2); $caps = array(); switch ($cap) { case 'remove_user': $caps[] = 'remove_users'; break; case 'promote_user': $caps[] = 'promote_users'; break; case 'edit_user': case 'edit_users': // Allow user to edit itself if ('edit_user' == $cap && isset($args[0]) && $user_id == $args[0]) { break; } // In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin. if (is_multisite() && (!is_super_admin($user_id) && 'edit_user' === $cap && is_super_admin($args[0]) || !user_can($user_id, 'manage_network_users'))) { $caps[] = 'do_not_allow'; } else { $caps[] = 'edit_users'; // edit_user maps to edit_users. } break; case 'delete_post': case 'delete_page': $post = get_post($args[0]); if ('revision' == $post->post_type) { $post = get_post($post->post_parent); } $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) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('delete_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } // 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)) { $caps[] = $post_type->cap->delete_published_posts; } } else { // If the post is draft... $caps[] = $post_type->cap->delete_posts; } } else { // 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) { $caps[] = $post_type->cap->delete_published_posts; } elseif ('private' == $post->post_status) { $caps[] = $post_type->cap->delete_private_posts; } } break; // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts case 'edit_post': case 'edit_page': $post = get_post($args[0]); if (empty($post)) { $caps[] = 'do_not_allow'; break; } if ('revision' == $post->post_type) { $post = get_post($post->post_parent); } $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) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('edit_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } // 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)) { $caps[] = $post_type->cap->edit_published_posts; } } else { // If the post is draft... $caps[] = $post_type->cap->edit_posts; } } else { // 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) { $caps[] = $post_type->cap->edit_published_posts; } elseif ('private' == $post->post_status) { $caps[] = $post_type->cap->edit_private_posts; } } break; case 'read_post': case 'read_page': $post = get_post($args[0]); if ('revision' == $post->post_type) { $post = get_post($post->post_parent); } $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) { $caps[] = $post_type->cap->{$cap}; // Prior to 3.1 we would re-call map_meta_cap here. if ('read_post' == $cap) { $cap = $post_type->cap->{$cap}; } break; } $status_obj = get_post_status_object($post->post_status); if ($status_obj->public) { $caps[] = $post_type->cap->read; break; } if ($post->post_author && $user_id == $post->post_author) { $caps[] = $post_type->cap->read; } elseif ($status_obj->private) { $caps[] = $post_type->cap->read_private_posts; } else { $caps = map_meta_cap('edit_post', $user_id, $post->ID); } break; case 'publish_post': $post = get_post($args[0]); $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; break; case 'edit_post_meta': case 'delete_post_meta': case 'add_post_meta': $post = get_post($args[0]); $caps = map_meta_cap('edit_post', $user_id, $post->ID); $meta_key = isset($args[1]) ? $args[1] : false; if ($meta_key && has_filter("auth_post_meta_{$meta_key}")) { /** * Filter whether the user is allowed to add post meta to a post. * * The dynamic portion of the hook name, `$meta_key`, refers to the * meta key passed to {@see map_meta_cap()}. * * @since 3.3.0 * * @param bool $allowed Whether the user can add the post meta. Default false. * @param string $meta_key The meta key. * @param int $post_id Post ID. * @param int $user_id User ID. * @param string $cap Capability name. * @param array $caps User capabilities. */ $allowed = apply_filters("auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps); if (!$allowed) { $caps[] = $cap; } } elseif ($meta_key && is_protected_meta($meta_key, 'post')) { $caps[] = $cap; } break; case 'edit_comment': $comment = get_comment($args[0]); if (empty($comment)) { break; } $post = get_post($comment->comment_post_ID); /* * If the post doesn't exist, we have an orphaned comment. * Fall back to the edit_posts capability, instead. */ if ($post) { $caps = map_meta_cap('edit_post', $user_id, $post->ID); } else { $caps = map_meta_cap('edit_posts', $user_id); } break; case 'unfiltered_upload': if (defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && (!is_multisite() || is_super_admin($user_id))) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } break; case 'unfiltered_html': // Disallow unfiltered_html for all users, even admins and super admins. if (defined('DISALLOW_UNFILTERED_HTML') && DISALLOW_UNFILTERED_HTML) { $caps[] = 'do_not_allow'; } elseif (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = $cap; } break; case 'edit_files': case 'edit_plugins': case 'edit_themes': // Disallow the file editors. if (defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT) { $caps[] = 'do_not_allow'; } elseif (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) { $caps[] = 'do_not_allow'; } elseif (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = $cap; } break; case 'update_plugins': case 'delete_plugins': case 'install_plugins': case 'upload_plugins': case 'update_themes': case 'delete_themes': case 'install_themes': case 'upload_themes': case 'update_core': // Disallow anything that creates, deletes, or updates core, plugin, or theme files. // Files in uploads are excepted. if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) { $caps[] = 'do_not_allow'; } elseif (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } elseif ('upload_themes' === $cap) { $caps[] = 'install_themes'; } elseif ('upload_plugins' === $cap) { $caps[] = 'install_plugins'; } else { $caps[] = $cap; } break; case 'activate_plugins': $caps[] = $cap; if (is_multisite()) { // update_, install_, and delete_ are handled above with is_super_admin(). $menu_perms = get_site_option('menu_items', array()); if (empty($menu_perms['plugins'])) { $caps[] = 'manage_network_plugins'; } } break; case 'delete_user': case 'delete_users': // If multisite only super admins can delete users. if (is_multisite() && !is_super_admin($user_id)) { $caps[] = 'do_not_allow'; } else { $caps[] = 'delete_users'; } // delete_user maps to delete_users. break; case 'create_users': if (!is_multisite()) { $caps[] = $cap; } elseif (is_super_admin($user_id) || get_site_option('add_new_users')) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } break; case 'manage_links': if (get_option('link_manager_enabled')) { $caps[] = $cap; } else { $caps[] = 'do_not_allow'; } break; case 'customize': $caps[] = 'edit_theme_options'; break; case 'delete_site': $caps[] = 'manage_options'; 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; } /** * Filter a user's capabilities depending on specific context and/or privilege. * * @since 2.8.0 * * @param array $caps Returns the user's actual capabilities. * @param string $cap Capability name. * @param int $user_id The user ID. * @param array $args Adds the context to the cap. Typically the object ID. */ return apply_filters('map_meta_cap', $caps, $cap, $user_id, $args); }
function _ppff_flt_map_media_edit_meta_cap($caps, $cap, $user_id, $args) { $extra_args = array_intersect_key($args, array_fill_keys(array('post', 'post_status', 'post_type', 'post_author_id'), true)); extract($extra_args, EXTR_SKIP); switch ($cap) { case 'delete_post': case 'delete_page': // 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 is published... if ('publish' == $post_status) { $caps[] = $post_type->cap->delete_published_posts; } elseif ('trash' == $post_status) { 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; } } else { // 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_status) { $caps[] = $post_type->cap->delete_published_posts; } elseif ('private' == $post_status) { $caps[] = $post_type->cap->delete_private_posts; } } break; // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts // edit_post breaks down to edit_posts, edit_published_posts, or // edit_others_posts case 'edit_post': case 'edit_page': // 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 is published... if ('publish' == $post_status) { $caps[] = $post_type->cap->edit_published_posts; } elseif ('trash' == $post_status) { 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; } } else { // 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_status) { $caps[] = $post_type->cap->edit_published_posts; } elseif ('private' == $post_status) { $caps[] = $post_type->cap->edit_private_posts; } } break; case 'publish_post': $caps[] = $post_type->cap->publish_posts; break; case 'edit_post_meta': case 'delete_post_meta': case 'add_post_meta': $caps = map_meta_cap('edit_post', $user_id, $post->ID); $meta_key = isset($args[1]) ? $args[1] : false; if ($meta_key && has_filter("auth_post_meta_{$meta_key}")) { /** * Filter whether the user is allowed to add post meta to a post. * * The dynamic portion of the hook name, $meta_key, refers to the * meta key passed to map_meta_cap(). * * @since 3.3.0 * * @param bool $allowed Whether the user can add the post meta. Default false. * @param string $meta_key The meta key. * @param int $post_id Post ID. * @param int $user_id User ID. * @param string $cap Capability name. * @param array $caps User capabilities. */ $allowed = apply_filters("auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps); if (!$allowed) { $caps[] = $cap; } } elseif ($meta_key && is_protected_meta($meta_key, 'post')) { $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; } return $caps; }