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": "",
+ "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": "