Make WordPress Core


Ignore:
Timestamp:
11/06/2026 08:36:45 AM (12 hours ago)
Author:
gziolo
Message:

Abilities API: Document input preparation for direct permission checks

WP_Ability::check_permissions() does not prepare the input. Callers outside of WP_Ability::execute() must run normalize_input(), validate_input(), and coerce_input() first, or the permission callback may get different input than during execute().

Developed in ​https://github.com/WordPress/wordpress-develop/pull/15514.

Props euvoor, gziolo, zaguiini, jorbin.
See #66482.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/abilities-api.php

    r64685 r65306  
    200200 *
    201201 * The execute callback performs the ability's core functionality. It receives
    202  * the normalized, validated input when an input schema is defined, and no arguments
    203  * otherwise. It returns either a result or `WP_Error` on failure. Exceptions thrown
    204  * by execute or permission callbacks are caught and converted to a `WP_Error`.
     202 * the normalized, validated, and coerced input when an input schema is defined,
     203 * and no arguments otherwise. It returns either a result or `WP_Error` on failure.
     204 * Exceptions thrown by execute or permission callbacks are caught and converted
     205 * to a `WP_Error`.
    205206 *
    206207 *     function my_plugin_analyze_text( string $input ): string|WP_Error {
    … …  
    225226 * with no required capabilities.
    226227 *
    227  * The permission callback determines whether the ability can be executed.
    228  * It receives the same input as the execute callback and must return a
    229  * boolean or `WP_Error`. Common use cases include checking user capabilities,
    230  * validating API keys, or verifying system state. In the example above, every
    231  * execution requires `edit_posts`, and the callback only adds the check that
    232  * depends on the input:
     228 * The permission callback determines whether the ability can be executed and
     229 * must return a boolean or `WP_Error`. When called through `WP_Ability::execute()`,
     230 * it receives the same normalized, validated, and coerced input as the execute
     231 * callback. Common use cases include checking user capabilities, validating API
     232 * keys, or verifying system state. In the example above, every execution requires
     233 * `edit_posts`, and the callback only adds the check that depends on the input:
    233234 *
    234235 *     function my_plugin_can_analyze_text( string $input ): bool|WP_Error {
    … …  
    242243 * ### Execution Lifecycle
    243244 *
    244  * Call `WP_Ability::execute()` to normalize and validate input, check permissions,
    245  * invoke the execute callback, and validate output. It returns the result or a
    246  * `WP_Error` on failure. Custom ability classes can override this behavior.
     245 * Call `WP_Ability::execute()` to normalize, validate, and coerce input, check
     246 * permissions, invoke the execute callback, and validate output. It returns the
     247 * result or a `WP_Error` on failure. Custom ability classes can override this
     248 * behavior.
     249 *
     250 * Integrations that call `WP_Ability::check_permissions()` directly must prepare
     251 * the input first. See `WP_Ability::check_permissions()` for the required steps.
    247252 *
    248253 * Hooks run in this order, and processing stops at the first failure:
    … …  
    252257 *  3. `wp_ability_normalize_input`, `wp_ability_validate_input`, and
    253258 *     `wp_ability_permission_result` filters. The input validation filter runs only
    254  *     when a non-empty input schema is defined.
     259 *     when a non-empty input schema is defined. Input coercion has no filter. It runs
     260 *     between validation and the permission check, only when a non-empty input
     261 *     schema is defined.
    255262 *  4. `wp_before_execute_ability` action.
    256263 *  5. `wp_ability_execute_result` and `wp_ability_validate_output` filters.
Note: See TracChangeset for help on using the changeset viewer.