Make WordPress Core

Changeset 59131


Ignore:
Timestamp:
09/30/2024 05:05:24 PM (2 years ago)
Author:
czapla
Message:

Interactivity API: Add wp_interactivity_get_element() function.

Introduces the wp_interactivity_get_element() function to the Interactivity API, analogous to the getElement() function in the @wordpress/interactivity JavaScript module. This function allows access to the current element being processed during directive processing.

The function returns an array containing the attributes property, which includes only the originally defined attributes present on the element. Attributes added or modified by directive processing are not included. This is intended for use in derived state properties inside wp_interactivity_state(), similar to how wp_interactivity_get_context() is used.

Example usage:

`php
wp_interactivity_state( 'myPlugin', array(

'buttonText' => function() {

$context = wp_interactivity_get_context();
$element = wp_interactivity_get_element();
return isset( $contextbuttonText )

? $contextbuttonText
: $elementattributesdata-default-button-text;

},

) );
`

Includes unit tests to cover the new functionality.

Props darerodz, swissspidy, cbravobernal, czapla.
Fixes #62136.

Location:
trunk
Files:
3 edited

Legend:

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

    r59130 r59131  
    9797
    9898        /**
     99         * Representation in array format of the element currently being processed.
     100         *
     101         * This is only available during directive processing, otherwise it is `null`.
     102         *
     103         * @since 6.7.0
     104         * @var array<mixed>|null
     105         */
     106        private $current_element = null;
     107        /**
    99108         * Gets and/or sets the initial state of an Interactivity API store for a
    100109         * given namespace.
    … …  
    297306                        ? $context[ $store_namespace ]
    298307                        : array();
     308        }
     309        /**
     310         * Returns an array representation of the current element being processed.
     311         *
     312         * The returned array contains a copy of the element attributes.
     313         *
     314         * @since 6.7.0
     315         *
     316         * @return array|null Current element.
     317         */
     318        public function get_element(): ?array {
     319                if ( null === $this->current_element ) {
     320                        _doing_it_wrong(
     321                                __METHOD__,
     322                                __( 'The element can only be read during directive processing.' ),
     323                                '6.7.0'
     324                        );
     325                }
     326
     327                return $this->current_element;
    299328        }
    300329
    … …  
    448477                                'enter' => ! $p->is_tag_closer(),
    449478                                'exit'  => $p->is_tag_closer() || ! $p->has_and_visits_its_closer_tag(),
     479                        );
     480
     481                        // Get the element attributes to include them in the element representation.
     482                        $element_attrs = array();
     483                        $attr_names    = $p->get_attribute_names_with_prefix( '' ) ?? array();
     484
     485                        foreach ( $attr_names as $name ) {
     486                                $element_attrs[ $name ] = $p->get_attribute( $name );
     487                        }
     488
     489                        // Assign the current element right before running its directive processors.
     490                        $this->current_element = array(
     491                                'attributes' => $element_attrs,
    450492                        );
    451493
    … …  
    471513                                }
    472514                        }
     515
     516                        // Clear the current element.
     517                        $this->current_element = null;
    473518                }
    474519
  • trunk/src/wp-includes/interactivity-api/interactivity-api.php

    r58327 r59131  
    126126        return wp_interactivity()->get_context( $store_namespace );
    127127}
     128
     129/**
     130 * Returns an array representation of the current element being processed.
     131 *
     132 * The function should be used only during directive processing.
     133 *
     134 * @since 6.7.0
     135 *
     136 * @return array|null Current element.
     137 */
     138function wp_interactivity_get_element(): ?array {
     139        return wp_interactivity()->get_element();
     140}
  • trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php

    r59083 r59131  
    13761376                $this->assertSame( 'myItem', $method->invoke( $this->interactivity, '-my-item-' ) );
    13771377        }
     1378
     1379        /**
     1380         * Tests that `wp_interactivity_get_element` returns an array with the
     1381         * current element's attributes.
     1382         *
     1383         * @ticket 62136
     1384         *
     1385         * @covers wp_interactivity_get_element
     1386         * @covers ::process_directives
     1387         */
     1388        public function test_get_element_returns_current_element_representation() {
     1389                /*
     1390                 * The global WP_Interactivity_API instance is momentarily replaced to
     1391                 * make the global function `wp_interactivity_get_element` work as expected.
     1392                 */
     1393                global $wp_interactivity;
     1394                $wp_interactivity_prev = $wp_interactivity;
     1395                $wp_interactivity      = $this->interactivity;
     1396
     1397                $this->interactivity->state(
     1398                        'myPlugin',
     1399                        array(
     1400                                'dataTest' => function () {
     1401                                        $element = wp_interactivity_get_element();
     1402                                        return $element['attributes']['data-test'];
     1403                                },
     1404                        )
     1405                );
     1406
     1407                $html = <<<HTML
     1408                        <section data-wp-interactive="myPlugin">
     1409                                <div class="buttons">
     1410                                        <button
     1411                                                class="button"
     1412                                                data-test="button 1"
     1413                                                data-wp-bind--data-test-value="state.dataTest"
     1414                                        ></button>
     1415                                        <button
     1416                                                class="button"
     1417                                                data-test="button 2"
     1418                                                data-wp-bind--data-test-value="state.dataTest"
     1419                                        ></button>
     1420                                </div>
     1421                        </section>
     1422HTML;
     1423
     1424                $processed_html = $this->interactivity->process_directives( $html );
     1425                $p              = new WP_HTML_Tag_Processor( $processed_html );
     1426                $p->next_tag( 'button' );
     1427                $this->assertSame( 'button 1', $p->get_attribute( 'data-test-value' ) );
     1428                $p->next_tag( 'button' );
     1429                $this->assertSame( 'button 2', $p->get_attribute( 'data-test-value' ) );
     1430
     1431                // Restore the original WP_Interactivity_API instance.
     1432                $wp_interactivity = $wp_interactivity_prev;
     1433        }
     1434
     1435        /**
     1436         * Tests that the attributes returned by `wp_interactivity_get_element` are
     1437         * those originally present before directives are processed.
     1438         *
     1439         * @ticket 62136
     1440         *
     1441         * @covers wp_interactivity_get_element
     1442         * @covers ::process_directives
     1443         */
     1444        public function test_get_element_returns_original_attributes_only() {
     1445                /*
     1446                 * The global WP_Interactivity_API instance is momentarily replaced to
     1447                 * make the global function `wp_interactivity_get_element` work as expected.
     1448                 */
     1449                global $wp_interactivity;
     1450                $wp_interactivity_prev = $wp_interactivity;
     1451                $wp_interactivity      = $this->interactivity;
     1452
     1453                $attributes = null;
     1454
     1455                $this->interactivity->state(
     1456                        'myPlugin',
     1457                        array(
     1458                                'processAttributes' => function () use ( &$attributes ) {
     1459                                        $element = wp_interactivity_get_element();
     1460                                        $attributes = $element['attributes'];
     1461                                        return 'processed';
     1462                                },
     1463                        )
     1464                );
     1465
     1466                $html = <<<HTML
     1467                        <section data-wp-interactive="myPlugin">
     1468                                <div class="buttons">
     1469                                        <button
     1470                                                disabled
     1471                                                class="original"
     1472                                                data-attr="original"
     1473                                                data-wp-bind--data-attr="state.processAttributes"
     1474                                        ></button>
     1475                                </div>
     1476                        </section>
     1477HTML;
     1478
     1479                $processed_html = $this->interactivity->process_directives( $html );
     1480
     1481                $this->assertSame(
     1482                        array(
     1483                                'disabled'                => true,
     1484                                'class'                   => 'original',
     1485                                'data-attr'               => 'original',
     1486                                'data-wp-bind--data-attr' => 'state.processAttributes',
     1487                        ),
     1488                        $attributes
     1489                );
     1490
     1491                $p = new WP_HTML_Tag_Processor( $processed_html );
     1492                $p->next_tag( 'button' );
     1493                $this->assertSame( 'processed', $p->get_attribute( 'data-attr' ) );
     1494
     1495                // Restore the original WP_Interactivity_API instance.
     1496                $wp_interactivity = $wp_interactivity_prev;
     1497        }
     1498
     1499        /**
     1500         * Tests that `wp_interactivity_get_element` should not be called outside of
     1501         * `process_directives` execution.
     1502         *
     1503         * @ticket 62136
     1504         *
     1505         * @covers wp_interactivity_get_element
     1506         * @expectedIncorrectUsage WP_Interactivity_API::get_element
     1507         */
     1508        public function test_get_element_outside_of_directive_processing() {
     1509                $element = $this->interactivity->get_element();
     1510                $this->assertNull( $element );
     1511        }
    13781512}
Note: See TracChangeset for help on using the changeset viewer.