feat: lit/library-save creates library entries like Divi (E4)

Reuses NewDraft for insert and rollback (P6), requires edit_global_library
for scope global (P7), refuses opaque and global roots before wrapping (P11)
and checks the node with StoredNodeGuard. The source page is never written.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 02:12:50 +02:00
co-authored by Claude Opus 5.5
parent 8fa285a265
commit 5035092805
14 changed files with 1112 additions and 21 deletions
@@ -142,4 +142,28 @@ final class LibraryAccessTest extends TestCase
self::assertInstanceOf(WP_Post::class, LibraryFixtures::access([], false)->item(1057, false));
self::assertNull(LibraryFixtures::access()->writableGate());
}
public function testSavingNeedsPublishPostsSaveLibraryAndAWritableGroup(): void
{
LibraryFixtures::given([]);
self::assertNull(LibraryFixtures::access()->canSave());
LibraryFixtures::given([], ['publish_posts']);
self::assertToolError(LibraryFixtures::access()->canSave(), 'forbidden');
LibraryFixtures::given([]);
self::assertToolError(LibraryFixtures::access(['save_library'])->canSave(), 'forbidden');
self::assertToolError(LibraryFixtures::access([], false)->canSave(), 'forbidden');
self::assertToolError(LibraryFixtures::access(['divi_library'])->canSave(), 'forbidden');
}
/** Ruling P7: a global entry additionally needs Divi's edit_global_library. */
public function testSavingAGlobalEntryNeedsEditGlobalLibrary(): void
{
LibraryFixtures::given([]);
self::assertNull(LibraryFixtures::access(['edit_global_library'])->canSave());
self::assertToolError(LibraryFixtures::access(['edit_global_library'])->canSave(true), 'forbidden');
self::assertNull(LibraryFixtures::access()->canSave(true));
}
}