PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
← All changes | app/Services/LandingPage/LandingPageHandler.php +77 -51 1.5.20 → 2.5.0 View file →
@@ -6,13 +6,15 @@
6 6 use FluentBooking\App\Hooks\Handlers\FrontEndHandler;
7 7 use FluentBooking\App\Models\Booking;
8 8 use FluentBooking\App\Models\Calendar;
9 9 use FluentBooking\App\Models\CalendarSlot;
10 +use FluentBooking\App\Services\CalendarEventService;
10 11 use FluentBooking\App\Services\BookingFieldService;
11 12 use FluentBooking\App\Services\BookingService;
12 13 use FluentBooking\App\Services\Helper;
13 14 use FluentBooking\Framework\Support\Arr;
14 15 use FluentBooking\Framework\Support\Collection;
16 +use FluentBooking\App\Vite;
15 17
16 18 class LandingPageHandler
17 19 {
18 20 public function boot()
@@ -38,15 +40,23 @@
38 40 }
39 41
40 42 $authorSlug = sanitize_text_field($urlParts[1]);
41 43
44 + if (isset($_GET['embedded'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
45 + $this->handleEmbeddedStyle();
46 + }
47 +
42 48 $this->routeView($authorSlug, Arr::get($urlParts, 2, null));
43 49 }
44 50
45 51 public function handleUrlParamsPage()
46 52 {
47 - $route = sanitize_text_field($_GET['fluent-booking']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
53 + $route = isset($_GET['fluent-booking']) ? sanitize_text_field(wp_unslash($_GET['fluent-booking'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
48 54
55 + if (isset($_GET['embedded'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
56 + $this->handleEmbeddedStyle();
57 + }
58 +
49 59 if ($route == 'booking') {
50 60 $this->handleAfterBookingPage();
51 61 return;
52 62 }
@@ -89,9 +99,9 @@
89 99 ->first();
90 100 if (!$slot) {
91 101 return;
92 102 }
93 - $this->renderBookingView($calendar, $slot);
103 + return $this->renderBookingView($calendar, $slot);
94 104 }
95 105
96 106 $this->renderHostView($calendar);
97 107 }
@@ -102,31 +112,17 @@
102 112 $settings = LandingPageHelper::getSettings($calendar, 'public');
103 113
104 114 $activeEvents = CalendarSlot::where('calendar_id', $calendar->id)
105 115 ->where('status', 'active');
106 -
116 +
107 117 if ($settings['show_type'] != 'all') {
108 118 $activeEvents = $activeEvents->whereIn('id', $settings['enabled_slots']);
109 119 }
110 -
120 +
111 121 $activeEvents = $activeEvents->get();
112 122
113 - $eventOrder = $calendar->getMeta('event_order');
123 + $activeEvents = CalendarEventService::processEvents($calendar, $activeEvents);
114 124
115 - if (!empty($eventOrder)) {
116 - $activeEvents = $activeEvents->sortBy(function($event) use ($eventOrder) {
117 - return array_search($event->id, $eventOrder);
118 - })->values();
119 - }
120 -
121 - foreach ($activeEvents as $activeEvent) {
122 - $activeEvent->payment_html = $activeEvent->getPaymentHtml();
123 - $activeEvent->public_url = $activeEvent->getPublicUrl();
124 - $activeEvent->durations = $activeEvent->getAvailableDurations();
125 - $activeEvent->description = $activeEvent->getDescription();
126 - $activeEvent->short_description = Helper::excerpt($activeEvent->description);
127 - }
128 -
129 125 $metaDescription = Helper::excerpt($calendar->description);
130 126
131 127 $calendar->description = wpautop($calendar->description);
132 128
@@ -155,11 +151,11 @@
155 151 $vars['lazy_js_files'] = $extraJs;
156 152 }
157 153 $jsVars['fcal_public_vars_' . $calendar->id . '_' . $activeEvent->id] = $vars;
158 154 $activeEvent->locations = $activeEvent->defaultLocationHtml();
155 + do_action_ref_array('fluent_booking/landing_page_event', [&$activeEvent]);
159 156 }
160 157
161 - $assetUrl = App::getInstance('url.assets');
162 158 $data = [
163 159 'calendar' => $calendar,
164 160 'events' => $activeEvents,
165 161 'author' => $authorProfile,
@@ -165,17 +161,18 @@
165 161 'author' => $authorProfile,
166 162 'title' => $calendar->title .' - '.get_bloginfo('name'),
167 163 'description' => $metaDescription,
168 164 'url' => home_url($wp->request),
165 + 'embedded' => isset($_GET['embedded']) ? true : false, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
169 166 'css_files' => [
170 - App::getInstance('url.assets') . 'public/saas.css'
167 + Vite::styleUrl('saas_css')
171 168 ],
172 169 'js_files' => [
173 - 'fluent-booking-public-js' => $assetUrl . 'public/js/app.js',
170 + 'fluent-booking-public-js' => Vite::scriptUrl('public_app'),
174 171 ],
175 172 'js_vars' => $jsVars,
176 173 'header_js_files' => [
177 - 'fluent_booking_team_app-js' => $assetUrl. 'public/js/team_app.js'
174 + 'fluent_booking_team_app-js' => Vite::scriptUrl('team_app')
178 175 ]
179 176 ];
180 177
181 178 if ($extraJsFiles) {
@@ -182,8 +179,10 @@
182 179 $extraJsFiles = array_unique($extraJsFiles);
183 180 $data['js_files'] = array_merge($data['js_files'], $extraJsFiles);
184 181 }
185 182
183 + $data = apply_filters('fluent_booking/host_view_page_vars', $data, $calendar, $activeEvents, $authorProfile);
184 +
186 185 $app = App::getInstance();
187 186 status_header(200);
188 187 $app->view->render('landing.author_landing', $data);
189 188 exit(200);
@@ -188,14 +187,16 @@
188 187 $app->view->render('landing.author_landing', $data);
189 188 exit(200);
190 189 }
191 190
192 - private function renderBookingView($calendar, $calendarEvent, $existingBooking = null)
191 + private function renderBookingView($calendar, $calendarEvent, $existingBooking = null, $isReschedule = false)
193 192 {
194 - $settings = LandingPageHelper::getSettings($calendar, 'public');
195 - if ($settings['show_type'] != 'all') {
196 - if (!in_array($calendarEvent->id, $settings['enabled_slots'])) {
197 - return '';
193 + if (!$isReschedule) {
194 + $settings = LandingPageHelper::getSettings($calendar, 'public');
195 + if ($settings['show_type'] != 'all') {
196 + if (!in_array($calendarEvent->id, $settings['enabled_slots'])) {
197 + return '';
198 + }
198 199 }
199 200 }
200 201
201 202 global $wp;
@@ -203,9 +204,9 @@
203 204 $calendarEvent->max_lookup_date = $calendarEvent->getMaxLookUpDate();
204 205 $calendarEvent->min_lookup_date = $calendarEvent->getMinLookUpDate();
205 206
206 207 if (!empty($_REQUEST['booking_id'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
207 - $bookingHash = sanitize_text_field($_REQUEST['booking_id']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
208 + $bookingHash = sanitize_text_field(wp_unslash($_REQUEST['booking_id'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
208 209 $booking = Booking::where('hash', $bookingHash)
209 210 ->where('event_id', $calendarEvent->id)
210 211 ->first();
211 212 if ($booking) {
@@ -227,26 +228,27 @@
227 228 $assetUrl = App::getInstance('url.assets');
228 229
229 230 $eventVars = (new FrontEndHandler())->getCalendarEventVars($calendar, $calendarEvent);
230 231
231 - $isRtl = Helper::fluentbooking_is_rtl();
232 + $publicCss = 'saas_css';
232 233
233 - $publicCss = 'public/saas.css';
234 - if ($isRtl) {
235 - $publicCss = 'public/saas-rtl.css';
236 - }
234 + $title = $calendarEvent->title . ' ' . __('with', 'fluent-booking') . ' ' . $authorProfile['name'];
235 +
236 + $title = apply_filters('fluent_booking/booking_confirmation_page_title', $title, $calendarEvent, $authorProfile);
237 +
237 238 $data = [
238 239 'calendar' => $calendar,
239 240 'calendar_event' => $calendarEvent,
240 241 'author' => $authorProfile,
241 - 'title' => $calendarEvent->title . ' ' . __('with', 'fluent-booking') . ' ' . $authorProfile['name'],
242 + 'title' => $title,
242 243 'description' => substr(strip_shortcodes(wp_strip_all_tags(str_replace(PHP_EOL, ' ', $calendarEvent->description))), 0, 300) . '...',
243 244 'url' => home_url($wp->request),
245 + 'embedded' => isset($_GET['embedded']) ? true : false, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
244 246 'css_files' => [
245 - $assetUrl . $publicCss
247 + Vite::styleUrl($publicCss)
246 248 ],
247 249 'js_files' => [
248 - 'fluent-booking-public-js' => $assetUrl . 'public/js/app.js',
250 + 'fluent-booking-public-js' => Vite::scriptUrl('public_app'),
249 251 ],
250 252 'js_vars' => [
251 253 'fluentCalendarPublicVars' => (new FrontEndHandler())->getGlobalVars(),
252 254 'fcal_public_vars_' . $calendar->id . '_' . $calendarEvent->id => $eventVars,
@@ -280,9 +282,8 @@
280 282
281 283 private function showBookingConfimationPage($booking, $actionType = 'confirmation')
282 284 {
283 285 $validActions = ['confirmation'];
284 - $isRtl = Helper::fluentbooking_is_rtl();
285 286
286 287 if (in_array($booking->status, ['scheduled', 'pending', 'rescheduled'])) {
287 288 $validActions = array_merge($validActions, ['reschedule', 'cancel']);
288 289 }
@@ -303,24 +304,24 @@
303 304 echo $icsText; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
304 305 die();
305 306 }
306 307
308 + global $wp;
309 +
307 310 $calendarEvent = $booking->calendar_event;
308 - global $wp;
311 +
309 312 $responseHtml = BookingService::getBookingConfirmationHtml($booking, $actionType);
310 313
311 314 $authorProfile = $calendarEvent->getAuthorProfile(true);
312 315
313 - $publicCss = 'public/saas_public.css';
314 - if ($isRtl) {
315 - $publicCss = 'public/saas_public-rtl.css';
316 - }
316 + $publicCss = 'saas_public_css';
317 +
317 318 $data = [
318 319 'title' => __('Confirmation: ', 'fluent-booking') . $calendarEvent->title . ' ' . __('with', 'fluent-booking') . ' ' . $authorProfile['name'],
319 320 'body' => $responseHtml,
320 321 'description' => substr(strip_shortcodes(wp_strip_all_tags(str_replace(PHP_EOL, ' ', $calendarEvent->description))), 0, 300) . '...',
321 322 'css_files' => [
322 - App::getInstance('url.assets') . $publicCss
323 + Vite::styleUrl($publicCss)
323 324 ],
324 325 'js_files' => [],
325 326 'js_vars' => [],
326 327 'author' => $authorProfile,
@@ -326,15 +327,23 @@
326 327 'author' => $authorProfile,
327 328 'slot' => $calendarEvent,
328 329 'url' => home_url($wp->request),
329 330 'action_type' => $actionType,
330 - 'theme' => Arr::get(get_option('_fluent_booking_settings'), 'theme','system-default')
331 + 'embedded' => isset($_GET['embedded']) ? true : false, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
332 + 'theme' => Arr::get(get_option('_fluent_booking_settings'), 'theme','system-default'),
333 + 'back_button' => [
334 + 'show' => true,
335 + 'text' => __('Back to home', 'fluent-booking'),
336 + 'url' => site_url('/')
337 + ]
331 338 ];
332 339
333 340 if ($actionType == 'cancel') {
334 - $data['js_files']['fluent-booking-public-manage-meeting-js'] = App::getInstance('url.assets') . 'public/js/public-manage-meeting.js';
341 + $data['js_files']['fluent-booking-public-manage-meeting-js'] = Vite::scriptUrl('manage_meeting');
335 342 }
336 343
344 + $data = apply_filters('fluent_booking/booking_confirmation_page_vars', $data, $booking, $calendarEvent);
345 +
337 346 $app = App::getInstance();
338 347 status_header(200);
339 348 $app->view->render('landing.confirmation_page', $data);
340 349 exit(200);
@@ -341,21 +350,20 @@
341 350 }
342 351
343 352 private function handleAfterBookingPage()
344 353 {
345 - $bookingHash = sanitize_text_field(Arr::get($_REQUEST, 'meeting_hash')); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
346 -
354 + $bookingHash = sanitize_text_field(wp_unslash(Arr::get($_REQUEST, 'meeting_hash'))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
347 355 if (!$bookingHash) {
348 356 return;
349 357 }
350 358
351 359 $booking = Booking::where('hash', $bookingHash)->first();
352 -
353 360 if (!$booking) {
354 361 return;
355 362 }
356 363
357 364 $type = Arr::get($_REQUEST, 'type', 'confirmation'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
365 +
358 366 $this->showBookingConfimationPage($booking, $type);
359 367 }
360 368
361 369 private function handleRescheduleView(Booking $booking)
@@ -423,11 +431,29 @@
423 431 </style>
424 432 <?php
425 433 });
426 434
427 - $this->renderBookingView($booking->calendar, $booking->calendar_event, $booking);
435 + $this->renderBookingView($booking->calendar, $booking->calendar_event, $booking, true);
428 436 }
429 437
438 + private function handleEmbeddedStyle()
439 + {
440 + add_action('wp_print_styles', function () {
441 + global $wp_styles;
442 + if($wp_styles) {
443 + foreach ($wp_styles->queue as $style) {
444 + $src = $wp_styles->registered[$style]->src;
445 + if (
446 + (strpos($src, 'fluentbooking') === false) &&
447 + (strpos($src, 'fluent_booking') === false)
448 + ) {
449 + wp_dequeue_style($wp_styles->registered[$style]->handle);
450 + }
451 + }
452 + }
453 + }, 100);
454 + }
455 +
430 456 public function getEventLandingExtraJsFiles($formFields, $calendarEvent)
431 457 {
432 458 $files = [];
433 459 $assetUrl = App::getInstance('url.assets');
@@ -432,9 +458,9 @@
432 458 $files = [];
433 459 $assetUrl = App::getInstance('url.assets');
434 460
435 461 if (BookingFieldService::hasPhoneNumberField($formFields)) {
436 - $files['fluent-booking-phone-field-js'] = $assetUrl . 'public/js/phone-field.js';
462 + $files['fluent-booking-phone-field-js'] = Vite::scriptUrl('phone_field');
437 463 }
438 464
439 465 if ($calendarEvent->type == 'paid') {
440 466 $files['fluent-booking-checkout-sdk-stripe-js'] = 'https://js.stripe.com/v3/';