Settings > Permalink Settings page by clicking on "Save changes" button.
* Finally, to display your feed, you’ll first need to flush your WordPress rewrite rules.
* The easiest way to do this is by logging in to the WordPress admin, and clicking Settings -> Permalinks.
* Once here, just click Save Changes, which will flush the rewrite rules.
*
* Otherwsie need to run ONLY once this:
*
* global $wp_rewrite;
* $wp_rewrite->flush_rules();
*
*/
function wpbm_make_export_ics_feeds(){
if ( function_exists( 'wp_parse_url' ) )
$my_parsed_url = wp_parse_url( $_SERVER[ 'REQUEST_URI' ] );
else
$my_parsed_url = @parse_url( $_SERVER[ 'REQUEST_URI' ] );
if ( false === $my_parsed_url ) { // seriously malformed URLs, parse_url() may return FALSE.
return;
}
$my_parsed_url_path = trim( $my_parsed_url[ 'path' ] );
$my_parsed_url_path = trim( $my_parsed_url_path, '/' );
//FixIn: 2.0.5.4
// check internal subfolder of WP, like http://server.com/my-website/ ... link ...
$server_url_sufix = '';
if ( function_exists( 'wp_parse_url' ) )
$wp_home_server_url = wp_parse_url( home_url() );
else
$wp_home_server_url = @parse_url( home_url() );
if ( ( false !== $wp_home_server_url ) && (! empty( $wp_home_server_url[ 'path' ] ) ) ){ // seriously malformed URLs, parse_url() may return FALSE.
$server_url_sufix = trim( $wp_home_server_url[ 'path' ] ); // [path] => /my-website
$server_url_sufix = trim( $server_url_sufix, '/' ); // my-website
if ( ! empty( $server_url_sufix ) ) {
$check_sufix = substr( $my_parsed_url_path, 0, strlen( $server_url_sufix ) );
if ( $check_sufix === $server_url_sufix ) {
$my_parsed_url_path = substr( $my_parsed_url_path, strlen( $server_url_sufix ) );
$my_parsed_url_path = trim( $my_parsed_url_path, '/' );
}
}
}
//End FixIn: 2.0.5.4
// Get booking resources and Export Feed URLS
$is_continue = false;
if ( function_exists( 'wpbc_br_cache' ) ) {
$resources_cache = wpbc_br_cache(); // Get booking resources from cache
$resource_list = $resources_cache->get_resources();
foreach ( $resource_list as $res_id => $res_arr) {
if ( ! empty( $res_arr[ 'export' ] ) ) {
$resource_feed_url = $res_arr[ 'export' ];
} else {
$resource_feed_url = '';
}
$resource_feed_url = trim( $resource_feed_url, '/' );
if ( ! empty( $resource_feed_url ) ) {
// if ( 0 === strpos( $my_parsed_url_path, $resource_feed_url ) ) { // First coocurence of $download_url_path in URL, like 'wpbm-ics-export' in 'http://beta/wpbm-ics-export/my-feed/'
if ( $my_parsed_url_path === $resource_feed_url ) {
$is_continue = true;
break;
}
}
}
} else if ( function_exists( 'get_bk_option' ) ) {
//TODO: cehck for Free version.
$res_id = 1;
$resource_feed_url = get_bk_option( 'booking_resource_export_ics_url' );
$resource_feed_url = trim( $resource_feed_url, '/' );
if ( ! empty( $resource_feed_url ) ) {
if ( $my_parsed_url_path === $resource_feed_url ) {
$is_continue = true;
}
}
} else {
return; // No Booking Calendar active, so ust opening some other page
}
if ( true === $is_continue) {
$download_url_path = $resource_feed_url;
$ics_export = wpbm_export_ics_feed__wpbm_ics( array( 'wh_booking_type' => $res_id ) );
if ( headers_sent() ){
die( 'headers_sent_before_download' );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Prepare system before downloading set time limits, server output options
////////////////////////////////////////////////////////////////////////////////////////////////////////////
$disabled = explode( ',', ini_get( 'disable_functions' ) );
$is_func_disabled = in_array( 'set_time_limit', $disabled );
if ( ! $is_func_disabled && ! ini_get( 'safe_mode' ) ) {
@set_time_limit( 0 );
}
//FixIn: 2.0.18.2
// if ( function_exists( 'get_magic_quotes_runtime' ) && get_magic_quotes_runtime() && version_compare( phpversion(), '5.4', '<' ) ) {
// set_magic_quotes_runtime( 0 );
// }
@session_write_close();
if ( function_exists( 'apache_setenv' ) ) {
@apache_setenv( 'no-gzip', 1 );
}
@ini_set( 'zlib.output_compression', 'Off' );
@ob_end_clean(); // In case, if somewhere opeded output buffer, may be required for working fpassthru with large files
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Set Headers before file download
////////////////////////////////////////////////////////////////////////////////////////////////////////////
$file = array();
$file['content_type'] = 'text/calendar';
$file['name'] = 'wpbm.ics';
if ( function_exists( 'mb_detect_encoding' ) ) //FixIn: 2.0.5.3
$text_encoding = mb_detect_encoding( $ics_export );
else
$text_encoding = ''; //Unknown
//debuge( mb_detect_encoding( $ics_export ) );die;
if ( ( is_array( $text_encoding ) )
&& ( ! in_array( 'UTF-8', $text_encoding ) )
){
$file['size'] = wpbm_get_bytes_from_str( $ics_export );
} else {
$file['size'] = 0; // UTF-8 encoding, so size alculated incorrectly, probabaly
}
nocache_headers();
header( "Robots: none" . "\n" );
@header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 200 OK' . "\n" );
header( "Content-Type: " . $file['content_type'] . "\n" );
header( "Content-Description: File Transfer" . "\n" );
header( "Content-Disposition: attachment; filename=\"" . $file['name'] . "\"" . "\n" );
header( "Content-Transfer-Encoding: binary" . "\n" );
if ( (int) $file['size'] > 0 )
header( "Content-Length: " . $file['size'] . "\n" );
echo $ics_export;
exit;
}
// Unknown error, or just opening some other page
}
add_action( 'template_redirect', 'wpbm_make_export_ics_feeds' );
/** Define export ICS here
* For testing: http://beta/?feed=wpbm-ics
*/
function wpbm_export_ics_feed__wpbm_ics( $param = array( 'wh_booking_type' => '1', 'wh_trash' => '' ) ) { //FixIn: 2.0.2.3
if ( ! function_exists( 'wpbc_api_get_bookings_arr' ) )
return '';
// // Start date of getting bookings
// $real_date = strtotime( '-1 year' );
// $wh_booking_date = date_i18n( "Y-m-d", $real_date );
// $param['wh_booking_date'] = $wh_booking_date;
// End date of getting bookings
$real_date = strtotime( '+2 years' ); //FixIn: 2.0.7.1
$wh_booking_date2 = date_i18n( "Y-m-d", $real_date );
$param['wh_booking_date2' ] = $wh_booking_date2;
// Export only approved bookings //FixIn: 2.0.11.1 //FixIn: 8.5.2.3
$booking_is_ics_export_only_approved = get_bk_option( 'booking_is_ics_export_only_approved' );
if ( 'On' == $booking_is_ics_export_only_approved ) {
$param['wh_approved'] = '1';
} else {
$param['wh_approved'] = '';
}
//'' | 'imported' | 'plugin' //FixIn: 8.8.3.19 //FixIn: 2.0.20.2
if ( 'imported' == get_bk_option( 'booking_is_ics_export_imported_bookings' ) ) {
$param['wh_sync_gid'] = 'imported';
}
if ( 'plugin' == get_bk_option( 'booking_is_ics_export_imported_bookings' ) ) {
$param['wh_sync_gid'] = 'plugin';
}
$_REQUEST['view_mode']= 'vm_calendar'; //FixIn: 8.5.2.15 2.0.11.2
// Get array of bookings.
$bookings_arr = wpbc_api_get_bookings_arr( $param );
ob_start();
// create the ical object
$icalobj = new ZCiCal();
foreach ( $bookings_arr['bookings'] as $bk_id => $bk_arr ) {
// create the event within the ical object
$eventobj = new ZCiCalNode( 'VEVENT', $icalobj->curnode );
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SUMMARY [Title]
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if ( function_exists( 'get_title_for_showing_in_day' ) ) { // Get title of booking pipiline in "Calendar Overview" page
if ( true ) { // admin
$what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_calendar_view_mode' );
} else { // front-end
$what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_timeline_front_end' );
}
//$title = esc_textarea( get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ) );
$title = get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ); //FixIn: 2.0.1.6.1
} else {
$title = ( ( isset( $bk_arr->form_data['name'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['name'] ) : '' )
. ( ( isset( $bk_arr->form_data['firstname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['firstname'] ) : '' )
. ( ( isset( $bk_arr->form_data['secondname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['secondname'] ) : '' )
. ( ( isset( $bk_arr->form_data['lastname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['lastname'] ) : '' );
}
// Insert the name of booking resource into title of .ics event
//$title = $bk_arr->form_data['_all_fields_']['resource_title']->title . ' - ' . $title;
$is_hide_details = get_wpbm_option( 'wpbm_is_hide_details' );
if ( 'On' === $is_hide_details ) { //FixIn: 2.0.12.3
$title = '';
}
$title = wpbm_esc_to_plain_text( $title ); //FixIn: 2.0.1.6.1
//$title = substr($title, 0, 5);
$eventobj->addNode( new ZCiCalDataNode( 'SUMMARY:' . trim( $title ) ) );
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$description = $bk_arr->form_show;
// if ( ( ! empty($bk_arr->dates) ) && ( $bk_arr->dates[0]->approved ) ){
// $description .= '
Status: Approved';
// } else {
// $description .= '
Status: Pending';
// }
//$description = html_entity_decode( sanitize_text_field( $description ) );
//$description = trim( wp_specialchars_decode( esc_html( stripslashes( $description ) ), ENT_QUOTES ) );
if ( 'On' === $is_hide_details ) { //FixIn: 2.0.12.3
$description = '';
}
$description = wpbm_esc_to_plain_text( $description );
//debuge($description . '!');die;
//$description = substr($description, 0, 1);
$description = preg_replace( array( "/\n/" ), array( '' ), $description );
//debuge( ZCiCal::formatContent( $description ) );die;
$eventobj->addNode( new ZCiCalDataNode( 'DESCRIPTION:' . ZCiCal::formatContent( $description ) ) );
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// START & END DATES
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$event_start = $bk_arr->dates_short[ 0 ];
if ( ( count($bk_arr->dates_short) > 1 ) && ( '-' === $bk_arr->dates_short[ 1 ] ) ) {
$event_end = $bk_arr->dates_short[ 2 ];
$event_end = wpbm_get_next_date_if_it_full_date( $event_end );
$period_start_index = 3;
} else { // comma
$event_end = $bk_arr->dates_short[ 0 ];
$event_end = wpbm_get_next_date_if_it_full_date( $event_end );
$period_start_index = 1;
}
// add start date
$eventobj->addNode( new ZCiCalDataNode( "DTSTART:" . ZCiCal::fromSqlDateTime( $event_start ) ) );
// add end date
$eventobj->addNode( new ZCiCalDataNode( "DTEND:" . ZCiCal::fromSqlDateTime( $event_end ) ) );
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// RDATE - Rule for other different dates.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
// 19960404T010000Z/PT3H
//
$rdate = array();
$previos_value = '';
foreach ( $bk_arr->dates_short as $short_ind => $bk_date ) {
if ( $short_ind < $period_start_index )
continue;
if ( ( $bk_date !== ',' ) && ( $bk_date !== '-' ) ) {
if ( $previos_value == '-' ) {
$bk_date = wpbm_get_next_date_if_it_full_date( $bk_date );
} else {
$bk_date = wpbm_get_only_date_if_it_full_date( $bk_date );
}
$rdate[]= ZCiCal::fromSqlDateTime( $bk_date );
} else if ( ( $bk_date === '-' ) && ( count($rdate) > 0 ) ) {
$rdate[] = '/'; // PERIOD
} else if ( ( $bk_date === ',' ) && ( count($rdate) > 0 ) ) {
$rdate[] = ','; // Other date
}
$previos_value = $bk_date;
}
if ( ! empty( $rdate ) ) {
$rdate = implode( '', $rdate );
// add RDATE
$eventobj->addNode( new ZCiCalDataNode( "RDATE;VALUE=PERIOD:" . $rdate ) );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Timezone
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Timezone must be a supported PHP timezone (see http://php.net/manual/en/timezones.php )
* Note: multi-word timezones must use underscore "_" separator
* Example: $tzid = "America/New_York";
*/
$tzid = get_bk_option( 'booking_gcal_timezone' );
if ( ! empty( $tzid ) ) {
// Add timezone data
ZCTimeZoneHelper::getTZNode( substr( $event_start, 0, 4 ), substr( $event_end, 0, 4 ), $tzid, $icalobj->curnode ); //FixIn: 2.0.3.3
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// UID
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$uid = $event_start . '_' . $bk_id . "@demo.icalendar.org";
$eventobj->addNode( new ZCiCalDataNode( "UID:" . $uid ) );
// DTSTAMP is a required item in VEVENT
$eventobj->addNode( new ZCiCalDataNode( "DTSTAMP:" . ZCiCal::fromSqlDateTime() ) );
$eventobj->addNode( new ZCiCalDataNode( "CREATED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
$eventobj->addNode( new ZCiCalDataNode( "LAST-MODIFIED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// STATUS:CONFIRMED ( "TENTATIVE" / "CONFIRMED" / "CANCELLED" ) // This property defines the overall status for EVENT
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$ics_status = 'TENTATIVE';
if ( ! ( empty( $bk_arr->trash ) ) ) {
$ics_status = 'CANCELLED';
} elseif ( ! ( empty( $bk_arr->dates[0]->approved ) ) ) {
$ics_status = 'CONFIRMED';
}
$eventobj->addNode( new ZCiCalDataNode( "STATUS:" . $ics_status ) ); //FixIn: 2.0.11.3 //FixIn: 2.0.12.2
//FixIn: 2.0.20.1
//ATTENDEE;SENT-BY=MAILTO:jan_doe@host1.com;CN=John Smith:MAILTO:jsmith@host1.com // More here https://www.kanzaki.com/docs/ical/attendee.html
if ( isset( $bk_arr->form_data['email'] ) ) {
$cn_title = ( ( isset( $bk_arr->form_data['name'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['name'] ) : '' )
. ( ( isset( $bk_arr->form_data['firstname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['firstname'] ) : '' )
. ( ( isset( $bk_arr->form_data['secondname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['secondname'] ) : '' )
. ( ( isset( $bk_arr->form_data['lastname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['lastname'] ) : '' );
$attendee_email = $bk_arr->form_data['email'];
$eventobj->addNode( new ZCiCalDataNode( "ATTENDEE;CN=" . $cn_title . ":MAILTO:" . $attendee_email ) );
}
// RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=WE,SA
// LOCATION:South Australia\, Australia
// SEQUENCE:1 // defines the revision sequence number of the calendar component within a sequence of revisions
// TRANSP:OPAQUE // This property defines whether or not an event is transparent to busy time searches ;Default value is OPAQUE
// OPAQUE - Blocks or opaque on busy time searches.
// TRANSPARENT - Transparent on busy time searches.
}
echo $icalobj->export(); // write iCalendar feed to stdout
$ics_export = ob_get_contents();
ob_end_clean();
return $ics_export;
}
/** Get Next day in MySQL format without time, if current day its Full day - ending with 00:00:00
*
* @param string $mysql_date - 2017-07-12 00:00:00
* @return string - 2017-07-13
*/
function wpbm_get_next_date_if_it_full_date( $mysql_date ) {
// Check if this date ending with 00:00:00 its means that it full day,
// so we need to add 24 hours for ending at 23:59:59 (basically 00:00:00 of next day) instead of at start of current day 00:00:00
if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
&& ( substr( $mysql_date, 11 ) == '00:00:00' )
) {
$mysql_date = date_i18n( "Y-m-d 00:00:00", strtotime( $mysql_date ) );
$mysql_date = strtotime( $mysql_date );
$mysql_date = date_i18n( "Y-m-d", strtotime( '+1 day', $mysql_date ) );
}
return $mysql_date;
}
/** Get day in MySQL format without time, if current day its Full day - ending with 00:00:00
*
* @param string $mysql_date - 2017-07-12 00:00:00
* @return string - 2017-07-12
*/
function wpbm_get_only_date_if_it_full_date( $mysql_date ) {
if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
&& ( substr( $mysql_date, 11) == '00:00:00' )
) {
$mysql_date = substr( $mysql_date, 0, 10 );
}
return $mysql_date;
}