Skip to content

Add [if-event] conditional, [link url], grouped-calendar priority + sortable admin UI#690

Open
rosinghal wants to merge 4 commits into
mainfrom
rohit/if-event
Open

Add [if-event] conditional, [link url], grouped-calendar priority + sortable admin UI#690
rosinghal wants to merge 4 commits into
mainfrom
rohit/if-event

Conversation

@rosinghal
Copy link
Copy Markdown
Member

@rosinghal rosinghal commented May 23, 2026

Summary

  • New [if-event id--in="…" id--not-in="…"] event-builder tag for conditional content; accepts full UIDs, event-IDs alone, and Google Calendar URL base64 IDs
  • New url attribute on [link] to override the event's own URL
  • Grouped calendars: events from earlier-listed source calendars win ties when start times are equal (new Event::$calendar_priority)
  • Grouped calendar admin: Select2 multiselect replaced with a jQuery UI Sortable widget — selection order is the priority order

Test plan

  • Add [if-event id--in="<uid>"]X[/if-event] to the event template and confirm X only renders for matching events; repeat with id--not-in
  • Try all three ID formats (full xxx@google.com, bare xxx, base64 URL ID) and confirm each matches
  • [link url="https://example.com"]click[/link] renders an anchor to example.com; omitting url still links to \$event->link
  • In a grouped calendar with two source calendars that have events at the same start time, reorder them in the admin and verify display order follows the new order
  • In the grouped calendar admin: add via dropdown, remove via ×, drag to reorder; save, reload, and confirm order persists

Summary by CodeRabbit

Release Notes

  • New Features

    • Added if-event template tag for conditional event rendering based on event ID
    • Grouped calendars can now be reordered in admin settings
  • Improvements

    • Event sorting enhanced: now respects calendar order alongside start date and event title in both grid and list views
    • Calendar ordering is preserved when displaying grouped calendar events

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

Warning

Review limit reached

@rosinghal, we couldn't start this review because you've used your available PR reviews for now.

Your plan currently allows 1 review/hour. Refill in 50 minutes and 21 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dee8470c-5ffd-4e2e-bc47-5773903ceaee

📥 Commits

Reviewing files that changed from the base of the PR and between 02111f5 and 2db75d5.

📒 Files selected for processing (6)
  • assets/js/admin.js
  • includes/calendars/views/default-calendar-grid.php
  • includes/calendars/views/default-calendar-list.php
  • includes/events/event-builder.php
  • includes/feeds/admin/grouped-calendars-admin.php
  • includes/feeds/grouped-calendars.php
📝 Walkthrough

Walkthrough

This PR implements calendar priority ordering for grouped calendars. It adds a calendar_priority property to events, assigns priority indices based on calendar position, reorders the admin UI to reflect saved ordering with Select2 integration, extends template tags with conditional event filtering, and updates both grid and list views to sort events by priority before title.

Changes

Calendar Priority Ordering

Layer / File(s) Summary
Event priority data model and assignment
includes/events/event.php, includes/feeds/grouped-calendars.php
Event class introduces calendar_priority property (default PHP_INT_MAX). Grouped_Calendars::get_events() iterates calendars with index as priority and assigns calendar_priority to each event from all nested calendar groupings.
Admin settings UI and Select2 reordering
includes/feeds/admin/grouped-calendars-admin.php, assets/js/admin.js
Admin panel normalizes saved calendar IDs and reorders displayed calendar options to match the saved selection order. Select2 handler appends newly selected options to the end and re-triggers change event.
Event template conditionals and link URL override
includes/events/event-builder.php
if-event conditional tag registers and implements ID-based inclusion/exclusion filtering via matches_event_id() helper, which supports direct UID match, @-suffix prefix match, and base64-decoded URL-style ID matching. Link/URL tag now accepts optional url attribute override.
View rendering with priority-aware event sorting
includes/calendars/views/default-calendar-grid.php, includes/calendars/views/default-calendar-list.php
Grid and list views introduce local_key() helper to compute timezone-local sort keys from start_dt Carbon instances, then sort events by local key, calendar_priority, and finally title.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Priorities gleam with each calendar's grace,
Events now sorted in their proper place,
Select2 dances as selections appear,
Grouped with precision, the order is clear!
Condition, template, and sorting align—
Calendar harmony, oh how you shine!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main features added in the PR: a conditional event tag, link URL override, grouped-calendar priority, and sortable admin UI.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rohit/if-event

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 and usage tips.

@rosinghal rosinghal requested a review from Akhill2020 May 23, 2026 07:48
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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/calendars/views/default-calendar-grid.php`:
- Around line 310-329: The primary sort key in local_key() currently formats
$event->start_dt in the event's timezone which can yield different string keys
for the same instant across timezones; change local_key() to return a
timezone-normalized epoch value (e.g. convert $event->start_dt to UTC and return
its UNIX timestamp or microsecond epoch) so comparisons in cmp() use the same
instant for all events; keep the existing fallback for non-Carbon $event->start
but convert it to a normalized epoch too, and ensure the returned value is
comparable (int or numeric string) so the tie-breaker logic (calendar_priority
and title) can run correctly.

In `@includes/calendars/views/default-calendar-list.php`:
- Around line 498-517: The primary sort key function local_key currently formats
start_dt in local time which can split identical instants across timezones and
bypass calendar_priority; change local_key to return a timezone-canonical
instant (e.g. UTC timestamp or Unix epoch) for start_dt instead of a
local-formatted string, and ensure the fallback for $event->start returns the
same canonical representation (numeric/string) so cmp's comparisons use the true
instant; update local_key and keep cmp's tie handling (calendar_priority and
title) unchanged.

In `@includes/events/event-builder.php`:
- Around line 584-603: The code block handling the 'if-event' shortcode (using
matches_event_id, $event->uid and calendar->get_event_html) has formatting drift
flagged by CI; run your project's Prettier formatter (e.g., prettier --write)
over this file to normalize spacing and line breaks, then re-run lint/CI and
commit the formatted changes; also apply the same formatting pass to the other
affected region around the logic that spans the 1251-1275 lines to keep the file
consistent.
🪄 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: 02e3b130-9e34-4f39-8575-c2a56e9be847

📥 Commits

Reviewing files that changed from the base of the PR and between 49c1d6a and 02111f5.

📒 Files selected for processing (7)
  • assets/js/admin.js
  • includes/calendars/views/default-calendar-grid.php
  • includes/calendars/views/default-calendar-list.php
  • includes/events/event-builder.php
  • includes/events/event.php
  • includes/feeds/admin/grouped-calendars-admin.php
  • includes/feeds/grouped-calendars.php

Comment on lines +310 to 329
private static function local_key($event)
{
return $event->start_dt instanceof Carbon ? $event->start_dt->format('YmdHis') : (string) $event->start;
}

private static function cmp($a, $b)
{
if ($a->start == $b->start) {
$a_local = self::local_key($a);
$b_local = self::local_key($b);
if ($a_local === $b_local) {
if ($a->calendar_priority != $b->calendar_priority) {
return $a->calendar_priority < $b->calendar_priority ? -1 : 1;
}
if ($a->title == $b->title) {
return 0;
}
return $a->title < $b->title ? -1 : 1;
} else {
return $a->start < $b->start ? -1 : 1;
}
return $a_local < $b_local ? -1 : 1;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a timezone-normalized timestamp key for primary sort.

On Line [312], formatting start_dt in the event’s own timezone can produce different keys for the same instant, so Line [320] tie-breaking by calendar_priority may never run for cross-timezone events. Use a normalized epoch key instead.

Suggested fix
 private static function local_key($event)
 {
-	return $event->start_dt instanceof Carbon ? $event->start_dt->format('YmdHis') : (string) $event->start;
+	return $event->start_dt instanceof Carbon
+		? $event->start_dt->copy()->setTimezone('UTC')->getTimestamp()
+		: intval($event->start);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static function local_key($event)
{
return $event->start_dt instanceof Carbon ? $event->start_dt->format('YmdHis') : (string) $event->start;
}
private static function cmp($a, $b)
{
if ($a->start == $b->start) {
$a_local = self::local_key($a);
$b_local = self::local_key($b);
if ($a_local === $b_local) {
if ($a->calendar_priority != $b->calendar_priority) {
return $a->calendar_priority < $b->calendar_priority ? -1 : 1;
}
if ($a->title == $b->title) {
return 0;
}
return $a->title < $b->title ? -1 : 1;
} else {
return $a->start < $b->start ? -1 : 1;
}
return $a_local < $b_local ? -1 : 1;
}
private static function local_key($event)
{
return $event->start_dt instanceof Carbon
? $event->start_dt->copy()->setTimezone('UTC')->getTimestamp()
: intval($event->start);
}
private static function cmp($a, $b)
{
$a_local = self::local_key($a);
$b_local = self::local_key($b);
if ($a_local === $b_local) {
if ($a->calendar_priority != $b->calendar_priority) {
return $a->calendar_priority < $b->calendar_priority ? -1 : 1;
}
if ($a->title == $b->title) {
return 0;
}
return $a->title < $b->title ? -1 : 1;
}
return $a_local < $b_local ? -1 : 1;
}
🧰 Tools
🪛 PHPMD (2.15.0)

[warning] 315-329: Avoid unused private methods such as 'cmp'. (undefined)

(UnusedPrivateMethod)

🤖 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/calendars/views/default-calendar-grid.php` around lines 310 - 329,
The primary sort key in local_key() currently formats $event->start_dt in the
event's timezone which can yield different string keys for the same instant
across timezones; change local_key() to return a timezone-normalized epoch value
(e.g. convert $event->start_dt to UTC and return its UNIX timestamp or
microsecond epoch) so comparisons in cmp() use the same instant for all events;
keep the existing fallback for non-Carbon $event->start but convert it to a
normalized epoch too, and ensure the returned value is comparable (int or
numeric string) so the tie-breaker logic (calendar_priority and title) can run
correctly.

Comment on lines +498 to 517
private static function local_key($event)
{
return $event->start_dt instanceof Carbon ? $event->start_dt->format('YmdHis') : (string) $event->start;
}

private static function cmp($a, $b)
{
if ($a->start == $b->start) {
$a_local = self::local_key($a);
$b_local = self::local_key($b);
if ($a_local === $b_local) {
if ($a->calendar_priority != $b->calendar_priority) {
return $a->calendar_priority < $b->calendar_priority ? -1 : 1;
}
if ($a->title == $b->title) {
return 0;
}
return $a->title < $b->title ? -1 : 1;
} else {
return $a->start < $b->start ? -1 : 1;
}
return $a_local < $b_local ? -1 : 1;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Primary sort key has the same cross-timezone tie bug as grid view.

On Line [500], using local formatted time from start_dt can split equal instants into different buckets, so priority ordering on Lines [508-510] is bypassed.

Suggested fix
 private static function local_key($event)
 {
-	return $event->start_dt instanceof Carbon ? $event->start_dt->format('YmdHis') : (string) $event->start;
+	return $event->start_dt instanceof Carbon
+		? $event->start_dt->copy()->setTimezone('UTC')->getTimestamp()
+		: intval($event->start);
 }
🧰 Tools
🪛 PHPMD (2.15.0)

[warning] 503-517: Avoid unused private methods such as 'cmp'. (undefined)

(UnusedPrivateMethod)

🤖 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/calendars/views/default-calendar-list.php` around lines 498 - 517,
The primary sort key function local_key currently formats start_dt in local time
which can split identical instants across timezones and bypass
calendar_priority; change local_key to return a timezone-canonical instant (e.g.
UTC timestamp or Unix epoch) for start_dt instead of a local-formatted string,
and ensure the fallback for $event->start returns the same canonical
representation (numeric/string) so cmp's comparisons use the true instant;
update local_key and keep cmp's tie handling (calendar_priority and title)
unchanged.

Comment thread includes/events/event-builder.php
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