Files
payloadcms/docs/versions/drafts.mdx
2024-07-15 15:29:11 -04:00

176 lines
9.0 KiB
Plaintext

---
title: Drafts
label: Drafts
order: 20
desc: Enable drafts on collection documents or globals and build true preview environments for your data.
keywords: version history, drafts, preview, draft, restore, publish, autosave, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload's Draft functionality builds on top of the Versions functionality to allow you to make changes to your collection documents and globals, but publish only when you're ready. This functionality allows you to build powerful Preview environments for your data, where you can make sure your changes look good before publishing documents.
<Banner type="warning">Drafts rely on Versions being enabled in order to function.</Banner>
By enabling Versions with Drafts, your collections and globals can maintain _newer_, and _unpublished_ versions of your documents. It's perfect for cases where you might want to work on a document, update it and save your progress, but not necessarily make it publicly published right away. Drafts are extremely helpful when building preview implementations.
![Drafts Enabled](/images/docs/drafts-enabled.png)
_If Drafts are enabled, the typical Save button is replaced with new actions which allow you to either save a draft, or publish your changes._
## Options
Collections and Globals both support the same options for configuring drafts. You can either set `versions.drafts` to `true`, or pass an object to configure draft properties.
| Draft Option | Description |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `autosave` | Enable `autosave` to automatically save progress while documents are edited. To enable, set to `true` or pass an object with [options](/docs/versions/autosave). |
| `validate` | Set `validate` to `true` to validate draft documents when saved. Default is `false`. |
## Database changes
By enabling drafts on a collection or a global, Payload will <strong>automatically inject a new field into your schema</strong> called `_status`. The `_status` field is used internally by Payload to store if a document is set to `draft` or `published`.
**Admin UI status indication**
Within the Admin UI, if drafts are enabled, a document can be shown with one of three "statuses":
1. <strong>Draft</strong> - if a document has never been published, and only draft versions of the document
are present
1. <strong>Published</strong> - if a document is published and there are no newer drafts available
1. <strong>Changed</strong> - if a document has been published, but there are newer drafts available
and not yet published
## Draft API
<Banner type="success">
If drafts are enabled on your collection or global, important and powerful changes are made to
your REST, GraphQL, and Local APIs that allow you to specify if you are interacting with drafts or
with live documents.
</Banner>
#### Updating or creating drafts
If you enable drafts on a collection or global, the `create` and `update` operations for REST, GraphQL, and Local APIs expose a new option called `draft` which allows you to specify if you are creating or updating a <strong>draft</strong>, or if you're just sending your changes straight to the published document. For example, if you pass the query parameter `?draft=true` to a REST `create` or `update` operation, your action will be treated as if you are creating a `draft` and not a published document. By default, the `draft` argument is set to `false`.
**Required fields**
If `draft` is enabled while creating or updating a document, all fields are considered as not required, so that you can save drafts that are incomplete.
#### Reading drafts vs. published documents
In addition to the `draft` argument within `create` and `update` operations, a `draft` argument is also exposed for `find` and `findByID` operations.
If `draft` is set to `true` while reading a document, <strong>Payload will automatically replace returned document(s) with their newest drafts</strong> if any newer drafts are available.
<strong>For example, let's take the following scenario:</strong>
1. You create a new collection document and publish it right away
1. You then make some updates, and save the updates as a draft
1. You then make some further updates, and save more updates as another draft
Here, you will have a published document that resides in your main collection, and then you'll have two _newer_ drafts that reside in the `_[collectionSlug]_versions` database collection.
If you simply fetch your created document using a `find` or `findByID` operation, your published document will be returned and the drafts will be ignored.
But, if you specify `draft` as `true`, Payload will automatically replace your published document's content with content coming from the most recently saved `version`. In this case, as we have created _two_ versions in the above scenario, Payload will send back data from the newest (second) draft and your document will appear as the most recently drafted version instead of the published version.
## Controlling who can see Collection drafts
<Banner type="warning">
If you're using the <strong>drafts</strong> feature, it's important for you to consider who can
view your drafts, and who can view only published documents. Luckily, Payload makes this extremely
simple and puts the power completely in your hands.
</Banner>
#### Restricting draft access
You can use the `read` [Access Control](../access-control/collections#read) method to restrict who is able to view drafts of your documents by simply returning a [query constraint](/docs/queries/overview) which restricts the documents that any given user is able to retrieve.
Here is an example that utilizes the `_status` field to require a user to be logged in to retrieve drafts:
```ts
import type { CollectionConfig } from 'payload'
export const Pages: CollectionConfig = {
slug: 'pages',
access: {
read: ({ req }) => {
// If there is a user logged in,
// let them retrieve all documents
if (req.user) return true
// If there is no user,
// restrict the documents that are returned
// to only those where `_status` is equal to `published`
return {
_status: {
equals: 'published',
},
}
},
},
versions: {
drafts: true,
},
//.. the rest of the Pages config here
}
```
<Banner type="warning">
<strong>Note regarding adding versions to an existing collection</strong>
<br />
If you already have a collection with documents, and you <em>opt in</em> to draft functionality
after you have already created existing documents, all of your old documents{' '}
<em>will not have a _status field</em> until you resave them. For this reason, if you are{' '}
<em>adding</em> versions into an existing collection, you might want to write your Access Control
function to allow for users to read both documents where{' '}
<strong>_status is equal to "published"</strong> as well as where{' '}
<strong>_status does not exist</strong>.
</Banner>
Here is an example for how to write an [Access Control](../access-control/overview) function that grants access to both documents where `_status` is equal to "published" and where `_status` does not exist:
```ts
import type { CollectionConfig } from 'payload'
export const Pages: CollectionConfig = {
slug: 'pages',
access: {
read: ({ req }) => {
// If there is a user logged in,
// let them retrieve all documents
if (req.user) return true
// If there is no user,
// restrict the documents that are returned
// to only those where `_status` is equal to `published`
// or where `_status` does not exist
return {
or: [
{
_status: {
equals: 'published',
},
},
{
_status: {
exists: false,
},
},
],
}
},
},
versions: {
drafts: true,
},
//.. the rest of the Pages config here
}
```
## Unpublishing drafts
If a document is published, the Payload Admin UI will be updated to show an "unpublish" button at the top of the sidebar, which will "unpublish" the currently published document. Consider this as a way to "revert" a document back to a draft state. On the API side, this is done by simply setting `_status: 'draft'` on any document.
## Reverting to published
If a document is published, and you have made further changes which are saved as a draft, Payload will show a "revert to published" button at the top of the sidebar which will allow you to reject your draft changes and "revert" back to the published state of the document. Your drafts will still be saved, but a new version will be created that will reflect the last published state of the document.