diff --git a/docs/guides/divi-attrs.md b/docs/guides/divi-attrs.md index ffe0f85..0fb25b6 100644 --- a/docs/guides/divi-attrs.md +++ b/docs/guides/divi-attrs.md @@ -41,7 +41,9 @@ Unbekannte Pfade → Fehler `invalid_attr_path` mit Vorschlägen unter `fields`. geprüft und vom Plugin neu erzeugt (siehe `divi-placeholders`). Eigenes HTML, CSS, HTML-Attribute, Interaktionen und die Lottie-Quelle (`…decoration.attributes`, `…decoration.interactions`, `…advanced.html`, `…css…`, `lottie.innerContent`) nur mit dem Recht `unfiltered_html`, sonst „nur im -Divi-Builder“. Unberührte Teile der Seite bleiben byte-identisch; Ausnahme: Divi selbst normalisiert Seiten +Divi-Builder“ – Interaktionen können im Browser beliebige HTML-Attribute und Cookies setzen, die +Lottie-Quelle lädt eine Animation von einer fremden Adresse, die Code ausführen kann. Dieselbe Grenze gilt +beim Kopieren und Einfügen gespeicherter Knoten (siehe `divi-library`). Unberührte Teile der Seite bleiben byte-identisch; Ausnahme: Divi selbst normalisiert Seiten mit eigenen HTML-/Attribut-Feldern beim Speichern – nur wenn die Seite noch nicht in Divis eigener gespeicherter Form vorliegt (z. B. importierter oder direkt in die Datenbank geschriebener Inhalt); über den Divi-Builder oder LIT MCP gespeicherte Seiten betrifft das praktisch nie (Warnung in der Antwort, neue `tree_rev` gilt). ## Pfade finden diff --git a/docs/guides/divi-design-system.md b/docs/guides/divi-design-system.md index ab092c9..6bcf720 100644 --- a/docs/guides/divi-design-system.md +++ b/docs/guides/divi-design-system.md @@ -11,6 +11,10 @@ - **Presets** (`presets`): Modul-Presets je Modul (`kind: module`, z. B. alle Button-Presets) und Gruppen-Presets (`kind: group`); `default: true` markiert das Standard-Preset eines Moduls. +Auf großen Websites eingrenzen: `only` (Liste aus `colors`, `variables`, `presets`) liefert nur diese Teile +(Schriften und Größen sind immer dabei), `module` (z. B. `"button"`) nur die Presets dieses Moduls; höchstens +200 Presets je Antwort (`notes` sagt, wenn es mehr gibt). + Regeln: 1. Vor dem Gestalten einer Seite das Designsystem lesen. diff --git a/docs/guides/divi-library.md b/docs/guides/divi-library.md new file mode 100644 index 0000000..09663dd --- /dev/null +++ b/docs/guides/divi-library.md @@ -0,0 +1,103 @@ +# Divi-Bibliothek und globale Module + +Die Divi-Bibliothek speichert Layouts, Abschnitte, Zeilen und Module zur Wiederverwendung. + +- **Normale Einträge** werden beim Einfügen kopiert; die Kopie ist danach unabhängig. +- **Globale Einträge** werden als Instanz eingefügt. Divi zeigt überall den aktuellen Inhalt des + Bibliothekseintrags: eine Änderung dort wirkt sofort auf allen Seiten mit diesem Modul – auch auf + veröffentlichten. + +## Werkzeuge + +- `lit/library-list` (über `mcp-adapter-execute-ability`): Einträge auflisten, Filter `layout_type` + (`layout`, `section`, `row`, `module`), `scope` (`normal`, `global`), `search` (Titel), `category` + (Name), weiterblättern mit `cursor`. Gelistet werden nur Einträge, die das Konto bearbeiten darf. Mit `id`: + ein Eintrag im Detail – Knoten-Übersicht (`outline`), `tree_rev` und bei globalen Einträgen die Seiten, die + ihn zeigen (`affected`, `affected_count`). +- `lit-library-insert`: einen Eintrag in eine Divi-Seite einfügen. `mode: "global"` (Standard bei globalen + Einträgen) fügt eine verknüpfte Instanz ein, `mode: "copy"` (Standard sonst) eine unabhängige Kopie. + Position wie bei `lit-divi-insert` (`parent`, `before`, `after`, ohne Angabe ans Seitenende); `tree_rev` + der Zielseite ist Pflicht. Die Kopie eines globalen Eintrags ist vollständig gelöst (auch darin enthaltene + globale Module); in der Kopie eines normalen Eintrags bleiben globale Module verknüpft. `mode: "global"` + geht nur bei globalen Einträgen mit genau einem Abschnitt, einer Zeile oder einem Modul ohne globale Module + darin – sonst `mode: "copy"` verwenden. Nur aktive Einträge (nicht im Papierkorb) lassen sich einfügen. +- `lit/library-save`: einen Abschnitt, eine Zeile oder ein Modul als neuen Eintrag speichern (`post_id`, + `tree_rev`, Pfad-ID `id`, `title`, `scope: "normal"` oder `"global"`, vorhandene `categories`/`tags`). Der + Knoten auf der Seite bleibt eine eigenständige Kopie – um ihn zu verknüpfen, ihn durch eine Instanz + ersetzen (siehe Ablauf unten). Ein Knoten, der selbst ein globales Modul ist oder eines enthält, lässt sich + nicht als globaler Eintrag speichern. +- `lit/divi-node-copy`: einen Knoten von einem Eintrag an eine Position eines anderen kopieren + (`source_post_id`, `source_id`, `source_tree_rev` aus `lit-divi-outline` der Quelle – Pflicht, weil + Pfad-IDs nur für diesen Stand gelten; Ziel mit `post_id`, `tree_rev`, Position). Quelle und Ziel dürfen + Seiten oder Bibliothekseinträge sein. Die Kopie ist byte-gleich; globale Module bleiben verknüpft. +- Die Divi-Werkzeuge arbeiten auch auf Bibliothekseinträgen: `lit-divi-outline`, `lit-divi-node-get`, + `lit-divi-insert`, `lit-divi-update`, `lit-divi-move`, `lit-divi-delete`, `lit/divi-duplicate-node` und + `lit/divi-replace-text` mit der ID des Eintrags als `post_id`. + +## Globale Module erkennen und ändern + +1. In `lit-divi-outline` einer Seite erscheinen Instanzen als z. B. `g0 section "Kontakt" [global 1058] + (nur lesbar)`; `lit-divi-node-get` nennt unter `global` die ID des Bibliothekseintrags. Auf der Seite + lassen sie sich nur als Ganzes verschieben, duplizieren oder löschen. +2. `lit-divi-outline` mit `post_id` = ID des Eintrags lesen und die Änderung wie auf einer Seite senden. +3. Ohne `confirm` ist jede Änderung eines globalen Eintrags ein Probelauf: Antwort `confirm_required` mit + `affected` (betroffene Seiten; Titel nicht lesbarer Seiten als „(nicht lesbar)“) und `affected_count`; + gespeichert wird nichts. +4. Dem Nutzer die betroffenen Seiten nennen und fragen. Erst nach Zustimmung dieselbe Änderung mit + `confirm: true` wiederholen (bei `lit-divi-delete` gilt dasselbe `confirm`). +5. Vorher entsteht eine Revision des Eintrags (`revision_id`); sind Revisionen abgeschaltet, eine + Sicherungskopie im Papierkorb (`backup_id`). Schlägt das Speichern danach fehl, nennt der Fehler die + `backup_id`. Nach dem Speichern wird Divis CSS-Cache für alle Seiten geleert. + +Die Bestätigung wird abgelehnt (`forbidden`), wenn das Konto einen veröffentlichten, privaten oder geplanten +Eintrag, der das Modul zeigt, nicht bearbeiten darf – schon der Probelauf warnt davor und nennt diese IDs in +`blocked_ids` (Entwürfe blockieren nicht). Sind Revisionen für die Bibliothek abgeschaltet, lehnt das +Werkzeug die Änderung außerdem ab (`unsupported`), wenn der Papierkorb deaktiviert ist oder das Konto kein +`unfiltered_html` hat (die Sicherungskopie wäre dann nicht verlustfrei). + +`lit/divi-replace-text` nimmt Bibliothekseinträge als `targets` (ID und `tree_rev` aus `lit-divi-outline`; +der Probelauf listet nur Seiten des Inhaltstyps): normale Einträge werden gespeichert, globale nie – ihr +Ergebnis nennt stattdessen die betroffenen Seiten; die Änderung dann nach Rückfrage mit `lit-divi-update` +und `confirm: true` vornehmen. + +Regeln für Bibliothekseinträge: ein Abschnitts-, Zeilen- oder Modul-Eintrag behält genau einen Knoten dieses +Typs (die Instanzen auf den Seiten erwarten ihn); ein Layout-Eintrag enthält nur Abschnitte; kein Eintrag +wird leer; ein globaler Eintrag enthält keine globalen Module. Nur aktive Einträge lassen sich ändern. + +`lit-page-render-summary` zeigt globale Module nicht (über die Schnittstelle rendert Divi sie nicht) und nennt +sie in `notes`; ihren Inhalt mit `lit-divi-outline` und der ID lesen. + +## Rechte + +- WordPress: die Bibliothek nutzen = Beiträge bearbeiten dürfen; einen Eintrag lesen oder ändern = diesen + Eintrag bearbeiten dürfen; neue Einträge anlegen = Beiträge veröffentlichen dürfen (Bibliothekseinträge + sind immer aktiv). +- Divi → Rollen-Editor: „Divi-Bibliothek“, „In der Bibliothek speichern“ (anlegen und ändern), „Aus der + Bibliothek hinzufügen“ (einfügen), „Globale Bibliothekselemente bearbeiten“ (globale Einträge anlegen und + ändern). Fehlt „Divi-Bibliothek“, gilt jeder Eintrag als nicht vorhanden (`not_found`) und die Liste + antwortet mit `forbidden`; fehlt eines der anderen, antwortet das Werkzeug mit `forbidden` und diesem + Hinweis. +- Einstellungen → LIT MCP → Tools: Gruppe „Divi-Bibliothek“ auf „nur lesen“ sperrt jeden Schreibzugriff auf + Bibliothekseinträge, auch über die Divi-Werkzeuge; deaktiviert gilt jeder Eintrag als nicht vorhanden. + `lit-library-insert` und `lit/divi-node-copy` sind außerdem gesperrt, wenn `lit-divi-insert` gesperrt ist. +- Ohne das Recht `unfiltered_html` überträgt LIT MCP beim Kopieren, Einfügen und Speichern (`lit/divi-node-copy`, + `lit-library-insert`, `lit/library-save`) nur Knoten, die das Konto auch selbst schreiben dürfte. Abgelehnt + werden – „nur im Divi-Builder“ – Knoten mit eigenem HTML, CSS oder HTML-Attributen, Interaktionen, einer + Lottie-Quelle, dem Code-Modul, fremden Blöcken oder Freitext zwischen den Blöcken, Text mit HTML, das der + HTML-Filter von WordPress verändern würde, und `$variable`-Verweisen, die die normale Prüfung nicht + bestehen (z. B. HTML davor/danach). Das ist strenger als Divi selbst; die Antwort nennt jede Fundstelle + (`validation_failed`), gespeichert wird nichts. Relative Links (`kontakt/`, `/pfad`, `#anker`) bleiben + kopierbar. + +## Ablauf: globale Module vorschlagen + +1. Die Seiten lesen (`lit-divi-outline`) und wiederkehrende Abschnitte suchen (gleiche Admin-Labels oder + Texte, z. B. Kontakt, Öffnungszeiten, Call-to-Action). +2. Dem Nutzer vorschlagen, welche davon globale Module werden sollen, und erklären: eine Änderung wirkt + danach auf allen Seiten. +3. Nach Zustimmung den Abschnitt einer Seite mit `lit/library-save` und `scope: "global"` speichern. +4. Auf jeder Seite (auch der ersten) die Instanz mit `lit-library-insert` direkt vor dem bisherigen Abschnitt + einfügen und den bisherigen Abschnitt nach Rückfrage mit `lit-divi-delete` entfernen. +5. Den Nutzer bitten, das Ergebnis im Divi-Builder anzusehen. + +Unterscheiden sich die Abschnitte in Details, vorher mit dem Nutzer klären, welche Fassung gilt. diff --git a/docs/guides/divi-placeholders.md b/docs/guides/divi-placeholders.md index 571e0e9..8145596 100644 --- a/docs/guides/divi-placeholders.md +++ b/docs/guides/divi-placeholders.md @@ -12,6 +12,7 @@ sich auch der Button. | `{{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}}` | +| `{{link:}}` | Link auf einen anderen Eintrag (Seite, Beitrag …), z. B. `{{link:42}}` – nur in Link-Feldern; Divi setzt beim Anzeigen die aktuelle Adresse ein, also auch für Entwürfe, die erst später veröffentlicht werden | | `"preset": ""` | Modul-Preset (kein Platzhalter, sondern eigenes Feld) | Beispiele: @@ -30,9 +31,19 @@ Unbekannte Namen lehnt das Werkzeug ab und nennt die vorhandenen; ist ein Name d 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). +In Link-Feldern (`url`, `button_url` …) für interne Links immer `{{link:}}` verwenden statt fester +Adressen wie `/?page_id=…`. Der Eintrag muss existieren und für das Konto lesbar sein; Einträge im Papierkorb, +automatische Entwürfe und Medien (Anhänge – dafür die Adresse aus der Mediathek) lehnt das Werkzeug ab, +ebenso `{{link:…}}` außerhalb von Link-Feldern. Solange das Ziel ein Entwurf oder privat ist, zeigt Divi +Besuchern nur die Adresse `?page_id=` (kein Titel); nach dem Veröffentlichen die normale Adresse. Sonst +nimmt ein Link-Feld jeden dynamischen Inhalt an; sinnvoll sind nur Werte, die eine Adresse ergeben +(`{{post:url}}`, ein Feld mit einer URL, eine Link-Variable). + +Welche dynamischen Quellen und Felder es für einen Inhaltstyp gibt, liefert `lit/divi-dynamic-sources` +(über `mcp-adapter-execute-ability`): Divis Quellen mit Platzhalter und die Felder, die sich als +`{{field:…}}` eignen. Gelistet werden nur textartige Felder; Beziehungs- und Dateifelder (Divi zeigt sie nur +als IDs), Tabellen-Felder und Felder unbekannten Typs stehen mit Grund unter `omitted`. Bei Auswahlfeldern +zeigt Divi den gespeicherten Wert, nicht die Beschriftung. ## `$variable`-Werte diff --git a/docs/guides/divi-shortform.md b/docs/guides/divi-shortform.md index fabee59..f933779 100644 --- a/docs/guides/divi-shortform.md +++ b/docs/guides/divi-shortform.md @@ -107,7 +107,9 @@ Bedarf die Vorlage im Builder neu wählen). 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, HTML-Attribute, Interaktionen und die Lottie-Quelle eines Moduls (`…decoration.attributes`, -`…decoration.interactions`, `…advanced.html`, `…css…`, `lottie.innerContent`) ändert nur, wer das Recht `unfiltered_html` hat – sonst „nur im Divi-Builder“. Unberührte Teile der +`…decoration.interactions`, `…advanced.html`, `…css…`, `lottie.innerContent`) ändert nur, wer das Recht `unfiltered_html` hat – sonst „nur im Divi-Builder“ (Interaktionen können im +Browser beliebige HTML-Attribute und Cookies setzen, die Lottie-Quelle lädt Animationen von fremden Adressen, +die Code ausführen können). Unberührte Teile der Seite bleiben byte-identisch; Ausnahme: Divi selbst normalisiert Seiten mit eigenen HTML-/Attribut-Feldern beim Speichern – nur wenn die Seite noch nicht in Divis eigener gespeicherter Form vorliegt (z. B. importierter oder direkt in die Datenbank geschriebener Inhalt); über den Divi-Builder oder LIT MCP gespeicherte Seiten betrifft das praktisch nie (dann Warnung, dass der Inhalt beim Speichern verändert wurde – mit der neuen `tree_rev` weiterarbeiten). diff --git a/docs/guides/divi-structure.md b/docs/guides/divi-structure.md index 53e42d8..1a70324 100644 --- a/docs/guides/divi-structure.md +++ b/docs/guides/divi-structure.md @@ -38,8 +38,10 @@ Neue Inhalte und Änderungen: siehe `divi-shortform` (Kurzform, `lit-divi-insert ## Was nicht bearbeitet wird - 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`. + duplizieren oder löschen. Globale Module zeigt die Übersicht mit `[global ]`: ihren Inhalt im + Bibliothekseintrag ändern (`lit-divi-outline` mit `post_id` = ID; Ablauf mit Probelauf und `confirm` siehe + `lit-guide` topic `divi-library`). `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 @@ -49,4 +51,5 @@ Neue Inhalte und Änderungen: siehe `divi-shortform` (Kurzform, `lit-divi-insert `lit-page-render-summary` rendert den Inhaltsbereich wie im Frontend und listet Überschriften, Texte, Links und Bilder samt Warnungen (Sprünge in der Überschriftenhierarchie, fehlende Alt-Texte, Links ohne Ziel). -Header, Footer und Theme-Builder-Vorlagen sind nicht enthalten. +Header, Footer und Theme-Builder-Vorlagen sind nicht enthalten; globale Module ebenfalls nicht (über die +Schnittstelle rendert Divi sie nicht) – `notes` nennt sie mit ihrer ID. diff --git a/docs/guides/overview.md b/docs/guides/overview.md index 29aad7e..a41a34b 100644 --- a/docs/guides/overview.md +++ b/docs/guides/overview.md @@ -36,12 +36,16 @@ Status (`lit/post-unpublish`, `lit/post-schedule`, `lit/post-trash`), Kopien (`l `lit/post-replace-with-copy`), Revisionen (`lit/revisions-list`, `lit/revision-restore`), Menüs (`lit/menu-list`, `lit/menu-get`, `lit/menu-create`, `lit/menu-set-items`, `lit/menu-assign-location`), Einstellungen (`lit/wp-settings-get`, `lit/wp-settings-update`), Medien (`lit/media-get`, `lit/media-upload`, -`lit/media-update`, `lit/media-delete`), Divi (`lit/divi-duplicate-node`, `lit/divi-replace-text`, `lit/divi-node-copy`, `lit/divi-dynamic-sources`), Divi-Bibliothek (`lit/library-list`, `lit/library-save`). +`lit/media-update`, `lit/media-delete`), Divi (`lit/divi-duplicate-node`, `lit/divi-replace-text`, +`lit/divi-node-copy`, `lit/divi-dynamic-sources`), Divi-Bibliothek (`lit/library-list`, `lit/library-save`). -Die `lit-divi-…`-Werkzeuge gibt es nur, wenn der Divi-5-Builder aktiv ist. +Die `lit-divi-…`-Werkzeuge gibt es nur, wenn der Divi-5-Builder aktiv ist. Sie arbeiten auch auf Einträgen +der Divi-Bibliothek (ID als `post_id`); globale Module: `lit-guide` topic `divi-library`. Weitere Themen: `lit-guide` mit `topic` = `content-types`, `workflows`, `media`, `divi-structure`, -`divi-shortform`, `divi-attrs`, `divi-placeholders` oder `divi-design-system`. +`divi-shortform`, `divi-attrs`, `divi-placeholders`, `divi-design-system` oder `divi-library`. + +Für den Einstieg liefert `lit-guide` mit dem Thema „all“ alle Themen in einem Aufruf. ## Rückmeldungen diff --git a/docs/guides/workflows.md b/docs/guides/workflows.md index 7ae6496..87734f8 100644 --- a/docs/guides/workflows.md +++ b/docs/guides/workflows.md @@ -22,6 +22,13 @@ 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`). +## Bibliothek und globale Module + +Vorhandene Abschnitte aus der Divi-Bibliothek zuerst suchen (`lit/library-list`) und mit `lit-library-insert` +einfügen, statt sie neu zu bauen. Einen gelungenen Abschnitt für später speichern: `lit/library-save`. +Abschnitte zwischen Seiten kopieren: `lit/divi-node-copy`. Globale Module ändern und neue vorschlagen: +`lit-guide` topic `divi-library`. + ## Text auf vielen Seiten ersetzen `lit/divi-replace-text` zuerst mit `dry_run: true` (Standard): zeigt Treffer je Seite mit `tree_rev`. Nach @@ -29,7 +36,8 @@ Rückfrage mit `dry_run: false`, `targets` (post_id + tree_rev aus dem Probelauf 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. +geändert, sondern in `skipped_nodes` genannt – sie im Bibliothekseintrag ändern (`lit-guide` topic +`divi-library`). ## Menüs pflegen diff --git a/docs/superpowers/notes/2026-09-27-etappe-3-entscheidungen-entwurf.md b/docs/superpowers/notes/2026-09-27-etappe-3-entscheidungen-entwurf.md index 7029bb0..f13c78d 100644 --- a/docs/superpowers/notes/2026-09-27-etappe-3-entscheidungen-entwurf.md +++ b/docs/superpowers/notes/2026-09-27-etappe-3-entscheidungen-entwurf.md @@ -160,3 +160,62 @@ Quellen der Web-Recherche: [Divi AI Agent – Ankündigung](https://www.elegantt - F3 Reihenfolge: erst 3a Bibliothek, dann 3b Theme Builder. - F4 Pods-Beziehungs-/Dateifelder: als dynamische Quelle nur textartige Felder anbieten; andere mit Hinweis auslassen. - F5 Testdaten: selbst erzeugen („Probier es selbst“) – über Divis eigene Speicherwege (Builder-REST-Controller/Services im Prozess), als „[Fixture] …“ markiert, danach als Fixtures ins Plugin exportiert. Pods ist lokal deaktiviert; Aktivierung für 3b beim Benutzer anfragen. + +## 6. Umsetzung Etappe 3a (Plan 2026-09-27-etappe-3a-bibliothek.md) + +- E5 präzisiert durch die Builder-Fixtures: Instanzen werden wie im Visual Builder erzeugt – `localAttrs` = + vollständiger Schnappschuss der Wurzel-Attribute (oberste Schlüssel sortiert), Kinder mit `globalParent`, + ohne Kinder selbstschließend – statt der minimalen Form ohne `localAttrs`. Byte-Test gegen + `page--globale-instanzen.html`. +- Neuer Befund 9: Bibliothekseinträge aus Divis Dialog haben `\r\n` zwischen Blöcken (Formular-Upload); + `LibraryContent::load()` vereinheitlicht das vor jeder Übernahme (undurchsichtige Blöcke bleiben unberührt). +- Kopie eines normalen Eintrags mit globalen Instanzen: Instanzen bleiben verknüpft (wie Divis `/load`); + entglobalisiert wird nur der Inhalt globaler Einträge (Divis Schadensbegrenzung, F10). `lit/library-save` + mit `scope: "normal"` übernimmt enthaltene Instanzen ebenfalls als Verweise. `mode: "global"` nur für + globale Einträge mit genau einer Wurzel ohne globale Module (P11: nie verschachtelte Instanzen). +- E6 erweitert: `StoredNodeGuard` prüft neben den S7/S26-Pfaden und dem Code-Modul auch fremde Blöcke, + Freitext, nicht lesbare Blöcke, kses-instabilen Rich-Text (P3) und `$variable`-Verweise (Ablehnung, wenn + `canonical()` sie für das Ziel ablehnt oder ihre Einstellungen verändern würde) – Grund: R2-Befund 1 + (before/after nach dem Autor des Ziel-Posts). Lesbare globale Instanzen werden geprüft (localAttrs und + Schnappschuss), nicht abgelehnt (P15). Strenger als Divi; sichtbare Ablehnung. URL-Werte: `url($v) === + trim($v)` oder relativer Link ohne Schema (P17/P18) – `kontakt/`, `/pfad`, `#anker` bleiben kopierbar. +- Builder-only erweitert (S7-Gate, gilt auch für Seiten): `decoration.interactions` (P16 – der Effekt + „Attribut“ setzt im Browser beliebige Attribute, z. B. `onclick`; „Cookie“ setzt Cookies) und + `lottie.innerContent` (P19 – `src` lädt fremdes JSON, lottie-web wertet Ausdrücke aus). Offen für + Etappe 4: Divi-Presets können beides tragen; Preset-Schreibwege brauchen dasselbe Gate. +- E3 ergänzt: neue Einträge zusätzlich nur mit `publish_posts` (Bibliothekseinträge sind immer `publish`); + `scope: "global"` braucht zusätzlich `edit_global_library` (P7). Ohne das Divi-Recht „Divi-Bibliothek“ + (oder mit deaktivierter Gruppe, P9) ist jede Bibliotheks-ID `not_found`, byte-gleich mit einer fehlenden ID + (P12); ohne `edit_post` auf dem Eintrag `forbidden` ohne Titel. `lit/library-list` listet nur Einträge mit + `edit_post` und liest höchstens 500 Zeilen je Aufruf. +- E9 umgesetzt mit: `lit/divi-node-copy` und `lit/divi-dynamic-sources` in der Gruppe „Divi“; die Gruppe + „Divi-Bibliothek“ sperrt als Ganzes („nur lesen“/deaktiviert) auch Schreibzugriffe der Divi-Werkzeuge auf + Bibliothekseinträge (`ExposurePolicy::groupWritable`). `lit-library-insert` und `lit/divi-node-copy` folgen + zusätzlich dem Zustand von `lit/divi-insert` (M2). Offen (P13, Schlusswelle): bei deaktivierter Gruppe + nennen Outline/node-get/Render-Auszug einer Seite noch die ID globaler Module. +- Antwort F2: jede Änderung eines globalen Eintrags ist zuerst ein Probelauf (auch ohne veröffentlichte + Instanzen); `lit-divi-delete` nutzt dasselbe `confirm`, sein `confirm_required` nennt dann ebenfalls die + betroffenen Seiten. P8a: die Bestätigung wird abgelehnt, wenn der Benutzer einen Eintrag mit Status + `publish`, `private` oder `future`, der den Eintrag zeigt, nicht bearbeiten darf (auch TB-Layouts und andere + Bibliothekseinträge); Entwürfe blockieren nicht. Der Probelauf nennt solche IDs vorab in `blocked_ids` + (P14). Revisionen aus: abgelehnt ohne `unfiltered_html` (die Sicherung liefe durch kses) oder bei + deaktiviertem Papierkorb (P9); scheitert das Speichern nach einer Sicherung, nennt der Fehler `backup_id` + (P14). Cache-Leerung für alle Seiten und den Theme Builder. +- P1: `lit/divi-replace-text` speichert normale Bibliothekseinträge über `DiviWriter::commit()`; globale nie + (die Ziele tragen kein `confirm`) – das Ergebnis nennt die betroffenen Seiten und verweist auf + `lit-divi-update` mit `confirm`. +- Bibliothekseinträge bekommen keine Divi-Flags (Befund 4); `_et_pb_row_layout` wird nicht geschrieben (Befund 5). +- E13a: `{{link:}}` nur in URL-Feldern; Ziel muss existieren, `read_post` bestehen, nicht Papierkorb, + `auto-draft` oder `inherit` sein – Anhänge sind damit ausgeschlossen (P10). Entwürfe und private Ziele + rendert Divi für Besucher als `?page_id=` (nur die ID wird sichtbar, Preflight). +- F4/E12: `lit/divi-dynamic-sources` listet nur textartige Felder; Beziehungs-/Dateifelder („nur IDs“), + Tabellen-Speicher und unbekannte Feldtypen (P9) stehen unter `omitted`; Auswahlfelder zeigen den + gespeicherten Wert, nicht die Beschriftung. Der Beispiel-Post ist nur einer, den der Benutzer bearbeiten + darf. +- E15: Adapter `DiviRoles`, `DiviLibraryStore`, Prüfung `DiviCompatibility` in `lit-site-status` + (`problems` je Komponente). +- E13d umgesetzt als Hinweis in `notes`; eine eigene Expansion globaler Module im Auszug unterbleibt. +- Tests: die Unit-Suite läuft mit `memory_limit` 512M (`phpunit.xml.dist` und `composer test`), weil der + Divi-Katalog beim Standard von 128M nicht mehr in den Speicher passt. +- Server-Instructions: Zeile „Divi-Bibliothek: …“ nur bei aktiver, beschreibbarer Gruppe; MCP-Prompts gibt es + noch nicht, der Ablauf „globale Module vorschlagen“ steht im Guide `divi-library` (E14). diff --git a/docs/superpowers/specs/2026-09-25-wp-lit-mcp-design.md b/docs/superpowers/specs/2026-09-25-wp-lit-mcp-design.md index fe3b4a8..8ec3f0b 100644 --- a/docs/superpowers/specs/2026-09-25-wp-lit-mcp-design.md +++ b/docs/superpowers/specs/2026-09-25-wp-lit-mcp-design.md @@ -114,7 +114,7 @@ Ob dieser Aufbau stabil funktioniert, entscheidet Etappe 0 (§12). - **Direkte Tools (~20):** mit vollem Schema sofort sichtbar; nur direkte Tools können Bilder (`ImageContent`) zurückgeben. Standard-Set: `lit/guide`, `lit/content-types`, `lit/content-query`, `lit/content-get`, `lit/content-create`, `lit/content-update`, `lit/post-publish`, `lit/media-search`, `lit/media-preview`, `lit/media-upload-from-url`, `lit/divi-outline`, `lit/divi-node-get`, `lit/divi-insert`, `lit/divi-update`, `lit/divi-move`, `lit/divi-delete`, `lit/divi-design-system`, `lit/divi-catalog`, `lit/library-insert`, `lit/page-render-summary`. -- **Stand nach Etappe 2 (Entscheidung D2, 2026-09-26):** 21 direkte Tools – das Standard-Set oben ohne `lit/library-insert` (kommt mit Etappe 3), dazu `lit/site-status` (leeres Eingabeschema, Anker der Verbindungstests) und `lit/media-download` (eingebettete Ressource, funktioniert nur direkt). `lit/divi-duplicate-node` und `lit/divi-replace-text` sind indirekt. Mit Etappe 3 sind es 22; das Budget wird dort erneut geprüft (Kosten entstehen vor allem durch große Eingabeschemas, nicht durch die Zahl). +- **Stand nach Etappe 2 (Entscheidung D2, 2026-09-26):** 21 direkte Tools – das Standard-Set oben ohne `lit/library-insert` (kommt mit Etappe 3), dazu `lit/site-status` (leeres Eingabeschema, Anker der Verbindungstests) und `lit/media-download` (eingebettete Ressource, funktioniert nur direkt). `lit/divi-duplicate-node` und `lit/divi-replace-text` sind indirekt. Mit Etappe 3 sind es 22; das Budget wird dort erneut geprüft (Kosten entstehen vor allem durch große Eingabeschemas, nicht durch die Zahl). **Stand nach Etappe 3a:** 22 direkte Tools (dazu `lit/library-insert`); indirekt neu `lit/library-list`, `lit/library-save`, `lit/divi-node-copy`, `lit/divi-dynamic-sources`. Neue Tool-Gruppe „Divi-Bibliothek“ (`lit/library-*`); `lit/divi-node-copy` und `lit/divi-dynamic-sources` gehören zur Gruppe „Divi“. - **Alle übrigen Abilities:** über die Meta-Tools des Adapters (`discover-abilities`, `get-ability-info`, `execute-ability`). - In den Einstellungen änderbar, welche Abilities direkt, indirekt oder deaktiviert sind. - Ability-Namen: `lit/-`. Der Adapter bildet daraus Tool-Namen (`lit--`). @@ -174,7 +174,7 @@ Seiten, Theme-Builder-Layouts (`et_header_layout`, `et_body_layout`, `et_footer_ - **Invariante:** Parse → Serialize ohne Änderung ergibt byte-identischen Inhalt. Fremde/unbekannte Blöcke bleiben unberührt. Ausnahme beim Speichern (nicht im BlockTree): Divi selbst normalisiert Seiten mit eigenen HTML-/Attribut-Feldern beim Speichern (`module.decoration.attributes`, `module.advanced.html` mit `htmlBefore`/`htmlAfter`/`elementType`) – Divi parst und serialisiert dann die ganze Seite neu, was nur Bytes ändert, die noch nicht in Divis `serialize_blocks()`-Form vorlagen; gemeldet als `CHANGED_ON_SAVE` (Ruling S7). - Reines PHP ohne WordPress-Abhängigkeit (vollständig unit-testbar). - Attributwerte mit `$variable(...)$` werden beim Serialisieren wie von Divi erwartet escaped (`"` → `"`). -- Umsetzung (D3): eigener Tokenizer mit dem Delimiter-Muster von `WP_Block_Parser` statt `parse_blocks()` – ohne WordPress testbar, jedes Byte zwischen den Delimitern bleibt erhalten. Knoten mit `globalModule`, `divi/global-layout` oder nicht dekodierbaren Attributen sind undurchsichtig: sie werden nicht betreten, nur als Ganzes verschoben, dupliziert oder gelöscht (Bearbeitung ab Etappe 3). Unbalanciertes Markup wird abgelehnt, nie repariert. +- Umsetzung (D3): eigener Tokenizer mit dem Delimiter-Muster von `WP_Block_Parser` statt `parse_blocks()` – ohne WordPress testbar, jedes Byte zwischen den Delimitern bleibt erhalten. Knoten mit `globalModule`, `divi/global-layout` oder nicht dekodierbaren Attributen sind undurchsichtig: sie werden nicht betreten, nur als Ganzes verschoben, dupliziert oder gelöscht (bearbeitet werden globale Module seit Etappe 3a im Bibliothekseintrag, E2). Unbalanciertes Markup wird abgelehnt, nie repariert. ### 5.3 Adressierung und optimistische Sperre @@ -216,6 +216,7 @@ Seiten, Theme-Builder-Layouts (`et_header_layout`, `et_body_layout`, `et_footer_ | `{{font:heading}}`, `{{font:body}}` | Theme-Schriften (`--et_global_heading_font` / `--et_global_body_font`) | | `{{post:title}}`, `{{post:excerpt}}`, `{{post:date}}`, … | Dynamic Content (Post-Daten) | | `{{field:}}` | Dynamic Content `custom_meta_` (Pods/Meta) | +| `{{link:}}` | interner Link: Dynamic Content `post_link_url_` mit `post_id` (nur Link-Felder; Ziel muss für den Benutzer lesbar sein, nicht im Papierkorb, kein automatischer Entwurf, kein Anhang; Entwürfe/private Ziele rendert Divi als `?page_id=`; Etappe 3a, E13a) | | `"preset": ""` | `modulePreset: [""]` | Unbekannte Namen → Fehler mit Liste der vorhandenen. @@ -249,7 +250,7 @@ Kurzform setzt Admin-Labels automatisch (` – `), sofern nich | `lit/divi-node-get` | lesen | vollständige Attribute eines Knotens (Vollform) | | `lit/divi-catalog` | lesen | Module, Kurzform-Felder, wichtige Attributpfade; Detail pro Modul | | `lit/divi-design-system` | lesen | Farben, Variablen, Presets, Theme-Schriften/-Größen | -| `lit/divi-dynamic-sources` | lesen | verfügbare Dynamic-Content-Quellen für einen Post-Typ (über `DynamicContentOptions::get_options` mit einem Beispiel-Post des Typs) – Etappe 3, mit dem Theme Builder (D6) | +| `lit/divi-dynamic-sources` | lesen | verfügbare Dynamic-Content-Quellen für einen Post-Typ (über `DynamicContentOptions::get_options` mit einem Beispiel-Post des Typs) – Etappe 3a (E12, E14); nur textartige Felder (Antwort F4): Beziehungs-, Datei-, Tabellen- und unbekannte Felder stehen mit Grund unter `omitted`, Auswahlfelder liefern den gespeicherten Wert; Beispiel-Post nur einer, den der Benutzer bearbeiten darf | | `lit/page-render-summary` | lesen | gerenderte Seite als strukturierter Auszug (Überschriften, Texte, Links, Bilder+Alt); Inhaltsbereich, im Prozess über `the_content` gerendert (ohne Header/Footer/Theme Builder); Teil der WordPress-Integration, funktioniert auch ohne Divi (D5) | | `lit/divi-insert` | schreiben | Knoten (Kurz-/Vollform, auch ganze Abschnitte) an Position `parent`/`before`/`after` einfügen | | `lit/divi-update` | schreiben | Werte setzen/entfernen (Kurz- oder Vollform) | @@ -257,10 +258,10 @@ Kurzform setzt Admin-Labels automatisch (` – `), sofern nich | `lit/divi-delete` | schreiben, destruktiv | Knoten entfernen | | `lit/divi-duplicate-node` | schreiben | Knoten duplizieren | | `lit/divi-replace-text` | schreiben | Text seitenübergreifend (je Inhaltstyp) ersetzen, `dry_run` (Standard `true`) liefert Treffer je Seite mit `tree_rev`; ausgeführt wird nur auf diesen `targets` mit `confirm: true`, jede Seite mit eigener Revision (D10) | -| `lit/library-list`, `lit/library-get` | lesen | Library-Einträge nach Typ (`layout_type`) und Scope | -| `lit/library-save` | schreiben | Knoten als Library-Eintrag speichern (normal oder global) | -| `lit/library-insert` | schreiben | Library-Eintrag als Kopie oder globale Instanz einfügen | -| `lit/divi-node-copy` | schreiben | Knoten von Seite A nach Seite B kopieren | +| `lit/library-list` | lesen | Einträge nach Typ (`layout_type`) und Scope, mit `cursor`; mit `id` Detail inkl. Knoten-Übersicht und betroffener Seiten (ersetzt `lit/library-get`, E9); nur Einträge mit `edit_post` | +| `lit/library-save` | schreiben | Knoten als Library-Eintrag speichern (normal oder global; global braucht Divis „Globale Bibliothekselemente bearbeiten“, P7); Knoten auf der Seite bleibt unverändert; StoredNodeGuard (E6) | +| `lit/library-insert` | schreiben | Library-Eintrag als Kopie oder globale Instanz im Format des Visual Builders (`localAttrs`-Schnappschuss, `globalParent`) einfügen; direkt | +| `lit/divi-node-copy` | schreiben | Knoten von Eintrag A nach Eintrag B kopieren (Seiten und Bibliothekseinträge; byte-gleich, `source_tree_rev` Pflicht, S7/S26-Prüfung E6) | | `lit/library-make-global` | schreiben | Knoten in globales Modul umwandeln; optional gleichartige Vorkommen ersetzen | | `lit/library-find-similar` | lesen | ähnliche Abschnitte seitenübergreifend (Struktur-Fingerabdruck: Modultypen, Aufbau, Presets) | | `lit/tb-list` | lesen | Vorlagen, Bedingungen, Layouts | @@ -401,15 +402,17 @@ Dynamisch pro Seite erzeugt (Server-Beschreibung → `instructions`), ca. 15 Zei - aktive Integrationen und Post-Typen, - Kernregeln: vor dem Schreiben `lit/divi-outline` und `lit/divi-design-system` lesen; Variablen/Presets vor festen Werten; native Module vor Code-Modul; Status nie ändern ohne ausdrücklichen Wunsch; immer `rev` (bei Divi-Änderungen `tree_rev`) mitgeben, - Verweis auf `lit/guide`. +- Etappe 3a: Zeile „Divi-Bibliothek: …“ (globale Module im Bibliothekseintrag ändern, Probelauf und `confirm: true`, Guide `divi-library`), nur wenn die Gruppe „Divi-Bibliothek“ aktiv und beschreibbar ist. ### 9.2 `lit/guide(topic)` Direktes Tool; Anleitungen als Markdown in `docs/guides/`, mit dem Plugin versioniert, per Filter `lit_mcp_guides` erweiterbar. -Themen: `overview`, `divi-structure`, `divi-shortform`, `divi-attrs`, `divi-placeholders`, `divi-design-system`, `theme-builder`, `content-types`, `workflows`. +Themen: `overview`, `divi-structure`, `divi-shortform`, `divi-attrs`, `divi-placeholders`, `divi-design-system`, `divi-library`, `theme-builder`, `content-types`, `media`, `workflows`. Thema `all` liefert alle Themen in einem Aufruf (Etappe 3a). ### 9.3 MCP-Prompts `corporate-design-uebernehmen`, `neue-website-aufsetzen`, `seite-pruefen`, `globale-module-vorschlagen`, `custom-post-type-vorlage`. +(Stand Etappe 3a: noch keine MCP-Prompts im Plugin; `globale-module-vorschlagen` steht als Ablauf im Guide `divi-library`.) ## 10. Sicherheit diff --git a/readme.txt b/readme.txt index 9593e5f..b239810 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: mcp, ai, divi, pods, oauth Requires at least: 6.9 Tested up to: 7.1 Requires PHP: 8.1 -Stable tag: 0.3.0 +Stable tag: 0.4.0 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -12,9 +12,9 @@ MCP-Server für WordPress, Divi 5 und Pods – mit OAuth für KI-Assistenten. == Description == -WP-LIT-MCP stellt einen MCP-Server bereit, über den ein KI-Assistent (z. B. Claude oder ein anderer MCP-fähiger Client mit OAuth) diese Website pflegt: -Inhalte aller Inhaltstypen inkl. Pods-Feldern, Status, Kopien, Revisionen, Menüs, freigegebene -WordPress-Einstellungen und die Mediathek. Jede Änderung läuft mit den Rechten des verbundenen +WP-LIT-MCP stellt einen MCP-Server bereit, über den ein KI-Assistent (ein MCP-fähiger Client mit OAuth) diese +Website pflegt: Inhalte aller Inhaltstypen inkl. Pods-Feldern, Status, Kopien, Revisionen, Menüs, freigegebene +WordPress-Einstellungen, die Mediathek sowie Divi-Seiten und die Divi-Bibliothek (auch globale Module). Jede Änderung läuft mit den Rechten des verbundenen WordPress-Benutzers und wird protokolliert. Einstellungen: Einstellungen → LIT MCP (Verbindung, Zugriff, Tools, Protokoll, Limits). @@ -46,9 +46,11 @@ Einstellungen: Einstellungen → LIT MCP (Verbindung, Zugriff, Tools, Protokoll, unfiltered_html ohne die kses-Filterung von WordPress, weil diese sonst jeden unveränderten Divi-Block neu schreiben würde. Alle Werte, die LIT MCP dabei schreibt, werden vorher bereinigt (wp_kses_post, sanitize_text_field, esc_url_raw); $variable-Verweise werden geparst, geprüft und vom Plugin neu erzeugt. - Inhalte des Code-Moduls bleiben nur mit unfiltered_html ungefiltert; eigenes HTML, CSS und HTML-Attribute - von Modulen schreibt LIT MCP nur für Benutzer mit unfiltered_html. Divis eigene Speicherfilter bleiben - aktiv. + Inhalte des Code-Moduls bleiben nur mit unfiltered_html ungefiltert; eigenes HTML, CSS, HTML-Attribute, + Interaktionen und die Lottie-Quelle von Modulen schreibt LIT MCP nur für Benutzer mit unfiltered_html. + Beim Kopieren, Einfügen und Speichern gespeicherter Knoten (Divi-Bibliothek, lit/divi-node-copy) lehnt + LIT MCP für Benutzer ohne unfiltered_html alles ab, was sie nicht selbst schreiben dürften – strenger als + Divi, mit sichtbarer Fehlermeldung. Divis eigene Speicherfilter bleiben aktiv. * Das Feld content von lit-content-create und lit-content-update nimmt kein Divi-Markup an (Divi-Blöcke