[ 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 ( 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 /** 516 * Filters whether the user is allowed to edit meta for specific object types/subtypes. 517 * 518 * Return true to have the mapped meta caps from `edit_{$object_type}` apply. 519 * 520 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered. 521 * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered. 522 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap(). 523 * 524 * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`. 525 * @since 4.7.0 Renamed from `auth_post_{$post_type}_meta_{$meta_key}` to 526 * `auth_{$object_type}_{$object_subtype}_meta_{$meta_key}`. 527 * @deprecated 4.9.8 Use {@see 'auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}'} instead. 528 * 529 * @param bool $allowed Whether the user can add the object meta. Default false. 530 * @param string $meta_key The meta key. 531 * @param int $object_id Object ID. 532 * @param int $user_id User ID. 533 * @param string $cap Capability name. 534 * @param string[] $caps Array of the user's capabilities. 535 */ 536 $allowed = apply_filters_deprecated( 537 "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", 538 array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ), 539 '4.9.8', 540 "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" 541 ); 542 543 if ( ! $allowed ) { 544 $caps[] = $cap; 545 } 546 } 547 break; 548 case 'edit_comment': 549 if ( ! isset( $args[0] ) ) { 550 /* translators: %s: Capability name. */ 551 $message = __( 'When checking for the %s capability, you must always check it against a specific comment.' ); 552 553 _doing_it_wrong( 554 __FUNCTION__, 555 sprintf( $message, '<code>' . $cap . '</code>' ), 556 '6.1.0' 557 ); 558 559 $caps[] = 'do_not_allow'; 560 break; 561 } 562 563 $comment = get_comment( $args[0] ); 564 if ( ! $comment ) { 565 $caps[] = 'do_not_allow'; 566 break; 567 } 568 569 $post = get_post( $comment->comment_post_ID ); 570 571 /* 572 * If the post doesn't exist, we have an orphaned comment. 573 * Fall back to the edit_posts capability, instead. 574 */ 575 if ( $post ) { 576 $caps = map_meta_cap( 'edit_post', $user_id, $post->ID ); 577 } else { 578 $caps = map_meta_cap( 'edit_posts', $user_id ); 579 } 580 break; 581 case 'unfiltered_upload': 582 if ( defined( 'ALLOW_UNFILTERED_UPLOADS' ) && ALLOW_UNFILTERED_UPLOADS && ( ! is_multisite() || is_super_admin( $user_id ) ) ) { 583 $caps[] = $cap; 584 } else { 585 $caps[] = 'do_not_allow'; 586 } 587 break; 588 case 'edit_css': 589 case 'unfiltered_html': 590 // Disallow unfiltered_html for all users, even admins and super admins. 591 if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) { 592 $caps[] = 'do_not_allow'; 593 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 594 $caps[] = 'do_not_allow'; 595 } else { 596 $caps[] = 'unfiltered_html'; 597 } 598 break; 599 case 'edit_files': 600 case 'edit_plugins': 601 case 'edit_themes': 602 // Disallow the file editors. 603 if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT ) { 604 $caps[] = 'do_not_allow'; 605 } elseif ( ! wp_is_file_mod_allowed( 'capability_edit_themes' ) ) { 606 $caps[] = 'do_not_allow'; 607 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 608 $caps[] = 'do_not_allow'; 609 } else { 610 $caps[] = $cap; 611 } 612 break; 613 case 'update_plugins': 614 case 'delete_plugins': 615 case 'install_plugins': 616 case 'upload_plugins': 617 case 'update_themes': 618 case 'delete_themes': 619 case 'install_themes': 620 case 'upload_themes': 621 case 'update_core': 622 /* 623 * Disallow anything that creates, deletes, or updates core, plugin, or theme files. 624 * Files in uploads are excepted. 625 */ 626 if ( ! wp_is_file_mod_allowed( 'capability_update_core' ) ) { 627 $caps[] = 'do_not_allow'; 628 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 629 $caps[] = 'do_not_allow'; 630 } elseif ( 'upload_themes' === $cap ) { 631 $caps[] = 'install_themes'; 632 } elseif ( 'upload_plugins' === $cap ) { 633 $caps[] = 'install_plugins'; 634 } else { 635 $caps[] = $cap; 636 } 637 break; 638 case 'install_languages': 639 case 'update_languages': 640 if ( ! wp_is_file_mod_allowed( 'can_install_language_pack' ) ) { 641 $caps[] = 'do_not_allow'; 642 } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) { 643 $caps[] = 'do_not_allow'; 644 } else { 645 $caps[] = 'install_languages'; 646 } 647 break; 648 case 'activate_plugins': 649 case 'deactivate_plugins': 650 case 'activate_plugin': 651 case 'deactivate_plugin': 652 $caps[] = 'activate_plugins'; 653 if ( is_multisite() ) { 654 // update_, install_, and delete_ are handled above with is_super_admin(). 655 $menu_perms = get_site_option( 'menu_items', array() ); 656 if ( empty( $menu_perms['plugins'] ) ) { 657 $caps[] = 'manage_network_plugins'; 658 } 659 } 660 break; 661 case 'resume_plugin': 662 $caps[] = 'resume_plugins'; 663 break; 664 case 'resume_theme': 665 $caps[] = 'resume_themes'; 666 break; 667 case 'delete_user': 668 case 'delete_users': 669 // If multisite only super admins can delete users. 670 if ( is_multisite() && ! is_super_admin( $user_id ) ) { 671 $caps[] = 'do_not_allow'; 672 } else { 673 $caps[] = 'delete_users'; // delete_user maps to delete_users. 674 } 675 break; 676 case 'create_users': 677 if ( ! is_multisite() ) { 678 $caps[] = $cap; 679 } elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) ) { 680 $caps[] = $cap; 681 } else { 682 $caps[] = 'do_not_allow'; 683 } 684 break; 685 case 'manage_links': 686 if ( get_option( 'link_manager_enabled' ) ) { 687 $caps[] = $cap; 688 } else { 689 $caps[] = 'do_not_allow'; 690 } 691 break; 692 case 'customize': 693 $caps[] = 'edit_theme_options'; 694 break; 695 case 'delete_site': 696 if ( is_multisite() ) { 697 $caps[] = 'manage_options'; 698 } else { 699 $caps[] = 'do_not_allow'; 700 } 701 break; 702 case 'edit_term': 703 case 'delete_term': 704 case 'assign_term': 705 if ( ! isset( $args[0] ) ) { 706 /* translators: %s: Capability name. */ 707 $message = __( 'When checking for the %s capability, you must always check it against a specific term.' ); 708 709 _doing_it_wrong( 710 __FUNCTION__, 711 sprintf( $message, '<code>' . $cap . '</code>' ), 712 '6.1.0' 713 ); 714 715 $caps[] = 'do_not_allow'; 716 break; 717 } 718 719 $term_id = (int) $args[0]; 720 $term = get_term( $term_id ); 721 if ( ! $term || is_wp_error( $term ) ) { 722 $caps[] = 'do_not_allow'; 723 break; 724 } 725 726 $tax = get_taxonomy( $term->taxonomy ); 727 if ( ! $tax ) { 728 $caps[] = 'do_not_allow'; 729 break; 730 } 731 732 if ( 'delete_term' === $cap 733 && ( (int) get_option( 'default_' . $term->taxonomy ) === $term->term_id 734 || (int) get_option( 'default_term_' . $term->taxonomy ) === $term->term_id ) 735 ) { 736 $caps[] = 'do_not_allow'; 737 break; 738 } 739 740 $taxo_cap = $cap . 's'; 741 742 $caps = map_meta_cap( $tax->cap->$taxo_cap, $user_id, $term_id ); 743 744 break; 745 case 'manage_post_tags': 746 case 'edit_categories': 747 case 'edit_post_tags': 748 case 'delete_categories': 749 case 'delete_post_tags': 750 $caps[] = 'manage_categories'; 751 break; 752 case 'assign_categories': 753 case 'assign_post_tags': 754 $caps[] = 'edit_posts'; 755 break; 756 case 'create_sites': 757 case 'delete_sites': 758 case 'manage_network': 759 case 'manage_sites': 760 case 'manage_network_users': 761 case 'manage_network_plugins': 762 case 'manage_network_themes': 763 case 'manage_network_options': 764 case 'upgrade_network': 765 $caps[] = $cap; 766 break; 767 case 'setup_network': 768 if ( is_multisite() ) { 769 $caps[] = 'manage_network_options'; 770 } else { 771 $caps[] = 'manage_options'; 772 } 773 break; 774 case 'update_php': 775 if ( is_multisite() && ! is_super_admin( $user_id ) ) { 776 $caps[] = 'do_not_allow'; 777 } else { 778 $caps[] = 'update_core'; 779 } 780 break; 781 case 'update_https': 782 if ( is_multisite() && ! is_super_admin( $user_id ) ) { 783 $caps[] = 'do_not_allow'; 784 } else { 785 $caps[] = 'manage_options'; 786 $caps[] = 'update_core'; 787 } 788 break; 789 case 'export_others_personal_data': 790 case 'erase_others_personal_data': 791 case 'manage_privacy_options': 792 $caps[] = is_multisite() ? 'manage_network' : 'manage_options'; 793 break; 794 case 'create_app_password': 795 case 'list_app_passwords': 796 case 'read_app_password': 797 case 'edit_app_password': 798 case 'delete_app_passwords': 799 case 'delete_app_password': 800 $caps = map_meta_cap( 'edit_user', $user_id, $args[0] ); 801 break; 802 case 'edit_block_binding': 803 $block_editor_context = $args[0]; 804 if ( isset( $block_editor_context->post ) ) { 805 $object_id = $block_editor_context->post->ID; 806 } 807 /* 808 * If the post ID is null, check if the context is the site editor. 809 * Fall back to the edit_theme_options in that case. 810 */ 811 if ( ! isset( $object_id ) ) { 812 if ( ! isset( $block_editor_context->name ) || 'core/edit-site' !== $block_editor_context->name ) { 813 $caps[] = 'do_not_allow'; 814 break; 815 } 816 $caps = map_meta_cap( 'edit_theme_options', $user_id ); 817 break; 818 } 819 820 $object_subtype = get_object_subtype( 'post', (int) $object_id ); 821 if ( empty( $object_subtype ) ) { 822 $caps[] = 'do_not_allow'; 823 break; 824 } 825 $post_type_object = get_post_type_object( $object_subtype ); 826 // Initialize empty array if it doesn't exist. 827 if ( ! isset( $post_type_object->capabilities ) ) { 828 $post_type_object->capabilities = array(); 829 } 830 $post_type_capabilities = get_post_type_capabilities( $post_type_object ); 831 $caps = map_meta_cap( $post_type_capabilities->edit_post, $user_id, $object_id ); 832 break; 833 default: 834 // Handle meta capabilities for custom post types. 835 global $post_type_meta_caps; 836 if ( isset( $post_type_meta_caps[ $cap ] ) ) { 837 return map_meta_cap( $post_type_meta_caps[ $cap ], $user_id, ...$args ); 838 } 839 840 // Block capabilities map to their post equivalent. 841 $block_caps = array( 842 'edit_blocks', 843 'edit_others_blocks', 844 'publish_blocks', 845 'read_private_blocks', 846 'delete_blocks', 847 'delete_private_blocks', 848 'delete_published_blocks', 849 'delete_others_blocks', 850 'edit_private_blocks', 851 'edit_published_blocks', 852 ); 853 if ( in_array( $cap, $block_caps, true ) ) { 854 $cap = str_replace( '_blocks', '_posts', $cap ); 855 } 856 857 // If no meta caps match, return the original cap. 858 $caps[] = $cap; 859 } 860 861 /** 862 * Filters the primitive capabilities required of the given user to satisfy the 863 * capability being checked. 864 * 865 * @since 2.8.0 866 * 867 * @param string[] $caps Primitive capabilities required of the user. 868 * @param string $cap Capability being checked. 869 * @param int $user_id The user ID. 870 * @param array $args Adds context to the capability check, typically 871 * starting with an object ID. 872 */ 873 return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args ); 874 } 875 876 /** 877 * Returns whether the current user has the specified capability. 878 * 879 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 880 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 881 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 882 * 883 * Example usage: 884 * 885 * current_user_can( 'edit_posts' ); 886 * current_user_can( 'edit_post', $post->ID ); 887 * current_user_can( 'edit_post_meta', $post->ID, $meta_key ); 888 * 889 * While checking against particular roles in place of a capability is supported 890 * in part, this practice is discouraged as it may produce unreliable results. 891 * 892 * Note: Will always return true if the current user is a super admin, unless specifically denied. 893 * 894 * @since 2.0.0 895 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter 896 * by adding it to the function signature. 897 * @since 5.8.0 Converted to wrapper for the user_can() function. 898 * 899 * @see WP_User::has_cap() 900 * @see map_meta_cap() 901 * 902 * @param string $capability Capability name. 903 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 904 * @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is 905 * passed, whether the current user has the given meta capability for the given object. 906 */ 907 function current_user_can( $capability, ...$args ) { 908 return user_can( wp_get_current_user(), $capability, ...$args ); 909 } 910 911 /** 912 * Returns whether the current user has the specified capability for a given site. 913 * 914 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 915 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 916 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 917 * 918 * This function replaces the current_user_can_for_blog() function. 919 * 920 * Example usage: 921 * 922 * current_user_can_for_site( $site_id, 'edit_posts' ); 923 * current_user_can_for_site( $site_id, 'edit_post', $post->ID ); 924 * current_user_can_for_site( $site_id, 'edit_post_meta', $post->ID, $meta_key ); 925 * 926 * @since 6.7.0 927 * 928 * @param int $site_id Site ID. 929 * @param string $capability Capability name. 930 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 931 * @return bool Whether the user has the given capability. 932 */ 933 function current_user_can_for_site( $site_id, $capability, ...$args ) { 934 $switched = is_multisite() ? switch_to_blog( $site_id ) : false; 935 936 $can = current_user_can( $capability, ...$args ); 937 938 if ( $switched ) { 939 restore_current_blog(); 940 } 941 942 return $can; 943 } 944 945 /** 946 * Returns whether the author of the supplied post has the specified capability. 947 * 948 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 949 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 950 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 951 * 952 * Example usage: 953 * 954 * author_can( $post, 'edit_posts' ); 955 * author_can( $post, 'edit_post', $post->ID ); 956 * author_can( $post, 'edit_post_meta', $post->ID, $meta_key ); 957 * 958 * @since 2.9.0 959 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter 960 * by adding it to the function signature. 961 * 962 * @param int|WP_Post $post Post ID or post object. 963 * @param string $capability Capability name. 964 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 965 * @return bool Whether the post author has the given capability. 966 */ 967 function author_can( $post, $capability, ...$args ) { 968 $post = get_post( $post ); 969 if ( ! $post ) { 970 return false; 971 } 972 973 $author = get_userdata( $post->post_author ); 974 975 if ( ! $author ) { 976 return false; 977 } 978 979 return $author->has_cap( $capability, ...$args ); 980 } 981 982 /** 983 * Returns whether a particular user has the specified capability. 984 * 985 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 986 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 987 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 988 * 989 * Example usage: 990 * 991 * user_can( $user->ID, 'edit_posts' ); 992 * user_can( $user->ID, 'edit_post', $post->ID ); 993 * user_can( $user->ID, 'edit_post_meta', $post->ID, $meta_key ); 994 * 995 * @since 3.1.0 996 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter 997 * by adding it to the function signature. 998 * 999 * @param int|WP_User $user User ID or object. 1000 * @param string $capability Capability name. 1001 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 1002 * @return bool Whether the user has the given capability. 1003 */ 1004 function user_can( $user, $capability, ...$args ) { 1005 if ( ! is_object( $user ) ) { 1006 $user = get_userdata( $user ); 1007 } 1008 1009 if ( empty( $user ) ) { 1010 // User is logged out, create anonymous user object. 1011 $user = new WP_User( 0 ); 1012 $user->init( new stdClass() ); 1013 } 1014 1015 return $user->has_cap( $capability, ...$args ); 1016 } 1017 1018 /** 1019 * Returns whether a particular user has the specified capability for a given site. 1020 * 1021 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta 1022 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to 1023 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`. 1024 * 1025 * Example usage: 1026 * 1027 * user_can_for_site( $user->ID, $site_id, 'edit_posts' ); 1028 * user_can_for_site( $user->ID, $site_id, 'edit_post', $post->ID ); 1029 * user_can_for_site( $user->ID, $site_id, 'edit_post_meta', $post->ID, $meta_key ); 1030 * 1031 * @since 6.7.0 1032 * 1033 * @param int|WP_User $user User ID or object. 1034 * @param int $site_id Site ID. 1035 * @param string $capability Capability name. 1036 * @param mixed ...$args Optional further parameters, typically starting with an object ID. 1037 * @return bool Whether the user has the given capability. 1038 */ 1039 function user_can_for_site( $user, $site_id, $capability, ...$args ) { 1040 if ( ! is_object( $user ) ) { 1041 $user = get_userdata( $user ); 1042 } 1043 1044 if ( empty( $user ) ) { 1045 // User is logged out, create anonymous user object. 1046 $user = new WP_User( 0 ); 1047 $user->init( new stdClass() ); 1048 } 1049 1050 // Check if the blog ID is valid. 1051 if ( ! is_numeric( $site_id ) || $site_id <= 0 ) { 1052 return false; 1053 } 1054 1055 $switched = is_multisite() ? switch_to_blog( $site_id ) : false; 1056 1057 $can = user_can( $user->ID, $capability, ...$args ); 1058 1059 if ( $switched ) { 1060 restore_current_blog(); 1061 } 1062 1063 return $can; 1064 } 1065 1066 /** 1067 * Retrieves the global WP_Roles instance and instantiates it if necessary. 1068 * 1069 * @since 4.3.0 1070 * 1071 * @global WP_Roles $wp_roles WordPress role management object. 1072 * 1073 * @return WP_Roles WP_Roles global instance if not already instantiated. 1074 */ 1075 function wp_roles() { 1076 global $wp_roles; 1077 1078 if ( ! isset( $wp_roles ) ) { 1079 $wp_roles = new WP_Roles(); 1080 } 1081 return $wp_roles; 1082 } 1083 1084 /** 1085 * Retrieves role object. 1086 * 1087 * @since 2.0.0 1088 * 1089 * @param string $role Role name. 1090 * @return WP_Role|null WP_Role object if found, null if the role does not exist. 1091 */ 1092 function get_role( $role ) { 1093 return wp_roles()->get_role( $role ); 1094 } 1095 1096 /** 1097 * Adds a role, if it does not exist. 1098 * 1099 * @since 2.0.0 1100 * 1101 * @param string $role Role name. 1102 * @param string $display_name Display name for role. 1103 * @param bool[] $capabilities List of capabilities keyed by the capability name, 1104 * e.g. array( 'edit_posts' => true, 'delete_posts' => false ). 1105 * @return WP_Role|void WP_Role object, if the role is added. 1106 */ 1107 function add_role( $role, $display_name, $capabilities = array() ) { 1108 if ( empty( $role ) ) { 1109 return; 1110 } 1111 1112 return wp_roles()->add_role( $role, $display_name, $capabilities ); 1113 } 1114 1115 /** 1116 * Removes a role, if it exists. 1117 * 1118 * @since 2.0.0 1119 * 1120 * @param string $role Role name. 1121 */ 1122 function remove_role( $role ) { 1123 wp_roles()->remove_role( $role ); 1124 } 1125 1126 /** 1127 * Retrieves a list of super admins. 1128 * 1129 * @since 3.0.0 1130 * 1131 * @global array $super_admins 1132 * 1133 * @return string[] List of super admin logins. 1134 */ 1135 function get_super_admins() { 1136 global $super_admins; 1137 1138 if ( isset( $super_admins ) ) { 1139 return $super_admins; 1140 } else { 1141 return get_site_option( 'site_admins', array( 'admin' ) ); 1142 } 1143 } 1144 1145 /** 1146 * Determines whether user is a site admin. 1147 * 1148 * @since 3.0.0 1149 * 1150 * @param int|false $user_id Optional. The ID of a user. Defaults to false, to check the current user. 1151 * @return bool Whether the user is a site admin. 1152 */ 1153 function is_super_admin( $user_id = false ) { 1154 if ( ! $user_id ) { 1155 $user = wp_get_current_user(); 1156 } else { 1157 $user = get_userdata( $user_id ); 1158 } 1159 1160 if ( ! $user || ! $user->exists() ) { 1161 return false; 1162 } 1163 1164 if ( is_multisite() ) { 1165 $super_admins = get_super_admins(); 1166 if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins, true ) ) { 1167 return true; 1168 } 1169 } elseif ( $user->has_cap( 'delete_users' ) ) { 1170 return true; 1171 } 1172 1173 return false; 1174 } 1175 1176 /** 1177 * Grants Super Admin privileges. 1178 * 1179 * @since 3.0.0 1180 * 1181 * @global array $super_admins 1182 * 1183 * @param int $user_id ID of the user to be granted Super Admin privileges. 1184 * @return bool True on success, false on failure. This can fail when the user is 1185 * already a super admin or when the `$super_admins` global is defined. 1186 */ 1187 function grant_super_admin( $user_id ) { 1188 // If global super_admins override is defined, there is nothing to do here. 1189 if ( isset( $GLOBALS['super_admins'] ) || ! is_multisite() ) { 1190 return false; 1191 } 1192 1193 /** 1194 * Fires before the user is granted Super Admin privileges. 1195 * 1196 * @since 3.0.0 1197 * 1198 * @param int $user_id ID of the user that is about to be granted Super Admin privileges. 1199 */ 1200 do_action( 'grant_super_admin', $user_id ); 1201 1202 // Directly fetch site_admins instead of using get_super_admins(). 1203 $super_admins = get_site_option( 'site_admins', array( 'admin' ) ); 1204 1205 $user = get_userdata( $user_id ); 1206 if ( $user && ! in_array( $user->user_login, $super_admins, true ) ) { 1207 $super_admins[] = $user->user_login; 1208 update_site_option( 'site_admins', $super_admins ); 1209 1210 /** 1211 * Fires after the user is granted Super Admin privileges. 1212 * 1213 * @since 3.0.0 1214 * 1215 * @param int $user_id ID of the user that was granted Super Admin privileges. 1216 */ 1217 do_action( 'granted_super_admin', $user_id ); 1218 return true; 1219 } 1220 return false; 1221 } 1222 1223 /** 1224 * Revokes Super Admin privileges. 1225 * 1226 * @since 3.0.0 1227 * 1228 * @global array $super_admins 1229 * 1230 * @param int $user_id ID of the user Super Admin privileges to be revoked from. 1231 * @return bool True on success, false on failure. This can fail when the user's email 1232 * is the network admin email or when the `$super_admins` global is defined. 1233 */ 1234 function revoke_super_admin( $user_id ) { 1235 // If global super_admins override is defined, there is nothing to do here. 1236 if ( isset( $GLOBALS['super_admins'] ) || ! is_multisite() ) { 1237 return false; 1238 } 1239 1240 /** 1241 * Fires before the user's Super Admin privileges are revoked. 1242 * 1243 * @since 3.0.0 1244 * 1245 * @param int $user_id ID of the user Super Admin privileges are being revoked from. 1246 */ 1247 do_action( 'revoke_super_admin', $user_id ); 1248 1249 // Directly fetch site_admins instead of using get_super_admins(). 1250 $super_admins = get_site_option( 'site_admins', array( 'admin' ) ); 1251 1252 $user = get_userdata( $user_id ); 1253 if ( $user && 0 !== strcasecmp( $user->user_email, get_site_option( 'admin_email' ) ) ) { 1254 $key = array_search( $user->user_login, $super_admins, true ); 1255 if ( false !== $key ) { 1256 unset( $super_admins[ $key ] ); 1257 update_site_option( 'site_admins', $super_admins ); 1258 1259 /** 1260 * Fires after the user's Super Admin privileges are revoked. 1261 * 1262 * @since 3.0.0 1263 * 1264 * @param int $user_id ID of the user Super Admin privileges were revoked from. 1265 */ 1266 do_action( 'revoked_super_admin', $user_id ); 1267 return true; 1268 } 1269 } 1270 return false; 1271 } 1272 1273 /** 1274 * Filters the user capabilities to grant the 'install_languages' capability as necessary. 1275 * 1276 * A user must have at least one out of the 'update_core', 'install_plugins', and 1277 * 'install_themes' capabilities to qualify for 'install_languages'. 1278 * 1279 * @since 4.9.0 1280 * 1281 * @param bool[] $allcaps An array of all the user's capabilities. 1282 * @return bool[] Filtered array of the user's capabilities. 1283 */ 1284 function wp_maybe_grant_install_languages_cap( $allcaps ) { 1285 if ( ! empty( $allcaps['update_core'] ) || ! empty( $allcaps['install_plugins'] ) || ! empty( $allcaps['install_themes'] ) ) { 1286 $allcaps['install_languages'] = true; 1287 } 1288 1289 return $allcaps; 1290 } 1291 1292 /** 1293 * Filters the user capabilities to grant the 'resume_plugins' and 'resume_themes' capabilities as necessary. 1294 * 1295 * @since 5.2.0 1296 * 1297 * @param bool[] $allcaps An array of all the user's capabilities. 1298 * @return bool[] Filtered array of the user's capabilities. 1299 */ 1300 function wp_maybe_grant_resume_extensions_caps( $allcaps ) { 1301 // Even in a multisite, regular administrators should be able to resume plugins. 1302 if ( ! empty( $allcaps['activate_plugins'] ) ) { 1303 $allcaps['resume_plugins'] = true; 1304 } 1305 1306 // Even in a multisite, regular administrators should be able to resume themes. 1307 if ( ! empty( $allcaps['switch_themes'] ) ) { 1308 $allcaps['resume_themes'] = true; 1309 } 1310 1311 return $allcaps; 1312 } 1313 1314 /** 1315 * Filters the user capabilities to grant the 'view_site_health_checks' capabilities as necessary. 1316 * 1317 * @since 5.2.2 1318 * 1319 * @param bool[] $allcaps An array of all the user's capabilities. 1320 * @param string[] $caps Required primitive capabilities for the requested capability. 1321 * @param array $args { 1322 * Arguments that accompany the requested capability check. 1323 * 1324 * @type string $0 Requested capability. 1325 * @type int $1 Concerned user ID. 1326 * @type mixed ...$2 Optional second and further parameters, typically object ID. 1327 * } 1328 * @param WP_User $user The user object. 1329 * @return bool[] Filtered array of the user's capabilities. 1330 */ 1331 function wp_maybe_grant_site_health_caps( $allcaps, $caps, $args, $user ) { 1332 if ( ! empty( $allcaps['install_plugins'] ) && ( ! is_multisite() || is_super_admin( $user->ID ) ) ) { 1333 $allcaps['view_site_health_checks'] = true; 1334 } 1335 1336 return $allcaps; 1337 } 1338 1339 return; 1340 1341 // Dummy gettext calls to get strings in the catalog. 1342 /* translators: User role for administrators. */ 1343 _x( 'Administrator', 'User role' ); 1344 /* translators: User role for editors. */ 1345 _x( 'Editor', 'User role' ); 1346 /* translators: User role for authors. */ 1347 _x( 'Author', 'User role' ); 1348 /* translators: User role for contributors. */ 1349 _x( 'Contributor', 'User role' ); 1350 /* translators: User role for subscribers. */ 1351 _x( 'Subscriber', 'User role' );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sat Jun 14 08:20:01 2025 | Cross-referenced by PHPXref |