| @@ -12,8 +12,9 @@ | ||
| 12 | 12 | use FluentBooking\App\Services\BookingService; |
| 13 | 13 | use FluentBooking\App\Services\Helper; |
| 14 | 14 | use FluentBooking\Framework\Support\Arr; |
| 15 | 15 | use FluentBooking\Framework\Support\Collection; |
| 16 | +use FluentBooking\App\Vite; | |
| 16 | 17 | |
| 17 | 18 | class LandingPageHandler |
| 18 | 19 | { |
| 19 | 20 | public function boot() |
| @@ -39,15 +40,23 @@ | ||
| 39 | 40 | } |
| 40 | 41 | |
| 41 | 42 | $authorSlug = sanitize_text_field($urlParts[1]); |
| 42 | 43 | |
| 44 | + if (isset($_GET['embedded'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 45 | + $this->handleEmbeddedStyle(); | |
| 46 | + } | |
| 47 | + | |
| 43 | 48 | $this->routeView($authorSlug, Arr::get($urlParts, 2, null)); |
| 44 | 49 | } |
| 45 | 50 | |
| 46 | 51 | public function handleUrlParamsPage() |
| 47 | 52 | { |
| 48 | - $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 | |
| 49 | 54 | |
| 55 | + if (isset($_GET['embedded'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 56 | + $this->handleEmbeddedStyle(); | |
| 57 | + } | |
| 58 | + | |
| 50 | 59 | if ($route == 'booking') { |
| 51 | 60 | $this->handleAfterBookingPage(); |
| 52 | 61 | return; |
| 53 | 62 | } |
| @@ -90,9 +99,9 @@ | ||
| 90 | 99 | ->first(); |
| 91 | 100 | if (!$slot) { |
| 92 | 101 | return; |
| 93 | 102 | } |
| 94 | - $this->renderBookingView($calendar, $slot); | |
| 103 | + return $this->renderBookingView($calendar, $slot); | |
| 95 | 104 | } |
| 96 | 105 | |
| 97 | 106 | $this->renderHostView($calendar); |
| 98 | 107 | } |
| @@ -103,9 +112,9 @@ | ||
| 103 | 112 | $settings = LandingPageHelper::getSettings($calendar, 'public'); |
| 104 | 113 | |
| 105 | 114 | $activeEvents = CalendarSlot::where('calendar_id', $calendar->id) |
| 106 | 115 | ->where('status', 'active'); |
| 107 | - | |
| 116 | + | |
| 108 | 117 | if ($settings['show_type'] != 'all') { |
| 109 | 118 | $activeEvents = $activeEvents->whereIn('id', $settings['enabled_slots']); |
| 110 | 119 | } |
| 111 | 120 | |
| @@ -145,9 +154,8 @@ | ||
| 145 | 154 | $activeEvent->locations = $activeEvent->defaultLocationHtml(); |
| 146 | 155 | do_action_ref_array('fluent_booking/landing_page_event', [&$activeEvent]); |
| 147 | 156 | } |
| 148 | 157 | |
| 149 | - $assetUrl = App::getInstance('url.assets'); | |
| 150 | 158 | $data = [ |
| 151 | 159 | 'calendar' => $calendar, |
| 152 | 160 | 'events' => $activeEvents, |
| 153 | 161 | 'author' => $authorProfile, |
| @@ -153,17 +161,18 @@ | ||
| 153 | 161 | 'author' => $authorProfile, |
| 154 | 162 | 'title' => $calendar->title .' - '.get_bloginfo('name'), |
| 155 | 163 | 'description' => $metaDescription, |
| 156 | 164 | 'url' => home_url($wp->request), |
| 165 | + 'embedded' => isset($_GET['embedded']) ? true : false, // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 157 | 166 | 'css_files' => [ |
| 158 | - App::getInstance('url.assets') . 'public/saas.css' | |
| 167 | + Vite::styleUrl('saas_css') | |
| 159 | 168 | ], |
| 160 | 169 | 'js_files' => [ |
| 161 | - 'fluent-booking-public-js' => $assetUrl . 'public/js/app.js', | |
| 170 | + 'fluent-booking-public-js' => Vite::scriptUrl('public_app'), | |
| 162 | 171 | ], |
| 163 | 172 | 'js_vars' => $jsVars, |
| 164 | 173 | 'header_js_files' => [ |
| 165 | - 'fluent_booking_team_app-js' => $assetUrl. 'public/js/team_app.js' | |
| 174 | + 'fluent_booking_team_app-js' => Vite::scriptUrl('team_app') | |
| 166 | 175 | ] |
| 167 | 176 | ]; |
| 168 | 177 | |
| 169 | 178 | if ($extraJsFiles) { |
| @@ -171,9 +180,9 @@ | ||
| 171 | 180 | $data['js_files'] = array_merge($data['js_files'], $extraJsFiles); |
| 172 | 181 | } |
| 173 | 182 | |
| 174 | 183 | $data = apply_filters('fluent_booking/host_view_page_vars', $data, $calendar, $activeEvents, $authorProfile); |
| 175 | - | |
| 184 | + | |
| 176 | 185 | $app = App::getInstance(); |
| 177 | 186 | status_header(200); |
| 178 | 187 | $app->view->render('landing.author_landing', $data); |
| 179 | 188 | exit(200); |
| @@ -178,14 +187,16 @@ | ||
| 178 | 187 | $app->view->render('landing.author_landing', $data); |
| 179 | 188 | exit(200); |
| 180 | 189 | } |
| 181 | 190 | |
| 182 | - private function renderBookingView($calendar, $calendarEvent, $existingBooking = null) | |
| 191 | + private function renderBookingView($calendar, $calendarEvent, $existingBooking = null, $isReschedule = false) | |
| 183 | 192 | { |
| 184 | - $settings = LandingPageHelper::getSettings($calendar, 'public'); | |
| 185 | - if ($settings['show_type'] != 'all') { | |
| 186 | - if (!in_array($calendarEvent->id, $settings['enabled_slots'])) { | |
| 187 | - 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 | + } | |
| 188 | 199 | } |
| 189 | 200 | } |
| 190 | 201 | |
| 191 | 202 | global $wp; |
| @@ -193,9 +204,9 @@ | ||
| 193 | 204 | $calendarEvent->max_lookup_date = $calendarEvent->getMaxLookUpDate(); |
| 194 | 205 | $calendarEvent->min_lookup_date = $calendarEvent->getMinLookUpDate(); |
| 195 | 206 | |
| 196 | 207 | if (!empty($_REQUEST['booking_id'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 197 | - $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 | |
| 198 | 209 | $booking = Booking::where('hash', $bookingHash) |
| 199 | 210 | ->where('event_id', $calendarEvent->id) |
| 200 | 211 | ->first(); |
| 201 | 212 | if ($booking) { |
| @@ -217,24 +228,27 @@ | ||
| 217 | 228 | $assetUrl = App::getInstance('url.assets'); |
| 218 | 229 | |
| 219 | 230 | $eventVars = (new FrontEndHandler())->getCalendarEventVars($calendar, $calendarEvent); |
| 220 | 231 | |
| 221 | - $isRtl = Helper::fluentbooking_is_rtl(); | |
| 232 | + $publicCss = 'saas_css'; | |
| 222 | 233 | |
| 223 | - $publicCss = $isRtl ? 'public/saas-rtl.css' : 'public/saas.css'; | |
| 234 | + $title = $calendarEvent->title . ' ' . __('with', 'fluent-booking') . ' ' . $authorProfile['name']; | |
| 224 | 235 | |
| 236 | + $title = apply_filters('fluent_booking/booking_confirmation_page_title', $title, $calendarEvent, $authorProfile); | |
| 237 | + | |
| 225 | 238 | $data = [ |
| 226 | 239 | 'calendar' => $calendar, |
| 227 | 240 | 'calendar_event' => $calendarEvent, |
| 228 | 241 | 'author' => $authorProfile, |
| 229 | - 'title' => $calendarEvent->title . ' ' . __('with', 'fluent-booking') . ' ' . $authorProfile['name'], | |
| 242 | + 'title' => $title, | |
| 230 | 243 | 'description' => substr(strip_shortcodes(wp_strip_all_tags(str_replace(PHP_EOL, ' ', $calendarEvent->description))), 0, 300) . '...', |
| 231 | 244 | 'url' => home_url($wp->request), |
| 245 | + 'embedded' => isset($_GET['embedded']) ? true : false, // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 232 | 246 | 'css_files' => [ |
| 233 | - $assetUrl . $publicCss | |
| 247 | + Vite::styleUrl($publicCss) | |
| 234 | 248 | ], |
| 235 | 249 | 'js_files' => [ |
| 236 | - 'fluent-booking-public-js' => $assetUrl . 'public/js/app.js', | |
| 250 | + 'fluent-booking-public-js' => Vite::scriptUrl('public_app'), | |
| 237 | 251 | ], |
| 238 | 252 | 'js_vars' => [ |
| 239 | 253 | 'fluentCalendarPublicVars' => (new FrontEndHandler())->getGlobalVars(), |
| 240 | 254 | 'fcal_public_vars_' . $calendar->id . '_' . $calendarEvent->id => $eventVars, |
| @@ -268,9 +282,8 @@ | ||
| 268 | 282 | |
| 269 | 283 | private function showBookingConfimationPage($booking, $actionType = 'confirmation') |
| 270 | 284 | { |
| 271 | 285 | $validActions = ['confirmation']; |
| 272 | - $isRtl = Helper::fluentbooking_is_rtl(); | |
| 273 | 286 | |
| 274 | 287 | if (in_array($booking->status, ['scheduled', 'pending', 'rescheduled'])) { |
| 275 | 288 | $validActions = array_merge($validActions, ['reschedule', 'cancel']); |
| 276 | 289 | } |
| @@ -291,24 +304,24 @@ | ||
| 291 | 304 | echo $icsText; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 292 | 305 | die(); |
| 293 | 306 | } |
| 294 | 307 | |
| 308 | + global $wp; | |
| 309 | + | |
| 295 | 310 | $calendarEvent = $booking->calendar_event; |
| 296 | - global $wp; | |
| 311 | + | |
| 297 | 312 | $responseHtml = BookingService::getBookingConfirmationHtml($booking, $actionType); |
| 298 | 313 | |
| 299 | 314 | $authorProfile = $calendarEvent->getAuthorProfile(true); |
| 300 | 315 | |
| 301 | - $publicCss = 'public/saas_public.css'; | |
| 302 | - if ($isRtl) { | |
| 303 | - $publicCss = 'public/saas_public-rtl.css'; | |
| 304 | - } | |
| 316 | + $publicCss = 'saas_public_css'; | |
| 317 | + | |
| 305 | 318 | $data = [ |
| 306 | 319 | 'title' => __('Confirmation: ', 'fluent-booking') . $calendarEvent->title . ' ' . __('with', 'fluent-booking') . ' ' . $authorProfile['name'], |
| 307 | 320 | 'body' => $responseHtml, |
| 308 | 321 | 'description' => substr(strip_shortcodes(wp_strip_all_tags(str_replace(PHP_EOL, ' ', $calendarEvent->description))), 0, 300) . '...', |
| 309 | 322 | 'css_files' => [ |
| 310 | - App::getInstance('url.assets') . $publicCss | |
| 323 | + Vite::styleUrl($publicCss) | |
| 311 | 324 | ], |
| 312 | 325 | 'js_files' => [], |
| 313 | 326 | 'js_vars' => [], |
| 314 | 327 | 'author' => $authorProfile, |
| @@ -314,15 +327,23 @@ | ||
| 314 | 327 | 'author' => $authorProfile, |
| 315 | 328 | 'slot' => $calendarEvent, |
| 316 | 329 | 'url' => home_url($wp->request), |
| 317 | 330 | 'action_type' => $actionType, |
| 318 | - '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 | + ] | |
| 319 | 338 | ]; |
| 320 | 339 | |
| 321 | 340 | if ($actionType == 'cancel') { |
| 322 | - $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'); | |
| 323 | 342 | } |
| 324 | 343 | |
| 344 | + $data = apply_filters('fluent_booking/booking_confirmation_page_vars', $data, $booking, $calendarEvent); | |
| 345 | + | |
| 325 | 346 | $app = App::getInstance(); |
| 326 | 347 | status_header(200); |
| 327 | 348 | $app->view->render('landing.confirmation_page', $data); |
| 328 | 349 | exit(200); |
| @@ -329,21 +350,20 @@ | ||
| 329 | 350 | } |
| 330 | 351 | |
| 331 | 352 | private function handleAfterBookingPage() |
| 332 | 353 | { |
| 333 | - $bookingHash = sanitize_text_field(Arr::get($_REQUEST, 'meeting_hash')); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 334 | - | |
| 354 | + $bookingHash = sanitize_text_field(wp_unslash(Arr::get($_REQUEST, 'meeting_hash'))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 335 | 355 | if (!$bookingHash) { |
| 336 | 356 | return; |
| 337 | 357 | } |
| 338 | 358 | |
| 339 | 359 | $booking = Booking::where('hash', $bookingHash)->first(); |
| 340 | - | |
| 341 | 360 | if (!$booking) { |
| 342 | 361 | return; |
| 343 | 362 | } |
| 344 | 363 | |
| 345 | 364 | $type = Arr::get($_REQUEST, 'type', 'confirmation'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 365 | + | |
| 346 | 366 | $this->showBookingConfimationPage($booking, $type); |
| 347 | 367 | } |
| 348 | 368 | |
| 349 | 369 | private function handleRescheduleView(Booking $booking) |
| @@ -411,11 +431,29 @@ | ||
| 411 | 431 | </style> |
| 412 | 432 | <?php |
| 413 | 433 | }); |
| 414 | 434 | |
| 415 | - $this->renderBookingView($booking->calendar, $booking->calendar_event, $booking); | |
| 435 | + $this->renderBookingView($booking->calendar, $booking->calendar_event, $booking, true); | |
| 416 | 436 | } |
| 417 | 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 | + | |
| 418 | 456 | public function getEventLandingExtraJsFiles($formFields, $calendarEvent) |
| 419 | 457 | { |
| 420 | 458 | $files = []; |
| 421 | 459 | $assetUrl = App::getInstance('url.assets'); |
| @@ -420,9 +458,9 @@ | ||
| 420 | 458 | $files = []; |
| 421 | 459 | $assetUrl = App::getInstance('url.assets'); |
| 422 | 460 | |
| 423 | 461 | if (BookingFieldService::hasPhoneNumberField($formFields)) { |
| 424 | - $files['fluent-booking-phone-field-js'] = $assetUrl . 'public/js/phone-field.js'; | |
| 462 | + $files['fluent-booking-phone-field-js'] = Vite::scriptUrl('phone_field'); | |
| 425 | 463 | } |
| 426 | 464 | |
| 427 | 465 | if ($calendarEvent->type == 'paid') { |
| 428 | 466 | $files['fluent-booking-checkout-sdk-stripe-js'] = 'https://js.stripe.com/v3/'; |