From dacd2beb73d52a6882b292bc7919df8c16bdaacf Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Fri, 15 May 2026 16:56:10 +0100 Subject: [PATCH] vault backup: 2026-05-15 16:56:10 --- raw/{ => _processed}/versions__autosave.md | 0 wiki/payloadcms/_index.md | 1 + wiki/payloadcms/versions-drafts.md | 149 +++++++++++++++++++++ 3 files changed, 150 insertions(+) rename raw/{ => _processed}/versions__autosave.md (100%) create mode 100644 wiki/payloadcms/versions-drafts.md diff --git a/raw/versions__autosave.md b/raw/_processed/versions__autosave.md similarity index 100% rename from raw/versions__autosave.md rename to raw/_processed/versions__autosave.md diff --git a/wiki/payloadcms/_index.md b/wiki/payloadcms/_index.md index 153313d..cc88dda 100644 --- a/wiki/payloadcms/_index.md +++ b/wiki/payloadcms/_index.md @@ -146,3 +146,4 @@ | [[wiki/payloadcms/troubleshooting\|Troubleshooting Common Issues]] | Dependency mismatches (duplicate packages, monorepos), "Unauthorized" cookie debug, --experimental-https HMR WebSocket fix, DB password encoding | raw/troubleshooting__troubleshooting.md | 2026-05-15 | | [[wiki/payloadcms/typescript-plugin\|TypeScript Plugin (Experimental)]] | `@payloadcms/typescript-plugin` — IDE path validation, export validation, autocomplete, go-to-definition for PayloadComponent import strings; VS Code workspace TS setup | raw/typescript__ts-plugin.md | 2026-05-15 | | [[wiki/payloadcms/versions-autosave\|Versions — Autosave]] | Autosave config (interval/showSaveDraftButton), single-version upsert storage strategy, `autosave` arg on Local API update, requires versions+drafts | raw/versions__autosave.md | 2026-05-15 | +| [[wiki/payloadcms/versions-drafts\|Versions — Drafts]] | draft param vs _status field, write location table (versions table vs main collection), access control for read/publish, scheduled publish via Jobs Queue | raw/versions__drafts.md | 2026-05-15 | diff --git a/wiki/payloadcms/versions-drafts.md b/wiki/payloadcms/versions-drafts.md new file mode 100644 index 0000000..6d63e27 --- /dev/null +++ b/wiki/payloadcms/versions-drafts.md @@ -0,0 +1,149 @@ +--- +title: "Versions — Drafts" +aliases: [payload-drafts, draft-publish, payload-draft-api] +tags: [payloadcms, versions, drafts, publish, access-control] +sources: [raw/versions__drafts.md] +created: 2026-05-15 +updated: 2026-05-15 +--- + +## Overview + +Drafts build on [[wiki/payloadcms/versions-autosave|Versions / Autosave]] to let you save changes without publishing them immediately. Requires `versions` to be enabled first. + +```ts +// Collection or Global +versions: { + drafts: { + autosave: true, // or pass autosave options object + schedulePublish: true, // allow future publish/unpublish events + validate: false, // validate on draft save (default: false) + localizeStatus: false, // Beta: localize _status field + }, +} +``` + +## Database Changes + +Enabling drafts injects a `_status` field (`'draft' | 'published'`) into your schema automatically. + +**Admin UI statuses:** +- **Draft** — never published; only draft versions exist +- **Published** — published, no newer drafts +- **Changed** — published, but newer unpublished drafts exist + +## How `draft` Param and `_status` Work Together + +| Operation | `draft` param | `_status` in data | Result | +|-----------|-------------------|---------------------|---------------------------------------------------------------| +| Create | `true` or `false` | omitted | Main collection updated with `_status: 'draft'` | +| Create | `true` or `false` | `'published'` | Main collection updated with `_status: 'published'` | +| Update | `true` | omitted or `'draft'`| **Only versions table** updated; main collection unchanged | +| Update | `true` | `'published'` | Main collection updated with `_status: 'published'` (override)| +| Update | `false` or omitted| omitted | Main collection updated with `_status: 'draft'` | +| Update | `false` or omitted| `'published'` | Main collection updated with `_status: 'published'` | + +**Key distinctions:** +- `draft: true` → skips required field validation + writes only to versions table +- `_status: 'published'` → overrides `draft: true` and updates the main collection +- Setting `_status: 'draft'` alone does **not** skip required field validation; use `draft: true` for that + +## Draft API Examples + +```ts +// Save as draft (only versions table updated) +await payload.update({ + collection: 'pages', + id, + data: { title: 'WIP' }, + draft: true, +}) + +// Publish (main collection updated) +await payload.update({ + collection: 'pages', + id, + data: { _status: 'published' }, +}) + +// Read latest version (draft or published) +await payload.findByID({ + collection: 'pages', + id, + draft: true, // returns newest version from versions table +}) +``` + +REST equivalent: `POST /api/pages?draft=true` + +## Controlling Who Can Read Drafts + +> **Critical:** `draft: true` on read does NOT filter by `_status`. Use Access Control. + +```ts +access: { + read: ({ req }) => { + if (req.user) return true // logged-in: see everything + return { _status: { equals: 'published' } } // guests: published only + }, +} +``` + +**Migration gotcha:** existing documents before drafts was enabled won't have `_status`. Allow both cases: + +```ts +return { + or: [ + { _status: { equals: 'published' } }, + { _status: { exists: false } }, + ], +} +``` + +## Controlling Who Can Publish + +Use `update` access control with a query constraint on `_status`: + +```ts +access: { + update: ({ req: { user } }) => { + if (!user) return false + if (user.role === 'admin') return true + // editors can only update drafts (not published docs) + return { _status: { equals: 'draft' } } + }, +} +``` + +This also suppresses the Publish/Unpublish buttons in Admin UI for non-admins. + +## Scheduled Publish + +Enable with `versions.drafts.schedulePublish: true`. Requires [[wiki/payloadcms/jobs-queue|Jobs Queue]] to be running — scheduled events are queued as background jobs. + +## Unpublishing & Reverting + +- **Unpublish** → sets `_status: 'draft'` on the main collection document +- **Revert to published** → creates a new version reflecting last published state (draft history is preserved) + +## Key Takeaways + +- `draft: true` controls **validation bypass** + **write location** (versions table only) +- `_status: 'published'` controls **publish state** — always overrides `draft: true` +- First document creation always writes to main collection regardless of `draft` param +- Read with `draft: true` returns the **newest version** (could be draft or published) +- Access Control is required to hide drafts from unauthenticated users +- `schedulePublish` requires the Jobs Queue to be configured and running +- Adding drafts to an existing collection → old docs have no `_status`; update AC accordingly + +## Related + +- [[wiki/payloadcms/versions-autosave|Versions — Autosave]] +- [[wiki/payloadcms/access-control|Access Control]] +- [[wiki/payloadcms/jobs-queue|Jobs Queue — Overview]] +- [[wiki/payloadcms/admin-preview|Admin Preview & Draft Preview]] +- [[wiki/payloadcms/live-preview|Live Preview — Overview]] + +## Sources + +- `raw/versions__drafts.md` — https://payloadcms.com/docs/versions/drafts