How to Create Add To Calendar Buttons for Your Events
- This topic has 10 replies, 2 voices, and was last updated 3 years, 10 months ago by
Ulysse.
-
AuthorPosts
-
May 31, 2021 at 5:34 AM #28543
Ulysse
ParticipantHello,
I try to follow your tuto but I experience some issues.
First, I use elementor to create the template of my custom posts and fields so I try to adapt the code.- I created my custom post event and custom fields:
ci_event_startdate
ci_event_enddate
ci_event_address (linked a google map to generate an address).
Then I created the snippet (using a plugin to include snippet):
<?php function justread_ics_download() { if ( is_singular( ‘event’ ) && isset( $_GET['ics'] ) ) { include get_stylesheet_directory() . '/inc/ICS.php'; header('Content-Type: text/calendar; charset=utf-8'); header('Content-Disposition: attachment; filename=invite.ics'); $ics = new ICS(array( 'location' => $_POST['location'], 'dtstart' => $_POST['start_date'], 'dtend' => $_POST['end_date'], 'summary' => $_POST['summary'], )); echo $ics->to_string(); exit(); } } add_action( 'template_redirect', 'justread_ics_download' ); ?>
Then I created this shortcode:
<?php add_shortcode( 'calendardata', function() { $start_date = rwmb_get_value( ci_event_start_date, array( 'format' => 'Y-m-d g:iA' ) ); $start_date = wp_date( 'Ymd\THis', $start_date ); $end_date = rwmb_get_value( ci_event_end_date, array( 'format' => 'Y-m-d g:iA' ) ); $end_date = wp_date( 'Ymd\THis', $end_date ); } ); ?>
Then, on template of the event custom post using elementor, I created a block, where I include the shortcode 'calendardata'
And then the htmlc code:<form method="post" action="?ics=true"> <input type="hidden" name="start_date" value="<?php echo $start_date; ?>"> <input type="hidden" name="end_date" value="<?php echo $end_date; ?>"> <input type="hidden" name="location" value="<?php echo rwmb_meta( 'ci_event_location_address' ); ?>"> <input type="hidden" name="summary" value="<?php the_title(); ?>"> <input type="submit" value="Add to Calendar"> </form>
I have 2 issues:
- The first one, my firewall blocked the access and I get the message:
Access Denied - https://mywebsite.com/event/test-event/?ics=true
Error Code 5558
This request has been blocked by Patchstack Web Application Firewall .
If you are a legitimate user, contact the administrator of the site with above error code if this message persists.
So why this is blocked?
- The second one is when I deactivate the firewall, the page refreshes and redirects to https://mywebsite.com/event/test-event/?ics=true
but not file is created.So, I don't know what's going on?
May 31, 2021 at 10:39 PM #28569Long Nguyen
ModeratorHi,
- When clicking the Add to Calendar button, there is a popup box to download the file .ics so the firewall might block this behavior. You can contact their support to get more information.
-
Change the curry quote to the single quote on this code
if ( is_singular( ‘event’ ) && isset( $_GET['ics'] ) ) {
to
if ( is_singular( 'event' ) && isset( $_GET['ics'] ) ) {
And the important point in step 2 of the article is to use a theme template. If not, this function get_stylesheet_directory() will not work.
You can copy content of the file ICS.php and add before the function
justread_ics_download()
class ICS { ... } function justread_ics_download() { ... }
The shortcode should include all PHP and HTML form, please don't break it into two parts.
add_shortcode( 'calendardata', function() { $start_date = rwmb_get_value( ci_event_start_date, array( 'format' => 'Y-m-d g:iA' ) ); $start_date = wp_date( 'Ymd\THis', $start_date ); $end_date = rwmb_get_value( ci_event_end_date, array( 'format' => 'Y-m-d g:iA' ) ); $end_date = wp_date( 'Ymd\THis', $end_date ); ?> <form method="post" action="?ics=true"> <input type="hidden" name="start_date" value="<?php echo $start_date; ?>"> <input type="hidden" name="end_date" value="<?php echo $end_date; ?>"> <input type="hidden" name="location" value="<?php echo rwmb_meta( 'event_location' ); ?>"> <input type="hidden" name="summary" value="<?php the_title(); ?>"> <input type="submit" value="Add to Calendar"> </form> <?php } );
May 31, 2021 at 11:52 PM #28574Ulysse
ParticipantThank you for your answer. I tried to follow your guidance but I failed.
In particular, I have included the part of the ics.php in my snippet as you said, but did not create a single-event.php<?php class ICS { const DT_FORMAT = 'Ymd\THis'; protected $properties = array(); private $available_properties = array( 'description', 'dtend', 'dtstart', 'location', 'summary', 'url' ); public function __construct($props) { $this->set($props); } public function set($key, $val = false) { if (is_array($key)) { foreach ($key as $k => $v) { $this->set($k, $v); } } else { if (in_array($key, $this->available_properties)) { $this->properties[$key] = $this->sanitize_val($val, $key); } } } public function to_string() { $rows = $this->build_props(); return implode("\r\n", $rows); } private function build_props() { // Build ICS properties - add header $ics_props = array( 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//hacksw/handcal//NONSGML v1.0//EN', 'CALSCALE:GREGORIAN', 'BEGIN:VEVENT' ); // Build ICS properties - add header $props = array(); foreach($this->properties as $k => $v) { $props[strtoupper($k . ($k === 'url' ? ';VALUE=URI' : ''))] = $v; } // Set some default values $props['DTSTAMP'] = $this->format_timestamp('now'); $props['UID'] = uniqid(); // Append properties foreach ($props as $k => $v) { $ics_props[] = "$k:$v"; } // Build ICS properties - add footer $ics_props[] = 'END:VEVENT'; $ics_props[] = 'END:VCALENDAR'; return $ics_props; } private function sanitize_val($val, $key = false) { switch($key) { case 'dtend': case 'dtstamp': case 'dtstart': $val = $this->format_timestamp($val); break; default: $val = $this->escape_string($val); } return $val; } private function format_timestamp($timestamp) { $dt = new DateTime($timestamp); return $dt->format(self::DT_FORMAT); } private function escape_string($str) { return preg_replace('/([\,;])/','\\\$1', $str); } } function justread_ics_download() { if ( is_singular( 'event' ) && isset( $_GET['ics'] ) ) { include get_stylesheet_directory() . '/inc/ICS.php'; header('Content-Type: text/calendar; charset=utf-8'); header('Content-Disposition: attachment; filename=invite.ics'); $ics = new ICS(array( 'location' => $_POST['location'], 'dtstart' => $_POST['start_date'], 'dtend' => $_POST['end_date'], 'summary' => $_POST['summary'], )); echo $ics->to_string(); exit(); } } add_action( 'template_redirect', 'justread_ics_download' ); ?>
But it still doesn't work.
June 1, 2021 at 12:44 PM #28586Long Nguyen
ModeratorHi,
I got the issue. The function
is_singular( 'event' )
still check if the template available on the theme templates, please remove this code.if ( isset( $_GET['ics'] ) ) { ...}
and remove unnecessary code
include get_stylesheet_directory() . '/inc/ICS.php';
wrap your field ID in the single quote
$start_date = rwmb_get_value( 'ci_event_start_date', array( 'format' => 'Y-m-d g:iA' ) ); $end_date = rwmb_get_value( 'ci_event_end_date', array( 'format' => 'Y-m-d g:iA' ) );
Let me know how it goes.
June 2, 2021 at 12:08 AM #28602Ulysse
ParticipantHi,
It's much better.
Now, I can download the ics file. My remaining issue is that, it stays blocked on white page as it was waiting something to exit. Maybe I have to make a kind a "call back" to go back to the page?June 2, 2021 at 3:10 PM #28619Ulysse
ParticipantEverytging seems to work. The ics file whiich is created is correct. My onlyissue is that I odn't know why at the end of the process, the visitor is blocked on a blanck page.
Here are my codes:
<?php class ICS { const DT_FORMAT = 'Ymd\THis'; protected $properties = array(); private $available_properties = array( 'description', 'dtend', 'dtstart', 'location', 'summary', 'url' ); public function __construct($props) { $this->set($props); } public function set($key, $val = false) { if (is_array($key)) { foreach ($key as $k => $v) { $this->set($k, $v); } } else { if (in_array($key, $this->available_properties)) { $this->properties[$key] = $this->sanitize_val($val, $key); } } } public function to_string() { $rows = $this->build_props(); return implode("\r\n", $rows); } private function build_props() { // Build ICS properties - add header $ics_props = array( 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//hacksw/handcal//NONSGML v1.0//EN', 'CALSCALE:GREGORIAN', 'BEGIN:VEVENT' ); // Build ICS properties - add header $props = array(); foreach($this->properties as $k => $v) { $props[strtoupper($k . ($k === 'url' ? ';VALUE=URI' : ''))] = $v; } // Set some default values $props['DTSTAMP'] = $this->format_timestamp('now'); $props['UID'] = uniqid(); // Append properties foreach ($props as $k => $v) { $ics_props[] = "$k:$v"; } // Build ICS properties - add footer $ics_props[] = 'END:VEVENT'; $ics_props[] = 'END:VCALENDAR'; return $ics_props; } private function sanitize_val($val, $key = false) { switch($key) { case 'dtend': case 'dtstamp': case 'dtstart': $val = $this->format_timestamp($val); break; default: $val = $this->escape_string($val); } return $val; } private function format_timestamp($timestamp) { $dt = new DateTime($timestamp); return $dt->format(self::DT_FORMAT); } private function escape_string($str) { return preg_replace('/([\,;])/','\\\$1', $str); } } function justread_ics_download() { if ( isset( $_GET['ics'] ) ) { // include get_stylesheet_directory() . '/inc/ICS.php'; header('Content-Type: text/calendar; charset=utf-8'); header('Content-Disposition: attachment; filename=invite.ics'); $ics = new ICS(array( 'location' => $_POST['location'], 'dtstart' => $_POST['start_date'], 'dtend' => $_POST['end_date'], 'summary' => $_POST['summary'], )); //return "It works"; echo $ics->to_string(); exit(); return; } } add_action('template_redirect', 'justread_ics_download' ); ?>
And the shortcode:
<?php add_shortcode( 'calendardata', function() { $start_date = rwmb_get_value( 'ci_event_start_date', array( 'format' => 'Y-m-d g:iA' ) ); $start_date = wp_date( 'Ymd\THis', $start_date ); $end_date = rwmb_get_value( 'ci_event_end_date', array( 'format' => 'Y-m-d g:iA' ) ); $end_date = wp_date( 'Ymd\THis', $end_date ); echo $end_date; echo $start_date; ?> <form method="post" action="?ics=true"> <input type="hidden" name="start_date" value="<?php echo $start_date; ?>"> <input type="hidden" name="end_date" value="<?php echo $end_date; ?>"> <input type="hidden" name="location" value="<?php echo rwmb_meta( 'ci_event_location_address' ); ?>"> <input type="hidden" name="summary" value="<?php the_title(); ?>"> <input type="submit" value="Add to Calendar"> </form> <?php return; } ); ?>
June 4, 2021 at 5:02 PM #28706Ulysse
ParticipantHello.
I don't see how to solve that. Once the "form" is submitted, it stays on a blank page.June 5, 2021 at 1:26 PM #28721Long Nguyen
ModeratorHi,
Please try to deactivate all plugins except Meta Box, MB extensions and use a default theme of WordPress to re-check this issue.
And please share your page URL, I will help you to check the issue.
June 5, 2021 at 2:38 PM #28724Ulysse
ParticipantHello,
I already tried to deactivate all my plugins and only keep what I needed : elementor pro / metabox / script organizer (the plugin I use to implement my codes). And I still has the same issue.I have been advised by Didou Schol to include target in my form, and it works.
<?php add_shortcode( 'calendardata', function() { $start_date = rwmb_get_value( 'ci_event_start_date', array( 'format' => 'Y-m-d g:iA' ) ); $start_date = wp_date( 'Ymd\THis', $start_date ); $end_date = rwmb_get_value( 'ci_event_end_date', array( 'format' => 'Y-m-d g:iA' ) ); $end_date = wp_date( 'Ymd\THis', $end_date ); echo $end_date; echo $start_date; ?> <form method="post" action="?ics=true" target="_blank"> <input type="hidden" name="start_date" value="<?php echo $start_date; ?>"> <input type="hidden" name="end_date" value="<?php echo $end_date; ?>"> <input type="hidden" name="location" value="<?php echo rwmb_meta( 'ci_event_location_address' ); ?>"> <input type="hidden" name="summary" value="<?php the_title(); ?>"> <input type="submit" value="Add to Calendar"> </form> <?php return; } ); ?>
And so now, when the user clicks on "add to calendar", a new tab is opened, the ICS file is downloaded and the tab is closed. I think, it's good ? What do you think?
June 5, 2021 at 4:11 PM #28728Long Nguyen
ModeratorHi,
Add attribute
target="_blank"
is a good way, thanks Didou. On my local site, both ways are worked. Screen record https://www.loom.com/share/956524cf111e4be186b9da75fd9d6e50Not sure what's wrong with your site but you can go on this way.
June 5, 2021 at 8:18 PM #28731Ulysse
ParticipantThank you very much for your time. I made several test and I don't know why it does not work without "target". (maybe cache on the server, or on the cdn?).
By the way, I created a button "add to google calendar" as well. It can be useful as well. I share the code below if it can help our community:
First, include in the function.php (or in a php code snippet):
function addToGoogleCalendar($title='', $startdate='', $enddate='', $location='', $details='') { $startdate = ($startdate ? $startdate : time()); $startdate = (is_numeric($startdate) ? $startdate : strtotime($startdate)); $enddate = ($enddate ? $enddate : $startdate + 3600); $enddate = (is_numeric($enddate) ? $enddate : strtotime($enddate)); $google_url = "https://www.google.com/calendar/event"; $action = "?action=TEMPLATE"; $title = ( $title ? ("&text=" . urlencode($title)) : "") ; $dates = "&dates=" . getIcalDate($startdate) . "Z/" . getIcalDate($enddate) . "Z"; $location = ( $location ? ("&location=" . urlencode($location)) : "") ; $details = ( $details ? ("&details=" . urlencode($details)) : "") ; $out = $google_url . $action . $title . $dates . $location . $details; return $out; } function getIcalDate($time, $incl_time = true) { return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time); }
Then create a shortcode [googlecalendar]
<?php add_shortcode( 'googlecalendar', function() { $start_date = rwmb_get_value( 'ci_event_start_date', array( 'format' => 'Y-m-d g:iA' ) ); $start_date = wp_date( 'Ymd\THis', $start_date ); $end_date = rwmb_get_value( 'ci_event_end_date', array( 'format' => 'Y-m-d g:iA' ) ); $end_date = wp_date( 'Ymd\THis', $end_date ); $title = get_the_title() ; $location = rwmb_meta( 'ci_event_location_address' ) ; $urlgc = addToGoogleCalendar($title, $start_date, $end_date, $location, $title); return $urlgc; } ); ?>
The result of the shortcode is a link with all the data of my custom post "events) to create an event in google calendar.
- I created my custom post event and custom fields:
-
AuthorPosts
- You must be logged in to reply to this topic.