Skip to content

Add subscribable ICS calendar feed for #277#278

Merged
dgershman merged 3 commits into
mainfrom
feature/mayo-277-need-ics-feed
May 20, 2026
Merged

Add subscribable ICS calendar feed for #277#278
dgershman merged 3 commits into
mainfrom
feature/mayo-277-need-ics-feed

Conversation

@dgershman

Copy link
Copy Markdown
Contributor

Closes #277.

Summary

  • Rewrites includes/CalendarFeed.php so ?feed=mayo_events is a true subscribable feed:
    • Recurring events emit RRULE (daily / weekly with BYDAY / monthly by date / monthly by nth or last weekday) with UNTIL from the pattern's end date, and EXDATE entries for skipped_occurrences. Series now show as a single repeating event in Google / Apple / Outlook instead of one shot at the base date.
    • Emits a per-timezone VTIMEZONE block and TZID-anchored DTSTART / DTEND so events render in their original local time instead of being coerced to UTC.
    • Adds Cache-Control: public, max-age=900, Last-Modified from MAX(post_modified_gmt), and If-Modified-Since / 304 handling for polling clients.
    • Stable UIDs: mayo-{id}@host for series; mayo-{id}-{date}@host for the fallback-expansion path.
    • Emits CREATED / LAST-MODIFIED per VEVENT so calendars detect updates.
    • Raises the SQL cap from 100 to 500 base events; recurring series are no longer truncated by the cap.
    • Fixes a latent ordering bug in escape_ical_text that double-escaped newlines.
  • Adds a Subscribe popover to the calendar dashicon in EventList.js: copy-able feed URL, webcal:// quick-subscribe link, one-time .ics download, and a one-liner explaining how to paste it into Google Calendar.
  • Updates tests/Unit/CalendarFeedTest.php to cover the new RRULE, EXDATE, VTIMEZONE, and fallback paths (24 tests, 514 in the full suite, all green).
  • Changelog entry under = 1.9.0 = in readme.txt; POT regenerated for the new strings.

Test plan

  • composer test — 514 tests / 1152 assertions / OK
  • npm run build
  • composer make-pot (new strings appear in languages/mayo-events-manager.pot)
  • On a staging WordPress, click the Subscribe popover → "Subscribe in default calendar app" opens Apple Calendar / Outlook with the URL prefilled.
  • Copy the URL → paste in Google Calendar → Other calendars → From URL. Verify: single events at correct local time; weekly recurring shows as a true repeating series; "2nd Wednesday" monthly shows as a recurring series; an event with skipped occurrences skips those dates.
  • Approve a new event in WP admin; confirm it appears in Google Calendar within Google's poll window (~12-24h).
  • curl -i 'https://site/?feed=mayo_events' shows Cache-Control and Last-Modified; a second request with If-Modified-Since returns 304.

dgershman added 3 commits May 19, 2026 23:57
The existing ?feed=mayo_events endpoint was a one-shot ICS download:
recurring events only emitted their base occurrence, all times were
flattened to UTC, and there was no cache plumbing for polling clients.
The UI also surfaced it as a download link, so users didn't know they
could subscribe to it.

Rewrites CalendarFeed to:
- Emit RRULE/EXDATE for recurring events (daily, weekly with BYDAY,
  monthly by date, monthly by nth/last weekday) with UNTIL when an
  end date is set, so series display as a single repeating event in
  Google Calendar / Apple Calendar / Outlook.
- Emit VTIMEZONE blocks and TZID-anchored DTSTART/DTEND so events
  display in their original timezone instead of being coerced to UTC.
- Add Cache-Control, Last-Modified, and If-Modified-Since/304 handling
  so subscribed clients poll politely.
- Use stable UIDs (mayo-{id}@host for series, mayo-{id}-{date}@host
  for fallback-expanded occurrences) and emit CREATED/LAST-MODIFIED
  so calendars detect updates.
- Raise the 100-event SQL cap to 500.

Adds a Subscribe popover to the EventList calendar icon with the
copy-able feed URL, a webcal:// quick-subscribe link, a one-time .ics
download, and Google Calendar instructions.

Fixes a latent escape_ical_text ordering bug where newlines were
double-escaped because backslashes were escaped after newline
replacement.
Cut a release containing the #277 subscribable ICS feed work.
The new calendar dashicon trigger used class .mayo-subscribe-button, which
collided with the unrelated newsletter-signup button styling further down
in public.css that paints it WordPress blue. Renames the icon-bar class
to .mayo-cal-subscribe-button so it stays the muted gray used by the
other action-bar icons.
@dgershman dgershman merged commit ae289df into main May 20, 2026
3 checks passed
@dgershman dgershman deleted the feature/mayo-277-need-ics-feed branch May 20, 2026 04:10
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.

Need ICS feed

1 participant