Dynamic iCal generator outside/inside wordpress

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();