PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.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 1.7.2 All 33 releases
fluent-booking / app / Services / Helper.php

Helper.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.5.0, at app/Services/Helper.php

2,098 lines 73.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Services;
4
5 use FluentBooking\App\App;
6 use FluentBooking\App\Models\Booking;
7 use FluentBooking\App\Models\Calendar;
8 use FluentBooking\App\Models\CalendarSlot;
9 use FluentBooking\App\Models\Meta;
10 use FluentBooking\App\Models\BookingMeta;
11 use FluentBooking\Framework\Support\Arr;
12
13 class Helper
14 {
15 public static $reserved = [
16 '0',
17 'about',
18 'access',
19 'account',
20 'accounts',
21 'activate',
22 'activities',
23 'activity',
24 'ad',
25 'add',
26 'address',
27 'adm',
28 'admin',
29 'administration',
30 'administrator',
31 'ads',
32 'adult',
33 'advertising',
34 'affiliate',
35 'affiliates',
36 'ajax',
37 'all',
38 'alpha',
39 'analysis',
40 'analytics',
41 'android',
42 'anon',
43 'anonymous',
44 'api',
45 'app',
46 'apps',
47 'archive',
48 'archives',
49 'article',
50 'asct',
51 'asset',
52 'atom',
53 'auth',
54 'authentication',
55 'avatar',
56 'backup',
57 'balancer-manager',
58 'banner',
59 'banners',
60 'beta',
61 'billing',
62 'bin',
63 'blog',
64 'blogs',
65 'board',
66 'book',
67 'bookmark',
68 'bot',
69 'bots',
70 'bug',
71 'business',
72 'cache',
73 'cadastro',
74 'calendar',
75 'call',
76 'campaign',
77 'cancel',
78 'captcha',
79 'career',
80 'careers',
81 'cart',
82 'categories',
83 'category',
84 'cgi',
85 'cgi-bin',
86 'changelog',
87 'chat',
88 'check',
89 'checking',
90 'checkout',
91 'client',
92 'cliente',
93 'clients',
94 'code',
95 'codereview',
96 'comercial',
97 'comment',
98 'comments',
99 'communities',
100 'community',
101 'company',
102 'compare',
103 'compras',
104 'config',
105 'configuration',
106 'connect',
107 'contact',
108 'contact-us',
109 'contact_us',
110 'contactus',
111 'contest',
112 'contribute',
113 'corp',
114 'create',
115 'css',
116 'dashboard',
117 'data',
118 'db',
119 'default',
120 'delete',
121 'demo',
122 'design',
123 'designer',
124 'destroy',
125 'dev',
126 'devel',
127 'developer',
128 'developers',
129 'diagram',
130 'diary',
131 'dict',
132 'dictionary',
133 'die',
134 'dir',
135 'direct_messages',
136 'directory',
137 'dist',
138 'doc',
139 'docs',
140 'documentation',
141 'domain',
142 'download',
143 'downloads',
144 'ecommerce',
145 'edit',
146 'editor',
147 'edu',
148 'education',
149 'email',
150 'employment',
151 'empty',
152 'end',
153 'enterprise',
154 'entries',
155 'entry',
156 'error',
157 'errors',
158 'eval',
159 'event',
160 'exit',
161 'explore',
162 'facebook',
163 'faq',
164 'favorite',
165 'favorites',
166 'feature',
167 'features',
168 'feed',
169 'feedback',
170 'feeds',
171 'file',
172 'files',
173 'first',
174 'flash',
175 'fleet',
176 'fleets',
177 'flog',
178 'follow',
179 'followers',
180 'following',
181 'forgot',
182 'form',
183 'forum',
184 'forums',
185 'founder',
186 'free',
187 'friend',
188 'friends',
189 'ftp',
190 'gadget',
191 'gadgets',
192 'game',
193 'games',
194 'get',
195 'ghost',
196 'gift',
197 'gifts',
198 'gist',
199 'github',
200 'graph',
201 'group',
202 'groups',
203 'guest',
204 'guests',
205 'help',
206 'home',
207 'homepage',
208 'host',
209 'hosting',
210 'hostmaster',
211 'hostname',
212 'howto',
213 'hpg',
214 'html',
215 'http',
216 'httpd',
217 'https',
218 'i',
219 'iamges',
220 'icon',
221 'icons',
222 'id',
223 'idea',
224 'ideas',
225 'image',
226 'images',
227 'imap',
228 'img',
229 'index',
230 'indice',
231 'info',
232 'information',
233 'inquiry',
234 'instagram',
235 'intranet',
236 'invitations',
237 'invite',
238 'ipad',
239 'iphone',
240 'irc',
241 'is',
242 'issue',
243 'issues',
244 'it',
245 'item',
246 'items',
247 'java',
248 'javascript',
249 'job',
250 'jobs',
251 'join',
252 'js',
253 'json',
254 'jump',
255 'knowledgebase',
256 'language',
257 'languages',
258 'last',
259 'ldap-status',
260 'legal',
261 'license',
262 'link',
263 'links',
264 'linux',
265 'list',
266 'lists',
267 'log',
268 'log-in',
269 'log-out',
270 'log_in',
271 'log_out',
272 'login',
273 'logout',
274 'logs',
275 'm',
276 'mac',
277 'mail',
278 'mail1',
279 'mail2',
280 'mail3',
281 'mail4',
282 'mail5',
283 'mailer',
284 'mailing',
285 'maintenance',
286 'manager',
287 'manual',
288 'map',
289 'maps',
290 'marketing',
291 'master',
292 'me',
293 'media',
294 'member',
295 'members',
296 'message',
297 'messages',
298 'messenger',
299 'microblog',
300 'microblogs',
301 'mine',
302 'mis',
303 'mob',
304 'mobile',
305 'movie',
306 'movies',
307 'mp3',
308 'msg',
309 'msn',
310 'music',
311 'musicas',
312 'mx',
313 'my',
314 'mysql',
315 'name',
316 'named',
317 'nan',
318 'navi',
319 'navigation',
320 'net',
321 'network',
322 'new',
323 'news',
324 'newsletter',
325 'nick',
326 'nickname',
327 'notes',
328 'noticias',
329 'notification',
330 'notifications',
331 'notify',
332 'ns',
333 'ns1',
334 'ns10',
335 'ns2',
336 'ns3',
337 'ns4',
338 'ns5',
339 'ns6',
340 'ns7',
341 'ns8',
342 'ns9',
343 'null',
344 'oauth',
345 'oauth_clients',
346 'offer',
347 'offers',
348 'official',
349 'old',
350 'online',
351 'openid',
352 'operator',
353 'order',
354 'orders',
355 'organization',
356 'organizations',
357 'overview',
358 'owner',
359 'owners',
360 'page',
361 'pager',
362 'pages',
363 'panel',
364 'password',
365 'payment',
366 'perl',
367 'phone',
368 'photo',
369 'photoalbum',
370 'photos',
371 'php',
372 'phpmyadmin',
373 'phppgadmin',
374 'phpredisadmin',
375 'pic',
376 'pics',
377 'ping',
378 'plan',
379 'plans',
380 'plugin',
381 'plugins',
382 'policy',
383 'pop',
384 'pop3',
385 'popular',
386 'portal',
387 'post',
388 'postfix',
389 'postmaster',
390 'posts',
391 'pr',
392 'premium',
393 'press',
394 'price',
395 'pricing',
396 'privacy',
397 'privacy-policy',
398 'privacy_policy',
399 'privacypolicy',
400 'private',
401 'product',
402 'products',
403 'profile',
404 'project',
405 'projects',
406 'promo',
407 'pub',
408 'public',
409 'purpose',
410 'put',
411 'python',
412 'query',
413 'random',
414 'ranking',
415 'read',
416 'readme',
417 'recent',
418 'recruit',
419 'recruitment',
420 'register',
421 'registration',
422 'release',
423 'remove',
424 'replies',
425 'report',
426 'reports',
427 'repositories',
428 'repository',
429 'req',
430 'request',
431 'requests',
432 'reset',
433 'roc',
434 'rss',
435 'ruby',
436 'rule',
437 'sag',
438 'sale',
439 'sales',
440 'sample',
441 'samples',
442 'save',
443 'school',
444 'script',
445 'scripts',
446 'search',
447 'secure',
448 'security',
449 'self',
450 'send',
451 'server',
452 'server-info',
453 'server-status',
454 'service',
455 'services',
456 'session',
457 'sessions',
458 'setting',
459 'settings',
460 'setup',
461 'share',
462 'shop',
463 'show',
464 'sign-in',
465 'sign-up',
466 'sign_in',
467 'sign_up',
468 'signin',
469 'signout',
470 'signup',
471 'site',
472 'sitemap',
473 'sites',
474 'smartphone',
475 'smtp',
476 'soporte',
477 'source',
478 'spec',
479 'special',
480 'sql',
481 'src',
482 'ssh',
483 'ssl',
484 'ssladmin',
485 'ssladministrator',
486 'sslwebmaster',
487 'staff',
488 'stage',
489 'staging',
490 'start',
491 'stat',
492 'state',
493 'static',
494 'stats',
495 'status',
496 'store',
497 'stores',
498 'stories',
499 'style',
500 'styleguide',
501 'stylesheet',
502 'stylesheets',
503 'subdomain',
504 'subscribe',
505 'subscriptions',
506 'suporte',
507 'support',
508 'svn',
509 'swf',
510 'sys',
511 'sysadmin',
512 'sysadministrator',
513 'system',
514 'tablet',
515 'tablets',
516 'tag',
517 'talk',
518 'task',
519 'tasks',
520 'team',
521 'teams',
522 'tech',
523 'telnet',
524 'term',
525 'terms',
526 'terms-of-service',
527 'terms_of_service',
528 'termsofservice',
529 'test',
530 'test1',
531 'test2',
532 'test3',
533 'teste',
534 'testing',
535 'tests',
536 'theme',
537 'themes',
538 'thread',
539 'threads',
540 'tmp',
541 'todo',
542 'tool',
543 'tools',
544 'top',
545 'topic',
546 'topics',
547 'tos',
548 'tour',
549 'translations',
550 'trends',
551 'tutorial',
552 'tux',
553 'tv',
554 'twitter',
555 'undef',
556 'unfollow',
557 'unsubscribe',
558 'update',
559 'upload',
560 'uploads',
561 'url',
562 'usage',
563 'user',
564 'username',
565 'users',
566 'usuario',
567 'vendas',
568 'ver',
569 'version',
570 'video',
571 'videos',
572 'visitor',
573 'watch',
574 'weather',
575 'web',
576 'webhook',
577 'webhooks',
578 'webmail',
579 'webmaster',
580 'website',
581 'websites',
582 'welcome',
583 'widget',
584 'widgets',
585 'wiki',
586 'win',
587 'windows',
588 'word',
589 'work',
590 'works',
591 'workshop',
592 'ww',
593 'wws',
594 'www',
595 'www1',
596 'www2',
597 'www3',
598 'www4',
599 'www5',
600 'www6',
601 'www7',
602 'wwws',
603 'wwww',
604 'xfn',
605 'xml',
606 'xmpp',
607 'xpg',
608 'xxx',
609 'yaml',
610 'year',
611 'yml',
612 'you',
613 'yourdomain',
614 'yourname',
615 'yoursite',
616 'yourusername'
617 ];
618
619 public static function isCalendarSlugAvailable($slug, $checkDb = true, $exceptId = false)
620 {
621 if (in_array($slug, self::$reserved)) {
622 return false;
623 }
624
625 if (strlen($slug) < 4) {
626 return false;
627 }
628
629 if ($checkDb) {
630
631 if ($exceptId) {
632 $exist = Calendar::where('slug', $slug)->where('id', '!=', $exceptId)->first();
633 } else {
634 $exist = Calendar::where('slug', $slug)->first();
635 }
636
637 if ($exist) {
638 return false;
639 }
640 }
641
642
643 if (is_numeric($slug)) {
644 return false;
645 }
646
647 // check if $slug has any special characters or any space. We will only allow alpha-numeric values
648 return preg_match('/^[a-zA-Z0-9_-]+$/', $slug);
649 }
650
651 public static function isEventSlugAvailable($slug, $checkDb = true, $calendarId = null, $exceptId = null)
652 {
653 if (in_array($slug, self::$reserved)) {
654 return false;
655 }
656
657 if (strlen($slug) < 4) {
658 return false;
659 }
660
661 if ($checkDb) {
662 $eventQuery = CalendarSlot::where('slug', $slug);
663
664 if ($exceptId) {
665 $eventQuery->where('id', '!=', $exceptId);
666 }
667
668 if ($calendarId) {
669 $eventQuery->where('calendar_id', $calendarId);
670 }
671
672 $exist = $eventQuery->first();
673
674 if ($exist) {
675 return false;
676 }
677 }
678
679 if (is_numeric($slug)) {
680 return false;
681 }
682
683 // check if $slug has any special characters or any space. We will only allow alpha-numeric values
684 return preg_match('/^[a-zA-Z0-9_-]+$/', $slug);
685 }
686
687 public static function getAppBaseUrl($extension = '')
688 {
689 return apply_filters('fluent_booking/admin_base_url', admin_url('admin.php?page=fluent-booking#/' . $extension), $extension);
690 }
691
692 public static function getAdminBookingUrl($bookingId)
693 {
694 return self::getAppBaseUrl('scheduled-events?booking_id=' . $bookingId);
695 }
696
697 public static function getUpgradeUrl()
698 {
699 return 'https://fluentbooking.com/pricing/?utm_source=plugin&utm_medium=wp_install&utm_campaign=fcal_upgrade';
700 }
701
702 public static function getNextBookingGroup()
703 {
704 $lastBooking = Booking::orderBy('group_id', 'desc')->first(['group_id']);
705
706 if ($lastBooking) {
707 return $lastBooking->group_id + 1;
708 }
709
710 return 1;
711 }
712
713 public static function getNextIndex()
714 {
715 static $index = 0;
716
717 $index += 1;
718 return $index;
719 }
720
721 public static function getGlobalPaymentSettings()
722 {
723 static $settings;
724
725 if ($settings) {
726 return $settings;
727 }
728
729 $settings = get_option('fluent_booking_global_payment_settings', []);
730
731 if (!$settings) {
732 $settings = [
733 'currency' => 'USD',
734 'is_active' => 'no'
735 ];
736 }
737
738 return $settings;
739 }
740
741 public static function isPaymentEnabled($calendarEvent = null)
742 {
743 $settings = self::getGlobalPaymentSettings();
744 if (Arr::get($settings, 'is_active') == 'yes') {
745 return true;
746 }
747
748 if ($calendarEvent) {
749 if ($calendarEvent->type != 'paid') {
750 return false;
751 }
752
753 $exist = Meta::where('object_type', 'calendar_slot')
754 ->where('object_id', $calendarEvent->id)
755 ->where('key', 'payment_settings')
756 ->first();
757
758 return $exist && $exist->value && Arr::get($exist->value, 'enabled') == 'yes';
759 }
760
761 return false;
762 }
763
764 public static function isPaymentConfigured($method = 'stripe')
765 {
766 $settings = get_option('fluent_booking_payment_settings_' . $method, []);
767
768 return Arr::get($settings, 'is_active', 'no') == 'yes';
769 }
770
771 /**
772 * Sanitize form inputs recursively.
773 *
774 * @param $input
775 *
776 * @return mixed $input
777 */
778 public static function fluentbookingSanitizer($input, $attribute = null, $fields = [])
779 {
780 if (is_string($input)) {
781 $element = Arr::get($fields, $attribute . '.element');
782
783 if (in_array($element, ['post_content', 'rich_text_input'])) {
784 return wp_kses_post($input);
785 } elseif ('textarea' === $element) {
786 $input = sanitize_textarea_field($input);
787 } elseif ('input_email' === $element) {
788 $input = strtolower(sanitize_text_field($input));
789 } elseif ('input_url' === $element) {
790 $input = sanitize_url($input);
791 } else {
792 $input = sanitize_text_field($input);
793 }
794 } elseif (is_array($input)) {
795 foreach ($input as $key => &$value) {
796 $attribute = $attribute ? $attribute . '[' . $key . ']' : $key;
797
798 $value = self::fluentbookingSanitizer($value, $attribute, $fields);
799
800 $attribute = null;
801 }
802 }
803
804 return $input;
805 }
806
807 public static function getMeta($group, $objectId, $key, $withModel = false)
808 {
809 $meta = Meta::where('object_type', $group)
810 ->where('object_id', $objectId)
811 ->where('key', $key)
812 ->first();
813
814 if ($meta) {
815 if ($withModel) {
816 return $meta;
817 }
818
819 return $meta->value;
820 }
821
822 return null;
823 }
824
825 public static function updateMeta($group, $objectId, $key, $value)
826 {
827 $meta = self::getMeta($group, $objectId, $key, true);
828
829 if ($meta) {
830 $meta->value = $value;
831 $meta->save();
832 return $meta;
833 }
834
835 return Meta::create([
836 'object_type' => $group,
837 'key' => $key,
838 'object_id' => $objectId,
839 'value' => $value
840 ]);
841 }
842
843 public static function deleteMeta($group, $objectId, $key)
844 {
845 return Meta::where('object_type', $group)
846 ->where('object_id', $objectId)
847 ->where('key', $key)
848 ->delete();
849 }
850
851 public static function getBookingMeta($eventId, $metaKey, $withModel = false)
852 {
853 $bookingMeta = BookingMeta::where('booking_id', $eventId)
854 ->where('meta_key', $metaKey)
855 ->first();
856
857 if ($bookingMeta) {
858 return $withModel ? $bookingMeta : $bookingMeta->value;
859 }
860
861 return null;
862 }
863
864 public static function updateBookingMeta($eventId, $metaKey, $value)
865 {
866 $bookingMeta = self::getBookingMeta($eventId, $metaKey, true);
867
868 if ($bookingMeta) {
869 $bookingMeta->value = $value;
870 $bookingMeta->save();
871 return $bookingMeta;
872 }
873
874 return BookingMeta::create([
875 'booking_id' => $eventId,
876 'meta_key' => $metaKey, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
877 'value' => $value
878 ]);
879 }
880
881 public static function getUserDisplayName($userId = null)
882 {
883 if (!$userId) {
884 $userId = get_current_user_id();
885 }
886
887 if (!$userId) {
888 return '';
889 }
890
891 $user = get_user_by('ID', $userId);
892
893 $name = trim($user->first_name . ' ' . $user->last_name);
894
895 if ($name) {
896 return $name;
897 }
898
899 return $user->display_name;
900 }
901
902 public static function getUserEmail($userId = null)
903 {
904 $userId = $userId ?: get_current_user_id();
905
906 if (!$userId) {
907 return '';
908 }
909
910 $user = get_user_by('ID', $userId);
911
912 return $user->user_email;
913 }
914
915 public static function excerpt($text, $max_length = 160)
916 {
917 // Strip HTML tags and convert entities to their corresponding characters
918 $text = html_entity_decode(wp_strip_all_tags($text));
919
920 // Remove any line breaks, tabs, or extra whitespace
921 $text = preg_replace('/\s+/', ' ', trim($text));
922
923 if (mb_strlen($text) > $max_length) {
924 $text = mb_substr($text, 0, $max_length);
925 $text = preg_replace('/\s+\S+$/', '', $text) . '...';
926 }
927
928 return $text;
929 }
930
931 public static function generateSlotSlug($default, $calendar)
932 {
933 $original = sanitize_title($default, $default, 'display');
934
935 $default = $original;
936
937 $counter = 1;
938
939 while (CalendarSlot::where('calendar_id', $calendar->id)->where('slug', $default)->first()) {
940 $default = $original . '-' . $counter;
941 $counter += 1;
942 }
943
944 return apply_filters('fluent_booking/slot_slug', $default, $original);
945 }
946
947 public static function getIp()
948 {
949 $server = $_SERVER;
950
951 $clientIp = Arr::get($server, 'HTTP_CLIENT_IP');
952 $xForwarded = Arr::get($server, 'HTTP_X_FORWARDED_FOR');
953
954 if (!empty($clientIp)) {
955 $ip = $clientIp;
956 } elseif (!empty($xForwarded)) {
957 $ip = $clientIp;
958 } else {
959 $ip = $clientIp;
960 }
961
962 return sanitize_text_field($ip);
963 }
964
965 public static function fcal_sanitize_html($html)
966 {
967 if (!$html) {
968 return $html;
969 }
970
971 // Return $html if it's just a plain text
972 if (!preg_match('/<[^>]*>/', $html)) {
973 return $html;
974 }
975
976 $tags = wp_kses_allowed_html('post');
977 $tags['style'] = [
978 'types' => [],
979 ];
980 // iframe
981 $tags['iframe'] = [
982 'width' => [],
983 'height' => [],
984 'src' => [],
985 'srcdoc' => [],
986 'title' => [],
987 'frameborder' => [],
988 'allow' => [],
989 'class' => [],
990 'id' => [],
991 'allowfullscreen' => [],
992 'style' => [],
993 ];
994 //button
995 $tags['button']['onclick'] = [];
996
997 //svg
998 if (empty($tags['svg'])) {
999 $svg_args = [
1000 'svg' => [
1001 'class' => true,
1002 'aria-hidden' => true,
1003 'aria-labelledby' => true,
1004 'role' => true,
1005 'xmlns' => true,
1006 'width' => true,
1007 'height' => true,
1008 'viewbox' => true,
1009 ],
1010 'g' => ['fill' => true],
1011 'title' => ['title' => true],
1012 'path' => [
1013 'd' => true,
1014 'fill' => true,
1015 'transform' => true,
1016 ],
1017 ];
1018 $tags = array_merge($tags, $svg_args);
1019 }
1020
1021 $tags = apply_filters('fluent_booking/allowed_html_tags', $tags);
1022
1023 return wp_kses($html, $tags);
1024 }
1025
1026 /**
1027 * Sanitize inputs recursively.
1028 *
1029 * @param array $input
1030 * @param array $sanitizeMap
1031 *
1032 * @return array $input
1033 */
1034 public static function fcal_backend_sanitizer($inputs, $sanitizeMap = [])
1035 {
1036 $originalValues = $inputs;
1037 foreach ($inputs as $key => &$value) {
1038 if (is_array($value)) {
1039 $value = self::fcal_backend_sanitizer($value, $sanitizeMap);
1040 } else {
1041 $method = Arr::get($sanitizeMap, $key);
1042 if (!$method) {
1043 continue;
1044 }
1045 if (is_callable($method)) {
1046 $value = call_user_func($method, $value);
1047 } elseif (method_exists(self::class, $method)) {
1048 $value = call_user_func([self::class, $method], $value);
1049 }
1050 }
1051 }
1052
1053 return apply_filters('fluent_booking/backend_sanitized_values', $inputs, $originalValues);
1054 }
1055
1056 /**
1057 * Recursively implode a multi-dimentional array
1058 *
1059 * @param string $glue
1060 * @param array $array
1061 *
1062 * @return string
1063 */
1064 public static function fcalImplodeRecursive($glue, array $array)
1065 {
1066 $fn = function ($glue, array $array) use (&$fn) {
1067 $result = '';
1068 foreach ($array as $item) {
1069 if (is_array($item)) {
1070 $result .= $fn($glue, $item);
1071 } else {
1072 $result .= $glue . $item;
1073 }
1074 }
1075
1076 return $result;
1077 };
1078
1079 return ltrim($fn($glue, $array), $glue);
1080 }
1081
1082 public static function getEventColors()
1083 {
1084 return apply_filters('fluent_booking/event_colors', [
1085 [
1086 'label' => __('Red-Orange', 'fluent-booking'),
1087 'value' => '#ff4f00'
1088 ],
1089 [
1090 'label' => __('Deep Lilac', 'fluent-booking'),
1091 'value' => '#e55cff'
1092 ],
1093 [
1094 'label' => __('Purple', 'fluent-booking'),
1095 'value' => '#8247f5'
1096 ],
1097 [
1098 'label' => __('Vivid Blue', 'fluent-booking'),
1099 'value' => '#0099ff'
1100 ],
1101 [
1102 'label' => __('Cyan', 'fluent-booking'),
1103 'value' => '#0ae8f0'
1104 ],
1105 [
1106 'label' => __('Emerald Green', 'fluent-booking'),
1107 'value' => '#17e885'
1108 ],
1109 [
1110 'label' => __('Lime Green', 'fluent-booking'),
1111 'value' => '#ccf000'
1112 ],
1113 [
1114 'label' => __('Amber', 'fluent-booking'),
1115 'value' => '#ffa600'
1116 ]
1117 ]);
1118 }
1119
1120 public static function getMeetingDurations()
1121 {
1122 return apply_filters('fluent_booking/meeting_durations_schema', [
1123 [
1124 'value' => '15',
1125 'label' => __('15 Minutes', 'fluent-booking')
1126 ],
1127 [
1128 'value' => '30',
1129 'label' => __('30 Minutes', 'fluent-booking')
1130 ],
1131 [
1132 'value' => '45',
1133 'label' => __('45 Minutes', 'fluent-booking')
1134 ],
1135 [
1136 'value' => '60',
1137 'label' => __('60 Minutes', 'fluent-booking')
1138 ],
1139 [
1140 'value' => 'custom',
1141 'label' => __('Custom', 'fluent-booking')
1142 ]
1143 ]);
1144 }
1145
1146 public static function getMeetingMultiDurations()
1147 {
1148 return apply_filters('fluent_booking/meeting_multi_durations_schema', [
1149 [
1150 'value' => '5',
1151 'label' => __('5 Minutes', 'fluent-booking')
1152 ],
1153 [
1154 'value' => '10',
1155 'label' => __('10 Minutes', 'fluent-booking')
1156 ],
1157 [
1158 'value' => '15',
1159 'label' => __('15 Minutes', 'fluent-booking')
1160 ],
1161 [
1162 'value' => '30',
1163 'label' => __('30 Minutes', 'fluent-booking')
1164 ],
1165 [
1166 'value' => '45',
1167 'label' => __('45 Minutes', 'fluent-booking')
1168 ],
1169 [
1170 'value' => '50',
1171 'label' => __('50 Minutes', 'fluent-booking')
1172 ],
1173 [
1174 'value' => '60',
1175 'label' => __('60 Minutes', 'fluent-booking')
1176 ],
1177 [
1178 'value' => '90',
1179 'label' => __('90 Minutes', 'fluent-booking')
1180 ],
1181 [
1182 'value' => '120',
1183 'label' => __('120 Minutes', 'fluent-booking')
1184 ],
1185 [
1186 'value' => '150',
1187 'label' => __('150 Minutes', 'fluent-booking')
1188 ],
1189 [
1190 'value' => '180',
1191 'label' => __('180 Minutes', 'fluent-booking')
1192 ],
1193 [
1194 'value' => '240',
1195 'label' => __('240 Minutes', 'fluent-booking')
1196 ],
1197 [
1198 'value' => '480',
1199 'label' => __('480 Minutes', 'fluent-booking')
1200 ]
1201 ]);
1202 }
1203
1204 public static function getDurationLookup($multiDuration = false)
1205 {
1206 $durations = $multiDuration ? self::getMeetingMultiDurations() : self::getMeetingDurations();
1207
1208 $durationLookup = [];
1209 foreach ($durations as $duration) {
1210 $durationLookup[$duration['value']] = $duration['label'];
1211 }
1212
1213 return $durationLookup;
1214 }
1215
1216 public static function getBufferTimes()
1217 {
1218 return apply_filters('fluent_booking/buffer_times_schema', [
1219 [
1220 'value' => '0',
1221 'label' => __('No buffer time', 'fluent-booking')
1222 ],
1223 [
1224 'value' => '5',
1225 'label' => __('5 Minutes', 'fluent-booking')
1226 ],
1227 [
1228 'value' => '10',
1229 'label' => __('10 Minutes', 'fluent-booking')
1230 ],
1231 [
1232 'value' => '15',
1233 'label' => __('15 Minutes', 'fluent-booking')
1234 ],
1235 [
1236 'value' => '20',
1237 'label' => __('20 Minutes', 'fluent-booking')
1238 ],
1239 [
1240 'value' => '30',
1241 'label' => __('30 Minutes', 'fluent-booking')
1242 ],
1243 [
1244 'value' => '45',
1245 'label' => __('45 Minutes', 'fluent-booking')
1246 ],
1247 [
1248 'value' => '60',
1249 'label' => __('60 Minutes', 'fluent-booking')
1250 ],
1251 [
1252 'value' => '90',
1253 'label' => __('90 Minutes', 'fluent-booking')
1254 ],
1255 [
1256 'value' => '120',
1257 'label' => __('120 Minutes', 'fluent-booking')
1258 ]
1259 ]);
1260 }
1261
1262 public static function getSlotIntervals()
1263 {
1264 return apply_filters('fluent_booking/slot_intervals_schema', [
1265 [
1266 'value' => '',
1267 'label' => __('Use event length (default)', 'fluent-booking')
1268 ],
1269 [
1270 'value' => '5',
1271 'label' => __('5 Minutes', 'fluent-booking')
1272 ],
1273 [
1274 'value' => '10',
1275 'label' => __('10 Minutes', 'fluent-booking')
1276 ],
1277 [
1278 'value' => '15',
1279 'label' => __('15 Minutes', 'fluent-booking')
1280 ],
1281 [
1282 'value' => '20',
1283 'label' => __('20 Minutes', 'fluent-booking')
1284 ],
1285 [
1286 'value' => '30',
1287 'label' => __('30 Minutes', 'fluent-booking')
1288 ],
1289 [
1290 'value' => '45',
1291 'label' => __('45 Minutes', 'fluent-booking')
1292 ],
1293 [
1294 'value' => '60',
1295 'label' => __('60 Minutes', 'fluent-booking')
1296 ],
1297 [
1298 'value' => '75',
1299 'label' => __('75 Minutes', 'fluent-booking')
1300 ],
1301 [
1302 'value' => '90',
1303 'label' => __('90 Minutes', 'fluent-booking')
1304 ],
1305 [
1306 'value' => '105',
1307 'label' => __('105 Minutes', 'fluent-booking')
1308 ],
1309 [
1310 'value' => '120',
1311 'label' => __('120 Minutes', 'fluent-booking')
1312 ]
1313 ]);
1314 }
1315
1316 public static function getBookingStatusChangingTimes()
1317 {
1318 return apply_filters('fluent_booking/booking_status_changing_times_schema', [
1319 [
1320 'value' => '5',
1321 'label' => __('5 Minutes', 'fluent-booking')
1322 ],
1323 [
1324 'value' => '10',
1325 'label' => __('10 Minutes', 'fluent-booking')
1326 ],
1327 [
1328 'value' => '20',
1329 'label' => __('20 Minutes', 'fluent-booking')
1330 ],
1331 [
1332 'value' => '30',
1333 'label' => __('30 Minutes', 'fluent-booking')
1334 ],
1335 [
1336 'value' => '40',
1337 'label' => __('40 Minutes', 'fluent-booking')
1338 ],
1339 [
1340 'value' => '50',
1341 'label' => __('50 Minutes', 'fluent-booking')
1342 ],
1343 [
1344 'value' => '60',
1345 'label' => __('1 Hour', 'fluent-booking')
1346 ],
1347 [
1348 'value' => '120',
1349 'label' => __('2 Hours', 'fluent-booking')
1350 ],
1351 [
1352 'value' => '180',
1353 'label' => __('3 Hours', 'fluent-booking')
1354 ],
1355 [
1356 'value' => '360',
1357 'label' => __('6 Hours', 'fluent-booking')
1358 ],
1359 [
1360 'value' => '720',
1361 'label' => __('12 Hours', 'fluent-booking')
1362 ],
1363 [
1364 'value' => '1440',
1365 'label' => __('1 Day', 'fluent-booking')
1366 ],
1367 [
1368 'value' => '2880',
1369 'label' => __('2 Days', 'fluent-booking')
1370 ]
1371 ]);
1372 }
1373
1374 public static function getBookingPeriodOptions()
1375 {
1376 return apply_filters('fluent_booking/booking_period_options', [
1377 'upcoming' => __('Upcoming', 'fluent-booking'),
1378 'completed' => __('Completed', 'fluent-booking'),
1379 'pending' => __('Pending', 'fluent-booking'),
1380 'cancelled' => __('Cancelled', 'fluent-booking'),
1381 'all' => __('All', 'fluent-booking'),
1382 ]);
1383 }
1384
1385 public static function getWeekSelectTimes()
1386 {
1387 return apply_filters('fluent_booking/week_select_times_schema', [
1388 'start' => '00:00',
1389 'step' => '00:15',
1390 'end' => '23:45'
1391 ]);
1392 }
1393
1394 public static function getOverrideSelectTimes()
1395 {
1396 return apply_filters('fluent_booking/override_select_times_schema', [
1397 'start' => '00:00',
1398 'step' => '00:15',
1399 'end' => '23:45'
1400 ]);
1401 }
1402
1403 public static function getWeeklyScheduleSchema()
1404 {
1405 return apply_filters('fluent_booking/weekly_schedule_schema', [
1406 'sun' => [
1407 'enabled' => false,
1408 'slots' => []
1409 ],
1410 'mon' => [
1411 'enabled' => true,
1412 'slots' => [
1413 ['start' => '09:00', 'end' => '17:00']
1414 ],
1415 ],
1416 'tue' => [
1417 'enabled' => true,
1418 'slots' => [
1419 ['start' => '09:00', 'end' => '17:00']
1420 ],
1421 ],
1422 'wed' => [
1423 'enabled' => true,
1424 'slots' => [
1425 ['start' => '09:00', 'end' => '17:00']
1426 ],
1427 ],
1428 'thu' => [
1429 'enabled' => true,
1430 'slots' => [
1431 ['start' => '09:00', 'end' => '17:00']
1432 ],
1433 ],
1434 'fri' => [
1435 'enabled' => true,
1436 'slots' => [
1437 ['start' => '09:00', 'end' => '17:00']
1438 ],
1439 ],
1440 'sat' => [
1441 'enabled' => false,
1442 'slots' => []
1443 ],
1444 ]);
1445 }
1446
1447 public static function getCustomFieldTypes()
1448 {
1449 return apply_filters('fluent_booking/custom_fields_types', [
1450 [
1451 'value' => 'email',
1452 'label' => __('Email', 'fluent-booking')
1453 ],
1454 [
1455 'value' => 'text',
1456 'label' => __('Text', 'fluent-booking')
1457 ],
1458 [
1459 'value' => 'textarea',
1460 'label' => __('Textarea', 'fluent-booking')
1461 ],
1462 [
1463 'value' => 'number',
1464 'label' => __('Number', 'fluent-booking')
1465 ],
1466 [
1467 'value' => 'phone',
1468 'label' => __('Phone', 'fluent-booking')
1469 ],
1470 [
1471 'value' => 'radio',
1472 'label' => __('Radio', 'fluent-booking')
1473 ],
1474 [
1475 'value' => 'dropdown',
1476 'label' => __('Select', 'fluent-booking')
1477 ],
1478 [
1479 'value' => 'multi-select',
1480 'label' => __('Multi Select', 'fluent-booking')
1481 ],
1482 [
1483 'value' => 'checkbox',
1484 'label' => __('Checkbox', 'fluent-booking')
1485 ],
1486 [
1487 'value' => 'checkbox-group',
1488 'label' => __('Checkbox Group', 'fluent-booking')
1489 ],
1490 [
1491 'value' => 'date',
1492 'label' => __('Date', 'fluent-booking')
1493 ]
1494 ]);
1495 }
1496
1497 public static function getDefaultEmailNotificationSettings()
1498 {
1499 $assetUrl = App::getInstance()['url.assets'];
1500
1501 $checkImage = $assetUrl . 'images/check-mark.png';
1502 $cancelImage = $assetUrl . 'images/cancel-mark.png';
1503 $scheduleImage = $assetUrl . 'images/schedule-mark.png';
1504
1505 return apply_filters('fluent_booking/default_email_notification_settings', [
1506 'booking_conf_attendee' => [
1507 'enabled' => true,
1508 'title' => __('Booking Confirmation Email to Attendee', 'fluent-booking'),
1509 'email' => [
1510 'subject' => 'Booking Confirmation between {{host.name}} & {{guest.full_name}}',
1511 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $checkImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">Your event has been scheduled</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_guest_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</p><hr/>' . self::getAddToCalendarHtml($assetUrl)
1512 ],
1513 ],
1514 'booking_conf_host' => [
1515 'enabled' => true,
1516 'is_host' => true,
1517 'title' => __('Booking Confirmation Email to Organizer (You)', 'fluent-booking'),
1518 'email' => [
1519 'additional_recipients' => '',
1520 'subject' => 'New Booking: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1521 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $checkImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">A new event has been scheduled</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1522 ],
1523 ],
1524 'reminder_to_attendee' => [
1525 'enabled' => false,
1526 'title' => __('Configure Meeting Reminder to Attendee', 'fluent-booking'),
1527 'email' => [
1528 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_attendee}}',
1529 'body' => '<h2 style="text-align: center;">Reminder: Your meeting will start in {{booking.start_time_human_format}}</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><h3><strong>When</strong></h3><p>{{booking.full_start_end_guest_timezone}}</p><h3><strong>Who</strong></h3><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</a></p>',
1530 'times' => [
1531 [
1532 'unit' => 'minutes',
1533 'value' => 15,
1534 ]
1535 ]
1536 ],
1537 ],
1538 'reminder_to_host' => [
1539 'enabled' => false,
1540 'is_host' => true,
1541 'title' => __('Configure Meeting Reminder to Organizer (You)', 'fluent-booking'),
1542 'email' => [
1543 'additional_recipients' => '',
1544 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_host}}',
1545 'body' => '<h2 style="text-align: center;">Reminder: Your meeting will start in {{booking.start_time_human_format}}</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>',
1546 'times' => [
1547 [
1548 'unit' => 'minutes',
1549 'value' => 15,
1550 ]
1551 ]
1552 ],
1553 ],
1554 'cancelled_by_attendee' => [
1555 'enabled' => true,
1556 'is_host' => true,
1557 'title' => __('Booking Cancelled by Attendee (email to Organizer)', 'fluent-booking'),
1558 'email' => [
1559 'additional_recipients' => '',
1560 'subject' => 'A booking was cancelled with {{guest.full_name}}',
1561 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Cancellation</h2><hr /><p>A scheduled meeting has been canceled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(cancelled)</strong></span></p><p><strong>Cancellation Reason</strong></p><p>{{booking.cancel_reason}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1562 ],
1563 ],
1564 'cancelled_by_host' => [
1565 'enabled' => true,
1566 'title' => __('Booking Cancelled by Organizer (email to Attendee)', 'fluent-booking'),
1567 'email' => [
1568 'subject' => 'Your booking was cancelled with {{host.name}}',
1569 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Cancellation</h2><hr /><p>Your scheduled meeting has been canceled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(cancelled)</strong></span></p><p><strong>Cancellation Reason</strong></p><p>{{booking.cancel_reason}}</p>'
1570 ],
1571 ],
1572 'rescheduled_by_attendee' => [
1573 'enabled' => true,
1574 'is_host' => true,
1575 'title' => __('Booking Rescheduled by Attendee (email to Organizer)', 'fluent-booking'),
1576 'email' => [
1577 'additional_recipients' => '',
1578 'subject' => 'A booking was rescheduled with {{guest.full_name}}',
1579 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Rescheduled</h2><hr /><p>A scheduled meeting has been rescheduled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>New Time: {{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(new)</strong></span></p><p>Previous Time: {{booking.previous_meeting_time}}</p><p><strong>Rescheduling Reason</strong></p><p>{{booking.reschedule_reason}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1580 ],
1581 ],
1582 'rescheduled_by_host' => [
1583 'enabled' => true,
1584 'title' => __('Booking Rescheduled by Organizer (email to Attendee)', 'fluent-booking'),
1585 'email' => [
1586 'subject' => 'Your booking was rescheduled with {{host.name}}',
1587 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Rescheduled</h2><hr /><p>Your scheduled meeting has been rescheduled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>New Time: {{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(new)</strong></span></p><p>Previous Time: {{booking.previous_meeting_time}}</p><p><strong>Rescheduling Reason</strong></p><p>{{booking.reschedule_reason}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</a></p><hr/>' . self::getAddToCalendarHtml($assetUrl)
1588 ],
1589 ],
1590 'booking_request_host' => [
1591 'enabled' => true,
1592 'is_host' => true,
1593 'title' => __('Booking Approval Request to Host (email to Organizer)', 'fluent-booking'),
1594 'email' => [
1595 'additional_recipients' => '',
1596 'subject' => 'Awaiting Approval: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1597 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">A booking is still waiting for your approval</h2><hr /><p>Someone has requested to schedule an event on your calendar. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr />' . self::getConfirmAndRejectButton($assetUrl) . '<p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
1598 ],
1599 ],
1600 'booking_request_attendee' => [
1601 'enabled' => true,
1602 'title' => __('Booking Submission Confirmation (email to Attendee)', 'fluent-booking'),
1603 'email' => [
1604 'subject' => 'Booking Submitted: Meeting between {{host.name}} & {{guest.full_name}}',
1605 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">Your booking has been submitted</h2><hr /><p>Please wait for the host to confirm your booking.</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_guest_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</p>'
1606 ],
1607 ],
1608 'declined_by_host' => [
1609 'enabled' => true,
1610 'title' => __('Booking Declined by Organizer (email to Attendee)', 'fluent-booking'),
1611 'email' => [
1612 'subject' => 'Booking Declined: Your booking was declined with {{host.name}}',
1613 'body' => '<p style="text-align: center;"><img class="alignnone wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Declined</h2><hr /><p>Your booking request has been declined. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(declined)</strong></span></p><p><strong>Reason</strong></p><p>{{booking.reject_reason}}</p>'
1614 ],
1615 ],
1616 ]);
1617 }
1618
1619 public static function getAddToCalendarHtml($assetUrl = '')
1620 {
1621 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1622
1623 $html = '<table style="margin: 0 auto; border: none;"><tbody><tr><td style="border: none; font-size: 1rem;">' . __('Add to calendar', 'fluent-booking') . '</td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_g_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/g-icon.png" alt="Google Calendar" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ol_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/ol-icon.png" alt="Outlook" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ms_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/msoffice.png" alt="Microsoft Office" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ics_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/ics.png" alt="Other Calendar" /></a></td></tr></tbody></table>';
1624
1625 return apply_filters('fluent_booking/add_to_calendar_html', $html);
1626 }
1627
1628 public static function getConfirmAndRejectButton($assetUrl = '')
1629 {
1630 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1631
1632 $html = '<table style="margin: 16px auto; border: none;"><tbody><tr><td style="border: none; border-radius: 3px;" align="center" valign="middle"><p style="display: inline-block; background: #292929; color: #ffffff; font-size: 14px; font-weight: 500; line-height: 16px; margin: 0; text-decoration: none; text-transform: none; padding: 10px 16px 10px 14px; border-radius: 6px; box-sizing: border-box; height: 36px;"><a href="##booking.booking_confirm_url##" style="color: #ffffff; text-decoration: none; display: flex; margin: auto;"><img src="' . $assetUrl . 'images/confirm-mark.png" style="height: 16px; width: 16px; margin-left: 0; margin-right: 0.5rem;" alt="" width="16px" data-bit="iit" />' . __('Confirm', 'fluent-booking') . '</a></p><p style="width: 16px; height: 16px; display: inline-block;"> </p><p style="display: inline-block; background: #ffffff; border: 1px solid #d1d5db; color: #ffffff; font-size: 14px; font-weight: 500; line-height: 16px; margin: 0; text-decoration: none; text-transform: none; padding: 10px 16px 10px 14px; border-radius: 6px; box-sizing: border-box; height: 36px;"><a href="##booking.booking_reject_url##" style="color: #292929; text-decoration: none; display: flex; margin: auto;"><img src="' . $assetUrl . 'images/reject-mark.png" style="height: 16px; width: 16px; margin-left: 0; margin-right: 8px;" alt="" width="16px" data-bit="iit" />' . __('Reject', 'fluent-booking') . '</a></p></td></tr></tbody></table>';
1633
1634 return apply_filters('fluent_booking/confirm_and_reject_button_html', $html);
1635 }
1636
1637 public static function getEditorShortCodes($calendarEvent = null, $isHtmlSupported = false)
1638 {
1639 if (!$isHtmlSupported) {
1640 $groups = [
1641 'guest' => [
1642 'title' => __('Attendee Data', 'fluent-booking'),
1643 'key' => 'guest',
1644 'shortcodes' => [
1645 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1646 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1647 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1648 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1649 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1650 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1651 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking')
1652 ]
1653 ],
1654 'booking' => [
1655 'title' => __('Booking Data', 'fluent-booking'),
1656 'key' => 'booking',
1657 'shortcodes' => [
1658 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1659 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1660 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1661 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1662 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1663 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1664 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1665 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1666 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1667 '{{booking.start_date_time_for_attendee}}' => __('Event Date Time (with attendee timezone)', 'fluent-booking'),
1668 '{{booking.start_date_time_for_host}}' => __('Event Date Time (with host timezone)', 'fluent-booking'),
1669 '{{booking.location_details_text}}' => __('Event Location Details', 'fluent-booking'),
1670 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1671 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1672 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1673 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1674 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1675 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1676 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1677 ]
1678 ],
1679 'host' => [
1680 'title' => __('Host Data', 'fluent-booking'),
1681 'key' => 'host',
1682 'shortcodes' => [
1683 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1684 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1685 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1686 ]
1687 ],
1688 'other' => [
1689 'title' => __('Other', 'fluent-booking'),
1690 'key' => 'other',
1691 'shortcodes' => [
1692 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1693 '{{calendar.id}}' => __('Calendar ID', 'fluent-booking'),
1694 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1695 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1696 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1697 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1698 ]
1699 ]
1700 ];
1701 } else {
1702 $groups = [
1703 'guest' => [
1704 'title' => __('Attendee Data', 'fluent-booking'),
1705 'key' => 'guest',
1706 'shortcodes' => [
1707 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1708 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1709 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1710 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1711 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1712 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1713 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking'),
1714 '{{guest.form_data_html}}' => __('Guest Form Submitted Data (HTML)', 'fluent-booking')
1715 ]
1716 ],
1717 'booking' => [
1718 'title' => __('Booking Data', 'fluent-booking'),
1719 'key' => 'booking',
1720 'shortcodes' => [
1721 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1722 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1723 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1724 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1725 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1726 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1727 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1728 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1729 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1730 '{{booking.start_date_time_for_attendee}}' => __('Event Date time (with guest timezone)', 'fluent-booking'),
1731 '{{booking.start_date_time_for_host}}' => __('Event Date time (with host timezone)', 'fluent-booking'),
1732 '{{booking.location_details_html}}' => __('Event Location Details (HTML)', 'fluent-booking'),
1733 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1734 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1735 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1736 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1737 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1738 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1739 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking')
1740 ]
1741 ],
1742 'host' => [
1743 'title' => __('Host Data', 'fluent-booking'),
1744 'key' => 'host',
1745 'shortcodes' => [
1746 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1747 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1748 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1749 ]
1750 ],
1751 'other' => [
1752 'title' => __('Other', 'fluent-booking'),
1753 'key' => 'other',
1754 'shortcodes' => [
1755 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1756 '{{event.calendar_id}}' => __('Calendar ID', 'fluent-booking'),
1757 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1758 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1759 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1760 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1761 ]
1762 ]
1763 ];
1764 }
1765
1766 if ($calendarEvent) {
1767 $customFields = BookingFieldService::getCustomFields($calendarEvent, true);
1768 foreach ($customFields as $fieldKey => $field) {
1769 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '}}'] = $field['label'];
1770 if ($field['type'] == 'date') {
1771 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '.format.Y-m-d}}'] = $field['label'] . ' (Ex: 2024-05-20)';
1772 }
1773 }
1774
1775 if (Helper::isPaymentEnabled($calendarEvent)) {
1776 $groups['payment'] = [
1777 'title' => __('Payment Data', 'fluent-booking'),
1778 'key' => 'payment',
1779 'shortcodes' => [
1780 '{{payment.payment_total}}' => __('Payment Total', 'fluent-booking'),
1781 '{{payment.payment_status}}' => __('Payment Status', 'fluent-booking'),
1782 '{{payment.payment_method}}' => __('Payment Method', 'fluent-booking'),
1783 '{{payment.currency}}' => __('Currency', 'fluent-booking'),
1784 '{{payment.payment_date}}' => __('Payment Date', 'fluent-booking'),
1785 ]
1786 ];
1787
1788 if ($isHtmlSupported) {
1789 $groups['payment']['shortcodes']['{{payment.receipt_html}}'] = __('Payment Receipt (HTML)', 'fluent-booking');
1790 }
1791 }
1792
1793 if ($calendarEvent->isMultiHostsEvent()) {
1794 $totalhost = count($calendarEvent->getHostIds());
1795 for ($i = 1; $i < $totalhost; $i++) {
1796 $groups['host']['shortcodes']['{{team_member.' . $i . '.name}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Name', 'fluent-booking');
1797 $groups['host']['shortcodes']['{{team_member.' . $i . '.email}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Email', 'fluent-booking');
1798 }
1799 }
1800 }
1801
1802 return apply_filters('fluent_booking/editor_shortcodes_groups', $groups, $calendarEvent, $isHtmlSupported);
1803 }
1804
1805 public static function encryptKey($value)
1806 {
1807 if (!$value) {
1808 return $value;
1809 }
1810
1811 if (!extension_loaded('openssl')) {
1812 return $value;
1813 }
1814
1815 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1816
1817 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1818 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1819 } else {
1820 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1821 }
1822
1823 $method = 'aes-256-ctr';
1824 $ivlen = openssl_cipher_iv_length($method);
1825 $iv = openssl_random_pseudo_bytes($ivlen);
1826
1827 $raw_value = openssl_encrypt($value . $salt, $method, $key, 0, $iv);
1828 if (!$raw_value) {
1829 return false;
1830 }
1831
1832 return base64_encode($iv . $raw_value); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
1833 }
1834
1835 public static function decryptKey($raw_value)
1836 {
1837
1838 if (!$raw_value) {
1839 return $raw_value;
1840 }
1841
1842 if (!extension_loaded('openssl')) {
1843 return $raw_value;
1844 }
1845
1846 $raw_value = base64_decode($raw_value, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
1847
1848 $method = 'aes-256-ctr';
1849 $ivlen = openssl_cipher_iv_length($method);
1850 $iv = substr($raw_value, 0, $ivlen);
1851
1852 $raw_value = substr($raw_value, $ivlen);
1853
1854 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1855 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1856 } else {
1857 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1858 }
1859
1860 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1861
1862 $value = openssl_decrypt($raw_value, $method, $key, 0, $iv);
1863 if (!$value || substr($value, -strlen($salt)) !== $salt) {
1864 return false;
1865 }
1866
1867 return substr($value, 0, -strlen($salt));
1868 }
1869
1870 public static function debugLog($data)
1871 {
1872 if (defined('FLUENT_BOOKING_DEBUG') && FLUENT_BOOKING_DEBUG) {
1873 error_log(print_r($data, true));
1874 }
1875 }
1876
1877 public static function getGlobalSettings($settingsKey = null)
1878 {
1879 $defaults = [
1880 'payments' => [
1881 'currency' => 'USD',
1882 'is_active' => 'no'
1883 ],
1884 'emailing' => [
1885 'from_name' => '',
1886 'from_email' => '',
1887 'reply_to_name' => '',
1888 'reply_to_email' => '',
1889 'use_host_name' => '',
1890 'use_host_email_on_reply' => '',
1891 'attach_ics_on_confirmation' => '',
1892 'email_footer' => ''
1893 ],
1894 'administration' => [
1895 'admin_email' => '{{wp.admin_email}}',
1896 'summary_notification' => 'no',
1897 'notification_frequency' => 'daily',
1898 'notification_day' => 'mon',
1899 'start_day' => 'sun',
1900 'auto_cancel_timing' => '10',
1901 'auto_complete_timing' => '60',
1902 'default_phone_country' => ''
1903 ],
1904 'time_format' => '12',
1905 'theme' => 'system-default'
1906 ];
1907
1908 $settings = get_option('_fluent_booking_settings', []);
1909
1910 if (empty($settings)) {
1911 $settings = [];
1912 }
1913
1914 $paymentSettings = get_option('fluent_booking_global_payment_settings', []);
1915
1916 if ($paymentSettings) {
1917 $settings['payments'] = $paymentSettings;
1918 }
1919
1920 $settings = wp_parse_args($settings, $defaults);
1921
1922 $emailSettings = $settings['emailing'];
1923
1924 if (empty($settings['administration']['auto_cancel_timing'])) {
1925 $settings['administration']['auto_cancel_timing'] = '10';
1926 }
1927
1928 if (empty($settings['administration']['auto_complete_timing'])) {
1929 $settings['administration']['auto_complete_timing'] = '10';
1930 }
1931
1932 if (empty($emailSettings['from_name']) && defined('FLUENTCRM')) {
1933 $crmSettings = fluentcrmGetGlobalSettings('email_settings', []);
1934 $emailSettings['from_name'] = Arr::get($crmSettings, 'from_name');
1935 if (empty($emailSettings['from_email'])) {
1936 $emailSettings['from_email'] = Arr::get($crmSettings, 'from_email');
1937 }
1938 if (empty($emailSettings['reply_to_name'])) {
1939 $emailSettings['reply_to_name'] = Arr::get($crmSettings, 'reply_to_name');
1940 }
1941 if (empty($emailSettings['reply_to_email'])) {
1942 $emailSettings['reply_to_email'] = Arr::get($crmSettings, 'reply_to_email');
1943 }
1944
1945 $settings['emailing'] = $emailSettings;
1946 }
1947
1948 if ($settingsKey) {
1949 return Arr::get($settings, $settingsKey, []);
1950 }
1951
1952 return $settings;
1953
1954 }
1955
1956 public static function getGlobalAdminSetting($key = null, $default = null)
1957 {
1958 static $settings;
1959 if ($settings) {
1960
1961 if ($key) {
1962 return Arr::get($settings, $key, $default);
1963 }
1964
1965 return $settings;
1966 }
1967
1968 $globalSettings = self::getGlobalSettings();
1969 $settings = Arr::get($globalSettings, 'administration', []);
1970
1971 if ($key) {
1972 return Arr::get($settings, $key, $default);
1973 }
1974
1975 return $settings;
1976 }
1977
1978 public static function getDefaultTimeFormat()
1979 {
1980 static $format;
1981
1982 if ($format) {
1983 return $format;
1984 }
1985
1986 $settings = self::getGlobalSettings();
1987 $format = Arr::get($settings, 'time_format', '24');
1988 return $format;
1989 }
1990
1991 public static function getVerifiedSenders()
1992 {
1993 $verifiedSenders = [];
1994 if (defined('FLUENTMAIL')) {
1995 $smtpSettings = get_option('fluentmail-settings', []);
1996 if ($smtpSettings && count($smtpSettings['mappings'])) {
1997 $verifiedSenders = array_keys($smtpSettings['mappings']);
1998 }
1999 }
2000 /**
2001 * Filter the verified email senders
2002 * @param array $verifiedSenders
2003 */
2004 return apply_filters('fluent_booking/verfied_email_senders', $verifiedSenders);
2005 }
2006
2007 public static function getBookingReceiptLandingBaseUrl()
2008 {
2009 return apply_filters('fluent_booking/booking_receipt_landing_base_url', site_url('/'));
2010 }
2011
2012 public static function getGlobalModuleSettings($cached = true)
2013 {
2014 static $settings = null;
2015
2016 if ($cached && $settings !== null) {
2017 return $settings;
2018 }
2019
2020 $settings = get_option('_fluent_booking_enabled_modules', []);
2021
2022 if (empty($settings) || !\is_array($settings)) {
2023 $settings = [];
2024 }
2025
2026 return $settings;
2027 }
2028
2029 public static function updateGlobalModuleSettings($settings = [])
2030 {
2031 if (!is_array($settings)) {
2032 $settings = [];
2033 }
2034
2035 update_option('_fluent_booking_enabled_modules', $settings);
2036
2037 return self::getGlobalModuleSettings(false);
2038 }
2039
2040 public static function isModuleEnabled($module)
2041 {
2042 $settings = self::getGlobalModuleSettings();
2043
2044 return isset($settings[$module]) && $settings[$module] === 'yes';
2045 }
2046
2047 /**
2048 * @return mixed|void
2049 */
2050 public static function fluentbooking_is_rtl()
2051 {
2052 /**
2053 * If FluentBooking is running on RTL Mode
2054 *
2055 * @param bool $is_rtl
2056 */
2057 return apply_filters('fluent_booking/is_rtl', is_rtl());
2058 }
2059
2060 public static function fluentBookingUserAvatar($id_or_email, $args)
2061 {
2062 if (empty($id_or_email)) {
2063 return '';
2064 }
2065 return apply_filters('fluent_booking/author_photo', get_avatar_url($id_or_email), $args);
2066 }
2067
2068 public static function getPrefSettins($cached = true)
2069 {
2070 static $pref = null;
2071
2072 if ($cached && $pref) {
2073 return $pref;
2074 }
2075
2076 $settings = [
2077 'frontend' => [
2078 'enabled' => 'no',
2079 'slug' => 'my-bookings',
2080 'render_type' => 'standalone',
2081 'page_id' => ''
2082 ]
2083 ];
2084
2085 $storedSettings = get_option('fluent_booking_modules', []);
2086
2087 if ($storedSettings && is_array($storedSettings)) {
2088 $settings = wp_parse_args($storedSettings, $settings);
2089 } else {
2090 update_option('fluent_booking_modules', $settings, 'yes');
2091 }
2092
2093 $pref = $settings;
2094
2095 return $settings;
2096 }
2097 }
2098