From 8f6e00260950057cdba637d69de01a1c0875fbf0 Mon Sep 17 00:00:00 2001 From: edalzell Date: Fri, 17 Apr 2026 06:41:34 -0700 Subject: [PATCH 1/8] wip --- src/Tags/Events.php | 23 ++++++++++++++++------- tests/Tags/EventsTest.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/Tags/Events.php b/src/Tags/Events.php index 537b64f..654efe1 100755 --- a/src/Tags/Events.php +++ b/src/Tags/Events.php @@ -7,6 +7,7 @@ use Carbon\CarbonInterface; use Carbon\CarbonPeriod; use Carbon\CarbonPeriodImmutable; +use Closure; use Illuminate\Pagination\Paginator; use Illuminate\Support\Collection; use Statamic\Contracts\Query\Builder; @@ -41,14 +42,14 @@ public function calendar(): Collection $month = $this->params->get('month', now()->englishMonth); $year = $this->params->get('year', now()->year); - $from = parse_date($month . ' ' . $year)->startOfMonth()->startOfWeek(); - $to = parse_date($month . ' ' . $year)->endOfMonth()->endOfWeek(); + $from = parse_date($month.' '.$year)->startOfMonth()->startOfWeek(); + $to = parse_date($month.' '.$year)->endOfMonth()->endOfWeek(); $occurrences = $this ->generator() ->between(from: $from, to: $to) ->groupBy($this->spanningDays()) - ->map(fn(EntryCollection $occurrences, string $date) => $this->day(date: $date, occurrences: $occurrences)); + ->map(fn (EntryCollection $occurrences, string $date) => $this->day(date: $date, occurrences: $occurrences)); $days = $this->output($this->makeEmptyDates(from: $from, to: $to)->merge($occurrences)->values()); @@ -139,8 +140,16 @@ private function day(string $date, EntryCollection $occurrences): array { return [ 'date' => $date, - 'dates' => $occurrences, - 'occurrences' => $occurrences, + 'occurrences' => $occurrences->map(function (Entry $occurrence) use ($date): Entry { + if ($occurrence->spanning) { + $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); + $occurrence + ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) + ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); + } + + return $occurrence; + })->values(), ]; } @@ -244,7 +253,7 @@ private function parseTermIds(string $key, array|Builder|string $terms): array ->all(); } - private function spanningDays(): \Closure + private function spanningDays(): Closure { return function (Entry $occurrence) { $spanningDays = CarbonPeriodImmutable::between( @@ -252,7 +261,7 @@ private function spanningDays(): \Closure $occurrence->end->endOfDay() )->toArray(); - return collect($spanningDays)->map(fn(CarbonImmutable $date) => $date->toDateString())->all(); + return collect($spanningDays)->map(fn (CarbonImmutable $date) => $date->toDateString())->all(); }; } } diff --git a/tests/Tags/EventsTest.php b/tests/Tags/EventsTest.php index 51a5b80..a925ffc 100755 --- a/tests/Tags/EventsTest.php +++ b/tests/Tags/EventsTest.php @@ -456,3 +456,34 @@ expect($occurrences)->toHaveCount(1) ->first()->spanning->toBeTrue(); }); + +it('sets "spanning-start" and "spanning-end"', function () { + Carbon::setTestNow(Carbon::parse('April 16 10:00am')); + + Entry::make() + ->collection('events') + ->slug('single-event') + ->id('single-event') + ->data([ + 'title' => 'Event', + 'start_date' => Carbon::now()->toDateString(), + 'start_time' => '11:00', + 'end_time' => '23:00', + ])->save(); + + $this->tag + ->setContext([]) + ->setParameters(['timezone' => 'Europe/Kyiv']); + + $days = $this->tag->calendar(); + $firstSpanningOccurrence = $days[17]['occurrences'][1]; + $secondSpanningOccurrence = $days[18]['occurrences'][0]; + + ray($days, $firstSpanningOccurrence); + expect($firstSpanningOccurrence) + ->spanning_start->toBeTrue() + ->spanning_end->toBeFalse(); + // expect($secondSpanningOccurrence) + // ->spanning_start->toBeFalse() + // ->spanning_end->toBeTrue(); +}); From afe0029e89cf0d1b012c7cf159ee8906cad02120 Mon Sep 17 00:00:00 2001 From: Marco Rieser Date: Fri, 17 Apr 2026 16:42:04 +0200 Subject: [PATCH 2/8] Return a clone of the occurrence, so we don't modify the same instance multiple times --- src/Tags/Events.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Tags/Events.php b/src/Tags/Events.php index 654efe1..252deaa 100755 --- a/src/Tags/Events.php +++ b/src/Tags/Events.php @@ -141,14 +141,16 @@ private function day(string $date, EntryCollection $occurrences): array return [ 'date' => $date, 'occurrences' => $occurrences->map(function (Entry $occurrence) use ($date): Entry { - if ($occurrence->spanning) { - $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); - $occurrence - ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) - ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); + if (!$occurrence->spanning) { + return $occurrence; } - return $occurrence; + $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); + $occurrence + ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) + ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); + + return clone $occurrence; })->values(), ]; } From 003757e88711da05e7bb81208ec2cff8bd90c0ec Mon Sep 17 00:00:00 2001 From: Marco Rieser Date: Fri, 17 Apr 2026 16:50:44 +0200 Subject: [PATCH 3/8] Bring back `dates` key in return array --- src/Tags/Events.php | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Tags/Events.php b/src/Tags/Events.php index 252deaa..29ace2a 100755 --- a/src/Tags/Events.php +++ b/src/Tags/Events.php @@ -138,20 +138,23 @@ public function upcoming(): EntryCollection|array private function day(string $date, EntryCollection $occurrences): array { + $occurrences = $occurrences->map(function (Entry $occurrence) use ($date): Entry { + if (!$occurrence->spanning) { + return $occurrence; + } + + $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); + $occurrence + ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) + ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); + + return clone $occurrence; + })->values(); + return [ 'date' => $date, - 'occurrences' => $occurrences->map(function (Entry $occurrence) use ($date): Entry { - if (!$occurrence->spanning) { - return $occurrence; - } - - $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); - $occurrence - ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) - ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); - - return clone $occurrence; - })->values(), + 'dates'=> $occurrences, + 'occurrences' => $occurrences, ]; } From a7b748fde48aca3f9c795f9a22ab7f5a0a7fc01e Mon Sep 17 00:00:00 2001 From: Marco Rieser Date: Fri, 17 Apr 2026 16:50:49 +0200 Subject: [PATCH 4/8] Fix tests --- tests/Tags/EventsTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Tags/EventsTest.php b/tests/Tags/EventsTest.php index a925ffc..cb2b4ab 100755 --- a/tests/Tags/EventsTest.php +++ b/tests/Tags/EventsTest.php @@ -476,14 +476,14 @@ ->setParameters(['timezone' => 'Europe/Kyiv']); $days = $this->tag->calendar(); - $firstSpanningOccurrence = $days[17]['occurrences'][1]; + $firstSpanningOccurrence = $days[17]['occurrences'][0]; $secondSpanningOccurrence = $days[18]['occurrences'][0]; - ray($days, $firstSpanningOccurrence); expect($firstSpanningOccurrence) ->spanning_start->toBeTrue() ->spanning_end->toBeFalse(); - // expect($secondSpanningOccurrence) - // ->spanning_start->toBeFalse() - // ->spanning_end->toBeTrue(); + + expect($secondSpanningOccurrence) + ->spanning_start->toBeFalse() + ->spanning_end->toBeTrue(); }); From 8cc2489827176800f83976f452affc9e40909e65 Mon Sep 17 00:00:00 2001 From: Marco Rieser Date: Fri, 17 Apr 2026 16:55:41 +0200 Subject: [PATCH 5/8] Formatting --- src/Tags/Events.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Tags/Events.php b/src/Tags/Events.php index 29ace2a..9fd9ded 100755 --- a/src/Tags/Events.php +++ b/src/Tags/Events.php @@ -42,14 +42,14 @@ public function calendar(): Collection $month = $this->params->get('month', now()->englishMonth); $year = $this->params->get('year', now()->year); - $from = parse_date($month.' '.$year)->startOfMonth()->startOfWeek(); - $to = parse_date($month.' '.$year)->endOfMonth()->endOfWeek(); + $from = parse_date($month . ' ' . $year)->startOfMonth()->startOfWeek(); + $to = parse_date($month . ' ' . $year)->endOfMonth()->endOfWeek(); $occurrences = $this ->generator() ->between(from: $from, to: $to) ->groupBy($this->spanningDays()) - ->map(fn (EntryCollection $occurrences, string $date) => $this->day(date: $date, occurrences: $occurrences)); + ->map(fn(EntryCollection $occurrences, string $date) => $this->day(date: $date, occurrences: $occurrences)); $days = $this->output($this->makeEmptyDates(from: $from, to: $to)->merge($occurrences)->values()); @@ -153,7 +153,7 @@ private function day(string $date, EntryCollection $occurrences): array return [ 'date' => $date, - 'dates'=> $occurrences, + 'dates' => $occurrences, 'occurrences' => $occurrences, ]; } @@ -266,7 +266,7 @@ private function spanningDays(): Closure $occurrence->end->endOfDay() )->toArray(); - return collect($spanningDays)->map(fn (CarbonImmutable $date) => $date->toDateString())->all(); + return collect($spanningDays)->map(fn(CarbonImmutable $date) => $date->toDateString())->all(); }; } } From a253485903c896dd1ddf4982749bfde11fec7c83 Mon Sep 17 00:00:00 2001 From: Marco Rieser Date: Fri, 17 Apr 2026 17:18:34 +0200 Subject: [PATCH 6/8] Remove legacy dates key --- src/Tags/Events.php | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/Tags/Events.php b/src/Tags/Events.php index 9fd9ded..9eae270 100755 --- a/src/Tags/Events.php +++ b/src/Tags/Events.php @@ -138,23 +138,20 @@ public function upcoming(): EntryCollection|array private function day(string $date, EntryCollection $occurrences): array { - $occurrences = $occurrences->map(function (Entry $occurrence) use ($date): Entry { - if (!$occurrence->spanning) { - return $occurrence; - } - - $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); - $occurrence - ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) - ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); - - return clone $occurrence; - })->values(); - return [ 'date' => $date, - 'dates' => $occurrences, - 'occurrences' => $occurrences, + 'occurrences' => $occurrences->map(function (Entry $occurrence) use ($date): Entry { + if (!$occurrence->spanning) { + return $occurrence; + } + + $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); + $occurrence + ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) + ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); + + return clone $occurrence; + })->values(), ]; } From 999f82578b8e0b09679f4aa2d8248aaf18e705be Mon Sep 17 00:00:00 2001 From: Marco Rieser Date: Fri, 17 Apr 2026 17:19:13 +0200 Subject: [PATCH 7/8] Fix tests --- tests/Tags/EventsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tags/EventsTest.php b/tests/Tags/EventsTest.php index cb2b4ab..0dc46dd 100755 --- a/tests/Tags/EventsTest.php +++ b/tests/Tags/EventsTest.php @@ -96,7 +96,7 @@ $occurrences = $this->tag->calendar(); expect($occurrences)->toHaveCount(42); - expect(Arr::get($occurrences, '5.dates'))->toHaveCount(2); + expect(Arr::get($occurrences, '5.occurrences'))->toHaveCount(2); expect(Arr::get($occurrences, '6.no_results'))->toBeTrue(); }); From 15e4bc1f3a1452cb44f83428602f6e346e012301 Mon Sep 17 00:00:00 2001 From: edalzell Date: Fri, 17 Apr 2026 09:56:06 -0700 Subject: [PATCH 8/8] tidy --- src/Tags/Events.php | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/Tags/Events.php b/src/Tags/Events.php index 9eae270..99e5e20 100755 --- a/src/Tags/Events.php +++ b/src/Tags/Events.php @@ -42,14 +42,14 @@ public function calendar(): Collection $month = $this->params->get('month', now()->englishMonth); $year = $this->params->get('year', now()->year); - $from = parse_date($month . ' ' . $year)->startOfMonth()->startOfWeek(); - $to = parse_date($month . ' ' . $year)->endOfMonth()->endOfWeek(); + $from = parse_date($month.' '.$year)->startOfMonth()->startOfWeek(); + $to = parse_date($month.' '.$year)->endOfMonth()->endOfWeek(); $occurrences = $this ->generator() ->between(from: $from, to: $to) ->groupBy($this->spanningDays()) - ->map(fn(EntryCollection $occurrences, string $date) => $this->day(date: $date, occurrences: $occurrences)); + ->map(fn (EntryCollection $occurrences, string $date) => $this->day(date: $date, occurrences: $occurrences)); $days = $this->output($this->makeEmptyDates(from: $from, to: $to)->merge($occurrences)->values()); @@ -136,22 +136,27 @@ public function upcoming(): EntryCollection|array return $this->output($occurrences->take($limit)); } + private function addSpanningStartEnd(string $date, EntryCollection $occurrences): EntryCollection + { + return $occurrences->map(function (Entry $occurrence) use ($date) { + if (! $occurrence->spanning) { + return $occurrence; + } + + $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); + $occurrence + ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) + ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); + + return clone $occurrence; + }); + } + private function day(string $date, EntryCollection $occurrences): array { return [ 'date' => $date, - 'occurrences' => $occurrences->map(function (Entry $occurrence) use ($date): Entry { - if (!$occurrence->spanning) { - return $occurrence; - } - - $carbonDate = Carbon::parse($date)->shiftTimezone($occurrence->start->timezone); - $occurrence - ->setSupplement('spanning_start', $occurrence->start->isSameDay($carbonDate)) - ->setSupplement('spanning_end', $occurrence->end->isSameDay($carbonDate)); - - return clone $occurrence; - })->values(), + 'occurrences' => $this->addSpanningStartEnd($date, $occurrences), ]; } @@ -263,7 +268,7 @@ private function spanningDays(): Closure $occurrence->end->endOfDay() )->toArray(); - return collect($spanningDays)->map(fn(CarbonImmutable $date) => $date->toDateString())->all(); + return collect($spanningDays)->map(fn (CarbonImmutable $date) => $date->toDateString())->all(); }; } }