Dynamic iCal generator outside/inside wordpress

So following on from this post: https://stackoverflow.com/q/1463480/1086990 I was wondering how exactly it would work integrating it into WordPress.

I have a custom post type setup, and so far I have tried both linking to a “ical.php” with the above link code (and changing the title into the_title() and the dates into GMT versions of my date(..) code). None work, because it can find the get_post_custom_values() which is obvious since not in WP loop, or a WP associated file.

Next I tried adding the headers into the header.php WP file, and adding a if(is_singular("event")), but the headers auto download. If I can stop the auto download then I’m ace, otherwise I come here for help!

Is there any reasonable way that is dynamically able to be populated via WP and only download when the link is clicked, not automatically?

I would host everything, but the events are going to be so often, that making and hosting would be a waste also is there maybe a href generator like Google Calendar that would automatically work?


EDIT (My working code):

Custom Taxonomy Loop

<form action="https://wordpress.stackexchange.com/questions/56187/<?php echo get_feed_link("calendar-event'); ?>" method="post">
    <input hidden="hidden" name="eventID" value="<?php the_ID(); ?>">
    <button title="Add to iCal" type="submit" name="iCalForm">iCal</button>
</form>

iCal.php
I included this into the functions.php via a require().

<?php //Event ICAL feed
class SH_Event_ICAL_Export  {

    public function load() { add_feed('calendar-event', array(__CLASS__,'export_events')); }

    // Creates an ICAL file of events in the database
    public function export_events(){ 

        //Give the iCal export a filename
        $filename = urlencode( 'event-ical-' . 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 echo get_bloginfo('name'); ?> //NONSGML Events //EN
CALSCALE:GREGORIAN
X-WR-CALNAME:<?php echo get_bloginfo('name');?>: Events
<?php // Query for events

    if(isset($_POST['iCalForm'])) {
        $post_ID = $_POST['eventID'];
        $events = new WP_Query(array(
            'p' => $post_ID,
            'post_type' => 'event'  //Or whatever the name of your post type is
        ));

    if($events->have_posts()) : while($events->have_posts()) : $events->the_post();
        $uid = get_the_ID(); // Universal unique ID
        $dtstamp = date_i18n('Ymd\THis\Z',time(), true); // Date stamp for now.
        $created_date = get_post_time('Ymd\THis\Z', true, get_the_ID() ); // Time event created
        // Other pieces of "get_post_custom_values()" that make up for the StartDate, EndDate, EventOrganiser, Location, etc.
        // I also had a DeadlineDate which I included into the BEGIN:VALARM
        // Other notes I found while trying to figure this out was for All-Day events, you just need the date("Ymd"), assuming that Apple iCal is your main focus, and not Outlook, or others which I haven't tested :]
?>
BEGIN:VEVENT
CREATED:<?php echo $created_date;?>

UID:<?php echo $uid;?>

DTEND;VALUE=DATE:<?php echo $end_date; ?>

TRANSP:OPAQUE
SUMMARY:<?php echo $organiser; ?>

DTSTART;VALUE=DATE:<?php echo $start_date ; ?>

DTSTAMP:<?php echo $dtstamp;?>

LOCATION:<?php echo $location;?>

ORGANIZER:<?php echo $organiser;?>

URL;VALUE=URI:<?php echo "http://".$url; ?>

BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DATE-TIME:<?php echo $dLine; ?>

DESCRIPTION:Closing submission day of films for <?php echo $organiser; ?>! Enter quickly!
END:VALARM
END:VEVENT
<?php endwhile; endif; } ?>
END:VCALENDAR
<?php //Collect output and echo 
    $eventsical = ob_get_contents();
    ob_end_clean();
    echo $eventsical;
    exit();
    }   

} // end class
SH_Event_ICAL_Export::load();
?>

Hope this serves well to whoever needs it, as it is a fantastic piece of work, so again thanks Stephen Harris who helped more than the question, and additionally without suggesting I use his plugin.

2 Answers
2

I would use WordPress’ feeds. You can create your own feed with add_feed. You specify a callback and this callback is responsible for displaying the output.

Creating a feed

add_feed('my-events','wpse56187_ical_cb');

wpse56187_ical_cb is that responsible for getting the events (use WP_Query), looping through them and printing the ICAL fields.

Downloading the ICAL file

If your feed is ‘my-events’, then the ical file can then be downloaded by going to:

www.yoursite.com?feed=my-events
www.yoursite.com/feed/my-events //If you have pretty permalinks

The link to the feed can be obtained by get_feed_link(). So if you wanted to create a link to you event’s feed in your template:

<a href="<?php echo get_feed_link('my-events'); ?>" > Click here for ical file </a>

Example

I’ve omitted the details of filling in the event details in ICAL format (how you do this will depend on how you’ve stored the details).

The following class implements the above method and creates a feed called ‘my-events’. You will need to make sure the details are formatted correctly and are valid (see this site)

Please note, I’ve not tested the following so there may be syntax errors

<?php
/**
 * Event ICAL feed
 */
class SH_Event_ICAL_Export  {

    public function load(){
        add_feed('my-events', array(__CLASS__,'export_events'));
    }

   /**
    * Creates an ICAL file of events in the database
    *  @param string filename - the name of the file to be created
    *  @param string filetype - the type of the file ('text/calendar')
    */ 
    public function export_events( ){ 

    //Give the ICAL a filename
    $filename = urlencode( 'event-ical-' . 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
  
    // Query for events
    $events = WP_Query(array(
         'post_type'=>'event' //Or whatever the name of your post type is
         'posts_per_page'=>-1 //Get all events
          ...
    ));

    if( $events->have_posts() ):
        while( $events->have_posts() ): $events->the_post();
            $uid=''; //Universal unique ID
            $dtstamp=date_i18n('Ymd\THis\Z',time(), true); //date stamp for now.
            $created_date=get_post_time('Ymd\THis\Z', true, get_the_ID() ); //time event created
            $start_date=""//event start date
            $end_date=""//event end date
            $reoccurrence_rule=false//event reoccurrence rule.
            $location=''//event location
            $organiser=""//event organiser
?>
BEGIN:VEVENT
UID:<?php echo $uid;?>

DTSTAMP:<?php echo $dtstamp;?>

CREATED:<?php echo $created_date;?>

DTSTART:<?php echo $start_date ; ?>

DTEND:<?php echo $end_date; ?>

<?php if ($reoccurrence_rule):?>
RRULE:<?php echo $reoccurrence_rule;?>

<?php endif;?>

LOCATION: <?php echo $location;?>

ORGANIZER: <?php $organiser;?>

END:VEVENT
<?php
        endwhile;
    endif;
?>
END:VCALENDAR
<?php

    //Collect output and echo 
    $eventsical = ob_get_contents();
    ob_end_clean();
    echo $eventsical;
    exit();
    }   

} // end class
SH_Event_ICAL_Export::load();

Leave a Comment