PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.10.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.10.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.10.0, at app/Services/Helper.php

2,212 lines 79.9 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&theme=' . self::getActiveThemeName();
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
719 return $index;
720 }
721
722 public static function getGlobalPaymentSettings()
723 {
724 static $settings;
725
726 if ($settings) {
727 return $settings;
728 }
729
730 $settings = get_option('fluent_booking_global_payment_settings', []);
731
732 return $settings;
733 }
734
735 public static function isPaymentEnabled($calendarEvent = null)
736 {
737 $settings = CurrenciesHelper::getGlobalCurrencySettings();
738 if (Arr::get($settings, 'is_active') == 'yes') {
739 return true;
740 }
741
742 if ($calendarEvent) {
743 if ($calendarEvent->type != 'paid') {
744 return false;
745 }
746
747 $exist = Meta::where('object_type', 'calendar_slot')
748 ->where('object_id', $calendarEvent->id)
749 ->where('key', 'payment_settings')
750 ->first();
751
752 return $exist && $exist->value && Arr::get($exist->value, 'enabled') == 'yes';
753 }
754
755 return false;
756 }
757
758 public static function isPaymentConfigured($method = 'stripe')
759 {
760 $settings = get_option('fluent_booking_payment_settings_' . $method, []);
761
762 return Arr::get($settings, 'is_active', 'no') == 'yes';
763 }
764
765 /**
766 * Sanitize form inputs recursively.
767 *
768 * @param $input
769 *
770 * @return mixed $input
771 */
772 public static function fluentbookingSanitizer($input, $attribute = null, $fields = [])
773 {
774 if (is_string($input)) {
775 $element = Arr::get($fields, $attribute . '.element');
776
777 if (in_array($element, ['post_content', 'rich_text_input'])) {
778 return wp_kses_post($input);
779 } elseif ('textarea' === $element) {
780 $input = sanitize_textarea_field($input);
781 } elseif ('input_email' === $element) {
782 $input = strtolower(sanitize_text_field($input));
783 } elseif ('input_url' === $element) {
784 $input = sanitize_url($input);
785 } else {
786 $input = sanitize_text_field($input);
787 }
788 } elseif (is_array($input)) {
789 foreach ($input as $key => &$value) {
790 $attribute = $attribute ? $attribute . '[' . $key . ']' : $key;
791
792 $value = self::fluentbookingSanitizer($value, $attribute, $fields);
793
794 $attribute = null;
795 }
796 }
797
798 return $input;
799 }
800
801 public static function getMeta($group, $objectId, $key, $withModel = false)
802 {
803 $meta = Meta::where('object_type', $group)
804 ->where('object_id', $objectId)
805 ->where('key', $key)
806 ->first();
807
808 if ($meta) {
809 if ($withModel) {
810 return $meta;
811 }
812
813 return $meta->value;
814 }
815
816 return null;
817 }
818
819 public static function updateMeta($group, $objectId, $key, $value)
820 {
821 $meta = self::getMeta($group, $objectId, $key, true);
822
823 if ($meta) {
824 $meta->value = $value;
825 $meta->save();
826 return $meta;
827 }
828
829 return Meta::create([
830 'object_type' => $group,
831 'key' => $key,
832 'object_id' => $objectId,
833 'value' => $value
834 ]);
835 }
836
837 public static function deleteMeta($group, $objectId, $key)
838 {
839 return Meta::where('object_type', $group)
840 ->where('object_id', $objectId)
841 ->where('key', $key)
842 ->delete();
843 }
844
845 public static function getBookingMeta($eventId, $metaKey, $withModel = false)
846 {
847 $bookingMeta = BookingMeta::where('booking_id', $eventId)
848 ->where('meta_key', $metaKey)
849 ->first();
850
851 if ($bookingMeta) {
852 return $withModel ? $bookingMeta : $bookingMeta->value;
853 }
854
855 return null;
856 }
857
858 public static function updateBookingMeta($eventId, $metaKey, $value)
859 {
860 $bookingMeta = self::getBookingMeta($eventId, $metaKey, true);
861
862 if ($bookingMeta) {
863 $bookingMeta->value = $value;
864 $bookingMeta->save();
865 return $bookingMeta;
866 }
867
868 return BookingMeta::create([
869 'booking_id' => $eventId,
870 'meta_key' => $metaKey, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
871 'value' => $value
872 ]);
873 }
874
875 public static function getUserDisplayName($userId = null)
876 {
877 if (!$userId) {
878 $userId = get_current_user_id();
879 }
880
881 if (!$userId) {
882 return '';
883 }
884
885 $user = get_user_by('ID', $userId);
886
887 $name = trim($user->first_name . ' ' . $user->last_name);
888
889 if ($name) {
890 return $name;
891 }
892
893 return $user->display_name;
894 }
895
896 public static function getUserEmail($userId = null)
897 {
898 $userId = $userId ?: get_current_user_id();
899
900 if (!$userId) {
901 return '';
902 }
903
904 $user = get_user_by('ID', $userId);
905
906 return $user->user_email;
907 }
908
909 public static function excerpt($text, $max_length = 160)
910 {
911 // Strip HTML tags and convert entities to their corresponding characters
912 $text = html_entity_decode(wp_strip_all_tags($text));
913
914 // Remove any line breaks, tabs, or extra whitespace
915 $text = preg_replace('/\s+/', ' ', trim($text));
916
917 if (mb_strlen($text) > $max_length) {
918 $text = mb_substr($text, 0, $max_length);
919 $text = preg_replace('/\s+\S+$/', '', $text) . '...';
920 }
921
922 return $text;
923 }
924
925 public static function generateSlotSlug($default, $calendar)
926 {
927 $original = sanitize_title($default, $default, 'display');
928
929 $default = $original;
930
931 $counter = 1;
932
933 while (CalendarSlot::where('calendar_id', $calendar->id)->where('slug', $default)->first()) {
934 $default = $original . '-' . $counter;
935 $counter += 1;
936 }
937
938 return apply_filters('fluent_booking/slot_slug', $default, $original);
939 }
940
941 public static function getIp()
942 {
943 $server = $_SERVER;
944
945 $ipSources = [
946 'clientIp' => Arr::get($server, 'HTTP_CLIENT_IP'),
947 'xForwarded' => Arr::get($server, 'HTTP_X_FORWARDED_FOR'),
948 'serverAddr' => Arr::get($server, 'SERVER_ADDR')
949 ];
950
951 $ip = '';
952 foreach ($ipSources as $source) {
953 if (!empty($source) && filter_var($source, FILTER_VALIDATE_IP)) {
954 $ip = $source;
955 break;
956 }
957 }
958
959 return sanitize_text_field($ip);
960 }
961
962 public static function fcal_sanitize_html($html)
963 {
964 if (!$html) {
965 return $html;
966 }
967
968 // Return $html if it's just a plain text
969 if (!preg_match('/<[^>]*>/', $html)) {
970 return $html;
971 }
972
973 $tags = wp_kses_allowed_html('post');
974 $tags['style'] = [
975 'types' => [],
976 ];
977 // iframe
978 $tags['iframe'] = [
979 'width' => [],
980 'height' => [],
981 'src' => [],
982 'srcdoc' => [],
983 'title' => [],
984 'frameborder' => [],
985 'allow' => [],
986 'class' => [],
987 'id' => [],
988 'allowfullscreen' => [],
989 'style' => [],
990 ];
991 //button
992 $tags['button']['onclick'] = [];
993
994 //svg
995 if (empty($tags['svg'])) {
996 $svg_args = [
997 'svg' => [
998 'class' => true,
999 'aria-hidden' => true,
1000 'aria-labelledby' => true,
1001 'role' => true,
1002 'xmlns' => true,
1003 'width' => true,
1004 'height' => true,
1005 'viewbox' => true,
1006 ],
1007 'g' => ['fill' => true],
1008 'title' => ['title' => true],
1009 'path' => [
1010 'd' => true,
1011 'fill' => true,
1012 'transform' => true,
1013 ],
1014 ];
1015 $tags = array_merge($tags, $svg_args);
1016 }
1017
1018 $tags = apply_filters('fluent_booking/allowed_html_tags', $tags);
1019
1020 return wp_kses($html, $tags);
1021 }
1022
1023 /**
1024 * Sanitize inputs recursively.
1025 *
1026 * @param array $input
1027 * @param array $sanitizeMap
1028 *
1029 * @return array $input
1030 */
1031 public static function fcal_backend_sanitizer($inputs, $sanitizeMap = [])
1032 {
1033 $originalValues = $inputs;
1034 foreach ($inputs as $key => &$value) {
1035 if (is_array($value)) {
1036 $value = self::fcal_backend_sanitizer($value, $sanitizeMap);
1037 } else {
1038 $method = Arr::get($sanitizeMap, $key);
1039 if (!$method) {
1040 continue;
1041 }
1042 if (is_callable($method)) {
1043 $value = call_user_func($method, $value);
1044 } elseif (method_exists(self::class, $method)) {
1045 $value = call_user_func([self::class, $method], $value);
1046 }
1047 }
1048 }
1049
1050 return apply_filters('fluent_booking/backend_sanitized_values', $inputs, $originalValues);
1051 }
1052
1053 /**
1054 * Recursively implode a multi-dimentional array
1055 *
1056 * @param string $glue
1057 * @param array $array
1058 *
1059 * @return string
1060 */
1061 public static function fcalImplodeRecursive($glue, array $array)
1062 {
1063 $fn = function ($glue, array $array) use (&$fn) {
1064 $result = '';
1065 foreach ($array as $item) {
1066 if (is_array($item)) {
1067 $result .= $fn($glue, $item);
1068 } else {
1069 $result .= $glue . $item;
1070 }
1071 }
1072
1073 return $result;
1074 };
1075
1076 return ltrim($fn($glue, $array), $glue);
1077 }
1078
1079 public static function getEventColors()
1080 {
1081 return apply_filters('fluent_booking/event_colors', [
1082 [
1083 'label' => __('Red-Orange', 'fluent-booking'),
1084 'value' => '#ff4f00'
1085 ],
1086 [
1087 'label' => __('Deep Lilac', 'fluent-booking'),
1088 'value' => '#e55cff'
1089 ],
1090 [
1091 'label' => __('Purple', 'fluent-booking'),
1092 'value' => '#8247f5'
1093 ],
1094 [
1095 'label' => __('Vivid Blue', 'fluent-booking'),
1096 'value' => '#0099ff'
1097 ],
1098 [
1099 'label' => __('Cyan', 'fluent-booking'),
1100 'value' => '#0ae8f0'
1101 ],
1102 [
1103 'label' => __('Emerald Green', 'fluent-booking'),
1104 'value' => '#17e885'
1105 ],
1106 [
1107 'label' => __('Lime Green', 'fluent-booking'),
1108 'value' => '#ccf000'
1109 ],
1110 [
1111 'label' => __('Amber', 'fluent-booking'),
1112 'value' => '#ffa600'
1113 ]
1114 ]);
1115 }
1116
1117 public static function getMeetingDurations()
1118 {
1119 return apply_filters('fluent_booking/meeting_durations_schema', [
1120 [
1121 'value' => '15',
1122 'label' => __('15 Minutes', 'fluent-booking')
1123 ],
1124 [
1125 'value' => '30',
1126 'label' => __('30 Minutes', 'fluent-booking')
1127 ],
1128 [
1129 'value' => '45',
1130 'label' => __('45 Minutes', 'fluent-booking')
1131 ],
1132 [
1133 'value' => '60',
1134 'label' => __('60 Minutes', 'fluent-booking')
1135 ],
1136 [
1137 'value' => 'custom',
1138 'label' => __('Custom', 'fluent-booking')
1139 ]
1140 ]);
1141 }
1142
1143 public static function getMeetingMultiDurations()
1144 {
1145 return apply_filters('fluent_booking/meeting_multi_durations_schema', [
1146 [
1147 'value' => '5',
1148 'label' => __('5 Minutes', 'fluent-booking')
1149 ],
1150 [
1151 'value' => '10',
1152 'label' => __('10 Minutes', 'fluent-booking')
1153 ],
1154 [
1155 'value' => '15',
1156 'label' => __('15 Minutes', 'fluent-booking')
1157 ],
1158 [
1159 'value' => '30',
1160 'label' => __('30 Minutes', 'fluent-booking')
1161 ],
1162 [
1163 'value' => '45',
1164 'label' => __('45 Minutes', 'fluent-booking')
1165 ],
1166 [
1167 'value' => '50',
1168 'label' => __('50 Minutes', 'fluent-booking')
1169 ],
1170 [
1171 'value' => '60',
1172 'label' => __('60 Minutes', 'fluent-booking')
1173 ],
1174 [
1175 'value' => '90',
1176 'label' => __('90 Minutes', 'fluent-booking')
1177 ],
1178 [
1179 'value' => '120',
1180 'label' => __('120 Minutes', 'fluent-booking')
1181 ],
1182 [
1183 'value' => '150',
1184 'label' => __('150 Minutes', 'fluent-booking')
1185 ],
1186 [
1187 'value' => '180',
1188 'label' => __('180 Minutes', 'fluent-booking')
1189 ],
1190 [
1191 'value' => '240',
1192 'label' => __('240 Minutes', 'fluent-booking')
1193 ],
1194 [
1195 'value' => '480',
1196 'label' => __('480 Minutes', 'fluent-booking')
1197 ]
1198 ]);
1199 }
1200
1201 public static function getDurationLookup($multiDuration = false)
1202 {
1203 $durations = $multiDuration ? self::getMeetingMultiDurations() : self::getMeetingDurations();
1204
1205 $durationLookup = [];
1206 foreach ($durations as $duration) {
1207 $durationLookup[$duration['value']] = $duration['label'];
1208 }
1209
1210 return $durationLookup;
1211 }
1212
1213 public static function formatDuration($totalMinutes)
1214 {
1215 $days = floor($totalMinutes / 1440); // 1440 minutes in a day
1216 $hours = floor(($totalMinutes % 1440) / 60);
1217 $minutes = $totalMinutes % 60;
1218
1219 $formattedDuration = [];
1220 if ($days > 0) {
1221 $unit = $days > 1 ? __('Days', 'fluent-booking') : __('Day', 'fluent-booking');
1222 $formattedDuration[] = $days . ' ' . $unit;
1223 }
1224
1225 if ($hours > 0) {
1226 $unit = $hours > 1 ? __('Hours', 'fluent-booking') : __('Hour', 'fluent-booking');
1227 $formattedDuration[] = $hours . ' ' . $unit;
1228 }
1229
1230 if ($minutes > 0 || empty($formattedDuration)) {
1231 $unit = $minutes > 1 ? __('Minutes', 'fluent-booking') : __('Minute', 'fluent-booking');
1232 $formattedDuration[] = $minutes . ' ' . $unit;
1233 }
1234
1235 return implode(' ', $formattedDuration);
1236 }
1237
1238 public static function getBufferTimes()
1239 {
1240 return apply_filters('fluent_booking/buffer_times_schema', [
1241 [
1242 'value' => '0',
1243 'label' => __('No buffer time', 'fluent-booking')
1244 ],
1245 [
1246 'value' => '5',
1247 'label' => __('5 Minutes', 'fluent-booking')
1248 ],
1249 [
1250 'value' => '10',
1251 'label' => __('10 Minutes', 'fluent-booking')
1252 ],
1253 [
1254 'value' => '15',
1255 'label' => __('15 Minutes', 'fluent-booking')
1256 ],
1257 [
1258 'value' => '20',
1259 'label' => __('20 Minutes', 'fluent-booking')
1260 ],
1261 [
1262 'value' => '30',
1263 'label' => __('30 Minutes', 'fluent-booking')
1264 ],
1265 [
1266 'value' => '45',
1267 'label' => __('45 Minutes', 'fluent-booking')
1268 ],
1269 [
1270 'value' => '60',
1271 'label' => __('60 Minutes', 'fluent-booking')
1272 ],
1273 [
1274 'value' => '90',
1275 'label' => __('90 Minutes', 'fluent-booking')
1276 ],
1277 [
1278 'value' => '120',
1279 'label' => __('120 Minutes', 'fluent-booking')
1280 ]
1281 ]);
1282 }
1283
1284 public static function getSlotIntervals()
1285 {
1286 return apply_filters('fluent_booking/slot_intervals_schema', [
1287 [
1288 'value' => '',
1289 'label' => __('Use event length (default)', 'fluent-booking')
1290 ],
1291 [
1292 'value' => '5',
1293 'label' => __('5 Minutes', 'fluent-booking')
1294 ],
1295 [
1296 'value' => '10',
1297 'label' => __('10 Minutes', 'fluent-booking')
1298 ],
1299 [
1300 'value' => '15',
1301 'label' => __('15 Minutes', 'fluent-booking')
1302 ],
1303 [
1304 'value' => '20',
1305 'label' => __('20 Minutes', 'fluent-booking')
1306 ],
1307 [
1308 'value' => '30',
1309 'label' => __('30 Minutes', 'fluent-booking')
1310 ],
1311 [
1312 'value' => '45',
1313 'label' => __('45 Minutes', 'fluent-booking')
1314 ],
1315 [
1316 'value' => '60',
1317 'label' => __('60 Minutes', 'fluent-booking')
1318 ],
1319 [
1320 'value' => '75',
1321 'label' => __('75 Minutes', 'fluent-booking')
1322 ],
1323 [
1324 'value' => '90',
1325 'label' => __('90 Minutes', 'fluent-booking')
1326 ],
1327 [
1328 'value' => '105',
1329 'label' => __('105 Minutes', 'fluent-booking')
1330 ],
1331 [
1332 'value' => '120',
1333 'label' => __('120 Minutes', 'fluent-booking')
1334 ]
1335 ]);
1336 }
1337
1338 public static function getBookingStatusChangingTimes()
1339 {
1340 return apply_filters('fluent_booking/booking_status_changing_times_schema', [
1341 [
1342 'value' => '5',
1343 'label' => __('5 Minutes', 'fluent-booking')
1344 ],
1345 [
1346 'value' => '10',
1347 'label' => __('10 Minutes', 'fluent-booking')
1348 ],
1349 [
1350 'value' => '20',
1351 'label' => __('20 Minutes', 'fluent-booking')
1352 ],
1353 [
1354 'value' => '30',
1355 'label' => __('30 Minutes', 'fluent-booking')
1356 ],
1357 [
1358 'value' => '40',
1359 'label' => __('40 Minutes', 'fluent-booking')
1360 ],
1361 [
1362 'value' => '50',
1363 'label' => __('50 Minutes', 'fluent-booking')
1364 ],
1365 [
1366 'value' => '60',
1367 'label' => __('1 Hour', 'fluent-booking')
1368 ],
1369 [
1370 'value' => '120',
1371 'label' => __('2 Hours', 'fluent-booking')
1372 ],
1373 [
1374 'value' => '180',
1375 'label' => __('3 Hours', 'fluent-booking')
1376 ],
1377 [
1378 'value' => '360',
1379 'label' => __('6 Hours', 'fluent-booking')
1380 ],
1381 [
1382 'value' => '720',
1383 'label' => __('12 Hours', 'fluent-booking')
1384 ],
1385 [
1386 'value' => '1440',
1387 'label' => __('1 Day', 'fluent-booking')
1388 ],
1389 [
1390 'value' => '2880',
1391 'label' => __('2 Days', 'fluent-booking')
1392 ]
1393 ]);
1394 }
1395
1396 public static function getBookingPeriodOptions()
1397 {
1398 return apply_filters('fluent_booking/booking_period_options', [
1399 'upcoming' => __('Upcoming', 'fluent-booking'),
1400 'completed' => __('Completed', 'fluent-booking'),
1401 'pending' => __('Pending', 'fluent-booking'),
1402 'cancelled' => __('Cancelled', 'fluent-booking'),
1403 'all' => __('All', 'fluent-booking'),
1404 ]);
1405 }
1406
1407 public static function getWeekSelectTimes()
1408 {
1409 return apply_filters('fluent_booking/week_select_times_schema', [
1410 'start' => '00:00',
1411 'step' => '00:15',
1412 'end' => '23:45'
1413 ]);
1414 }
1415
1416 public static function getOverrideSelectTimes()
1417 {
1418 return apply_filters('fluent_booking/override_select_times_schema', [
1419 'start' => '00:00',
1420 'step' => '00:15',
1421 'end' => '23:45'
1422 ]);
1423 }
1424
1425 public static function getWeeklyScheduleSchema()
1426 {
1427 return apply_filters('fluent_booking/weekly_schedule_schema', [
1428 'sun' => [
1429 'enabled' => false,
1430 'slots' => []
1431 ],
1432 'mon' => [
1433 'enabled' => true,
1434 'slots' => [
1435 ['start' => '09:00', 'end' => '17:00']
1436 ],
1437 ],
1438 'tue' => [
1439 'enabled' => true,
1440 'slots' => [
1441 ['start' => '09:00', 'end' => '17:00']
1442 ],
1443 ],
1444 'wed' => [
1445 'enabled' => true,
1446 'slots' => [
1447 ['start' => '09:00', 'end' => '17:00']
1448 ],
1449 ],
1450 'thu' => [
1451 'enabled' => true,
1452 'slots' => [
1453 ['start' => '09:00', 'end' => '17:00']
1454 ],
1455 ],
1456 'fri' => [
1457 'enabled' => true,
1458 'slots' => [
1459 ['start' => '09:00', 'end' => '17:00']
1460 ],
1461 ],
1462 'sat' => [
1463 'enabled' => false,
1464 'slots' => []
1465 ],
1466 ]);
1467 }
1468
1469 public static function getCustomFieldTypes()
1470 {
1471 return apply_filters('fluent_booking/custom_fields_types', [
1472 [
1473 'value' => 'email',
1474 'label' => __('Email', 'fluent-booking')
1475 ],
1476 [
1477 'value' => 'text',
1478 'label' => __('Text', 'fluent-booking')
1479 ],
1480 [
1481 'value' => 'textarea',
1482 'label' => __('Textarea', 'fluent-booking')
1483 ],
1484 [
1485 'value' => 'number',
1486 'label' => __('Number', 'fluent-booking')
1487 ],
1488 [
1489 'value' => 'phone',
1490 'label' => __('Phone', 'fluent-booking')
1491 ],
1492 [
1493 'value' => 'radio',
1494 'label' => __('Radio', 'fluent-booking')
1495 ],
1496 [
1497 'value' => 'dropdown',
1498 'label' => __('Select', 'fluent-booking')
1499 ],
1500 [
1501 'value' => 'multi-select',
1502 'label' => __('Multi Select', 'fluent-booking')
1503 ],
1504 [
1505 'value' => 'checkbox',
1506 'label' => __('Checkbox', 'fluent-booking')
1507 ],
1508 [
1509 'value' => 'checkbox-group',
1510 'label' => __('Checkbox Group', 'fluent-booking')
1511 ],
1512 [
1513 'value' => 'date',
1514 'label' => __('Date', 'fluent-booking')
1515 ],
1516 [
1517 'value' => 'file',
1518 'label' => __('File', 'fluent-booking')
1519 ],
1520 [
1521 'value' => 'hidden',
1522 'label' => __('Hidden', 'fluent-booking')
1523 ],
1524 [
1525 'value' => 'terms-and-conditions',
1526 'label' => __('Terms & Conditions', 'fluent-booking')
1527 ]
1528 ]);
1529 }
1530
1531 public static function getDefaultTermsAndConditions()
1532 {
1533 $termsAndConditions = __('I have read and agree to the <a href="#" target="_blank" rel="noopener">Terms and Conditions</a> and <a href="#" target="_blank" rel="noopener">Privacy Policy</a>.', 'fluent-booking');
1534
1535 return apply_filters('fluent_booking/default_terms_and_conditions', $termsAndConditions);
1536 }
1537
1538 public static function getDefaultEmailNotificationSettings()
1539 {
1540 $assetUrl = App::getInstance()['url.assets'];
1541
1542 $checkImage = $assetUrl . 'images/check-mark.png';
1543 $cancelImage = $assetUrl . 'images/cancel-mark.png';
1544 $scheduleImage = $assetUrl . 'images/schedule-mark.png';
1545
1546 return apply_filters('fluent_booking/default_email_notification_settings', [
1547 'booking_conf_attendee' => [
1548 'enabled' => true,
1549 'title' => __('Booking Confirmation Email to Attendee', 'fluent-booking'),
1550 'email' => [
1551 'subject' => 'Booking Confirmation between {{host.name}} & {{guest.full_name}}',
1552 '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)
1553 ],
1554 ],
1555 'booking_conf_host' => [
1556 'enabled' => true,
1557 'is_host' => true,
1558 'title' => __('Booking Confirmation Email to Organizer (You)', 'fluent-booking'),
1559 'email' => [
1560 'additional_recipients' => '',
1561 'subject' => 'New Booking: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1562 '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>'
1563 ],
1564 ],
1565 'reminder_to_attendee' => [
1566 'enabled' => false,
1567 'title' => __('Configure Meeting Reminder to Attendee', 'fluent-booking'),
1568 'email' => [
1569 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_attendee}}',
1570 '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>',
1571 'times' => [
1572 [
1573 'unit' => 'minutes',
1574 'value' => 15,
1575 ]
1576 ]
1577 ],
1578 ],
1579 'reminder_to_host' => [
1580 'enabled' => false,
1581 'is_host' => true,
1582 'title' => __('Configure Meeting Reminder to Organizer (You)', 'fluent-booking'),
1583 'email' => [
1584 'additional_recipients' => '',
1585 'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_host}}',
1586 '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>',
1587 'times' => [
1588 [
1589 'unit' => 'minutes',
1590 'value' => 15,
1591 ]
1592 ]
1593 ],
1594 ],
1595 'cancelled_by_attendee' => [
1596 'enabled' => true,
1597 'is_host' => true,
1598 'title' => __('Booking Cancelled by Attendee (email to Organizer)', 'fluent-booking'),
1599 'email' => [
1600 'additional_recipients' => '',
1601 'subject' => 'A booking was cancelled with {{guest.full_name}}',
1602 '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>'
1603 ],
1604 ],
1605 'cancelled_by_host' => [
1606 'enabled' => true,
1607 'title' => __('Booking Cancelled by Organizer (email to Attendee)', 'fluent-booking'),
1608 'email' => [
1609 'subject' => 'Your booking was cancelled with {{host.name}}',
1610 '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>'
1611 ],
1612 ],
1613 'rescheduled_by_attendee' => [
1614 'enabled' => true,
1615 'is_host' => true,
1616 'title' => __('Booking Rescheduled by Attendee (email to Organizer)', 'fluent-booking'),
1617 'email' => [
1618 'additional_recipients' => '',
1619 'subject' => 'A booking was rescheduled with {{guest.full_name}}',
1620 '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>'
1621 ],
1622 ],
1623 'rescheduled_by_host' => [
1624 'enabled' => true,
1625 'title' => __('Booking Rescheduled by Organizer (email to Attendee)', 'fluent-booking'),
1626 'email' => [
1627 'subject' => 'Your booking was rescheduled with {{host.name}}',
1628 '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_guest_timezone}}</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)
1629 ],
1630 ],
1631 'booking_request_host' => [
1632 'enabled' => true,
1633 'is_host' => true,
1634 'title' => __('Booking Approval Request to Host (email to Organizer)', 'fluent-booking'),
1635 'email' => [
1636 'additional_recipients' => '',
1637 'subject' => 'Awaiting Approval: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
1638 '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>'
1639 ],
1640 ],
1641 'booking_request_attendee' => [
1642 'enabled' => true,
1643 'title' => __('Booking Submission Confirmation (email to Attendee)', 'fluent-booking'),
1644 'email' => [
1645 'subject' => 'Booking Submitted: Meeting between {{host.name}} & {{guest.full_name}}',
1646 '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>'
1647 ],
1648 ],
1649 'declined_by_host' => [
1650 'enabled' => true,
1651 'title' => __('Booking Declined by Organizer (email to Attendee)', 'fluent-booking'),
1652 'email' => [
1653 'subject' => 'Booking Declined: Your booking was declined with {{host.name}}',
1654 '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>'
1655 ],
1656 ],
1657 ]);
1658 }
1659
1660 public static function getAddToCalendarHtml($assetUrl = '')
1661 {
1662 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1663
1664 $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>';
1665
1666 return apply_filters('fluent_booking/add_to_calendar_html', $html);
1667 }
1668
1669 public static function getConfirmAndRejectButton($assetUrl = '')
1670 {
1671 $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];
1672
1673 $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>';
1674
1675 return apply_filters('fluent_booking/confirm_and_reject_button_html', $html);
1676 }
1677
1678 public static function getIframeHtml()
1679 {
1680 $html = '<iframe id="fluentbooking" loading="lazy" height="700px" width="100%" style="min-width:320px;height:700px;" frameborder="0" src="##landing_page_url##"></iframe>';
1681
1682 return apply_filters('fluent_booking/get_iframe_html', $html);
1683 }
1684
1685 public static function getEditorShortCodes($calendarEvent = null, $isHtmlSupported = false, $iframeHtml = '')
1686 {
1687 if (!$isHtmlSupported) {
1688 $groups = [
1689 'guest' => [
1690 'title' => __('Attendee Data', 'fluent-booking'),
1691 'key' => 'guest',
1692 'shortcodes' => [
1693 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1694 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1695 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1696 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1697 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1698 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1699 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking'),
1700 '{{guest.total_guest}}' => __('Total Guest Count', 'fluent-booking')
1701 ]
1702 ],
1703 'booking' => [
1704 'title' => __('Booking Data', 'fluent-booking'),
1705 'key' => 'booking',
1706 'shortcodes' => [
1707 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1708 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1709 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1710 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1711 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1712 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1713 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1714 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1715 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1716 '{{booking.start_date_time_for_attendee}}' => __('Event Date Time (with attendee timezone)', 'fluent-booking'),
1717 '{{booking.start_date_time_for_host}}' => __('Event Date Time (with host timezone)', 'fluent-booking'),
1718 '{{booking.start_date_time_for_attendee.format.Y-m-d}}' => __('Event Date Time (with attendee timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1719 '{{booking.start_date_time_for_host.format.Y-m-d}}' => __('Event Date Time (with host timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1720 '{{booking.location_details_text}}' => __('Event Location Details', 'fluent-booking'),
1721 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1722 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1723 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1724 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1725 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1726 '{{booking.utm_source}}' => __('UTM Source', 'fluent-booking'),
1727 '{{booking.utm_medium}}' => __('UTM Medium', 'fluent-booking'),
1728 '{{booking.utm_campaign}}' => __('UTM Campaign', 'fluent-booking'),
1729 '{{booking.utm_term}}' => __('UTM Term', 'fluent-booking'),
1730 '{{booking.utm_content}}' => __('UTM Content', 'fluent-booking'),
1731 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1732 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking'),
1733 '{{booking.previous_meeting_date_time_host_timezone}}' => __('Previous Meeting Date & Time (with host timezone)', 'fluent-booking'),
1734 '{{booking.previous_meeting_date_time_guest_timezone}}' => __('Previous Meeting Date & Time (with guest timezone)', 'fluent-booking'),
1735 ]
1736 ],
1737 'host' => [
1738 'title' => __('Host Data', 'fluent-booking'),
1739 'key' => 'host',
1740 'shortcodes' => [
1741 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1742 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1743 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1744 ]
1745 ],
1746 'other' => [
1747 'title' => __('Other', 'fluent-booking'),
1748 'key' => 'other',
1749 'shortcodes' => [
1750 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1751 '{{calendar.id}}' => __('Calendar ID', 'fluent-booking'),
1752 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1753 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1754 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1755 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1756 ]
1757 ]
1758 ];
1759 } else {
1760 $groups = [
1761 'guest' => [
1762 'title' => __('Attendee Data', 'fluent-booking'),
1763 'key' => 'guest',
1764 'shortcodes' => [
1765 '{{guest.first_name}}' => __('Guest First Name', 'fluent-booking'),
1766 '{{guest.last_name}}' => __('Guest Last Name', 'fluent-booking'),
1767 '{{guest.full_name}}' => __('Guest Full Name', 'fluent-booking'),
1768 '{{guest.email}}' => __('Guest Email', 'fluent-booking'),
1769 '{{booking.phone}}' => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
1770 '{{guest.note}}' => __('Guest Note', 'fluent-booking'),
1771 '{{guest.timezone}}' => __('Guest Timezone', 'fluent-booking'),
1772 '{{guest.total_guest}}' => __('Total Guest Count', 'fluent-booking'),
1773 '{{guest.form_data_html}}' => __('Guest Form Submitted Data (HTML)', 'fluent-booking')
1774 ]
1775 ],
1776 'booking' => [
1777 'title' => __('Booking Data', 'fluent-booking'),
1778 'key' => 'booking',
1779 'shortcodes' => [
1780 '{{booking.event_name}}' => __('Event Name', 'fluent-booking'),
1781 '{{booking.description}}' => __('Event Description', 'fluent-booking'),
1782 '{{booking.booking_title}}' => __('Booking Title', 'fluent-booking'),
1783 '{{booking.additional_guests}}' => __('Additional Guests', 'fluent-booking'),
1784 '{{booking.full_start_end_guest_timezone}}' => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
1785 '{{booking.full_start_end_host_timezone}}' => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
1786 '{{booking.full_start_and_end_guest_timezone}}' => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
1787 '{{booking.full_start_and_end_host_timezone}}' => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
1788 '{{booking.start_date_time}}' => __('Event Date Time (UTC)', 'fluent-booking'),
1789 '{{booking.start_date_time_for_attendee}}' => __('Event Date time (with guest timezone)', 'fluent-booking'),
1790 '{{booking.start_date_time_for_host}}' => __('Event Date time (with host timezone)', 'fluent-booking'),
1791 '{{booking.start_date_time_for_attendee.format.Y-m-d}}' => __('Event Date Time (with attendee timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1792 '{{booking.start_date_time_for_host.format.Y-m-d}}' => __('Event Date Time (with host timezone) (Ex: 2024-05-20)', 'fluent-booking'),
1793 '{{booking.location_details_html}}' => __('Event Location Details (HTML)', 'fluent-booking'),
1794 '{{booking.cancel_reason}}' => __('Event Cancel Reason', 'fluent-booking'),
1795 '{{booking.start_time_human_format}}' => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
1796 '##booking.cancelation_url##' => __('Booking Cancellation URL', 'fluent-booking'),
1797 '##booking.reschedule_url##' => __('Booking Reschedule URL', 'fluent-booking'),
1798 '##booking.admin_booking_url##' => __('Booking Details Admin URL', 'fluent-booking'),
1799 '{{booking.utm_source}}' => __('UTM Source', 'fluent-booking'),
1800 '{{booking.utm_medium}}' => __('UTM Medium', 'fluent-booking'),
1801 '{{booking.utm_campaign}}' => __('UTM Campaign', 'fluent-booking'),
1802 '{{booking.utm_term}}' => __('UTM Term', 'fluent-booking'),
1803 '{{booking.utm_content}}' => __('UTM Content', 'fluent-booking'),
1804 '{{booking.booking_hash}}' => __('Unique Booking Hash', 'fluent-booking'),
1805 '{{booking.reschedule_reason}}' => __('Event Reschedule Reason', 'fluent-booking'),
1806 '{{booking.previous_meeting_date_time_host_timezone}}' => __('Previous Meeting Date & Time (with host timezone)', 'fluent-booking'),
1807 '{{booking.previous_meeting_date_time_guest_timezone}}' => __('Previous Meeting Date & Time (with guest timezone)', 'fluent-booking'),
1808 ]
1809 ],
1810 'host' => [
1811 'title' => __('Host Data', 'fluent-booking'),
1812 'key' => 'host',
1813 'shortcodes' => [
1814 '{{host.name}}' => __('Host Name', 'fluent-booking'),
1815 '{{host.email}}' => __('Host Email', 'fluent-booking'),
1816 '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
1817 ]
1818 ],
1819 'other' => [
1820 'title' => __('Other', 'fluent-booking'),
1821 'key' => 'other',
1822 'shortcodes' => [
1823 '{{event.id}}' => __('Event ID', 'fluent-booking'),
1824 '{{event.calendar_id}}' => __('Calendar ID', 'fluent-booking'),
1825 '{{event.title}}' => __('Event Title', 'fluent-booking'),
1826 '{{calendar.title}}' => __('Calendar Title', 'fluent-booking'),
1827 '{{calendar.description}}' => __('Calendar Description', 'fluent-booking'),
1828 '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
1829 ]
1830 ]
1831 ];
1832 }
1833
1834 if ($calendarEvent) {
1835 $customFields = BookingFieldService::getCustomFields($calendarEvent, true);
1836 foreach ($customFields as $fieldKey => $field) {
1837 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '}}'] = $field['label'];
1838 if ($field['type'] == 'date') {
1839 $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '.format.Y-m-d}}'] = $field['label'] . ' (Ex: 2024-05-20)';
1840 }
1841 }
1842
1843 if (Helper::isPaymentEnabled($calendarEvent)) {
1844 $groups['payment'] = [
1845 'title' => __('Payment Data', 'fluent-booking'),
1846 'key' => 'payment',
1847 'shortcodes' => [
1848 '{{payment.payment_total}}' => __('Payment Total', 'fluent-booking'),
1849 '{{payment.payment_status}}' => __('Payment Status', 'fluent-booking'),
1850 '{{payment.payment_method}}' => __('Payment Method', 'fluent-booking'),
1851 '{{payment.currency}}' => __('Currency', 'fluent-booking'),
1852 '{{payment.payment_date}}' => __('Payment Date', 'fluent-booking'),
1853 ]
1854 ];
1855
1856 if ($isHtmlSupported) {
1857 $groups['payment']['shortcodes']['{{payment.receipt_html}}'] = __('Payment Receipt (HTML)', 'fluent-booking');
1858 }
1859 }
1860
1861 if ($calendarEvent->isMultiHostsEvent()) {
1862 $totalhost = count($calendarEvent->getHostIds());
1863 for ($i = 1; $i < $totalhost; $i++) {
1864 $groups['host']['shortcodes']['{{team_member.' . $i . '.name}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Name', 'fluent-booking');
1865 $groups['host']['shortcodes']['{{team_member.' . $i . '.email}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Email', 'fluent-booking');
1866 }
1867 }
1868 }
1869
1870 return apply_filters('fluent_booking/editor_shortcodes_groups', $groups, $calendarEvent, $isHtmlSupported);
1871 }
1872
1873 public static function encryptKey($value)
1874 {
1875 if (!$value) {
1876 return $value;
1877 }
1878
1879 if (!extension_loaded('openssl')) {
1880 return $value;
1881 }
1882
1883 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1884
1885 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1886 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1887 } else {
1888 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1889 }
1890
1891 $method = 'aes-256-ctr';
1892 $ivlen = openssl_cipher_iv_length($method);
1893 $iv = openssl_random_pseudo_bytes($ivlen);
1894
1895 $raw_value = openssl_encrypt($value . $salt, $method, $key, 0, $iv);
1896 if (!$raw_value) {
1897 return false;
1898 }
1899
1900 return base64_encode($iv . $raw_value); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
1901 }
1902
1903 public static function decryptKey($raw_value)
1904 {
1905
1906 if (!$raw_value) {
1907 return $raw_value;
1908 }
1909
1910 if (!extension_loaded('openssl')) {
1911 return $raw_value;
1912 }
1913
1914 $raw_value = base64_decode($raw_value, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
1915
1916 $method = 'aes-256-ctr';
1917 $ivlen = openssl_cipher_iv_length($method);
1918 $iv = substr($raw_value, 0, $ivlen);
1919
1920 $raw_value = substr($raw_value, $ivlen);
1921
1922 if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
1923 $key = FLUENT_BOOKING_ENCRYPTION_KEY;
1924 } else {
1925 $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
1926 }
1927
1928 $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';
1929
1930 $value = openssl_decrypt($raw_value, $method, $key, 0, $iv);
1931 if (!$value || substr($value, -strlen($salt)) !== $salt) {
1932 return false;
1933 }
1934
1935 return substr($value, 0, -strlen($salt));
1936 }
1937
1938 public static function debugLog($data)
1939 {
1940 if (defined('FLUENT_BOOKING_DEBUG') && FLUENT_BOOKING_DEBUG) {
1941 error_log(print_r($data, true)); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
1942 }
1943 }
1944
1945 public static function getGlobalSettings($settingsKey = null)
1946 {
1947 $defaults = [
1948 'payments' => [
1949 'currency' => 'USD',
1950 'is_active' => 'no'
1951 ],
1952 'emailing' => [
1953 'from_name' => '',
1954 'from_email' => '',
1955 'reply_to_name' => '',
1956 'reply_to_email' => '',
1957 'use_host_name' => '',
1958 'use_host_email_on_reply' => '',
1959 'attach_ics_on_confirmation' => '',
1960 'email_footer' => ''
1961 ],
1962 'administration' => [
1963 'admin_email' => '{{wp.admin_email}}',
1964 'summary_notification' => 'no',
1965 'notification_frequency' => 'daily',
1966 'notification_day' => 'mon',
1967 'start_day' => 'sun',
1968 'auto_cancel_timing' => '10',
1969 'auto_complete_timing' => '60',
1970 'default_phone_country' => ''
1971 ],
1972 'time_format' => '12',
1973 'theme' => 'system-default'
1974 ];
1975
1976 $settings = get_option('_fluent_booking_settings', []);
1977
1978 if (empty($settings)) {
1979 $settings = [];
1980 }
1981
1982 $settings['payments'] = CurrenciesHelper::getGlobalCurrencySettings();
1983
1984 $settings = wp_parse_args($settings, $defaults);
1985
1986 $emailSettings = $settings['emailing'];
1987
1988 if (empty($settings['administration']['auto_cancel_timing'])) {
1989 $settings['administration']['auto_cancel_timing'] = '10';
1990 }
1991
1992 if (empty($settings['administration']['auto_complete_timing'])) {
1993 $settings['administration']['auto_complete_timing'] = '10';
1994 }
1995
1996 if (empty($emailSettings['from_name']) && defined('FLUENTCRM')) {
1997 $crmSettings = fluentcrmGetGlobalSettings('email_settings', []);
1998 $emailSettings['from_name'] = Arr::get($crmSettings, 'from_name');
1999 if (empty($emailSettings['from_email'])) {
2000 $emailSettings['from_email'] = Arr::get($crmSettings, 'from_email');
2001 }
2002 if (empty($emailSettings['reply_to_name'])) {
2003 $emailSettings['reply_to_name'] = Arr::get($crmSettings, 'reply_to_name');
2004 }
2005 if (empty($emailSettings['reply_to_email'])) {
2006 $emailSettings['reply_to_email'] = Arr::get($crmSettings, 'reply_to_email');
2007 }
2008
2009 $settings['emailing'] = $emailSettings;
2010 }
2011
2012 if ($settingsKey) {
2013 return Arr::get($settings, $settingsKey, []);
2014 }
2015
2016 return $settings;
2017
2018 }
2019
2020 public static function getGlobalAdminSetting($key = null, $default = null)
2021 {
2022 static $settings;
2023 if ($settings) {
2024
2025 if ($key) {
2026 return Arr::get($settings, $key, $default);
2027 }
2028
2029 return $settings;
2030 }
2031
2032 $globalSettings = self::getGlobalSettings();
2033 $settings = Arr::get($globalSettings, 'administration', []);
2034
2035 if ($key) {
2036 return Arr::get($settings, $key, $default);
2037 }
2038
2039 return $settings;
2040 }
2041
2042 public static function getDefaultTimeFormat()
2043 {
2044 static $format;
2045
2046 if ($format) {
2047 return $format;
2048 }
2049
2050 $settings = self::getGlobalSettings();
2051 $format = Arr::get($settings, 'time_format', '24');
2052 return $format;
2053 }
2054
2055 public static function getDefaultBookingFilters()
2056 {
2057 return apply_filters('fluent_booking/default_booking_filters', [
2058 'period' => 'upcoming',
2059 'author' => 'me', // me, all, calendar_id
2060 'event' => 'all',
2061 'event_type' => 'all'
2062 ]);
2063 }
2064
2065 public static function getDefaultPaginations()
2066 {
2067 return apply_filters('fluent_booking/default_paginations', [
2068 'bookings' => 10,
2069 'calendars' => 10,
2070 'coupons' => 10,
2071 'availabilities' => 10
2072 ]);
2073 }
2074
2075 public static function getVerifiedSenders()
2076 {
2077 $verifiedSenders = [];
2078 if (defined('FLUENTMAIL')) {
2079 $smtpSettings = get_option('fluentmail-settings', []);
2080 if ($smtpSettings && count($smtpSettings['mappings'])) {
2081 $verifiedSenders = array_keys($smtpSettings['mappings']);
2082 }
2083 }
2084 /**
2085 * Filter the verified email senders
2086 * @param array $verifiedSenders
2087 */
2088 return apply_filters('fluent_booking/verfied_email_senders', $verifiedSenders);
2089 }
2090
2091 public static function getBookingReceiptLandingBaseUrl()
2092 {
2093 return apply_filters('fluent_booking/booking_receipt_landing_base_url', site_url('/'));
2094 }
2095
2096 public static function getGlobalModuleSettings($cached = true)
2097 {
2098 static $settings = null;
2099
2100 if ($cached && $settings !== null) {
2101 return $settings;
2102 }
2103
2104 $settings = get_option('_fluent_booking_enabled_modules', []);
2105
2106 if (empty($settings) || !\is_array($settings)) {
2107 $settings = [];
2108 }
2109
2110 return $settings;
2111 }
2112
2113 public static function updateGlobalModuleSettings($settings = [])
2114 {
2115 if (!is_array($settings)) {
2116 $settings = [];
2117 }
2118
2119 update_option('_fluent_booking_enabled_modules', $settings);
2120
2121 return self::getGlobalModuleSettings(false);
2122 }
2123
2124 public static function isModuleEnabled($module)
2125 {
2126 $settings = self::getGlobalModuleSettings();
2127
2128 return isset($settings[$module]) && $settings[$module] === 'yes';
2129 }
2130
2131 /**
2132 * @return mixed|void
2133 */
2134 public static function fluentbooking_is_rtl()
2135 {
2136 /**
2137 * If FluentBooking is running on RTL Mode
2138 *
2139 * @param bool $is_rtl
2140 */
2141 return apply_filters('fluent_booking/is_rtl', is_rtl());
2142 }
2143
2144 public static function fluentBookingUserAvatar($id_or_email, $args)
2145 {
2146 if (empty($id_or_email)) {
2147 return '';
2148 }
2149 return apply_filters('fluent_booking/author_photo', get_avatar_url($id_or_email), $args);
2150 }
2151
2152 public static function getPrefSettings($cached = true)
2153 {
2154 static $pref = null;
2155
2156 if ($cached && $pref) {
2157 return $pref;
2158 }
2159
2160 $settings = [
2161 'frontend' => [
2162 'enabled' => 'no',
2163 'slug' => 'my-bookings',
2164 'render_type' => 'standalone',
2165 'page_id' => ''
2166 ],
2167 'coupon' => [
2168 'enabled' => 'no'
2169 ]
2170 ];
2171
2172 $storedSettings = get_option('fluent_booking_modules', []);
2173
2174 if ($storedSettings && is_array($storedSettings)) {
2175 $settings = wp_parse_args($storedSettings, $settings);
2176 } else {
2177 update_option('fluent_booking_modules', $settings, 'yes');
2178 }
2179
2180 $pref = $settings;
2181
2182 return $settings;
2183 }
2184
2185 public static function getPrefSettins($cached = true)
2186 {
2187 return self::getPrefSettings($cached);
2188 }
2189
2190 public static function getFeatures()
2191 {
2192 return apply_filters('fluent_booking/get_features', [
2193 'has_fluentcrm' => defined('FLUENTCRM'),
2194 'has_fluentsmtp' => defined('FLUENTMAIL'),
2195 'has_fluentform' => defined('FLUENTFORM'),
2196 'has_fluentboards' => defined('FLUENT_BOARDS'),
2197 'has_fluentcart' => defined('FLUENTCART_VERSION')
2198 ]);
2199 }
2200
2201 public static function getActiveThemeName()
2202 {
2203 $ins = get_option('_fb_ins_by');
2204
2205 if ($ins) {
2206 return sanitize_text_field($ins);
2207 }
2208
2209 return get_option('template');
2210 }
2211 }
2212