From 10c98cd3c6438b569a85d0106cf04614bd8c113d Mon Sep 17 00:00:00 2001 From: Jan-Niclas Loosen Date: Sat, 26 Sep 2026 17:13:59 +0200 Subject: [PATCH] docs: Divi guides shortform/placeholders, hints name the write tools; test: Divi write end-to-end; version 0.3.0 - Hints (PostPresenter::DIVI_NOTE, outline, catalog) and server instructions (tree_rev rule) name the Divi write tools; guides divi-shortform and divi-placeholders, additions to divi-structure, divi-attrs, overview (tool groups, 'nur lesen'), workflows, content-types. - D7 wording and the S7 exception in readme, guides and spec 1.3/5.2; readme 0.3.0. - ToolNamingTest: every referenced guide topic exists; overview lists exactly the topics. - tests/Integration/divi-write-smoke.sh: all write tools via OAuth, editor without unfiltered_html with benign probes (S6), Divi's own save filters on the new fixture synthetic-divi-filters.html (S7); admin-render.php accepts the new wrap class. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7 --- docs/guides/content-types.md | 14 +- docs/guides/divi-attrs.md | 25 ++ docs/guides/divi-placeholders.md | 47 +++ docs/guides/divi-shortform.md | 112 ++++++ docs/guides/divi-structure.md | 17 +- docs/guides/overview.md | 13 +- docs/guides/workflows.md | 19 + .../notes/2026-09-26-etappe-2b-abnahme.md | 112 ++++++ .../specs/2026-09-25-wp-lit-mcp-design.md | 4 +- readme.txt | 36 +- src/Guides/InstructionsBuilder.php | 8 +- .../Divi/Pages/DiviOutlineAbility.php | 7 +- .../Divi/Schema/DiviCatalogAbility.php | 2 +- .../WordPress/Content/PostPresenter.php | 5 +- src/Plugin.php | 2 +- .../Fixtures/divi/synthetic-divi-filters.html | 1 + tests/Integration/admin-render.php | 2 +- tests/Integration/divi-write-smoke.sh | 364 ++++++++++++++++++ tests/Unit/Guides/InstructionsBuilderTest.php | 2 + tests/Unit/Guides/ToolNamingTest.php | 34 ++ .../Divi/Pages/DiviReadAbilitiesTest.php | 3 +- .../Divi/Schema/DiviCatalogAbilityTest.php | 2 + .../WordPress/Content/PostPresenterTest.php | 4 + wp-lit-mcp.php | 2 +- 24 files changed, 811 insertions(+), 26 deletions(-) create mode 100644 docs/guides/divi-placeholders.md create mode 100644 docs/guides/divi-shortform.md create mode 100644 docs/superpowers/notes/2026-09-26-etappe-2b-abnahme.md create mode 100644 tests/Fixtures/divi/synthetic-divi-filters.html create mode 100755 tests/Integration/divi-write-smoke.sh diff --git a/docs/guides/content-types.md b/docs/guides/content-types.md index 213800c..fb0e28c 100644 --- a/docs/guides/content-types.md +++ b/docs/guides/content-types.md @@ -23,14 +23,16 @@ Werkzeugnamen: `lit-…` sind direkt aufrufbare Tools; `lit/…` sind Abilities, Trefferliste. Geliefert werden nur Einträge, die der verbundene Nutzer selbst bearbeiten darf (fremde Entwürfe/private Inhalte ohne die passende Berechtigung erscheinen nicht). - `lit-content-get`: alle Daten eines Eintrags inkl. Feldern, Begriffen, Beitragsbild und `rev`. - Bei Divi-Seiten fehlt `content`; den Aufbau liest `lit-divi-outline` (siehe `divi-structure`), geändert - wird er vorerst im Divi-Builder (Titel, Auszug, Felder und Begriffe gehen weiter über - `lit-content-update`). + Bei Divi-Seiten fehlt `content`; den Aufbau liest `lit-divi-outline`, geändert wird er mit den + Divi-Werkzeugen (siehe `divi-structure`); Titel, Auszug, Felder und Begriffe gehen weiter über + `lit-content-update`. ## Anlegen und Ändern - `lit-content-create` legt immer einen **Entwurf** an. Felder werden gegen das Schema geprüft; ein Fehler - bricht den ganzen Aufruf ab (`fields.` im Fehler nennt die Ursache). + bricht den ganzen Aufruf ab (`fields.` im Fehler nennt die Ursache). Divi-Seiten gleich mit + Inhalt: `divi` = Liste von Abschnitten in Kurzform (siehe `divi-shortform`) statt `content`; die Antwort + enthält dann die `tree_rev` für weitere Divi-Änderungen. - `lit-content-update` ändert nur die übergebenen Werte, der Status bleibt. `rev` aus `lit-content-get` ist **Pflicht** – hat jemand parallel gespeichert (Inhalt, Titel, Auszug, Status oder irgendetwas anderes am Eintrag), kommt `rev_mismatch`: neu lesen, Änderung auf dem aktuellen Stand wiederholen. @@ -59,8 +61,8 @@ Werkzeugnamen: `lit-…` sind direkt aufrufbare Tools; `lit/…` sind Abilities, ## Sicher überarbeiten 1. `lit/post-duplicate` → Entwurfskopie; die Antwort enthält die `rev` der Kopie für `lit-content-update`. -2. Kopie mit `lit-content-update` (Divi-Inhalte vorerst im Divi-Builder) bearbeiten und dem Nutzer die - Vorschau zeigen; `lit-page-render-summary` fasst den gerenderten Inhalt zusammen. +2. Kopie mit `lit-content-update` bzw. den Divi-Werkzeugen bearbeiten und dem Nutzer die Vorschau zeigen; + `lit-page-render-summary` fasst den gerenderten Inhalt zusammen. 3. `lit/post-replace-with-copy` übernimmt die Kopie ins Original (ID, URL, Status und Menüeinträge bleiben). Voraussetzungen: die Kopie muss noch Entwurf oder ausstehend sein, `rev` des Originals aus `lit-content-get` ist Pflicht (sie deckt Titel, Inhalt, Auszug und Status ab – Felder/Meta, die direkt am diff --git a/docs/guides/divi-attrs.md b/docs/guides/divi-attrs.md index f6e570e..5d9d919 100644 --- a/docs/guides/divi-attrs.md +++ b/docs/guides/divi-attrs.md @@ -18,6 +18,31 @@ Der Wert eines Pfads ist eine Zuordnung **Breakpoint → Zustand → Wert**: Breakpoints: `desktop`, `tablet`, `phone` (je nach Website auch `tabletWide`, `phoneWide`, `widescreen`, `ultraWide`); Zustände: `value`, `hover`, `sticky`. +## Setzen + +In `attrs` (bei `lit-divi-insert` je Knoten, bei `lit-divi-update` je Änderung) steht Pfad → Wert je Breakpoint. +Kurz: `{"desktop": "#1a1a1a", "phone": "…"}` bzw. bei Objektwerten `{"desktop": {"size": "28px"}}`; Hover und +Sticky: `{"hover": {…}}` bzw. `{"desktop": {"value": {…}, "hover": {…}}}`. Nur die genannten Breakpoints +werden ersetzt, der Rest bleibt; `null` entfernt einen Pfad, Breakpoint oder Zustand: + +```json +{ "id": "s0.r0.c1.m0", + "attrs": { "title.decoration.font.font": { "desktop": { "color": "{{color:heading}}" }, + "phone": { "size": "28px" } }, + "module.decoration.spacing": null } } +``` + +Ein Objektwert ersetzt den bisherigen Wert dieses Breakpoints ganz (Unterschlüssel werden nicht +zusammengeführt): z. B. bei `module.decoration.sizing` einer Spalte `flexType` immer mitschicken (siehe +`divi-shortform`). + +Unbekannte Pfade → Fehler `invalid_attr_path` mit Vorschlägen unter `fields`. Texte werden bereinigt +(HTML nur, wo Divi Rich-Text erwartet; Links ohne `javascript:`). `$variable`-Verweise werden geparst, +geprüft und vom Plugin neu erzeugt (siehe `divi-placeholders`). Eigenes HTML, CSS und HTML-Attribute +(`…decoration.attributes`, `…advanced.html`, `…css…`) nur mit dem Recht `unfiltered_html`, sonst „nur im +Divi-Builder“. Unberührte Teile der Seite bleiben byte-identisch; Ausnahme: Divi selbst normalisiert Seiten +mit eigenen HTML-/Attribut-Feldern beim Speichern (Warnung in der Antwort, neue `tree_rev` gilt). + ## Pfade finden - `lit-divi-catalog` ohne `module` listet alle Module dieser Website; mit `module` (z. B. `"heading"`) alle diff --git a/docs/guides/divi-placeholders.md b/docs/guides/divi-placeholders.md new file mode 100644 index 0000000..16fb767 --- /dev/null +++ b/docs/guides/divi-placeholders.md @@ -0,0 +1,47 @@ +# Platzhalter für Divi-Inhalte + +Platzhalter stehen **allein** im Wert (nicht mitten im Text) und werden beim Speichern in Divis eigene +Verweise übersetzt. So bleibt die Seite mit dem Designsystem verbunden: ändert sich die Primärfarbe, ändert +sich auch der Button. + +| Platzhalter | Bedeutung | +|---|---| +| `{{color:primary}}`, `secondary`, `heading`, `body`, `link` | die fünf Theme-Farben | +| `{{color:}}` | eigene globale Farbe (Name wie in `lit-divi-design-system`) | +| `{{var:}}` | globale Variable (Zahl, Text, Bild, Link) | +| `{{font:heading}}`, `{{font:body}}` | Theme-Schrift für Überschriften bzw. Fließtext | +| `{{post:title}}`, `excerpt`, `date`, `modified`, `author`, `url`, `featured_image`, `categories`, `tags` | dynamischer Inhalt des angezeigten Beitrags | +| `{{field:}}` | dynamischer Inhalt aus einem Feld (Pods/Meta), z. B. `{{field:telefon}}` | +| `"preset": ""` | Modul-Preset (kein Platzhalter, sondern eigenes Feld) | + +Beispiele: + +```json +{ "type": "button", "text": "Anrufen", "url": "{{field:telefon_link}}", + "attrs": { "button.decoration.background": { "desktop": { "color": "{{color:primary}}" }, + "hover": { "color": "{{color:Nachtblau}}" } } } } +``` + +```json +{ "type": "heading", "text": "{{post:title}}", "level": "h1" } +``` + +Unbekannte Namen lehnt das Werkzeug ab und nennt die vorhandenen; ist ein Name doppelt vergeben, statt des +Namens die ID aus `lit-divi-design-system` angeben (z. B. `{{color:gcid-…}}`). Felder, deren Schlüssel mit `_` +beginnt (geschützte Meta-Daten), sind nicht erlaubt. + +In Link-Feldern (`url`, `button_url` …) nimmt das Werkzeug jeden dynamischen Inhalt an, auch `{{post:title}}`; +sinnvoll sind dort nur Werte, die eine Adresse ergeben (`{{post:url}}`, ein Feld mit einer URL, eine +Link-Variable). + +## `$variable`-Werte + +In `lit-divi-node-get` erscheinen die übersetzten Verweise als `$variable({…})$`. Diese Werte unverändert +lassen oder wieder durch einen Platzhalter ersetzen. `$variable`-Verweise werden geparst, geprüft und vom +Plugin neu erzeugt: erlaubt sind nur ganze Werte mit bekannten Farben, Variablen, Schriften und +dynamischen Quellen; Zusatztexte davor/danach (`before`/`after`) werden bereinigt; alles andere (z. B. ein +Verweis mitten im Text, eigenes HTML-Ausgeben von Feldern) lehnt das Werkzeug mit `validation_failed` ab. + +Unberührte Teile der Seite bleiben dabei byte-identisch. Ausnahme: Divi selbst normalisiert Seiten mit +eigenen HTML-/Attribut-Feldern beim Speichern; die Antwort warnt dann, dass der Inhalt beim Speichern +verändert wurde, und die neue `tree_rev` gilt. diff --git a/docs/guides/divi-shortform.md b/docs/guides/divi-shortform.md new file mode 100644 index 0000000..45333ad --- /dev/null +++ b/docs/guides/divi-shortform.md @@ -0,0 +1,112 @@ +# Divi-Kurzform + +Neue Divi-Inhalte beschreibt man als JSON-Knoten. `lit-divi-insert` (in `nodes`) und `lit-content-create` (in +`divi`) nehmen dieselbe Form. Jeder Knoten hat einen `type`; dazu Kurzform-Felder, optional `label` +(Admin-Label), `preset` (Name eines Modul-Presets aus `lit-divi-design-system`) und `attrs` (Vollform, siehe +`divi-attrs`). Kurz- und Vollform lassen sich kombinieren, aber nicht für denselben Pfad (dann Fehler +`validation_failed` mit dem Pfad). + +## Aufbau + +```json +{ "type": "section", "label": "Hero", "background_color": "{{color:primary}}", + "rows": [ + { "columns": "1_3,2_3", + "modules": [ + [ { "type": "image", "image_id": 33 } ], + [ { "type": "heading", "text": "Willkommen", "level": "h1" }, + { "type": "text", "content": "

Seit 1987 in Köln.

" }, + { "type": "button", "text": "Termin buchen", "url": "/kontakt", "preset": "CTA primär" } ] + ] } + ] } +``` + +- **Abschnitt** (`section`): `rows` (Zeilen) oder – für eine einspaltige Zeile – direkt `modules`; + `section_type: "fullwidth"` für Vollbreite-Abschnitte (dann nur `fullwidth-…`-Module in `modules`); + `background_color`. Spezialabschnitte (specialty) nur im Divi-Builder bauen. +- **Zeile** (`row`): `columns` = Breiten als Brüche, die zusammen 1 ergeben (`"4_4"`, `"1_2,1_2"`, + `"1_3,2_3"`, `"1_4,1_4,1_2"`, auch Fünftel); `modules` = je Spalte eine Liste (bei einer Spalte reicht eine + einfache Liste). +- **Module** mit Kind-Modulen (Akkordeon, Tabs, Slider, Kontaktformular, Karte, Social-Media-Follow, + Icon-Liste) bekommen ihre Einträge in `items`; der Eintragstyp ergibt sich von selbst. +- `label` fehlt → Admin-Label „ – “, z. B. „Hero – Button“. Abschnitten deshalb ein Label + geben. +- `heading` ohne `level` wird `h2` (eine Seite hat meist schon eine `h1` im Titel). + +## Kurzform-Felder + +| Modul | Felder | +|---|---| +| `text` | `content` (HTML) | +| `heading` | `text`, `level` (`h1`–`h6`) | +| `button` | `text`, `url`, `new_window` (true/false) | +| `image` | `image_id` (Mediathek, setzt URL/ID/Alt), `src`, `alt`, `title`, `url` | +| `blurb` | `title`, `url`, `content`, `image_id`, `src`, `alt`, `level` | +| `cta` | `title`, `content`, `button_text`, `button_url` | +| `icon` | `url`, `title` | +| `divider` | `show`, `color` | +| `testimonial` | `author`, `job_title`, `company`, `company_url`, `content`, `portrait_id`, `portrait_url` | +| `team-member` | `name`, `position`, `content`, `image_id`, `image_url` | +| `accordion` → `accordion-item` | Eintrag: `title`, `content`, `open` | +| `tabs` → `tab` | Eintrag: `title`, `content` | +| `toggle` | `title`, `content`, `open` | +| `gallery` | `image_ids` (Liste von Anhang-IDs) | +| `slider` → `slide` | Eintrag: `title`, `content`, `button_text`, `button_url`, `image_id`, `src`, `alt` | +| `contact-form` → `contact-field` | Formular: `title`, `email`, `success_message`, `submit_text`; Feld: `title`, `id`, `type` (`input`, `email`, `text`, `checkbox`, `radio`, `select`), `required` | +| `map` → `map-pin` | Karte: `address`, `lat`, `lng`, `zoom`; Pin: `title`, `content`, `address`, `lat`, `lng` | +| `video` | `src`, `thumbnail` | +| `number-counter` | `number`, `title`, `percent` | +| `social-media-follow` → `social-media-follow-network` | Eintrag: `network` (z. B. `facebook`), `url`, `label` | +| `icon-list` → `icon-list-item` | Eintrag: `text` | +| `code` | `content` – nur, wenn kein natives Modul passt (Warnung) | + +Alle anderen Module (siehe `lit-divi-catalog`) gehen über `attrs`. Die Kurzform-Felder eines Moduls samt Pfad +zeigt `lit-divi-catalog` mit `module`. + +Zwei Felder heißen wie Knoten-Schlüssel und lassen sich deshalb beim Einfügen **nicht** in Kurzform setzen: +`type` des Kontaktformular-Felds (`type` ist dort der Modultyp) und `label` des Social-Media-Netzwerks (`label` +ist dort das Admin-Label). Beim Einfügen über `attrs` (`fieldItem.advanced.type` bzw. +`socialNetwork.innerContent` mit `label`) setzen, danach auch mit `lit-divi-update` über `set` +(`{"set": {"type": "email"}}`). + +## Einfügen, ändern, verschieben, löschen + +- `lit-divi-insert`: `nodes` + Position – `parent` (Pfad-ID, z. B. Spalte `s0.r0.c1`; optional `index`), + `before` oder `after`; ohne Position ans Seitenende. Oben auf der Seite sind nur Abschnitte erlaubt, in + Abschnitten Zeilen, in Spalten Module. +- `lit-divi-update`: `changes` = `[{"id": "s0.r0.c1.m2", "set": {"text": "Jetzt buchen"}, "preset": "CTA + primär", "label": "Hero – Button"}]` – mehrere Knoten in einem Aufruf; `null` entfernt einen Wert. Denselben + Pfad nicht zugleich über `set` und `attrs` ändern (dann zwei Änderungen senden). +- `lit-divi-move`: `id` + Position (auch in andere Zeilen oder Abschnitte). +- `lit-divi-delete`: `ids`, erst nach Rückfrage mit `confirm: true`. +- `lit/divi-duplicate-node`: Kopie direkt hinter dem Original. +- Jede Antwort enthält die neue `tree_rev` (für die nächste Änderung), `changed` mit den neuen Pfad-IDs, + den betroffenen Abschnitt als `outline`, `warnings` (Qualität, siehe unten) und `revision_id`. + +Fehler: `validation_failed` bzw. `invalid_attr_path` mit `fields` (Eingabepfad → Problem, z. B. +`nodes[0].rows[0].columns`); dann wurde nichts gespeichert. + +## Spaltenbreiten ändern + +Die Breite einer Spalte steht in `module.decoration.sizing` (Desktop: `flexType`, z. B. `8_24` = 1/3). Wer +diesen Desktop-Wert über `attrs` ersetzt, ersetzt das ganze Objekt: `flexType` immer mitschicken, sonst fällt +die Breite weg. In einer Zeile mit festen Breiten alle Spalten zusammen ändern (Summe 1). Die Angabe +`flexColumnStructure` der Zeile (Spaltenvorlage im Divi-Builder) passt das Werkzeug nicht an; nach einer +Breitenänderung zeigt der Builder dort evtl. noch die alte Vorlage; gespeichert sind die neuen Breiten (bei +Bedarf die Vorlage im Builder neu wählen). + +## Sicherheit und Speichern + +Alle Werte werden vor dem Speichern bereinigt: Texte ohne HTML, Rich-Text ohne `unfiltered_html` nur mit dem +HTML, das WordPress in Beiträgen erlaubt, Links ohne `javascript:`. +`$variable`-Verweise werden geparst, geprüft und vom Plugin neu erzeugt. Eigenes HTML, CSS und HTML-Attribute eines Moduls (`…decoration.attributes`, `…advanced.html`, +`…css…`) ändert nur, wer das Recht `unfiltered_html` hat – sonst „nur im Divi-Builder“. Unberührte Teile der +Seite bleiben byte-identisch; Ausnahme: Divi selbst normalisiert Seiten mit eigenen HTML-/Attribut-Feldern +beim Speichern (dann Warnung, dass der Inhalt beim Speichern verändert wurde – mit der neuen `tree_rev` +weiterarbeiten). + +## Warnungen + +Neue oder geänderte Knoten werden geprüft: feste Farben/Schriften, obwohl eine passende globale existiert; +Bilder ohne Alt-Text; leere Module; Sprünge in der Überschriftenhierarchie; Code-Modul. Warnungen dem Nutzer +nennen und möglichst gleich beheben. diff --git a/docs/guides/divi-structure.md b/docs/guides/divi-structure.md index 51e74f0..53e42d8 100644 --- a/docs/guides/divi-structure.md +++ b/docs/guides/divi-structure.md @@ -22,9 +22,24 @@ Spalten (`column`), Spalten Module (`text`, `heading`, `button`, …). Manche Mo des letzten Lesevorgangs. - `rev` ist davon getrennt: der Stand des ganzen Eintrags (Titel, Auszug, Status …) für `lit-content-update`. +## Ändern + +Neue Inhalte und Änderungen: siehe `divi-shortform` (Kurzform, `lit-divi-insert`, `lit-divi-update`, +`lit-divi-move`, `lit-divi-delete`), `divi-attrs` (Vollform) und `divi-placeholders`. Ablauf: + +1. `lit-divi-outline` lesen (liefert `tree_rev`), `lit-divi-design-system` für Farben, Variablen, Presets. +2. Änderung mit dieser `tree_rev` senden. Die Antwort enthält die neue `tree_rev` und die neuen Pfad-IDs – + damit direkt weiterarbeiten, ohne erneut zu lesen. +3. `rev_mismatch`: jemand hat die Seite inzwischen geändert (z. B. im Divi-Builder) → neu lesen. +4. Zum Schluss `lit-page-render-summary` prüfen und dem Nutzer die Vorschau (`preview_url`) bzw. den + Divi-Builder (`edit_url`) nennen. Der Status bleibt unverändert; veröffentlichte Seiten werden live + geändert (vorher entsteht eine Revision, `revision_id`). + ## Was nicht bearbeitet wird -- Knoten mit „nur lesbar“ (globale Module `g…`, fremde Blöcke `x…`) ändern die Divi-Werkzeuge nicht. +- Knoten mit „nur lesbar“ (globale Module `g…`, fremde Blöcke `x…`) lassen sich nur als Ganzes verschieben, + duplizieren oder löschen; ihr Inhalt wird im Divi-Builder bearbeitet (globale Module folgen später). + `lit/divi-replace-text` ändert sie nicht, sondern nennt sie in `skipped_nodes`. - Divi-4-Inhalt (Shortcodes `[et_pb_…]`) wird nicht gelesen oder geändert: Seite einmal im Divi-Builder öffnen und speichern, Divi 5 wandelt sie dabei um. - Ist das Markup beschädigt, lehnen die Werkzeuge ab (`unsupported`); die Seite im Divi-Builder öffnen und diff --git a/docs/guides/overview.md b/docs/guides/overview.md index 7cc5165..c0e55c1 100644 --- a/docs/guides/overview.md +++ b/docs/guides/overview.md @@ -23,8 +23,12 @@ Direkt sichtbar: `lit-guide`, `lit-site-status`, `lit-content-types`, `lit-conte `lit-divi-outline`, `lit-divi-node-get`, `lit-divi-catalog`, `lit-divi-design-system`, `lit-divi-insert`, `lit-divi-update`, `lit-divi-move`, `lit-divi-delete`. -Welche Tools direkt sichtbar sind, lässt sich unter Einstellungen → LIT MCP → Tools ändern (außer bei -`lit-guide`, das immer direkt bleibt). +Die Tools sind nach Integration gruppiert (Grundlagen, WordPress, Medien, Divi). Jede Gruppe hat unter +Einstellungen → LIT MCP → Tools eine eigene Einstellung (direkt/indirekt/deaktiviert), die ihre Tools übernehmen +(„wie Gruppe“). Eine Einstellung am einzelnen Tool geht vor; die Gruppe zeigt dann „gemischt“. „nur lesen“ +schaltet alle schreibenden Tools der Gruppe ab – auch solche mit eigener Einstellung. `lit-guide` bleibt immer +direkt; `lit-media-preview`/`lit-media-download` bleiben bei Gruppe „indirekt“ direkt. Ab mehr als 25 direkten +Tools warnt die Seite (Kontextkosten in claude.ai). Änderungen gelten ab der nächsten Verbindung. Über `mcp-adapter-discover-abilities` / `mcp-adapter-execute-ability` (Ability-Namen `lit/…`; in Guides und Hinweisen immer so geschrieben): @@ -37,12 +41,13 @@ Einstellungen (`lit/wp-settings-get`, `lit/wp-settings-update`), Medien (`lit/me Die `lit-divi-…`-Werkzeuge gibt es nur, wenn der Divi-5-Builder aktiv ist. Weitere Themen: `lit-guide` mit `topic` = `content-types`, `workflows`, `media`, `divi-structure`, -`divi-attrs` oder `divi-design-system`. +`divi-shortform`, `divi-attrs`, `divi-placeholders` oder `divi-design-system`. ## Rückmeldungen - Erfolg: `ok`, `summary`, `changed`, `warnings`, `rev`, `revision_id` (Revision mit dem Stand vorher, nur bei - Tools, die Inhalt überschreiben, sonst `null`), `log_id`, URLs. + Tools, die Inhalt überschreiben, sonst `null`), `log_id`, URLs. Divi-Werkzeuge zusätzlich `tree_rev` (Stand + des Seiteninhalts, Pflicht für die nächste Divi-Änderung) und `outline` (betroffener Abschnitt). - Fehler: JSON mit `code` (z. B. `validation_failed`, `rev_mismatch`, `write_failed`, `partial_write`), `message`, `hint` (und ggf. `fields`). Dem `hint` folgen. - `confirm_required`: Nutzer fragen, dann mit `confirm: true` wiederholen. diff --git a/docs/guides/workflows.md b/docs/guides/workflows.md index 7d20bb5..3b0b2d9 100644 --- a/docs/guides/workflows.md +++ b/docs/guides/workflows.md @@ -11,6 +11,25 @@ 5. Menü: `lit/menu-create` (optional mit `location` aus `lit/menu-list`), Einträge mit `lit/menu-set-items`. 6. Veröffentlichen erst, wenn der Nutzer es ausdrücklich möchte. +## Divi-Seite bauen + +1. `lit-divi-design-system` lesen (Farben, Schriften, Presets) und `lit-divi-catalog` für die Module. +2. Seite als Entwurf mit Inhalt anlegen: `lit-content-create` mit `divi` (Abschnitte in Kurzform, siehe + `divi-shortform`) – oder eine leere Seite anlegen und Abschnitte mit `lit-divi-insert` einfügen. +3. Weitere Abschnitte/Module mit `lit-divi-insert`, Anpassungen mit `lit-divi-update`; immer die `tree_rev` + der letzten Antwort mitgeben. +4. `lit-page-render-summary` prüfen, `warnings` beheben, dem Nutzer `preview_url` und `edit_url` (Divi-Builder) + nennen. Veröffentlichen nur auf Wunsch (`lit-post-publish`). + +## Text auf vielen Seiten ersetzen + +`lit/divi-replace-text` zuerst mit `dry_run: true` (Standard): zeigt Treffer je Seite mit `tree_rev`. Nach +Rückfrage mit `dry_run: false`, `targets` (post_id + tree_rev aus dem Probelauf) und `confirm: true` +ausführen; jede Seite bekommt eine eigene Revision, `results` meldet das Ergebnis je Seite. Ersetzt wird nur +sichtbarer Text (keine Links, Stile, Code oder dynamischen Inhalte); in reinen Textfeldern (Titel, +Button-Texte) werden Leerzeichen am Anfang und Ende der Ersetzung entfernt. Globale Module werden nicht +geändert, sondern in `skipped_nodes` genannt – dem Nutzer sagen, dass er sie in der Divi-Bibliothek ändern muss. + ## Menüs pflegen - `lit/menu-get` liefert den Baum und `menu_rev` (Stand des Menüs). `lit/menu-set-items` verlangt diese diff --git a/docs/superpowers/notes/2026-09-26-etappe-2b-abnahme.md b/docs/superpowers/notes/2026-09-26-etappe-2b-abnahme.md new file mode 100644 index 0000000..7802903 --- /dev/null +++ b/docs/superpowers/notes/2026-09-26-etappe-2b-abnahme.md @@ -0,0 +1,112 @@ +# Etappe 2b – Manuelle Abnahme (Divi schreiben) + +Vorbereitet von Task 10 (Hinweise, Guides, Version 0.3.0, Ende-zu-Ende-Test). Automatisch geprüft sind +bereits: + +- alle Unit-Tests (`composer test`) und Lint (`composer lint`); +- die fünf Integrationsskripte `divi-write-smoke.sh`, `divi-read-smoke.sh`, `mcp-smoke.sh`, + `wp-basis-smoke.sh` und `media-admin-smoke.sh` (alle in `tests/Integration/`). + +`divi-write-smoke.sh` prüft über den OAuth-Endpunkt: + +- Einfügen, Ändern, Verschieben, Löschen und Duplizieren; +- Ersetzen mit Probelauf; +- `lit-content-create` mit Divi-Inhalt; +- den ersten Abschnitt auf einer leeren Seite; +- einen Redakteur ohne `unfiltered_html`: unberührte Bytes bleiben gleich, und es wird weder Skript, + Event-Handler, `javascript:` noch ein eingeschleustes Attribut gespeichert oder gerendert; +- Divis eigene Speicherfilter (Seite mit eigenen HTML-Attributen). + +Details stehen im Report von Task 10 (`.superpowers/sdd/2026-09-26-etappe-2b-divi-schreiben/task-10-report.md`). + +Die folgenden Punkte lassen sich nicht automatisch prüfen, weil sie den echten Divi Visual Builder und den +claude.ai-Connector brauchen. Jan-Niclas prüft sie selbst (Spec §1.3 Nr. 2, §13 „Bearbeitbarkeit im +Visual Builder“). Abweichungen als kurze Notiz zurückmelden; sie werden Folgeaufgaben (z. B. anders +gespeicherte Spaltenbreiten, D8). + +## 1. Visual Builder: von Claude gebaute Seite + +- [ ] Dieser Auftrag in claude.ai: + „Lege eine Entwurfsseite ‚Abnahme Divi‘ an mit Hero (Überschrift, Text, Button mit Preset), einer + Zeile 1/3 + 2/3 mit Bild und Blurb, einem Akkordeon und einem Kontaktformular.“ + Erwartet: + - Claude liest vorher `lit-divi-design-system` und `lit-divi-catalog`; + - dann `lit-content-create` mit `divi` (oder eine leere Seite plus `lit-divi-insert`); + - die Antwort nennt `preview_url` und `edit_url`. +- [ ] Die Seite im Divi Visual Builder öffnen (`edit_url`) und prüfen: + - [ ] Alle Module erscheinen als **native Module**, nicht als Code-Modul. + - [ ] Die Admin-Labels folgen dem Muster „ – “, z. B. „Hero – Button“. + - [ ] Jedes Modul lässt sich anklicken, ändern und speichern, ohne Fehlermeldung des Builders. + - [ ] Die Spaltenbreiten stimmen (1/3 + 2/3), auch in der Spalteneinstellung des Builders. + - [ ] Farben aus `{{color:…}}` sind als **globale Farbe** verknüpft: der Farbwähler zeigt die globale + Farbe, nicht einen festen Hex-Wert. + - [ ] Das Button-Preset ist im Builder als Preset ausgewählt. + - [ ] Akkordeon-Einträge und Kontaktformular-Felder sind einzeln bearbeitbar. +- [ ] Eine zweite Seite nur mit `lit-divi-insert` aufbauen lassen: leere Seite anlegen, dann + „Füge einen Abschnitt ‚Start‘ mit Überschrift und Text ein“. Im Builder öffnen: der Abschnitt + erscheint normal und ist bearbeitbar (Ruling S9: Hülle `divi/placeholder` wie beim Builder). + +## 2. Visual Builder: von Claude geänderte Seite + +- [ ] Eine bestehende, im Builder gebaute Seite kopieren (`lit/post-duplicate`) und an der Kopie per + claude.ai einen Button-Text ändern, ein Modul verschieben und einen Abschnitt duplizieren lassen. +- [ ] Die Kopie im Builder öffnen und prüfen: + - [ ] Alle unveränderten Module sehen aus wie vorher (Einstellungen, Presets, globale Farben). + - [ ] Die geänderten Module sind bearbeitbar, und die Änderung ist sichtbar. + - [ ] Die Kopie eines Abschnitts heißt „