diff --git a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php index df0ce154..8a694a59 100644 --- a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php +++ b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php @@ -4348,6 +4348,10 @@ private function isRuntimeDomTarget(DOMElement $element): bool } foreach ( array_keys($this->runtimeDomSelectors) as $selector ) { + if ( $this->isPresentationalAnimationDataSelector((string) $selector) ) { + continue; + } + if ( $this->elementMatchesRuntimeSelector($element, (string) $selector) ) { return true; } @@ -4496,6 +4500,26 @@ private function shouldPreserveDataAttributeRuntimeTarget(DOMElement $element): foreach ( array_keys($this->runtimeDomSelectors) as $selector ) { if ( str_contains((string) $selector, '[') && $this->elementMatchesRuntimeSelector($element, (string) $selector) ) { + if ( $this->isPresentationalAnimationDataSelector((string) $selector) ) { + continue; + } + + return true; + } + } + + return false; + } + + private function isPresentationalAnimationDataSelector(string $selector): bool + { + if ( ! preg_match('/\[(data-[A-Za-z][A-Za-z0-9_-]*)/', $selector, $match) ) { + return false; + } + + $attribute = strtolower((string) $match[1]); + foreach ( preg_split('/[^a-z0-9]+/', substr($attribute, 5)) ?: array() as $token ) { + if ( in_array($token, array( 'animate', 'animation', 'appear', 'delay', 'fade', 'motion', 'parallax', 'reveal', 'scroll', 'transition' ), true) ) { return true; } } diff --git a/php-transformer/tests/fixtures/parity/html-presentational-data-attributes-native.json b/php-transformer/tests/fixtures/parity/html-presentational-data-attributes-native.json new file mode 100644 index 00000000..9bb4eedd --- /dev/null +++ b/php-transformer/tests/fixtures/parity/html-presentational-data-attributes-native.json @@ -0,0 +1,38 @@ +{ + "schema": "blocks-engine/php-transformer/parity-fixture/v1", + "name": "html-presentational-data-attributes-native", + "description": "Presentation-only animation data attributes such as data-reveal/data-delay do not force editable text and generic groups into core/html runtime preservation when callers provide matching runtime_dom_selectors.", + "source_reference": { + "repo": "php-transformer", + "path": "tests/fixtures/parity/html-presentational-data-attributes-native.json", + "notes": "Generic regression for static marketing sections that use data-* reveal hooks on labels, headings, paragraphs, and wrappers." + }, + "legacy_comparison": { + "skip": true, + "reason": "Covers current PHP transformer generic data-attribute runtime selector behavior; no downstream legacy comparison." + }, + "operation": "html_transformer.transform", + "input": { + "content": "
Feature Label

Built on care
and craft

Readable source copy.

", + "options": { + "runtime_dom_selectors": ["[data-reveal]", "[data-delay]"] + } + }, + "expected_blocks": [ + { "path": "blocks.0", "name": "core/group", "attrs": { "className": "feature-section", "tagName": "section" } }, + { "path": "blocks.0.innerBlocks.0", "name": "core/group", "attrs": { "className": "feature-header" } }, + { "path": "blocks.0.innerBlocks.0.innerBlocks.0", "name": "core/paragraph", "attrs": { "content": "Feature Label" } }, + { "path": "blocks.0.innerBlocks.0.innerBlocks.1", "name": "core/heading", "attrs": { "content": "Built on care
and craft", "level": 2, "className": "feature-heading" } }, + { "path": "blocks.0.innerBlocks.0.innerBlocks.2", "name": "core/paragraph", "attrs": { "content": "Readable source copy.", "className": "feature-sub" } } + ], + "expected_fallbacks": [], + "expect": [ + { "path": "status", "assert": "equals", "value": "success" }, + { "path": "blocks", "assert": "count", "count": 1 }, + { "path": "fallbacks", "assert": "count", "count": 0 }, + { "path": "coverage.0.fallback_count", "assert": "equals", "value": 0 }, + { "path": "serialized_blocks", "assert": "not_contains", "value": "