Make WordPress Core


Ignore:
Timestamp:
04/16/2026 07:22:23 AM (7 weeks ago)
Author:
gziolo
Message:

Abilities API: Catch exceptions thrown by ability callbacks and return WP_Error.

Wraps invoke_callback() in a try/catch so that exceptions thrown by execute or permission callbacks are converted to a WP_Error with the ability_callback_exception code instead of propagating as uncaught throwables.

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

Props priyankagusani, jamesgiroux, jeffpaul, dkotter, adamsilverstein, justlevine, jorbin, pavanpatil1.
Fixes #65058.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/abilities-api/wpAbility.php

    r61130 r62238  
    499499
    500500    /**
     501     * Tests that an exception thrown by the execute callback is converted to a WP_Error
     502     * instead of being propagated as an uncaught throwable.
     503     *
     504     * @ticket 65058
     505     */
     506    public function test_execute_catches_callback_exception() {
     507        $args = array_merge(
     508            self::$test_ability_properties,
     509            array(
     510                'execute_callback' => static function (): int {
     511                    throw new RuntimeException( 'boom' );
     512                },
     513            )
     514        );
     515
     516        $ability = new WP_Ability( self::$test_ability_name, $args );
     517        $result  = $ability->execute();
     518
     519        $this->assertWPError( $result, 'Ability::execute() should return WP_Error when the callback throws.' );
     520        $this->assertSame( 'ability_callback_exception', $result->get_error_code() );
     521        $this->assertStringContainsString( 'boom', $result->get_error_message() );
     522    }
     523
     524    /**
     525     * Tests that an exception thrown by the permission callback is converted to a WP_Error
     526     * instead of being propagated as an uncaught throwable.
     527     *
     528     * @ticket 65058
     529     */
     530    public function test_check_permissions_catches_callback_exception() {
     531        $args = array_merge(
     532            self::$test_ability_properties,
     533            array(
     534                'permission_callback' => static function (): bool {
     535                    throw new RuntimeException( 'permission exploded' );
     536                },
     537            )
     538        );
     539
     540        $ability = new WP_Ability( self::$test_ability_name, $args );
     541        $result  = $ability->check_permissions();
     542
     543        $this->assertWPError( $result, 'Ability::check_permissions() should return WP_Error when the callback throws.' );
     544        $this->assertSame( 'ability_callback_exception', $result->get_error_code() );
     545        $this->assertStringContainsString( 'permission exploded', $result->get_error_message() );
     546    }
     547
     548    /**
    501549     * Tests that before_execute_ability action is fired with correct parameters.
    502550     *
Note: See TracChangeset for help on using the changeset viewer.