Make WordPress Core

Changeset 58825


Ignore:
Timestamp:
07/29/2024 11:08:18 AM (4 months ago)
Author:
luisherranz
Message:

Interactivity API: Allow server derived state to appear in non-final position

In some cases, derived state returns an associative array. Directives may wish to continue to access properties of the associative array, when using the syntax state.arrayReturnedByClosure.property. This patch continues evaluating the path after the associative array has been returned by the Closure.

Props jonsurrell, luisherranz.

Fixes #61741.

Location:
trunk
Files:
2 edited

Legend:

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

    r58729 r58825  
    495495     * @since 6.6.0 The function now adds a warning when the namespace is null, falsy, or the directive value is empty.
    496496     * @since 6.6.0 Removed `default_namespace` and `context` arguments.
     497     * @since 6.6.0 Add support for derived state.
    497498     *
    498499     * @param string|true $directive_value The directive attribute value string or `true` when it's a boolean attribute.
     
    531532                return null;
    532533            }
    533         }
    534 
    535         if ( $current instanceof Closure ) {
    536             /*
    537              * This state getter's namespace is added to the stack so that
    538              * `state()` or `get_config()` read that namespace when called
    539              * without specifying one.
    540              */
    541             array_push( $this->namespace_stack, $ns );
    542             try {
    543                 $current = $current();
    544             } catch ( Throwable $e ) {
    545                 _doing_it_wrong(
    546                     __METHOD__,
    547                     sprintf(
    548                         /* translators: 1: Path pointing to an Interactivity API state property, 2: Namespace for an Interactivity API store. */
    549                         __( 'Uncaught error executing a derived state callback with path "%1$s" and namespace "%2$s".' ),
    550                         $path,
    551                         $ns
    552                     ),
    553                     '6.6.0'
    554                 );
    555                 return null;
    556             } finally {
    557                 // Remove the property's namespace from the stack.
    558                 array_pop( $this->namespace_stack );
     534
     535            if ( $current instanceof Closure ) {
     536                /*
     537                 * This state getter's namespace is added to the stack so that
     538                 * `state()` or `get_config()` read that namespace when called
     539                 * without specifying one.
     540                 */
     541                array_push( $this->namespace_stack, $ns );
     542                try {
     543                    $current = $current();
     544                } catch ( Throwable $e ) {
     545                    _doing_it_wrong(
     546                        __METHOD__,
     547                        sprintf(
     548                            /* translators: 1: Path pointing to an Interactivity API state property, 2: Namespace for an Interactivity API store. */
     549                            __( 'Uncaught error executing a derived state callback with path "%1$s" and namespace "%2$s".' ),
     550                            $path,
     551                            $ns
     552                        ),
     553                        '6.6.0'
     554                    );
     555                    return null;
     556                } finally {
     557                    // Remove the property's namespace from the stack.
     558                    array_pop( $this->namespace_stack );
     559                }
    559560            }
    560561        }
  • trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php

    r58729 r58825  
    12981298    }
    12991299
    1300 
    13011300    /**
    13021301     * Tests the `evaluate` method for derived state functions that throw.
     
    13211320        $result = $this->evaluate( 'state.derivedThatThrows' );
    13221321        $this->assertNull( $result );
     1322    }
     1323
     1324    /**
     1325     * Tests the `evaluate` method for derived state intermediate values.
     1326     *
     1327     * @ticket 61741
     1328     *
     1329     * @covers ::evaluate
     1330     */
     1331    public function test_evaluate_derived_state_intermediate() {
     1332        $this->interactivity->state(
     1333            'myPlugin',
     1334            array(
     1335                'derivedState' => function () {
     1336                    return array( 'property' => 'value' );
     1337                },
     1338            )
     1339        );
     1340        $this->set_internal_context_stack();
     1341        $this->set_internal_namespace_stack( 'myPlugin' );
     1342
     1343        $result = $this->evaluate( 'state.derivedState.property' );
     1344        $this->assertSame( 'value', $result );
    13231345    }
    13241346
Note: See TracChangeset for help on using the changeset viewer.