Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
165 lines
24 KiB
Markdown
165 lines
24 KiB
Markdown
# Etappe 4 – Designsystem schreiben: Entscheidungen (Entwurf)
|
||
|
||
Stand 2026-09-28, Brainstorming läuft (Weg: architektonisch → Spec → Plan). Branch `etappe-4` (ab main 903246d).
|
||
|
||
## Verstandenes Ziel
|
||
- Corporate Design in einem Rutsch übernehmen: lesen (`lit/divi-design-system`) → Zuordnung vorschlagen → nach Bestätigung schreiben.
|
||
- Schreiben nur über Divis eigene Funktionen; vor jeder Änderung ein Snapshot (Standard 20), Wiederherstellen per Tool.
|
||
- Preset-Sperren wie bei Modulen (Lottie, Interactions, rohes HTML/CSS ohne `unfiltered_html`) – offen aus 3a.
|
||
- Rechte: `edit_theme_options`, für Variablen zusätzlich Divis `variables_manager` (strenger als Divi selbst).
|
||
|
||
## Antworten der Auftraggeberin/des Auftraggebers
|
||
- G1 Echte Designdaten: (b) selbst über Divis Funktionen anlegen → erledigt, Commit 65bd86f, Formate in `2026-09-28-etappe-4-divi-formate.md`, Fixtures in `tests/Fixtures/divi/stage4/`, Seite 3182 „[Fixture] Designsystem“ (Entwurf).
|
||
- G2 Site-weite Änderungen (Presets, Farben, Variablen): (a) wie globale Module – Probelauf zeigt Änderung und betroffene Seiten, erst `confirm: true` schreibt; Snapshot immer.
|
||
- G4 Zuschnitt (2026-10-16): (b) ganz Etappe 4 in einer Spec; Presets lesen (inkl. Einstellungen), anlegen, ändern und zuweisen (Modul- und Gruppen-Presets) sind ausdrücklicher Teil.
|
||
- G3 Theme-Optionen-Umfang (2026-10-16): (a) Design-Optionen ohne SEO (Theme-Schriften/-Größen, Akzent-/Linkfarben, Layout-Breiten). Annahme: Button-Standards (`all_buttons_*`) und Logo (`divi_logo`, ePanel) bleiben draußen.
|
||
- G5 Löschen (2026-10-16): (b) Preset/Variable nur löschen, wenn nirgends verwendet; sonst Fehler mit Fundstellen. Dazu eigene site-weite Funktion „Verweise überall entfernen“ (Seiten, Bibliothek, Theme Builder): (a) nur den Verweis entfernen, Module fallen auf Standard zurück; Probelauf je Seite, `confirm: true`, Revision je Seite, Snapshot vorher.
|
||
- G6 Snapshots (2026-10-16): (a) je Bereich (Farben, Variablen, Presets, Theme-Optionen) getrennt, je 20; Liste per Tool; Wiederherstellen mit Probelauf (Diff) und `confirm: true`, vorher selbst ein Snapshot; Seiteninhalte nicht (WordPress-Revisionen).
|
||
- Farben löschen: nur „inaktiv“ wie Divi (Annahme, nicht widersprochen).
|
||
- G7 Preset-Inhalt (2026-10-16): (a) `set` (Kurzform) + `attrs` (Vollform) wie lit-divi-update, gleiche Prüfung/Sperren/Platzhalter; zusätzlich `from_node` {post_id, id} übernimmt das Design eines Moduls (ohne Texte/Inhalte). Gruppen-Presets analog mit `group`, nur Attribute dieser Gruppe.
|
||
- G8 Zuweisen (2026-10-16): insert/update um Stapel (`preset` als Liste) und `group_presets` {Gruppe: Name|null} erweitern; zusätzlich site-weite Massenzuweisung (a) – gleiches Gerüst wie „Verweise entfernen“ (G5), Filter Modultyp, Seiten, nur ohne Preset / mit bestimmtem bisherigem Preset.
|
||
- G9 Lokale Werte vs. Preset (2026-10-16): (a) Probelauf/Antwort meldet je Modul lokale Werte, die das Preset überdecken; `clear_overrides: true` entfernt genau diese; sonst nur Warnung. Gilt für Einzel- und Massenzuweisung.
|
||
- G10 Schriften (2026-10-16): (b) Google-Fonts aus Divis Liste (Namensprüfung mit Vorschlägen) und eigene Schriftdateien hochladen (Divi „Custom Fonts“, Option `et_uploaded_fonts`). Annahme: Quelle per URL wie lit-media-upload-from-url. Code: `FontsUtility::font_add()` (B5 `VisualBuilder/Fonts/FontsUtility.php:102`) nutzt `wp_handle_upload` (prüft `is_uploaded_file`) → für geladene Dateien eigener Sideload mit Divis Filtern `upload_dir_font`/`check_filetype_and_ext_font` nötig; DSGVO-Lokal-Laden bleibt Theme-Einstellung.
|
||
- G11 Ablauf „Corporate Design übernehmen“ (2026-10-16): (c) kein eigener Ablauf/Prompt, nur Tools; Claude stellt den Ablauf selbst zusammen.
|
||
- G12 Schleifen-Inhalte (2026-10-16): in Etappe 4 aufnehmen. Befund: `DynamicContentRules::fieldsFor()` (`src/Integrations/Divi/Compose/DynamicContentRules.php:117`) lehnt `loop_*` immer ab (Ruling S36, E12) – kein Erkennungsfehler; Meldung „nur innerhalb von Divi-Schleifen“ irreführend. Praxisfall: Datumsformat in Karten (`loop_post_date`), Pills (Kategorien/Tags) in Modulen unter einer Schleifen-Spalte. Ziel: Schleifen-Kontext aus dem nächsten Vorfahren mit `module.advanced.loop.desktop.value.enable` (+ `queryType`) bestimmen und passende `loop_*`-Optionen zulassen (S36 lockern, Sicherheitsblick).
|
||
- Ansatz (2026-10-16): A – ein Tool je Bereich, gemeinsame Änderungs-Pipeline; gemeinsamer Baustein für Seiten-Umschreiben (Zuweisen/Entfernen); `lit/divi-preset-get` zum Lesen.
|
||
- Entwurf Abschnitt 1 (Pipeline + Snapshots) freigegeben (2026-10-16); übrige Abschnitte direkt in die Spec `docs/superpowers/specs/2026-10-16-etappe-4-designsystem-design.md` (Annahmen A1–A11), Freigabe der Spec ausstehend.
|
||
|
||
## Noch zu klären (je eine Frage)
|
||
- (alle Fragen beantwortet)
|
||
|
||
## Danach
|
||
Ansätze vorschlagen → Entwurf abschnittsweise freigeben → Spec schreiben → Plan (writing-plans) → Umsetzung subagent-driven mit Reviews, Security-Audit am Ende.
|
||
|
||
## Umsetzung 4a (Plan 2026-10-16-etappe-4a-presets.md)
|
||
- Pipeline `DesignChange` (alle Bereiche), Snapshots `SnapshotStore`, Bereich `presets`.
|
||
- Tools: lit/divi-preset-get, lit/divi-presets-set, lit/divi-presets-delete, lit/divi-design-snapshots, lit/divi-design-restore (alle indirekt).
|
||
- Schreiben über die Schrittfolge von `GlobalPresetController::sync` (Mirror `preset-sync`).
|
||
- Offen für 4b (erledigt in 4b, R11 und Task 10): Fundstellen von Standard-Gruppen-Presets (Gruppenliste je Modul), lit/divi-design-detach.
|
||
|
||
## Etappe 4b (Plan 2026-10-18-etappe-4b-zuweisen.md)
|
||
- Tools: lit-divi-insert/-update/lit-content-create (preset-Stapel, group_presets, clear_overrides), lit/divi-presets-assign, lit/divi-design-detach (beide indirekt); Outline und node-get zeigen Gruppen-Presets.
|
||
- R1 Fundstellen: keine Klasse DesignUsages; GlobalUsages::reportFor()/rowsFor() plus ModuleUsageQuery (alle Module eines Typs).
|
||
- R2 Stapel: preset = String | Liste (1–10) | null; doppelte IDs und leere Liste sind Fehler; letzter im Stapel gewinnt bei gleicher Priorität.
|
||
- R3 Gruppen-Schlüssel: Kurzname, voller Name oder Attributpfad; mehrdeutiger Name → Fehler mit den Pfaden; gleichnamige Gruppen in einem Modul sind auch in lit/divi-presets-set und im Composer (group_presets) ein Fehler, dort hilft der Attributpfad als Schlüssel; GroupKeys ersetzt die private Suche im PresetComposer.
|
||
- R4 Überdeckungen (G9): Vergleich je Blatt (Pfad, Breakpoint, Zustand), nur ausdrücklich zugewiesene Presets, Warnung nur bei abweichendem Wert; clear_overrides entfernt alle lokalen Blätter auf Preset-Blättern.
|
||
- R5 Warnungstext je Preset eine Zeile, bis zu 5 Pfade.
|
||
- R6 Outline: group_presets je Zeile und in node-get; Fingerprint unverändert.
|
||
- R7 clear_overrides beim Einfügen wirkt nach set/attrs desselben Knotens; nicht-boolesch → Fehler.
|
||
- R8 Seiten-Umschreiber: globale Instanzen nie umgeschrieben (skipped; Bibliotheks-ID nur bei sichtbaren Bibliotheks-IDs, P13), Bibliothekseintrag ist eigene Fundstelle; nicht ladbare Seiten skipped; remaining zählt nur Seiten mit Änderungen.
|
||
- P8a mit post_ids: nur die genannten Seiten können das Schreiben blockieren, HARD_CAP gilt nicht (die Rechteprüfung der Live-Seiten entfällt dann vorab, loadWritable() prüft jede Seite einzeln und meldet skipped). Eine genannte veröffentlichte, private oder geplante Seite ohne Bearbeitungsrecht verweigert den ganzen Aufruf (forbidden, blocked_ids, nichts geschrieben; der Probelauf listet sie in blocked_ids); eine genannte Seite, die nicht live ist (Entwurf usw.) und nicht bearbeitet werden darf, steht in skipped. Ohne post_ids verweigert jede blockierte Live-Fundstelle oder zu viele Fundstellen den ganzen Aufruf, nichts wird geschrieben.
|
||
- R9 Kein unfiltered_html-Zwang: der Umschreiber ändert nur Preset-Verweise und entfernt lokale Werte, Speichern über DiviSaver.
|
||
- R10 detach nur Presets: Eingabe preset = Objekt {module|group, preset}; variable → unsupported (4c); ohne post_ids zuerst verschachtelte Verweise über DesignChange (Snapshot, design_rev), danach Seiten (≤ 50); scheitert die erste Seite danach, nennt der Fehler Snapshot und diff; Standard-Presets nur ausdrückliche Verweise.
|
||
- lit/divi-presets-assign: preset: null, leerer Text und null in group_presets werden abgewiesen (Hinweis auf lit/divi-design-detach); ein leerer Probelauf ist ein normales „nichts zu tun“.
|
||
- R11 Standard-Gruppen-Presets: PresetUsageMatcher erkennt implizite Nutzung (Modul hat die Gruppe, kein ausdrücklicher Eintrag); Kandidaten fail closed über wp:divi/; der 4a-Hinweis „nicht aufgelistet“ entfällt.
|
||
- 4b-Nachtrag zu R11: Das ändert das 4a-Verhalten. lit/divi-presets-set und lit/divi-presets-delete eines Standard-GRUPPEN-Presets nehmen jetzt jede Divi-Seite mit dieser Gruppe in ihren Fundstellenbericht auf; auf Sites mit mehr als 2000 Live-Divi-Seiten wird die bestätigte Änderung daher abgewiesen (tooMany), wie bisher nur bei Standard-Modul-Presets; konsistent mit P8a.
|
||
- Grenze je Aufruf A6: 50 Seiten, remaining; Teilerfolg partial_write mit den gespeicherten Seiten.
|
||
- Offen für 4c: detach für Variablen (A7: Referenz durch den aktuellen Wert ersetzen, bei Farben entfällt detach), Wiederverwendung des PageRewriter/TreeRewrite dafür (NodeRewrite-Strategie `VariableDetachRewrite`).
|
||
- Offen für 4c/4e: Smoke divi-presets-assign-smoke.sh läuft nur mit deaktivierten Plugins postlos und asynclistry.
|
||
|
||
## Offene Kleinpunkte aus 4a (Reviews, nicht merge-relevant)
|
||
- Task 1: minor (deferred): Nachtrag verweist nicht auf §7 Punkt 4 („strenger als Divi“ gilt für Presets nicht mehr)
|
||
- Task 2: minor (deferred): PresetBook::with() erzwingt kein id-Feld
|
||
- Task 2: minor (deferred): rein numerische IDs/Namen werden int-Keys → TypeError bei new PresetScope (scopeOf/nestedUsers/toRest); (string)-Cast
|
||
- Task 2: minor (deferred): PresetScope-Regex lehnt "_" ab
|
||
- Task 3: minor (deferred): Standardwechsel X→Y meldet nur default_set Y, nicht default_cleared X
|
||
- Task 3: minor (deferred): Testabdeckung dünn (Gruppen, Standardwechsel, name-only)
|
||
- Task 4: minor (deferred): attachLog ignoriert fehlgeschlagenes update_option; RMW ohne Lock; Testlücken (Grenze MAX_BYTES, attachLog null/unbekannt)
|
||
- Task 5: minor (deferred): savePresets bereinigt bei mayRemove beide Arten (Obermenge von Divi), ACTION_DELETE_GROUP ungenutzt, Docblock erwähnt es nicht
|
||
- Task 5: minor (deferred): keine Unit-Tests für WP_Error→RuntimeException und Cleanup-Pfad (Integration in Task 14)
|
||
- Task 6: minor (deferred): UsageQuery-Vertrag „bereits vorbereitet“ nur Konvention; kein reportFor()-Test
|
||
- Task 7: minor (deferred): leere ID → LIKE %% (teuer); Testlücken _initial/[""]/Legacy-String beim Standard
|
||
- Task 8: minor (deferred): kein RED-Lauf dokumentiert (Tests und Code in einem Schritt)
|
||
- Task 8: minor (deferred): kein Test für DiviLocked aus area->write(); Read-back-Test prüft Rollback nur lose; kein Test für fehlende design_rev
|
||
- Task 9: minor (deferred): META_KEYS (modulePreset, groupPreset, globalModule, localAttrs) im Post-Check unsichtbar – heute nicht erreichbar; explizite Ablehnung als Defense in Depth
|
||
- Task 10: minor (deferred): Scope-Fehler immer unter fields.module; fehlendes preset → not_found statt validation_failed
|
||
- Task 11: minor (deferred): Test „nichts geschrieben“ prüft nicht, dass items[0] fehlerfrei ist
|
||
- Task 12: minor (deferred): in_use-Antwort ohne affected_count/hidden_count; Testlücken (verschachtelt+mitgelöscht, mehrere Items, Rechte)
|
||
- Task 13: minor (deferred): kein Paginierungs-/next_cursor-Test; Restore-Rechte nicht im Ability-Test
|
||
- Task 14: minor (deferred): Guide nennt Exklusivität name/rename und Namensgrenzen nicht ausdrücklich; Smoke hinterlässt Snapshots im SnapshotStore; Restore-Check vergleicht nicht den ganzen Bestand
|
||
- DesignLock: zwei gleichzeitige Übernahmen einer veralteten Sperre möglich (sehr kleines Fenster); Schreibvorgang > 120 s kann Sperre verlieren
|
||
- Verwaister @param-Docblock in DiviPresetsDeleteAbility
|
||
- Smoke divi-presets-smoke.sh läuft nur mit deaktivierten Plugins postlos (Monolog 2) und asynclistry (Deprecated-Ausgabe)
|
||
|
||
## Etappe 4d (Plan 2026-10-19-etappe-4d-theme-optionen-schriften.md)
|
||
|
||
Belege: `2026-10-19-etappe-4d-divi-recherche.md`; Formate-Nachtrag „Etappe 4d“. Die Rulings amendieren Spec §8 und §10.
|
||
|
||
- **W1:** Drei neue Fähigkeiten `theme-option-read`, `theme-option-write` und `font-upload`; der Mirror `customizer-typography` trägt Lesen und Schreiben, die Schriftlisten-Aufrufe tragen `theme-option-write`, `font-upload` und `variable-write`.
|
||
- **W2:** Whitelist von 20 Theme-Optionen (vier Schriften, zwei Gewichte, Größen, Zeilenhöhen, Abstände, `body_header_style`, vier Layout-Werte); Standards, Bereiche und Sanitizer sind Literale in `ThemeOptionSpec`/`ThemeOptionsAdapter`, gesichert durch den Mirror.
|
||
- **W3:** „Nicht gesetzt“ ist der Divi-Standard; `null` setzt zurück (`et_delete_option`), `'none'` und `false` werden abgelehnt; Tablet-/Phone-Größen erben, solange sie nicht gesetzt sind.
|
||
- **W4:** Das Plugin prüft Bereiche, Schritte und Auswahl selbst (Divis Sanitizer klemmen nicht); `body_header_style` nimmt genau einen Wert; Zahlen als Zahl oder Ziffern-String.
|
||
- **W5:** Schriftnamen gelten exakt (Groß-/Kleinschreibung) gegen Divis gemergte Liste; unbekannt → `validation_failed` mit bis zu fünf ähnlichen Namen; die Liste wird je Request einmal geladen.
|
||
- **W6:** Snapshot `theme_options` hält die vorhandenen Whitelist-Schlüssel mit Rohwert und Typ; Restore ersetzt die Whitelist vollständig (`et_update_option`/`et_delete_option`) und leert die Caches wie der Customizer.
|
||
- **W7:** Theme-Optionen haben keinen Seitenbezug; der Probelauf warnt „wirkt auf die gesamte Website“ (bei Schriften auch auf den Builder), `usages` bleibt `null`.
|
||
- **W8:** Der Upload installiert im Prozess über `FontsUtility::font_add()` mit `wp_handle_upload_rest`; Mirror `font-install`; Formate `woff2`, `woff`, `ttf`, `otf`; Teilerfolg wird erkannt und mit `font_remove` zurückgenommen.
|
||
- **W9:** Name 1–100 Zeichen aus `A–Z a–z 0–9`, Leerzeichen, `_`, `-`, nicht in Google-, Web-Safe- oder hochgeladenen Schriften; je Datei höchstens `min(Upload-Limit, 5 MB)`, 1–4 Dateien, Magic Bytes passend zur Endung, URL-Regeln über den geteilten `RemoteFileFetcher`.
|
||
- **W10:** Der Probelauf lädt wirklich herunter (nur Temp-Dateien) und meldet Dateien mit Größe und SHA-256; mit `confirm: true` erneut laden, prüfen, installieren; kein Snapshot.
|
||
- **W11:** Restore kennt den Bereich `theme_options` (`ThemeOptionsRestorePlanner`); Rechte wie beim Schreiben.
|
||
- **W12:** Variablen vom Typ `fonts` werden zusätzlich gegen den Schriftkatalog geprüft; `VariableValue` bleibt rein.
|
||
- **W13:** Divi-Grenzen, die dokumentiert statt behoben sind:
|
||
- `et_update_option` schreibt das ganze `et_divi`-Array aus dem Request-Global (Lost-Update-Risiko; `design_rev` und Sperre mindern es).
|
||
- `body_header_style` nimmt in Divi nur einen Wert.
|
||
- Divi prüft keine Bereiche; das Plugin tut es.
|
||
- `font_add` meldet Teilerfolg als Erfolg (Plugin vergleicht und nimmt zurück).
|
||
- `remove_static_resources` wirkt nur mit angemeldetem Benutzer (Smokes laufen mit `--user`).
|
||
- Divis Leser kennen für `tablet_*`/`phone_*` feste Standards 14 bzw. 30; bei „gleich dem Größeren“ erzeugt Divi keine CSS-Regel.
|
||
- Zwischen `RemoteFileFetcher::allows()` und dem cURL-Abruf bleibt ein DNS-Rebinding-Fenster (das „IPv4-Pinning“ ist nur `CURL_IPRESOLVE_V4`); Thema für das Security-Audit in 4e.
|
||
- Schema-Fehler (Bereich, unbekannter Schlüssel) lehnt der MCP-Adapter mit dem Eingabeschema ab, bevor die Tools laufen; sie tragen dann nicht die `validation_failed`-Feldpfade des Plugins.
|
||
- **W14:** `DesignRights::themeOptions()` verlangt `edit_theme_options` und `theme_customizer` (der Parameter `$writer` ist ungenutzt, B2), `DesignRights::fonts()` verlangt `upload_files`, `edit_theme_options` und `custom_fonts_management`; die Fehlertexte nennen das fehlende Recht und die Divi-Rolle.
|
||
|
||
**Folgepunkte (außerhalb 4d):** Schriftprüfung in Preset- und Modul-Attributen; `lit/divi-fonts-list` bzw. Schriftsuche (Vorschläge gibt es nur in Fehlern); Entfernen hochgeladener Schriften (A2); Format `eot`.
|
||
|
||
### Offene Kleinpunkte aus 4d (Reviews, nicht merge-relevant)
|
||
- Theme-Optionen: `ThemeOptionSpec` Zahlen-Regex ohne `/D` („15\n“); Werte neben dem Schritt (1.70000001) werden nicht gerundet; `rev()` von INF/NAN; `effective()` gibt gespeicherte Unwerte bei Auswahlfeldern unverändert zurück; `FontSuggest` rechnet bytebasiert.
|
||
- Update-Tool: unnötiger Schreibvorgang bei gespeichertem „16“ gegen gesetzte 16 (`ThemeOptionsArea::same` nutzen); Schriftname wird vor dem Trimmen geprüft (" Roboto"); `DesignRights::themeOptions` mit ungenutztem `$writer` samt Test-Mock; kein Hinweis zu Schriftstärken im Builder.
|
||
- Gespeichertes `false`: Tests für `get`/Planer/Restore und `design_rev`-Vergleich fehlen; ungesetzte, gespeicherte `false`-Schlüssel entfernt `write()` still.
|
||
- Schrift-Variablen: Test, dass reine Status-/Label-Änderungen den Katalog nicht laden; ein erneut gesendeter Wert einer Schrift, die Divis Liste verlassen hat, wird `validation_failed`.
|
||
- Upload: `confirm` bindet die im Probelauf gezeigte SHA-256 nicht (optionale Eingabe); der Probelauf prüft den Rohnamen, `install()` nutzt `sanitize_file_name`; `FontInstaller::install()` prüft die Endung nicht selbst gegen `FORMATS`; Meldung bei fehlendem `fileinfo` irreführend; Tests für Fetcher-Ausnahme/Aufräumen und leeres `wp_tempnam` fehlen; nur vier Magic-Byte-Signaturen; gleichzeitiger Upload desselben Namens in anderer Schreibweise.
|
||
- `FontInstaller` lässt die verschobene Datei in `et-fonts`, wenn `font_add` wirft (nicht-Array `et_uploaded_fonts`); Aufräumen mit `catch Throwable` ergänzen.
|
||
- Smoke-Skripte: fehlende `file_exists`-Prüfung in Schritt 7, Format-Grep im Probelauf vakuos (stattdessen `sha256`/`bytes` prüfen), Namenskonflikt prüft nicht auf `conflict`, `'none'` nicht isoliert, kein Zurücklesen von `body_font`, EXIT-Trap stellt ganz `et_divi` wieder her (Admin-Änderungen während des Laufs gehen verloren) und räumt Snapshots sowie Dateien fälschlich akzeptierter Schriften nicht auf, Sentinel-Prüfung vakuos, `restore()` verbirgt stderr.
|
||
- Protokoll: `src/Admin/LogObjects.php` kennt den Objekttyp `divi_font` nicht (Anzeige als Code).
|
||
- Kleinkram: Reihenfolge der `use`-Blöcke; `DiviLocked`-Rethrow setzt voraus, dass die Sperre vor jedem Schreiben greift.
|
||
|
||
## Etappe 4e (Plan 2026-10-19-etappe-4e-schleifen-guides-audit.md)
|
||
|
||
Belege: `2026-10-19-etappe-4e-recherche-schleifen.md` (rekonstruiert, siehe dort), Audit `2026-10-19-etappe-4e-security-audit.md` (Status nach der Fix-Welle). Die Rulings amendieren Spec §9.
|
||
|
||
- **X1:** Der Schleifen-Kontext ist der des nächsten Vorfahren-oder-selbst mit `loop.desktop.value.enable === "on"`; `queryType` fehlt → `post_types`; die innerste Schleife gilt.
|
||
- **X2:** Arten `post`, `term`, `user`, `menu`; die Art einer Option folgt der Divi-Gruppe, die Meta-Schlüssel-Optionen dem Namen; gespeichert wird der Array-Schlüssel.
|
||
- **X3:** `VariableRef` und `DynamicContentRules` bekommen einen `LoopScope`; Insert, Update und Move prüfen im Kontext des Ziels, Move warnt statt abzulehnen (A11); `lit-content-create` hat nie einen Kontext.
|
||
- **X4:** Kurzform `{{loop:<option>}}` über die Tabelle `LOOP` in `Placeholders`.
|
||
- **X5:** Neue Meldungen („braucht eine Divi-Schleife“, „passt nicht zur Schleife … (Typ: …)“); Ruling S36 abgelöst.
|
||
- **X6:** `lit/divi-dynamic-sources` mit `post_id` + `node` nennt die zur Schleife des Knotens passenden Quellen.
|
||
- **X7:** Grenzen statt Lösung: Schleifen über `attrs` schaltbar, globale Module ohne Kontext, Kopieren mit `unfiltered_html`, Preset-Schleifen unerkannt, ACF-Wiederholungsfelder nicht unterstützt.
|
||
- **X8:** Guides ohne Prompts: Ablauf „Corporate Design übernehmen“ in `workflows.md`, Design-Tools und Fehlercodes in `divi-design-system.md`/`overview.md`, Loop-Regeln in `divi-placeholders.md`/`divi-shortform.md`.
|
||
- **X9:** Unabhängiger Security-Audit (0 kritisch, 0 hoch, 1 mittel, 9 niedrig, 10 Info); Fix-Welle für M1, L1 (Option B), L2, L4–L8 und DNS-Rebinding.
|
||
- **X10:** Version 0.6.1 → 0.7.0, kein Tag, kein Release.
|
||
- **Zusätze aus dem Audit:** Kettenregel für `_meta_key_`-Optionen (M1), `queryType` wie `sanitize_key` mit Aliasen `terms`/`users` (L2), Rechteprüfung für Schleifen-Einstellungen (L1 B: `list_users`, `read_private_posts`), Restore berechnet Fundstellen (L4), ein Lock für Farben und Theme-Optionen, atomarer `DesignLock` (L5, L6), `CURLOPT_RESOLVE` gegen DNS-Rebinding und Abruf nur mit cURL (L8).
|
||
|
||
### Folgearbeit nach Etappe 4
|
||
|
||
Aus dem Audit (nicht behoben):
|
||
- **L3:** Globale Instanzen und Kopien (`unfiltered_html`: `lit/library-insert` im Kopiermodus, `lit/divi-node-copy`) tragen `loop_*`-Inhalt über Schleifen-Arten ohne Prüfung oder Warnung; braucht einen eigenen Plan.
|
||
- **L9:** Der Seiten-Umschreiber parst jeden Kandidaten bei jedem Probelauf und Confirm, ohne Cap für Entwürfe (Administrator-Niveau, Wirkung endet mit dem Request).
|
||
- **L8-Rest:** Bei https mit einem cURL ohne SSL kann Requests auf fsockopen ausweichen (selten, bewusst belassen).
|
||
- **I1–I10:** I1 Preset-Detach ohne Marker-Prüfung der Affixe; I2 abgelöster Variablenwert ohne Bereinigung für den Feldtyp; I3 `from_node` mit `unfiltered_html` kopiert `loop_*` ungeprüft in Presets; I4 Lese-Tools prüfen Rechte nur in `permission()`; I5 Shortcodes und Bedingungen in Term-/Benutzer-/Menü-Schleifen laufen gegen den Beitrag mit der Term-/Benutzer-ID; I6 Font-Probelauf verrät private DNS-Auflösung; I7 Font-Confirm ist nicht an die Probelauf-SHA-256 gebunden; I8 Font-Download bis ca. 120 s je Aufruf, Temp-Reste bei Abbruch; I9 Lost Update auf `et_uploaded_fonts`; I10 `numbers`-Variablen akzeptieren `url(https://…)`.
|
||
- **Gesamtreview 4e:** M-4 `DesignLock`: im Fallback `wp_cache_flush_runtime` statt `wp_cache_flush` (kein Flush des persistenten Caches); M-5 Guide-Hinweis, dass Inhalt unter einer Administrator-Benutzer-Schleife Konten-Daten zeigen kann; `ValueCleaner::listsPrivatePosts` entflechten; `DiviDynamicSourcesAbility::page()` lädt zweimal; `DesignLock::acquire` aufteilen (Sperre nehmen, Cache verwerfen).
|
||
- **Z1:** Schleifen und `loop_*`-Verweise aus Presets erkennt die Baumprüfung nicht (fail closed; auf der Website ohne Wirkung, weil Divi die Schleife aus dem rohen Dokument liest).
|
||
|
||
Übernommen aus 4d und früher:
|
||
- Schema-Fehler-Form projektweit (Adapter-Eingabeschema statt `validation_failed`-Feldpfade).
|
||
- Schriftnamen in Preset- und Modul-Attributen prüfen; `lit/divi-fonts-list`/Schriftsuche; Entfernen hochgeladener Schriften; Format `eot`.
|
||
- Rev-Helfer der Book-Klassen vereinheitlichen.
|
||
- `dryRun()`/`installed()` aus `DiviFontsUploadAbility::upload()` herauslösen.
|
||
- sha256-Pin beim Upload-`confirm` (`expected_sha256`).
|
||
- Weitere Minor-Punkte aus den Abschnitten „Offene Kleinpunkte“ (4a, 4d) und unten (4e).
|
||
|
||
### Offene Kleinpunkte aus 4e (Ledger, nicht behoben)
|
||
- `LoopScope`/`LoopContext`: `LOOP`-Tabelle mit 31 Identitätszuordnungen (Stil); Lücken bei Tests (int/bool `queryType`, Groß-/Kleinschreibung, Wurzelknoten opak, kein Test für den Standard-Konstruktor von `Placeholders`).
|
||
- `DynamicContentMapTest` prüft nur „Schleifen“ statt „braucht eine Divi-Schleife“; die Fehlanpassungsmatrix hat nicht alle Zeilen (Benutzer-Meta in Term-/Menü-Schleife, `loop_product_*` in Nicht-Beitrags-Schleifen); ein nicht unterstützter `queryType` erscheint roh im Fehlertext; `VariableRefTest` akzeptiert zwei Meldungen.
|
||
- Insert: Meldung „braucht eine Divi-Schleife“, wenn derselbe Aufruf die Schleife am Knoten setzt, dessen Elternteil keine hat; doppelter Warntext, wenn Vorfahr und Nachfahr zugleich geändert werden; Wechsel von keiner zu nicht unterstützter Schleife ohne Warnung; Cache-Schlüssel `''` für „keine“ und „nicht unterstützt“ geteilt; Wortlaut der Move-Warnung „Divi zeigt sie dort leer“ für nicht unterstützte Ziele.
|
||
- Tests: `testInLoopChecksLoopContentAgainstItsScope` und `testLoopContentBelowANewLoopContainerIsRefused` zu schwach; Obfuskations-Datenprovider prüft nur `problems !== ''`; kein Test „keine Schleifen-Warnung bei einfachem Update in der Schleife“; Testzeilen über 120 Zeichen (Tests außerhalb des Lints).
|
||
- `lit/divi-dynamic-sources`: Bibliothekseinträge und Theme-Builder-Layouts nicht erreichbar (Docblock verspricht mehr); `page()` lädt zweimal; tote Fixture-Einträge in `withLoopPage`.
|
||
- Audit-Spur: Innerhalb einer Schleife reicht Divi `loop_id`/`loop_query_type`/`loop_object` an jede Inhaltsvariable; Resolver von Nicht-Loop-Optionen, die `loop_id` nutzen, sind nicht einzeln nachverfolgt (I5 deckt Shortcodes ab).
|