feat: Divi tools write library entries; global ones with dry run, confirm and backup (E2, F2)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 01:15:58 +02:00
co-authored by Claude Opus 5.5
parent 681bb755ff
commit d66ad36c2e
23 changed files with 1066 additions and 44 deletions
@@ -14,8 +14,8 @@ defined('ABSPATH') || exit;
* The frame of the Divi write tools (spec §5.6): permission and execute both load the page
* through DiviWriter::page() (rights, Divi layout, tree_rev lock – execute never trusts state
* from permission), the tool changes the tree in change() – only when its whole input
* validated, all or nothing (ruling S39) – and DiviWriter::save() stores it and builds the
* result. The composition is bound to the page (DiviWriter::composition(), ruling S22).
* validated, all or nothing (ruling S39) – and DiviWriter::commit() stores it (library entries:
* GlobalEdits) and builds the result. The composition is bound to the page (DiviWriter::composition(), ruling S22).
*/
abstract class DiviWriteAbility implements Ability
{
@@ -33,7 +33,14 @@ abstract class DiviWriteAbility implements Ability
public function outputSchema(): ?array
{
return ToolResult::schema(['tree_rev' => ['type' => 'string']], ['tree_rev']);
return ToolResult::schema([
'tree_rev' => ['type' => 'string'],
// Global library entries (answer F2): the pages that show the entry, and the backup
// made when revisions are off.
'affected' => ['type' => 'array', 'items' => ['type' => 'object']],
'affected_count' => ['type' => 'integer'],
'backup_id' => ['type' => 'integer'],
], ['tree_rev']);
}
public function isDirect(): bool
@@ -43,6 +50,11 @@ abstract class DiviWriteAbility implements Ability
final public function permission(array $input): bool|WP_Error
{
$refusal = $this->precheck($input);
if ($refusal !== null) {
return $refusal;
}
$page = $this->writer->page($input);
return $page instanceof WP_Error ? $page : true;
@@ -50,6 +62,11 @@ abstract class DiviWriteAbility implements Ability
final public function execute(array $input): mixed
{
$refusal = $this->precheck($input);
if ($refusal !== null) {
return $refusal;
}
$page = $this->writer->page($input);
if ($page instanceof WP_Error) {
return $page;
@@ -57,9 +74,20 @@ abstract class DiviWriteAbility implements Ability
$change = $this->change($page, $input, $this->writer->composition($page));
if ($change instanceof WP_Error) {
return $change;
return $this->writer->notice($page, $change);
}
return $this->writer->save($this->name(), $page, $change, $input);
return $this->writer->commit($this->name(), $page, $change, $input);
}
/**
* Checks of a tool beyond the page (rights and Tools-tab gates of another group) – run in
* permission() and again in execute(). Null = none.
*
* @param array<string, mixed> $input
*/
protected function precheck(array $input): ?WP_Error
{
return null;
}
}