fix: global-edit rules for every library entry that pages show (L2)
Divi renders any referenced et_pb_layout, whatever its scope term. A normal entry with usages now gets the dry run, confirm, P8a, backup and the site-wide GlobalItem scope; lit-divi-delete's notice and the library-list detail name its pages too. The usage scan is the same single query. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,10 @@ defined('ABSPATH') || exit;
|
||||
* The extra rules of a Divi write to a library entry (E2, answer F2), checked after the whole
|
||||
* change validated and before anything is saved:
|
||||
* - every entry keeps its shape (LibraryContent::shapeViolation) – instances expect their root type;
|
||||
* - a global entry changes every page that shows it at once (F7): without confirm: true nothing is
|
||||
* saved and the answer lists those pages (a dry run of the fully validated change); with it the
|
||||
* - a global entry – and any entry that pages show as an instance, global scope or not (audit L2:
|
||||
* Divi renders every referenced entry) – changes every page that shows it at once (F7): without
|
||||
* confirm: true nothing is saved and the answer lists those pages (a dry run of the fully
|
||||
* validated change); with it the
|
||||
* save scope is GlobalItem (site-wide cache) and, when revisions are off for the entry, a backup
|
||||
* copy is made first – the revision itself is DiviSaver's restore point, as for every page.
|
||||
* Confirm stays honour-based (ruling P9, like D10). A confirmed edit is refused while the user may
|
||||
@@ -87,17 +89,18 @@ final class GlobalEdits
|
||||
return Errors::invalidInput($violation . ' Nichts wurde gespeichert.', ['post_id' => $violation]);
|
||||
}
|
||||
|
||||
if (! $global) {
|
||||
// Audit L2: Divi renders every entry an instance names, global scope or not.
|
||||
$report = $this->usages->report($id);
|
||||
if (! $global && ! $report->exists()) {
|
||||
return ['scope' => SaveScope::LibraryItem, 'details' => []];
|
||||
}
|
||||
|
||||
$report = $this->usages->report($id);
|
||||
if (($input['confirm'] ?? false) !== true) {
|
||||
return Errors::confirmRequired(
|
||||
sprintf(
|
||||
'Globaler Bibliothekseintrag %d: die Änderung wirkt sofort auf %d %s (siehe affected), auch '
|
||||
. 'veröffentlichte. Nichts wurde gespeichert (Probelauf).',
|
||||
$id,
|
||||
'%s: die Änderung wirkt sofort auf %d %s (siehe affected), auch veröffentlichte. Nichts wurde '
|
||||
. 'gespeichert (Probelauf).',
|
||||
self::label($id, $global),
|
||||
$report->count,
|
||||
self::pages($report->count)
|
||||
) . self::hiddenNote($report) . self::blockedNote($report),
|
||||
@@ -105,7 +108,7 @@ final class GlobalEdits
|
||||
);
|
||||
}
|
||||
|
||||
$refusal = $this->pagesRefusal($id, $report) ?? $this->backupRefusal($item);
|
||||
$refusal = $this->pagesRefusal(self::label($id, $global), $report) ?? $this->backupRefusal($item);
|
||||
if ($refusal !== null) {
|
||||
return $refusal;
|
||||
}
|
||||
@@ -119,23 +122,29 @@ final class GlobalEdits
|
||||
}
|
||||
|
||||
/**
|
||||
* A tool's own confirm_required (lit-divi-delete) on a global entry, extended by the affected
|
||||
* pages – so the one confirm the client sends covers both questions.
|
||||
* A tool's own confirm_required (lit-divi-delete) on a global or referenced entry (audit L2),
|
||||
* extended by the affected pages – so the one confirm the client sends covers both questions.
|
||||
*/
|
||||
public function notice(DiviPage $page, WP_Error $error): WP_Error
|
||||
{
|
||||
if (Errors::codeOf($error) !== 'confirm_required' || ! $this->access->isGlobal($page->post)) {
|
||||
if (Errors::codeOf($error) !== 'confirm_required') {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$global = $this->access->isGlobal($page->post);
|
||||
$report = $this->usages->report((int) $page->post->ID);
|
||||
if (! $global && ! $report->exists()) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$data = $error->get_error_data();
|
||||
$details = is_array($data) ? array_diff_key($data, ['status' => true, 'hint' => true]) : [];
|
||||
|
||||
return Errors::confirmRequired(
|
||||
Errors::clientMessage($error)
|
||||
. sprintf(
|
||||
' Globaler Bibliothekseintrag: wirkt auf %d %s (siehe affected).',
|
||||
' %s: wirkt auf %d %s (siehe affected).',
|
||||
$global ? 'Globaler Bibliothekseintrag' : 'Bibliothekseintrag (als globales Modul verwendet)',
|
||||
$report->count,
|
||||
self::pages($report->count)
|
||||
)
|
||||
@@ -149,15 +158,14 @@ final class GlobalEdits
|
||||
* Ruling P8a: a confirmed edit needs edit_post on every live post that shows entry $id; above
|
||||
* GlobalUsages::HARD_CAP live posts it is refused as a whole (audit L1).
|
||||
*/
|
||||
private function pagesRefusal(int $id, UsageReport $report): ?WP_Error
|
||||
private function pagesRefusal(string $label, UsageReport $report): ?WP_Error
|
||||
{
|
||||
if ($report->tooMany) {
|
||||
return Errors::unsupported(
|
||||
sprintf(
|
||||
'Globaler Bibliothekseintrag %d erscheint auf %d veröffentlichten, privaten oder geplanten '
|
||||
. 'Einträgen – mehr als %d; so große Änderungen nimmt LIT MCP nicht vor. Nichts wurde '
|
||||
. 'gespeichert.',
|
||||
$id,
|
||||
'%s erscheint auf %d veröffentlichten, privaten oder geplanten Einträgen – mehr als %d; so große '
|
||||
. 'Änderungen nimmt LIT MCP nicht vor. Nichts wurde gespeichert.',
|
||||
$label,
|
||||
$report->live,
|
||||
GlobalUsages::HARD_CAP
|
||||
),
|
||||
@@ -171,9 +179,9 @@ final class GlobalEdits
|
||||
|
||||
return Errors::forbidden(
|
||||
sprintf(
|
||||
'Globaler Bibliothekseintrag %d erscheint auf veröffentlichten, privaten oder geplanten Einträgen, '
|
||||
. 'die dieses Konto nicht bearbeiten darf (%s); nichts wurde gespeichert.',
|
||||
$id,
|
||||
'%s erscheint auf veröffentlichten, privaten oder geplanten Einträgen, die dieses Konto nicht '
|
||||
. 'bearbeiten darf (%s); nichts wurde gespeichert.',
|
||||
$label,
|
||||
self::blockedList($report)
|
||||
),
|
||||
'Die Änderung von jemandem vornehmen lassen, der alle diese Einträge bearbeiten darf (z. B. Redakteur '
|
||||
@@ -234,6 +242,14 @@ final class GlobalEdits
|
||||
. ($more > 0 ? sprintf(' und %d weitere', $more) : '');
|
||||
}
|
||||
|
||||
/** How messages name entry $id: global, or a normal entry that pages show as a global module (L2). */
|
||||
private static function label(int $id, bool $global): string
|
||||
{
|
||||
return $global
|
||||
? sprintf('Globaler Bibliothekseintrag %d', $id)
|
||||
: sprintf('Bibliothekseintrag %d (auf Seiten als globales Modul verwendet)', $id);
|
||||
}
|
||||
|
||||
private static function pages(int $count): string
|
||||
{
|
||||
return $count === 1 ? 'Seite' : 'Seiten';
|
||||
|
||||
@@ -21,9 +21,10 @@ defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* lit/library-list: the Divi Library (spec §5.7, E9 – replaces lit/library-get). Without id a page
|
||||
* of published entries (filters, cursor); with id one entry with its node outline, tree_rev and,
|
||||
* for a global entry, the pages that show it. Rights: LibraryAccess (edit_posts + divi_library;
|
||||
* every listed entry also edit_post – others are left out, without title or count). With id,
|
||||
* of published entries (filters, cursor); with id one entry with its node outline, tree_rev and
|
||||
* the pages that show it as an instance (global entries always, others when any page does, L2).
|
||||
* Rights: LibraryAccess (edit_posts + divi_library; every listed entry also edit_post – others are
|
||||
* left out, without title or count). With id,
|
||||
* everything but a library entry the user may read answers like a missing ID (ruling P12).
|
||||
*/
|
||||
final class LibraryListAbility implements Ability
|
||||
@@ -53,7 +54,7 @@ final class LibraryListAbility implements Ability
|
||||
{
|
||||
return 'Listet Einträge der Divi-Bibliothek (Layouts, Abschnitte, Zeilen, Module; normal oder global), '
|
||||
. 'filterbar nach layout_type, scope, search und category, blätterbar mit cursor. Mit id: ein Eintrag '
|
||||
. 'im Detail – Knoten-Übersicht, tree_rev und bei globalen Einträgen die Seiten, die ihn zeigen '
|
||||
. 'im Detail – Knoten-Übersicht, tree_rev und die Seiten, die ihn als globales Modul zeigen '
|
||||
. '(affected). Einfügen mit lit-library-insert; bearbeiten mit den Divi-Werkzeugen und der ID als post_id.';
|
||||
}
|
||||
|
||||
@@ -232,8 +233,10 @@ final class LibraryListAbility implements Ability
|
||||
'rev' => Rev::ofPost($page->post),
|
||||
'edit_url' => $page->editUrl(),
|
||||
];
|
||||
if ($item['scope'] === 'global') {
|
||||
$result += $this->usages->report((int) $page->post->ID, false)->listing();
|
||||
// Audit L2: a normal entry that pages show as an instance names them too.
|
||||
$report = $this->usages->report((int) $page->post->ID, false);
|
||||
if ($item['scope'] === 'global' || $report->exists()) {
|
||||
$result += $report->listing();
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
Reference in New Issue
Block a user