feat: Presets als Stapel, Gruppen-Presets und clear_overrides im Composer
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
fafa140546
commit
be6ca5bee0
@@ -18,6 +18,9 @@ use LIT\MCP\Integrations\Divi\Compose\ValueSanitizer;
|
||||
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
|
||||
use LIT\MCP\Integrations\Divi\Compose\Warnings;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemWriter;
|
||||
use LIT\MCP\Integrations\Divi\Design\PresetAssignment;
|
||||
use LIT\MCP\Integrations\Divi\Design\PresetBook;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
@@ -29,6 +32,11 @@ defined('ABSPATH') || exit;
|
||||
* and ONE ValueCleaner instance are shared by AttrWriter, ShortformWriter and Composer, and the
|
||||
* same AttrWriter serves Composer and the abilities.
|
||||
*
|
||||
* Presets (D7) reach blocks through ONE PresetAssignment per composition: its book is Divi's stored preset
|
||||
* inventory (DesignSystemWriter::presets()), read lazily and at most once – only when a write names a preset or a
|
||||
* warning looks at a block that has one – and Divi's option groups come from DesignSystemWriter::groupsOf().
|
||||
* Without a preset source (null, unit tests) there are no presets.
|
||||
*
|
||||
* forPost() binds the composition to the entry being written (DiviWriter::composition() does it
|
||||
* for the abilities); unbound, VariableRef's default map applies. Not final so abilities can be
|
||||
* tested with a mock.
|
||||
@@ -42,6 +50,7 @@ class DiviComposition
|
||||
private ?ValueCleaner $cleaner = null;
|
||||
private ?AttrWriter $attrWriter = null;
|
||||
private ?Composer $composer = null;
|
||||
private ?PresetAssignment $assignment = null;
|
||||
|
||||
public function __construct(
|
||||
private DiviModules $modules,
|
||||
@@ -49,7 +58,8 @@ class DiviComposition
|
||||
private ValueSanitizer $sanitizer = new WpValueSanitizer(),
|
||||
private MediaResolver $media = new WpMediaResolver(),
|
||||
private DynamicContentMap $dynamicContent = new DynamicContentMap(),
|
||||
private LinkTargets $links = new WpLinkTargets()
|
||||
private LinkTargets $links = new WpLinkTargets(),
|
||||
private ?DesignSystemWriter $presetSource = null
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -64,6 +74,7 @@ class DiviComposition
|
||||
$bound->cleaner = null;
|
||||
$bound->attrWriter = null;
|
||||
$bound->composer = null;
|
||||
$bound->assignment = null;
|
||||
|
||||
return $bound;
|
||||
}
|
||||
@@ -102,6 +113,21 @@ class DiviComposition
|
||||
return $this->attrWriter ??= new AttrWriter($this->modules->catalog(), $this->placeholders(), $this->cleaner());
|
||||
}
|
||||
|
||||
/**
|
||||
* The one PresetAssignment of this composition (D7, rulings R2, R3): the book comes lazily from Divi's stored
|
||||
* presets, ids must pass the choke point unchanged.
|
||||
*
|
||||
* @internal Public for tests; code uses composer() / warnings().
|
||||
*/
|
||||
public function presets(): PresetAssignment
|
||||
{
|
||||
return $this->assignment ??= new PresetAssignment(
|
||||
fn (): PresetBook => PresetBook::fromDivi($this->presetSource?->presets() ?? []),
|
||||
fn (string $module): array => $this->presetSource?->groupsOf($module) ?? [],
|
||||
$this->cleaner()->keepsId(...)
|
||||
);
|
||||
}
|
||||
|
||||
public function composer(): Composer
|
||||
{
|
||||
return $this->composer ??= new Composer(
|
||||
@@ -110,7 +136,7 @@ class DiviComposition
|
||||
new ShortformWriter($this->placeholders(), $this->media, $this->cleaner()),
|
||||
$this->attrWriter(),
|
||||
$this->cleaner(),
|
||||
$this->design->read(),
|
||||
$this->presets(),
|
||||
$this->modules->builderVersion()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ final class DiviInsertAbility extends DiviWriteAbility
|
||||
return 'Fügt Divi-Knoten ein: Module, Zeilen oder ganze Abschnitte in Kurzform (z. B. {"type": "button", '
|
||||
. '"text": "Termin buchen", "url": "/kontakt", "preset": "CTA primär"}) und/oder Vollform ("attrs"). '
|
||||
. 'Position über parent, before oder after (Pfad-IDs aus lit-divi-outline), sonst ans Seitenende. '
|
||||
. 'Platzhalter wie {{color:primary}} statt fester Werte. tree_rev ist Pflicht; alles oder nichts. '
|
||||
. 'Platzhalter wie {{color:primary}} statt fester Werte. Presets: preset = Name/ID oder Liste (Stapel; '
|
||||
. 'das letzte gewinnt bei gleicher Priorität), group_presets = {Gruppe: Preset}, clear_overrides: true '
|
||||
. 'entfernt lokale Werte, die ein Preset überdecken. tree_rev ist Pflicht; alles oder nichts. '
|
||||
. 'Format: lit-guide topic "divi-shortform".';
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,12 @@ final class DiviUpdateAbility extends DiviWriteAbility
|
||||
public function description(): string
|
||||
{
|
||||
return 'Ändert vorhandene Divi-Knoten: changes = Liste von {id, set: {Kurzform-Felder}, attrs: {Attributpfad: '
|
||||
. '{Breakpoint: Wert}}, preset, label}. null entfernt einen Wert. Nicht genannte Einstellungen bleiben '
|
||||
. 'unverändert. Jeder Knoten nur einmal pro Aufruf; denselben Pfad nicht zugleich über set und attrs. '
|
||||
. 'tree_rev aus lit-divi-outline ist Pflicht; alles oder nichts.';
|
||||
. '{Breakpoint: Wert}}, preset, group_presets, clear_overrides, label}. null entfernt einen Wert. '
|
||||
. 'preset = Name/ID oder Liste (Stapel, bis 10; bei gleicher Priorität gewinnt das letzte Preset im '
|
||||
. 'Stapel); group_presets = {Gruppe: Preset}, z. B. {"font-body": "Fließtext"}. Überdecken lokale Werte '
|
||||
. 'ein Preset, meldet die Antwort das; clear_overrides: true entfernt sie (nach set/attrs). Nicht '
|
||||
. 'genannte Einstellungen bleiben unverändert. Jeder Knoten nur einmal pro Aufruf; denselben Pfad nicht '
|
||||
. 'zugleich über set und attrs. tree_rev aus lit-divi-outline ist Pflicht; alles oder nichts.';
|
||||
}
|
||||
|
||||
public function inputSchema(): array
|
||||
@@ -58,7 +61,22 @@ final class DiviUpdateAbility extends DiviWriteAbility
|
||||
'type' => 'object',
|
||||
'description' => 'Vollform: Attributpfad → Breakpoint-Werte.',
|
||||
],
|
||||
'preset' => ['type' => ['string', 'null'], 'description' => 'Preset-Name; null entfernt.'],
|
||||
'preset' => self::presetValue(
|
||||
'Preset-Name oder -ID, Liste (Stapel, 1–10) oder null zum Entfernen. Bei gleicher '
|
||||
. 'Priorität gewinnt das letzte Preset im Stapel.'
|
||||
),
|
||||
'group_presets' => [
|
||||
'type' => 'object',
|
||||
'description' => 'Gruppen-Presets: {Gruppe: Preset-Name | Liste | null}. Gruppe = '
|
||||
. 'Kurzname (font-body), voller Name (divi/font-body) oder Attributpfad; null '
|
||||
. 'entfernt den Eintrag der Gruppe.',
|
||||
'additionalProperties' => self::presetValue(),
|
||||
],
|
||||
'clear_overrides' => [
|
||||
'type' => 'boolean',
|
||||
'description' => 'true entfernt lokale Werte, die Werte der zugewiesenen Presets '
|
||||
. 'überdecken (nach set und attrs).',
|
||||
],
|
||||
'label' => [
|
||||
'type' => ['string', 'null'],
|
||||
'description' => 'Admin-Label im Divi-Builder; null entfernt.',
|
||||
@@ -154,4 +172,21 @@ final class DiviUpdateAbility extends DiviWriteAbility
|
||||
|
||||
return $change;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schema of one preset value: a name or id, a stack of 1–10 of them, or null.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private static function presetValue(string $description = ''): array
|
||||
{
|
||||
$schema = [
|
||||
'type' => ['string', 'array', 'null'],
|
||||
'items' => ['type' => 'string'],
|
||||
'minItems' => 1,
|
||||
'maxItems' => 10,
|
||||
];
|
||||
|
||||
return $description === '' ? $schema : $schema + ['description' => $description];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user