Skip to content

Add post scheduling feature#89

Open
kraftbj wants to merge 8 commits intotrunkfrom
shape-spec
Open

Add post scheduling feature#89
kraftbj wants to merge 8 commits intotrunkfrom
shape-spec

Conversation

@kraftbj
Copy link
Collaborator

@kraftbj kraftbj commented Mar 6, 2026

Summary

  • Adds a "Schedule" option to the More actions dropdown menu, allowing users to schedule posts for future publication
  • Uses @wordpress/components DateTimePicker in a popover with site timezone display
  • Confirmation button dynamically shows "Schedule" (future dates) or "Publish" (past dates), matching Gutenberg's pattern
  • Integrates with WordPress's native future post status and wp-cron for automatic publishing
  • Includes reschedule support for already-scheduled posts

Closes #31

Changes

PHP (backend):

  • press-this-plugin.php: Added 'future' to REST status enum, date parameter with ISO 8601 validation, and scheduling logic in save handler with publish_posts capability gating
  • class-wp-press-this-plugin.php: Added timezone, postStatus, postDate to pressThisData
  • includes/class-press-this-assets.php: Added wp-keyboard-shortcuts to fallback dependencies

JS (frontend):

  • src/components/Header.js: Schedule MenuItem, DateTimePicker Popover with timezone abbreviation, past/future date logic with 1-minute buffer, accessible aria-label
  • src/components/PressThisEditor.js: Extended handleSave to pass date, translatable schedule snackbar, locale-aware date formatting
  • src/App.js: Threads timezone/capabilities/postStatus/postDate to child components, updates postStatus state after scheduling
  • src/styles/partials/_header-schedule.scss: Responsive popover styles

Tests:

  • 5 PHP tests (status enum, date validation, post_date/gmt, capability gating, error handling)
  • 17 JS tests (save handler, UI rendering, integration workflows, accessibility)

Test plan

  • Verify "Schedule" appears in the More actions dropdown for users with publish_posts
  • Verify "Schedule" is hidden for contributors
  • Select a future date and confirm — post should save with future status, snackbar shows formatted date
  • Select a past date — button should read "Publish", post publishes immediately
  • After scheduling, reopen menu — should show "Reschedule" with pre-populated date
  • Test with site timezone different from browser timezone
  • Run vendor/bin/phpunit tests/php/test-scheduling.php (5 tests pass)
  • Run npx jest tests/components/ --no-coverage (17+ tests pass)

Allow users to schedule posts for future publication from the More
actions dropdown menu, using a DateTimePicker popover with timezone
display and dynamic Schedule/Publish confirmation button.

Closes #31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds post scheduling support to Press This, exposing a “Schedule/Reschedule” action in the header UI and wiring scheduled datetime through the frontend save flow into the REST save endpoint using WordPress’s native future status.

Changes:

  • Add a Schedule/Reschedule UI in the Header using DateTimePicker within a Popover, including timezone display and publish-vs-schedule logic.
  • Extend the save flow to submit an optional date parameter and show a schedule-specific snackbar on success.
  • Update the REST save endpoint to accept future status + validate date, set post_date / post_date_gmt, and gate scheduling behind publish_posts capability; add PHP/JS tests and styling.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
press-this-plugin.php Accept future status + date param in REST save route and implement scheduling logic in save handler.
class-wp-press-this-plugin.php Thread timezone, postStatus, and postDate into pressThisData for the React app.
includes/class-press-this-assets.php Add wp-keyboard-shortcuts to fallback dependency list.
src/App.js Maintain postStatus/postDate in React state and thread timezone/status/date to Header + Editor.
src/components/Header.js Implement Schedule/Reschedule menu item + DateTimePicker popover workflow and timezone label.
src/components/PressThisEditor.js Send date in REST body, show schedule snackbar, and notify parent of status/date changes.
src/styles/main.scss Import new schedule popover styles.
src/styles/partials/_header-schedule.scss Add styles for schedule popover layout and responsive sizing.
tests/php/test-scheduling.php Add backend tests for scheduling status/date validation, capability gating, and date fields.
tests/components/header-schedule-ui.test.js Add string-based UI coverage for schedule menu/popover/confirm logic.
tests/components/save-handler-scheduling.test.js Add string-based tests for save handler date threading + schedule snackbar behavior.
tests/components/scheduling-integration.test.js Add end-to-end string-based checks across Header → App → Editor save flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Use mysql_to_rfc3339() for postDate to ensure consistent cross-browser parsing
- Derive timezone abbreviation from selected date instead of current date (DST accuracy)
- Avoid browser-timezone reinterpretation in formatScheduleDate by formatting in UTC
- Rename error code to press_this_invalid_date_format for API consistency
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

kraftbj added 2 commits March 7, 2026 00:17
- Parse date parts in getTimezoneAbbreviation to avoid DST mismatch from browser-local interpretation
- Use IANA timezone string directly in formatScheduleDate snackbar instead of deriving abbreviation from wrong instant
- Anchor date validation regex to reject trailing timezone qualifiers (Z, -05:00, etc.)
- Fix block_http filter accepted_args for PHP 8+ compatibility
- Replace new Date() parsing in isFutureDate with parseNaiveToMs() that
  extracts date parts directly via Date.UTC(), avoiding browser-local
  timezone interpretation that breaks at DST boundaries
- Use IANA timezone string in formatScheduleDate snackbar (simpler, always correct)
- Parse date parts in getTimezoneAbbreviation via Date.UTC() for DST accuracy
- Anchor date validation regex to reject trailing tz qualifiers
- Fix block_http filter accepted_args for PHP 8+ compatibility
@kraftbj kraftbj requested a review from Copilot March 6, 2026 23:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

kraftbj added 2 commits March 16, 2026 13:57
…dule coverage

- Export scheduling utility functions (isFutureDate, parseNaiveToMs,
  getCurrentDateInTimezone, getTimezoneAbbreviation, formatScheduleDate)
  as named exports for direct testing
- Rewrite all 3 JS test files to call functions with real inputs and
  assert outputs, replacing fs.readFileSync string-matching approach
- Add cross-module integration tests verifying Header utilities produce
  data consumable by Editor formatting
- Add PHP test for rescheduling an already-scheduled post to a new date
- Add explanatory comment for edit_date flag in save handler
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +112 to +116
try {
const now = new Date();
const formatter = new Intl.DateTimeFormat( 'en-CA', {
timeZone: tz,
year: 'numeric',
Intl.DateTimeFormat only accepts IANA zone names and "UTC", not
fixed-offset strings like "UTC+2". Add an explicit path that parses
the offset and applies it manually. Also normalize the catch fallback
to return a naive datetime string (no Z suffix or milliseconds) so
scheduled dates stay consistent.
@kraftbj kraftbj added this to the 2.1.0 milestone Mar 16, 2026
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.

Allow Press This to schedule a post as an alternate to Publish

2 participants