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/Hooks/Handlers/BlockEditorHandler.php +174 -141 1.5.0 → 2.5.0 View file →
@@ -2,11 +2,14 @@
2 2
3 3 namespace FluentBooking\App\Hooks\Handlers;
4 4
5 5 use FluentBooking\App\App;
6 +use FluentBooking\App\Vite;
6 7 use FluentBooking\App\Models\Calendar;
7 8 use FluentBooking\App\Models\CalendarSlot;
9 +use FluentBooking\App\Services\CalendarEventService;
8 10 use FluentBooking\App\Services\Helper;
11 +use FluentBooking\App\Services\LocationService;
9 12 use FluentBooking\Framework\Support\Arr;
10 13
11 14 class BlockEditorHandler
12 15 {
@@ -12,48 +15,25 @@
12 15 {
13 16 public function init()
14 17 {
15 18 add_action('enqueue_block_editor_assets', function () {
16 - $app = App::getInstance();
17 - $assets = $app['url.assets'];
19 + $blockDeps = array('wp-blocks', 'wp-components', 'wp-block-editor', 'wp-element');
18 20
19 - wp_enqueue_script(
20 - 'fluent-booking/calendar',
21 - $assets . 'admin/fluent-booking-index.js',
22 - array('wp-blocks', 'wp-components', 'wp-block-editor', 'wp-element'),
23 - FLUENT_BOOKING_ASSETS_VERSION,
24 - true
25 - );
21 + $assetsVersion = Vite::isDev() ? time() : FLUENT_BOOKING_ASSETS_VERSION;
26 22
23 + Vite::enqueueScript('fluent-booking/calendar', 'fb_index', $blockDeps, $assetsVersion);
24 +
27 25 wp_localize_script('fluent-booking/calendar', 'fluentCalendarGutenbergVars', [
28 - 'ajaxurl' => admin_url('admin-ajax.php'),
26 + 'ajaxurl' => admin_url('admin-ajax.php'),
29 27 ]);
30 28
31 - wp_enqueue_script(
32 - 'fluent-booking/team-management',
33 - $assets . 'admin/fluent-booking-team-management-index.js',
34 - array('wp-blocks', 'wp-components', 'wp-block-editor', 'wp-element'),
35 - FLUENT_BOOKING_ASSETS_VERSION,
36 - true
37 - );
29 + Vite::enqueueScript('fluent-booking/team-management', 'fb_team', $blockDeps, $assetsVersion);
38 30
39 - wp_enqueue_script(
40 - 'fluent-booking/calendar-management',
41 - $assets . 'admin/fluent-booking-calendar-management-index.js',
42 - array('wp-blocks', 'wp-components', 'wp-block-editor', 'wp-element'),
43 - FLUENT_BOOKING_ASSETS_VERSION,
44 - true
45 - );
31 + Vite::enqueueScript('fluent-booking/calendar-management', 'fb_calendar', $blockDeps, $assetsVersion);
46 32
47 - wp_enqueue_script(
48 - 'fluent-booking/booking-management',
49 - $assets . 'admin/fluent-booking-booking-management-index.js',
50 - array('wp-blocks', 'wp-components', 'wp-block-editor', 'wp-element'),
51 - FLUENT_BOOKING_ASSETS_VERSION,
52 - true
53 - );
33 + Vite::enqueueScript('fluent-booking/booking-management', 'fb_booking', $blockDeps, $assetsVersion);
54 34
55 - $calendars = Calendar::with(['events' => function ($query) {
35 + $calendars = Calendar::with(['metas', 'events' => function ($query) {
56 36 $query->where('status', 'active');
57 37 }])->where('status', 'active')->get();
58 38
59 39 $formattedCalendars = [];
@@ -58,22 +38,23 @@
58 38
59 39 $formattedCalendars = [];
60 40
61 41 foreach ($calendars as $calendar) {
62 - $events = $calendar->events;
63 - if ($events->isEmpty()) {
42 + if ($calendar->events->isEmpty()) {
64 43 continue;
65 44 }
66 45
67 46 $formattedEvents = [];
68 -
69 47 foreach ($calendar->events as $event) {
70 48 $formattedEvents[] = [
71 - 'id' => (string)$event->id,
72 - 'title' => $event->title,
73 - 'duration' => (array)$event->duration,
74 - 'desctiption' => $event->description,
75 - 'color_schema' => $event->color_schema
49 + 'id' => (string)$event->id,
50 + 'title' => $event->title,
51 + 'color_schema' => $event->color_schema,
52 + 'durations' => $event->getAvailableDurations(),
53 + 'locations' => $event->defaultLocationHtml(),
54 + 'payment_html' => $event->getPaymentHtml(),
55 + 'loc_settings' => LocationService::sanitizePublicLocationSettings($event->location_settings),
56 + 'description' => $event->short_description
76 57 ];
77 58 }
78 59
79 60 $formattedCalendars[$calendar->id] = [
@@ -79,19 +60,33 @@
79 60 $formattedCalendars[$calendar->id] = [
80 61 'id' => (string)$calendar->id,
81 62 'title' => $calendar->title,
82 63 'description' => wpautop(Helper::excerpt($calendar->description, 200)),
83 - 'author' => $calendar->getAuthorProfile(),
64 + 'author' => Arr::only($calendar->getAuthorProfile(), ['name', 'avatar']),
65 + 'event_order' => $calendar->getMeta('event_order'),
84 66 'events' => $formattedEvents
85 67 ];
86 68 }
87 69
88 70 wp_localize_script('fluent-booking/calendar', 'fluent_booking_block', [
89 - 'assets_url' => $assets,
71 + 'assets_url' => App::getInstance()['url.assets'] ?? '',
90 72 'hosts' => $formattedCalendars
91 73 ]);
92 74 });
93 75
76 + add_action('enqueue_block_assets', function () {
77 + if (!is_admin()) {
78 + return;
79 + }
80 +
81 + $assetsVersion = Vite::isDev() ? time() : FLUENT_BOOKING_ASSETS_VERSION;
82 +
83 + Vite::enqueueStyle('fluent-booking/calendar-style', 'fb_index_css', [], $assetsVersion);
84 + Vite::enqueueStyle('fluent-booking/team-management-style', 'fb_team_css', [], $assetsVersion);
85 + Vite::enqueueStyle('fluent-booking/calendar-management-style', 'fb_calendar_css', [], $assetsVersion);
86 + Vite::enqueueStyle('fluent-booking/booking-management-style', 'fb_booking_css', [], $assetsVersion);
87 + });
88 +
94 89 register_block_type('fluent-booking/calendar', array(
95 90 'editor_script' => 'fluent-booking/calendar',
96 91 'render_callback' => array($this, 'fcalRenderBlock'),
97 92 'attributes' => [
@@ -102,8 +97,12 @@
102 97 'calendarId' => [
103 98 'type' => 'string',
104 99 'default' => '',
105 100 ],
101 + 'eventHash' => [
102 + 'type' => 'string',
103 + 'default' => '',
104 + ],
106 105 'avatar_rounded' => [
107 106 'type' => 'boolean',
108 107 'default' => false
109 108 ],
@@ -133,24 +132,24 @@
133 132 register_block_type('fluent-booking/team-management', array(
134 133 'editor_script' => 'fluent-booking/team-management',
135 134 'render_callback' => array($this, 'fcalRenderTeamManagementBlock'),
136 135 'attributes' => [
137 - 'title' => [
138 - 'type' => 'string',
139 - 'default' => ''
140 - ],
141 - 'description' => [
142 - 'type' => 'string',
143 - 'default' => ''
144 - ],
145 - 'headerImage' => [
146 - 'type' => 'object',
147 - 'default' => ''
148 - ],
149 - 'hosts' => [
150 - 'type' => 'object',
151 - 'default' => ''
152 - ]
136 + 'title' => [
137 + 'type' => 'string',
138 + 'default' => ''
139 + ],
140 + 'description' => [
141 + 'type' => 'string',
142 + 'default' => ''
143 + ],
144 + 'headerImage' => [
145 + 'type' => 'object',
146 + 'default' => ''
147 + ],
148 + 'hosts' => [
149 + 'type' => 'object',
150 + 'default' => ''
151 + ]
153 152 ]
154 153 ));
155 154
156 155 register_block_type('fluent-booking/calendar-management', array(
@@ -172,13 +171,13 @@
172 171 'calendarId' => array(
173 172 'type' => 'string',
174 173 'default' => ''
175 174 ),
176 - 'eventIds' => array(
175 + 'eventIds' => array(
177 176 'type' => 'array',
178 177 'default' => []
179 178 ),
180 - 'hideInfo' => array(
179 + 'hideInfo' => array(
181 180 'type' => 'boolean',
182 181 'default' => false
183 182 )
184 183 )
@@ -187,36 +186,36 @@
187 186 register_block_type('fluent-booking/booking-management', array(
188 187 'editor_script' => 'fluent-booking/booking-management',
189 188 'render_callback' => array($this, 'fcalRenderBookingManagementBlock'),
190 189 'attributes' => [
191 - 'title' => [
192 - 'type' => 'string',
193 - 'default' => __('My Bookings', 'fluent-booking')
194 - ],
195 - 'showFilter' => [
196 - 'type' => 'boolean',
197 - 'default' => true
198 - ],
199 - 'showPagination' => [
200 - 'type' => 'boolean',
201 - 'default' => true
202 - ],
203 - 'period' => [
204 - 'type' => 'string',
205 - 'default' => 'all'
206 - ],
207 - 'perPage' => [
208 - 'type' => 'number',
209 - 'default' => 5
210 - ],
211 - 'noBookingsMessage' => [
212 - 'type' => 'string',
213 - 'default' => __('No bookings found', 'fluent-booking')
214 - ],
215 - 'calendarIds' => [
216 - 'type' => 'array',
217 - 'default' => ['all']
218 - ]
190 + 'title' => [
191 + 'type' => 'string',
192 + 'default' => __('My Bookings', 'fluent-booking')
193 + ],
194 + 'showFilter' => [
195 + 'type' => 'boolean',
196 + 'default' => true
197 + ],
198 + 'showPagination' => [
199 + 'type' => 'boolean',
200 + 'default' => true
201 + ],
202 + 'period' => [
203 + 'type' => 'string',
204 + 'default' => 'all'
205 + ],
206 + 'perPage' => [
207 + 'type' => 'number',
208 + 'default' => 5
209 + ],
210 + 'noBookingsMessage' => [
211 + 'type' => 'string',
212 + 'default' => __('No bookings found', 'fluent-booking')
213 + ],
214 + 'calendarIds' => [
215 + 'type' => 'array',
216 + 'default' => ['all']
217 + ]
219 218 ]
220 219 ));
221 220 }
222 221
@@ -232,40 +231,32 @@
232 231
233 232 $hostItems = [];
234 233
235 234 foreach ($hosts as $config) {
236 - $calendar = Calendar::find($config['id']);
235 + $calendar = Calendar::with('metas')->find($config['id']);
237 236 if (!$calendar) {
238 237 continue;
239 238 }
239 +
240 240 $eventIds = Arr::get($config, 'events', []);
241 241 if (!$eventIds) {
242 242 continue;
243 243 }
244 244
245 - $isAll = in_array('all', $eventIds);
245 + $eventsQuery = CalendarSlot::where('calendar_id', $calendar->id)
246 + ->where('status', 'active');
246 247
247 - if ($isAll) {
248 - $events = CalendarSlot::where('calendar_id', $calendar->id)
249 - ->where('status', 'active')
250 - ->get();
251 - } else {
252 - $events = CalendarSlot::where('calendar_id', $calendar->id)
253 - ->whereIn('id', $eventIds)
254 - ->where('status', 'active')
255 - ->get();
248 + if (!in_array('all', $eventIds)) {
249 + $eventsQuery->whereIn('id', $eventIds);
256 250 }
257 251
252 + $events = $eventsQuery->get();
253 +
258 254 if ($events->isEmpty()) {
259 255 continue;
260 256 }
261 257
262 - foreach ($events as $event) {
263 - $event->public_url = $event->getPublicUrl();
264 - $event->durations = $event->getAvailableDurations();
265 - $event->description = $event->getDescription();
266 - $event->short_description = Helper::excerpt($event->description);
267 - }
258 + $events = CalendarEventService::processEvents($calendar, $events);
268 259
269 260 $calendar->activeEvents = $events;
270 261
271 262 $hostItems[$calendar->id] = $calendar;
@@ -271,11 +262,11 @@
271 262 $hostItems[$calendar->id] = $calendar;
272 263 }
273 264
274 265 return (new FrontEndHandler())->renderTeamHosts($hostItems, [
275 - 'title' => Arr::get($attributes, 'title'),
276 - 'description' => Arr::get($attributes, 'description'),
277 - 'logo' => Arr::get($attributes, 'headerImage.url'),
266 + 'title' => Arr::get($attributes, 'title'),
267 + 'description' => Arr::get($attributes, 'description'),
268 + 'logo' => Arr::get($attributes, 'headerImage.url'),
278 269 'wrapper_class' => $wrapperClassName
279 270 ]);
280 271 }
281 272
@@ -293,32 +284,23 @@
293 284 if (!$calendar) {
294 285 return '';
295 286 }
296 287
297 - $isAll = in_array('all', $eventIds);
288 + $eventsQuery = CalendarSlot::where('calendar_id', $calendar->id)
289 + ->where('status', 'active');
298 290
299 - if ($isAll) {
300 - $events = CalendarSlot::where('calendar_id', $calendar->id)
301 - ->where('status', 'active')
302 - ->get();
303 - } else {
304 - $events = CalendarSlot::where('calendar_id', $calendar->id)
305 - ->whereIn('id', $eventIds)
306 - ->where('status', 'active')
307 - ->get();
291 + if (!in_array('all', $eventIds)) {
292 + $eventsQuery->whereIn('id', $eventIds);
308 293 }
309 294
295 + $events = $eventsQuery->get();
296 +
310 297 if ($events->isEmpty()) {
311 298 return '';
312 299 }
313 300
314 - foreach ($events as $event) {
315 - $event->public_url = $event->getPublicUrl();
316 - $event->durations = $event->getAvailableDurations();
317 - $event->description = $event->getDescription();
318 - $event->short_description = Helper::excerpt($event->description);
319 - }
320 -
301 + $events = CalendarEventService::processEvents($calendar, $events);
302 +
321 303 $calendar->activeEvents = $events;
322 304
323 305 return (new FrontEndHandler())->renderCalendarBlock($calendar, [
324 306 'title' => Arr::get($attributes, 'title'),
@@ -330,13 +312,19 @@
330 312 }
331 313
332 314 public function fcalRenderBookingManagementBlock($attributes)
333 315 {
334 - $calendarIds = Arr::get($attributes, 'calendarIds', []);
335 -
316 + $calendarIds = (array) Arr::get($attributes, 'calendarIds', []);
317 +
318 + if (!$calendarIds || in_array('all', $calendarIds, true)) {
319 + $calendarIds = 'all';
320 + } else {
321 + $calendarIds = implode(',', array_map('intval', $calendarIds));
322 + }
323 +
336 324 $title = sanitize_text_field(Arr::get($attributes, 'title'));
337 325
338 - $period = sanitize_text_field(Arr::get($attributes, 'period', 'all'));
326 + $period = sanitize_key(Arr::get($attributes, 'period', 'all'));
339 327
340 328 $perPage = intval(Arr::get($attributes, 'perPage', 10));
341 329
342 330 $showFilter = Arr::isTrue($attributes, 'showFilter', true) ? 'show' : 'hide';
@@ -344,29 +332,74 @@
344 332 $showPagination = Arr::isTrue($attributes, 'showPagination', true) ? 'show' : 'hide';
345 333
346 334 $noBookingsMessage = sanitize_text_field(Arr::get($attributes, 'noBookingsMessage'));
347 335
348 - return do_shortcode("[fluent_booking_lists title=\"$title\" period=$period per_page=$perPage filter=$showFilter pagination=$showPagination no_bookings=\"$noBookingsMessage\" calendar_ids=" . implode(',', $calendarIds) . "]");
336 + $shortcode = sprintf(
337 + '[fluent_booking_lists title="%s" period=%s per_page=%d filter=%s pagination=%s no_bookings="%s" calendar_ids=%s]',
338 + esc_attr($title),
339 + $period,
340 + $perPage,
341 + $showFilter,
342 + $showPagination,
343 + esc_attr($noBookingsMessage),
344 + $calendarIds
345 + );
346 +
347 + return do_shortcode($shortcode);
349 348 }
350 349
351 350 public function fcalRenderBlock($attributes)
352 351 {
353 - $output = '<style>
354 - :root {
355 - --fcal_primary_color: ' . esc_attr($attributes['primary_color']) . ' !important;
356 - --fcal_date_radius: ' . esc_attr($attributes['date_round']) . ' !important;
357 - --fcal_avatar_radius: ' . esc_attr($attributes['avatarStyle']) . ' !important;
352 + $primaryColor = sanitize_hex_color(Arr::get($attributes, 'primary_color', ''));
353 + $dateRadius = self::sanitizeCssLength(Arr::get($attributes, 'date_round', ''));
354 + $avatarRadius = self::sanitizeCssLength(Arr::get($attributes, 'avatarStyle', ''));
355 +
356 + $output = '<style>:root {';
357 + if ($primaryColor) {
358 + $output .= '--fcal_primary_color: ' . $primaryColor . ' !important;';
359 + }
360 + if ($dateRadius) {
361 + $output .= '--fcal_date_radius: ' . $dateRadius . ' !important;';
362 + }
363 + if ($avatarRadius) {
364 + $output .= '--fcal_avatar_radius: ' . $avatarRadius . ' !important;';
365 + }
366 + $output .= '}</style>';
367 +
368 + $slotId = (int) Arr::get($attributes, 'slotId');
369 + $disableHost = Arr::isTrue($attributes, 'hideHostInfo') ? 'yes' : 'no';
370 + $theme = sanitize_key(Arr::get($attributes, 'theme', 'light'));
371 + $eventHash = sanitize_text_field(Arr::get($attributes, 'eventHash', ''));
372 + $align = sanitize_html_class(Arr::get($attributes, 'align', ''));
373 +
374 + $slot = CalendarSlot::find($slotId);
375 +
376 + if (!$slot) {
377 + $slot = CalendarSlot::where('hash', $eventHash)->first();
378 + if (!$slot) {
379 + return '';
358 380 }
359 - </style>';
381 + $slotId = (int) $slot->id;
382 + $eventHash = (string) $slot->hash;
383 + }
360 384
361 - $slotId = $attributes['slotId'];
362 - $disableHost = $attributes['hideHostInfo'];
363 - $theme = Arr::get($attributes, 'theme', 'light');
385 + $output .= '<div class="fluent-booking-calendar-block align' . esc_attr($align) . '">';
364 386
365 - $output .= '<div class="fluent-booking-calendar-block align'.Arr::get($attributes,'align').'">';
387 + $output .= do_shortcode(sprintf(
388 + '[fluent_booking id=%d disable_author=%s theme=%s hash=%s]',
389 + $slotId,
390 + $disableHost,
391 + $theme,
392 + esc_attr($eventHash)
393 + ));
366 394
367 - $output .= do_shortcode("[fluent_booking id=$slotId disable_author=$disableHost theme=$theme]");
368 -
369 395 $output .= '</div>';
370 396 return $output;
397 + }
398 +
399 + private static function sanitizeCssLength($value)
400 + {
401 + $value = trim((string) $value);
402 +
403 + return preg_match('/^\d{1,3}(\.\d+)?(px|%|em|rem)$/', $value) ? $value : '';
371 404 }
372 405 }