payload-plugin-scheduler
v1.1.0
Published
Scheduled posts plugin for PayloadCMS
Maintainers
Readme
payload-plugin-scheduler
Plugin that adds an imperative field-based scheduling flow on top of Payload's native functionality, with at-a-glance schedule status in the admin UI.
Starting in v3, Payload has a built-in workflow for scheduling posts via the job queue and "Schedule Publish" drawer. This plugin adds a configurable Date field to opted-in collections and globals that, when set to a future date, automatically queues a schedulePublish job in the background with waitUntil set to that date. This results in a more ergonomic workflow for editors where they can view the schedule status at a glance in the document editor, and sort/filter by publish time in the list view.
This plugin was originally written for Payload v2, and included a background scheduler that's since been superseded by v3's native queue. For Payload v2, use version <=0.1.3.
UI Demo


Requirements
- Payload v3
Installation
npm add payload-plugin-schedulerUsage
After configuring the plugin, ensure that you've regenerated payload's import map, otherwise the custom components won't display.
// payload.config.ts
import { buildConfig } from 'payload'
import { ScheduledPostPlugin } from 'payload-plugin-scheduler'
import Pages from './collections/Pages'
import Posts from './collections/Posts'
import Home from './globals/Home'
export default buildConfig({
collections: [Pages, Posts, Users],
globals: [Home],
plugins: [
ScheduledPostPlugin({
collections: ['pages', 'posts'],
globals: ['home'],
interval: 10,
}),
],
})Running Jobs
This plugin creates Payload Jobs; it does not run the job worker for you. Your host app is responsible for running Payload's Jobs Queue.
See Payload's docs for current deployment guidance:
Options
Enabled collections and globals must support drafts. The plugin merges the required scheduled-publish draft config into versions.drafts.schedulePublish and preserves existing version/draft settings.
collections?: string[]
ScheduledPostPlugin({
collections: ['pages', 'posts'],
})globals?: string[]
ScheduledPostPlugin({
globals: ['home'],
})interval?: number
Time interval, in minutes, passed to the Date field's time picker and Payload's scheduled-publish draft config. Defaults to 5.
ScheduledPostPlugin({
collections: ['posts'],
interval: 15,
})Your job queue cron interval should match this value, eg autoRun: [{ cron: '*/5 * * * *' }].
executionAccess?: 'user' | 'override'
Controls whose access permissions Payload uses when the scheduled publish job executes. Defaults to user.
userstores the authenticated scheduling user's ID on the job. Payload re-checks that user's current permissions at execution time. Scheduling without an authenticated user throws an error.overrideomits the user from the job, causing Payload to execute it with access overridden.
ScheduledPostPlugin({
collections: ['posts'],
executionAccess: 'override',
})publishDate?: object
Configure the generated publish-date field.
ScheduledPostPlugin({
collections: ['posts'],
// these are the default values
publishDate: {
name: 'publish_date',
label: 'Publish Date',
index: true,
admin: {
position: 'sidebar',
},
},
})All properties are configurable except type, timezone, admin.date.pickerAppearance, admin.date.timeIntervals, admin.components.afterInput, and admin.components.Cell.
Manual Field Placement
By default, the plugin injects the publish-date field into every opted-in collection and global. If you need to place the field manually, use the exported publishDate() helper.
import type { CollectionConfig } from 'payload'
import { publishDate } from 'payload-plugin-scheduler'
export const Posts: CollectionConfig = {
slug: 'posts',
versions: {
drafts: true,
},
fields: [
{
type: 'tabs',
tabs: [
{
label: 'Content',
fields: [
{
name: 'title',
type: 'text',
},
],
},
{
label: 'Publishing',
fields: [publishDate()],
},
],
},
],
}Manual placement is only valid inside collections or globals that are opted in through ScheduledPostPlugin({ collections, globals }).
You can also pass arguments to publishDate to override the global publishDate options, eg to override the admin display properties on a one-off basis. Overrides are merged with the top-level publishDate config, with name being the only field that's only configurable at the global level.
publishDate({
admin: {
width: '50%',
description: 'Custom description for this collection only'
}
})SafeRelationship
A drop-in replacement for Payload's relationship field, this is a helper field that throws an error if a user attempts to publish a document with relationships to unpublished documents.
import type { Field } from 'payload'
import { SafeRelationship } from 'payload-plugin-scheduler'
export const featuredContent: Field = SafeRelationship({
name: 'featured_content',
relationTo: ['posts', 'pages'],
hasMany: true,
})Debugging
Set DEBUG=payload-plugin-scheduler in your runtime env to enable debug logging.
Contributing
After cloning the repo and installing dependencies, run pnpm exec simple-git-hooks to setup automatic pre-commit linting.
Migration From v2
The v3 plugin no longer creates or writes to a plugin-owned scheduled_posts collection, and it no longer uses node-schedule. Scheduled publishes are represented as native Payload schedulePublish jobs in Payload's jobs collection.
To upgrade:
- Remove any application code that reads from or customizes
scheduled_posts. - Configure and run Payload Jobs in the host app. Dedicated servers and serverless deployments need different worker/cron strategies.
- If you use Payload
admin.timezones, verify the resulting<fieldName>_tzvalues in your own scheduling flow. - Generate and run a new database migration.
- Rebuild payload's import map.
