Skip to content

[6.x] Scheduled Revision Publishing - #11508

Open
edalzell wants to merge 50 commits into
statamic:6.xfrom
edalzell:feature/scheduled-revisions
Open

edalzell wants to merge 50 commits into
statamic:6.xfrom
edalzell:feature/scheduled-revisions

Conversation

@edalzell

@edalzell edalzell commented Feb 26, 2025 •

Copy link
Copy Markdown
Contributor

We have clients who have future campaigns, and they'd like to get all the content set up ahead of time so they can review and adjust. They use revisions.

So they'd like to schedule a revision to be published at a specific date/time.

Closes statamic/ideas#642.

Companion eloquent-driver PR: statamic/eloquent-driver#613

@edalzell
edalzell requested a review from jasonvarga February 28, 2025 22:58
@edalzell

Copy link
Copy Markdown
Contributor Author

@jasonvarga I'm not sure if the same event should be used. We don't really need it because the cache will be invalidated on the save, but folks might be listening for it?

@edalzell
edalzell marked this pull request as ready for review March 1, 2025 15:04
@tao

tao commented Sep 3, 2025

Copy link
Copy Markdown
Contributor

Nice, I built myself a whole publishing workflow on top of Statamic with the Revisions system to try achieve something similar.

I use my own publish controller and a combination of event listeners to put everything through a state machine to determine the next stage in the publishing workflow. So nothing actually gets published until it's at the end of the workflow.

Then I have some custom code to show the state in each Entry

Screenshot 2025-09-03 at 22 21 09 -

And then a Dashboard widget which is kind of like a publishing queue

Screenshot 2025-09-03 at 22 24 24 -

What you can't see in the screenshot is the translation review stage, which is another state in the workflow before something can be publishing. So translators can move something from draft into review and then only approved team members can review the entry and move it into the ready stage, so when we are actually ready to publish it then we hit the publish button again and it is actually published this time.

Screenshot 2025-09-03 at 22 30 53 -

It's a bit hacky overriding the publish controller but it works for us so we can stop translators from publishing directly to the website without a review, and easy to use because you just hit the publish button like normal to try go to the next stage. If you don't have permission it just stays in the same stage of the workflow, so you can edit it multiple times or even unpublished it to go backwards in the state machine. So it also lets us review new changes to content before they can be published and schedule them too.

@duncanmcclean duncanmcclean changed the title [5.x] Scheduled Revision Publishing [6.x] Scheduled Revision Publishing Jan 28, 2026
@duncanmcclean
duncanmcclean changed the base branch from 5.x to 6.x January 28, 2026 17:32
# Conflicts:
#	lang/en/messages.php
#	resources/js/components/entries/PublishActions.vue
#	src/Contracts/Revisions/Revision.php
#	src/Providers/AppServiceProvider.php
#	src/Revisions/Revisable.php
#	src/Revisions/Revision.php
#	src/Revisions/RevisionRepository.php
#	tests/Revisions/RepositoryTest.php
@edalzell

Copy link
Copy Markdown
Contributor Author

@jasonvarga this is finally ready for you!

@edalzell
edalzell marked this pull request as draft March 24, 2026 23:48
# Conflicts:
#	src/Http/Controllers/CP/Collections/EntryRevisionsController.php
@edalzell
edalzell marked this pull request as ready for review March 25, 2026 17:01

@jasonvarga jasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review findings (see inline comments for details).

Also blocking, not tied to a single line:

  • The branch no longer merges cleanly against 6.x (mergeStateStatus: DIRTY). Conflicts in src/Providers/AppServiceProvider.php and tests/Revisions/RepositoryTest.php, and resources/js/components/entries/PublishActions.vue auto-merges into a duplicate emits key (this branch has emits: ['saving', 'saved', 'failed'], 6.x now has emits: ['closed', 'saving', 'saved', 'failed']) — needs a manual resolve, not an accept-both merge.
  • No test exercises HandleRevisionSchedule::handle() at all — nothing asserts an entry actually becomes published, that the working copy is removed, or that a publish-action revision is recorded. A single test dispatching the job would have caught the TypeError and the missing published(true) call flagged inline below.
  • tests/Feature/Revisions/__fixtures__/123/{1553546421,1553546422,working}.yaml are added but nothing in the suite references them (the only __fixtures__ path used is tests/Revisions/__fixtures__/). Dead files.
  • There's an open, unanswered question from @edalzell on whether reusing the EntryScheduleReached event is correct here — its existing meaning is "an entry's own date has arrived," which isn't quite what's happening on a scheduled revision publish. Would like a maintainer call on this before merge.

Comment thread src/Jobs/HandleRevisionSchedule.php Outdated
Comment thread src/Jobs/HandleRevisionSchedule.php Outdated
Comment thread src/Providers/AppServiceProvider.php Outdated
Comment thread src/Entries/MinuteRevisions.php Outdated
Comment thread src/Entries/MinuteRevisions.php Outdated
Comment thread src/Contracts/Revisions/Revision.php Outdated
Comment thread src/Revisions/Revisable.php Outdated
Comment thread src/Revisions/Revisable.php Outdated
Comment thread resources/js/components/entries/PublishActions.vue Outdated
Comment thread src/Revisions/Revision.php Outdated
…visions

# Conflicts:
#	src/Providers/AppServiceProvider.php
#	tests/Revisions/RepositoryTest.php
Query the revisions store directly for revisions due (publish_at <= now) instead of scanning every entry, so missed scheduler ticks catch up. Publishing a scheduled revision now sets the entry published, records a publish revision, clears publish_at so it is not re-applied, and removes the working copy unless it changed since scheduling.
@edalzell

edalzell commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Merged 6.x and addressed the review:

  • Job rewritten: queries the revisions store for publish_at <= now (catches up missed ticks), publishes via a new Revisable::publishRevision() that sets published, records a publish revision, clears publish_at, and removes the working copy unless it changed since scheduling. Covered by HandleRevisionScheduleTest.
  • Scheduler keeps the handle_scheduled_entries gate and class-string job form; the revision job is only registered when revisions are enabled.
  • publish_at validated (nullable|date|after:now).
  • entry() dropped from the contract; createRevision() signature and ?? null defaults restored.
  • toArray()['publish_at'] is a timestamp.
  • UI: no default date, submit disabled until one is picked, revision history shows a "Scheduled" badge with the date. Cancelling/editing a schedule I'd rather do as a follow-up PR.
  • Dead fixtures removed.

Still open for a maintainer call: whether reusing EntryScheduleReached is right here.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scheduled publish/unpublish of revisions

3 participants