fix: name the WordPress revision screen for library and layout revisions (audit L3)
lit/revision-restore takes only content types, so a write to a library entry or a Theme Builder layout now answers with restore_url (wp-admin revision.php for its revision_id), also per page in lit/divi-replace-text. The guides and readme no longer present lit/revision-restore as the way back for these types. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -75,7 +75,8 @@ Die Divi-Bibliothek speichert Layouts, Abschnitte, Zeilen und Module zur Wiederv
|
|||||||
4. Dem Nutzer die betroffenen Seiten nennen und fragen. Erst nach Zustimmung dieselbe Änderung mit
|
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`).
|
`confirm: true` wiederholen (bei `lit-divi-delete` gilt dasselbe `confirm`).
|
||||||
5. Vorher entsteht eine Revision des Eintrags (`revision_id`); sind Revisionen abgeschaltet, eine
|
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
|
Sicherungskopie im Papierkorb (`backup_id`). `lit/revision-restore` gilt nicht für Bibliothekseinträge:
|
||||||
|
Zurück geht es über `restore_url` in der Antwort (Revisionsvergleich in WordPress, dort wiederherstellen). Schlägt das Speichern danach fehl, nennt der Fehler die
|
||||||
`backup_id`. Nach dem Speichern wird Divis CSS-Cache für alle Seiten geleert.
|
`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
|
Die Bestätigung wird abgelehnt (`forbidden`), wenn das Konto einen veröffentlichten, privaten oder geplanten
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ Für den Einstieg liefert `lit-guide` mit dem Thema „all“ alle Themen in ein
|
|||||||
- Erfolg: `ok`, `summary`, `changed`, `warnings`, `rev`, `revision_id` (Revision mit dem Stand vorher, nur bei
|
- Erfolg: `ok`, `summary`, `changed`, `warnings`, `rev`, `revision_id` (Revision mit dem Stand vorher, nur bei
|
||||||
Tools, die Inhalt überschreiben, sonst `null`), `log_id`, URLs. Divi-Werkzeuge zusätzlich `tree_rev` (Stand
|
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);
|
des Seiteninhalts, Pflicht für die nächste Divi-Änderung) und `outline` (betroffener Abschnitt);
|
||||||
`lit/divi-replace-text` nennt `tree_rev` je Seite in `results` (Probelauf: in `matches`).
|
`lit/divi-replace-text` nennt `tree_rev` je Seite in `results` (Probelauf: in `matches`). Bei
|
||||||
|
Bibliothekseinträgen und Theme-Builder-Layouts kommt `restore_url` hinzu (Revisionsvergleich in WordPress) –
|
||||||
|
`lit/revision-restore` gilt nur für Inhaltstypen.
|
||||||
- Fehler: JSON mit `code` (z. B. `validation_failed`, `rev_mismatch`, `write_failed`, `partial_write`),
|
- Fehler: JSON mit `code` (z. B. `validation_failed`, `rev_mismatch`, `write_failed`, `partial_write`),
|
||||||
`message`, `hint` (und ggf. `fields`). Dem `hint` folgen.
|
`message`, `hint` (und ggf. `fields`). Dem `hint` folgen.
|
||||||
- `confirm_required`: Nutzer fragen, dann mit `confirm: true` wiederholen.
|
- `confirm_required`: Nutzer fragen, dann mit `confirm: true` wiederholen.
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ Kopf- und Fußzeile heißen „global“, weil andere Vorlagen sie mitbenutzen.
|
|||||||
`confirm: true`: Bedingungen einer aktiven Vorlage ändern (`lit/tb-assign`) und ein Layout ändern, das eine
|
`confirm: true`: Bedingungen einer aktiven Vorlage ändern (`lit/tb-assign`) und ein Layout ändern, das eine
|
||||||
aktive Vorlage zeigt (die `lit-divi-…`-Werkzeuge; die Antwort nennt die Vorlagen unter `templates`, solche
|
aktive Vorlage zeigt (die `lit-divi-…`-Werkzeuge; die Antwort nennt die Vorlagen unter `templates`, solche
|
||||||
ohne Berechtigung nur als Anzahl `hidden_templates`). Vor dem
|
ohne Berechtigung nur als Anzahl `hidden_templates`). Vor dem
|
||||||
Speichern eines sichtbaren Layouts entsteht eine Revision; sind Revisionen abgeschaltet, eine
|
Speichern eines sichtbaren Layouts entsteht eine Revision (wiederherstellbar über `restore_url`, siehe
|
||||||
Sicherungskopie im Papierkorb (`backup_id`).
|
„Rückgängig machen“); sind Revisionen abgeschaltet, eine Sicherungskopie im Papierkorb (`backup_id`).
|
||||||
- `lit/divi-replace-text` ändert sichtbare Layouts nicht; solche Änderungen mit `lit-divi-update` und
|
- `lit/divi-replace-text` ändert sichtbare Layouts nicht; solche Änderungen mit `lit-divi-update` und
|
||||||
`confirm: true` vornehmen.
|
`confirm: true` vornehmen.
|
||||||
- Die Standardvorlage ändert LIT MCP nicht (nur im Theme Builder).
|
- Die Standardvorlage ändert LIT MCP nicht (nur im Theme Builder).
|
||||||
@@ -100,8 +100,11 @@ bleiben die Felder ungeprüft (die Antwort sagt das). Kopf- und Fußzeile werden
|
|||||||
## Rückgängig machen
|
## Rückgängig machen
|
||||||
|
|
||||||
Vorlagen haben keine Revisionen: `lit/tb-assign` nennt die bisherigen Bedingungen (`previous`), `lit/tb-activate`
|
Vorlagen haben keine Revisionen: `lit/tb-assign` nennt die bisherigen Bedingungen (`previous`), `lit/tb-activate`
|
||||||
schaltet zurück; jede Änderung steht im Protokoll. Layouts erhalten wie Divi-Seiten eine Revision. Neu angelegte
|
schaltet zurück; jede Änderung steht im Protokoll. Layouts erhalten wie Divi-Seiten eine Revision (`revision_id`),
|
||||||
Vorlagen im Divi Theme Builder löschen.
|
aber `lit/revisions-list` und `lit/revision-restore` gelten nur für Seiten, Beiträge und andere Inhaltstypen,
|
||||||
|
nicht für Theme-Builder-Layouts: Die Antwort nennt deshalb `restore_url`, den Revisionsvergleich in WordPress,
|
||||||
|
in dem der Nutzer die Revision wiederherstellt. Schneller Weg zurück bei einem sichtbaren Layout: die Vorlage mit
|
||||||
|
`lit/tb-activate` (`enabled: false`) ausblenden. Neu angelegte Vorlagen im Divi Theme Builder löschen.
|
||||||
|
|
||||||
## Ablauf: Vorlage für einen Inhaltstyp (custom-post-type-vorlage)
|
## Ablauf: Vorlage für einen Inhaltstyp (custom-post-type-vorlage)
|
||||||
|
|
||||||
|
|||||||
+7
-5
@@ -125,12 +125,14 @@ Es gibt keine allgemeine "Rückgängig"-Funktion; was sich wie zurücksetzen lä
|
|||||||
* Divi-Seiten: jede Divi-Änderung legt vorher eine Revision an (revision_id in der Antwort); zurück über
|
* Divi-Seiten: jede Divi-Änderung legt vorher eine Revision an (revision_id in der Antwort); zurück über
|
||||||
lit/revision-restore. Beim seitenübergreifenden Ersetzen erhält jede geänderte Seite eine eigene Revision.
|
lit/revision-restore. Beim seitenübergreifenden Ersetzen erhält jede geänderte Seite eine eigene Revision.
|
||||||
* Bibliothekseinträge: jede Änderung legt vorher eine Revision an (revision_id), bei abgeschalteten Revisionen
|
* Bibliothekseinträge: jede Änderung legt vorher eine Revision an (revision_id), bei abgeschalteten Revisionen
|
||||||
eine Sicherungskopie im Papierkorb (backup_id); zurück über WordPress (Eintrag der Divi-Bibliothek
|
eine Sicherungskopie im Papierkorb (backup_id); zurück über den Revisionsvergleich in WordPress (restore_url
|
||||||
bearbeiten → Revisionen). Neu angelegte Einträge (lit/library-save, lit/library-make-global) in der
|
in der Antwort; lit/revision-restore gilt nur für Inhaltstypen, nicht für Bibliothekseinträge). Neu
|
||||||
Divi-Bibliothek löschen; durch Instanzen ersetzte Knoten über die Revision der jeweiligen Seite zurückholen.
|
angelegte Einträge (lit/library-save, lit/library-make-global) in der Divi-Bibliothek löschen; durch
|
||||||
|
Instanzen ersetzte Knoten über die Revision der jeweiligen Seite zurückholen.
|
||||||
* Theme Builder: Vorlagen haben keine Revisionen. lit/tb-assign nennt die bisherigen Bedingungen (previous) und
|
* Theme Builder: Vorlagen haben keine Revisionen. lit/tb-assign nennt die bisherigen Bedingungen (previous) und
|
||||||
schreibt sie ins Protokoll; lit/tb-activate schaltet zurück. Layouts erhalten wie Divi-Seiten eine Revision.
|
schreibt sie ins Protokoll; lit/tb-activate schaltet zurück. Layouts erhalten wie Divi-Seiten eine Revision,
|
||||||
Neu angelegte Vorlagen und Layouts im Divi Theme Builder löschen.
|
wiederherstellbar im Revisionsvergleich von WordPress (restore_url in der Antwort; nicht über
|
||||||
|
lit/revision-restore). Neu angelegte Vorlagen und Layouts im Divi Theme Builder löschen.
|
||||||
* Original durch eine Kopie ersetzen (lit/post-replace-with-copy): vorher legt das Werkzeug eine Revision
|
* Original durch eine Kopie ersetzen (lit/post-replace-with-copy): vorher legt das Werkzeug eine Revision
|
||||||
und eine vollständige Sicherung des bisherigen Originals im Papierkorb an (backup_id in der Antwort) –
|
und eine vollständige Sicherung des bisherigen Originals im Papierkorb an (backup_id in der Antwort) –
|
||||||
von dort in WordPress wiederherstellbar.
|
von dort in WordPress wiederherstellbar.
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ final class DiviReplaceTextAbility implements Ability
|
|||||||
'revision_id' => $saved['revision_id'] ?? null,
|
'revision_id' => $saved['revision_id'] ?? null,
|
||||||
'log_id' => $saved['log_id'] ?? null,
|
'log_id' => $saved['log_id'] ?? null,
|
||||||
'warnings' => is_array($saved['warnings'] ?? null) ? $saved['warnings'] : [],
|
'warnings' => is_array($saved['warnings'] ?? null) ? $saved['warnings'] : [],
|
||||||
];
|
] + (isset($saved['restore_url']) ? ['restore_url' => $saved['restore_url']] : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ abstract class DiviWriteAbility implements Ability
|
|||||||
'affected_count' => ['type' => 'integer'],
|
'affected_count' => ['type' => 'integer'],
|
||||||
'hidden_count' => ['type' => 'integer'],
|
'hidden_count' => ['type' => 'integer'],
|
||||||
'backup_id' => ['type' => 'integer'],
|
'backup_id' => ['type' => 'integer'],
|
||||||
|
// Library entries and Theme Builder layouts: their revision in WordPress' revision screen (audit L3 –
|
||||||
|
// lit/revision-restore takes only content types).
|
||||||
|
'restore_url' => ['type' => 'string'],
|
||||||
// Theme Builder layouts: the enabled templates that show the layout – those the user may edit; the
|
// Theme Builder layouts: the enabled templates that show the layout – those the user may edit; the
|
||||||
// others only as a count (ruling Q22).
|
// others only as a count (ruling Q22).
|
||||||
'templates' => ['type' => 'array', 'items' => ['type' => 'object']],
|
'templates' => ['type' => 'array', 'items' => ['type' => 'object']],
|
||||||
|
|||||||
@@ -155,10 +155,28 @@ final class DiviWriter
|
|||||||
foreach ($change->entries() as $entry) {
|
foreach ($change->entries() as $entry) {
|
||||||
$tool->changed(DiviChange::idOf($entry, $index) ?? '?', $entry['type'], $entry['action'], $entry['label']);
|
$tool->changed(DiviChange::idOf($entry, $index) ?? '?', $entry['type'], $entry['action'], $entry['label']);
|
||||||
}
|
}
|
||||||
|
$restore = self::restoreUrl($page, $saved['revision_id']);
|
||||||
|
if ($restore !== null) {
|
||||||
|
$tool->with('restore_url', $restore);
|
||||||
|
}
|
||||||
|
|
||||||
return $tool->toArray();
|
return $tool->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Audit L3: lit/revision-restore takes only the content types (ContentSchema) – not library entries or Theme
|
||||||
|
* Builder layouts. Their revision is restored in WordPress' revision screen; null for everything else.
|
||||||
|
*/
|
||||||
|
private static function restoreUrl(DiviPage $page, mixed $revisionId): ?string
|
||||||
|
{
|
||||||
|
$noRestoreTool = $page->isLibraryItem() || $page->isThemeBuilderLayout();
|
||||||
|
if (! $noRestoreTool || ! is_int($revisionId) || $revisionId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return admin_url('revision.php?revision=' . $revisionId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save() for the Divi tools (E2): pages as before; a library entry keeps its shape, a global one
|
* save() for the Divi tools (E2): pages as before; a library entry keeps its shape, a global one
|
||||||
* needs confirm (dry run first), gets a backup when revisions are off and clears every page's
|
* needs confirm (dry run first), gets a backup when revisions are off and clears every page's
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ final class LibraryFixtures
|
|||||||
static fn (string $key, string $value, string $url): string => $url . '&' . $key . '=' . $value
|
static fn (string $key, string $value, string $url): string => $url . '&' . $key . '=' . $value
|
||||||
);
|
);
|
||||||
Functions\when('get_preview_post_link')->justReturn('https://kunde.test/?page_id=7&preview=true');
|
Functions\when('get_preview_post_link')->justReturn('https://kunde.test/?page_id=7&preview=true');
|
||||||
|
Functions\when('admin_url')->alias(static fn (string $path = ''): string => 'https://kunde.test/wp-admin/' . $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A store that answers isGlobal()/layoutType() from ITEMS (no database). */
|
/** A store that answers isGlobal()/layoutType() from ITEMS (no database). */
|
||||||
|
|||||||
@@ -206,6 +206,8 @@ final class GlobalEditsTest extends TestCase
|
|||||||
self::assertTrue($result['ok']);
|
self::assertTrue($result['ok']);
|
||||||
self::assertSame(SaveScope::GlobalItem, $this->saved[0][1]);
|
self::assertSame(SaveScope::GlobalItem, $this->saved[0][1]);
|
||||||
self::assertSame(811, $result['revision_id']);
|
self::assertSame(811, $result['revision_id']);
|
||||||
|
// Audit L3: lit/revision-restore does not take library entries – the WordPress revision screen does.
|
||||||
|
self::assertSame('https://kunde.test/wp-admin/revision.php?revision=811', $result['restore_url']);
|
||||||
self::assertSame(2, $result['affected_count']);
|
self::assertSame(2, $result['affected_count']);
|
||||||
self::assertArrayNotHasKey('backup_id', $result);
|
self::assertArrayNotHasKey('backup_id', $result);
|
||||||
self::assertSame(0, $this->backups);
|
self::assertSame(0, $this->backups);
|
||||||
@@ -537,6 +539,7 @@ final class GlobalEditsTest extends TestCase
|
|||||||
self::assertSame(1, $result['results'][0]['count']);
|
self::assertSame(1, $result['results'][0]['count']);
|
||||||
self::assertSame(SaveScope::LibraryItem, $this->saved[0][1]);
|
self::assertSame(SaveScope::LibraryItem, $this->saved[0][1]);
|
||||||
self::assertStringContainsString('Bibliotheksmodul', $this->saved[0][0]);
|
self::assertStringContainsString('Bibliotheksmodul', $this->saved[0][0]);
|
||||||
|
self::assertSame('https://kunde.test/wp-admin/revision.php?revision=811', $result['results'][0]['restore_url']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ruling P1 / answer F2: a global entry is never changed without the dry run that names its pages. */
|
/** Ruling P1 / answer F2: a global entry is never changed without the dry run that names its pages. */
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ final class DiviInsertAbilityTest extends DiviWriteAbilityTestCase
|
|||||||
self::assertSame(Rev::of($this->saved[0]), $result['tree_rev']);
|
self::assertSame(Rev::of($this->saved[0]), $result['tree_rev']);
|
||||||
self::assertSame(Rev::ofPost($this->post), $result['rev']);
|
self::assertSame(Rev::ofPost($this->post), $result['rev']);
|
||||||
self::assertSame(811, $result['revision_id']);
|
self::assertSame(811, $result['revision_id']);
|
||||||
|
self::assertArrayNotHasKey('restore_url', $result, 'pages: lit/revision-restore');
|
||||||
self::assertSame(4711, $result['log_id']);
|
self::assertSame(4711, $result['log_id']);
|
||||||
self::assertStringStartsWith('s0 section "Hero"', (string) $result['outline']);
|
self::assertStringStartsWith('s0 section "Hero"', (string) $result['outline']);
|
||||||
self::assertSame('https://kunde.test/?page_id=7&et_fb=1', $result['edit_url']);
|
self::assertSame('https://kunde.test/?page_id=7&et_fb=1', $result['edit_url']);
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ final class DiviWriterThemeBuilderTest extends TestCase
|
|||||||
self::assertTrue($result['ok']);
|
self::assertTrue($result['ok']);
|
||||||
self::assertCount(1, $this->saved);
|
self::assertCount(1, $this->saved);
|
||||||
self::assertSame(1066, $result['templates'][0]['id']);
|
self::assertSame(1066, $result['templates'][0]['id']);
|
||||||
|
// Audit L3: lit/revision-restore does not take Theme Builder layouts – the WordPress revision screen does.
|
||||||
|
self::assertSame('https://kunde.test/wp-admin/revision.php?revision=811', $result['restore_url']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLayoutOfADisabledTemplateSavesAtOnce(): void
|
public function testLayoutOfADisabledTemplateSavesAtOnce(): void
|
||||||
|
|||||||
Reference in New Issue
Block a user