feat: VariableDetachRewrite ersetzt ganze Verweise auf eine Variable durch ihren Wert (V9)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 14:13:33 +02:00
co-authored by Claude Sonnet 5.5
parent 116d866c61
commit 6e9218a2bc
3 changed files with 289 additions and 2 deletions
@@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Integrations\Divi\Design;
use LIT\MCP\Integrations\Divi\BlockTree\Block;
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
defined('ABSPATH') || exit;
/**
* Replaces the references to global variable $id in the attributes of Divi blocks by its value (lit/divi-design-detach
* with variable, ruling V9): every attribute value that is exactly one reference $variable({"type":"content",
* "value":{"name":"<id>",…}})$ becomes the value – for a strings variable with the reference's own before/after
* around it. References embedded in a longer text stay (Divi resolves them inside the text; cutting them out would
* change the text) and are named in notes(). Other references – colors, other variables, dynamic content – stay
* untouched. Pure PHP.
*/
final class VariableDetachRewrite implements NodeRewrite
{
private const EMBEDDED = '%s: Die Variable steht hier eingebettet in einem längeren Text; dieser Verweis bleibt '
. 'stehen – im Divi-Builder ersetzen.';
public function __construct(private string $id, private string $value, private string $variableType)
{
}
/**
* What one whole reference to a variable of $variableType becomes: its value, for strings with the reference's
* before/after settings around it.
*/
public static function replacement(string $reference, string $value, string $variableType): string
{
if ($variableType !== 'strings') {
return $value;
}
$settings = VariableRef::settingsOf($reference);
$before = is_string($settings['before'] ?? null) ? $settings['before'] : '';
$after = is_string($settings['after'] ?? null) ? $settings['after'] : '';
return $before . $value . $after;
}
public function rewrite(Block $block): ?array
{
if (! $block->isDivi()) {
return null;
}
$changed = false;
$attrs = $this->resolved($block->attrs(), $changed);
return $changed && is_array($attrs) ? $attrs : null;
}
public function notes(Block $block, string $nodeId): array
{
return $this->embeds($block->attrs()) ? [sprintf(self::EMBEDDED, $nodeId)] : [];
}
public function concernsInstance(Block $instance): bool
{
return DetachRewrite::mentions($instance, $this->id);
}
/** $value with every whole reference to the variable replaced; $changed tells whether one was. */
private function resolved(mixed $value, bool &$changed): mixed
{
if (is_string($value)) {
if (VariableRef::nameOf($value) !== $this->id) {
return $value;
}
$changed = true;
return self::replacement($value, $this->value, $this->variableType);
}
if (! is_array($value)) {
return $value;
}
foreach ($value as $key => $item) {
$value[$key] = $this->resolved($item, $changed);
}
return $value;
}
/** Whether a string below $value names the variable inside a longer text. */
private function embeds(mixed $value): bool
{
if (is_string($value)) {
return VariableRef::contains($value) && str_contains($value, '"' . $this->id . '"');
}
if (! is_array($value)) {
return false;
}
foreach ($value as $item) {
if ($this->embeds($item)) {
return true;
}
}
return false;
}
}