Once more than one person writes for a site, someone has to be the editor. The Editorial Workflow adds a review step to any content type: authors below Admin submit items for review instead of publishing them, and an Admin approves each submission — or sends it back as a draft with feedback. Nothing a contributor writes can reach the public site until someone with the Admin role signs off.
What it does
- Per-type opt-in. Each content type has its own Require review before publishing switch (Dashboard → Content Types → edit a type, in the options card next to Enable comments). Types that don't opt in behave exactly as before — the feature never forces review on anything.
- Submit for review. On a review-required type, users below Admin (Managers, Standard users) lose the Published option. Their status select offers Draft and Submit for review, and the primary save button becomes Submit for review. Submitting stamps who submitted and when, and the item enters the review queue as Pending review.
- A review queue. Every content type's list now has status tabs — All / Draft / Pending review / Published / Scheduled — with per-status counts. Pending items wear an amber Pending review badge and sort to the top of the default tab on review-required types, so waiting submissions are impossible to miss.
- Approve or request changes. An Admin opening a pending item sees an amber Awaiting review card naming the submitter, with two actions: Approve & publish (publishes immediately, or schedules when a future publish-at is set) and Request changes, which requires written feedback and sends the item back to Draft. The author sees that feedback in a Changes requested card on their draft, fixes it, and resubmits — resubmitting clears the old feedback.
- Email notifications both ways. Submitting emails every Admin-or-higher user a link to review the item. Approving or requesting changes emails the submitting author (including the feedback text). Mail failures never block the save.
- Activity log entries. Submissions, approvals, and change requests each write an explicit entry to the Activity Log (when that feature is on), on top of the ordinary content-change logging.
Leak safety
A pending item is invisible on the public site by construction: every public gate in the CMS — listings, detail pages, collection rows, search, sitemap, RSS — filters on status = 'published'. Pending items 404 on their detail URL and never appear in any listing. The scheduled-publishing command only flips scheduled items, so a pending item can never auto-publish; the only way out of the queue is an Admin's decision.
Rules and edge cases
- Roles. "Author" means any user below Admin (Standard, Manager). "Reviewer" means Admin or Super. There is no separate Editor role.
- Server-enforced. The publish restriction is validated server-side on every save — hiding the option in the UI is cosmetic; a forged request can't set
publishedon a review-required type either. - Already-published items. A below-Admin author editing an item that is already live may keep it published (their edits go straight to the live item) — but can never transition an item to published. To route edits of live content through review, have authors work in a draft instead.
- Admins skip the queue. Admin-or-higher users can still publish directly on review-required types, and may also park an item as Pending review themselves.
- Turning the feature off leaves any pending items hidden (they're still not published). Opening one in the editor demotes it to Draft on the next save; the list keeps showing a Pending review tab as long as stale pending items remain.
For developers
- Schema (
2026_07_10_020900_add_editorial_workflow_to_content):content_items.statusgains apendingenum value (MySQL ALTER guarded; SQLite strings need no change);content_itemsgainssubmitted_by/submitted_at/review_feedback/reviewed_by/reviewed_at;content_type_definitionsgainsrequires_review(default false). - Transitions live in the content
⚡create/⚡editVolt components:allowedStatuses()drives both the select options and the server validation;approveAndPublish()/requestChanges()are the reviewer actions. - Fan-out is
App\Support\EditorialWorkflow(recordSubmitted/recordApproved/recordChangesRequested) — writes theActivityLoggerentry (eventssubmitted,approved,changes_requested) and sends the mail notifications inApp\Notifications\EditorialWorkflow\*, fire-and-forget. - Model helpers:
ContentItem::requiresReview(),ContentItem::scopePendingReview(),submittedBy()/reviewedBy()relations. - This is a core content-system change gated by a feature flag, not an
app/Features/module — same pattern as the Events content type.