wp/wp-includes/capabilities.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     5  * @package WordPress
     5  * @package WordPress
     6  * @subpackage Users
     6  * @subpackage Users
     7  */
     7  */
     8 
     8 
     9 /**
     9 /**
    10  * Map meta capabilities to primitive capabilities.
    10  * Maps meta capabilities to primitive capabilities.
       
    11  *
       
    12  * This function also accepts an ID of an object to map against if the capability is a meta capability. Meta
       
    13  * capabilities such as `edit_post` and `edit_user` are capabilities used by this function to map to primitive
       
    14  * capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`.
       
    15  *
       
    16  * Example usage:
       
    17  *
       
    18  *     map_meta_cap( 'edit_posts', $user->ID );
       
    19  *     map_meta_cap( 'edit_post', $user->ID, $post->ID );
       
    20  *     map_meta_cap( 'edit_post_meta', $user->ID, $post->ID, $meta_key );
    11  *
    21  *
    12  * This does not actually compare whether the user ID has the actual capability,
    22  * This does not actually compare whether the user ID has the actual capability,
    13  * just what the capability or capabilities are. Meta capability list value can
    23  * just what the capability or capabilities are. Meta capability list value can
    14  * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post',
    24  * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post',
    15  * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'.
    25  * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'.
    16  *
    26  *
    17  * @since 2.0.0
    27  * @since 2.0.0
       
    28  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
    29  *              by adding it to the function signature.
    18  *
    30  *
    19  * @global array $post_type_meta_caps Used to get post type meta capabilities.
    31  * @global array $post_type_meta_caps Used to get post type meta capabilities.
    20  *
    32  *
    21  * @param string $cap       Capability name.
    33  * @param string $cap     Capability name.
    22  * @param int    $user_id   User ID.
    34  * @param int    $user_id User ID.
    23  * @param int    $object_id Optional. ID of the specific object to check against if `$cap` is a "meta" cap.
    35  * @param mixed  ...$args Optional further parameters, typically starting with an object ID.
    24  *                          "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
    36  * @return string[] Actual capabilities for meta capability.
    25  *                          by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
    37  */
    26  *                          'edit_others_posts', etc. The parameter is accessed via func_get_args().
    38 function map_meta_cap( $cap, $user_id, ...$args ) {
    27  * @return array Actual capabilities for meta capability.
       
    28  */
       
    29 function map_meta_cap( $cap, $user_id ) {
       
    30 	$args = array_slice( func_get_args(), 2 );
       
    31 	$caps = array();
    39 	$caps = array();
    32 
    40 
    33 	switch ( $cap ) {
    41 	switch ( $cap ) {
    34 		case 'remove_user':
    42 		case 'remove_user':
    35 			// In multisite the user must be a super admin to remove themselves.
    43 			// In multisite the user must be a super admin to remove themselves.
    43 		case 'add_users':
    51 		case 'add_users':
    44 			$caps[] = 'promote_users';
    52 			$caps[] = 'promote_users';
    45 			break;
    53 			break;
    46 		case 'edit_user':
    54 		case 'edit_user':
    47 		case 'edit_users':
    55 		case 'edit_users':
    48 			// Allow user to edit itself
    56 			// Allow user to edit themselves.
    49 			if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] ) {
    57 			if ( 'edit_user' === $cap && isset( $args[0] ) && $user_id == $args[0] ) {
    50 				break;
    58 				break;
    51 			}
    59 			}
    52 
    60 
    53 			// In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin.
    61 			// In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin.
    54 			if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) {
    62 			if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) {
    63 			if ( ! $post ) {
    71 			if ( ! $post ) {
    64 				$caps[] = 'do_not_allow';
    72 				$caps[] = 'do_not_allow';
    65 				break;
    73 				break;
    66 			}
    74 			}
    67 
    75 
    68 			if ( 'revision' == $post->post_type ) {
    76 			if ( 'revision' === $post->post_type ) {
    69 				$post = get_post( $post->post_parent );
    77 				$caps[] = 'do_not_allow';
    70 				if ( ! $post ) {
    78 				break;
    71 					$caps[] = 'do_not_allow';
       
    72 					break;
       
    73 				}
       
    74 			}
    79 			}
    75 
    80 
    76 			if ( ( get_option( 'page_for_posts' ) == $post->ID ) || ( get_option( 'page_on_front' ) == $post->ID ) ) {
    81 			if ( ( get_option( 'page_for_posts' ) == $post->ID ) || ( get_option( 'page_on_front' ) == $post->ID ) ) {
    77 				$caps[] = 'manage_options';
    82 				$caps[] = 'manage_options';
    78 				break;
    83 				break;
    79 			}
    84 			}
    80 
    85 
    81 			$post_type = get_post_type_object( $post->post_type );
    86 			$post_type = get_post_type_object( $post->post_type );
    82 			if ( ! $post_type ) {
    87 			if ( ! $post_type ) {
    83 				/* translators: 1: post type, 2: capability name */
    88 				/* translators: 1: Post type, 2: Capability name. */
    84 				_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' );
    89 				_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' );
    85 				$caps[] = 'edit_others_posts';
    90 				$caps[] = 'edit_others_posts';
    86 				break;
    91 				break;
    87 			}
    92 			}
    88 
    93 
    89 			if ( ! $post_type->map_meta_cap ) {
    94 			if ( ! $post_type->map_meta_cap ) {
    90 				$caps[] = $post_type->cap->$cap;
    95 				$caps[] = $post_type->cap->$cap;
    91 				// Prior to 3.1 we would re-call map_meta_cap here.
    96 				// Prior to 3.1 we would re-call map_meta_cap here.
    92 				if ( 'delete_post' == $cap ) {
    97 				if ( 'delete_post' === $cap ) {
    93 					$cap = $post_type->cap->$cap;
    98 					$cap = $post_type->cap->$cap;
    94 				}
    99 				}
    95 				break;
   100 				break;
    96 			}
   101 			}
    97 
   102 
    98 			// If the post author is set and the user is the author...
   103 			// If the post author is set and the user is the author...
    99 			if ( $post->post_author && $user_id == $post->post_author ) {
   104 			if ( $post->post_author && $user_id == $post->post_author ) {
   100 				// If the post is published or scheduled...
   105 				// If the post is published or scheduled...
   101 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   106 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   102 					$caps[] = $post_type->cap->delete_published_posts;
   107 					$caps[] = $post_type->cap->delete_published_posts;
   103 				} elseif ( 'trash' == $post->post_status ) {
   108 				} elseif ( 'trash' === $post->post_status ) {
   104 					$status = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
   109 					$status = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
   105 					if ( in_array( $status, array( 'publish', 'future' ), true ) ) {
   110 					if ( in_array( $status, array( 'publish', 'future' ), true ) ) {
   106 						$caps[] = $post_type->cap->delete_published_posts;
   111 						$caps[] = $post_type->cap->delete_published_posts;
   107 					} else {
   112 					} else {
   108 						$caps[] = $post_type->cap->delete_posts;
   113 						$caps[] = $post_type->cap->delete_posts;
   115 				// The user is trying to edit someone else's post.
   120 				// The user is trying to edit someone else's post.
   116 				$caps[] = $post_type->cap->delete_others_posts;
   121 				$caps[] = $post_type->cap->delete_others_posts;
   117 				// The post is published or scheduled, extra cap required.
   122 				// The post is published or scheduled, extra cap required.
   118 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   123 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   119 					$caps[] = $post_type->cap->delete_published_posts;
   124 					$caps[] = $post_type->cap->delete_published_posts;
   120 				} elseif ( 'private' == $post->post_status ) {
   125 				} elseif ( 'private' === $post->post_status ) {
   121 					$caps[] = $post_type->cap->delete_private_posts;
   126 					$caps[] = $post_type->cap->delete_private_posts;
   122 				}
   127 				}
   123 			}
   128 			}
   124 
   129 
   125 			/*
   130 			/*
   130 				$caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) );
   135 				$caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) );
   131 			}
   136 			}
   132 
   137 
   133 			break;
   138 			break;
   134 		// edit_post breaks down to edit_posts, edit_published_posts, or
   139 		// edit_post breaks down to edit_posts, edit_published_posts, or
   135 		// edit_others_posts
   140 		// edit_others_posts.
   136 		case 'edit_post':
   141 		case 'edit_post':
   137 		case 'edit_page':
   142 		case 'edit_page':
   138 			$post = get_post( $args[0] );
   143 			$post = get_post( $args[0] );
   139 			if ( ! $post ) {
   144 			if ( ! $post ) {
   140 				$caps[] = 'do_not_allow';
   145 				$caps[] = 'do_not_allow';
   141 				break;
   146 				break;
   142 			}
   147 			}
   143 
   148 
   144 			if ( 'revision' == $post->post_type ) {
   149 			if ( 'revision' === $post->post_type ) {
   145 				$post = get_post( $post->post_parent );
   150 				$post = get_post( $post->post_parent );
   146 				if ( ! $post ) {
   151 				if ( ! $post ) {
   147 					$caps[] = 'do_not_allow';
   152 					$caps[] = 'do_not_allow';
   148 					break;
   153 					break;
   149 				}
   154 				}
   150 			}
   155 			}
   151 
   156 
   152 			$post_type = get_post_type_object( $post->post_type );
   157 			$post_type = get_post_type_object( $post->post_type );
   153 			if ( ! $post_type ) {
   158 			if ( ! $post_type ) {
   154 				/* translators: 1: post type, 2: capability name */
   159 				/* translators: 1: Post type, 2: Capability name. */
   155 				_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' );
   160 				_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' );
   156 				$caps[] = 'edit_others_posts';
   161 				$caps[] = 'edit_others_posts';
   157 				break;
   162 				break;
   158 			}
   163 			}
   159 
   164 
   160 			if ( ! $post_type->map_meta_cap ) {
   165 			if ( ! $post_type->map_meta_cap ) {
   161 				$caps[] = $post_type->cap->$cap;
   166 				$caps[] = $post_type->cap->$cap;
   162 				// Prior to 3.1 we would re-call map_meta_cap here.
   167 				// Prior to 3.1 we would re-call map_meta_cap here.
   163 				if ( 'edit_post' == $cap ) {
   168 				if ( 'edit_post' === $cap ) {
   164 					$cap = $post_type->cap->$cap;
   169 					$cap = $post_type->cap->$cap;
   165 				}
   170 				}
   166 				break;
   171 				break;
   167 			}
   172 			}
   168 
   173 
   169 			// If the post author is set and the user is the author...
   174 			// If the post author is set and the user is the author...
   170 			if ( $post->post_author && $user_id == $post->post_author ) {
   175 			if ( $post->post_author && $user_id == $post->post_author ) {
   171 				// If the post is published or scheduled...
   176 				// If the post is published or scheduled...
   172 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   177 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   173 					$caps[] = $post_type->cap->edit_published_posts;
   178 					$caps[] = $post_type->cap->edit_published_posts;
   174 				} elseif ( 'trash' == $post->post_status ) {
   179 				} elseif ( 'trash' === $post->post_status ) {
   175 					$status = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
   180 					$status = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
   176 					if ( in_array( $status, array( 'publish', 'future' ), true ) ) {
   181 					if ( in_array( $status, array( 'publish', 'future' ), true ) ) {
   177 						$caps[] = $post_type->cap->edit_published_posts;
   182 						$caps[] = $post_type->cap->edit_published_posts;
   178 					} else {
   183 					} else {
   179 						$caps[] = $post_type->cap->edit_posts;
   184 						$caps[] = $post_type->cap->edit_posts;
   186 				// The user is trying to edit someone else's post.
   191 				// The user is trying to edit someone else's post.
   187 				$caps[] = $post_type->cap->edit_others_posts;
   192 				$caps[] = $post_type->cap->edit_others_posts;
   188 				// The post is published or scheduled, extra cap required.
   193 				// The post is published or scheduled, extra cap required.
   189 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   194 				if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
   190 					$caps[] = $post_type->cap->edit_published_posts;
   195 					$caps[] = $post_type->cap->edit_published_posts;
   191 				} elseif ( 'private' == $post->post_status ) {
   196 				} elseif ( 'private' === $post->post_status ) {
   192 					$caps[] = $post_type->cap->edit_private_posts;
   197 					$caps[] = $post_type->cap->edit_private_posts;
   193 				}
   198 				}
   194 			}
   199 			}
   195 
   200 
   196 			/*
   201 			/*
   208 			if ( ! $post ) {
   213 			if ( ! $post ) {
   209 				$caps[] = 'do_not_allow';
   214 				$caps[] = 'do_not_allow';
   210 				break;
   215 				break;
   211 			}
   216 			}
   212 
   217 
   213 			if ( 'revision' == $post->post_type ) {
   218 			if ( 'revision' === $post->post_type ) {
   214 				$post = get_post( $post->post_parent );
   219 				$post = get_post( $post->post_parent );
   215 				if ( ! $post ) {
   220 				if ( ! $post ) {
   216 					$caps[] = 'do_not_allow';
   221 					$caps[] = 'do_not_allow';
   217 					break;
   222 					break;
   218 				}
   223 				}
   219 			}
   224 			}
   220 
   225 
   221 			$post_type = get_post_type_object( $post->post_type );
   226 			$post_type = get_post_type_object( $post->post_type );
   222 			if ( ! $post_type ) {
   227 			if ( ! $post_type ) {
   223 				/* translators: 1: post type, 2: capability name */
   228 				/* translators: 1: Post type, 2: Capability name. */
   224 				_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' );
   229 				_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' );
   225 				$caps[] = 'edit_others_posts';
   230 				$caps[] = 'edit_others_posts';
   226 				break;
   231 				break;
   227 			}
   232 			}
   228 
   233 
   229 			if ( ! $post_type->map_meta_cap ) {
   234 			if ( ! $post_type->map_meta_cap ) {
   230 				$caps[] = $post_type->cap->$cap;
   235 				$caps[] = $post_type->cap->$cap;
   231 				// Prior to 3.1 we would re-call map_meta_cap here.
   236 				// Prior to 3.1 we would re-call map_meta_cap here.
   232 				if ( 'read_post' == $cap ) {
   237 				if ( 'read_post' === $cap ) {
   233 					$cap = $post_type->cap->$cap;
   238 					$cap = $post_type->cap->$cap;
   234 				}
   239 				}
   235 				break;
   240 				break;
   236 			}
   241 			}
   237 
   242 
   238 			$status_obj = get_post_status_object( $post->post_status );
   243 			$status_obj = get_post_status_object( $post->post_status );
       
   244 			if ( ! $status_obj ) {
       
   245 				/* translators: 1: Post status, 2: Capability name. */
       
   246 				_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post status %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post with that status.' ), $post->post_status, $cap ), '5.4.0' );
       
   247 				$caps[] = 'edit_others_posts';
       
   248 				break;
       
   249 			}
       
   250 
   239 			if ( $status_obj->public ) {
   251 			if ( $status_obj->public ) {
   240 				$caps[] = $post_type->cap->read;
   252 				$caps[] = $post_type->cap->read;
   241 				break;
   253 				break;
   242 			}
   254 			}
   243 
   255 
   256 				break;
   268 				break;
   257 			}
   269 			}
   258 
   270 
   259 			$post_type = get_post_type_object( $post->post_type );
   271 			$post_type = get_post_type_object( $post->post_type );
   260 			if ( ! $post_type ) {
   272 			if ( ! $post_type ) {
   261 				/* translators: 1: post type, 2: capability name */
   273 				/* translators: 1: Post type, 2: Capability name. */
   262 				_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' );
   274 				_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' );
   263 				$caps[] = 'edit_others_posts';
   275 				$caps[] = 'edit_others_posts';
   264 				break;
   276 				break;
   265 			}
   277 			}
   266 
   278 
   276 		case 'delete_term_meta':
   288 		case 'delete_term_meta':
   277 		case 'add_term_meta':
   289 		case 'add_term_meta':
   278 		case 'edit_user_meta':
   290 		case 'edit_user_meta':
   279 		case 'delete_user_meta':
   291 		case 'delete_user_meta':
   280 		case 'add_user_meta':
   292 		case 'add_user_meta':
   281 			list( $_, $object_type, $_ ) = explode( '_', $cap );
   293 			$object_type = explode( '_', $cap )[1];
   282 			$object_id                   = (int) $args[0];
   294 			$object_id   = (int) $args[0];
   283 
   295 
   284 			$object_subtype = get_object_subtype( $object_type, $object_id );
   296 			$object_subtype = get_object_subtype( $object_type, $object_id );
   285 
   297 
   286 			if ( empty( $object_subtype ) ) {
   298 			if ( empty( $object_subtype ) ) {
   287 				$caps[] = 'do_not_allow';
   299 				$caps[] = 'do_not_allow';
   347 					 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
   359 					 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
   348 					 * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered.
   360 					 * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered.
   349 					 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
   361 					 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
   350 					 *
   362 					 *
   351 					 * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`.
   363 					 * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`.
   352 					 * @since 4.7.0
   364 					 * @since 4.7.0 Renamed from `auth_post_{$post_type}_meta_{$meta_key}` to
   353 					 * @deprecated 4.9.8 Use `auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}`
   365 					 *              `auth_{$object_type}_{$object_subtype}_meta_{$meta_key}`.
       
   366 					 * @deprecated 4.9.8 Use {@see 'auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}'} instead.
   354 					 *
   367 					 *
   355 					 * @param bool     $allowed   Whether the user can add the object meta. Default false.
   368 					 * @param bool     $allowed   Whether the user can add the object meta. Default false.
   356 					 * @param string   $meta_key  The meta key.
   369 					 * @param string   $meta_key  The meta key.
   357 					 * @param int      $object_id Object ID.
   370 					 * @param int      $object_id Object ID.
   358 					 * @param int      $user_id   User ID.
   371 					 * @param int      $user_id   User ID.
   359 					 * @param string   $cap       Capability name.
   372 					 * @param string   $cap       Capability name.
   360 					 * @param string[] $caps      Array of the user's capabilities.
   373 					 * @param string[] $caps      Array of the user's capabilities.
   361 					 */
   374 					 */
   362 					$allowed = apply_filters_deprecated( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ), '4.9.8', "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" );
   375 					$allowed = apply_filters_deprecated(
       
   376 						"auth_{$object_type}_{$object_subtype}_meta_{$meta_key}",
       
   377 						array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ),
       
   378 						'4.9.8',
       
   379 						"auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}"
       
   380 					);
   363 				}
   381 				}
   364 
   382 
   365 				if ( ! $allowed ) {
   383 				if ( ! $allowed ) {
   366 					$caps[] = $cap;
   384 					$caps[] = $cap;
   367 				}
   385 				}
   519 			if ( ! $tax ) {
   537 			if ( ! $tax ) {
   520 				$caps[] = 'do_not_allow';
   538 				$caps[] = 'do_not_allow';
   521 				break;
   539 				break;
   522 			}
   540 			}
   523 
   541 
   524 			if ( 'delete_term' === $cap && ( $term->term_id == get_option( 'default_' . $term->taxonomy ) ) ) {
   542 			if ( 'delete_term' === $cap
       
   543 				&& ( get_option( 'default_' . $term->taxonomy ) == $term->term_id
       
   544 					|| get_option( 'default_term_' . $term->taxonomy ) == $term->term_id )
       
   545 			) {
   525 				$caps[] = 'do_not_allow';
   546 				$caps[] = 'do_not_allow';
   526 				break;
   547 				break;
   527 			}
   548 			}
   528 
   549 
   529 			$taxo_cap = $cap . 's';
   550 			$taxo_cap = $cap . 's';
   574 			break;
   595 			break;
   575 		default:
   596 		default:
   576 			// Handle meta capabilities for custom post types.
   597 			// Handle meta capabilities for custom post types.
   577 			global $post_type_meta_caps;
   598 			global $post_type_meta_caps;
   578 			if ( isset( $post_type_meta_caps[ $cap ] ) ) {
   599 			if ( isset( $post_type_meta_caps[ $cap ] ) ) {
   579 				$args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args );
   600 				return map_meta_cap( $post_type_meta_caps[ $cap ], $user_id, ...$args );
   580 				return call_user_func_array( 'map_meta_cap', $args );
       
   581 			}
   601 			}
   582 
   602 
   583 			// Block capabilities map to their post equivalent.
   603 			// Block capabilities map to their post equivalent.
   584 			$block_caps = array(
   604 			$block_caps = array(
   585 				'edit_blocks',
   605 				'edit_blocks',
   613 	 */
   633 	 */
   614 	return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
   634 	return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
   615 }
   635 }
   616 
   636 
   617 /**
   637 /**
   618  * Whether the current user has a specific capability.
   638  * Returns whether the current user has the specified capability.
       
   639  *
       
   640  * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta
       
   641  * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to
       
   642  * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`.
       
   643  *
       
   644  * Example usage:
       
   645  *
       
   646  *     current_user_can( 'edit_posts' );
       
   647  *     current_user_can( 'edit_post', $post->ID );
       
   648  *     current_user_can( 'edit_post_meta', $post->ID, $meta_key );
   619  *
   649  *
   620  * While checking against particular roles in place of a capability is supported
   650  * While checking against particular roles in place of a capability is supported
   621  * in part, this practice is discouraged as it may produce unreliable results.
   651  * in part, this practice is discouraged as it may produce unreliable results.
   622  *
   652  *
   623  * Note: Will always return true if the current user is a super admin, unless specifically denied.
   653  * Note: Will always return true if the current user is a super admin, unless specifically denied.
   624  *
   654  *
   625  * @since 2.0.0
   655  * @since 2.0.0
       
   656  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
   657  *              by adding it to the function signature.
   626  *
   658  *
   627  * @see WP_User::has_cap()
   659  * @see WP_User::has_cap()
   628  * @see map_meta_cap()
   660  * @see map_meta_cap()
   629  *
   661  *
   630  * @param string $capability Capability name.
   662  * @param string $capability Capability name.
   631  * @param int    $object_id  Optional. ID of the specific object to check against if `$capability` is a "meta" cap.
   663  * @param mixed  ...$args    Optional further parameters, typically starting with an object ID.
   632  *                           "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
       
   633  *                           by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
       
   634  *                           'edit_others_posts', etc. Accessed via func_get_args() and passed to WP_User::has_cap(),
       
   635  *                           then map_meta_cap().
       
   636  * @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is
   664  * @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is
   637  *              passed, whether the current user has the given meta capability for the given object.
   665  *              passed, whether the current user has the given meta capability for the given object.
   638  */
   666  */
   639 function current_user_can( $capability ) {
   667 function current_user_can( $capability, ...$args ) {
   640 	$current_user = wp_get_current_user();
   668 	$current_user = wp_get_current_user();
   641 
   669 
   642 	if ( empty( $current_user ) ) {
   670 	if ( empty( $current_user ) ) {
   643 		return false;
   671 		return false;
   644 	}
   672 	}
   645 
   673 
   646 	$args = array_slice( func_get_args(), 1 );
   674 	return $current_user->has_cap( $capability, ...$args );
   647 	$args = array_merge( array( $capability ), $args );
   675 }
   648 
   676 
   649 	return call_user_func_array( array( $current_user, 'has_cap' ), $args );
   677 /**
   650 }
   678  * Returns whether the current user has the specified capability for a given site.
   651 
   679  *
   652 /**
   680  * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta
   653  * Whether the current user has a specific capability for a given site.
   681  * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to
       
   682  * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`.
       
   683  *
       
   684  * Example usage:
       
   685  *
       
   686  *     current_user_can_for_blog( $blog_id, 'edit_posts' );
       
   687  *     current_user_can_for_blog( $blog_id, 'edit_post', $post->ID );
       
   688  *     current_user_can_for_blog( $blog_id, 'edit_post_meta', $post->ID, $meta_key );
   654  *
   689  *
   655  * @since 3.0.0
   690  * @since 3.0.0
       
   691  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
   692  *              by adding it to the function signature.
   656  *
   693  *
   657  * @param int    $blog_id    Site ID.
   694  * @param int    $blog_id    Site ID.
   658  * @param string $capability Capability name.
   695  * @param string $capability Capability name.
       
   696  * @param mixed  ...$args    Optional further parameters, typically starting with an object ID.
   659  * @return bool Whether the user has the given capability.
   697  * @return bool Whether the user has the given capability.
   660  */
   698  */
   661 function current_user_can_for_blog( $blog_id, $capability ) {
   699 function current_user_can_for_blog( $blog_id, $capability, ...$args ) {
   662 	$switched = is_multisite() ? switch_to_blog( $blog_id ) : false;
   700 	$switched = is_multisite() ? switch_to_blog( $blog_id ) : false;
   663 
   701 
   664 	$current_user = wp_get_current_user();
   702 	$current_user = wp_get_current_user();
   665 
   703 
   666 	if ( empty( $current_user ) ) {
   704 	if ( empty( $current_user ) ) {
   668 			restore_current_blog();
   706 			restore_current_blog();
   669 		}
   707 		}
   670 		return false;
   708 		return false;
   671 	}
   709 	}
   672 
   710 
   673 	$args = array_slice( func_get_args(), 2 );
   711 	$can = $current_user->has_cap( $capability, ...$args );
   674 	$args = array_merge( array( $capability ), $args );
       
   675 
       
   676 	$can = call_user_func_array( array( $current_user, 'has_cap' ), $args );
       
   677 
   712 
   678 	if ( $switched ) {
   713 	if ( $switched ) {
   679 		restore_current_blog();
   714 		restore_current_blog();
   680 	}
   715 	}
   681 
   716 
   682 	return $can;
   717 	return $can;
   683 }
   718 }
   684 
   719 
   685 /**
   720 /**
   686  * Whether the author of the supplied post has a specific capability.
   721  * Returns whether the author of the supplied post has the specified capability.
       
   722  *
       
   723  * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta
       
   724  * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to
       
   725  * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`.
       
   726  *
       
   727  * Example usage:
       
   728  *
       
   729  *     author_can( $post, 'edit_posts' );
       
   730  *     author_can( $post, 'edit_post', $post->ID );
       
   731  *     author_can( $post, 'edit_post_meta', $post->ID, $meta_key );
   687  *
   732  *
   688  * @since 2.9.0
   733  * @since 2.9.0
       
   734  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
   735  *              by adding it to the function signature.
   689  *
   736  *
   690  * @param int|WP_Post $post       Post ID or post object.
   737  * @param int|WP_Post $post       Post ID or post object.
   691  * @param string      $capability Capability name.
   738  * @param string      $capability Capability name.
       
   739  * @param mixed       ...$args    Optional further parameters, typically starting with an object ID.
   692  * @return bool Whether the post author has the given capability.
   740  * @return bool Whether the post author has the given capability.
   693  */
   741  */
   694 function author_can( $post, $capability ) {
   742 function author_can( $post, $capability, ...$args ) {
   695 	if ( ! $post = get_post( $post ) ) {
   743 	$post = get_post( $post );
       
   744 	if ( ! $post ) {
   696 		return false;
   745 		return false;
   697 	}
   746 	}
   698 
   747 
   699 	$author = get_userdata( $post->post_author );
   748 	$author = get_userdata( $post->post_author );
   700 
   749 
   701 	if ( ! $author ) {
   750 	if ( ! $author ) {
   702 		return false;
   751 		return false;
   703 	}
   752 	}
   704 
   753 
   705 	$args = array_slice( func_get_args(), 2 );
   754 	return $author->has_cap( $capability, ...$args );
   706 	$args = array_merge( array( $capability ), $args );
   755 }
   707 
   756 
   708 	return call_user_func_array( array( $author, 'has_cap' ), $args );
   757 /**
   709 }
   758  * Returns whether a particular user has the specified capability.
   710 
   759  *
   711 /**
   760  * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta
   712  * Whether a particular user has a specific capability.
   761  * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to
       
   762  * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`.
       
   763  *
       
   764  * Example usage:
       
   765  *
       
   766  *     user_can( $user->ID, 'edit_posts' );
       
   767  *     user_can( $user->ID, 'edit_post', $post->ID );
       
   768  *     user_can( $user->ID, 'edit_post_meta', $post->ID, $meta_key );
   713  *
   769  *
   714  * @since 3.1.0
   770  * @since 3.1.0
       
   771  * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
       
   772  *              by adding it to the function signature.
   715  *
   773  *
   716  * @param int|WP_User $user       User ID or object.
   774  * @param int|WP_User $user       User ID or object.
   717  * @param string      $capability Capability name.
   775  * @param string      $capability Capability name.
       
   776  * @param mixed       ...$args    Optional further parameters, typically starting with an object ID.
   718  * @return bool Whether the user has the given capability.
   777  * @return bool Whether the user has the given capability.
   719  */
   778  */
   720 function user_can( $user, $capability ) {
   779 function user_can( $user, $capability, ...$args ) {
   721 	if ( ! is_object( $user ) ) {
   780 	if ( ! is_object( $user ) ) {
   722 		$user = get_userdata( $user );
   781 		$user = get_userdata( $user );
   723 	}
   782 	}
   724 
   783 
   725 	if ( ! $user || ! $user->exists() ) {
   784 	if ( ! $user || ! $user->exists() ) {
   726 		return false;
   785 		return false;
   727 	}
   786 	}
   728 
   787 
   729 	$args = array_slice( func_get_args(), 2 );
   788 	return $user->has_cap( $capability, ...$args );
   730 	$args = array_merge( array( $capability ), $args );
       
   731 
       
   732 	return call_user_func_array( array( $user, 'has_cap' ), $args );
       
   733 }
   789 }
   734 
   790 
   735 /**
   791 /**
   736  * Retrieves the global WP_Roles instance and instantiates it if necessary.
   792  * Retrieves the global WP_Roles instance and instantiates it if necessary.
   737  *
   793  *
   738  * @since 4.3.0
   794  * @since 4.3.0
   739  *
   795  *
   740  * @global WP_Roles $wp_roles WP_Roles global instance.
   796  * @global WP_Roles $wp_roles WordPress role management object.
   741  *
   797  *
   742  * @return WP_Roles WP_Roles global instance if not already instantiated.
   798  * @return WP_Roles WP_Roles global instance if not already instantiated.
   743  */
   799  */
   744 function wp_roles() {
   800 function wp_roles() {
   745 	global $wp_roles;
   801 	global $wp_roles;
   765 /**
   821 /**
   766  * Add role, if it does not exist.
   822  * Add role, if it does not exist.
   767  *
   823  *
   768  * @since 2.0.0
   824  * @since 2.0.0
   769  *
   825  *
   770  * @param string $role Role name.
   826  * @param string $role         Role name.
   771  * @param string $display_name Display name for role.
   827  * @param string $display_name Display name for role.
   772  * @param array $capabilities List of capabilities, e.g. array( 'edit_posts' => true, 'delete_posts' => false );
   828  * @param bool[] $capabilities List of capabilities keyed by the capability name,
       
   829  *                             e.g. array( 'edit_posts' => true, 'delete_posts' => false ).
   773  * @return WP_Role|null WP_Role object if role is added, null if already exists.
   830  * @return WP_Role|null WP_Role object if role is added, null if already exists.
   774  */
   831  */
   775 function add_role( $role, $display_name, $capabilities = array() ) {
   832 function add_role( $role, $display_name, $capabilities = array() ) {
   776 	if ( empty( $role ) ) {
   833 	if ( empty( $role ) ) {
   777 		return;
   834 		return;
   795  *
   852  *
   796  * @since 3.0.0
   853  * @since 3.0.0
   797  *
   854  *
   798  * @global array $super_admins
   855  * @global array $super_admins
   799  *
   856  *
   800  * @return array List of super admin logins
   857  * @return string[] List of super admin logins.
   801  */
   858  */
   802 function get_super_admins() {
   859 function get_super_admins() {
   803 	global $super_admins;
   860 	global $super_admins;
   804 
   861 
   805 	if ( isset( $super_admins ) ) {
   862 	if ( isset( $super_admins ) ) {
   816  *
   873  *
   817  * @param int $user_id (Optional) The ID of a user. Defaults to the current user.
   874  * @param int $user_id (Optional) The ID of a user. Defaults to the current user.
   818  * @return bool True if the user is a site admin.
   875  * @return bool True if the user is a site admin.
   819  */
   876  */
   820 function is_super_admin( $user_id = false ) {
   877 function is_super_admin( $user_id = false ) {
   821 	if ( ! $user_id || $user_id == get_current_user_id() ) {
   878 	if ( ! $user_id || get_current_user_id() == $user_id ) {
   822 		$user = wp_get_current_user();
   879 		$user = wp_get_current_user();
   823 	} else {
   880 	} else {
   824 		$user = get_userdata( $user_id );
   881 		$user = get_userdata( $user_id );
   825 	}
   882 	}
   826 
   883 
   828 		return false;
   885 		return false;
   829 	}
   886 	}
   830 
   887 
   831 	if ( is_multisite() ) {
   888 	if ( is_multisite() ) {
   832 		$super_admins = get_super_admins();
   889 		$super_admins = get_super_admins();
   833 		if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins ) ) {
   890 		if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins, true ) ) {
   834 			return true;
   891 			return true;
   835 		}
   892 		}
   836 	} else {
   893 	} else {
   837 		if ( $user->has_cap( 'delete_users' ) ) {
   894 		if ( $user->has_cap( 'delete_users' ) ) {
   838 			return true;
   895 			return true;
   866 	 *
   923 	 *
   867 	 * @param int $user_id ID of the user that is about to be granted Super Admin privileges.
   924 	 * @param int $user_id ID of the user that is about to be granted Super Admin privileges.
   868 	 */
   925 	 */
   869 	do_action( 'grant_super_admin', $user_id );
   926 	do_action( 'grant_super_admin', $user_id );
   870 
   927 
   871 	// Directly fetch site_admins instead of using get_super_admins()
   928 	// Directly fetch site_admins instead of using get_super_admins().
   872 	$super_admins = get_site_option( 'site_admins', array( 'admin' ) );
   929 	$super_admins = get_site_option( 'site_admins', array( 'admin' ) );
   873 
   930 
   874 	$user = get_userdata( $user_id );
   931 	$user = get_userdata( $user_id );
   875 	if ( $user && ! in_array( $user->user_login, $super_admins ) ) {
   932 	if ( $user && ! in_array( $user->user_login, $super_admins, true ) ) {
   876 		$super_admins[] = $user->user_login;
   933 		$super_admins[] = $user->user_login;
   877 		update_site_option( 'site_admins', $super_admins );
   934 		update_site_option( 'site_admins', $super_admins );
   878 
   935 
   879 		/**
   936 		/**
   880 		 * Fires after the user is granted Super Admin privileges.
   937 		 * Fires after the user is granted Super Admin privileges.
   913 	 *
   970 	 *
   914 	 * @param int $user_id ID of the user Super Admin privileges are being revoked from.
   971 	 * @param int $user_id ID of the user Super Admin privileges are being revoked from.
   915 	 */
   972 	 */
   916 	do_action( 'revoke_super_admin', $user_id );
   973 	do_action( 'revoke_super_admin', $user_id );
   917 
   974 
   918 	// Directly fetch site_admins instead of using get_super_admins()
   975 	// Directly fetch site_admins instead of using get_super_admins().
   919 	$super_admins = get_site_option( 'site_admins', array( 'admin' ) );
   976 	$super_admins = get_site_option( 'site_admins', array( 'admin' ) );
   920 
   977 
   921 	$user = get_userdata( $user_id );
   978 	$user = get_userdata( $user_id );
   922 	if ( $user && 0 !== strcasecmp( $user->user_email, get_site_option( 'admin_email' ) ) ) {
   979 	if ( $user && 0 !== strcasecmp( $user->user_email, get_site_option( 'admin_email' ) ) ) {
   923 		if ( false !== ( $key = array_search( $user->user_login, $super_admins ) ) ) {
   980 		$key = array_search( $user->user_login, $super_admins, true );
       
   981 		if ( false !== $key ) {
   924 			unset( $super_admins[ $key ] );
   982 			unset( $super_admins[ $key ] );
   925 			update_site_option( 'site_admins', $super_admins );
   983 			update_site_option( 'site_admins', $super_admins );
   926 
   984 
   927 			/**
   985 			/**
   928 			 * Fires after the user's Super Admin privileges are revoked.
   986 			 * Fires after the user's Super Admin privileges are revoked.
  1005 }
  1063 }
  1006 
  1064 
  1007 return;
  1065 return;
  1008 
  1066 
  1009 // Dummy gettext calls to get strings in the catalog.
  1067 // Dummy gettext calls to get strings in the catalog.
  1010 /* translators: user role for administrators  */
  1068 /* translators: User role for administrators. */
  1011 _x( 'Administrator', 'User role' );
  1069 _x( 'Administrator', 'User role' );
  1012 /* translators: user role for editors */
  1070 /* translators: User role for editors. */
  1013 _x( 'Editor', 'User role' );
  1071 _x( 'Editor', 'User role' );
  1014 /* translators: user role for authors */
  1072 /* translators: User role for authors. */
  1015 _x( 'Author', 'User role' );
  1073 _x( 'Author', 'User role' );
  1016 /* translators: user role for contributors */
  1074 /* translators: User role for contributors. */
  1017 _x( 'Contributor', 'User role' );
  1075 _x( 'Contributor', 'User role' );
  1018 /* translators: user role for subscriber */
  1076 /* translators: User role for subscribers. */
  1019 _x( 'Subscriber', 'User role' );
  1077 _x( 'Subscriber', 'User role' );