In this blog, we will learn about how to add an ical feature in WordPress without a plugin.
Define the following constant in your functions.php
define( 'EVENT_CALENDAR_FEED_SLUG', 'events-calendar' );
define( 'CUSTOM_POST_TYPE_SLUG', 'your-post-type-slug' );
Create a file called ical.php
and include it in your functions.php
define( 'EVENT_CALENDAR_FEED_SLUG', 'events-calendar' );
define( 'CUSTOM_POST_TYPE_SLUG', 'your-post-type-slug' );
Create a file called ical.php and include it in your functions.php
<?php
/**
* Ical functions.
*
* For a better understanding of ics requirements and time formats
* please check https://gist.github.com/jakebellacera/635416
*
* @package YoutTheme
*/
namespace YourNamespace;
use WP_Query;
/**
* Escapes a string of characters
*
* @param string $string String.
*
* @return array|string
*/
function escapeString( string $string ) {
return preg_replace( '/([\,;])/', '\\\$1', $string );
}
/**
* Shorten a string to desired characters length
*
* eg. shorter_version($string, 100);
*
* @param string $string String.
* @param int $length Length.
*
* @return false|mixed|string
*/
function shorter_version( string $string, int $length ) {
if ( empty( $string ) || empty( $length ) ) {
return '';
}
return strlen( $string ) >= $length ? substr( $string, 0, $length ) : $string;
}
/**
* Add a custom endpoint 'event-calendar'
*/
function add_calendar_feed(){
add_feed( EVENT_CALENDAR_FEED_SLUG, __NAMESPACE__ . '\\export_ics' );
/**
* Only uncomment the below two lines, the first time you load this script,
* to update WP rewrite rules, or in case you see a 404
*/
global $wp_rewrite;
$wp_rewrite->flush_rules( false );
}
add_action('init', __NAMESPACE__ . '\\add_calendar_feed');
/**
* Calendar function
*/
function export_ics(){
// Collect output.
ob_start();
// Set the correct headers for this file
header("Content-Description: File Transfer");
header('Content-type: text/calendar; charset=utf-8');
header("Pragma: 0");
header("Expires: 0");
$eol = "\r\n";
?>
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//<?php echo get_bloginfo('name'); ?> //NONSGML Events //EN
CALSCALE:GREGORIAN
X-WR-CALNAME:<?php echo get_bloginfo('name').$eol;?>
<?php
// Query the event.
$the_event = new WP_Query( [
'post_type' => CUSTOM_POST_TYPE_SLUG,
'p' => intval( $_REQUEST['id'] ), // Post Id.
'update_post_meta_cache' => false,
'no_found_rows' => true,
'update_post_term_cache' => false,
] );
if ( $the_event->have_posts() ) :
while ( $the_event->have_posts() ) : $the_event->the_post();
/**
* The correct date format, for ALL dates is date_i18n('Ymd\THis\Z',time(), true)
* So if your date is not in this format, use that function
* Second param of date_i18n needs to be a timestamp.
*/
$event_start_date = 'your-event-start-date-time-stamp';
$event_end_date = 'your-event-end-date-time-stamp';
$start_date = date_i18n( 'Ymd\THis\Z', strtotime( $event_start_date ) );
$end_date = date_i18n( 'Ymd\THis\Z', strtotime( $event_end_date ) );
$deadline = date_i18n( 'Ymd\THis\Z', strtotime( $event_end_date ) ); // Reminder is set 30 mins before this time.
$timestamp = date_i18n( 'Ymd\THis\Z', time(), true );
$uid = get_the_ID();
$created_date = get_post_time( 'Ymd\THis\Z', true, $uid );
$organiser = __( 'Codeytek Academy', 'text-domain' );
$address = __( 'Codeytek Academy', 'text-domain' ); // @TODO be checked later if this needs to change.
$url = get_the_permalink();
$content = html_entity_decode( trim( preg_replace( '/\s\s+/', ' ', get_the_content() ) ) ); // removes newlines and double spaces
$title = html_entity_decode( get_the_title() );
//Give the iCal export a filename
$filename = sprintf( '%1$s-ical-%2$s.ics', esc_html( $title ), date('Y-m-d') );
$filename = urlencode( $filename );
header( "Content-Disposition: attachment; filename=" . $filename );
/**
* The below ics structure MUST NOT have spaces before each line
*
* @see https://gist.github.com/jakebellacera/635416
*/
?>
BEGIN:VEVENT
CREATED:<?php printf( '%1$s%2$s', esc_html( $created_date ), $eol );?>
UID:<?php printf( '%1$s%2$s', esc_html( $uid ), $eol );?>
DTEND;VALUE=DATE:<?php printf( '%1$s%2$s', esc_html( $end_date ), $eol );?>
DTSTART;VALUE=DATE:<?php printf( '%1$s%2$s', esc_html( $start_date ), $eol );?>
DTSTAMP:<?php printf( '%1$s%2$s', esc_html( $timestamp ), $eol );?>
LOCATION:<?php printf( '%1$s%2$s', esc_html( $address ), $eol );?>
DESCRIPTION:<?php printf( '%1$s%2$s', esc_html( $content ), $eol );?>
SUMMARY:<?php printf( '%1$s%2$s', esc_html( $title ), $eol );?>
ORGANIZER:<?php printf( '%1$s%2$s', esc_html( escapeString( $organiser ) ), $eol );?>
URL;VALUE=URI:<?php printf( '%1$s%2$s', esc_url( escapeString( $url ) ), $eol );?>
TRANSP:OPAQUE
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DATE-TIME:<?php printf( '%1$s%2$s', esc_html( $deadline ), $eol );?>
DESCRIPTION:Reminder for <?php printf( '%1$s%2$s', esc_html( escapeString( $title ) ), $eol );?>
END:VALARM
END:VEVENT<?php echo $eol; ?>
<?php endwhile; ?>END:VCALENDAR<?php
//Collect output and echo
$eventsical = ob_get_contents();
ob_end_clean();
echo $eventsical;
exit();
endif;
}
?>
Then to include the link for downloadable `Ical`, use the following.
$calendar_feed_link = sprintf( '%1$s?id=%2$s', get_feed_link( EVENT_CALENDAR_FEED_SLUG ), get_the_ID() );
<a class="no-underline-link flex items-center py-5 lg:py-6" href="<?php echo esc_url( $calendar_feed_link ); ?>" title="<?php esc_attr_e( 'Add to my calendar', 'text-domain' ); ?>">
<span class="text-2xl lg:text-3xl uppercase"><?php esc_html_e( 'Add to my calendar', 'text-domain' ); ?></span>
</a>
Now click on that link it will download a .ics
file. Click on that file and add it to the calendar.


You can also open the file in an editor and checkout the output.
Inspiration Blogs and Credits.
https://www.noeltock.com/web-design/wordpress/how-to-ical-with-custom-post-types/
https://gist.github.com/jakebellacera/635416
https://www.shambix.com/ics-calendar-wordpress-post/
That’s all folks!
Leave a Reply