Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
211 lines
17 KiB
Markdown
211 lines
17 KiB
Markdown
# 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.
|