Make WordPress Core

Changeset 59131


Ignore:
Timestamp:
09/30/2024 05:05:24 PM (2 months 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?
: $elementattributes?data-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.