# Divi-Absicherung – Design-Spezifikation - **Datum:** 2026-09-29 - **Status:** Entwurf zur Freigabe - **Autor:** Jan-Niclas Loosen (Loosen-IT), erarbeitet mit Claude - **Einordnung:** eigene Etappe vor Etappe 4 (Designsystem schreiben); Etappe 4 baut darauf auf. ## 1. Ziel und Kontext ### 1.1 Problem Die Divi-Integration hängt an Divi-Interna, nicht an einer zugesicherten Schnittstelle (Divi 5 bietet zum Schreiben keine an). Stand 0.5.0: - 19 Dateien rufen Divi direkt auf (`et_*`-Funktionen, `ET\…`-Klassen, `_et_*`-Meta, Option `et_divi`), auch außerhalb von `Integrations/Divi/` (`MediaUsageFinder`, `PostPresenter`, `ContentSchema`). - Einige Stellen **bilden Divi-Speicherlogik nach** (Theme-Builder-Templateliste/Bedingungen/`_et_enabled` nach `et_theme_builder_api_save()`, Bibliothekseinträge nach `et_pb_submit_layout()`, Builder-Kennzeichen nach `SyncToServerController`). Ändert Divi diese Logik, schreibt das Plugin still falsche Daten. - Welche Divi-Teile genutzt werden, steht an drei Orten (`DiviCompatibility`, `DiviThemeBuilder::FUNCTIONS`, Docblocks mit Zeilennummern aus Divi 5.2.1). `DiviCompatibility` prüft nur Existenz, nicht Verhalten. - Eine Divi-Version wird nicht geprüft. ### 1.2 Ziele (Vorgabe Auftraggeber) 1. **Weniger Aufwand pro Divi-Update.** 2. **Ungetestete Divi-Version → nichts schreiben, klare Antwort.** Lesende Divi-Tools laufen weiter mit Hinweis „Achtung, ungetestet“; schreibende Divi-Tools sind gesperrt und sagen warum. 3. **Freigabe ohne Plugin-Update möglich:** getestete Versionen stehen fest im Code; zusätzlich kann ein Administrator auf einer Website im WP-Admin eine Prüfung laufen lassen und die Version danach freigeben (Eintrag in der Datenbank). Freigeben geht nur nach bestandener Prüfung. 4. **Wartbarkeit:** Divi-Zugriffe an einer Stelle bündeln (bestehender Code wird umgebaut, nicht nur neuer Code). ### 1.3 Erfolgskriterien 1. Außerhalb der fünf Divi-Adapter (§3) gibt es keinen direkten Divi-Zugriff; ein Unit-Test erzwingt das. 2. Jede genutzte Divi-Funktion/-Klasse/-Methode, jeder Post-Typ, jede Taxonomie, jeder Meta-Schlüssel und jede Option steht im Manifest ihres Adapters; nachgebaute Divi-Funktionen haben einen Fingerabdruck. 3. Mit einer nicht freigegebenen Divi-Version schreibt kein Divi-Tool; die Antwort trägt `divi_untested` bzw. `divi_incompatible` und einen deutschen Hinweis. Lesende Divi-Tools liefern ihr Ergebnis mit Hinweis in `warnings`. 4. Die Admin-Prüfung läuft auf einer Live-Website ohne sichtbare Spuren: die Wegwerfseite ist danach in jedem Fall gelöscht. 5. Alle bestehenden Unit-Tests und Smoke-Skripte sind nach dem Umbau unverändert grün (Umbau ohne Verhaltensänderung). 6. Eine neue Divi-Version lokal prüfen ist ein Befehl (`wp lit-mcp divi-check`); bei Rot zeigt `--diff` die geänderten Divi-Funktionen. ### 1.4 Nicht Teil dieser Etappe - Sperren für Pods (nutzt nur die öffentliche Pods-API) oder den MCP-Adapter. - Automatisierter Browsertest des Visual Builders. - Schreiben ins Designsystem (Etappe 4 – dort gleich mit Manifest). ## 2. Begriffe - **Adapter:** Klasse, die als einzige Divi direkt anspricht (§3). - **Manifest:** Beschreibung der Divi-Abhängigkeiten eines Adapters (§4). - **Nachbau (Mirror):** Plugin-Code, der Speicherlogik einer Divi-Funktion wiederholt, statt sie aufzurufen. - **Fingerabdruck:** SHA-256 des normalisierten Quelltexts einer Divi-Funktion/-Methode (§4.2). - **Live-Prüfung:** Abgleich aller Manifeste mit dem installierten Divi (Existenz + Fingerabdrücke), zur Laufzeit, zwischengespeichert (§5.4). - **Admin-Prüfung:** vollständige Prüfung aus dem WP-Admin inkl. Schreibtest (§6). ## 3. Divi-Grenze Nur fünf Adapter greifen auf Divi zu. Vorhandene Klassen werden wo möglich zu Adaptern bzw. in sie hineingezogen, damit der Umbau klein bleibt. | Adapter | Übernimmt (Stand 0.5.0) | |---|---| | **Seiten** | `DiviSaver` (Divi-Teil), `DiviFlags`, CSS-Cache `ET_Core_PageResource`, `WpLinkTargets` (Divi-Teil) | | **Bibliothek** | `DiviLibraryStore`, `LibraryItemSpec`, `NewLibraryEntry`, `DiviRoles`, `LibraryAccess` (Divi-Teil), `GlobalLayout` | | **Theme Builder** | `DiviThemeBuilder`, `Template`, `TemplateConditions` (Divi-Teile) | | **Designsystem** | `DesignSystemReader`, `DesignSystem` (Divi-Teil), Option `et_divi` inkl. `divi_logo` für `MediaUsageFinder` | | **Katalog** | `DiviModules`, `DynamicContentMap`, Divi-Post-Typen/Flags für `PostPresenter` und `ContentSchema` | Die genaue Klassenaufteilung legt der Plan fest; Regel: jede Divi-Berührung liegt in genau einem Adapter, der Rest des Plugins nutzt nur dessen Methoden. Parser, Serializer und `Compose/` bleiben, wo sie sind: sie kennen das Divi-**Format** (Blockmarkup, Attributpfade), rufen aber keine Divi-**Funktionen** auf. Ihr Schutz ist die Katalog- und Formatprüfung (§6.2 Schritte 2–3). **Architekturtest (Unit):** durchsucht `src/`; außerhalb der Adapter-Dateien sind `et_*(`-Aufrufe, `ET\…`- und `ET_…`-Klassen sowie `'_et_…'`/`'et_divi'`-Schlüssel ein Fehler. Innerhalb der Adapter ist jede solche Fundstelle ein Fehler, die nicht im Manifest des Adapters steht. Während des Umbaus gibt es eine Ausnahmeliste für Altbestand; am Ende der Etappe ist sie leer und wird entfernt. ## 4. Manifest ### 4.1 Inhalt Jeder Adapter liefert ein Manifest (festes PHP-Wertobjekt, keine Konfigurationsdatei) mit: - `functions`: Divi-Funktionen, die aufgerufen werden; - `methods`: Klasse + Methode (+ erwartete Mindest-Parameterzahl), z. B. `ET\Builder\Packages\GlobalData\GlobalData::get_global_colors`; - `classes`: Klassen, deren Existenz genügt; - `post_types`, `taxonomies`, `block_types`; - `meta_keys`, `options`: Divi-Schlüssel, die gelesen oder geschrieben werden (dokumentarisch; Architekturtest nutzt sie); - `mirrors`: nachgebaute Divi-Funktionen/-Methoden mit Fingerabdruck und Kurzbeschreibung, was nachgebaut wird; - `sources`: Quellenangaben (Divi-Datei, Funktion) – ersetzt die Zeilennummern in Docblocks. Zeilennummern entfallen. ### 4.2 Fingerabdruck `sha256` über den Quelltext der Funktion bzw. Methode (per `ReflectionFunction`/`ReflectionMethod`: Datei, Start- und Endzeile), normalisiert mit `token_get_all()`: `T_COMMENT`, `T_DOC_COMMENT`, `T_WHITESPACE` entfernt, übrige Tokens aneinandergehängt. Kommentar- und Formatänderungen ändern den Fingerabdruck nicht; Codeänderungen schon. Die Soll-Fingerabdrücke werden mit dem Plugin ausgeliefert (erzeugte Datei im Plugin, z. B. JSON neben den Manifesten). Die normalisierten Soll-Quelltexte liegen nur für die Entwicklung unter `tests/Fixtures/divi/reference/` (per `.gitattributes` nicht im Plugin-Paket) und dienen `--diff` (§7). ### 4.3 `DiviCompatibility` Verliert ihre handgepflegte Liste und prüft alle Manifeste: Existenz von Funktionen/Klassen/Methoden (inkl. Parameterzahl), Post-Typen, Taxonomien, Block-Typen; Fingerabdrücke der Mirrors. Ergebnis: Liste roter Punkte mit Adapter, Divi-Symbol, Fundort in der installierten Version. Die bisherigen Sonderprüfungen (z. B. `divi/global-layout` registriert oder in den Core-Metadaten) werden Manifest-Einträge mit eigener Prüfregel. ## 5. Freigabe und Sperre zur Laufzeit ### 5.1 Divi-Version Aus dem aktiven Theme wie bisher (`EnvironmentProbe`: Template `Divi`, bei Child-Theme Version des Eltern-Themes). ### 5.2 Zustände | Zustand | Bedingung | Schreibende Divi-Tools | Lesende Divi-Tools | |---|---|---|---| | `released` | Version freigegeben (§5.3) **und** Live-Prüfung grün | laufen | laufen | | `untested` | Live-Prüfung grün, Version nicht freigegeben | gesperrt, `divi_untested` | laufen, Hinweis | | `incompatible` | Live-Prüfung rot | gesperrt, `divi_incompatible` | laufen, Hinweis | Die Live-Prüfung zählt immer, auch für Versionen aus der Code-Liste (erkennt z. B. Hotfixes mit gleicher Versionsnummer). Ist Divi nicht aktiv, gibt es wie bisher keine Divi-Tools; der Zustand ist dann ohne Bedeutung. ### 5.3 Quellen der Freigabe Eine Divi-Version ist freigegeben, wenn sie 1. **im Code** steht: feste Liste getesteter Versionen (PHP-Konstante), vom Entwickler gepflegt; **oder** 2. **in der Datenbank der Website** steht: Option `lit_mcp_divi_releases`, Liste von Einträgen `{divi_version, plugin_version, user_id, released_at, report_id}`. Ein Eintrag entsteht nur über die Admin-Prüfung nach grünem Bericht (§6.3) und gilt **nur für die Plugin-Version, mit der geprüft wurde**. Nach einem Plugin-Update muss eine nur per Datenbank freigegebene Divi-Version neu geprüft werden, außer sie steht inzwischen in der Code-Liste. Ein Administrator kann Einträge zurückziehen. Multisite: pro Website (Optionen der jeweiligen Website). ### 5.4 Live-Prüfung und Zwischenspeicher Die Live-Prüfung (Manifeste, §4.3) wird im Transient `lit_mcp_divi_state` zwischengespeichert, Schlüssel aus Divi-Version, Plugin-Version und `filemtime` der Dateien aller Mirrors und Methoden. Weicht der Schlüssel ab oder lief ein Theme-Update (`upgrader_process_complete` für das Divi-Theme), wird neu berechnet. Kosten ohne Cache: Reflection + Tokenisieren von rund zehn Funktionen. ### 5.5 Sperre **Zentral (`AbilityRegistrar`):** Für jedes Tool der Divi-Integration wird vor `execute` der Zustand ermittelt. - Schreibendes Tool (Annotation nicht `readonly`) und Zustand ≠ `released`: sofort `WP_Error` mit Code `divi_untested` bzw. `divi_incompatible`, keine Ausführung, Protokolleintrag als abgelehnter Aufruf. - Lesendes Tool und Zustand ≠ `released`: normale Ausführung, Hinweis in `warnings` des Ergebnisses. Welche Tools „Divi-Tools“ sind, ergibt sich aus der Integrations-Zugehörigkeit (`IntegrationRegistry::groupMap()`); Divi-lastige Tools anderer Integrationen deklarieren sich zusätzlich (Ability-Eigenschaft „nutzt Divi“), ein Unit-Test prüft die Zuordnung. **In den Adaptern:** Jede schreibende Adapter-Methode prüft den Zustand selbst und wirft bei ≠ `released` eine eigene Ausnahme, die auf dieselben Fehlercodes abgebildet wird; bestehendes Rollback greift. Das deckt Wege ab, die Divi-Interna indirekt nutzen (z. B. Content-Update einer Divi-Seite über `DiviSaver`). Generisches Kopieren/Wiederherstellen von Posts (`PostCloner`, Revisionen) berührt keine Divi-Interna und bleibt ungesperrt. **Prüfmodus:** Der Schreibtest der Admin-Prüfung (§6.2 Schritt 4) muss trotz `untested` schreiben. Er setzt dafür eine request-lokale Ausnahme, die ausschließlich für die ID der Wegwerfseite gilt; sie ist nicht von außen setzbar (kein Parameter, keine Option). ### 5.6 Hinweistexte - `divi_untested`: „Achtung: Divi {version} ist auf dieser Website noch nicht für LIT MCP freigegeben. Schreibende Divi-Werkzeuge sind gesperrt, bis ein Administrator unter Einstellungen → LIT MCP → Divi die Prüfung ausführt und die Version freigibt. Es wurde nichts geändert.“ - `divi_incompatible`: „Divi {version} hat Stellen geändert, die LIT MCP nutzt. Schreibende Divi-Werkzeuge sind gesperrt, bis LIT MCP aktualisiert wurde. Es wurde nichts geändert.“ - Lesehinweis (`warnings`): „Achtung: Divi {version} ist für LIT MCP ungetestet (bzw. inkompatibel); Lesen funktioniert, Schreiben ist gesperrt.“ ### 5.7 `lit-site-status` Zeigt für Divi zusätzlich: Zustand, Quelle der Freigabe (`code`/`database` mit Datum und Benutzer), rote Punkte der Live-Prüfung. ## 6. Admin-Prüfung ### 6.1 Oberfläche und Rechte Neuer Reiter **„Divi“** unter Einstellungen → LIT MCP: Zustand, Divi-Version, Quelle der Freigabe, letzter Prüfbericht, Knöpfe „Prüfung starten“, „Divi {version} freigeben“, „Freigabe zurückziehen“. Alle Aktionen: `manage_options`, Nonce, `admin-post`-Aktionen wie die übrigen Reiter (`AdminPostAction`). Eine Sperre (Transient) verhindert zwei gleichzeitige Prüfungen. ### 6.2 Prüfschritte 1. **Manifeste:** Live-Prüfung (§4.3), ohne Cache. 2. **Modulkatalog:** Alle Attributpfade aus `ShortformMap` existieren im Live-Katalog von Divi. Die Logik von `tests/Integration/divi-shortform-check.php` wandert dafür ins Plugin; das Skript nutzt danach die Plugin-Klasse. 3. **Format im Speicher:** Ein mit dem Plugin ausgelieferter Referenzinhalt (Divi-5-Blockmarkup, deckt die Alltagsmodule ab) wird mit dem Plugin-Parser gelesen und serialisiert und muss byte-identisch herauskommen; `parse_blocks()` muss dieselbe Blockstruktur (Namen, Verschachtelung) liefern. 4. **Schreibtest auf Wegwerfseite:** privater Entwurf „[LIT MCP Prüfung] {Datum}“ (Post-Typ `page`); über den normalen Schreibweg (Composer → Serializer → Seiten-Adapter) je ein Exemplar der Alltagsmodule schreiben; prüfen: Inhalt gespeichert wie serialisiert, Builder-Kennzeichen gesetzt, Rendern über Divi ohne PHP-Fehler/Warnung und mit den erwarteten Texten in der Ausgabe. Kein Eintrag im Änderungsprotokoll. Im `finally` immer `wp_delete_post($id, true)` (endgültig, mit Revisionen und Meta); schlägt das fehl, nennt der Bericht die ID zum Löschen von Hand und der Bericht ist rot. Jeder Schritt meldet grün/rot mit Einzelpunkten. Ein Fehler in einem Schritt bricht die übrigen nicht ab (außer Schritt 4 bei rotem Schritt 1: dann kein Schreibtest). ### 6.3 Bericht und Freigabe Der Bericht wird in der Option `lit_mcp_divi_check_report` gespeichert (letzter Bericht; ID, Zeit, Benutzer, Divi-Version, Plugin-Version, Cache-Schlüssel aus §5.4, Ergebnisse). „Freigeben“ ist nur aktiv – und wird serverseitig nur ausgeführt –, wenn der letzte Bericht vollständig grün ist und Divi-Version, Plugin-Version und Cache-Schlüssel zum aktuellen Stand passen. Freigabe und Zurückziehen werden im Änderungsprotokoll vermerkt. Hinweis im Bericht (blockiert nichts): „Optional: eine Divi-Seite im Visual Builder öffnen und speichern.“ ## 7. WP-CLI für die Entwicklung `wp lit-mcp divi-check` (nur registriert, wenn `WP_CLI` definiert ist) führt die Prüfschritte aus §6.2 aus und gibt den Bericht aus; Rückgabecode ≠ 0 bei Rot. Freigaben schreibt der Befehl nicht. - `--diff`: zeigt für jeden roten Mirror den Unterschied zwischen Soll-Quelltext (`tests/Fixtures/divi/reference/`) und installiertem Quelltext, mit Datei und Zeilen in der installierten Version. - `--update-reference`: schreibt Soll-Fingerabdrücke und Referenz-Quelltexte neu – nur, wenn alle übrigen Prüfschritte grün sind. Gedacht nach dem Anpassen eines Nachbaus. Ablauf bei neuer Divi-Version: lokal einspielen → `wp lit-mcp divi-check` → bei Grün Version in die Code-Liste eintragen; bei Rot `--diff`, Nachbau anpassen, `--update-reference`, Smoke-Skripte, Version eintragen → Plugin-Release. ## 8. Daten und Deinstallation Neu: Optionen `lit_mcp_divi_releases`, `lit_mcp_divi_check_report`; Transients `lit_mcp_divi_state`, Prüfsperre. `Uninstaller` und `uninstall.php`-Doku werden ergänzt. ## 9. Fehlerbehandlung - Reflection/Tokenisieren scheitert (Funktion fehlt, Datei nicht lesbar): Punkt rot → `incompatible`, nie Ausnahme nach außen. - Zustand nicht ermittelbar (unerwartete Ausnahme): wie `incompatible` behandeln (Schreiben gesperrt), Protokoll-Fehlereintrag. - Admin-Prüfung bricht ab (Timeout, Fatal im Rendern): Wegwerfseite im `finally` gelöscht; bei Fatal zusätzlich beim nächsten Aufruf des Reiters nach verwaisten „[LIT MCP Prüfung]“-Entwürfen des Plugins suchen (Marker-Meta) und löschen. ## 10. Tests **Unit:** - Zustandsberechnung: alle Kombinationen aus Code-Liste, DB-Eintrag (passende/andere Plugin-Version), Live-Prüfung grün/rot. - Sperre in `AbilityRegistrar`: lesend/schreibend × drei Zustände; Fehlercodes und Texte; `warnings` bei lesenden Tools. - Sperre in Adaptern inkl. Prüfmodus nur für die Wegwerfseiten-ID. - Fingerabdruck: Kommentar/Leerraum ändert nichts, Codeänderung schon. - Architekturtest (§3) und Test „jedes Divi-Tool ist als solches erkannt“. - Freigabe nur bei frischem grünem Bericht (Version, Plugin-Version, Cache-Schlüssel); Rechte und Nonce. - `Uninstaller` entfernt die neuen Optionen/Transients. **Integration gegen echtes Divi (Smoke-Skript):** - Admin-Prüfung komplett grün; Wegwerfseite danach nicht mehr vorhanden (auch keine Revisionen). - Künstlich veränderter Soll-Fingerabdruck → `incompatible`, schreibendes Tool liefert `divi_incompatible`, lesendes Tool liefert Ergebnis + Hinweis. - Version aus Code-Liste entfernt → `untested`; nach Admin-Prüfung + Freigabe → `released`. - `wp lit-mcp divi-check` grün; `--diff` bei verändertem Soll zeigt den Unterschied. **Regression:** alle bestehenden Unit-Tests und Smoke-Skripte unverändert grün. ## 11. Umsetzungsreihenfolge 1. Manifest-Format, Fingerabdruck, Architekturtest mit Ausnahmeliste für Altbestand. 2. Adapter nacheinander umbauen, bis die Ausnahmeliste leer ist; `DiviCompatibility` auf Manifeste umstellen; Docblock-Zeilennummern entfernen. 3. Zustand, Freigabe (Code-Liste, Datenbank), zentrale und Adapter-Sperre, `lit-site-status`. 4. Admin-Reiter „Divi“, Prüfschritte, Wegwerfseite, Bericht, Freigabe. 5. WP-CLI-Befehl mit `--diff` und `--update-reference`. 6. Security-Audit; danach Etappe 4.