Draft & Publish
The Builder’s editing model is built around a draft/publish split. This page covers what merchants need to know about it: the publish modal, the validator, the merge-with-other-edits flow, and the rollback when something goes wrong.
For the architectural picture (atomic snapshot writes, optimistic locking, the PHPStan rule that enforces published-only on the storefront), see Drafts, Publishing & Snapshots.
The publish flow
Section titled “The publish flow”Every edit lives in the draft tables until you explicitly publish. When you click Publish in the Builder top bar, the publish modal opens.
[SCREENSHOT: The publish modal with a publish-comment field and the Publish button.]
The modal contains:
- A short explainer paragraph describing what publish does.
- A Publish comment textarea (optional). A short note that’s stored alongside the snapshot — handy “what changed” labels: “added vegan filter”, “trim copy on Q3”.
- Cancel and Publish buttons.
- If validation fails when you click Publish, the modal renders an inline alert listing the failures.
On a successful publish the modal closes and the Builder shows a “published” toast.
What the validator checks
Section titled “What the validator checks”The validator runs continuously, not just at publish time. It surfaces errors in the Validation footer at the bottom of the Edit tab. Common checks:
- Every answer routes somewhere.
- Every question has at least one answer.
- Every routing target points at an existing question in the same variant, or → End.
- Every upvote references a product or variant that still exists in WooCommerce.
- Variants with traffic weight 0 aren’t marked active.
- Image-choice answers have images attached.
If the validator is red, save your draft (the Builder auto-saves on every change) and fix the errors one by one. The validator updates as you edit.
Publishing changes already in flight
Section titled “Publishing changes already in flight”The real safety on concurrent edits is the expected_draft_version
integer that every PATCH and publish carries:
- The Builder sees the draft at version N and includes N in every request.
- If the server’s current version has moved on (your colleague saved
while you were editing), the request returns
409 dd_draft_version_mismatch. - The Builder shows a “refresh to see the latest” banner and pulls the new state. Your local edits stay in the editor until you reconcile.
Unpublishing — there isn’t one
Section titled “Unpublishing — there isn’t one”There is no “unpublish” button in 0.1.0. A published snapshot stays published until either:
- You publish a new snapshot (which becomes the live one).
- You delete the quiz (soft-delete via
DELETE /quizzes/{id}). - You restore an older snapshot through the History tab and publish that.
The reasoning is conservative — accidentally unpublishing a live quiz breaks every embedded shortcode on the storefront. Restoring an old snapshot and republishing achieves the same outcome with an explicit review step.
The Builder’s auto-save
Section titled “The Builder’s auto-save”The Builder auto-saves on every change, so navigating away from the Edit tab doesn’t lose your work. Saves go to the draft tables; the storefront sees none of them until you publish.
If you want to throw away your in-progress draft and start fresh from the published snapshot, the History tab lets you restore the current published snapshot — see History & Snapshots.
What’s emitted on a publish
Section titled “What’s emitted on a publish”The dino_discover_quiz_published action fires after a successful
publish with (int $quiz_id, int $snapshot_id). Subscribe in PHP if
you need to:
- Invalidate a CDN cache for the page hosting the quiz.
- Notify a Slack channel that a quiz was published.
- Trigger a re-index in an external search tool.
See Hook Reference for the signature.
What’s next
Section titled “What’s next”- History & Snapshots — the rollback workflow.
- Settings — capability scoping for publish access.
- Drafts, Publishing & Snapshots — the deeper architectural picture.
- Hook Reference —
quiz_publishedand related lifecycle hooks.