{"id":125000,"date":"2026-07-29T08:07:53","date_gmt":"2026-07-29T08:07:53","guid":{"rendered":"https:\/\/make.wordpress.org\/core\/?p=125000"},"modified":"2026-07-31T19:34:39","modified_gmt":"2026-07-31T19:34:39","slug":"new-execution-lifecycle-filters-for-the-abilities-api-in-wordpress-7-1","status":"publish","type":"post","link":"https:\/\/make.wordpress.org\/core\/2026\/07\/29\/new-execution-lifecycle-filters-for-the-abilities-api-in-wordpress-7-1\/","title":{"rendered":"New execution lifecycle filters for the Abilities API in WordPress 7.1"},"content":{"rendered":"<p class=\"wp-block-paragraph\">WordPress 7.1 introduces four filters that allow plugins to customise the execution lifecycle of abilities registered with the Abilities <span tabindex='0' class='glossary-item-container'>API<span class='glossary-item-hidden-content'><span class='glossary-item-header'>API<\/span> <span class='glossary-item-description'>An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.<\/span><\/span><\/span>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Abilities API previously provided the <code>wp_before_execute_ability<\/code> and <code>wp_after_execute_ability<\/code> actions. These actions are useful for observing execution, but they cannot change its behaviour.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The new filters allow developers to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Short-circuit ability execution.<\/li>\n\n\n\n<li>Transform normalised input.<\/li>\n\n\n\n<li>Apply additional authorisation rules.<\/li>\n\n\n\n<li>Transform or recover an execution result.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">These changes were introduced in <span tabindex='0' class='glossary-item-container'>Trac<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Trac<\/span> <span class='glossary-item-description'>An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress.<\/span><\/span><\/span> <span tabindex='0' class='glossary-item-container'>ticket<span class='glossary-item-hidden-content'><span class='glossary-item-header'>ticket<\/span> <span class='glossary-item-description'>Created for both bug reports and feature development on the bug tracker.<\/span><\/span><\/span> <a href=\"https:\/\/core.trac.wordpress.org\/ticket\/64989\">#64989<\/a> and changeset <a href=\"https:\/\/core.trac.wordpress.org\/changeset\/62397\">[62397]<\/a>.<\/p>\n\n\n<nav aria-label=\"Table of Contents\" class=\"wp-block-table-of-contents\"><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"#updated-execution-lifecycle\">Updated execution lifecycle<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#short-circuiting-execution-with-wp-pre-execute-ability\">Short-circuiting execution with wp_pre_execute_ability<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"#temporarily-disabling-an-ability\">Temporarily disabling an ability<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#transforming-input-with-wp-ability-normalize-input\">Transforming input with wp_ability_normalize_input<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"#adding-contextual-input\">Adding contextual input<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#filtering-permission-results-with-wp-ability-permission-result\">Filtering permission results with wp_ability_permission_result<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"#applying-an-additional-authorisation-policy\">Applying an additional authorisation policy<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#transforming-results-with-wp-ability-execute-result\">Transforming results with wp_ability_execute_result<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"#removing-internal-response-data\">Removing internal response data<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#recovering-from-selected-execution-failures\">Recovering from selected execution failures<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#new-wp-filter-sentinel-class\">New WP_Filter_Sentinel class<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#backward-compatibility\">Backward compatibility<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"#summary\">Summary<\/a><\/li><\/ol><\/nav>\n\n\n<h2 id=\"updated-execution-lifecycle\" class=\"wp-block-heading\">Updated execution lifecycle<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The filters are applied in the following order:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; highlight: [1,7,13,19]; title: ; notranslate\" title=\"\">\nwp_pre_execute_ability\n        \u2502\n        \u251c\u2500\u2500 short-circuit when an override is returned\n        \u2193\nWP_Ability::normalize_input()\n        \u2193\nwp_ability_normalize_input\n        \u2193\nWP_Ability::validate_input()\n        \u2193\nWP_Ability::check_permissions()\n        \u2193\nwp_ability_permission_result\n        \u2193\nwp_before_execute_ability\n        \u2193\nRegistered execute callback\n        \u2193\nwp_ability_execute_result\n        \u2193\nWP_Ability::validate_output()\n        \u2193\nwp_after_execute_ability\n        \u2193\nReturn result\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Input and output transformations occur before their respective schema-validation steps. Transformed values must therefore continue to satisfy the ability\u2019s registered schemas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The exception is <code>wp_pre_execute_ability<\/code>, which bypasses the rest of the pipeline completely.<\/p>\n\n\n\n<h2 id=\"short-circuiting-execution-with-wp-pre-execute-ability\" class=\"wp-block-heading\">Short-circuiting execution with <code>wp_pre_execute_ability<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>wp_pre_execute_ability<\/code> <span tabindex='0' class='glossary-item-container'>filter<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Filter<\/span> <span class='glossary-item-description'>Filters are one of the two types of Hooks <a href=\"https:\/\/codex.wordpress.org\/Plugin_API\/Hooks\">https:\/\/codex.wordpress.org\/Plugin_API\/Hooks<\/a>. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output.<\/span><\/span><\/span> runs at the beginning of <code>WP_Ability::execute()<\/code>, before input normalization, validation or permission checks.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\n\/**\n * Filters whether to short-circuit ability execution.\n *\n * @param mixed      $pre          Precomputed result. Return it unchanged to\n *                                 continue normal execution.\n * @param string     $ability_name Name of the ability.\n * @param mixed      $input        Raw input passed to execute().\n * @param WP_Ability $ability      Ability instance.\n *\/\napply_filters(\n    'wp_pre_execute_ability',\n    $pre,\n    $ability_name,\n    $input,\n    $ability\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Returning <code>$pre<\/code> unchanged allows execution to continue. Returning any other value short-circuits execution and returns that value directly to the caller.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The filter uses a unique internal sentinel as its default. This means that any <span tabindex='0' class='glossary-item-container'>PHP<span class='glossary-item-hidden-content'><span class='glossary-item-header'>PHP<\/span> <span class='glossary-item-description'>The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher<\/span><\/span><\/span> value\u2014including <code>null<\/code>, <code>false<\/code>, or an object\u2014can be used as a legitimate short-circuit result.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The filter can be used for caching, rate limiting, maintenance mode, approval workflows and test mocking.<\/p>\n\n\n\n<h3 id=\"temporarily-disabling-an-ability\" class=\"wp-block-heading\">Temporarily disabling an ability<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The filter can short-circuit selected abilities during maintenance without running input validation, permission checks, or the registered callback:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_filter(\n    'wp_pre_execute_ability',\n    function ( $pre, $ability_name, $input, $ability ) {\n        if ( 'my-plugin\/sync-catalog' !== $ability_name ) {\n            return $pre;\n        }\n\n        if ( ! get_option( 'my_plugin_maintenance_mode', false ) ) {\n            return $pre;\n        }\n\n        return new WP_Error(\n            'ability_temporarily_unavailable',\n            __( 'This operation is temporarily unavailable due to maintenance.', 'my-plugin' ),\n            array(\n                'status' =&gt; 503,\n            )\n        );\n    },\n    10,\n    4\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Returning <code>$pre<\/code> unchanged continues normal execution. When maintenance mode is enabled, the <code>WP_Error<\/code> is returned immediately, and the remaining ability pipeline is bypassed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because this filter runs before permission checks and validation, it should make only narrow decisions that do not depend on validated input or the current ability authorisation result.<\/p>\n\n\n\n<h2 id=\"transforming-input-with-wp-ability-normalize-input\" class=\"wp-block-heading\">Transforming input with <code>wp_ability_normalize_input<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>wp_ability_normalize_input<\/code> filter runs inside <code>WP_Ability::normalize_input()<\/code>, after the method has applied any defaults declared by the input schema.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\n\/**\n * Filters normalized ability input.\n *\n * @param mixed      $input        Normalized input.\n * @param string     $ability_name Name of the ability.\n * @param WP_Ability $ability      Ability instance.\n *\/\napply_filters(\n    'wp_ability_normalize_input',\n    $input,\n    $ability_name,\n    $ability\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">This filter can be used to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Add defaults that cannot be expressed through <span tabindex='0' class='glossary-item-container'>JSON<span class='glossary-item-hidden-content'><span class='glossary-item-header'>JSON<\/span> <span class='glossary-item-description'>JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.<\/span><\/span><\/span> Schema.<\/li>\n\n\n\n<li>Normalize incoming values.<\/li>\n\n\n\n<li>Enrich an AI prompt.<\/li>\n\n\n\n<li>Inject caller or execution-context metadata.<\/li>\n<\/ul>\n\n\n\n<h3 id=\"adding-contextual-input\" class=\"wp-block-heading\">Adding contextual input<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_filter(\n    'wp_ability_normalize_input',\n    function ( $input, $ability_name, $ability ) {\n        if ( 'my-plugin\/process-content' !== $ability_name ) {\n            return $input;\n        }\n\n        if ( ! is_array( $input ) ) {\n            $input = array();\n        }\n\n        $input['requesting_user_id'] = get_current_user_id();\n        $input['site_url']           = home_url();\n\n        return $input;\n    },\n    10,\n    3\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The transformed input is subsequently checked against the ability\u2019s <code>input_schema<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Returning a <code>WP_Error<\/code> stops execution before input validation, permission checks and the registered callback:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_filter(\n    'wp_ability_normalize_input',\n    function ( $input, $ability_name ) {\n        if ( 'my-plugin\/process-content' !== $ability_name ) {\n            return $input;\n        }\n\n        if ( my_plugin_rate_limit_exceeded() ) {\n            return new WP_Error(\n                'ability_rate_limit_exceeded',\n                __( 'The ability rate limit has been exceeded.', 'my-plugin' ),\n                array( 'status' =&gt; 429 )\n            );\n        }\n\n        return $input;\n    },\n    10,\n    2\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">When execution occurs through the Abilities <span tabindex='0' class='glossary-item-container'>REST API<span class='glossary-item-hidden-content'><span class='glossary-item-header'>REST API<\/span> <span class='glossary-item-description'>The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think \u201cphone app\u201d or \u201cwebsite\u201d) can communicate with the data store (think \u201cdatabase\u201d or \u201cfile system\u201d)\r<a href=\"https:\/\/developer.wordpress.org\/rest-api\/\">https:\/\/developer.wordpress.org\/rest-api\/<\/a><\/span><\/span><\/span>, a <code>WP_Error<\/code> returned during normalization is now propagated by the REST controller. It defaults to <span tabindex='0' class='glossary-item-container'>HTTP<span class='glossary-item-hidden-content'><span class='glossary-item-header'>HTTP<\/span> <span class='glossary-item-description'>HTTP is an acronym for Hyper Text Transfer Protocol. HTTP  is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands.<\/span><\/span><\/span> status 400 unless the error specifies another status, such as 422 or 429.<\/p>\n\n\n\n<h2 id=\"filtering-permission-results-with-wp-ability-permission-result\" class=\"wp-block-heading\">Filtering permission results with <code>wp_ability_permission_result<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>wp_ability_permission_result<\/code> filter runs inside <code>WP_Ability::check_permissions()<\/code>, after the registered <code>permission_callback<\/code> has executed.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\n\/**\n * Filters the result of an ability permission check.\n *\n * @param bool|WP_Error $permission   Result from permission_callback.\n * @param string        $ability_name Name of the ability.\n * @param mixed         $input        Input used for the permission check.\n * @param WP_Ability    $ability      Ability instance.\n *\/\napply_filters(\n    'wp_ability_permission_result',\n    $permission,\n    $ability_name,\n    $input,\n    $ability\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The filter may return:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>true<\/code> to permit execution.<\/li>\n\n\n\n<li><code>false<\/code> to deny execution.<\/li>\n\n\n\n<li>A <code>WP_Error<\/code> to deny execution with a specific error and message.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Any other return value is converted to <code>false<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because the filter is part of <code>check_permissions()<\/code>, it also applies when permission checks are performed independently of <code>execute()<\/code>, including REST API and <span tabindex='0' class='glossary-item-container'>WP-CLI<span class='glossary-item-hidden-content'><span class='glossary-item-header'>WP-CLI<\/span> <span class='glossary-item-description'>WP-CLI is the Command Line Interface for WordPress, used to do administrative and development tasks in a programmatic way. The project page is <a href=\"http:\/\/wp-cli.org\/\">http:\/\/wp-cli.org\/<\/a> <a href=\"https:\/\/make.wordpress.org\/cli\/\">https:\/\/make.wordpress.org\/cli\/<\/a><\/span><\/span><\/span> integrations.<\/p>\n\n\n\n<h3 id=\"applying-an-additional-authorisation-policy\" class=\"wp-block-heading\">Applying an additional authorisation policy<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_filter(\n    'wp_ability_permission_result',\n    function ( $permission, $ability_name, $input, $ability ) {\n        if ( 'my-plugin\/delete-records' !== $ability_name ) {\n            return $permission;\n        }\n\n        \/\/ preserve both false and WP_Error results\n        if ( false === $permission || is_wp_error( $permission ) ) {\n            return $permission;\n        }\n\n        if ( ! current_user_can( 'manage_options' ) ) {\n            return new WP_Error(\n                'ability_additional_permission_required',\n                __( 'This operation requires administrator access.', 'my-plugin' )\n            );\n        }\n\n        return true;\n    },\n    10,\n    4\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Plugins should exercise particular care with this filter because returning <code>true<\/code> can override a denial from the ability\u2019s original <code>permission_callback<\/code>.<\/p>\n\n\n\n<h2 id=\"transforming-results-with-wp-ability-execute-result\" class=\"wp-block-heading\">Transforming results with <code>wp_ability_execute_result<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>wp_ability_execute_result<\/code> filter runs after the ability\u2019s registered execution callback and before output validation.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\n\/**\n * Filters the result returned by an ability execute callback.\n *\n * @param mixed      $result       Result returned by the execute callback,\n *                                 or WP_Error when execution failed.\n * @param string     $ability_name Name of the ability.\n * @param mixed      $input        Normalized input.\n * @param WP_Ability $ability      Ability instance.\n *\/\napply_filters(\n    'wp_ability_execute_result',\n    $result,\n    $ability_name,\n    $input,\n    $ability\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Possible uses include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Formatting a response.<\/li>\n\n\n\n<li>Removing internal metadata.<\/li>\n\n\n\n<li>Applying content-safety filtering.<\/li>\n\n\n\n<li>Enriching a result.<\/li>\n\n\n\n<li>Converting a successful result into an error.<\/li>\n\n\n\n<li>Recovering from an execution error.<\/li>\n<\/ul>\n\n\n\n<h3 id=\"removing-internal-response-data\" class=\"wp-block-heading\">Removing internal response data<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_filter(\n    'wp_ability_execute_result',\n    function ( $result, $ability_name, $input, $ability ) {\n        if (\n            'my-plugin\/get-report' !== $ability_name ||\n            is_wp_error( $result ) ||\n            ! is_array( $result )\n        ) {\n            return $result;\n        }\n\n        unset( $result['internal_debug_data'] );\n\n        return $result;\n    },\n    10,\n    4\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The filtered result is subsequently validated against the ability\u2019s <code>output_schema<\/code>.<\/p>\n\n\n\n<h3 id=\"recovering-from-selected-execution-failures\" class=\"wp-block-heading\">Recovering from selected execution failures<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The filter receives <code>WP_Error<\/code> values produced by the registered callback, so plugins may implement narrowly scoped recovery behaviour:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_filter(\n    'wp_ability_execute_result',\n    function ( $result, $ability_name, $input, $ability ) {\n        if (\n            'my-plugin\/get-remote-data' !== $ability_name ||\n            ! is_wp_error( $result ) ||\n            'remote_service_unavailable' !== $result-&gt;get_error_code()\n        ) {\n            return $result;\n        }\n\n        $fallback = my_plugin_get_fallback_data();\n\n        \/*\n         * The fallback must conform to the ability's registered\n         * output_schema because it will be validated after this filter.\n         *\/\n        return $fallback;\n    },\n    10,\n    4\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Any recovered value must still conform to the registered <code>output_schema<\/code>.<\/p>\n\n\n\n<h2 id=\"new-wp-filter-sentinel-class\" class=\"wp-block-heading\">New <code>WP_Filter_Sentinel<\/code> class<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress 7.1 also introduces <code>WP_Filter_Sentinel<\/code>, a reusable marker class loaded alongside <code>WP_Hook<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span tabindex='0' class='glossary-item-container'>Core<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Core<\/span> <span class='glossary-item-description'>Core is the set of software required to run WordPress. The Core Development Team builds WordPress.<\/span><\/span><\/span> uses a unique sentinel instance as the default value for <code>wp_pre_execute_ability<\/code>. Comparing object identity allows Core to distinguish an unchanged default from every possible user-supplied value, including <code>null<\/code>, <code>false<\/code>, arrays and arbitrary objects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Developers using <code>wp_pre_execute_ability<\/code> do not need to instantiate this class. To continue normal execution, callbacks should simply return the received <code>$pre<\/code> value unchanged.<\/p>\n\n\n\n<h2 id=\"backward-compatibility\" class=\"wp-block-heading\">Backward compatibility<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These changes are additive:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Existing abilities require no changes.<\/li>\n\n\n\n<li>Existing <code>wp_before_execute_ability<\/code> and <code>wp_after_execute_ability<\/code> callbacks continue to work.<\/li>\n\n\n\n<li>Ability callbacks and permission callbacks retain their existing behaviour when none of the new filters is used.<\/li>\n\n\n\n<li>Input and output schemas remain the final validation boundaries for normal execution.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Plugins that already provide their own ability-execution <span tabindex='0' class='glossary-item-container'>hooks<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Hooks<\/span> <span class='glossary-item-description'>In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same.<\/span><\/span><\/span> may wish to evaluate whether some functionality can now use these Core filters. Protocol- or domain-specific hooks can still be layered on top when they need more specialised context.<\/p>\n\n\n\n<h2 id=\"summary\" class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress 7.1 adds the following Abilities API filters:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Filter<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>wp_pre_execute_ability<\/code><\/td><td>Short-circuit the complete execution pipeline<\/td><\/tr><tr><td><code>wp_ability_normalize_input<\/code><\/td><td>Transform normalized input before validation<\/td><\/tr><tr><td><code>wp_ability_permission_result<\/code><\/td><td>Modify or override permission results<\/td><\/tr><tr><td><code>wp_ability_execute_result<\/code><\/td><td>Transform or recover results before output validation<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These filters make the Abilities API more <span tabindex='0' class='glossary-item-container'>extensible<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Extensible<\/span> <span class='glossary-item-description'>This is the ability to add additional functionality to the code. Plugins extend the WordPress core software.<\/span><\/span><\/span> for AI integrations, automation systems, protocol adapters, authorisation layers and other tools that mediate ability execution.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For additional context, see Trac ticket <a href=\"https:\/\/core.trac.wordpress.org\/ticket\/64989\">#64989<\/a> and changeset <a href=\"https:\/\/core.trac.wordpress.org\/changeset\/62397\">[62397]<\/a>.<\/p>\n\n\n\n<p class=\"has-text-align-right wp-block-paragraph\"><em>Props to <a href=\"https:\/\/profiles.wordpress.org\/benjamin_zekavica\/\" class=\"mention\"><span class=\"mentions-prefix\">@<\/span>benjamin_zekavica<\/a> and <a href=\"https:\/\/profiles.wordpress.org\/audrasjb\/\" class=\"mention\"><span class=\"mentions-prefix\">@<\/span>audrasjb<\/a> for peer review.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n<p class=\"o2-appended-tags\"><a href=\"https:\/\/make.wordpress.org\/core\/tag\/abilities-api\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>abilities-api<\/a>, <a href=\"https:\/\/make.wordpress.org\/core\/tag\/7-1\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>7-1<\/a>, <a href=\"https:\/\/make.wordpress.org\/core\/tag\/dev-notes\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>dev-notes<\/a>, <a href=\"https:\/\/make.wordpress.org\/core\/tag\/dev-notes-7-1\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>dev-notes-7-1<\/a><\/p><nav class='o2-post-footer-actions'><ul class='o2-post-footer-action-row'><li class='o2-post-footer-action'><a href=\"https:\/\/login.wordpress.org\/?redirect_to=https%3A%2F%2Fmake.wordpress.org%2Fcore%2F2026%2F07%2F29%2Fnew-execution-lifecycle-filters-for-the-abilities-api-in-wordpress-7-1%2F%23respond&#038;locale=en_US\" title=\"Login to Reply\"  class=\"genericon  genericon-reply\"  data-action=\"login-to-reply\"  data-actionstate=\"default\" >Login to Reply<\/a><\/li><\/ul><div class='o2-post-footer-action-likes'><\/div><ul class='o2-post-footer-action-row'><\/ul><\/nav>","protected":false},"excerpt":{"rendered":"<p>WordPress 7.1 introduces four filters that allow plugins to customise the execution lifecycle of abilities registered with the Abilities API.<\/p>\n","protected":false},"author":7923389,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_seo_schema_type":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1175],"tags":[5778,5885,1443,5894],"class_list":["post-125000","post","type-post","status-publish","format-standard","hentry","category-general","tag-abilities-api","tag-7-1","tag-dev-notes","tag-dev-notes-7-1","mentions-audrasjb","mentions-benjamin_zekavica","author-milana_cap"],"revision_note":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2AvED-ww8","jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/125000","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/users\/7923389"}],"replies":[{"embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/comments?post=125000"}],"version-history":[{"count":26,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/125000\/revisions"}],"predecessor-version":[{"id":125076,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/125000\/revisions\/125076"}],"wp:attachment":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/media?parent=125000"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/categories?post=125000"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/tags?post=125000"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}