# Staging (Working Copies) Staging lets editors edit a copy of already-published content without touching the live version. A *working copy* is created next to the live *baseline*, edited in isolation, and then either applied back onto the baseline or discarded. ## Overview When a baseline is staged: - A working copy is cloned into the same parent container as the baseline. - The working copy is put into the *Arbeitskopie* (working copy) workflow state, so it is never publicly visible (see {doc}`website_workflow`). - The baseline and working copy are linked to each other. A baseline can have only one working copy at a time. - Editing happens on the working copy. The baseline stays live and unchanged. - Internal links and Simplelayout block references inside the working copy are rewritten so the copy is self-contained. When the editor is done, the working copy is either **applied** (its changes are merged back into the baseline and the working copy is removed) or **discarded** (the working copy is removed and the baseline is left untouched). Working copies and their baselines are protected: they cannot be moved, deleted, or copied through the normal content actions while the staging relationship exists. ## Staging actions Staging is driven by three browser actions on the staged content. Each accepts an `Accept: application/json` request header and then returns a JSON object with the URL the client should navigate to, instead of issuing an HTTP redirect. ### Create a working copy Call `create_working_copy` on the baseline. It clones the baseline into the parent container and returns the working copy URL. If a working copy already exists for this baseline, the request fails with `400 Bad Request`. ```http POST /Plone/my-page/create_working_copy HTTP/1.1 Host: localhost:8080 Accept: application/json ``` Response: ```json { "redirect_url": "http://localhost:8080/Plone/my-page-1" } ``` ### Apply a working copy Call `apply_working_copy` on the working copy. Its changes are merged back into the baseline, a review-history entry (“Updated from working copy”) is added to the baseline, the working copy is removed, and the baseline URL is returned. Calling this on something that is not a working copy fails with `400 Bad Request`. An optional `version-comment` form value is recorded as the comment on the baseline's review-history entry. ```http POST /Plone/my-page-1/apply_working_copy HTTP/1.1 Host: localhost:8080 Accept: application/json ``` Response: ```json { "redirect_url": "http://localhost:8080/Plone/my-page" } ``` ### Discard a working copy Call `delete_working_copy` on the working copy. The working copy is removed, the baseline is left unchanged, and the baseline URL is returned. Calling this on something that is not a working copy fails with `400 Bad Request`. ```http POST /Plone/my-page-1/delete_working_copy HTTP/1.1 Host: localhost:8080 Accept: application/json ``` Response: ```json { "redirect_url": "http://localhost:8080/Plone/my-page" } ``` ### Driving the actions from JavaScript ```javascript async function createWorkingCopy(baselineUrl, token) { const response = await fetch(`${baselineUrl}/create_working_copy`, { method: 'POST', headers: { 'Accept': 'application/json', 'Authorization': `Bearer ${token}` } }); const data = await response.json(); return data.redirect_url; // navigate the editor here } async function applyWorkingCopy(workingCopyUrl, token) { const response = await fetch(`${workingCopyUrl}/apply_working_copy`, { method: 'POST', headers: { 'Accept': 'application/json', 'Authorization': `Bearer ${token}` } }); const data = await response.json(); return data.redirect_url; // back to the (now updated) baseline } ``` ## How staged content appears A working copy is an ordinary content object living next to its baseline, so it is fetched, navigated, and edited through the standard content endpoints. It carries the *Arbeitskopie* workflow state, which keeps it out of public/anonymous views. For folderish content, the working-copy folder serialization is enriched so that a client editing the copy also sees the baseline's existing children. When listing the items of a working-copy folder, the response merges: - the items that physically live in the working copy (newly added or modified pages, served from the working-copy path), and - the baseline's existing items (served from the baseline path), so the editor sees the full structure rather than only the staged subset. ```http GET /Plone/folder-workingcopy?include_items=true HTTP/1.1 Host: localhost:8080 Accept: application/json ``` Response: ```{literalinclude} ./http-examples/staging-folder.resp :language: http ``` In the example, `new-page` and `modified-page` are served from the working-copy path (`/plone/folder-workingcopy/...`), while `existing-page` and `another-page` are surfaced from the baseline path (`/plone/folder/...`). This lets a frontend render the complete folder while the editor works on the copy. ## Availability Staging is only offered while the content is in a state where a working copy is allowed. The set of states that do *not* permit a working copy is configured through the registry record `wcs.backend.workflow.non_working_copy_states`. Content whose current state is listed there cannot be staged.