CMS Draft & Publish Workflow
Standard call shape (every curl below). The
<AUTH>placeholder is shorthand forAuthorization: Bearer <TOKEN>only. Body-bearing requests also needContent-Type: application/json.
Some CMS collections gate their items behind a draft/publish workflow instead of writing straight to the live site. Such a collection has the Draft Items plugin installed. Each item is in one of three states — DRAFT, PUBLISHED, or CHANGED (a published item with a pending draft edit) — and edits are staged as drafts until explicitly published.
This reference is for an agent that must detect whether a collection uses this workflow, read the right version of an item, and drive item state transitions (publish, unpublish, revert, delete) through the public Wix Data REST API.
Prerequisites
- Wix CMS enabled on the site.
- The collection already exists (see CMS Schema Management).
- API access with write permission on the collection's data items (reading, authoring drafts, and publishing all go through the Data Items API), plus collection-management permission to add or remove the Draft Items plugin.
Required APIs
- Data Items API: REST — includes Publish Data Item Draft and Unpublish Data Item.
- Data Collections API: REST — Add/Delete Data Collection Plugin.
Mental model — where drafts live
A collection with the Draft Items plugin has two paired surfaces:
| Surface | Collection ID | Holds |
|---|---|---|
| Published (live) | the collection's own id (e.g. articles) |
Items visible on the site |
| Paired drafts | draftItemsPluginOptions.draftsCollectionId (conventionally <collectionId>__drafts, e.g. articles__drafts) |
Pending drafts (new items not yet published, or edits to a published item) |
Read the drafts collection id from the plugin — do not assume the __drafts suffix. The published collection's Draft Items plugin exposes draftItemsPluginOptions.draftsCollectionId; the drafts collection's plugin exposes draftItemsPluginOptions.publishedCollectionId. Resolve the pairing from those fields.
Item state is derived from where the item exists:
| State | Meaning | Where it lives |
|---|---|---|
| DRAFT | Not yet on the site | Only in the drafts collection |
| PUBLISHED | Live on the site, no pending edit | Only in the published collection |
| CHANGED | Live on the site and has a pending draft edit | In both the published and drafts collections |
Treat state as server-authoritative. Derive it from the published/draft surfaces (or the item the API returns) — never render an optimistic status before the write confirms.
1. Detect the workflow on a collection
Read the collection and inspect its plugins. A collection with the Draft Items plugin uses the draft/publish workflow.
curl -X GET \
'https://www.wixapis.com/wix-data/v2/collections/articles' \
-H 'Authorization: <AUTH>'- Draft Items plugin present → the collection gates items behind draft/publish. Its
draftItemsPluginOptions.draftsCollectionIdgives the paired drafts collection to author and edit drafts against. - Draft Items plugin absent → plain collection; every insert/update goes straight live. No draft surface exists.
2. Read items
Reads target a specific surface — there is no merged view:
- Published items: query the published collection (
articles). - Drafts: query the drafts collection resolved from
draftItemsPluginOptions.draftsCollectionId(e.g.articles__drafts).
Endpoint: POST https://www.wixapis.com/wix-data/v2/items/query
{
"dataCollectionId": "articles__drafts",
"query": {
"filter": { "category": "news" },
"paging": { "limit": 50, "offset": 0 }
}
}- To read only published items, query with
dataCollectionId: "articles". - To read drafts, query with
dataCollectionIdset to the paired drafts collection id. - Compute CHANGED by checking whether an item id exists in both the published and drafts surfaces.
3. Write & transition items
Author a brand-new draft
Insert into the drafts collection. The item starts as DRAFT.
Endpoint: POST https://www.wixapis.com/wix-data/v2/items
{
"dataCollectionId": "articles__drafts",
"dataItem": {
"data": { "title": "Draft headline", "body": "Work in progress" }
}
}Edit a draft
Update or patch against the drafts collection (articles__drafts). See CMS Data Items CRUD for Update/Patch shapes.
Edit a PUBLISHED item → produces CHANGED
Editing a live item does not overwrite the live copy — it stages a pending draft, leaving the published version untouched until published. The live item then has a pending draft (state CHANGED).
Create the draft first, then edit it. To edit a published item, explicitly create the draft via the create-draft flow (createDataItemDraft) rather than relying on an implicit draft-on-update. Create-draft seeds a full draft copy of the currently-published item into the drafts collection under the same item id; you then apply your edits to that draft. This is the more reliable path — a bare partial update straight to the drafts collection risks producing a draft that is missing the fields you didn't touch. So: create-draft for the published item id, then Update/Patch that draft on the drafts collection (articles__drafts).
Publish a pending draft (DRAFT/CHANGED → PUBLISHED)
Replaces the published item's data with the draft's content; the draft is then deleted. Pass the published collection id.
Endpoint: POST https://www.wixapis.com/wix-data/v2/items/publish-draft
curl -X POST \
'https://www.wixapis.com/wix-data/v2/items/publish-draft' \
-H 'Content-Type: application/json' \
-H 'Authorization: <AUTH>' \
-d '{
"dataCollectionId": "articles",
"dataItemId": "5331fc15-9441-4fd4-bc7b-7f6870c69228"
}'Response — the newly-published item (the draft is gone):
{
"dataItem": {
"id": "5331fc15-9441-4fd4-bc7b-7f6870c69228",
"dataCollectionId": "articles",
"data": { "_id": "5331fc15-...", "title": "Draft headline" }
}
}- Returns
NOT_FOUNDif no pending draft exists for that id.
Unpublish a live item (PUBLISHED/CHANGED → DRAFT)
Retracts a published item back to draft state. Pass the published collection id.
Endpoint: POST https://www.wixapis.com/wix-data/v2/items/unpublish
curl -X POST \
'https://www.wixapis.com/wix-data/v2/items/unpublish' \
-H 'Content-Type: application/json' \
-H 'Authorization: <AUTH>' \
-d '{
"dataCollectionId": "articles",
"dataItemId": "5331fc15-9441-4fd4-bc7b-7f6870c69228",
"copyToDraft": true
}'copyToDraft controls the two "keep vs discard" variants:
copyToDraft |
Behavior | Use for |
|---|---|---|
true (default) |
Removes the live copy, creates a draft seeded with the previously-published data. Any existing pending draft for that id is overwritten. | "Unpublish and keep changes" |
false |
Removes the live copy without creating a draft. No dataItem returned. |
"Unpublish and discard" |
- Response (
copyToDraft: true) carries the new draft, not the removed live item. - Returns
NOT_FOUNDif no published item exists with that id.
Revert to live version (CHANGED → PUBLISHED, discard the pending edit)
Discard the pending draft while keeping the live version as-is: delete the item from the drafts collection.
curl -X DELETE \
'https://www.wixapis.com/wix-data/v2/items/5331fc15-...?dataCollectionId=articles__drafts' \
-H 'Authorization: <AUTH>'Delete an item entirely (removes both versions)
Deleting must remove both the live item and any pending draft.
# live version
curl -X DELETE 'https://www.wixapis.com/wix-data/v2/items/<id>?dataCollectionId=articles' -H 'Authorization: <AUTH>'
# drafts collection, if a draft exists
curl -X DELETE 'https://www.wixapis.com/wix-data/v2/items/<id>?dataCollectionId=articles__drafts' -H 'Authorization: <AUTH>'4. Enable / disable the workflow on a collection
Enable — add the Draft Items plugin (requires collection-management permission). Use the dedicated endpoint; the Draft Items plugin cannot be added through the generic add-plugin call.
Endpoint: POST https://www.wixapis.com/wix-data/v2/collections/add-draft-items-plugin
curl -X POST 'https://www.wixapis.com/wix-data/v2/collections/add-draft-items-plugin' \
-H 'Content-Type: application/json' \
-H 'Authorization: <AUTH>' \
-d '{
"dataCollectionId": "articles",
"publishPluginConflictAction": "FAIL_WHEN_PUBLISH_INSTALLED"
}'publishPluginConflictAction controls what happens if the legacy Publish plugin is already installed:
| Value | Behavior |
|---|---|
FAIL_WHEN_PUBLISH_INSTALLED |
Fail if the Publish plugin is already installed. |
COPY_DRAFT_ITEMS_WITH_DRAFT_STATUS |
Copy draft items with draft status; where a published version already exists, discard the draft item. |
Disable — remove the plugin:
Endpoint: POST https://www.wixapis.com/wix-data/v2/collections/delete-draft-items-plugin
curl -X POST 'https://www.wixapis.com/wix-data/v2/collections/delete-draft-items-plugin' \
-H 'Content-Type: application/json' \
-H 'Authorization: <AUTH>' \
-d '{
"dataCollectionId": "articles",
"draftItemsRemovalAction": "FAIL_IF_DRAFT_ITEMS_EXIST"
}'draftItemsRemovalAction decides the fate of existing drafts:
| Value | Behavior |
|---|---|
FAIL_IF_DRAFT_ITEMS_EXIST |
Fail if any draft items exist. |
DISCARD_EXISTING_DRAFT_ITEMS |
Discard draft items (data loss). |
PUBLISH_EXISTING_DRAFT_ITEMS |
Publish draft items, overwriting any currently published items with the same ids. |
Permissions
At the REST level, every read/author/publish/unpublish call here goes through the Data Items API and requires write access to the collection's data items. Beyond that, individual draft and publish actions may be further permission-restricted per caller on the collection, and there's no way to introspect those permissions ahead of time — so attempt the action and handle authorization errors gracefully if the write is rejected.
Decision table — collection + desired action → API + permission
| Collection state | Desired action | API call | Permission needed |
|---|---|---|---|
| Draft Items plugin absent | Any write | Normal insert/update — writes go live immediately | Write Data Items |
| Draft Items enabled | Detect workflow | GET https://www.wixapis.com/wix-data/v2/collections/{id} → inspect plugins for the Draft Items plugin; read draftItemsPluginOptions.draftsCollectionId |
(read) |
| Draft Items enabled | Read published items | POST https://www.wixapis.com/wix-data/v2/items/query on the published id |
read |
| Draft Items enabled | Read drafts | POST https://www.wixapis.com/wix-data/v2/items/query on the drafts collection id |
read |
| PUBLISHED | Edit into a pending draft (→ CHANGED) | Create the draft (createDataItemDraft), then edit it on the drafts collection |
Write Data Items |
| — | Create new draft (→ DRAFT) | POST https://www.wixapis.com/wix-data/v2/items on the drafts collection |
Write Data Items |
| DRAFT / CHANGED | Publish (→ PUBLISHED) | POST https://www.wixapis.com/wix-data/v2/items/publish-draft (published id) |
Write Data Items |
| PUBLISHED / CHANGED | Unpublish, keep as draft (→ DRAFT) | POST https://www.wixapis.com/wix-data/v2/items/unpublish copyToDraft:true |
Write Data Items |
| PUBLISHED / CHANGED | Unpublish, discard | POST https://www.wixapis.com/wix-data/v2/items/unpublish copyToDraft:false |
Write Data Items |
| CHANGED | Revert to live version (discard edit) | DELETE https://www.wixapis.com/wix-data/v2/items/{id}?dataCollectionId=<drafts id> |
Write Data Items |
| any | Delete entirely (both versions) | Delete on the published id (+ drafts id if a draft exists) | Write Data Items |
| plain, no plugin | Enable workflow | POST https://www.wixapis.com/wix-data/v2/collections/add-draft-items-plugin |
Manage Data Collections |
Agent gotchas
- Resolve the drafts collection from the plugin. Read
draftItemsPluginOptions.draftsCollectionIdoff the published collection's Draft Items plugin rather than assuming a__draftssuffix. - Status is server-authoritative. Derive DRAFT/PUBLISHED/CHANGED from the published + drafts surfaces (or the value the API returns). Never compute it locally, and never render an optimistic status before the write confirms (confirm-then-render).
- Pass the published collection id to
publish-draftandunpublish— not the drafts collection id. Author and edit drafts against the drafts collection id. - Publishing deletes the draft. After
publish-draft, the pending draft no longer exists; the returned item is the live one. - Unpublish overwrites an existing draft when
copyToDraft: true— any pending edit for that id is replaced with the previously-published data. - Refetch after publish/unpublish. State changes across the published/draft surfaces are not guaranteed atomic; re-query rather than assuming local state. Wix Data is eventually consistent — use
consistentRead: trueif you must read immediately after a write.
Related Documentation
- Publish Data Item Draft
- Unpublish Data Item
- Data Collections API — plugin management
- CMS Data Items CRUD — insert/update/patch/delete/query shapes
- CMS Schema Management — creating and modifying collections
- Wix Data and Eventual Consistency