diff --git a/src/wp-includes/interactivity-api/class-wp-interactivity-api.php b/src/wp-includes/interactivity-api/class-wp-interactivity-api.php index 1763142167211..3ac0a48a93f78 100644 --- a/src/wp-includes/interactivity-api/class-wp-interactivity-api.php +++ b/src/wp-includes/interactivity-api/class-wp-interactivity-api.php @@ -520,7 +520,12 @@ private function _process_directives( string $html ) { array_pop( $tag_stack ); } } else { - if ( 0 !== count( $p->get_attribute_names_with_prefix( 'data-wp-each-child' ) ) ) { + $each_child_attrs = $p->get_attribute_names_with_prefix( 'data-wp-each-child' ); + if ( null === $each_child_attrs ) { + continue; + } + + if ( null !== $each_child_attrs && 0 !== count( $each_child_attrs ) ) { /* * If the tag has a `data-wp-each-child` directive, jump to its closer * tag because those tags have already been processed. diff --git a/tests/phpunit/tests/interactivity-api/wpInteractivityAPIDirectivesProcessor.php b/tests/phpunit/tests/interactivity-api/wpInteractivityAPIDirectivesProcessor.php index d674f5e54ce06..3ef06bb2e62f7 100644 --- a/tests/phpunit/tests/interactivity-api/wpInteractivityAPIDirectivesProcessor.php +++ b/tests/phpunit/tests/interactivity-api/wpInteractivityAPIDirectivesProcessor.php @@ -12,6 +12,34 @@ * @coversDefaultClass WP_Interactivity_API_Directives_Processor */ class Tests_Interactivity_API_WpInteractivityAPIDirectivesProcessor extends WP_UnitTestCase { + + /** + * Regression: _process_directives should not fatal when encountering malformed markup + * (e.g., a stray
) that causes get_attribute_names_with_prefix() to return null. + * + * Before the fix: PHP 8+ threw a TypeError from count(null). + */ + public function test_process_directives_handles_noncountable_each_child_attrs() { + $html = '


x
'; + + $api = new WP_Interactivity_API(); + + $ref = new ReflectionClass( $api ); + $method = $ref->getMethod( '_process_directives' ); + $method->setAccessible( true ); + + // This would throw if there is an error. + $processed = $method->invoke( $api, $html ); + + $this->assertIsString( $processed ); + $this->assertStringContainsString( 'assertStringContainsString( 'data-wp-bind--text', $processed ); + + // Assert content still intact despite the malformed
. + $this->assertStringContainsString( '
', $processed ); + } + + /** * Tests the `get_content_between_balanced_template_tags` method on template * tags.