Files
WP-LIT-MCP/docs/superpowers/specs/2026-10-16-etappe-4-designsystem-design.md

28 KiB
Raw Permalink Blame History

Etappe 4 – Designsystem schreiben – Design-Spezifikation

  • Datum: 2026-10-16
  • Status: umgesetzt (Etappe 4a–4e, Version 0.7.0)
  • Autor: Jan-Niclas Loosen (Loosen-IT), erarbeitet mit Claude
  • Einordnung: Etappe 4 der Gesamt-Spec (2026-09-25-wp-lit-mcp-design.md §7, §13); baut auf der Divi-Absicherung (2026-09-29-divi-absicherung-design.md) auf. Entscheidungen G1–G12: docs/superpowers/notes/2026-09-28-etappe-4-entscheidungen-entwurf.md. Datenformate: docs/superpowers/notes/2026-09-28-etappe-4-divi-formate.md (Divi 5.2.1).
  • Annahmen sind mit (A…) markiert: Punkte, die im Brainstorming nicht einzeln gefragt wurden; bei der Freigabe der Spec bestätigen oder ändern.

1. Ziel und Kontext

1.1 Problem

Das Plugin liest das Designsystem (lit/divi-design-system: Farben, Variablen, Theme-Schriften/-Größen, Presets mit Name und ID) und kann einem Modul beim Einfügen/Ändern ein Modul-Preset per Name geben ("preset": "<Name>"). Es fehlt:

  • Einstellungen eines Presets lesen; Presets anlegen, ändern, löschen; Gruppen-Presets und Preset-Stapel zuweisen; Presets auf viele Seiten auf einmal ausrollen oder überall entfernen.
  • Globale Farben, Variablen, Design-Theme-Optionen und Schriften schreiben.
  • Eine Wiederherstellung: Divi 5 führt für Farben, Variablen und Presets keine serverseitige Historie (Formate §7.6).
  • Schleifen-Inhalte (loop_*, z. B. Datum oder Kategorien in Karten einer Loop-Spalte) wurden bis 4d immer abgelehnt (Ruling S36), mit irreführender Meldung „nur innerhalb von Divi-Schleifen“ (G12); seit 4e gelten die Regeln aus §9.

1.2 Ziele

  1. Ein Corporate Design lässt sich über die Tools vollständig übernehmen: Farben, Variablen, Schriften, Theme-Optionen, Presets – und auf bestehende Seiten ausrollen.
  2. Jede site-weite Änderung: Probelauf mit Diff und betroffenen Seiten, erst confirm: true schreibt, vorher immer ein Snapshot (G2, G6).
  3. Schreiben nur über Divis eigene Funktionen, abgesichert über Manifest und Freigabe (Divi-Absicherung).
  4. Schleifen-Inhalte in Modulen innerhalb einer Divi-Schleife setzen können (G12).

1.3 Erfolgskriterien

  1. Ein Preset lässt sich lesen (Kurz- und Vollform), anlegen (aus set/attrs oder aus einem Modul), ändern, als Standard setzen und – wenn unbenutzt – löschen; die Frontend-Ausgabe entspricht einem im Builder angelegten Preset (Integrationstest gegen echtes Divi).
  2. Modul- und Gruppen-Presets, auch gestapelt, lassen sich einzelnen Modulen und per Massenzuweisung vielen Seiten zuweisen; Verweise lassen sich überall entfernen.
  3. Farben, Variablen, Design-Theme-Optionen und Schriften lassen sich schreiben; der Builder zeigt sie danach unverändert an.
  4. Jede Änderung eines Bereichs erzeugt vorher einen Snapshot; lit/divi-design-restore stellt ihn mit Probelauf wieder her.
  5. {{…}}/Vollform mit loop_post_date in einem Modul unter einer Spalte mit aktiver Schleife wird gespeichert; ohne Schleifen-Kontext kommt eine verständliche Ablehnung.
  6. Architekturtest (Divi-Grenze) grün; alle bestehenden Tests grün; Security-Audit ohne offene kritische/hohe Punkte.

1.4 Nicht Teil dieser Etappe

  • SEO-Optionen, Logo (divi_logo), Button-Standards (all_buttons_*) (G3, A1).
  • MCP-Prompts und eigener Guide „Corporate Design übernehmen“ (G11) – nur Tools; Tool-Beschreibungen tragen die Reihenfolge.
  • Echtes Löschen von Farben (nur inactive, wie Divi); Löschen hochgeladener Schriften (A2).
  • Loop Builder anlegen (Schleife an einem Container einschalten/konfigurieren) – nur Inhalte innerhalb bestehender Schleifen (A3).
  • Snapshots von Seiteninhalten (dafür WordPress-Revisionen).

2. Begriffe

  • Bereich: colors, variables, presets, theme_options – Einheit für Snapshot, design_rev und Rechte.
  • design_rev: Hash über den gelesenen Rohbestand eines Bereichs; Sperre gegen gleichzeitige Änderungen (wie tree_rev bei Seiten).
  • Änderungs-Pipeline: gemeinsamer Ablauf aller Schreib-Tools des Designsystems (§4).
  • Seiten-Umschreiber: gemeinsamer Baustein, der Verweise in vielen Seiten ändert (§6.6).
  • Fundstellen: Seiten, Bibliothekseinträge und Theme-Builder-Layouts, die ein Preset, eine Farbe oder Variable verwenden.

3. Architektur

Tools (Abilities)                    Pipeline / Domäne (reines PHP)          Adapter (Divi-Grenze)
lit/divi-presets-set ─┐              DesignChange (Rechte→Prüfung→Diff→      Designsystem-Adapter
lit/divi-colors-set  ─┤              confirm→Snapshot→Schreiben→Protokoll)   ├ Reader (vorhanden)
lit/divi-variables-set┤──────────▶   PresetStore / ColorStore / …    ──────▶ └ Writer (neu)
lit/divi-theme-options-*             SnapshotStore                           Katalog-Adapter
lit/divi-design-restore              DesignUsages (Fundstellen)              (Gruppen-Namen, Preset-
lit/divi-presets-assign ─┐           SiteRewrite (Seiten-Umschreiber) ─────▶  Attr-Mapping, Google-Fonts)
lit/divi-design-detach  ─┘                                                    Seiten-Adapter (DiviSaver)
  • Neue Divi-Aufrufe liegen nur im Designsystem-Adapter (Schreiben: GlobalData::set_global_colors, set_global_variables, GlobalPreset::prepare_data, validate_preset_count, save_data, et_update_option, FontsUtility/Divis Upload-Filter) und im Katalog-Adapter (GlobalPreset::get_group_preset_default_attr, get_default_group_name, Conversion::get_preset_attrs_mapping, get_preset_attrs, et_builder_get_google_fonts, Loop-Optionen). Jeder Eintrag steht im Manifest; nachgebaute Logik bekommt einen Fingerabdruck. Divi-Funktionen werden aufgerufen, wo möglich, statt nachgebaut.
  • Domänenklassen (Bestände berechnen, Diff, Prüfregeln, Überdeckungen) sind reines PHP und unit-testbar; sie arbeiten auf den Rohdaten des Adapters.
  • Seitenänderungen laufen über die vorhandenen Bausteine: Parser/TreeEditor/Composer/Serializer und DiviSaver (Revision je Seite, Cache), Rechte und Grenzen wie GlobalUsages/VisibleEdits.
  • Formate stammen aus Divi 5.2.1 (Formate aus 5.2.1/5.14.0 geprüft, 5.15.1 maßgeblich); freigegeben sind 5.2.1, 5.14.0 und 5.15.1. Erster Umsetzungsschritt: Formate und Funktionssignaturen gegen 5.15.1 prüfen und die Formate-Notiz nachführen (Spec §14 Gesamt-Spec: „nur aus Code abgeleitet“).

4. Änderungs-Pipeline (freigegeben)

Jedes Schreib-Tool des Designsystems:

  1. Rechte des Bereichs (§10).
  2. Eingabe prüfen: JSON-Schema, dann fachlich (Namen, IDs, Platzhalter {{color:…}}/{{var:…}}/{{font:…}}, Werte über ValueCleaner/Composer mit denselben Sperren wie bei Modulen: Lottie, Interactions, rohes HTML/CSS ohne unfiltered_html). Fehler gesammelt als validation_failed mit fields.
  3. Neuen Bestand berechnen aus aktuellem Rohbestand (live gelesen) + Änderung.
  4. Probelauf (ohne confirm): diff (je Eintrag vorher/nachher, Eintragsart added|changed|removed|deactivated), affected (Fundstellen über DesignUsages, Regeln wie UsageReport: lesbare Seiten mit Titel, sonst Anzahl; blocked_ids), design_rev. Nichts gespeichert.
  5. Mit confirm: true: design_rev vergleichen (sonst conflict, nichts geschrieben) → Snapshot → Schreiben über Divi → nach dem Schreiben zurücklesen und mit dem erwarteten Bestand vergleichen (fängt stille Fehlschläge wie bei set_global_variables) → Caches → Protokoll.
  6. Antwort: ToolResult mit diff, snapshot_id, log_id, neuem design_rev, warnings.
  7. Fehler beim Schreiben oder Zurücklesen: Snapshot zurückschreiben (Rollback), WriteFailed (rolled_back/partial).

Jedes Tool nimmt mehrere Einträge eines Bereichs je Aufruf (ein Snapshot, ein Diff) (A4). Keine Ausnahme für „harmlose“ Änderungen: auch ein neues, unbenutztes Preset braucht Probelauf + confirm.

5. Snapshots (freigegeben)

  • Speicher: je Bereich eine Option lit_mcp_snapshots_<bereich> (autoload aus), höchstens 20 Einträge (FIFO). Eintrag: id, created (UTC), user_id, ability, log_id, size, data (Rohbestand wie Divi ihn speichert; Farben inkl. der fünf Customizer-Farben aus et_divi).
  • Größe: Snapshot über 2 MB → Änderung abgelehnt (snapshot_too_large), statt ohne Sicherung zu schreiben.
  • lit/divi-design-snapshots (lesen): je Bereich die Liste ohne data, mit cursor/limit.
  • lit/divi-design-restore (snapshot_id): Probelauf = Diff Snapshot ↔ aktueller Stand; mit confirm Snapshot des aktuellen Stands, dann Zurückschreiben über dieselben Divi-Funktionen wie beim Schreiben. Presets: save_data() mit dem Snapshot-Bestand (ohne validate_preset_count, weil das Wiederherstellen Presets entfernen darf); verwaiste Verweise in Seiten meldet der Probelauf als Warnung.
  • Deinstallation entfernt die Snapshot-Optionen.

6. Presets

6.1 Identifikation

  • Modul-Presets über module (button oder divi/button), Gruppen-Presets über group (font-body oder divi/font-body).
  • Ein Preset wird über id oder name angesprochen. Namen sind in Divi nicht eindeutig: Ein mehrdeutiger Name ist ein Fehler mit den passenden IDs (wie Ruling S13a). Neue Presets mit einem schon vergebenen Namen desselben Moduls/derselben Gruppe werden abgelehnt (A5) – strenger als Divi, damit Namen beim Zuweisen eindeutig bleiben.

6.2 Lesen: lit/divi-preset-get

  • Eingabe: module oder group, id oder name.
  • Antwort: id, name, kind, module/group, default (Standard-Preset?), set (Einstellungen in Kurzform, soweit abbildbar), attrs (Vollform, nur was nicht in set steht), verschachtelte group_presets mit Namen, Werte im selben Format wie lit-divi-node-get (Roh-Verweise $variable(…)$; Namen und Platzhalter liefert lit-divi-design-system), usage (Fundstellen wie §4 Schritt 4, gekappt), design_rev.
  • lit-divi-design-system bleibt die Übersicht (Name, ID, Standard).

6.3 Anlegen und ändern: lit/divi-presets-set

items = Liste von Einträgen:

{ "module": "button", "name": "CTA primär",            // oder "group": "font-body"; "id" zum Ändern
  "rename": "CTA Primär",                               // optional, nur beim Ändern
  "set":   { "background_color": "{{color:primary}}", "text_color": "#ffffff" },
  "attrs": { "button.decoration.border.desktop.value.radius": "{{var:Eckenradius}}" },
  "from_node": { "post_id": 12, "id": "s0.r0.c1.m2" },
  "group_presets": { "font": "Button-Schrift" },        // verschachtelte Gruppen-Presets (nur Modul-Presets)
  "make_default": false }
  • Ohne id und ohne gleichnamiges Preset → anlegen; mit id (oder eindeutigem name) → ändern. Ändern mischt: genannte Pfade werden gesetzt, null entfernt einen Pfad/Breakpoint, Nicht-Genanntes bleibt (wie lit-divi-update).
  • set/attrs laufen durch den Composer des Moduls (module) bzw. des Quellmoduls der Gruppe: dieselbe Kurzform, Pfadprüfung, Platzhalter, Bereinigung und Sperren wie bei Modulen. Nur Pfade, die Divis Preset-Attribut-Mapping des Moduls kennt (Conversion::get_preset_attrs_mapping), sind erlaubt; Inhalte (Texte, URLs, Bilder-IDs …) werden abgelehnt (validation_failed mit Pfad).
  • Gruppen-Presets: nur Pfade unterhalb der Gruppe (groupId, z. B. content.decoration.bodyFont); Speicherung mit groupName, groupId, Quell-moduleName wie der Builder (Formate §3).
  • from_node: liest den Knoten (Leserecht auf die Seite), übernimmt alle Attribute, die das Preset-Mapping des Moduls als Preset-Attribute führt; Inhalte nicht. Kombinierbar mit set/attrs (gehen vor). Gruppen: nur die Pfade der Gruppe.
  • styleAttrs/renderAttrs werden serverseitig mit Divis Conversion::get_preset_attrs(…) berechnet, version = installierte Builder-Version, created/updated in Millisekunden, IDs 10 Zeichen [0-9a-z] (Formate §3).
  • make_default: true: wird Standard-Preset des Moduls/der Gruppe; Probelauf nennt alle Seiten mit Modulen dieses Typs ohne eigenes Preset als betroffen.
  • Schreiben: vollständiger Bestand → prepare_data() (Sanitize wie der Controller) → validate_preset_count() → save_data().

6.4 Löschen: lit/divi-presets-delete

  • items = Presets (module/group + id/name).
  • Nur unbenutzte Presets (G5): Fundstellen in Seiten, Bibliothek, Theme Builder und als verschachteltes Gruppen-Preset in anderen Presets. Sonst Fehler in_use mit Fundstellen und dem Hinweis auf lit/divi-design-detach.
  • Ein Standard-Preset wird erst gelöscht, nachdem default auf "" gesetzt ist (im selben Aufruf automatisch, im Diff sichtbar).
  • Schreiben wie §6.3 mit actionType-Semantik DELETE_* (kein preset_count_decreased); Divi-4-Altoption wie der Controller bereinigen (remove_preset_from_legacy_option).

6.5 Zuweisen an einzelne Module (lit-divi-insert, lit-divi-update, lit-content-create)

  • "preset": Name oder Liste von Namen (Stapel, letzter gewinnt wie in Divi); null entfernt. Speicherung modulePreset: [ids].
  • "group_presets": { "<Gruppe>": "<Name>" | ["<Name>", …] | null }, Gruppe als Kurzname (font-body) oder divi/font-body; Zuordnung zum Attributpfad über Divis Gruppenliste des Moduls (get_group_preset_default_attr). Speicherung groupPreset: { "<groupId>": { presetId: [ids], groupName } }.
  • Überdeckungen (G9): Lokale Werte des Moduls auf denselben Pfaden (Pfad + Breakpoint + Zustand) wie das Preset werden gemeldet (warnings: „s0.r0.c1.m2: Hintergrundfarbe, Schriftgröße überdecken ‚CTA primär‘“). clear_overrides: true entfernt genau diese lokalen Werte.
  • lit-divi-outline zeigt Gruppen-Presets mit Namen zusätzlich zu Modul-Presets.

6.6 Seiten-Umschreiber (gemeinsam für §6.7 und §6.8)

  • Findet Fundstellen (DesignUsages: lesbare Seiten, Bibliothekseinträge, Theme-Builder-Layouts; Rechte- und Theme-Builder-Regeln wie GlobalUsages), ändert je Seite den Baum über TreeEditor/Composer und speichert über DiviSaver (Revision je Seite, Cache, Protokoll).
  • Probelauf: je Seite die betroffenen Knoten (Pfad-ID, Modul, Label) und Überdeckungen; blocked_ids für Live-Seiten ohne edit_post; keine Änderung, wenn eine Seite blockiert ist (wie GlobalEdits).
  • Grenze je Aufruf (A6): höchstens 50 Seiten werden mit confirm geschrieben; die Antwort nennt remaining. Beide Operationen sind wiederholbar (Filter treffen bereits geänderte Module nicht mehr), der nächste Aufruf macht weiter. Über GlobalUsages::HARD_CAP Live-Seiten: Ablehnung wie bisher.
  • Seiten mit globalen Modulen: Instanzen werden nicht umgeschrieben, sondern der Bibliothekseintrag (eigene Fundstelle, F7-Regeln); nicht bearbeitbare/gesperrte Knoten (StoredNodeGuard) bleiben unverändert und werden gemeldet.
  • Pro Seite gilt ein frisch gelesener Baum (kein tree_rev nötig); schlägt eine Seite fehl, sind die bereits gespeicherten Seiten gespeichert (Revisionen in der Antwort), die Antwort meldet partial.

6.7 Massenzuweisung: lit/divi-presets-assign

  • Eingabe: module (Pflicht), preset (Name/Liste) und/oder group_presets, Filter: post_ids (optional, sonst alle Fundstellen mit diesem Modultyp), only_without_preset (bool) oder only_with_preset (Name), clear_overrides (bool, G9).
  • Probelauf → confirm wie §6.6.

6.8 Verweise überall entfernen: lit/divi-design-detach

  • Eingabe: preset (module/group + Name/ID) oder variable (Name/ID). Optional post_ids.
  • Preset: entfernt die ID aus modulePreset/groupPreset-Stapeln; Module fallen auf das nächste Preset im Stapel bzw. das Standard-Preset zurück (G5 a). Verschachtelte Verwendung in anderen Presets entfernt der Aufruf im selben Schritt über die Pipeline (Snapshot presets).
  • Variable: ersetzt die Referenz durch ihren aktuellen Wert als festen Wert (A7) – „Verweis entfernen“ ohne Wert würde Inhalte leeren; bei Farben entfällt detach (sie werden nur deaktiviert).
  • Danach ist das Löschen (Presets, §6.4) bzw. das Archivieren (Variablen, §7.2) möglich.

7. Farben und Variablen

7.1 lit/divi-colors-set

  • items: { id?, "label": "Primär", "color": "#5b3a29" | "{{color:Primär}}" + "relative": {hue, saturation, lightness, opacity}, "folder"?, "status": "active"|"inactive" }. id nennt eine vorhandene Farbe (ID, Name, Alias oder Optionsname); ohne id wird neu angelegt. Die fünf Hauptfarben über ihre festen Namen (accent_color …). Unbekannte Felder (z. B. delete) lehnt das Tool ab.
  • Schreiben über set_global_colors($data, true) (mischen), Hauptfarben nur, wenn sie geändert werden (Standardwert-Abweichung Formate §4). Neue IDs gcid- + 10 Zeichen.
  • „Löschen“ = status: inactive; der Probelauf nennt Fundstellen in Seiten, Bibliothek und Theme Builder unter affected; nur Presets und relative Farben, die auf die Farbe bauen, sind warnings (Ruling V8).
  • Zyklen bei relativen Farben (Tiefe max. 10 wie Divi) → validation_failed.

7.2 lit/divi-variables-set

  • items: { id?, "type": "numbers|strings|images|links|fonts", "label", "value", "status": "active"|"archived" }. Echtes Löschen gibt es nicht: Divi 5.15.1 verweigert jeden Bestand, dem eine gespeicherte gvid--ID fehlt (Plan 4c, Ruling V1). id nennt eine vorhandene Variable (ID, Name oder Alias); ohne id wird neu angelegt. Unbekannte Felder (z. B. delete) lehnt das Tool ab.
  • Prüfung je Typ (Zahlen: CSS-Ausdruck ohne ;{}, Links: URL, Bilder: Anhang-ID/URL der Mediathek, Schriften: §8.2, Strings: Text).
  • Schreiben: vollständig lesen, stdClass → Array, allowedActions und Customizer-Schriften entfernen, set_global_variables() (ersetzt), zurücklesen (stiller Fehlschlag bei fehlendem variables_manager).
  • Archivieren geht immer (Divi-Verhalten); der Probelauf nennt Fundstellen in Seiten, Bibliothek und Theme Builder unter affected; nur Presets sind warnings (Ruling V8). lit/divi-design-detach löst die Verweise vorher (§6.8). Ein Restore behält später angelegte Variablen archiviert.

8. Theme-Optionen und Schriften

8.1 lit/divi-theme-options-get / lit/divi-theme-options-update

  • Whitelist (G3 a): Schriften (heading_font, body_font, primary_nav_font, secondary_nav_font, heading_font_weight, body_font_weight), Größen (body_font_size, tablet_…, phone_…, body_header_size, tablet_header_font_size, phone_header_font_size, body_font_height, body_header_height, body_header_spacing, body_header_style), Layout (content_width, gutter_width, section_padding, row_padding).
  • Die fünf Hauptfarben listet get nicht; es verweist für sie nur auf lit/divi-colors-set (eine Quelle, Snapshot colors) (A8).
  • get liefert je Feld Typ, Beschreibung, aktuellen Wert und Divi-Standard; update bereinigt mit Divis Customizer-Sanitize-Callbacks (Katalog-Adapter), schreibt mit et_update_option() und leert die Caches wie der Customizer (remove_static_resources, et_pb_force_regenerate_templates).
  • body_header_style nimmt genau einen Wert (italic, uppercase oder underline); Divis Sanitizer lehnt Kombinationen ab. null setzt einen Schlüssel auf den Divi-Standard zurück (et_delete_option); 'none' und false werden abgelehnt.

8.2 Schriften

  • Schriftnamen werden für Theme-Optionen und Schrift-Variablen geprüft (Preset- und Modul-Schriftattribute folgen in 4e), und zwar gegen Divis Google-Fonts-Liste, hochgeladene Schriften (et_uploaded_fonts) und Web-Safe-Schriften; Unbekanntes → Fehler mit ähnlichen Namen.
  • lit/divi-fonts-upload (G10 b): name, files ({ "woff2": "<URL>", "woff": …, "ttf": …, "otf": … }), weights (all oder Liste), generic_family. Laden mit wp_safe_remote_get (Größenlimit wie Medien, Grenze je Datei 5 MB (A9)), Dateityp über Inhalt prüfen (Magic Bytes), Installation im Prozess über FontsUtility::font_add() mit Temp-Dateien (action: wp_handle_upload_rest, wie Divis KI-Pfad install_to_custom_fonts()); Divi legt Datei und et_uploaded_fonts-Eintrag selbst an, ein Mirror font-install sichert die Aufrufkonvention. Formate: woff2, woff, ttf, otf. Namensregeln wie Divi (Sonderzeichen, Länge, kein Google-/vorhandener Name).
  • Keine Snapshots für Schriften: ein Upload legt nur neu an, überschreibt nie (A2). Probelauf + confirm gelten trotzdem.
  • DSGVO: lokales Laden der Google-Fonts bleibt Theme-Einstellung; Tool-Beschreibung weist auf hochgeladene Schriften als datensparsame Variante hin.

9. Schleifen-Inhalte (G12, umgesetzt in 4e; aus Divi 5.15.1 abgeleitet)

Belege: docs/superpowers/notes/2026-10-19-etappe-4e-recherche-schleifen.md; Audit: …-etappe-4e-security-audit.md.

  • Kontext (X1): Der Schleifen-Kontext eines Knotens ist der des nächsten Vorfahren-oder-selbst, dessen module.advanced.loop.desktop.value.enable genau "on" ist (Tablet-, Phone- und Hover-Varianten zählen nicht, wie bei Divi). queryType wird wie bei Divi mit sanitize_key gelesen; fehlt er (auch null), gilt post_types; terms und users sind Aliase für Term- und Benutzer-Schleifen (L2). Verschachtelte Schleifen: die innerste gilt für alles darunter; für loop_<art>_meta_key_*-Optionen muss die Art jeder eingeschalteten Schleife der Vorfahrenkette passen, weil eine leere innere Schleife ihren Block unverändert an die äußere gibt (Kettenregel, Audit M1).
  • Arten und Optionen (X2): post (post_types, current_page), term (post_taxonomies, terms), user (user_roles, users), menu (menus). Die Art einer Option folgt der Gruppe der Divi-Option, die drei Meta-Schlüssel-Optionen dem Namen; gespeichert wird der Array-Schlüssel (loop_term_name). repeater_<ACF>-Schleifen sind nicht unterstützt: loop_* darin wird abgelehnt (X7e). DynamicContentMap::loopFields($art) liefert die Optionen je Art, DynamicContentRules/VariableRef nehmen einen LoopScope.
  • Typabgleich als Sicherheitsgrenze: Ein loop_*-Wert ist nur erlaubt, wenn die Art des Kontexts zur Art der Option passt; ohne Schleife ist jede loop_*-Option abgelehnt. Grund: Divi liest loop_post_meta_key_* in einer Term-/Benutzer-Schleife als Post-Meta des Objekts mit der Schleifen-ID (und umgekehrt). Die Meta-Schlüssel-Regeln S29/S30 gelten auch für loop_*_meta_key_.
  • Meldungen (X5): ohne Schleife: „Schleifen-Inhalt "%s" braucht eine Divi-Schleife in diesem Modul oder einem übergeordneten Element (Abschnitt, Zeile, Spalte, Gruppe).“; falsche Art: „… passt nicht zur Schleife dieses Elements (Typ: Terme).“ (Typ: Beiträge, Terme, Benutzer, Menü).
  • Kurzform (X4): {{loop:<option>}} (z. B. {{loop:post_date}} → loop_post_date) mit Einstellungen wie {{post:…}} (A10); die Tabelle LOOP in Placeholders ordnet Kurznamen den Optionen zu.
  • lit/divi-dynamic-sources (X6): optional post_id + node (Pfad-ID): zusätzlich die zur Schleife dieses Knotens passenden loop_*-Optionen; ohne Schleife im Kontext ein Hinweis statt einer Liste; Leserecht auf die Seite wie lit-divi-node-get.
  • Insert, Update, Move (X3): Insert prüft im Kontext der Zielposition; schaltet ein Aufruf eine neue Schleife und loop_*-Inhalt zugleich ein, wird fail closed auf den komponierten Blöcken entschieden. Update prüft im Kontext des Knotens (ein Composer je Kontext, neue loop-Attribute desselben Aufrufs zählen) und warnt, wenn der Wechsel der Schleifen-Art unveränderte Kinder mit loop_* betrifft. Move prüft am Ziel und warnt (lehnt nicht ab; A11), wenn loop_*-Inhalte ihre Schleife verlassen oder in eine andere Art kommen. Die Warnung gilt nur für Inhalte, die vorher zur Schleifen-Kette passten (M1). lit-content-create und Theme-Builder-Anlage haben nie einen Schleifen-Kontext.
  • Rechte (Audit L1, Option B): Eine Schleife in module.advanced.loop, die Benutzer (user_roles) ausgibt, verlangt list_users; eine Beitrags-Schleife mit leeren, any- oder attachment-subTypes verlangt read_private_posts; das gilt auch beim Kopieren.
  • Grenzen (X7, dokumentiert): Schleifen schalten über attrs bleibt möglich (A3 verbietet nur ein eigenes Werkzeug); globale Module werden nicht betreten, loop_* in Bibliothekseinträgen wird abgelehnt (die Einfügung globaler Instanzen und das Kopieren mit unfiltered_html prüfen die Art nicht, Audit L3, offen); Schleifen aus Presets erkennt die Baumprüfung nicht (fail closed).
  • Ruling S36 ist abgelöst (X5).

10. Rechte

Bereich / Tool Voraussetzung
Lesen (preset-get, theme-options-get, design-snapshots) wie lit/divi-design-system (edit_posts)
Farben, Presets schreiben, Restore (Farben/Presets/Variablen) edit_theme_options (strenger als Divi, Formate §7.4) + Divi-Rolle use_visual_builder
Variablen zusätzlich variables_manager
Theme-Optionen (schreiben, Restore) edit_theme_options + Divi-Rolle theme_customizer (kein Visual Builder)
Fonts-Upload upload_files + edit_theme_options + Divi-Rolle custom_fonts_management
Massenzuweisung, Detach Recht des Bereichs + edit_post für jede Live-Fundstelle (Regeln P8/P8a), Theme-Builder-Zugriff wie bisher
set mit rohem HTML/CSS, Lottie, Interactions wie bei Modulen (unfiltered_html)

Alle Schreib-Tools sind Divi-Schreib-Tools im Sinne der Divi-Absicherung (gesperrt bei divi_untested/divi_incompatible).

11. Fehler und Antworten

  • Neue Codes: conflict (design_rev; alternativ rev_mismatch mit eigener Meldung, Plan entscheidet nach Bestand), in_use (vorhandener Code, mit Fundstellen), ambiguous_name (mit IDs), snapshot_too_large, snapshot_not_found, font_fetch_failed, font_invalid.
  • Vorhandene: validation_failed (fields), forbidden, confirm_required (Probelauf-Antwort wie bei globalen Modulen und lit/tb-activate: Fehlerobjekt mit diff, affected, design_rev in den Details), divi_untested/divi_incompatible, write_failed (rolled_back/partial).
  • Jede Antwort mit hint bei Fehlern; Probeläufe nennen den nächsten Schritt (confirm: true, remaining).

12. Daten, Deinstallation, Sicherheit

  • Neue Optionen: lit_mcp_snapshots_{colors,variables,presets,theme_options}; Deinstallation entfernt sie. Hochgeladene Schriften bleiben (gehören Divi).
  • Protokoll: je Aufruf ein Eintrag mit Bereich, Anzahl Einträge, snapshot_id, betroffene Seiten-IDs (keine Inhalte).
  • Security-Audit am Ende: Preset-attrs (XSS über Style-/Render-Attribute, unfiltered_html), Font-Upload (SSRF, Dateityp, Pfad), Massen-Schreibrechte, Schleifen-Optionen (Meta-Schlüssel), Snapshot-Restore (Rechte, Größe).

13. Tests

Unit (reines PHP): Bestandsberechnung je Bereich (anlegen/ändern/mischen/löschen/deaktivieren), Diff, design_rev-Konflikt, Snapshot-FIFO und Größenlimit, Restore-Diff; Preset-Pfadfilter (Mapping, Gruppen-Pfade, Inhalte abgelehnt), from_node, Namensregeln, Stapel und Gruppen-Zuweisung, Überdeckungen und clear_overrides; Fundstellen-Erkennung (Modul-/Gruppen-Preset, verschachtelt, Variablen in Seiten/Presets/Farben); Seiten-Umschreiber (Grenze 50, remaining, blockierte Seiten, globale Module, partial); Schleifen-Kontext (selbst, Vorfahre, verschachtelt, falscher Typ, keiner), Meldungen; Rechte-Matrix; Architekturtest.

Integration gegen echtes Divi (Smoke-Skripte, Fixture-Seite 3182): Preset anlegen → Frontend-Klassen und CSS wie beim Builder-Preset; Gruppen-Preset und Stapel zuweisen; Massenzuweisung über zwei Seiten; detach + delete; Farben/Variablen schreiben und im Builder-Lesepfad unverändert; Variablen ohne variables_manager → Fehler statt stiller Erfolg; Theme-Option schreiben; Font-Upload (woff2) und Verwendung in Preset; Snapshot + Restore je Bereich; Loop-Karte mit loop_post_date speichern und rendern.

Regression: alle bestehenden Unit-Tests und Smoke-Skripte grün; lit-divi-design-system-Antwort unverändert bis auf neue Felder.

14. Umsetzungsreihenfolge

  1. Formate und Signaturen gegen Divi 5.15.1 prüfen (Presets, Farben, Variablen, Theme-Optionen, Fonts, Loop-Kontext); Formate-Notiz nachführen; Manifest-Einträge.
  2. Pipeline, design_rev, SnapshotStore, design-snapshots/design-restore (zuerst mit Bereich presets).
  3. Presets: preset-get, presets-set (inkl. from_node, Gruppen, Standard), presets-delete.
  4. Zuweisen an Module: Stapel, group_presets, Überdeckungen/clear_overrides, Outline mit Gruppen-Presets.
  5. Fundstellen (DesignUsages) und Seiten-Umschreiber; presets-assign, design-detach.
  6. Farben, Variablen (inkl. detach für Variablen).
  7. Theme-Optionen, Schriftprüfung, Fonts-Upload.
  8. Schleifen-Inhalte.
  9. Guides (divi-design-system, divi-shortform, workflows) nachführen; Security-Audit; Version.