Make WordPress Core


Ignore:
Timestamp:
05/21/2026 08:31:02 AM (3 months ago)
Author:
gziolo
Message:

Abilities API: Add filters for input and output validation

Introduce the wp_ability_validate_input and wp_ability_validate_output filters so developers can layer custom validation on top of the default JSON
Schema checks, either augmenting an existing WP_Error or rejecting otherwise valid data.

Props priethor, gziolo, westonruter, enej.
Fixes #64311.

File:
1 edited

Legend:

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

    r62397 r62398  
    13861386                $this->assertSame( 'execute_failed', $result->get_error_code(), 'Filter saw the expected WP_Error and passed it through.' );
    13871387        }
     1388
     1389        /**
     1390         * Tests wp_ability_validate_input filter receives all parameters.
     1391         *
     1392         * @ticket 64311
     1393         */
     1394        public function test_validate_input_filter_receives_all_parameters() {
     1395                $captured = array();
     1396
     1397                $args = array_merge(
     1398                        self::$test_ability_properties,
     1399                        array(
     1400                                'input_schema'     => array(
     1401                                        'type'        => 'string',
     1402                                        'description' => 'Test input string.',
     1403                                        'required'    => true,
     1404                                ),
     1405                                'execute_callback' => static function ( string $input ): int {
     1406                                        return strlen( $input );
     1407                                },
     1408                        )
     1409                );
     1410
     1411                add_filter(
     1412                        'wp_ability_validate_input',
     1413                        static function ( $is_valid, $input, $ability_name ) use ( &$captured ) {
     1414                                $captured = array( $is_valid, $input, $ability_name );
     1415                                return $is_valid;
     1416                        },
     1417                        10,
     1418                        3
     1419                );
     1420
     1421                $ability = new WP_Ability( self::$test_ability_name, $args );
     1422                $ability->execute( 'hello' );
     1423
     1424                $this->assertTrue( $captured[0] );
     1425                $this->assertSame( 'hello', $captured[1] );
     1426                $this->assertSame( self::$test_ability_name, $captured[2] );
     1427        }
     1428
     1429        /**
     1430         * Tests wp_ability_validate_input filter can override validation failure.
     1431         *
     1432         * @ticket 64311
     1433         */
     1434        public function test_validate_input_filter_overrides_validation_failure() {
     1435                $args = array_merge(
     1436                        self::$test_ability_properties,
     1437                        array(
     1438                                'input_schema'     => array(
     1439                                        'type'        => 'integer',
     1440                                        'description' => 'Test input integer.',
     1441                                        'required'    => true,
     1442                                ),
     1443                                'output_schema'    => array(
     1444                                        'type'        => 'integer',
     1445                                        'description' => 'Result integer.',
     1446                                        'required'    => true,
     1447                                ),
     1448                                'execute_callback' => static function () {
     1449                                        return 99;
     1450                                },
     1451                        )
     1452                );
     1453
     1454                add_filter(
     1455                        'wp_ability_validate_input',
     1456                        static function ( $is_valid ) {
     1457                                return true;
     1458                        },
     1459                        10,
     1460                        1
     1461                );
     1462
     1463                $ability = new WP_Ability( self::$test_ability_name, $args );
     1464                $result  = $ability->execute( 'invalid' );
     1465
     1466                $this->assertSame( 99, $result );
     1467        }
     1468
     1469        /**
     1470         * Tests wp_ability_validate_input filter receives WP_Error on validation failure.
     1471         *
     1472         * @ticket 64311
     1473         */
     1474        public function test_validate_input_filter_receives_error_on_invalid_input() {
     1475                $error_code = null;
     1476
     1477                $args = array_merge(
     1478                        self::$test_ability_properties,
     1479                        array(
     1480                                'input_schema'     => array(
     1481                                        'type'        => 'integer',
     1482                                        'description' => 'Test input integer.',
     1483                                        'required'    => true,
     1484                                ),
     1485                                'execute_callback' => static function ( int $input ): int {
     1486                                        return $input * 2;
     1487                                },
     1488                        )
     1489                );
     1490
     1491                add_filter(
     1492                        'wp_ability_validate_input',
     1493                        static function ( $is_valid ) use ( &$error_code ) {
     1494                                if ( is_wp_error( $is_valid ) ) {
     1495                                        $error_code = $is_valid->get_error_code();
     1496                                }
     1497                                return $is_valid;
     1498                        },
     1499                        10,
     1500                        1
     1501                );
     1502
     1503                $ability = new WP_Ability( self::$test_ability_name, $args );
     1504                $ability->execute( 'invalid' );
     1505
     1506                $this->assertSame( 'ability_invalid_input', $error_code );
     1507        }
     1508
     1509        /**
     1510         * Tests wp_ability_validate_input filter can replace error with custom error.
     1511         *
     1512         * @ticket 64311
     1513         */
     1514        public function test_validate_input_filter_replaces_error_with_custom() {
     1515                $args = array_merge(
     1516                        self::$test_ability_properties,
     1517                        array(
     1518                                'input_schema'     => array(
     1519                                        'type'        => 'integer',
     1520                                        'description' => 'Test input integer.',
     1521                                        'required'    => true,
     1522                                ),
     1523                                'execute_callback' => static function ( int $input ): int {
     1524                                        return $input * 2;
     1525                                },
     1526                        )
     1527                );
     1528
     1529                add_filter(
     1530                        'wp_ability_validate_input',
     1531                        static function () {
     1532                                return new WP_Error( 'custom_error', 'Custom message.' );
     1533                        },
     1534                        10,
     1535                        1
     1536                );
     1537
     1538                $ability = new WP_Ability( self::$test_ability_name, $args );
     1539                $result  = $ability->execute( 'invalid' );
     1540
     1541                $this->assertInstanceOf( WP_Error::class, $result );
     1542                $this->assertSame( 'custom_error', $result->get_error_code() );
     1543        }
     1544
     1545        /**
     1546         * Tests wp_ability_validate_output filter receives all parameters.
     1547         *
     1548         * @ticket 64311
     1549         */
     1550        public function test_validate_output_filter_receives_all_parameters() {
     1551                $captured = array();
     1552
     1553                $args = array_merge(
     1554                        self::$test_ability_properties,
     1555                        array(
     1556                                'output_schema'    => array(
     1557                                        'type'        => 'integer',
     1558                                        'description' => 'The result integer.',
     1559                                        'required'    => true,
     1560                                ),
     1561                                'execute_callback' => static function (): int {
     1562                                        return 42;
     1563                                },
     1564                        )
     1565                );
     1566
     1567                add_filter(
     1568                        'wp_ability_validate_output',
     1569                        static function ( $is_valid, $output, $ability_name ) use ( &$captured ) {
     1570                                $captured = array( $is_valid, $output, $ability_name );
     1571                                return $is_valid;
     1572                        },
     1573                        10,
     1574                        3
     1575                );
     1576
     1577                $ability = new WP_Ability( self::$test_ability_name, $args );
     1578                $ability->execute();
     1579
     1580                $this->assertTrue( $captured[0] );
     1581                $this->assertSame( 42, $captured[1] );
     1582                $this->assertSame( self::$test_ability_name, $captured[2] );
     1583        }
     1584
     1585        /**
     1586         * Tests wp_ability_validate_output filter can override validation failure.
     1587         *
     1588         * @ticket 64311
     1589         */
     1590        public function test_validate_output_filter_overrides_validation_failure() {
     1591                $args = array_merge(
     1592                        self::$test_ability_properties,
     1593                        array(
     1594                                'output_schema'    => array(
     1595                                        'type'        => 'string',
     1596                                        'description' => 'The result string.',
     1597                                        'required'    => true,
     1598                                ),
     1599                                'execute_callback' => static function (): int {
     1600                                        return 42;
     1601                                },
     1602                        )
     1603                );
     1604
     1605                add_filter(
     1606                        'wp_ability_validate_output',
     1607                        static function () {
     1608                                return true;
     1609                        },
     1610                        10,
     1611                        1
     1612                );
     1613
     1614                $ability = new WP_Ability( self::$test_ability_name, $args );
     1615                $result  = $ability->execute();
     1616
     1617                $this->assertSame( 42, $result );
     1618        }
     1619
     1620        /**
     1621         * Tests wp_ability_validate_output filter receives WP_Error on validation failure.
     1622         *
     1623         * @ticket 64311
     1624         */
     1625        public function test_validate_output_filter_receives_error_on_invalid_output() {
     1626                $error_code = null;
     1627
     1628                $args = array_merge(
     1629                        self::$test_ability_properties,
     1630                        array(
     1631                                'output_schema'    => array(
     1632                                        'type'        => 'string',
     1633                                        'description' => 'The result string.',
     1634                                        'required'    => true,
     1635                                ),
     1636                                'execute_callback' => static function (): int {
     1637                                        return 42;
     1638                                },
     1639                        )
     1640                );
     1641
     1642                add_filter(
     1643                        'wp_ability_validate_output',
     1644                        static function ( $is_valid ) use ( &$error_code ) {
     1645                                if ( is_wp_error( $is_valid ) ) {
     1646                                        $error_code = $is_valid->get_error_code();
     1647                                }
     1648                                return $is_valid;
     1649                        },
     1650                        10,
     1651                        1
     1652                );
     1653
     1654                $ability = new WP_Ability( self::$test_ability_name, $args );
     1655                $ability->execute();
     1656
     1657                $this->assertSame( 'ability_invalid_output', $error_code );
     1658        }
     1659
     1660        /**
     1661         * Tests wp_ability_validate_output filter can replace error with custom error.
     1662         *
     1663         * @ticket 64311
     1664         */
     1665        public function test_validate_output_filter_replaces_error_with_custom() {
     1666                $args = array_merge(
     1667                        self::$test_ability_properties,
     1668                        array(
     1669                                'output_schema'    => array(
     1670                                        'type'        => 'string',
     1671                                        'description' => 'The result string.',
     1672                                        'required'    => true,
     1673                                ),
     1674                                'execute_callback' => static function (): int {
     1675                                        return 42;
     1676                                },
     1677                        )
     1678                );
     1679
     1680                add_filter(
     1681                        'wp_ability_validate_output',
     1682                        static function () {
     1683                                return new WP_Error( 'custom_output_error', 'Custom output message.' );
     1684                        },
     1685                        10,
     1686                        1
     1687                );
     1688
     1689                $ability = new WP_Ability( self::$test_ability_name, $args );
     1690                $result  = $ability->execute();
     1691
     1692                $this->assertInstanceOf( WP_Error::class, $result );
     1693                $this->assertSame( 'custom_output_error', $result->get_error_code() );
     1694        }
    13881695}
Note: See TracChangeset for help on using the changeset viewer.