I really need your help with a feature I have never worked with so far.
I have a custom-post-type named wr_event
. And I created this custom WP_Query
to retrieve all posts for this post-type that are “younger” than yesterday. Fairly simple and this works like a charm.
function event_list_iCal() {
$yesterday = time() - 24*60*60;
$args = array(
'post_type' => 'wr_event',
'posts_per_page' => -1, // show all posts
'meta_key' => 'event_date',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'meta_value' => $yesterday,
'meta_compare' => '>',
);
$loop = new WP_Query( $args );
$ical = "BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN";
$posts = get_posts( $args );
foreach( $posts as $post ) : setup_postdata($post);
$ical .= "BEGIN:VEVENT
UID:" . md5(uniqid(mt_rand(), true)) . "mysite.com
DTSTAMP:" . gmdate('Ymd').'T'. gmdate('His') . "Z
DTSTART:".unixToiCal(get_event_date($post), get_event_time($post))."00Z
DTEND:".unixToiCal(get_event_end_date($post), get_event_end_time($post))."00Z
SUMMARY:".get_the_title($post->ID)."
DESCRIPTION:".get_the_content($post->ID)."
END:VEVENT";
endforeach;
$ical .= "END:VCALENDAR";
header('Content-type: text/calendar; charset=utf-8');
header('Content-Disposition: inline; filename=calendar.ics');
echo $ical;
exit;
}
function unixToiCal($uStamp = 0, $tzone = 0.0) {
$uStampUTC = $uStamp + ($tzone * 3600);
$stamp = date("Ymd\THis\Z", $uStampUTC);
return $stamp;
}
I use this function call in my index.php
to list all “upcoming” events.
Creating a .ics file.
There is another feature that I’d like to have. I want to create a .ics (iCal) file on the fly with all “upcoming” events. So I guess this shoudln’t be to hard as I already have the query.
Any ideas on that matter? I would really appreciate some help with this.
Update:
I have two more problems with the .ics Calendar file.
I have a function get_event_date($timestamp)
that returns a timestamp of the event-date. However there is a (for me) rather complicated part in it.
There are two variables $date[0]
and $time[0]
that hold different formats.
The $date[0]
holds a timestamp 1347667200
and the $time[0]
holds a string e.g. 14:00
. I now need to calculate the final timestamp of the “date” plus “time” to pass it along to the unixToical()
function.
if ( $timestamp ) {
if ( !empty( $time[0]) ) {
$time = explode(':', $time[0]);
$hours = $time[0];
$minutes = $time[1];
} else {
//$hours = "00";
//$minutes = "00";
}
$seconds = "00";
return $date[0] + ($hours * 60) + $minutes;
exit;
}
The part where I set $hours
to “00” is for when there is no time set. In that case I want to time in the final .ics to be “00:00” (midnight).
Any idea what I’m doing wrong here. I guess this might be the problem why when importing the calendar file to iCal only the first event is imported. (When opening the file with a text-editor all events are in there)
2 Answers
This is entirely based on Event Organiser (a plug-in I’ve developed). The code is lifted almost straight from the source but with alterations. As such I’ve not tested the code as given.
Step 1: Create a feed
This is simple:
add_action('init','wpse63611_add_events_feed');
function wpse63611_add_events_feed(){
add_feed('my-events','wpse63611_events_feed_output');
}
This adds a feed to your site: www.site.com?feed=my-events
or www.site.com/feed/my-events
if you have pretty permalinks. The wpse63611_events_feed_output()
callback will output the contents of the ICAL file. But first…
Step 2: Alter the query
WordPress doesn’t know what this feed is meant to contain. Here we use the pre_get_posts
to tell WordPress, that for this feed we want posts of post type ‘wr_event’. We could get events from a particular category, venue or between certain dates too.
By separating out the query from the output, you can have multiple feeds which use the same output function – but query different events (based on time, location, category etc).
add_action( 'pre_get_posts', 'wpse63611_event_feed_query' );
function wpse63611_event_feed_query( $query ) {
$yesterday = current_time('timestamp') - 24*60*60;
$compare = $latest ? '>' : '<';
if( $query->is_feed('eo-events') ){
$query->set('post_type', 'wr_event');
$query->set('posts_per_page', -1);
$query->set('meta_key', 'event_date');
$query->set('orderby', 'meta_value_num');
$query->set('order', 'ASC');
$query->set('meta_compare', $compare);
$query->set('meta_value', $value);
}
}
Step 3: The contents of the ICS file
As mentioned earlier, wpse63611_events_feed_output()
is responsible for printing the output of our feed.
function wpse63611_events_feed_output(){
//Let's give it a name;
$filename = urlencode( 'my_events' . date('Y-m-d') . '.ics' );
//Collect output
ob_start();
// File header
header( 'Content-Description: File Transfer' );
header( 'Content-Disposition: attachment; filename=" . $filename );
header("Content-type: text/calendar');
header("Pragma: 0");
header("Expires: 0");
?>
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//<?php get_bloginfo('name'); ?>//NONSGML Events //EN
CALSCALE:GREGORIAN
X-WR-CALNAME:<?php echo get_bloginfo('name');?> - Events
<?php
// Loop through events
if ( have_posts() ):
$now = new DateTime();
$datestamp =$now->format('Ymd\THis\Z');
while( have_posts() ): the_post();
global $post;
$uid = md5(uniqid(mt_rand(), true))."@mysite.com";
$start = unixToiCal(get_event_date($post), get_event_time($post));
$end = unixToiCal(get_event_end_date($post), get_event_end_time($post));
$summary = wpse63611_escape_icalText(get_the_title())
$description = apply_filters('the_excerpt_rss', get_the_content());
$description = wpse63611_escape_icalText($description);
BEGIN:VEVENT
UID:<?php echo $uid;?>
DTSTAMP:<?php echo $datestamp;?>
DTSTART:<?php echo $start; ?>
DTEND:<?php echo $end; ?>
SUMMARY:<?php echo wpse63611_esc_ical_text($summary);?>
DESCRIPTION:<?php echo wpse63611_esc_ical_text($description);?>
END:VEVENT
endwhile;
endif;
?>
END:VCALENDAR
<?php
//Collect output and echo
$eventsical = ob_get_contents();
ob_end_clean();
echo $eventsical;
exit();
}
I’ve used the unixToiCal
function you’ve defined in your question. I’ve also used the following to remove anything that might upset an ICAL parser:
function wpse63611_esc_ical_text( $text="" ){
$text = str_replace("\\", "\\\\", $text);
$text = str_replace(",", "\,", $text);
$text = str_replace(";", "\;", $text);
$text = str_replace("\n", "\n ", $text);
return $text;
}