PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / trunk
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution vtrunk
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
← All changes | app/Services/EditorShortCodeParser.php +125 -30 1.5.10trunk View file →
@@ -28,9 +28,9 @@
28 28 static::setData($booking);
29 29 return static::parseShortCodes($parsable);
30 30 } catch (\Exception $e) {
31 31 if (defined('WP_DEBUG') && WP_DEBUG) {
32 - error_log($e->getTraceAsString());
32 + error_log($e->getTraceAsString()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
33 33 }
34 34 return '';
35 35 }
36 36 }
@@ -88,30 +88,50 @@
88 88 if ($key == 'full_start_and_end_host_timezone') {
89 89 return $booking->getFullBookingDateTimeText($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
90 90 }
91 91
92 + if ($key == 'all_bookings_short_times_guest_timezone') {
93 + return implode("<br>", $booking->getAllBookingShortTimes($booking->person_time_zone, true));
94 + }
95 +
96 + if ($key == 'all_bookings_short_times_host_timezone') {
97 + return implode("<br>", $booking->getAllBookingShortTimes($booking->getHostTimezone(), true));
98 + }
99 +
100 + if ($key == 'all_bookings_full_times_guest_timezone') {
101 + return implode("<br>", $booking->getAllBookingFullTimes($booking->person_time_zone, true));
102 + }
103 +
104 + if ($key == 'all_bookings_full_times_host_timezone') {
105 + return implode("<br>", $booking->getAllBookingFullTimes($booking->getHostTimezone(), true));
106 + }
107 +
92 108 if ($key == 'start_date_time') {
93 109 return $booking->start_time;
94 110 }
95 111
96 - if ($key == 'start_date_time_for_attendee') {
97 - return DateTimeHelper::convertFromUtc($booking->start_time, $booking->person_time_zone, 'Y-m-d H:i:s');
112 + if (strpos($key, 'start_date_time_for_attendee') === 0) {
113 + $format = preg_match('/format\.([a-zA-Z\-: ]+)/', $key, $matches) ? $matches[1] : 'Y-m-d H:i:s';
114 + $dateTime = DateTimeHelper::convertFromUtc($booking->start_time, $booking->person_time_zone, 'Y-m-d H:i:s');
115 + return date_i18n($format, strtotime($dateTime));
98 116 }
99 117
100 - if ($key == 'start_date_time_for_host') {
101 - return DateTimeHelper::convertFromUtc($booking->start_time, $booking->getHostTimezone(), 'Y-m-d H:i:s');
118 + if (strpos($key, 'start_date_time_for_host') === 0) {
119 + $format = preg_match('/format\.([a-zA-Z\-: ]+)/', $key, $matches) ? $matches[1] : 'Y-m-d H:i:s';
120 + $dateTime = DateTimeHelper::convertFromUtc($booking->start_time, $booking->getHostTimezone(), 'Y-m-d H:i:s');
121 + return date_i18n($format, strtotime($dateTime));
102 122 }
103 123
104 124 if ($key == 'cancel_reason') {
105 - return $booking->getCancelReason(true);
125 + return $booking->getCancelReason(false, true);
106 126 }
107 127
108 128 if ($key == 'reject_reason') {
109 - return $booking->getRejectReason(true);
129 + return $booking->getRejectReason(false, true);
110 130 }
111 131
112 132 if ($key == 'reschedule_reason') {
113 - return $booking->getRescheduleReason();
133 + return $booking->getRescheduleReason(true);
114 134 }
115 135
116 136 if ($key == 'previous_meeting_time') {
117 137 return $booking->getPreviousMeetingTime($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
@@ -116,8 +136,20 @@
116 136 if ($key == 'previous_meeting_time') {
117 137 return $booking->getPreviousMeetingTime($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
118 138 }
119 139
140 + if ($key == 'previous_meeting_time_guest_timezone') {
141 + return $booking->getPreviousMeetingTime($booking->person_time_zone) . ' (' . $booking->person_time_zone . ')';
142 + }
143 +
144 + if ($key == 'previous_meeting_date_time_host_timezone') {
145 + return $booking->getPreviousMeetingDateTimeText($booking->getHostTimezone()) . ' (' . $booking->getHostTimezone() . ')';
146 + }
147 +
148 + if ($key == 'previous_meeting_date_time_guest_timezone') {
149 + return $booking->getPreviousMeetingDateTimeText($booking->person_time_zone) . ' (' . $booking->person_time_zone . ')';
150 + }
151 +
120 152 if ($key == 'start_time_human_format') {
121 153 if (time() > strtotime($booking->start_time)) {
122 154 $suffix = __(' ago', 'fluent-booking');
123 155 } else {
@@ -182,13 +214,39 @@
182 214 self::$store['custom_booking_data'] = $booking->getMeta('custom_fields_data', []);
183 215 }
184 216
185 217 if (self::$store['custom_booking_data']) {
186 - if (preg_match('/format\.([a-zA-Z\-]+)/', $key, $matches)) {
187 - $value = Arr::get(self::$store['custom_booking_data'], preg_split('/\.format\./', $key)[0]);
188 - return gmdate($matches[1], strtotime($value)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
218 + if (preg_match('/format\.([a-zA-Z\-: ]+)/', $key, $matches)) {
219 + $fieldKey = preg_split('/\.format\./', $key)[0];
220 + $value = Arr::get(self::$store['custom_booking_data'], $fieldKey);
221 + $customField = BookingFieldService::getBookingFieldByName($booking->calendar_event, $fieldKey);
222 + $formattedDate = DateTimeHelper::getFormattedDate($value, Arr::get($customField, 'date_format'));
223 + return $formattedDate ? date_i18n($matches[1], strtotime($formattedDate)) : '';
189 224 }
190 225
226 + $customField = BookingFieldService::getBookingFieldByName($booking->calendar_event, $key);
227 +
228 + if (Arr::get($customField, 'type') == 'file') {
229 + return self::getUploadedFileUrl(Arr::get(self::$store['custom_booking_data'], $key));
230 + }
231 +
232 + if (Arr::get($customField, 'type') == 'hidden') {
233 + static $resolving = [];
234 +
235 + // Guest-supplied hidden values are parsed again, so a self-reference would recurse until the stack runs out.
236 + if (isset($resolving[$key])) {
237 + return Arr::get(self::$store['custom_booking_data'], $key);
238 + }
239 +
240 + $resolving[$key] = true;
241 +
242 + try {
243 + return self::parseShortCodes(Arr::get(self::$store['custom_booking_data'], $key));
244 + } finally {
245 + unset($resolving[$key]);
246 + }
247 + }
248 +
191 249 return Arr::get(self::$store['custom_booking_data'], $key);
192 250 }
193 251
194 252 return '';
@@ -203,9 +261,9 @@
203 261 }
204 262
205 263 if ($key == 'timezone') {
206 264 $booking = static::$store['booking'];
207 - return $booking->getHostTimezone();
265 + return $booking ? $booking->getHostTimezone() : null;
208 266 }
209 267
210 268 return Arr::get($host, $key, '');
211 269 }
@@ -233,20 +291,23 @@
233 291 if ('full_name' == $key) {
234 292 return $guest['first_name'] . ' ' . $guest['last_name'];
235 293 }
236 294 if ('timezone' == $key) {
237 - $booking = static::$store['booking'];
238 - return $booking->person_time_zone;
295 + return $guest->person_time_zone;
239 296 }
240 297 if ('note' == $key) {
241 298 return $guest->getMessage();
242 299 }
243 300
301 + if ($key == 'total_guest') {
302 + return $guest->getTotalGuestCount();
303 + }
304 +
244 305 if ($key == 'form_data_html') {
245 306 return __('will be available soon', 'fluent-booking');
246 307 }
247 308
248 - return Arr::get($guest, $key, '');
309 + return self::resolveScalarAttribute($guest, $key);
249 310 }
250 311
251 312 protected static function getBookingEventData($key)
252 313 {
@@ -261,9 +322,9 @@
261 322 if (in_array($key, $fillables)) {
262 323 return $bookingEvent->{$key};
263 324 }
264 325
265 - return '';
326 + return self::resolveScalarAttribute($bookingEvent, $key);
266 327 }
267 328
268 329 protected static function getCalendarData($key)
269 330 {
@@ -278,11 +339,26 @@
278 339 if (in_array($key, $fillables)) {
279 340 return $calendar->{$key};
280 341 }
281 342
282 - return '';
343 + return self::resolveScalarAttribute($calendar, $key);
283 344 }
284 345
346 + /**
347 + * Resolve a scalar attribute only; never a relation (dumps as JSON) or a
348 + * dotted hop into a relation's columns.
349 + */
350 + protected static function resolveScalarAttribute($model, $key)
351 + {
352 + if (strpos($key, '.') !== false) {
353 + return '';
354 + }
355 +
356 + $value = isset($model[$key]) ? $model[$key] : '';
357 +
358 + return is_scalar($value) ? $value : '';
359 + }
360 +
285 361 protected static function getPaymentData($key)
286 362 {
287 363 $booking = static::$store['booking'];
288 364
@@ -303,9 +379,9 @@
303 379 }
304 380
305 381 $order = static::$store['payment_order'];
306 382
307 - if ($key == 'payment_total') {
383 + if ($key == 'payment_total' && $order) {
308 384 $isZeroDecimal = CurrenciesHelper::isZeroDecimal($order->currency);
309 385 if ($isZeroDecimal) {
310 386 return $order->total_amount;
311 387 } else {
@@ -317,23 +393,23 @@
317 393 return apply_filters('fluent_booking/payment_receipt_html', '', $booking->hash);
318 394 }
319 395
320 396 if ($key == 'payment_status') {
321 - return $order->status;
397 + return $order ? $order->status : '';
322 398 }
323 399
324 400 if ($key == 'payment_currency') {
325 - return $order->currency;
401 + return $order ? $order->currency : '';
326 402 }
327 403
328 404 if ($key == 'payment_date') {
329 - return $order->created_at;
405 + return $order ? $order->created_at : '';
330 406 }
331 407
332 408 $fillables = (new \FluentBookingPro\App\Models\Order())->getFillable();
333 409
334 410 if (in_array($key, $fillables)) {
335 - return $order->{$key};
411 + return $order ? $order->{$key} : '';
336 412 }
337 413
338 414 return '';
339 415 }
@@ -339,12 +415,13 @@
339 415 }
340 416
341 417 protected static function getUserData($key)
342 418 {
343 - if (is_null(static::$store['user'])) {
344 - static::$store['user'] = wp_get_current_user();
419 + $user = static::$store['user'];
420 + if (is_null($user)) {
421 + $user = wp_get_current_user();
345 422 }
346 - return static::$store['user']->{$key};
423 + return $user ? $user->{$key} : '';
347 424 }
348 425
349 426 protected static function getWPData($key)
350 427 {
@@ -361,9 +438,14 @@
361 438 }
362 439
363 440 protected static function getOtherData($key)
364 441 {
365 - self::$store['meeting_bookmarks'] ??= static::$store['booking']->getMeetingBookmarks();
442 + $meetingBookmarks = self::$store['meeting_bookmarks'];
443 + if (!$meetingBookmarks) {
444 + $booking = static::$store['booking'];
445 + $meetingBookmarks = $booking ? $booking->getMeetingBookmarks() : null;
446 + self::$store['meeting_bookmarks'] = $meetingBookmarks;
447 + }
366 448
367 449 if (0 === strpos($key, 'date.')) {
368 450 $format = str_replace('date.', '', $key);
369 451 return gmdate($format, strtotime(current_time('mysql'))); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
@@ -369,18 +451,31 @@
369 451 return gmdate($format, strtotime(current_time('mysql'))); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
370 452 } elseif ('add_booking_to_calendar' === $key) {
371 453 return static::parseShortCodes(Helper::getAddToCalendarHtml());
372 454 } elseif ('add_to_g_calendar_url' === $key) {
373 - return Arr::get(self::$store['meeting_bookmarks'], 'google.url');
455 + return Arr::get($meetingBookmarks, 'google.url');
374 456 } elseif ('add_to_ol_calendar_url' === $key) {
375 - return Arr::get(self::$store['meeting_bookmarks'], 'outlook.url');
457 + return Arr::get($meetingBookmarks, 'outlook.url');
376 458 } elseif ('add_to_ms_calendar_url' === $key) {
377 - return Arr::get(self::$store['meeting_bookmarks'], 'msoffice.url');
459 + return Arr::get($meetingBookmarks, 'msoffice.url');
378 460 } elseif ('add_to_ics_calendar_url' === $key) {
379 - return Arr::get(self::$store['meeting_bookmarks'], 'other.url');
461 + return Arr::get($meetingBookmarks, 'other.url');
380 462 }
381 463
382 464 return $key;
465 + }
466 +
467 + protected static function getUploadedFileUrl($fieldValue)
468 + {
469 + if (empty($fieldValue)) {
470 + return '';
471 + }
472 +
473 + $files = array_map(function($file) {
474 + return '<a href="' . esc_url($file) . '" style="color:#222;font-size:15px;" target="_blank" download="' . esc_attr(basename($file)) . '">' . esc_html(basename($file)) . '</a>';
475 + }, $fieldValue);
476 +
477 + return '<ul><li>' . implode('</li><li>', $files) . '</li></ul>';
383 478 }
384 479
385 480 protected static function parseShortCodes($parsable)
386 481 {