[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Core User Role & Capabilities API 4 * 5 * @package WordPress 6 * @subpackage Users 7 */ 8 9 /** 10 * Maps a capability to the primitive capabilities required of the given user to 11 * satisfy the capability being checked. 12 * 13 * This function also accepts an ID of an object to map against if the capability is a meta capability. Meta 14 * capabilities such as `edit_post` and `edit_user` are capabilities used by this function to map to primitive 15 * capabilities that a user or role requires, such as `edit_posts` and `edit_others_posts`. 16 * 17 * Example usage: 18 * 19 * map_meta_cap( 'edit_posts', $user->ID ); 20 * map_meta_cap( 'edit_post', $user->ID, $post->ID ); 21 * map_meta_cap( 'edit_post_meta', $user->ID, $post->ID, $meta_key ); 22 * 23 * This function does not check whether the user has the required capabilities, 24 * it just returns what the required capabilities are. 25 * 26 * @since 2.0.0 27 * @since 4.9.6 Added the `export_others_personal_data`, `erase_others_personal_data`, 28 * and `manage_privacy_options` capabilities. 29 * @since 5.1.0 Added the `update_php` capability. 30 * @since 5.2.0 Added the `resume_plugin` and `resume_theme` capabilities. 31 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter 32 * by adding it to the function signature. 33 * @since 5.7.0 Added the `create_app_password`, `list_app_passwords`, `read_app_password`, 34 * `edit_app_password`, `delete_app_passwords`, `delete_app_password`, 35 * and `update_https` capabilities. 36 * @since 6.7.0 Added the `edit_block_binding` capability. 37 * 38 * @global array $post_type_meta_caps Used to get post type meta capabilities. 39 * 40 * @param string $cap Capability being checked. 41 * @param int $user_id User ID. 42 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 43 * @return string[] Primitive capabilities required of the user. 44 */ 45 function map_meta_cap( $cap, $user_id, ...$args ) { 46 $caps = array(); 47 48 switch ( $cap ) { 49 case 'remove_user': 50 // In multisite the user must be a super admin to remove themselves. 51 if ( isset( $args[0] ) && $user_id === (int) $args[0] && ! is_super_admin( $user_id ) ) { 52 $caps[] = 'do_not_allow'; 53 } else { 54 $caps[] = 'remove_users'; 55 } 56 break; 57 case 'promote_user': 58 case 'add_users': 59 $caps[] = 'promote_users'; 60 break; 61 case 'edit_user': 62 case 'edit_users': 63 // Allow user to edit themselves. 64 if ( 'edit_user' === $cap && isset( $args[0] ) && $user_id === (int) $args[0] ) { 65 break; 66 } 67 68 // In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin. 69 if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) { 70 $caps[] = 'do_not_allow'; 71 } else { 72 $caps[] = 'edit_users'; // edit_user maps to edit_users. 73 } 74 break; 75 case 'delete_post': 76 case 'delete_page': 77 if ( ! isset( $args[0] ) ) { 78 if ( 'delete_post' === $cap ) { 79 /* translators: %s: Capability name. */ 80 $message = __( 'When checking for the %s capability, you must always check it against a specific post.' ); 81 } else { 82 /* translators: %s: Capability name. */ 83 $message = __( 'When checking for the %s capability, you must always check it against a specific page.' ); 84 } 85 86 _doing_it_wrong( 87 __FUNCTION__, 88 sprintf( $message, '<code>' . $cap . '</code>' ), 89 '6.1.0' 90 ); 91 92 $caps[] = 'do_not_allow'; 93 break; 94 } 95 96 $post = get_post( $args[0] ); 97 if ( ! $post ) { 98 $caps[] = 'do_not_allow'; 99 break; 100 } 101 102 if ( 'revision' === $post->post_type ) { 103 $caps[] = 'do_not_allow'; 104 break; 105 } 106 107 if ( (int) get_option( 'page_for_posts' ) === $post->ID 108 || (int) get_option( 'page_on_front' ) === $post->ID 109 ) { 110 $caps[] = 'manage_options'; 111 break; 112 } 113 114 $post_type = get_post_type_object( $post->post_type ); 115 if ( ! $post_type ) { 116 /* translators: 1: Post type, 2: Capability name. */ 117 $message = __( '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.' ); 118 119 _doing_it_wrong( 120 __FUNCTION__, 121 sprintf( 122 $message, 123 '<code>' . $post->post_type . '</code>', 124 '<code>' . $cap . '</code>' 125 ), 126 '4.4.0' 127 ); 128 129 $caps[] = 'edit_others_posts'; 130 break; 131 } 132 133 if ( ! $post_type->map_meta_cap ) { 134 $caps[] = $post_type->cap->$cap; 135 // Prior to 3.1 we would re-call map_meta_cap here. 136 if ( 'delete_post' === $cap ) { 137 $cap = $post_type->cap->$cap; 138 } 139 break; 140 } 141 142 // If the post author is set and the user is the author... 143 if ( $post->post_author && $user_id === (int) $post->post_author ) { 144 // If the post is published or scheduled... 145 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { 146 $caps[] = $post_type->cap->delete_published_posts; 147 } elseif ( 'trash' === $post->post_status ) { 148 $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true ); 149 if ( in_array( $status, array( 'publish', 'future' ), true ) ) { 150 $caps[] = $post_type->cap->delete_published_posts; 151 } else { 152 $caps[] = $post_type->cap->delete_posts; 153 } 154 } else { 155 // If the post is draft... 156 $caps[] = $post_type->cap->delete_posts; 157 } 158 } else { 159 // The user is trying to edit someone else's post. 160 $caps[] = $post_type->cap->delete_others_posts; 161 // The post is published or scheduled, extra cap required. 162 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { 163 $caps[] = $post_type->cap->delete_published_posts; 164 } elseif ( 'private' === $post->post_status ) { 165 $caps[] = $post_type->cap->delete_private_posts; 166 } 167 } 168 169 /* 170 * Setting the privacy policy page requires `manage_privacy_options`, 171 * so deleting it should require that too. 172 */ 173 if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) { 174 $caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) ); 175 } 176 177 break; 178 /* 179 * edit_post breaks down to edit_posts, edit_published_posts, or 180 * edit_others_posts. 181 */ 182 case 'edit_post': 183 case 'edit_page': 184 if ( ! isset( $args[0] ) ) { 185 if ( 'edit_post' === $cap ) { 186 /* translators: %s: Capability name. */ 187 $message = __( 'When checking for the %s capability, you must always check it against a specific post.' ); 188 } else { 189 /* translators: %s: Capability name. */ 190 $message = __( 'When checking for the %s capability, you must always check it against a specific page.' ); 191 } 192 193 _doing_it_wrong( 194 __FUNCTION__, 195 sprintf( $message, '<code>' . $cap . '</code>' ), 196 '6.1.0' 197 ); 198 199 $caps[] = 'do_not_allow'; 200 break; 201 } 202 203 $post = get_post( $args[0] ); 204 if ( ! $post ) { 205 $caps[] = 'do_not_allow'; 206 break; 207 } 208 209 if ( 'revision' === $post->post_type ) { 210 $post = get_post( $post->post_parent ); 211 if ( ! $post ) { 212 $caps[] = 'do_not_allow'; 213 break; 214 } 215 } 216 217 $post_type = get_post_type_object( $post->post_type ); 218 if ( ! $post_type ) { 219 /* translators: 1: Post type, 2: Capability name. */ 220 $message = __( '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.' ); 221 222 _doing_it_wrong( 223 __FUNCTION__, 224 sprintf( 225 $message, 226 '<code>' . $post->post_type . '</code>', 227 '<code>' . $cap . '</code>' 228 ), 229 '4.4.0' 230 ); 231 232 $caps[] = 'edit_others_posts'; 233 break; 234 } 235 236 if ( ! $post_type->map_meta_cap ) { 237 $caps[] = $post_type->cap->$cap; 238 // Prior to 3.1 we would re-call map_meta_cap here. 239 if ( 'edit_post' === $cap ) { 240 $cap = $post_type->cap->$cap; 241 } 242 break; 243 } 244 245 // If the post author is set and the user is the author... 246 if ( $post->post_author && $user_id === (int) $post->post_author ) { 247 // If the post is published or scheduled... 248 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { 249 $caps[] = $post_type->cap->edit_published_posts; 250 } elseif ( 'trash' === $post->post_status ) { 251 $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true ); 252 if ( in_array( $status, array( 'publish', 'future' ), true ) ) { 253 $caps[] = $post_type->cap->edit_published_posts; 254 } else { 255 $caps[] = $post_type->cap->edit_posts; 256 } 257 } else { 258 // If the post is draft... 259 $caps[] = $post_type->cap->edit_posts; 260 } 261 } else { 262 // The user is trying to edit someone else's post. 263 $caps[] = $post_type->cap->edit_others_posts; 264 // The post is published or scheduled, extra cap required. 265 if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) { 266 $caps[] = $post_type->cap->edit_published_posts; 267 } elseif ( 'private' === $post->post_status ) { 268 $caps[] = $post_type->cap->edit_private_posts; 269 } 270 } 271 272 /* 273 * Setting the privacy policy page requires `manage_privacy_options`, 274 * so editing it should require that too. 275 */ 276 if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) { 277 $caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) ); 278 } 279 280 break; 281 case 'read_post': 282 case 'read_page': 283 if ( ! isset( $args[0] ) ) { 284 if ( 'read_post' === $cap ) { 285 /* translators: %s: Capability name. */ 286 $message = __( 'When checking for the %s capability, you must always check it against a specific post.' ); 287 } else { 288 /* translators: %s: Capability name. */ 289 $message = __( 'When checking for the %s capability, you must always check it against a specific page.' ); 290 } 291 292 _doing_it_wrong( 293 __FUNCTION__, 294 sprintf( $message, '<code>' . $cap . '</code>' ), 295 '6.1.0' 296 ); 297 298 $caps[] = 'do_not_allow'; 299 break; 300 } 301 302 $post = get_post( $args[0] ); 303 if ( ! $post ) { 304 $caps[] = 'do_not_allow'; 305 break; 306 } 307 308 if ( 'revision' === $post->post_type ) { 309 $post = get_post( $post->post_parent ); 310 if ( ! $post ) { 311 $caps[] = 'do_not_allow'; 312 break; 313 } 314 } 315 316 $post_type = get_post_type_object( $post->post_type ); 317 if ( ! $post_type ) { 318 /* translators: 1: Post type, 2: Capability name. */ 319 $message = __( '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.' ); 320 321 _doing_it_wrong( 322 __FUNCTION__, 323 sprintf( 324 $message, 325 '<code>' . $post->post_type . '</code>', 326 '<code>' . $cap . '</code>' 327 ), 328 '4.4.0' 329 ); 330 331 $caps[] = 'edit_others_posts'; 332 break; 333 } 334 335 if ( ! $post_type->map_meta_cap ) { 336 $caps[] = $post_type->cap->$cap; 337 // Prior to 3.1 we would re-call map_meta_cap here. 338 if ( 'read_post' === $cap ) { 339 $cap = $post_type->cap->$cap; 340 } 341 break; 342 } 343 344 $status_obj = get_post_status_object( get_post_status( $post ) ); 345 if ( ! $status_obj ) { 346 /* translators: 1: Post status, 2: Capability name. */ 347 $message = __( '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.' ); 348 349 _doing_it_wrong( 350 __FUNCTION__, 351 sprintf( 352 $message, 353 '<code>' . get_post_status( $post ) . '</code>', 354 '<code>' . $cap . '</code>' 355 ), 356 '5.4.0' 357 ); 358 359 $caps[] = 'edit_others_posts'; 360 break; 361 } 362 363 if ( $status_obj->public ) { 364 $caps[] = $post_type->cap->read; 365 break; 366 } 367 368 if ( $post->post_author && $user_id === (int) $post->post_author ) { 369 $caps[] = $post_type->cap->read; 370 } elseif ( $status_obj->private ) { 371 $caps[] = $post_type->cap->read_private_posts; 372 } else { 373 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); 374 } 375 break; 376 case 'publish_post': 377 if ( ! isset( $args[0] ) ) { 378 /* translators: %s: Capability name. */ 379 $message = __( 'When checking for the %s capability, you must always check it against a specific post.' ); 380 381 _doing_it_wrong( 382 __FUNCTION__, 383 sprintf( $message, '<code>' . $cap . '</code>' ), 384 '6.1.0' 385 ); 386 387 $caps[] = 'do_not_allow'; 388 break; 389 } 390 391 $post = get_post( $args[0] ); 392 if ( ! $post ) { 393 $caps[] = 'do_not_allow'; 394 break; 395 } 396 397 $post_type = get_post_type_object( $post->post_type ); 398 if ( ! $post_type ) { 399 /* translators: 1: Post type, 2: Capability name. */ 400 $message = __( '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.' ); 401 402 _doing_it_wrong( 403 __FUNCTION__, 404 sprintf( 405 $message, 406 '<code>' . $post->post_type . '</code>', 407 '<code>' . $cap . '</code>' 408 ), 409 '4.4.0' 410 ); 411 412 $caps[] = 'edit_others_posts'; 413 break; 414 } 415 416 $caps[] = $post_type->cap->publish_posts; 417 break; 418 case 'edit_post_meta': 419 case 'delete_post_meta': 420 case 'add_post_meta': 421 case 'edit_comment_meta': 422 case 'delete_comment_meta': 423 case 'add_comment_meta': 424 case 'edit_term_meta': 425 case 'delete_term_meta': 426 case 'add_term_meta': 427 case 'edit_user_meta': 428 case 'delete_user_meta': 429 case 'add_user_meta': 430 $object_type = explode( '_', $cap )[1]; 431 432 if ( ! isset( $args[0] ) ) { 433 if ( 'post' === $object_type ) { 434 /* translators: %s: Capability name. */ 435 $message = __( 'When checking for the %s capability, you must always check it against a specific post.' ); 436 } elseif ( 'comment' === $object_type ) { 437 /* translators: %s: Capability name. */ 438 $message = __( 'When checking for the %s capability, you must always check it against a specific comment.' ); 439 } elseif ( 'term' === $object_type ) { 440 /* translators: %s: Capability name. */ 441 $message = __( 'When checking for the %s capability, you must always check it against a specific term.' ); 442 } else { 443 /* translators: %s: Capability name. */ 444 $message = __( 'When checking for the %s capability, you must always check it against a specific user.' ); 445 } 446 447 _doing_it_wrong( 448 __FUNCTION__, 449 sprintf( $message, '<code>' . $cap . '</code>' ), 450 '6.1.0' 451 ); 452 453 $caps[] = 'do_not_allow'; 454 break; 455 } 456 457 $object_id = (int) $args[0]; 458 459 $object_subtype = get_object_subtype( $object_type, $object_id ); 460 461 if ( empty( $object_subtype ) ) { 462 $caps[] = 'do_not_allow'; 463 break; 464 } 465 466 $caps = map_meta_cap( "edit_{$object_type}", $user_id, $object_id ); 467 468 $meta_key = isset( $args[1] ) ? $args[1] : false; 469 470 if ( $meta_key ) { 471 $allowed = ! is_protected_meta( $meta_key, $object_type ); 472 473 if ( ! empty( $object_subtype ) && has_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) { 474 475 /** 476 * Filters whether the user is allowed to edit a specific meta key of a specific object type and subtype. 477 * 478 * The dynamic portions of the hook name, `$object_type`, `$meta_key`, 479 * and `$object_subtype`, refer to the metadata object type (comment, post, term or user), 480 * the meta key value, and the object subtype respectively. 481 * 482 * @since 4.9.8 483 * 484 * @param bool $allowed Whether the user can add the object meta. Default false. 485 * @param string $meta_key The meta key. 486 * @param int $object_id Object ID. 487 * @param int $user_id User ID. 488 * @param string $cap Capability name. 489 * @param string[] $caps Array of the user's capabilities. 490 */ 491 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); 492 } else { 493 494 /** 495 * Filters whether the user is allowed to edit a specific meta key of a specific object type. 496 * 497 * Return true to have the mapped meta caps from `edit_{$object_type}` apply. 498 * 499 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered. 500 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap(). 501 * 502 * @since 3.3.0 As `auth_post_meta_{$meta_key}`. 503 * @since 4.6.0 504 * 505 * @param bool $allowed Whether the user can add the object meta. Default false. 506 * @param string $meta_key The meta key. 507 * @param int $object_id Object ID. 508 * @param int $user_id User ID. 509 * @param string $cap Capability name. 510 * @param string[] $caps Array of the user's capabilities. 511 */ 512 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); 513 } 514 515 if ( ! empty( $object_subtype ) ) { 516 517 /** 518 * Filters whether the user is allowed to edit meta for specific object types/subtypes. 519 * 520 * Return true to have the mapped meta caps from `edit_{$object_type}` apply. 521 * 522 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered. 523 * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered. 524 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap(). 525 * 526 * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`. 527 * @since 4.7.0 Renamed from `auth_post_{$post_type}_meta_{$meta_key}` to 528 * `auth_{$object_type}_{$object_subtype}_meta_{$meta_key}`. 529 * @deprecated 4.9.8 Use {@see 'auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}'} instead. 530 * 531 * @param bool $allowed Whether the user can add the object meta. Default false. 532 * @param string $meta_key The meta key. 533 * @param int $object_id Object ID. 534 * @param int $user_id User ID. 535 * @param string $cap Capability name. 536 * @param string[] $caps Array of the user's capabilities. 537 */ 538 $allowed = apply_filters_deprecated( 539 "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", 540 array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ), 541 '4.9.8', 542 "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" 543 ); 544 } 545 546 if ( ! $allowed ) { 547 $caps[] = $cap; 548 } 549 } 550 break; 551 case 'edit_comment': 552 if ( ! isset( $args[0] ) ) { 553 /* translators: %s: Capability name. */ 554 $message = __( 'When checking for the %s capability, you must always check it against a specific comment.' ); 555 556 _doing_it_wrong( 557 __FUNCTION__, 558 sprintf( $message, '<code>' . $cap . '</code>' ), 559 '6.1.0' 560 ); 561 562 $caps[] = 'do_not_allow'; 563 break; 564 } 565 566 $comment = get_comment( $args[0] ); 567 if ( ! $comment ) { 568 $caps[] = 'do_not_allow'; 569 break; 570 } 571 572 $post = get_post( $comment->comment_post_ID ); 573 574 /* 575 * If the post doesn't exist, we have an orphaned comment. 576 * Fall back to the edit_posts capability, instead. 577 */ 578 if ( $post ) { 579 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); 580 } else { 581 $caps = map_meta_cap( 'edit_posts', $user_id ); 582 } 583 break; 584 case 'unfiltered_upload': 585 if ( defined( 'ALLOW_UNFILTERED_UPLOADS' ) && ALLOW_UNFILTERED_UPLOADS && ( ! is_multisite() || is_super_admin( $user_id ) ) ) { 586 $caps[] = $cap; 587 } else { 588 $caps[] = 'do_not_allow'; 589 } 590 break; 591 case 'edit_css': 592 case 'unfiltered_html': 593 // Disallow unfiltered_html for all users, even admins and super admins. 594 if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) { 595 $caps[] = 'do_not_allow'; 596 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 597 $caps[] = 'do_not_allow'; 598 } else { 599 $caps[] = 'unfiltered_html'; 600 } 601 break; 602 case 'edit_files': 603 case 'edit_plugins': 604 case 'edit_themes': 605 // Disallow the file editors. 606 if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT ) { 607 $caps[] = 'do_not_allow'; 608 } elseif ( ! wp_is_file_mod_allowed( 'capability_edit_themes' ) ) { 609 $caps[] = 'do_not_allow'; 610 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 611 $caps[] = 'do_not_allow'; 612 } else { 613 $caps[] = $cap; 614 } 615 break; 616 case 'update_plugins': 617 case 'delete_plugins': 618 case 'install_plugins': 619 case 'upload_plugins': 620 case 'update_themes': 621 case 'delete_themes': 622 case 'install_themes': 623 case 'upload_themes': 624 case 'update_core': 625 /* 626 * Disallow anything that creates, deletes, or updates core, plugin, or theme files. 627 * Files in uploads are excepted. 628 */ 629 if ( ! wp_is_file_mod_allowed( 'capability_update_core' ) ) { 630 $caps[] = 'do_not_allow'; 631 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 632 $caps[] = 'do_not_allow'; 633 } elseif ( 'upload_themes' === $cap ) { 634 $caps[] = 'install_themes'; 635 } elseif ( 'upload_plugins' === $cap ) { 636 $caps[] = 'install_plugins'; 637 } else { 638 $caps[] = $cap; 639 } 640 break; 641 case 'install_languages': 642 case 'update_languages': 643 if ( ! wp_is_file_mod_allowed( 'can_install_language_pack' ) ) { 644 $caps[] = 'do_not_allow'; 645 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 646 $caps[] = 'do_not_allow'; 647 } else { 648 $caps[] = 'install_languages'; 649 } 650 break; 651 case 'activate_plugins': 652 case 'deactivate_plugins': 653 case 'activate_plugin': 654 case 'deactivate_plugin': 655 $caps[] = 'activate_plugins'; 656 if ( is_multisite() ) { 657 // update_, install_, and delete_ are handled above with is_super_admin(). 658 $menu_perms = get_site_option( 'menu_items', array() ); 659 if ( empty( $menu_perms['plugins'] ) ) { 660 $caps[] = 'manage_network_plugins'; 661 } 662 } 663 break; 664 case 'resume_plugin': 665 $caps[] = 'resume_plugins'; 666 break; 667 case 'resume_theme': 668 $caps[] = 'resume_themes'; 669 break; 670 case 'delete_user': 671 case 'delete_users': 672 // If multisite only super admins can delete users. 673 if ( is_multisite() && ! is_super_admin( $user_id ) ) { 674 $caps[] = 'do_not_allow'; 675 } else { 676 $caps[] = 'delete_users'; // delete_user maps to delete_users. 677 } 678 break; 679 case 'create_users': 680 if ( ! is_multisite() ) { 681 $caps[] = $cap; 682 } elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) ) { 683 $caps[] = $cap; 684 } else { 685 $caps[] = 'do_not_allow'; 686 } 687 break; 688 case 'manage_links': 689 if ( get_option( 'link_manager_enabled' ) ) { 690 $caps[] = $cap; 691 } else { 692 $caps[] = 'do_not_allow'; 693 } 694 break; 695 case 'customize': 696 $caps[] = 'edit_theme_options'; 697 break; 698 case 'delete_site': 699 if ( is_multisite() ) { 700 $caps[] = 'manage_options'; 701 } else { 702 $caps[] = 'do_not_allow'; 703 } 704 break; 705 case 'edit_term': 706 case 'delete_term': 707 case 'assign_term': 708 if ( ! isset( $args[0] ) ) { 709 /* translators: %s: Capability name. */ 710 $message = __( 'When checking for the %s capability, you must always check it against a specific term.' ); 711 712 _doing_it_wrong( 713 __FUNCTION__, 714 sprintf( $message, '<code>' . $cap . '</code>' ), 715 '6.1.0' 716 ); 717 718 $caps[] = 'do_not_allow'; 719 break; 720 } 721 722 $term_id = (int) $args[0]; 723 $term = get_term( $term_id ); 724 if ( ! $term || is_wp_error( $term ) ) { 725 $caps[] = 'do_not_allow'; 726 break; 727 } 728 729 $tax = get_taxonomy( $term->taxonomy ); 730 if ( ! $tax ) { 731 $caps[] = 'do_not_allow'; 732 break; 733 } 734 735 if ( 'delete_term' === $cap 736 && ( (int) get_option( 'default_' . $term->taxonomy ) === $term->term_id 737 || (int) get_option( 'default_term_' . $term->taxonomy ) === $term->term_id ) 738 ) { 739 $caps[] = 'do_not_allow'; 740 break; 741 } 742 743 $taxo_cap = $cap . 's'; 744 745 $caps = map_meta_cap( $tax->cap->$taxo_cap, $user_id, $term_id ); 746 747 break; 748 case 'manage_post_tags': 749 case 'edit_categories': 750 case 'edit_post_tags': 751 case 'delete_categories': 752 case 'delete_post_tags': 753 $caps[] = 'manage_categories'; 754 break; 755 case 'assign_categories': 756 case 'assign_post_tags': 757 $caps[] = 'edit_posts'; 758 break; 759 case 'create_sites': 760 case 'delete_sites': 761 case 'manage_network': 762 case 'manage_sites': 763 case 'manage_network_users': 764 case 'manage_network_plugins': 765 case 'manage_network_themes': 766 case 'manage_network_options': 767 case 'upgrade_network': 768 $caps[] = $cap; 769 break; 770 case 'setup_network': 771 if ( is_multisite() ) { 772 $caps[] = 'manage_network_options'; 773 } else { 774 $caps[] = 'manage_options'; 775 } 776 break; 777 case 'update_php': 778 if ( is_multisite() && ! is_super_admin( $user_id ) ) { 779 $caps[] = 'do_not_allow'; 780 } else { 781 $caps[] = 'update_core'; 782 } 783 break; 784 case 'update_https': 785 if ( is_multisite() && ! is_super_admin( $user_id ) ) { 786 $caps[] = 'do_not_allow'; 787 } else { 788 $caps[] = 'manage_options'; 789 $caps[] = 'update_core'; 790 } 791 break; 792 case 'export_others_personal_data': 793 case 'erase_others_personal_data': 794 case 'manage_privacy_options': 795 $caps[] = is_multisite() ? 'manage_network' : 'manage_options'; 796 break; 797 case 'create_app_password': 798 case 'list_app_passwords': 799 case 'read_app_password': 800 case 'edit_app_password': 801 case 'delete_app_passwords': 802 case 'delete_app_password': 803 $caps = map_meta_cap( 'edit_user', $user_id, $args[0] ); 804 break; 805 case 'edit_block_binding': 806 $block_editor_context = $args[0]; 807 if ( isset( $block_editor_context->post ) ) { 808 $object_id = $block_editor_context->post->ID; 809 } 810 /* 811 * If the post ID is null, check if the context is the site editor. 812 * Fall back to the edit_theme_options in that case. 813 */ 814 if ( ! isset( $object_id ) ) { 815 if ( ! isset( $block_editor_context->name ) || 'core/edit-site' !== $block_editor_context->name ) { 816 $caps[] = 'do_not_allow'; 817 break; 818 } 819 $caps = map_meta_cap( 'edit_theme_options', $user_id ); 820 break; 821 } 822 823 $object_subtype = get_object_subtype( 'post', (int) $object_id ); 824 if ( empty( $object_subtype ) ) { 825 $caps[] = 'do_not_allow'; 826 break; 827 } 828 $post_type_object = get_post_type_object( $object_subtype ); 829 // Initialize empty array if it doesn't exist. 830 if ( ! isset( $post_type_object->capabilities ) ) { 831 $post_type_object->capabilities = array(); 832 } 833 $post_type_capabilities = get_post_type_capabilities( $post_type_object ); 834 $caps = map_meta_cap( $post_type_capabilities->edit_post, $user_id, $object_id ); 835 break; 836 default: 837 // Handle meta capabilities for custom post types. 838 global $post_type_meta_caps; 839 if ( isset( $post_type_meta_caps[ $cap ] ) ) { 840 return map_meta_cap( $post_type_meta_caps[ $cap ], $user_id, ...$args ); 841 } 842 843 // Block capabilities map to their post equivalent. 844 $block_caps = array( 845 'edit_blocks', 846 'edit_others_blocks', 847 'publish_blocks', 848 'read_private_blocks', 849 'delete_blocks', 850 'delete_private_blocks', 851 'delete_published_blocks', 852 'delete_others_blocks', 853 'edit_private_blocks', 854 'edit_published_blocks', 855 ); 856 if ( in_array( $cap, $block_caps, true ) ) { 857 $cap = str_replace( '_blocks', '_posts', $cap ); 858 } 859 860 // If no meta caps match, return the original cap. 861 $caps[] = $cap; 862 } 863 864 /** 865 * Filters the primitive capabilities required of the given user to satisfy the 866 * capability being checked. 867 * 868 * @since 2.8.0 869 * 870 * @param string[] $caps Primitive capabilities required of the user. 871 * @param string $cap Capability being checked. 872 * @param int $user_id The user ID. 873 * @param array $args Adds context to the capability check, typically 874 * starting with an object ID. 875 */ 876 return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args ); 877 } 878 879 /** 880 * Returns whether the current user has the specified capability. 881 * 882 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 883 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 884 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 885 * 886 * Example usage: 887 * 888 * current_user_can( 'edit_posts' ); 889 * current_user_can( 'edit_post', $post->ID ); 890 * current_user_can( 'edit_post_meta', $post->ID, $meta_key ); 891 * 892 * While checking against particular roles in place of a capability is supported 893 * in part, this practice is discouraged as it may produce unreliable results. 894 * 895 * Note: Will always return true if the current user is a super admin, unless specifically denied. 896 * 897 * @since 2.0.0 898 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter 899 * by adding it to the function signature. 900 * @since 5.8.0 Converted to wrapper for the user_can() function. 901 * 902 * @see WP_User::has_cap() 903 * @see map_meta_cap() 904 * 905 * @param string $capability Capability name. 906 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 907 * @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is 908 * passed, whether the current user has the given meta capability for the given object. 909 */ 910 function current_user_can( $capability, ...$args ) { 911 return user_can( wp_get_current_user(), $capability, ...$args ); 912 } 913 914 /** 915 * Returns whether the current user has the specified capability for a given site. 916 * 917 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 918 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 919 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 920 * 921 * This function replaces the current_user_can_for_blog() function. 922 * 923 * Example usage: 924 * 925 * current_user_can_for_site( $site_id, 'edit_posts' ); 926 * current_user_can_for_site( $site_id, 'edit_post', $post->ID ); 927 * current_user_can_for_site( $site_id, 'edit_post_meta', $post->ID, $meta_key ); 928 * 929 * @since 6.7.0 930 * 931 * @param int $site_id Site ID. 932 * @param string $capability Capability name. 933 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 934 * @return bool Whether the user has the given capability. 935 */ 936 function current_user_can_for_site( $site_id, $capability, ...$args ) { 937 $switched = is_multisite() ? switch_to_blog( $site_id ) : false; 938 939 $can = current_user_can( $capability, ...$args ); 940 941 if ( $switched ) { 942 restore_current_blog(); 943 } 944 945 return $can; 946 } 947 948 /** 949 * Returns whether the author of the supplied post has the specified capability. 950 * 951 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 952 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 953 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 954 * 955 * Example usage: 956 * 957 * author_can( $post, 'edit_posts' ); 958 * author_can( $post, 'edit_post', $post->ID ); 959 * author_can( $post, 'edit_post_meta', $post->ID, $meta_key ); 960 * 961 * @since 2.9.0 962 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter 963 * by adding it to the function signature. 964 * 965 * @param int|WP_Post $post Post ID or post object. 966 * @param string $capability Capability name. 967 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 968 * @return bool Whether the post author has the given capability. 969 */ 970 function author_can( $post, $capability, ...$args ) { 971 $post = get_post( $post ); 972 if ( ! $post ) { 973 return false; 974 } 975 976 $author = get_userdata( $post->post_author ); 977 978 if ( ! $author ) { 979 return false; 980 } 981 982 return $author->has_cap( $capability, ...$args ); 983 } 984 985 /** 986 * Returns whether a particular user has the specified capability. 987 * 988 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 989 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 990 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 991 * 992 * Example usage: 993 * 994 * user_can( $user->ID, 'edit_posts' ); 995 * user_can( $user->ID, 'edit_post', $post->ID ); 996 * user_can( $user->ID, 'edit_post_meta', $post->ID, $meta_key ); 997 * 998 * @since 3.1.0 999 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter 1000 * by adding it to the function signature. 1001 * 1002 * @param int|WP_User $user User ID or object. 1003 * @param string $capability Capability name. 1004 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 1005 * @return bool Whether the user has the given capability. 1006 */ 1007 function user_can( $user, $capability, ...$args ) { 1008 if ( ! is_object( $user ) ) { 1009 $user = get_userdata( $user ); 1010 } 1011 1012 if ( empty( $user ) ) { 1013 // User is logged out, create anonymous user object. 1014 $user = new WP_User( 0 ); 1015 $user->init( new stdClass() ); 1016 } 1017 1018 return $user->has_cap( $capability, ...$args ); 1019 } 1020 1021 /** 1022 * Returns whether a particular user has the specified capability for a given site. 1023 * 1024 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 1025 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 1026 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 1027 * 1028 * Example usage: 1029 * 1030 * user_can_for_site( $user->ID, $site_id, 'edit_posts' ); 1031 * user_can_for_site( $user->ID, $site_id, 'edit_post', $post->ID ); 1032 * user_can_for_site( $user->ID, $site_id, 'edit_post_meta', $post->ID, $meta_key ); 1033 * 1034 * @since 6.7.0 1035 * 1036 * @param int|WP_User $user User ID or object. 1037 * @param int $site_id Site ID. 1038 * @param string $capability Capability name. 1039 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 1040 * @return bool Whether the user has the given capability. 1041 */ 1042 function user_can_for_site( $user, $site_id, $capability, ...$args ) { 1043 if ( ! is_object( $user ) ) { 1044 $user = get_userdata( $user ); 1045 } 1046 1047 if ( empty( $user ) ) { 1048 // User is logged out, create anonymous user object. 1049 $user = new WP_User( 0 ); 1050 $user->init( new stdClass() ); 1051 } 1052 1053 // Check if the blog ID is valid. 1054 if ( ! is_numeric( $site_id ) || $site_id <= 0 ) { 1055 return false; 1056 } 1057 1058 $switched = is_multisite() ? switch_to_blog( $site_id ) : false; 1059 1060 $can = user_can( $user->ID, $capability, ...$args ); 1061 1062 if ( $switched ) { 1063 restore_current_blog(); 1064 } 1065 1066 return $can; 1067 } 1068 1069 /** 1070 * Retrieves the global WP_Roles instance and instantiates it if necessary. 1071 * 1072 * @since 4.3.0 1073 * 1074 * @global WP_Roles $wp_roles WordPress role management object. 1075 * 1076 * @return WP_Roles WP_Roles global instance if not already instantiated. 1077 */ 1078 function wp_roles() { 1079 global $wp_roles; 1080 1081 if ( ! isset( $wp_roles ) ) { 1082 $wp_roles = new WP_Roles(); 1083 } 1084 return $wp_roles; 1085 } 1086 1087 /** 1088 * Retrieves role object. 1089 * 1090 * @since 2.0.0 1091 * 1092 * @param string $role Role name. 1093 * @return WP_Role|null WP_Role object if found, null if the role does not exist. 1094 */ 1095 function get_role( $role ) { 1096 return wp_roles()->get_role( $role ); 1097 } 1098 1099 /** 1100 * Adds a role, if it does not exist. 1101 * 1102 * @since 2.0.0 1103 * 1104 * @param string $role Role name. 1105 * @param string $display_name Display name for role. 1106 * @param bool[] $capabilities List of capabilities keyed by the capability name, 1107 * e.g. array( 'edit_posts' => true, 'delete_posts' => false ). 1108 * @return WP_Role|void WP_Role object, if the role is added. 1109 */ 1110 function add_role( $role, $display_name, $capabilities = array() ) { 1111 if ( empty( $role ) ) { 1112 return; 1113 } 1114 1115 return wp_roles()->add_role( $role, $display_name, $capabilities ); 1116 } 1117 1118 /** 1119 * Removes a role, if it exists. 1120 * 1121 * @since 2.0.0 1122 * 1123 * @param string $role Role name. 1124 */ 1125 function remove_role( $role ) { 1126 wp_roles()->remove_role( $role ); 1127 } 1128 1129 /** 1130 * Retrieves a list of super admins. 1131 * 1132 * @since 3.0.0 1133 * 1134 * @global array $super_admins 1135 * 1136 * @return string[] List of super admin logins. 1137 */ 1138 function get_super_admins() { 1139 global $super_admins; 1140 1141 if ( isset( $super_admins ) ) { 1142 return $super_admins; 1143 } else { 1144 return get_site_option( 'site_admins', array( 'admin' ) ); 1145 } 1146 } 1147 1148 /** 1149 * Determines whether user is a site admin. 1150 * 1151 * @since 3.0.0 1152 * 1153 * @param int|false $user_id Optional. The ID of a user. Defaults to false, to check the current user. 1154 * @return bool Whether the user is a site admin. 1155 */ 1156 function is_super_admin( $user_id = false ) { 1157 if ( ! $user_id ) { 1158 $user = wp_get_current_user(); 1159 } else { 1160 $user = get_userdata( $user_id ); 1161 } 1162 1163 if ( ! $user || ! $user->exists() ) { 1164 return false; 1165 } 1166 1167 if ( is_multisite() ) { 1168 $super_admins = get_super_admins(); 1169 if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins, true ) ) { 1170 return true; 1171 } 1172 } elseif ( $user->has_cap( 'delete_users' ) ) { 1173 return true; 1174 } 1175 1176 return false; 1177 } 1178 1179 /** 1180 * Grants Super Admin privileges. 1181 * 1182 * @since 3.0.0 1183 * 1184 * @global array $super_admins 1185 * 1186 * @param int $user_id ID of the user to be granted Super Admin privileges. 1187 * @return bool True on success, false on failure. This can fail when the user is 1188 * already a super admin or when the `$super_admins` global is defined. 1189 */ 1190 function grant_super_admin( $user_id ) { 1191 // If global super_admins override is defined, there is nothing to do here. 1192 if ( isset( $GLOBALS['super_admins'] ) || ! is_multisite() ) { 1193 return false; 1194 } 1195 1196 /** 1197 * Fires before the user is granted Super Admin privileges. 1198 * 1199 * @since 3.0.0 1200 * 1201 * @param int $user_id ID of the user that is about to be granted Super Admin privileges. 1202 */ 1203 do_action( 'grant_super_admin', $user_id ); 1204 1205 // Directly fetch site_admins instead of using get_super_admins(). 1206 $super_admins = get_site_option( 'site_admins', array( 'admin' ) ); 1207 1208 $user = get_userdata( $user_id ); 1209 if ( $user && ! in_array( $user->user_login, $super_admins, true ) ) { 1210 $super_admins[] = $user->user_login; 1211 update_site_option( 'site_admins', $super_admins ); 1212 1213 /** 1214 * Fires after the user is granted Super Admin privileges. 1215 * 1216 * @since 3.0.0 1217 * 1218 * @param int $user_id ID of the user that was granted Super Admin privileges. 1219 */ 1220 do_action( 'granted_super_admin', $user_id ); 1221 return true; 1222 } 1223 return false; 1224 } 1225 1226 /** 1227 * Revokes Super Admin privileges. 1228 * 1229 * @since 3.0.0 1230 * 1231 * @global array $super_admins 1232 * 1233 * @param int $user_id ID of the user Super Admin privileges to be revoked from. 1234 * @return bool True on success, false on failure. This can fail when the user's email 1235 * is the network admin email or when the `$super_admins` global is defined. 1236 */ 1237 function revoke_super_admin( $user_id ) { 1238 // If global super_admins override is defined, there is nothing to do here. 1239 if ( isset( $GLOBALS['super_admins'] ) || ! is_multisite() ) { 1240 return false; 1241 } 1242 1243 /** 1244 * Fires before the user's Super Admin privileges are revoked. 1245 * 1246 * @since 3.0.0 1247 * 1248 * @param int $user_id ID of the user Super Admin privileges are being revoked from. 1249 */ 1250 do_action( 'revoke_super_admin', $user_id ); 1251 1252 // Directly fetch site_admins instead of using get_super_admins(). 1253 $super_admins = get_site_option( 'site_admins', array( 'admin' ) ); 1254 1255 $user = get_userdata( $user_id ); 1256 if ( $user && 0 !== strcasecmp( $user->user_email, get_site_option( 'admin_email' ) ) ) { 1257 $key = array_search( $user->user_login, $super_admins, true ); 1258 if ( false !== $key ) { 1259 unset( $super_admins[ $key ] ); 1260 update_site_option( 'site_admins', $super_admins ); 1261 1262 /** 1263 * Fires after the user's Super Admin privileges are revoked. 1264 * 1265 * @since 3.0.0 1266 * 1267 * @param int $user_id ID of the user Super Admin privileges were revoked from. 1268 */ 1269 do_action( 'revoked_super_admin', $user_id ); 1270 return true; 1271 } 1272 } 1273 return false; 1274 } 1275 1276 /** 1277 * Filters the user capabilities to grant the 'install_languages' capability as necessary. 1278 * 1279 * A user must have at least one out of the 'update_core', 'install_plugins', and 1280 * 'install_themes' capabilities to qualify for 'install_languages'. 1281 * 1282 * @since 4.9.0 1283 * 1284 * @param bool[] $allcaps An array of all the user's capabilities. 1285 * @return bool[] Filtered array of the user's capabilities. 1286 */ 1287 function wp_maybe_grant_install_languages_cap( $allcaps ) { 1288 if ( ! empty( $allcaps['update_core'] ) || ! empty( $allcaps['install_plugins'] ) || ! empty( $allcaps['install_themes'] ) ) { 1289 $allcaps['install_languages'] = true; 1290 } 1291 1292 return $allcaps; 1293 } 1294 1295 /** 1296 * Filters the user capabilities to grant the 'resume_plugins' and 'resume_themes' capabilities as necessary. 1297 * 1298 * @since 5.2.0 1299 * 1300 * @param bool[] $allcaps An array of all the user's capabilities. 1301 * @return bool[] Filtered array of the user's capabilities. 1302 */ 1303 function wp_maybe_grant_resume_extensions_caps( $allcaps ) { 1304 // Even in a multisite, regular administrators should be able to resume plugins. 1305 if ( ! empty( $allcaps['activate_plugins'] ) ) { 1306 $allcaps['resume_plugins'] = true; 1307 } 1308 1309 // Even in a multisite, regular administrators should be able to resume themes. 1310 if ( ! empty( $allcaps['switch_themes'] ) ) { 1311 $allcaps['resume_themes'] = true; 1312 } 1313 1314 return $allcaps; 1315 } 1316 1317 /** 1318 * Filters the user capabilities to grant the 'view_site_health_checks' capabilities as necessary. 1319 * 1320 * @since 5.2.2 1321 * 1322 * @param bool[] $allcaps An array of all the user's capabilities. 1323 * @param string[] $caps Required primitive capabilities for the requested capability. 1324 * @param array $args { 1325 * Arguments that accompany the requested capability check. 1326 * 1327 * @type string $0 Requested capability. 1328 * @type int $1 Concerned user ID. 1329 * @type mixed ...$2 Optional second and further parameters, typically object ID. 1330 * } 1331 * @param WP_User $user The user object. 1332 * @return bool[] Filtered array of the user's capabilities. 1333 */ 1334 function wp_maybe_grant_site_health_caps( $allcaps, $caps, $args, $user ) { 1335 if ( ! empty( $allcaps['install_plugins'] ) && ( ! is_multisite() || is_super_admin( $user->ID ) ) ) { 1336 $allcaps['view_site_health_checks'] = true; 1337 } 1338 1339 return $allcaps; 1340 } 1341 1342 return; 1343 1344 // Dummy gettext calls to get strings in the catalog. 1345 /* translators: User role for administrators. */ 1346 _x( 'Administrator', 'User role' ); 1347 /* translators: User role for editors. */ 1348 _x( 'Editor', 'User role' ); 1349 /* translators: User role for authors. */ 1350 _x( 'Author', 'User role' ); 1351 /* translators: User role for contributors. */ 1352 _x( 'Contributor', 'User role' ); 1353 /* translators: User role for subscribers. */ 1354 _x( 'Subscriber', 'User role' );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Tue Dec 24 08:20:01 2024 | Cross-referenced by PHPXref |