Make WordPress Core

Changeset 59477


Ignore:
Timestamp:
12/02/2024 08:08:34 AM (3 months ago)
Author:
gziolo
Message:

Interactivity API: Support length property on strings and arrays on the server

The Interactivity API tries to align client and server rendering so that the behavior is the same. Adds missing handling for .length to directives processing on the server on strings and numeric arrays which is inherently supported through JavaScript language on the client.

Props jonsurrell, gziolo, luisherranz.
Fixes #62582.

Location:
trunk
Files:
2 edited

Legend:

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

    r59416 r59477  
    580580        $current       = $store;
    581581        foreach ( $path_segments as $path_segment ) {
     582            /*
     583             * Special case for numeric arrays and strings. Add length
     584             * property mimicking JavaScript behavior.
     585             *
     586             * @since 6.8.0
     587             */
     588            if ( 'length' === $path_segment ) {
     589                if ( is_array( $current ) && array_is_list( $current ) ) {
     590                    $current = count( $current );
     591                    break;
     592                }
     593
     594                if ( is_string( $current ) ) {
     595                    /*
     596                     * Differences in encoding between PHP strings and
     597                     * JavaScript mean that it's complicated to calculate
     598                     * the string length JavaScript would see from PHP.
     599                     * `strlen` is a reasonable approximation.
     600                     *
     601                     * Users that desire a more precise length likely have
     602                     * more precise needs than "bytelength" and should
     603                     * implement their own length calculation in derived
     604                     * state taking into account encoding and their desired
     605                     * output (codepoints, graphemes, bytes, etc.).
     606                     */
     607                    $current = strlen( $current );
     608                    break;
     609                }
     610            }
     611
    582612            if ( ( is_array( $current ) || $current instanceof ArrayAccess ) && isset( $current[ $path_segment ] ) ) {
    583613                $current = $current[ $path_segment ];
  • trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php

    r59398 r59477  
    15421542        $this->assertNull( $element );
    15431543    }
     1544
     1545    /**
     1546     * Verify behavior of .length directive access.
     1547     *
     1548     * @ticket 62582
     1549     *
     1550     * @covers ::process_directives
     1551     *
     1552     * @dataProvider data_length_directives
     1553     *
     1554     * @param mixed $value     The property value.
     1555     * @param string $expected The expected property length as a string,
     1556     *                         or "" if no length is expected.
     1557     */
     1558    public function test_process_directives_string_array_length( $value, string $expected ) {
     1559        $this->interactivity->state(
     1560            'myPlugin',
     1561            array( 'prop' => $value )
     1562        );
     1563        $html           = '<div data-wp-text="myPlugin::state.prop.length"></div>';
     1564        $processed_html = $this->interactivity->process_directives( $html );
     1565        $processor      = new WP_HTML_Tag_Processor( $processed_html );
     1566        $processor->next_tag( 'DIV' );
     1567        $processor->next_token();
     1568        $this->assertSame( $expected, $processor->get_modifiable_text() );
     1569    }
     1570
     1571    /**
     1572     * Data provider.
     1573     *
     1574     * @return array
     1575     */
     1576    public static function data_length_directives(): array {
     1577        return array(
     1578            'numeric array'     => array( array( 'a', 'b', 'c' ), '3' ),
     1579            'empty array'       => array( array(), '0' ),
     1580            'string'            => array( 'abc', '3' ),
     1581            'empty string'      => array( '', '0' ),
     1582
     1583            // Failure cases resulting in empty string.
     1584            'non-numeric array' => array( array( 'a' => 'a' ), '' ),
     1585            'object'            => array( new stdClass(), '' ),
     1586        );
     1587    }
    15441588}
Note: See TracChangeset for help on using the changeset viewer.