Created
May 27, 2023 17:56
-
-
Save frontycore/ce4ff94dde5e0616daf8857533a5ba96 to your computer and use it in GitHub Desktop.
Export to calendar (Google + Outlook + ICS)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Utils; | |
use DateTime; | |
use App\PostTypes\Event; | |
use Nette\Utils\Strings; | |
use Jsvrcek\ICS\CalendarExport; | |
use Jsvrcek\ICS\CalendarStream; | |
use Jsvrcek\ICS\Utility\Formatter; | |
use Jsvrcek\ICS\Model\CalendarEvent; | |
use Jsvrcek\ICS\Model\Calendar as ICalendar; | |
/** | |
* Create Google and Outlook add-to-calendar links, generated iCal file. | |
* | |
* @see https://dylanbeattie.net/2021/01/12/adding-events-to-google-calendar-via-a-link.html | |
* @see https://stackoverflow.com/questions/50518151/how-to-generate-url-to-add-event-to-outlook-web-client-calendar | |
* @see https://github.com/jasvrcek/ICS | |
*/ | |
class Calendar | |
{ | |
/** @var string */ | |
private const ICS_COMPANY = 'Super duper company'; | |
/** @var string */ | |
private const ICS_CALENDAR = 'Calendar of great events'; | |
/** @var string */ | |
private const GOOGLE_URL = 'https://calendar.google.com/calendar/u/0/r/eventedit?'; | |
/** @var string */ | |
private const OUTLOOK_URL = 'https://outlook.office.com/owa/?path=/calendar/action/compose&rruaddevent&'; | |
public function __construct( | |
private string $id, | |
private DateTime $start, | |
private DateTime $end, | |
private string $name, | |
private string $description = '', | |
private string $location = '', | |
private string $url = '' | |
) { } | |
// Factory from WP post type | |
public static function fromEvent(Event $event): self | |
{ | |
return new self( | |
sha1($event->ID), | |
$event->getStart(), | |
$event->getEnd(), | |
$event->post_title, | |
nl2br($event->getSchedule()), | |
$event->getAddress(), | |
get_permalink($event->ID) | |
); | |
} | |
public function googleUrl(): string | |
{ | |
$googleParams = array_filter([ | |
'text' => $this->name, | |
'dates' => $this->start->format('Ymd\THisp') . '/' . $this->end->format('Ymd\THisp'), | |
'location' => $this->location, | |
'details' => $this->getDetails() | |
]); | |
return self::GOOGLE_URL . http_build_query($googleParams); | |
} | |
public function outlookUrl(): string | |
{ | |
$outlookParams = array_filter([ | |
'allDay' => $this->isAllDay() ? 'true' : 'false', | |
'startdt' => $this->start->format('Y-m-d\TH:i:s'), | |
'enddt' => $this->end->format('Y-m-d\TH:i:s'), | |
'subject' => $this->name, | |
'location' => $this->location, | |
'body' => $this->getDetails() | |
]); | |
return self::OUTLOOK_URL . http_build_query($outlookParams); | |
} | |
// WP-relevant method | |
public function iCalUrl(Event $event): string | |
{ | |
return get_bloginfo('url') . '/?ical=' . $event->ID; | |
} | |
public function getICal(): ICalendar | |
{ | |
$event = new CalendarEvent(); | |
$event | |
->setUid($this->id) | |
->setStart($this->start) | |
->setEnd($this->end) | |
->setAllDay($this->isAllDay()) | |
->setSummary($this->name); | |
if ($this->description) $event->setDescription($this->description); | |
if ($this->url) $event->setUrl($this->url); | |
$calendar = new ICalendar(); | |
$calendar->setProdId('-//' . self::ICS_COMPANY . '//' . self::ICS_CALENDAR . '//EN') | |
->addEvent($event); | |
return $calendar; | |
} | |
private function isAllDay(): bool | |
{ | |
$day = 24 * 60 * 60; | |
return $this->end->getTimestamp() - $this->start->getTimestamp() > $day; | |
} | |
private function getDetails(): string | |
{ | |
$details = $this->description; | |
if ($this->url) $details .= ($details ? PHP_EOL . PHP_EOL : '') . $this->url; | |
return $details; | |
} | |
} | |
// For Wordpress | |
add_action('wp', function() { | |
if (!isset($_GET['ical']) || !is_numeric($_GET['ical'])) return; | |
$event = new Event($_GET['ical']); | |
$calendar = Calendar::fromEvent($event)->getICal(); | |
$calendarExport = new CalendarExport(new CalendarStream, new Formatter()); | |
$calendarExport->addCalendar($calendar); | |
$filename = Strings::webalize($event->post_title); | |
header('Content-type: text/calendar; charset=utf-8'); | |
header('Content-Disposition: attachment; filename=' . $filename . '.ics'); | |
echo $calendarExport->getStream(); | |
exit(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment