Support Forum
Hello,
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.
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?
Hi,
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
} );
Thank 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.
Hi,
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.
Hi,
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?
Everytging 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;
}
);
?>
Hello.
I don't see how to solve that. Once the "form" is submitted, it stays on a blank page.
Hi,
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.
Hello,
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?
Hi,
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/956524cf111e4be186b9da75fd9d6e50
Not sure what's wrong with your site but you can go on this way.
Thank 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.