PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 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 All 34 releases
← All changes | app/Services/BookingFieldService.php +31 -13 2.4.0 → 2.5.0 View file →
@@ -3,14 +3,18 @@
3 3 namespace FluentBooking\App\Services;
4 4
5 5 use FluentBooking\App\Models\Booking;
6 6 use FluentBooking\App\Models\CalendarSlot;
7 +use FluentBooking\App\Services\Libs\FileSystem;
7 8 use FluentBooking\App\Services\SanitizeService;
8 9 use FluentBooking\Framework\Support\Arr;
9 10
10 11 class BookingFieldService
11 12 {
12 - public static function getCustomFieldsData($postedData, CalendarSlot $slot)
13 + /**
14 + * @param array|null $mappedKeys Fluent Forms mapped fields: read and sanitized only, the form owns validation.
15 + */
16 + public static function getCustomFieldsData($postedData, CalendarSlot $slot, $mappedKeys = null)
13 17 {
14 18 $customFields = self::getCustomFields($slot, true);
15 19
16 20 $errors = [];
@@ -17,10 +21,25 @@
17 21
18 22 $formattedValues = [];
19 23
20 24 foreach ($customFields as $fieldKey => $customField) {
25 + $isMapped = $mappedKeys !== null;
26 +
27 + if ($isMapped && !in_array($fieldKey, $mappedKeys, true)) {
28 + continue;
29 + }
30 +
21 31 $value = wp_unslash(Arr::get($postedData, $fieldKey));
22 - if (Arr::isTrue($customField, 'required')) {
32 +
33 + if ($customField['type'] === 'file' && $value) {
34 + // A posted external URL would render as a trusted download link, and
35 + // pro deletes stored basenames from the upload folder with the booking.
36 + // Slice first so a crafted array can't force a check per entry.
37 + $value = array_slice((array) $value, 0, (int) Arr::get($customField, 'max_file_allow', 1));
38 + $value = array_values(array_filter($value, [FileSystem::class, 'isUploadedFileUrl']));
39 + }
40 +
41 + if (!$isMapped && Arr::isTrue($customField, 'required')) {
23 42 $isTerms = $customField['type'] === 'terms-and-conditions';
24 43 $isCheckbox = $customField['type'] === 'checkbox';
25 44 if (!$value || ($isCheckbox && $value !== 'Yes') || ($isTerms && $value !== 'Accepted')) {
26 45 /* translators: %s: Field label */
@@ -34,12 +53,8 @@
34 53 $value = array_map(function ($item) {
35 54 $val = is_array($item) ? Arr::get($item, 'value') : $item;
36 55 return sanitize_text_field($val);
37 56 },$value);
38 - } else if ($customField['type'] === 'file') {
39 - $maxField = Arr::get($customField, 'max_file_allow', 1);
40 - $value = array_slice($value, 0, $maxField);
41 - $value = array_map('sanitize_text_field', $value);
42 57 } else {
43 58 $value = array_map('sanitize_text_field', $value);
44 59 }
45 60 } else if ($customField['type'] == 'textarea') {
@@ -47,9 +62,9 @@
47 62 } else {
48 63 $value = sanitize_text_field($value);
49 64 }
50 65
51 - if ($customField['type'] === 'phone' && $value && !Helper::isValidPhoneNumber($value)) {
66 + if (!$isMapped && $customField['type'] === 'phone' && $value && !Helper::isValidPhoneNumber($value)) {
52 67 /* translators: %s: Field label */
53 68 $errors[$fieldKey . '.valid_phone_number'] = sprintf(__('%s is not a valid phone number', 'fluent-booking'), $customField['label']);
54 69 continue;
55 70 }
@@ -65,12 +80,12 @@
65 80 }
66 81
67 82 public static function getBookingFields(CalendarSlot $calendarSlot, $cached = false)
68 83 {
69 - static $bookingFields = null;
84 + static $bookingFields = [];
70 85
71 - if ($cached && $bookingFields) {
72 - return $bookingFields;
86 + if ($cached && isset($bookingFields[$calendarSlot->id])) {
87 + return $bookingFields[$calendarSlot->id];
73 88 }
74 89
75 90 $requiredIndexes = ['name', 'email', 'message', 'cancellation_reason', 'rescheduling_reason'];
76 91
@@ -242,11 +257,9 @@
242 257 }
243 258
244 259 $existingFields['email']['disabled'] = false;
245 260
246 - $bookingFields = apply_filters('fluent_booking/booking_fields', array_values($existingFields), $calendarSlot);
247 -
248 - return $bookingFields;
261 + return $bookingFields[$calendarSlot->id] = apply_filters('fluent_booking/booking_fields', array_values($existingFields), $calendarSlot);
249 262 }
250 263
251 264 public static function getBookingFieldLabels(CalendarSlot $calendarSlot, $enabledOnly = false)
252 265 {
@@ -322,8 +335,13 @@
322 335
323 336 if ($fieldType == 'hidden') {
324 337 if ($isPublic) continue;
325 338 $formattedValue = EditorShortcodeParser::parse($formattedValue, $booking);
339 +
340 + // Some shortcodes return HTML, and the admin renders hidden values as HTML.
341 + if ($htmlSupport) {
342 + $formattedValue = wp_kses_post($formattedValue);
343 + }
326 344 }
327 345
328 346 $formattedData[$dataKey] = [
329 347 'label' => $label,