PluginProbe
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar / 2.0.11
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar v2.0.11
2.1.22 2.1.21 2.1.20 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 trunk 1.1 2.0 2.0.1 2.0.10.2 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.17 2.0.18 2.0.2 2.0.20 2.0.21 All 56 releases
booking-manager / core / wpbc / wpbm-bc-export.php

wpbm-bc-export.php in Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar 2.0.11, at core/wpbc/wpbm-bc-export.php

447 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version 1.0
4 * @description Booking Calendar integration - Export
5 *
6 * @author wpdevelop
7 * @link https://oplugins.com/
8 * @email [email protected]
9 *
10 * @modified 2017-06-28
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
14
15
16
17 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18 // E X P O R T
19 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20
21 /** Define ICS Feeds names
22 *
23 * wpbm-ics - Example of Feed Name.
24 *
25 * Have to work correctly immediately: http://beta/?feed=wpbm-ics
26 * Nice looking link: http://beta/feed/wpbm-ics -- require to update permalink structure at WordPress > Settings > Permalink Settings page by clicking on "Save changes" button.
27 * Finally, to display your feed, you’ll first need to flush your WordPress rewrite rules.
28 * The easiest way to do this is by logging in to the WordPress admin, and clicking Settings -> Permalinks.
29 * Once here, just click Save Changes, which will flush the rewrite rules.
30 *
31 * Otherwsie need to run ONLY once this:
32 *
33 * global $wp_rewrite;
34 * $wp_rewrite->flush_rules();
35 *
36 */
37 function wpbm_make_export_ics_feeds(){
38
39 if ( function_exists( 'wp_parse_url' ) )
40 $my_parsed_url = wp_parse_url( $_SERVER[ 'REQUEST_URI' ] );
41 else
42 $my_parsed_url = @parse_url( $_SERVER[ 'REQUEST_URI' ] );
43
44 if ( false === $my_parsed_url ) { // seriously malformed URLs, parse_url() may return FALSE.
45 return;
46 }
47
48 $my_parsed_url_path = trim( $my_parsed_url[ 'path' ] );
49 $my_parsed_url_path = trim( $my_parsed_url_path, '/' );
50
51 //FixIn: 2.0.5.4
52 // check internal subfolder of WP, like http://server.com/my-website/ ... link ...
53 $server_url_sufix = '';
54 if ( function_exists( 'wp_parse_url' ) )
55 $wp_home_server_url = wp_parse_url( home_url() );
56 else
57 $wp_home_server_url = @parse_url( home_url() );
58
59 if ( ( false !== $wp_home_server_url ) && (! empty( $wp_home_server_url[ 'path' ] ) ) ){ // seriously malformed URLs, parse_url() may return FALSE.
60 $server_url_sufix = trim( $wp_home_server_url[ 'path' ] ); // [path] => /my-website
61 $server_url_sufix = trim( $server_url_sufix, '/' ); // my-website
62 if ( ! empty( $server_url_sufix ) ) {
63 $check_sufix = substr( $my_parsed_url_path, 0, strlen( $server_url_sufix ) );
64 if ( $check_sufix === $server_url_sufix ) {
65 $my_parsed_url_path = substr( $my_parsed_url_path, strlen( $server_url_sufix ) );
66 $my_parsed_url_path = trim( $my_parsed_url_path, '/' );
67 }
68 }
69 }
70 //End FixIn: 2.0.5.4
71
72
73
74 // Get booking resources and Export Feed URLS
75 $is_continue = false;
76 if ( function_exists( 'wpbc_br_cache' ) ) {
77
78 $resources_cache = wpbc_br_cache(); // Get booking resources from cache
79 $resource_list = $resources_cache->get_resources();
80
81 foreach ( $resource_list as $res_id => $res_arr) {
82
83 if ( ! empty( $res_arr[ 'export' ] ) ) {
84 $resource_feed_url = $res_arr[ 'export' ];
85 } else {
86 $resource_feed_url = '';
87 }
88
89 $resource_feed_url = trim( $resource_feed_url, '/' );
90 if ( ! empty( $resource_feed_url ) ) {
91 // 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/'
92 if ( $my_parsed_url_path === $resource_feed_url ) {
93 $is_continue = true;
94 break;
95 }
96 }
97 }
98 } else if ( function_exists( 'get_bk_option' ) ) {
99
100 //TODO: cehck for Free version.
101 $res_id = 1;
102 $resource_feed_url = get_bk_option( 'booking_resource_export_ics_url' );
103
104 $resource_feed_url = trim( $resource_feed_url, '/' );
105
106 if ( ! empty( $resource_feed_url ) ) {
107 if ( $my_parsed_url_path === $resource_feed_url ) {
108 $is_continue = true;
109 }
110 }
111
112 } else {
113 return; // No Booking Calendar active, so ust opening some other page
114 }
115
116
117 if ( true === $is_continue) {
118
119 $download_url_path = $resource_feed_url;
120
121 $ics_export = wpbm_export_ics_feed__wpbm_ics( array( 'wh_booking_type' => $res_id ) );
122
123 if ( headers_sent() ){
124 die( 'headers_sent_before_download' );
125 }
126
127 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
128 // Prepare system before downloading set time limits, server output options
129 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
130 $disabled = explode( ',', ini_get( 'disable_functions' ) );
131 $is_func_disabled = in_array( 'set_time_limit', $disabled );
132 if ( ! $is_func_disabled && ! ini_get( 'safe_mode' ) ) {
133 @set_time_limit( 0 );
134 }
135
136 if ( function_exists( 'get_magic_quotes_runtime' ) && get_magic_quotes_runtime() && version_compare( phpversion(), '5.4', '<' ) ) {
137 set_magic_quotes_runtime( 0 );
138 }
139
140 @session_write_close();
141 if ( function_exists( 'apache_setenv' ) ) {
142 @apache_setenv( 'no-gzip', 1 );
143 }
144 @ini_set( 'zlib.output_compression', 'Off' );
145
146 @ob_end_clean(); // In case, if somewhere opeded output buffer, may be required for working fpassthru with large files
147
148
149 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
150 // Set Headers before file download
151 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
152 $file = array();
153 $file['content_type'] = 'text/calendar';
154 $file['name'] = 'wpbm.ics';
155
156 if ( function_exists( 'mb_detect_encoding' ) ) //FixIn: 2.0.5.3
157 $text_encoding = mb_detect_encoding( $ics_export );
158 else
159 $text_encoding = ''; //Unknown
160
161 //debuge( mb_detect_encoding( $ics_export ) );die;
162
163 if ( ( is_array( $text_encoding ) )
164 && ( ! in_array( 'UTF-8', $text_encoding ) )
165 ){
166 $file['size'] = wpbm_get_bytes_from_str( $ics_export );
167 } else {
168 $file['size'] = 0; // UTF-8 encoding, so size alculated incorrectly, probabaly
169 }
170
171 nocache_headers();
172 header( "Robots: none" . "\n" );
173 @header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 200 OK' . "\n" );
174 header( "Content-Type: " . $file['content_type'] . "\n" );
175 header( "Content-Description: File Transfer" . "\n" );
176 header( "Content-Disposition: attachment; filename=\"" . $file['name'] . "\"" . "\n" );
177 header( "Content-Transfer-Encoding: binary" . "\n" );
178
179 if ( (int) $file['size'] > 0 )
180 header( "Content-Length: " . $file['size'] . "\n" );
181
182
183 echo $ics_export;
184
185 exit;
186 }
187 // Unknown error, or just opening some other page
188
189
190 }
191 add_action( 'template_redirect', 'wpbm_make_export_ics_feeds' );
192
193
194
195 /** Define export ICS here
196 * For testing: http://beta/?feed=wpbm-ics
197 */
198 function wpbm_export_ics_feed__wpbm_ics( $param = array( 'wh_booking_type' => '1', 'wh_trash' => '' ) ) { //FixIn: 2.0.2.3
199
200 if ( ! function_exists( 'wpbc_api_get_bookings_arr' ) )
201 return '';
202
203 // // Start date of getting bookings
204 // $real_date = strtotime( '-1 year' );
205 // $wh_booking_date = date_i18n( "Y-m-d", $real_date );
206 // $param['wh_booking_date'] = $wh_booking_date;
207 // End date of getting bookings
208 $real_date = strtotime( '+2 years' ); //FixIn: 2.0.7.1
209 $wh_booking_date2 = date_i18n( "Y-m-d", $real_date );
210 $param['wh_booking_date2' ] = $wh_booking_date2;
211
212 // Export only approved bookings //FixIn: 2.0.11.1 //FixIn: 8.5.2.3
213 $booking_is_ics_export_only_approved = get_bk_option( 'booking_is_ics_export_only_approved' );
214 if ( 'On' == $booking_is_ics_export_only_approved ) {
215 $param['wh_approved'] = '1';
216 } else {
217 $param['wh_approved'] = '';
218 }
219
220 $_REQUEST['view_mode']= 'vm_calendar'; //FixIn: 8.5.2.15 2.0.11.2
221 // Get array of bookings.
222 $bookings_arr = wpbc_api_get_bookings_arr( $param );
223
224
225 ob_start();
226
227 // create the ical object
228 $icalobj = new ZCiCal();
229
230
231 foreach ( $bookings_arr['bookings'] as $bk_id => $bk_arr ) {
232
233 // create the event within the ical object
234 $eventobj = new ZCiCalNode( 'VEVENT', $icalobj->curnode );
235
236 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
237 // SUMMARY [Title]
238 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
239
240 if ( function_exists( 'get_title_for_showing_in_day' ) ) { // Get title of booking pipiline in "Calendar Overview" page
241
242 if ( true ) { // admin
243 $what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_calendar_view_mode' );
244 } else { // front-end
245 $what_show_in_day_template = get_bk_option( 'booking_default_title_in_day_for_timeline_front_end' );
246 }
247 //$title = esc_textarea( get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ) );
248 $title = get_title_for_showing_in_day( $bk_id, $bookings_arr['bookings'], $what_show_in_day_template ); //FixIn: 2.0.1.6.1
249
250 } else {
251
252 $title = ( ( isset( $bk_arr->form_data['name'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['name'] ) : '' )
253 . ( ( isset( $bk_arr->form_data['firstname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['firstname'] ) : '' )
254 . ( ( isset( $bk_arr->form_data['secondname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['secondname'] ) : '' )
255 . ( ( isset( $bk_arr->form_data['lastname'] ) ) ? ' ' . esc_textarea( $bk_arr->form_data['lastname'] ) : '' );
256 }
257
258 $title = wpbm_esc_to_plain_text( $title ); //FixIn: 2.0.1.6.1
259
260 //$title = substr($title, 0, 5);
261 $eventobj->addNode( new ZCiCalDataNode( 'SUMMARY:' . trim( $title ) ) );
262
263 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
264 // DESCRIPTION
265 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
266 $description = $bk_arr->form_show;
267 // if ( ( ! empty($bk_arr->dates) ) && ( $bk_arr->dates[0]->approved ) ){
268 // $description .= '<br>Status: Approved';
269 // } else {
270 // $description .= '<br>Status: Pending';
271 // }
272
273 //$description = html_entity_decode( sanitize_text_field( $description ) );
274 //$description = trim( wp_specialchars_decode( esc_html( stripslashes( $description ) ), ENT_QUOTES ) );
275
276 $description = wpbm_esc_to_plain_text( $description );
277
278 //debuge($description . '!');die;
279 //$description = substr($description, 0, 1);
280 $description = preg_replace( array( "/\n/" ), array( '' ), $description );
281 //debuge( ZCiCal::formatContent( $description ) );die;
282 $eventobj->addNode( new ZCiCalDataNode( 'DESCRIPTION:' . ZCiCal::formatContent( $description ) ) );
283
284 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
285 // START & END DATES
286 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
287 $event_start = $bk_arr->dates_short[ 0 ];
288 if ( ( count($bk_arr->dates_short) > 1 ) && ( '-' === $bk_arr->dates_short[ 1 ] ) ) {
289
290 $event_end = $bk_arr->dates_short[ 2 ];
291
292 $event_end = wpbm_get_next_date_if_it_full_date( $event_end );
293
294 $period_start_index = 3;
295 } else { // comma
296 $event_end = $bk_arr->dates_short[ 0 ];
297
298 $event_end = wpbm_get_next_date_if_it_full_date( $event_end );
299
300 $period_start_index = 1;
301 }
302
303 // add start date
304 $eventobj->addNode( new ZCiCalDataNode( "DTSTART:" . ZCiCal::fromSqlDateTime( $event_start ) ) );
305
306 // add end date
307 $eventobj->addNode( new ZCiCalDataNode( "DTEND:" . ZCiCal::fromSqlDateTime( $event_end ) ) );
308
309 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
310 // RDATE - Rule for other different dates.
311 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
312 //
313 // RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
314 // 19960404T010000Z/PT3H
315 //
316 $rdate = array();
317 $previos_value = '';
318 foreach ( $bk_arr->dates_short as $short_ind => $bk_date ) {
319
320 if ( $short_ind < $period_start_index )
321 continue;
322
323 if ( ( $bk_date !== ',' ) && ( $bk_date !== '-' ) ) {
324
325 if ( $previos_value == '-' ) {
326 $bk_date = wpbm_get_next_date_if_it_full_date( $bk_date );
327 } else {
328 $bk_date = wpbm_get_only_date_if_it_full_date( $bk_date );
329 }
330
331 $rdate[]= ZCiCal::fromSqlDateTime( $bk_date );
332
333 } else if ( ( $bk_date === '-' ) && ( count($rdate) > 0 ) ) {
334
335 $rdate[] = '/'; // PERIOD
336
337 } else if ( ( $bk_date === ',' ) && ( count($rdate) > 0 ) ) {
338
339 $rdate[] = ','; // Other date
340
341 }
342 $previos_value = $bk_date;
343 }
344 if ( ! empty( $rdate ) ) {
345 $rdate = implode( '', $rdate );
346 // add RDATE
347 $eventobj->addNode( new ZCiCalDataNode( "RDATE;VALUE=PERIOD:" . $rdate ) );
348
349 }
350
351 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
352 // Timezone
353 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
354 /* Timezone must be a supported PHP timezone (see http://php.net/manual/en/timezones.php )
355 * Note: multi-word timezones must use underscore "_" separator
356 * Example: $tzid = "America/New_York";
357 */
358
359 $tzid = get_bk_option( 'booking_gcal_timezone' );
360
361 if ( ! empty( $tzid ) ) {
362 // Add timezone data
363 ZCTimeZoneHelper::getTZNode( substr( $event_start, 0, 4 ), substr( $event_end, 0, 4 ), $tzid, $icalobj->curnode ); //FixIn: 2.0.3.3
364 }
365
366 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
367 // UID
368 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
369 $uid = $event_start . '_' . $bk_id . "@demo.icalendar.org";
370 $eventobj->addNode( new ZCiCalDataNode( "UID:" . $uid ) );
371
372 // DTSTAMP is a required item in VEVENT
373 $eventobj->addNode( new ZCiCalDataNode( "DTSTAMP:" . ZCiCal::fromSqlDateTime() ) );
374
375 $eventobj->addNode( new ZCiCalDataNode( "CREATED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
376 $eventobj->addNode( new ZCiCalDataNode( "LAST-MODIFIED:" . ZCiCal::fromSqlDateTime( $bk_arr->modification_date ) ) );
377
378
379 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
380 // STATUS:CONFIRMED ( "TENTATIVE" / "CONFIRMED" / "CANCELLED" ) // This property defines the overall status for EVENT
381 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
382
383 $ics_status = 'TENTATIVE';
384 if ( ! ( empty( $bk_arr->trash ) ) ) {
385 $ics_status = 'CANCELLED';
386 } elseif ( ! ( empty( $bk_arr->dates[0]->approved ) ) ) {
387 $ics_status = 'CONFIRMED';
388 }
389 // $eventobj->addNode( new ZCiCalDataNode( "STATUS:" . $ics_status ) ); //FixIn: 2.0.11.3
390
391
392 // RRULE:FREQ=WEEKLY;COUNT=3;BYDAY=WE,SA
393 // LOCATION:South Australia\, Australia
394 // SEQUENCE:1 // defines the revision sequence number of the calendar component within a sequence of revisions
395 // TRANSP:OPAQUE // This property defines whether or not an event is transparent to busy time searches ;Default value is OPAQUE
396 // OPAQUE - Blocks or opaque on busy time searches.
397 // TRANSPARENT - Transparent on busy time searches.
398
399 }
400
401 echo $icalobj->export(); // write iCalendar feed to stdout
402
403 $ics_export = ob_get_contents();
404
405 ob_end_clean();
406
407 return $ics_export;
408 }
409
410
411 /** Get Next day in MySQL format without time, if current day its Full day - ending with 00:00:00
412 *
413 * @param string $mysql_date - 2017-07-12 00:00:00
414 * @return string - 2017-07-13
415 */
416 function wpbm_get_next_date_if_it_full_date( $mysql_date ) {
417
418 // Check if this date ending with 00:00:00 its means that it full day,
419 // 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
420 if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
421 && ( substr( $mysql_date, 11 ) == '00:00:00' )
422 ) {
423
424 $mysql_date = date_i18n( "Y-m-d 00:00:00", strtotime( $mysql_date ) );
425 $mysql_date = strtotime( $mysql_date );
426 $mysql_date = date_i18n( "Y-m-d", strtotime( '+1 day', $mysql_date ) );
427 }
428
429 return $mysql_date;
430 }
431
432
433 /** Get day in MySQL format without time, if current day its Full day - ending with 00:00:00
434 *
435 * @param string $mysql_date - 2017-07-12 00:00:00
436 * @return string - 2017-07-12
437 */
438 function wpbm_get_only_date_if_it_full_date( $mysql_date ) {
439
440 if ( ( strlen( $mysql_date ) > 10 ) // , like 2017-07-12 00:00:00
441 && ( substr( $mysql_date, 11) == '00:00:00' )
442 ) {
443 $mysql_date = substr( $mysql_date, 0, 10 );
444 }
445
446 return $mysql_date;
447 }