# "Add to Calendar" Download for Events

> Adds an "Add to calendar" link to single events that downloads an .ics file for Apple Calendar, Outlook and Google Calendar.

- Type: PHP
- Runs: Run everywhere
- Category: [Custom Post Types & Fields](https://wpide.com/library/category/post-types/)
- Tags: events, calendar, ics
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/event-add-to-calendar/

## Code

```php
add_action( 'template_redirect', function () {
    if ( ! isset( $_GET['ical'] ) || ! is_singular( 'event' ) ) { // phpcs:ignore WordPress.Security.NonceVerification -- read-only download.
        return;
    }

    $post  = get_queried_object();
    $tz    = wp_timezone();
    $start = date_create_immutable( (string) get_post_meta( $post->ID, '_event_start', true ), $tz );

    if ( ! $start || ! get_post_meta( $post->ID, '_event_start', true ) ) {
        return;
    }

    $end_raw = (string) get_post_meta( $post->ID, '_event_end', true );
    $end     = $end_raw ? date_create_immutable( $end_raw, $tz ) : false;
    $end     = ( $end && $end > $start ) ? $end : $start->modify( '+1 hour' );
    $utc     = new DateTimeZone( 'UTC' );
    $text    = function ( $value ) {
        return addcslashes( str_replace( array( "\r\n", "\n" ), '\n', wp_strip_all_tags( (string) $value ) ), ',;\\' );
    };
    $where   = trim( get_post_meta( $post->ID, '_event_venue', true ) . ', ' . get_post_meta( $post->ID, '_event_address', true ), ', ' );

    $lines = array(
        'BEGIN:VCALENDAR',
        'VERSION:2.0',
        'PRODID:-//' . $text( get_bloginfo( 'name' ) ) . '//Events//EN',
        'CALSCALE:GREGORIAN',
        'BEGIN:VEVENT',
        'UID:event-' . $post->ID . '@' . wp_parse_url( home_url(), PHP_URL_HOST ),
        'DTSTAMP:' . gmdate( 'Ymd\THis\Z' ),
        'DTSTART:' . $start->setTimezone( $utc )->format( 'Ymd\THis\Z' ),
        'DTEND:' . $end->setTimezone( $utc )->format( 'Ymd\THis\Z' ),
        'SUMMARY:' . $text( get_the_title( $post ) ),
        'URL:' . esc_url_raw( get_permalink( $post ) ),
        'DESCRIPTION:' . $text( get_the_excerpt( $post ) ),
        'LOCATION:' . $text( $where ),
        'END:VEVENT',
        'END:VCALENDAR',
    );

    nocache_headers();
    header( 'Content-Type: text/calendar; charset=utf-8' );
    header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $post->post_name ) . '.ics"' );
    echo implode( "\r\n", $lines ) . "\r\n"; // phpcs:ignore WordPress.Security.EscapeOutput -- calendar format, escaped above.
    exit;
} );

add_filter( 'the_content', function ( $content ) {
    if ( ! is_singular( 'event' ) || ! in_the_loop() || ! is_main_query() || ! get_post_meta( get_the_ID(), '_event_start', true ) ) {
        return $content;
    }

    return $content . '<p class="event-add-to-calendar"><a href="' . esc_url( add_query_arg( 'ical', '1', get_permalink() ) ) . '" rel="nofollow">Add to calendar (.ics)</a></p>';
} );
```

## Notes

Reads the start, end, venue and address saved by the Event Details meta box snippet. Events without an end time last one hour.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find ""Add to Calendar" Download for Events" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
