Creating ICal For Custom Post Type In WordPress Without A Plugin.

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!


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *