From 44f5da2caf0c74ac46bbe8f04f4772e2cff2ce8f Mon Sep 17 00:00:00 2001 From: Rando Hinn Date: Sun, 13 Feb 2022 17:36:30 +0200 Subject: [PATCH 1/5] Add functionality to render a calendar into .ics when appending ?ics=true --- includes/functions/shared.php | 33 +++++++++++++++++++++++++++++++-- includes/main.php | 9 +++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/includes/functions/shared.php b/includes/functions/shared.php index 94b64d8e..3943eae2 100644 --- a/includes/functions/shared.php +++ b/includes/functions/shared.php @@ -113,6 +113,36 @@ function simcal_get_calendar( $object ) { return $objects instanceof \SimpleCalendar\Objects ? $objects->get_calendar( $object ) : null; } +/** + * Compose and return a ics feed from the calendar + * @return void + * + */ +function simcal_draw_calendar_ics($post) { + $calendar = simcal_get_calendar($post); + $events = $calendar->events; + header('Content-Type:text/plain'); + $ics = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Wordpress/Simple-Calendar\n"; + + foreach($events as $eventarr) { + $event = $eventarr[0]; + $ics .= "BEGIN:VEVENT\n"; + $ics .="UID:" . $event->ical_id . "\n"; + $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\n"; + $ics .= "ORGANIZER;CN=" . $event->source . "\n"; + $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\n"; + $ics .= "DTEND:" . $event->start_dt->format('Ymd\THis') . "\n"; + $ics.= "SUMMARY:" . $event->title . "\n"; + $ics .= "DESCRIPTION:" . str_replace("\n\t\n","\n\t",str_replace("\n","\n\t",$event->description)) . "\n"; + $ics .= "LOCATION:" . $event->start_location["name"] .';' . $event->start_location["address"] ."\n"; + $ics .= "GEO:" . $event->start_location["lat"] . ';' . $event->start_location["lng"] . "\n"; + $ics .= "END:VEVENT\n"; + } + + $ics .= 'END:VCALENDAR'; + die($ics); +} + /** * Get a calendar view. * @@ -140,7 +170,6 @@ function simcal_get_calendar_view( $id = 0, $name = '' ) { function simcal_print_calendar( $object ) { $calendar = simcal_get_calendar( $object ); - if ( $calendar instanceof \SimpleCalendar\Abstracts\Calendar ) { $calendar->html(); } @@ -485,4 +514,4 @@ function simcal_delete_feed_transients( $id = '' ) { } return delete_transient( '_simple-calendar_feed_ids' ); -} \ No newline at end of file +} diff --git a/includes/main.php b/includes/main.php index 9a58e56b..1d683da6 100644 --- a/includes/main.php +++ b/includes/main.php @@ -180,6 +180,13 @@ public function load_admin() { } } +public function simcal_ics_action() { + global $post; + if(isset($post) && $post->post_type == "calendar" && isset($_GET["ics"]) && $_GET["ics"] == true) { + simcal_draw_calendar_ics($post); + } +} + /** * Init plugin when WordPress initializes. * @@ -198,6 +205,8 @@ public function init() { // Upon init action hook. do_action( 'simcal_init' ); + + add_action('template_redirect',array($this, 'simcal_ics_action'), 10 ); } /** From a5703adbc66ed4e96b999e640d864aae0311c393 Mon Sep 17 00:00:00 2001 From: Rando Hinn Date: Sun, 13 Feb 2022 17:49:47 +0200 Subject: [PATCH 2/5] Change to use the event uid so there is a uid for the GCAL Pro addon calendar events too. --- includes/functions/shared.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/functions/shared.php b/includes/functions/shared.php index 3943eae2..36c949b6 100644 --- a/includes/functions/shared.php +++ b/includes/functions/shared.php @@ -127,7 +127,7 @@ function simcal_draw_calendar_ics($post) { foreach($events as $eventarr) { $event = $eventarr[0]; $ics .= "BEGIN:VEVENT\n"; - $ics .="UID:" . $event->ical_id . "\n"; + $ics .="UID:" . $event->uid . "\n"; $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\n"; $ics .= "ORGANIZER;CN=" . $event->source . "\n"; $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\n"; From 407c104dffa4cefe0a8640c265c6489886c36f54 Mon Sep 17 00:00:00 2001 From: Rando Hinn Date: Sun, 13 Feb 2022 17:54:30 +0200 Subject: [PATCH 3/5] Fix end timestamp and prevent duplicates for multi-day events. --- includes/functions/shared.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/includes/functions/shared.php b/includes/functions/shared.php index 36c949b6..5677ba3e 100644 --- a/includes/functions/shared.php +++ b/includes/functions/shared.php @@ -126,17 +126,20 @@ function simcal_draw_calendar_ics($post) { foreach($events as $eventarr) { $event = $eventarr[0]; - $ics .= "BEGIN:VEVENT\n"; - $ics .="UID:" . $event->uid . "\n"; - $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics .= "ORGANIZER;CN=" . $event->source . "\n"; - $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics .= "DTEND:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics.= "SUMMARY:" . $event->title . "\n"; - $ics .= "DESCRIPTION:" . str_replace("\n\t\n","\n\t",str_replace("\n","\n\t",$event->description)) . "\n"; - $ics .= "LOCATION:" . $event->start_location["name"] .';' . $event->start_location["address"] ."\n"; - $ics .= "GEO:" . $event->start_location["lat"] . ';' . $event->start_location["lng"] . "\n"; - $ics .= "END:VEVENT\n"; + if($strpos($ics, $event->uid) == false) { + $ics .= "BEGIN:VEVENT\n"; + $ics .="UID:" . $event->uid . "\n"; + $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\n"; + $ics .= "ORGANIZER;CN=" . $event->source . "\n"; + $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\n"; + $ics .= "DTEND:" . $event->end_dt->format('Ymd\THis') . "\n"; + $ics.= "SUMMARY:" . $event->title . "\n"; + $ics .= "DESCRIPTION:" . str_replace("\n\t\n","\n\t",str_replace("\n","\n\t",$event->description)) . "\n"; + $ics .= "LOCATION:" . $event->start_location["name"] .';' . $event->start_location["address"] ."\n"; + $ics .= "GEO:" . $event->start_location["lat"] . ';' . $event->start_location["lng"] . "\n"; + $ics .= "END:VEVENT\n"; + } + } $ics .= 'END:VCALENDAR'; From 5b8649812c2ec3da504c21b5615a3d5dce89f2a8 Mon Sep 17 00:00:00 2001 From: Rando Hinn Date: Sun, 13 Feb 2022 18:30:57 +0200 Subject: [PATCH 4/5] Work on getting some fields to be more standards-compatible. --- includes/functions/shared.php | 57 ++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/includes/functions/shared.php b/includes/functions/shared.php index 5677ba3e..33594fb3 100644 --- a/includes/functions/shared.php +++ b/includes/functions/shared.php @@ -112,32 +112,55 @@ function simcal_get_calendar( $object ) { $objects = \SimpleCalendar\plugin()->objects; return $objects instanceof \SimpleCalendar\Objects ? $objects->get_calendar( $object ) : null; } +/** + * Formats strings to ical standard + * + * @param string $s + * + * @return string + */ +function format_ical_string( $s ) { + $r = wordwrap( + preg_replace( + array( '/,/', '/;/', '/[\r\n]/' ), + array( '\,', '\;', '\n' ), + $s + ), 73, "\n", TRUE + ); + + // Indent all lines but first: + $r = preg_replace( '/\n/', "\n ", $r ); + + return $r; +} + /** * Compose and return a ics feed from the calendar + * @param string|int|object|WP_Post $object * @return void * */ function simcal_draw_calendar_ics($post) { $calendar = simcal_get_calendar($post); $events = $calendar->events; - header('Content-Type:text/plain'); - $ics = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Wordpress/Simple-Calendar\n"; + header('Content-Type:text/calendar'); + $ics = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Wordpress/Simple-Calendar\r\n"; foreach($events as $eventarr) { $event = $eventarr[0]; - if($strpos($ics, $event->uid) == false) { - $ics .= "BEGIN:VEVENT\n"; - $ics .="UID:" . $event->uid . "\n"; - $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics .= "ORGANIZER;CN=" . $event->source . "\n"; - $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics .= "DTEND:" . $event->end_dt->format('Ymd\THis') . "\n"; - $ics.= "SUMMARY:" . $event->title . "\n"; - $ics .= "DESCRIPTION:" . str_replace("\n\t\n","\n\t",str_replace("\n","\n\t",$event->description)) . "\n"; - $ics .= "LOCATION:" . $event->start_location["name"] .';' . $event->start_location["address"] ."\n"; - $ics .= "GEO:" . $event->start_location["lat"] . ';' . $event->start_location["lng"] . "\n"; - $ics .= "END:VEVENT\n"; + if(strpos($ics, $event->uid) == false) { + $ics .= "BEGIN:VEVENT\r\n"; + $ics .="UID:" . $event->uid . "\r\n"; + $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\r\n"; + $ics .= "ORGANIZER;CN=" . $event->source . ":MAILTO:".$event->source."\r\n"; + $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\r\n"; + $ics .= "DTEND:" . $event->end_dt->format('Ymd\THis') . "\r\n"; + $ics.= "SUMMARY:" . format_ical_string($event->title) . "\r\n"; + $ics .= "DESCRIPTION:" . format_ical_string($event->description) . "\r\n"; + $ics .= "LOCATION:" . $event->start_location["name"] .';' . $event->start_location["address"] ."\r\n"; + $ics .= "GEO:" . $event->start_location["lat"] . ';' . $event->start_location["lng"] . "\r\n"; + $ics .= "END:VEVENT\r\n"; } } @@ -319,11 +342,11 @@ function simcal_default_event_template() { $content = '' . '[title]' . ''; $content .= "\n\n"; - $content .= '[when]' . "\n"; + $content .= '[when]' . "\r\n"; $content .= '[location]'; - $content .= "\n"; + $content .= "\r\n"; $content .= '
' . '[description]' . '
'; - $content .= "\n" . '[link newwindow="yes"]' . __( 'See more details', 'google-calendar-events' ) . '[/link]'; + $content .= "\r\n" . '[link newwindow="yes"]' . __( 'See more details', 'google-calendar-events' ) . '[/link]'; return apply_filters( 'simcal_default_event_template', $content ); } From 03d2450f3970e1704422a3047772fedb056ba231 Mon Sep 17 00:00:00 2001 From: Rando Hinn Date: Thu, 24 Mar 2022 17:28:21 +0200 Subject: [PATCH 5/5] Proper newlines --- composer.json | 3 ++ includes/functions/shared.php | 58 +++++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index f99729a2..e7cde5ca 100644 --- a/composer.json +++ b/composer.json @@ -54,6 +54,9 @@ "config": { "platform": { "php": "7.3" + }, + "allow-plugins": { + "composer/installers": true } }, "scripts": { diff --git a/includes/functions/shared.php b/includes/functions/shared.php index 3943eae2..33594fb3 100644 --- a/includes/functions/shared.php +++ b/includes/functions/shared.php @@ -112,31 +112,57 @@ function simcal_get_calendar( $object ) { $objects = \SimpleCalendar\plugin()->objects; return $objects instanceof \SimpleCalendar\Objects ? $objects->get_calendar( $object ) : null; } +/** + * Formats strings to ical standard + * + * @param string $s + * + * @return string + */ +function format_ical_string( $s ) { + $r = wordwrap( + preg_replace( + array( '/,/', '/;/', '/[\r\n]/' ), + array( '\,', '\;', '\n' ), + $s + ), 73, "\n", TRUE + ); + + // Indent all lines but first: + $r = preg_replace( '/\n/', "\n ", $r ); + + return $r; +} + /** * Compose and return a ics feed from the calendar + * @param string|int|object|WP_Post $object * @return void * */ function simcal_draw_calendar_ics($post) { $calendar = simcal_get_calendar($post); $events = $calendar->events; - header('Content-Type:text/plain'); - $ics = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Wordpress/Simple-Calendar\n"; + header('Content-Type:text/calendar'); + $ics = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Wordpress/Simple-Calendar\r\n"; foreach($events as $eventarr) { $event = $eventarr[0]; - $ics .= "BEGIN:VEVENT\n"; - $ics .="UID:" . $event->ical_id . "\n"; - $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics .= "ORGANIZER;CN=" . $event->source . "\n"; - $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics .= "DTEND:" . $event->start_dt->format('Ymd\THis') . "\n"; - $ics.= "SUMMARY:" . $event->title . "\n"; - $ics .= "DESCRIPTION:" . str_replace("\n\t\n","\n\t",str_replace("\n","\n\t",$event->description)) . "\n"; - $ics .= "LOCATION:" . $event->start_location["name"] .';' . $event->start_location["address"] ."\n"; - $ics .= "GEO:" . $event->start_location["lat"] . ';' . $event->start_location["lng"] . "\n"; - $ics .= "END:VEVENT\n"; + if(strpos($ics, $event->uid) == false) { + $ics .= "BEGIN:VEVENT\r\n"; + $ics .="UID:" . $event->uid . "\r\n"; + $ics .="DTSTAMP:" . $event->start_dt->format('Ymd\THis') . "\r\n"; + $ics .= "ORGANIZER;CN=" . $event->source . ":MAILTO:".$event->source."\r\n"; + $ics .= "DTSTART:" . $event->start_dt->format('Ymd\THis') . "\r\n"; + $ics .= "DTEND:" . $event->end_dt->format('Ymd\THis') . "\r\n"; + $ics.= "SUMMARY:" . format_ical_string($event->title) . "\r\n"; + $ics .= "DESCRIPTION:" . format_ical_string($event->description) . "\r\n"; + $ics .= "LOCATION:" . $event->start_location["name"] .';' . $event->start_location["address"] ."\r\n"; + $ics .= "GEO:" . $event->start_location["lat"] . ';' . $event->start_location["lng"] . "\r\n"; + $ics .= "END:VEVENT\r\n"; + } + } $ics .= 'END:VCALENDAR'; @@ -316,11 +342,11 @@ function simcal_default_event_template() { $content = '' . '[title]' . ''; $content .= "\n\n"; - $content .= '[when]' . "\n"; + $content .= '[when]' . "\r\n"; $content .= '[location]'; - $content .= "\n"; + $content .= "\r\n"; $content .= '
' . '[description]' . '
'; - $content .= "\n" . '[link newwindow="yes"]' . __( 'See more details', 'google-calendar-events' ) . '[/link]'; + $content .= "\r\n" . '[link newwindow="yes"]' . __( 'See more details', 'google-calendar-events' ) . '[/link]'; return apply_filters( 'simcal_default_event_template', $content ); }