Tribe__Events__iCal::generate_ical_feed( int|null $post = null, boolean $echo = true )

Generates the iCal file


Parameters #

$post

(int|null) (Optional) If you want the ical file for a single event

Default value: null

$echo

(boolean) (Optional) Whether the content should be echoed or returned

Default value: true


Top ↑

Return #

(string)


Top ↑

Source #

File: src/Tribe/iCal.php

	public function generate_ical_feed( $post = null, $echo = true ) {
		$tec         = Tribe__Events__Main::instance();
		$events      = '';
		$blogHome    = get_bloginfo( 'url' );
		$blogName    = get_bloginfo( 'name' );

		if ( $post ) {
			$events_posts = is_array( $post ) ? $post : array( $post );
		} elseif ( tribe_is_month() ) {
			$events_posts = self::get_month_view_events();
		} elseif ( tribe_is_organizer() ) {
			$events_posts = $this->get_events_list( array(
				'organizer'    => get_the_ID(),
				'eventDisplay' => 'list',
			) );
		} elseif ( tribe_is_venue() ) {
			$events_posts = $this->get_events_list( array(
				'venue'        => get_the_ID(),
				'eventDisplay' => tribe_get_request_var( 'tribe_event_display', 'list' ),
			) );
		} else {

			if ( ! $wp_query = tribe_get_global_query_object() ) {
				return;
			}

			$args = $wp_query->query_vars;

			if ( 'list' === $args['eventDisplay'] ) {
				// Whe producing a List view iCal feed the `eventDate` is misleading.
				unset( $args['eventDate'] );
			}

			$events_posts = $this->get_events_list( $args, $wp_query );
		}

		$event_ids = wp_list_pluck( $events_posts, 'ID' );

		foreach ( $events_posts as $event_post ) {
			// add fields to iCal output
			$item = array();

			$full_format = 'Ymd\THis';
			$utc_format  = 'Ymd\THis\Z';
			$all_day     = ( 'yes' === get_post_meta( $event_post->ID, '_EventAllDay', true ) );
			$time        = (object) array(
				'start'    => tribe_get_start_date( $event_post->ID, false, 'U' ),
				'end'      => tribe_get_end_date( $event_post->ID, false, 'U' ),
				'modified' => Tribe__Date_Utils::wp_strtotime( $event_post->post_modified ),
				'created'  => Tribe__Date_Utils::wp_strtotime( $event_post->post_date ),
			);

			if ( $all_day ) {
				$type   = 'DATE';
				$format = 'Ymd';
			} else {
				$type   = 'DATE-TIME';
				$format = $full_format;
			}

			$tzoned = (object) array(
				'start'    => date( $format, $time->start ),
				'end'      => date( $format, $time->end ),
				'modified' => date( $utc_format, $time->modified ),
				'created'  => date( $utc_format, $time->created ),
			);

			$dtstart = $tzoned->start;
			$dtend   = $tzoned->end;

			if ( 'DATE' === $type ) {
				// For all day events dtend should always be +1 day.
				if ( $all_day ) {
					$dtend = date( $format, strtotime( '+1 day', strtotime( $dtend ) ) );
				}

				$item[] = 'DTSTART;VALUE=' . $type . ':' . $dtstart;
				$item[] = 'DTEND;VALUE=' . $type . ':' . $dtend;
			} else {
				// Are we using the sitewide timezone or the local event timezone?
				$tz = Tribe__Events__Timezones::EVENT_TIMEZONE === Tribe__Events__Timezones::mode()
					? Tribe__Events__Timezones::get_event_timezone_string( $event_post->ID )
					: Tribe__Events__Timezones::wp_timezone_string();

				$item[] = 'DTSTART;TZID=' . $tz . ':' . $dtstart;
				$item[] = 'DTEND;TZID=' . $tz . ':' . $dtend;
			}

			$item[] = 'DTSTAMP:' . date( $full_format, time() );
			$item[] = 'CREATED:' . $tzoned->created;
			$item[] = 'LAST-MODIFIED:' . $tzoned->modified;
			$item[] = 'UID:' . $event_post->ID . '-' . $time->start . '-' . $time->end . '@' . parse_url( home_url( '/' ), PHP_URL_HOST );
			$item[] = 'SUMMARY:' . str_replace( array( ',', "\n", "\r" ), array( '\,', '\n', '' ), html_entity_decode( strip_tags( $event_post->post_title ), ENT_QUOTES ) );
			$item[] = 'DESCRIPTION:' . str_replace( array( ',', "\n", "\r" ), array( '\,', '\n', '' ), html_entity_decode( strip_tags( str_replace( '</p>', '</p> ', apply_filters( 'the_content', tribe( 'editor.utils' )->exclude_tribe_blocks( $event_post->post_content ) ) ) ), ENT_QUOTES ) );
			$item[] = 'URL:' . get_permalink( $event_post->ID );

			// add location if available
			$location = $tec->fullAddressString( $event_post->ID );
			if ( ! empty( $location ) ) {
				$str_location = str_replace( array( ',', "\n" ), array( '\,', '\n' ), html_entity_decode( $location, ENT_QUOTES ) );

				$item[] = 'LOCATION:' .  $str_location;
			}

			// add geo coordinates if available
			if ( class_exists( 'Tribe__Events__Pro__Geo_Loc' ) ) {
				$long = Tribe__Events__Pro__Geo_Loc::instance()->get_lng_for_event( $event_post->ID );
				$lat  = Tribe__Events__Pro__Geo_Loc::instance()->get_lat_for_event( $event_post->ID );

				if ( ! empty( $long ) && ! empty( $lat ) ) {
					$item[] = sprintf( 'GEO:%s;%s', $lat, $long );

					$str_title = str_replace( array( ',', "\n" ), array( '\,', '\n' ), html_entity_decode( tribe_get_address( $event_post->ID ), ENT_QUOTES ) );

					if ( ! empty( $str_title ) && ! empty( $str_location ) ) {
						$item[] =
							'X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS=' . str_replace( '\,', '', trim( $str_location ) ) . ';' .
							'X-APPLE-RADIUS=500;' .
							'X-TITLE=' . trim( $str_title ) . ':geo:' . $long . ',' . $lat;
					}
				}
			}

			// add categories if available
			$event_cats = (array) wp_get_object_terms( $event_post->ID, Tribe__Events__Main::TAXONOMY, array( 'fields' => 'names' ) );

			if ( ! empty( $event_cats ) ) {
				$item[] = 'CATEGORIES:' . html_entity_decode( join( ',', $event_cats ), ENT_QUOTES );
			}

			// add featured image if available
			if ( has_post_thumbnail( $event_post->ID ) ) {
				$thumbnail_id        = get_post_thumbnail_id( $event_post->ID );
				$thumbnail_url       = wp_get_attachment_url( $thumbnail_id );
				$thumbnail_mime_type = get_post_mime_type( $thumbnail_id );

				/**
				 * Allow for customization of an individual iCal-exported event's thumbnail.
				 *
				 * @param string $string This thumbnail's iCal-formatted "ATTACH;" string with the thumbnail mime type and URL.
				 * @param int $post_id The ID of the event this thumbnail belongs to.
				 */
				$item[] = apply_filters( 'tribe_ical_feed_item_thumbnail', sprintf( 'ATTACH;FMTTYPE=%s:%s', $thumbnail_mime_type, $thumbnail_url ), $event_post->ID );
			}

			// add organizer if available
			$organizer_email = tribe_get_organizer_email( $event_post->ID, false );
			if ( $organizer_email ) {
				$organizer_id = tribe_get_organizer_id( $event_post->ID );
				$organizer    = get_post( $organizer_id );

				if ( $organizer_id ) {
					$item[] = sprintf( 'ORGANIZER;CN="%s":MAILTO:%s', rawurlencode( $organizer->post_title ), $organizer_email );
				} else {
					$item[] = sprintf( 'ORGANIZER:MAILTO:%s', $organizer_email );
				}
			}

			/**
			 * Allow for customization of an individual "VEVENT" item to be rendered inside an iCal export file.
			 *
			 * @param array $item The various iCal file format components of this specific event item.
			 * @param object $event_post The WP_Post of this event.
			 */
			$item = apply_filters( 'tribe_ical_feed_item', $item, $event_post );

			$events .= "BEGIN:VEVENT\r\n" . implode( "\r\n", $item ) . "\r\nEND:VEVENT\r\n";
		}

		$site = sanitize_title( get_bloginfo( 'name' ) );
		$hash = substr( md5( implode( $event_ids ) ), 0, 11 );

		/**
		 * Modifies the filename provided in the Content-Disposition header for iCal feeds.
		 *
		 * @var string       $ical_feed_filename
		 * @var WP_Post|null $post
		 */
		$filename = apply_filters( 'tribe_events_ical_feed_filename', $site . '-' . $hash . '.ics', $post );

		header( 'HTTP/1.0 200 OK', true, 200 );
		header( 'Content-type: text/calendar; charset=UTF-8' );
		header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
		$content  = "BEGIN:VCALENDAR\r\n";
		$content .= "VERSION:2.0\r\n";
		$content .= 'PRODID:-//' . $blogName . ' - ECPv' . Tribe__Events__Main::VERSION . "//NONSGML v1.0//EN\r\n";
		$content .= "CALSCALE:GREGORIAN\r\n";
		$content .= "METHOD:PUBLISH\r\n";

		/**
		* Allows for customizing the value of the generated iCal file's "X-WR-CALNAME:" property.
		*
		* @param string $blogName The value to use for "X-WR-CALNAME"; defaults to value of get_bloginfo( 'name' ).
		*/
		$x_wr_calname = apply_filters( 'tribe_ical_feed_calname', $blogName );
		if ( ! empty( $x_wr_calname ) ) {
			$content .= 'X-WR-CALNAME:' . $x_wr_calname . "\r\n";
		}

		$content .= 'X-ORIGINAL-URL:' . $blogHome . "\r\n";
		$content .= 'X-WR-CALDESC:' . sprintf( esc_html_x( 'Events for %s', 'iCal feed description', 'the-events-calendar' ), $blogName ) . "\r\n";

		/**
		 * Allows for customization of the various properties at the top of the generated iCal file.
		 *
		 * @param string $content Existing properties atop the file; starts at "BEGIN:VCALENDAR", ends at "X-WR-CALDESC".
		 */
		$content  = apply_filters( 'tribe_ical_properties', $content );

		$content .= $events;
		$content .= 'END:VCALENDAR';

		if ( $echo ) {
			tribe_exit( $content );
		}

		return $content;
	}