docs: Guides korrigiert (not_found, Snapshot-Gesamtgrenze, Schleifen-Warnungen) und LoopGuideTest enger an den Code gebunden

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-19 23:26:40 +02:00
co-authored by Claude Sonnet 5.5
parent fc35cbe9dd
commit 52208764f0
5 changed files with 26 additions and 15 deletions
+2 -2
View File
@@ -231,14 +231,14 @@ Website: den Nutzer ausdrücklich fragen. Jede Änderung legt einen Snapshot an.
## Snapshots und Wiederherstellen ## Snapshots und Wiederherstellen
Vor jeder Änderung an Presets, Farben, Variablen und Theme-Optionen sichert LIT MCP den Bereich (je Bereich bleiben Vor jeder Änderung an Presets, Farben, Variablen und Theme-Optionen sichert LIT MCP den Bereich (je Bereich bleiben
die letzten 20 Snapshots); die Antwort nennt die `snapshot_id`. Wäre der Bereich zu groß für eine Sicherung (über die letzten 20 Snapshots; eine Gesamtgrenze von 8 MB entfernt ältere früher); die Antwort nennt die `snapshot_id`. Wäre der Bereich zu groß für eine Sicherung (über
2 MB), antwortet das Werkzeug mit `snapshot_too_large` und schreibt nichts. 2 MB), antwortet das Werkzeug mit `snapshot_too_large` und schreibt nichts.
- `lit/divi-design-snapshots` mit `area` (`presets`, `colors`, `variables` oder `theme_options`; Standard - `lit/divi-design-snapshots` mit `area` (`presets`, `colors`, `variables` oder `theme_options`; Standard
`presets`) listet die Snapshots eines Bereichs, neueste zuerst, mit Zeitpunkt, Werkzeug und Protokolleintrag. `presets`) listet die Snapshots eines Bereichs, neueste zuerst, mit Zeitpunkt, Werkzeug und Protokolleintrag.
- `lit/divi-design-restore` mit `snapshot_id`: Der Probelauf zeigt den Unterschied zum aktuellen Stand (`diff`, - `lit/divi-design-restore` mit `snapshot_id`: Der Probelauf zeigt den Unterschied zum aktuellen Stand (`diff`,
`design_rev`); nach Rückfrage `confirm: true`. Vorher sichert LIT MCP den aktuellen Stand selbst – auch eine `design_rev`); nach Rückfrage `confirm: true`. Vorher sichert LIT MCP den aktuellen Stand selbst – auch eine
Wiederherstellung lässt sich zurücknehmen. Ist die ID unbekannt oder verdrängt, kommt `snapshot_not_found`. Wiederherstellung lässt sich zurücknehmen. Ist die ID unbekannt oder verdrängt, kommt `not_found`.
- Was ein Restore macht, hängt vom Bereich ab: **Farben**, die es im Snapshot nicht gibt, entfallen. **Variablen**, - Was ein Restore macht, hängt vom Bereich ab: **Farben**, die es im Snapshot nicht gibt, entfallen. **Variablen**,
die erst nach dem Snapshot entstanden, bleiben archiviert erhalten (Divi löscht keine). **Theme-Optionen**, die die erst nach dem Snapshot entstanden, bleiben archiviert erhalten (Divi löscht keine). **Theme-Optionen**, die
im Snapshot nicht gesetzt waren, kehren zum Divi-Standard zurück. **Presets**: Rechte-Regel `unfiltered_html` im Snapshot nicht gesetzt waren, kehren zum Divi-Standard zurück. **Presets**: Rechte-Regel `unfiltered_html`
+11 -8
View File
@@ -88,7 +88,9 @@ Regeln und Fehlermeldungen:
3. Passt die Option nicht zur Art der Schleife, steht in der Meldung: `… passt nicht zur Schleife dieses Elements 3. Passt die Option nicht zur Art der Schleife, steht in der Meldung: `… passt nicht zur Schleife dieses Elements
(Typ: Terme).` (Typ: Beiträge, Terme, Benutzer oder Menü). Eine Option der passenden Art wählen. Das ist eine (Typ: Terme).` (Typ: Beiträge, Terme, Benutzer oder Menü). Eine Option der passenden Art wählen. Das ist eine
Sicherheitsgrenze, kein Schönheitsfehler: Divi liest die Feld-Optionen in einer Term-, Benutzer- oder Sicherheitsgrenze, kein Schönheitsfehler: Divi liest die Feld-Optionen in einer Term-, Benutzer- oder
Menü-Schleife sonst bei dem Objekt mit derselben ID und gäbe fremde Daten aus. Nie umgehen. Menü-Schleife sonst bei dem Objekt mit derselben ID und gäbe fremde Daten aus. Nie umgehen. Bei einer nicht
unterstützten Schleife (ACF-Wiederholungsfeld, Alias oder leere Art) nennt die Meldung statt des Typs die rohe
Abfrageart der Schleife; in solchen Schleifen ist jede `loop_*`-Option abgelehnt.
4. Die Feld-Optionen (`loop_*_meta_key_manual_custom_field`) gibt es nur in der Vollform; für den Schlüssel gelten 4. Die Feld-Optionen (`loop_*_meta_key_manual_custom_field`) gibt es nur in der Vollform; für den Schlüssel gelten
dieselben Regeln wie bei `{{field:<meta_key>}}` (kein Schlüssel mit `_` am Anfang). dieselben Regeln wie bei `{{field:<meta_key>}}` (kein Schlüssel mit `_` am Anfang).
5. Vor dem Setzen lesen: `lit/divi-dynamic-sources` mit `post_type`, `post_id` und `node` (Pfad-ID des Moduls aus 5. Vor dem Setzen lesen: `lit/divi-dynamic-sources` mit `post_type`, `post_id` und `node` (Pfad-ID des Moduls aus
@@ -98,11 +100,11 @@ Regeln und Fehlermeldungen:
6. `lit-divi-move` erlaubt das Verschieben von Schleifen-Inhalt aus der Schleife heraus oder in eine Schleife 6. `lit-divi-move` erlaubt das Verschieben von Schleifen-Inhalt aus der Schleife heraus oder in eine Schleife
anderer Art (Divi lässt es zu), antwortet aber mit einer Warnung: der Inhalt zeigt dort nichts oder falsche anderer Art (Divi lässt es zu), antwortet aber mit einer Warnung: der Inhalt zeigt dort nichts oder falsche
Daten. Warnung dem Nutzer nennen, Modul zurückschieben oder den Inhalt neu setzen. Daten. Warnung dem Nutzer nennen, Modul zurückschieben oder den Inhalt neu setzen.
7. `lit-divi-update` warnt ebenso, wenn ein Update die Art der Schleife eines Elements ändert und darunter 7. `lit-divi-update` warnt ebenso, wenn ein Update die Art der Schleife eines Elements ändert oder die Schleife
unveränderte Schleifen-Inhalte stehen. ausschaltet (Art wird „keine“) und darunter unveränderte Schleifen-Inhalte stehen.
8. Ein neues Element mit eigener Schleife und Schleifen-Inhalten darunter geht nicht in einem `lit-divi-insert`- 8. `lit-divi-insert` lehnt einen Aufruf ab, in dem irgendwo ein neues Element mit eigener Schleife und irgendwo
Aufruf (die Schleife gilt erst nach dem Speichern): erst das Element mit Schleife einfügen, dann die Inhalte Schleifen-Inhalt vorkommt (die Schleife gilt erst nach dem Speichern): erst das Element mit Schleife einfügen,
mit `parent` = dieses Element. dann die Inhalte mit `parent` = dieses Element in einem zweiten Aufruf.
Grenzen (bewusst nicht gelöst; dem Nutzer sagen, statt zu umgehen): Grenzen (bewusst nicht gelöst; dem Nutzer sagen, statt zu umgehen):
@@ -111,8 +113,9 @@ Grenzen (bewusst nicht gelöst; dem Nutzer sagen, statt zu umgehen):
Schleife am Element selbst ein. Schleife am Element selbst ein.
- Der Zwei-Aufruf-Weg wird nicht verhindert, nur gemeldet: Schleifen-Inhalte (z. B. ein Beitrags-Feld) in einer - Der Zwei-Aufruf-Weg wird nicht verhindert, nur gemeldet: Schleifen-Inhalte (z. B. ein Beitrags-Feld) in einer
Beitrags-Schleife einfügen und danach die Art der Schleife ändern oder das Modul in eine Schleife anderer Art Beitrags-Schleife einfügen und danach die Art der Schleife ändern oder das Modul in eine Schleife anderer Art
verschieben. Das Werkzeug antwortet nur mit einer Warnung (Divis eigener Builder erlaubt dasselbe); sie dem verschieben. Das Werkzeug antwortet nur mit einer Warnung (Divis eigener Builder erlaubt dasselbe), obwohl Divi
Nutzer nennen und nicht ignorieren. dann Felder eines anderen Objekts mit derselben ID ausgeben kann; die Warnung dem Nutzer nennen und nicht
ignorieren.
- **Globale Module** (`[global <ID>]`) haben keinen Schleifen-Kontext; `loop_*` dort ist abgelehnt. - **Globale Module** (`[global <ID>]`) haben keinen Schleifen-Kontext; `loop_*` dort ist abgelehnt.
- `lit-content-create` und Theme-Builder-Vorlagen kennen keinen Schleifen-Kontext: erst die Seite mit Schleife - `lit-content-create` und Theme-Builder-Vorlagen kennen keinen Schleifen-Kontext: erst die Seite mit Schleife
anlegen (Nutzer im Divi-Builder), dann die Inhalte mit `lit-divi-insert` setzen. anlegen (Nutzer im Divi-Builder), dann die Inhalte mit `lit-divi-insert` setzen.
+1 -1
View File
@@ -131,7 +131,7 @@ Module in einem Element mit eingeschalteter Divi-Schleife zeigen Daten des jewei
`{"type": "text", "content": "{{loop:post_date}}"}` mit `parent` = die Spalte (oder das Element) der Schleife. `{"type": "text", "content": "{{loop:post_date}}"}` mit `parent` = die Spalte (oder das Element) der Schleife.
Das gilt in `lit-divi-insert` und `lit-divi-update` (`set`); außerhalb einer Schleife und in einer Schleife anderer Das gilt in `lit-divi-insert` und `lit-divi-update` (`set`); außerhalb einer Schleife und in einer Schleife anderer
Art lehnt das Werkzeug `loop_*`-Inhalte ab (Meldungen, Optionen und Grenzen: `divi-placeholders`, Abschnitt Art lehnt das Werkzeug `loop_*`-Inhalte ab (Meldungen, Optionen und Grenzen: `divi-placeholders`, Abschnitt
„Schleifen-Inhalte“). `lit-divi-move` warnt, wenn ein Modul mit Schleifen-Inhalt die Schleife verlässt. „Schleifen-Inhalte“). `lit-divi-move` warnt, wenn ein Modul mit Schleifen-Inhalt die Schleife verlässt oder in eine Schleife anderer Art kommt.
`lit-content-create` kennt keinen Schleifen-Kontext. `lit-content-create` kennt keinen Schleifen-Kontext.
## Einfügen, ändern, verschieben, löschen ## Einfügen, ändern, verschieben, löschen
+1 -1
View File
@@ -68,7 +68,7 @@ Für den Einstieg liefert `lit-guide` mit dem Thema „all“ alle Themen in ein
`message`, `hint` (und ggf. `fields`). Dem `hint` folgen. Weitere Codes: `forbidden` (ein Recht fehlt, die `message`, `hint` (und ggf. `fields`). Dem `hint` folgen. Weitere Codes: `forbidden` (ein Recht fehlt, die
Meldung nennt es), `in_use` (ein Preset oder Eintrag wird noch verwendet; `usages` nennt die Fundstellen), Meldung nennt es), `in_use` (ein Preset oder Eintrag wird noch verwendet; `usages` nennt die Fundstellen),
`conflict` (eine andere Änderung am Designsystem läuft noch, oder der Name einer Schrift ist vergeben), `conflict` (eine andere Änderung am Designsystem läuft noch, oder der Name einer Schrift ist vergeben),
`snapshot_not_found`, `snapshot_too_large`, `font_fetch_failed` (Schriftdatei nicht ladbar) und `font_invalid` `not_found` (z. B. eine unbekannte oder verdrängte `snapshot_id`), `snapshot_too_large`, `font_fetch_failed` (Schriftdatei nicht ladbar) und `font_invalid`
(Datei passt nicht zum Format). (Datei passt nicht zum Format).
- `confirm_required`: Nutzer fragen, dann mit `confirm: true` wiederholen. Beim Designsystem enthält die Antwort - `confirm_required`: Nutzer fragen, dann mit `confirm: true` wiederholen. Beim Designsystem enthält die Antwort
die `design_rev`, die mit `confirm: true` zurückgegeben wird; `rev_mismatch` heißt dort: der Bestand hat sich die `design_rev`, die mit `confirm: true` zurückgegeben wird; `rev_mismatch` heißt dort: der Bestand hat sich
+11 -3
View File
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Guides; namespace LIT\MCP\Tests\Unit\Guides;
use LIT\MCP\Integrations\Divi\Compose\Placeholders;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RecursiveDirectoryIterator; use RecursiveDirectoryIterator;
use RecursiveIteratorIterator; use RecursiveIteratorIterator;
@@ -53,16 +54,22 @@ final class LoopGuideTest extends TestCase
public function testRefusalPhrasesAreTheOnesTheCodeSays(): void public function testRefusalPhrasesAreTheOnesTheCodeSays(): void
{ {
// Only string literals count (no comments), matched exactly including case.
$code = ''; $code = '';
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(self::root() . '/src')); $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(self::root() . '/src'));
foreach ($files as $file) { foreach ($files as $file) {
if (str_ends_with((string) $file, '.php')) { if (! str_ends_with((string) $file, '.php')) {
$code .= (string) file_get_contents((string) $file); continue;
}
foreach (token_get_all((string) file_get_contents((string) $file)) as $token) {
if (is_array($token) && in_array($token[0], [T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE], true)) {
$code .= $token[1] . "\n";
}
} }
} }
foreach (self::PHRASES as $phrase) { foreach (self::PHRASES as $phrase) {
self::assertNotFalse(mb_stripos($code, $phrase), 'no source says "' . $phrase . '"'); self::assertNotFalse(mb_strpos($code, $phrase), 'no source string says "' . $phrase . '"');
} }
} }
@@ -72,6 +79,7 @@ final class LoopGuideTest extends TestCase
self::assertNotEmpty($examples[1], 'the guides show no {{loop:…}} example'); self::assertNotEmpty($examples[1], 'the guides show no {{loop:…}} example');
foreach (array_unique($examples[1]) as $name) { foreach (array_unique($examples[1]) as $name) {
self::assertContains('loop_' . $name, self::DIVI_LOOP_OPTIONS, '{{loop:' . $name . '}} is no Divi option'); self::assertContains('loop_' . $name, self::DIVI_LOOP_OPTIONS, '{{loop:' . $name . '}} is no Divi option');
self::assertSame('loop_' . $name, Placeholders::LOOP[$name] ?? null, '{{loop:' . $name . '}} is not in Placeholders::LOOP');
} }
} }
} }