Skip to content

Add post scheduling feature#89

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

Add post scheduling feature#89
kraftbj wants to merge 4 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.

Comment on lines +1559 to +1560
'postStatus' => get_post_status( $post_ID ),
'postDate' => mysql_to_rfc3339( get_post( $post_ID )->post_date ),
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

$post is already available from get_default_post_to_edit(), but this adds fresh get_post_status()/get_post() calls. Consider using the existing $post object (e.g., $post->post_status / $post->post_date) to avoid redundant lookups and keep the data source consistent.

Suggested change
'postStatus' => get_post_status( $post_ID ),
'postDate' => mysql_to_rfc3339( get_post( $post_ID )->post_date ),
'postStatus' => $post->post_status,
'postDate' => mysql_to_rfc3339( $post->post_date ),

Copilot uses AI. Check for mistakes.
* in the user's preferred language rather than hardcoded to English.
*
* @param {string} dateString ISO date string to format.
* @param {string} timezone IANA timezone string (e.g., "America/New_York").
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

The JSDoc for formatScheduleDate() says the timezone param is an IANA timezone (e.g. "America/New_York"), but wp_timezone_string() can also return fixed-offset strings like "UTC+2". Updating the doc (or normalizing timezone values) would prevent incorrect assumptions by future callers.

Suggested change
* @param {string} timezone IANA timezone string (e.g., "America/New_York").
* @param {string} timezone Timezone label (e.g., "America/New_York" or "UTC+2").

Copilot uses AI. Check for mistakes.
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