Skip to content

ICS export option#732

Open
Akhill2020 wants to merge 5 commits into
mainfrom
Export-ICS-feed
Open

ICS export option#732
Akhill2020 wants to merge 5 commits into
mainfrom
Export-ICS-feed

Conversation

@Akhill2020

@Akhill2020 Akhill2020 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Description: I have added ICS Export button similar to print calendar button user can check this from appearance and button will display below the calendar in grid/list view by pressing button user can download the ICS file.

Clickup: https://app.clickup.com/t/1867958/86d3e1phg
After: https://drive.google.com/file/d/1ZNIDXfrQaRbe_DZN-E_2Lsi454A3Nisc/view?usp=drivesdk

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Added an ICS Export option in calendar admin to enable an ICS download button on the frontend.
    • Added an optional ICS feed URL button for Pro, with support for extending action buttons.
  • Bug Fixes
    • Updated the print UI behavior to bind to the correct selector and hide the action bar during printing.
    • Improved ICS-related cache invalidation when deleting calendars.
  • Documentation
    • Updated the changelog for 4.1.0 with ICS Export notes and the frontend extension hook.

@Akhill2020
Akhill2020 requested a review from rosinghal July 16, 2026 09:13
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Akhill2020, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 29 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7c73d9fe-03b9-44a0-9865-01df5d970715

📥 Commits

Reviewing files that changed from the base of the PR and between d56f5fb and 252d959.

📒 Files selected for processing (4)
  • assets/css/default-calendar-grid.css
  • assets/js/default-calendar.js
  • includes/admin/metaboxes/settings.php
  • includes/ics-export.php
📝 Walkthrough

Walkthrough

Adds configurable frontend ICS export, generates .ics downloads from calendar events, centralizes calendar actions, adds print and URL interactions, styles the action bar, invalidates related feed caches, and documents the 4.1.0 feature.

Changes

ICS Export

Layer / File(s) Summary
Export configuration and plugin wiring
includes/admin/metaboxes/settings.php, includes/main.php
Adds and persists ICS export settings and registers the export handler during plugin loading.
ICS request and event generation
includes/ics-export.php
Validates requests, builds VCALENDAR/VEVENT content, escapes and folds RFC 5545 lines, and returns downloadable files.
Shared calendar action controls
includes/ics-export.php, includes/calendars/views/default-calendar-*.php, assets/css/default-calendar-grid.css, readme.txt
Centralizes action rendering, styles and hides the action bar for print, and updates the changelog.
Print and URL button interactions
assets/js/default-calendar.js
Uses the shared print-button class and copies ICS URLs with clipboard fallback and temporary feedback.
Feed cache invalidation
includes/functions/shared.php
Fires the ICS feed cache-clearing action for bulk and single-calendar transient deletion.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Visitor
  participant CalendarView
  participant Ics_Export
  participant Calendar
  Visitor->>CalendarView: Select ICS export
  CalendarView->>Ics_Export: Request export URL
  Ics_Export->>Calendar: Validate setting and load events
  Calendar-->>Ics_Export: Calendar event groups
  Ics_Export-->>Visitor: Download .ics file
Loading

Possibly related PRs

Suggested reviewers: rosinghal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main change: adding an ICS export option.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Export-ICS-feed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@includes/ics-export.php`:
- Around line 275-279: Update the line-folding loop to use mb_strcut() instead
of substr() when extracting each 75-byte segment, preserving the existing
CRLF-and-space folding format and remaining-line handling while ensuring
multibyte characters are never split.
- Around line 195-200: Update the event end-date calculation in the
`$event->end_dt` branch to normalize `end_dt` with `startOfDay()->addDay()`
before formatting it as `Ymd`. Remove the brittle `addSeconds(59)` logic while
preserving the existing fallback calculation for events without an end date.
- Around line 51-54: Update the calendar validation around
get_post($calendar_id) to allow exports only when the calendar is published or
the current user is authorized to access its private or draft status. Preserve
the existing invalid-post and wrong-post-type rejection, and terminate
unauthorized requests with the established 404 response without exposing
calendar events.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 186f69c9-9df8-46e3-82e8-c50d967d3f61

📥 Commits

Reviewing files that changed from the base of the PR and between 6756744 and 2d65ff9.

📒 Files selected for processing (7)
  • assets/css/default-calendar-grid.css
  • includes/admin/metaboxes/settings.php
  • includes/calendars/views/default-calendar-grid.php
  • includes/calendars/views/default-calendar-list.php
  • includes/ics-export.php
  • includes/main.php
  • readme.txt

Comment thread includes/ics-export.php
Comment thread includes/ics-export.php
Comment thread includes/ics-export.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
assets/js/default-calendar.js (1)

434-439: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make Copied! translatableassets/js/default-calendar.js hardcodes the copy feedback label; pass it through the localized script strings so non-English sites can translate it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/js/default-calendar.js` around lines 434 - 439, Update showCopied in
the default calendar script to obtain the “Copied!” feedback text from the
existing localized script strings instead of hardcoding it, while preserving the
timeout that restores originalLabel. Add or reuse the appropriate localization
key and ensure the localized value is displayed through $label.text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/css/default-calendar-grid.css`:
- Around line 610-617: Update the stroke declaration in .simcal-calendar-actions
.simcal-calendar-action-icon to use the lowercase currentcolor keyword required
by stylelint, leaving the surrounding icon styles unchanged.
- Around line 558-608: Update the shared focus styling for
.simcal-calendar-actions links and buttons to provide a clearly visible keyboard
focus indicator, replacing the outline: none !important rule with an accessible
focus treatment while preserving the existing hover appearance and other button
styling.

In `@assets/js/default-calendar.js`:
- Around line 454-459: Update copyWithTextarea so the temporary textarea is
visually hidden/offscreen before appending it, preventing flashes and scroll
jumps, then explicitly focus the created textarea before calling select().
Preserve the existing execCommand('copy') and cleanup behavior.

---

Nitpick comments:
In `@assets/js/default-calendar.js`:
- Around line 434-439: Update showCopied in the default calendar script to
obtain the “Copied!” feedback text from the existing localized script strings
instead of hardcoding it, while preserving the timeout that restores
originalLabel. Add or reuse the appropriate localization key and ensure the
localized value is displayed through $label.text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 05ee2bed-8274-4252-b072-4b39e16757ea

📥 Commits

Reviewing files that changed from the base of the PR and between 2d65ff9 and cee5146.

📒 Files selected for processing (5)
  • assets/css/default-calendar-grid.css
  • assets/js/default-calendar.js
  • includes/calendars/views/default-calendar-grid.php
  • includes/calendars/views/default-calendar-list.php
  • includes/ics-export.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/calendars/views/default-calendar-grid.php

Comment thread assets/css/default-calendar-grid.css
Comment thread assets/css/default-calendar-grid.css
Comment thread assets/js/default-calendar.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
includes/ics-export.php (3)

269-273: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not collapse ID-less events that share a start time.

When both uid and ical_id are empty, the deduplication key becomes -{$event->start}. Two distinct events at the same start time are therefore silently omitted, even though build_vevent() has a fallback identity based on title/start/end at Lines 300-303. Use the same fallback or another stable per-event identifier.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/ics-export.php` around lines 269 - 273, Update the deduplication key
logic near $dedupe_key so events without both uid and ical_id use the same
stable fallback identity as build_vevent(), including title, start, and end,
instead of relying only on the shared start time. Preserve existing uid and
ical_id-based deduplication for identified events.

322-326: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not emit DTEND equal to DTSTART.

When end_utc/end is missing, this path emits an explicit zero-length VEVENT, which is invalid. Omit DTEND for an event with no valid end, or derive a positive duration from the event model.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/ics-export.php` around lines 322 - 326, Update the event export
logic around $end_utc so missing or invalid end values do not fall back to
$start_utc and emit a zero-length DTEND. Omit the DTEND line when no valid end
exists, or derive and emit a strictly later end time from the event model;
preserve DTSTART generation.

Source: MCP tools


347-348: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use URI-specific escaping for the URL property.

URL takes a URI value, and RFC 5545 does not apply the TEXT backslash escaping rules to URI values. escape_text() rewrites commas, semicolons, and backslashes inside the URL, so links like https://example.com/a,b?x=1 are exported as https://example.com/a\,b?x=1. Sanitize the link without adding backslash escapes before using it in URL:.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/ics-export.php` around lines 347 - 348, Update the URL export in the
event serialization block to use URI-specific sanitization instead of
escape_text(), preserving commas, semicolons, and backslashes as valid URI
content. Keep the existing empty-link guard and URL: prefix unchanged.

Source: MCP tools

🧹 Nitpick comments (1)
includes/ics-export.php (1)

275-275: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid repeatedly copying the accumulated ICS payload.

array_merge($lines, ...) copies the growing $lines array for every event, which becomes quadratic for large calendars. Append each VEVENT line directly instead.

Proposed refactor
-					$lines = array_merge($lines, $this->build_vevent($event));
+					foreach ($this->build_vevent($event) as $vevent_line) {
+						$lines[] = $vevent_line;
+					}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/ics-export.php` at line 275, Update the event loop around
build_vevent to append each generated VEVENT line directly to the existing
$lines array instead of repeatedly calling array_merge, preserving the same
output order and contents without copying the accumulated payload.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@includes/ics-export.php`:
- Around line 269-273: Update the deduplication key logic near $dedupe_key so
events without both uid and ical_id use the same stable fallback identity as
build_vevent(), including title, start, and end, instead of relying only on the
shared start time. Preserve existing uid and ical_id-based deduplication for
identified events.
- Around line 322-326: Update the event export logic around $end_utc so missing
or invalid end values do not fall back to $start_utc and emit a zero-length
DTEND. Omit the DTEND line when no valid end exists, or derive and emit a
strictly later end time from the event model; preserve DTSTART generation.
- Around line 347-348: Update the URL export in the event serialization block to
use URI-specific sanitization instead of escape_text(), preserving commas,
semicolons, and backslashes as valid URI content. Keep the existing empty-link
guard and URL: prefix unchanged.

---

Nitpick comments:
In `@includes/ics-export.php`:
- Line 275: Update the event loop around build_vevent to append each generated
VEVENT line directly to the existing $lines array instead of repeatedly calling
array_merge, preserving the same output order and contents without copying the
accumulated payload.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e4466c2-0be5-4887-8afb-f7d988e46e56

📥 Commits

Reviewing files that changed from the base of the PR and between cee5146 and 38c0013.

📒 Files selected for processing (3)
  • includes/functions/shared.php
  • includes/ics-export.php
  • readme.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • readme.txt

@coderabbitai coderabbitai Bot mentioned this pull request Jul 24, 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.

1 participant