PluginProbe
Booking Calendar / 11.1
Booking Calendar v11.1
11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 All 203 releases
booking / includes / page-form-builder / save-load / bfb-activate.php

bfb-activate.php in Booking Calendar 11.1, at includes/page-form-builder/save-load/bfb-activate.php

915 lines 26.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Booking Form Builder - Activation helpers.
4 *
5 * Responsibilities:
6 * 1) Create BFB DB table (wp_booking_form_structures) on activation (if missing).
7 * 2) Ensure the "Booking Form Preview" page exists during activation.
8 *
9 * @package Booking Calendar.
10 * @author wpdevelop, oplugins
11 * @web-site https://wpbookingcalendar.com/
12 * @email info@wpbookingcalendar.com
13 *
14 * @since 11.0.x
15 * @file ../includes/page-form-builder/save-load/bfb-activate.php
16 * @modified 2026-02-23
17 */
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit; // Exit if accessed directly.
21 }
22
23 /**
24 * Return option key where preview page ID is stored.
25 *
26 * Must match WPBC_BFB_Preview_Service::get_page_option_key().
27 *
28 * @return string
29 */
30 function wpbc_bfb_activation__get_preview_page_option_key() {
31 return 'wpbc_bfb_preview_page_id';
32 }
33
34 /**
35 * Return meta key used to mark the preview page (for recovery).
36 *
37 * @return string
38 */
39 function wpbc_bfb_activation__get_preview_page_meta_key() {
40 return '_wpbc_bfb_preview_page';
41 }
42
43 /**
44 * Return canonical slug for the preview page.
45 *
46 * @return string
47 */
48 function wpbc_bfb_activation__get_preview_page_slug() {
49 return 'wpbc-bfb-preview';
50 }
51
52 /**
53 * Try to find an administrator user ID (best-effort).
54 *
55 * @return int Admin user ID, or 0 if not found.
56 */
57 function wpbc_bfb_activation__get_any_admin_user_id() {
58
59 $users = get_users( array(
60 'role' => 'administrator',
61 'number' => 1,
62 'fields' => array( 'ID' ),
63 ) );
64
65 if ( empty( $users ) ) {
66 return 0;
67 }
68
69 if ( is_object( $users[0] ) && isset( $users[0]->ID ) ) {
70 return (int) $users[0]->ID;
71 }
72
73 if ( is_array( $users[0] ) && isset( $users[0]['ID'] ) ) {
74 return (int) $users[0]['ID'];
75 }
76
77 return 0;
78 }
79
80 /**
81 * Temporarily switch current user to an admin user if the current user
82 * cannot create private pages (activation edge-cases like WP-CLI).
83 *
84 * @return int Previous user ID (0 if none). Caller should restore with wp_set_current_user().
85 */
86 function wpbc_bfb_activation__maybe_switch_to_admin_user() {
87
88 $prev_user_id = (int) get_current_user_id();
89
90 // If current user can create pages, do nothing.
91 if ( $prev_user_id > 0 && user_can( $prev_user_id, 'publish_pages' ) ) {
92 return $prev_user_id;
93 }
94
95 $admin_id = wpbc_bfb_activation__get_any_admin_user_id();
96 if ( $admin_id > 0 ) {
97 wp_set_current_user( $admin_id );
98 }
99
100 return $prev_user_id;
101 }
102
103 /**
104 * Restore previous user after temporary switch.
105 *
106 * @param int $prev_user_id Previous user ID.
107 *
108 * @return void
109 */
110 function wpbc_bfb_activation__restore_user( $prev_user_id ) {
111
112 $prev_user_id = (int) $prev_user_id;
113
114 // Restore to previous user if we had one; otherwise, reset to 0.
115 if ( $prev_user_id > 0 ) {
116 wp_set_current_user( $prev_user_id );
117 } else {
118 wp_set_current_user( 0 );
119 }
120 }
121
122 /**
123 * Validate that a page ID is a real WP page.
124 *
125 * @param int $page_id Page ID.
126 *
127 * @return bool
128 */
129 function wpbc_bfb_activation__is_valid_page_id( $page_id ) {
130
131 $page_id = (int) $page_id;
132
133 if ( $page_id <= 0 ) {
134 return false;
135 }
136
137 $page = get_post( $page_id );
138
139 return ( $page instanceof WP_Post && 'page' === $page->post_type );
140 }
141
142 /**
143 * Try to locate an existing preview page by meta marker.
144 *
145 * @return int Page ID or 0.
146 */
147 function wpbc_bfb_activation__find_preview_page_by_meta() {
148
149 $meta_key = wpbc_bfb_activation__get_preview_page_meta_key();
150
151 $q = new WP_Query( array(
152 'post_type' => 'page',
153 'post_status' => array( 'private', 'publish', 'draft', 'pending' ),
154 'posts_per_page' => 1,
155 'fields' => 'ids',
156 'no_found_rows' => true,
157 'suppress_filters' => true, // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters
158 'meta_key' => $meta_key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
159 'meta_value' => '1', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
160 ) );
161
162 if ( empty( $q->posts ) ) {
163 return 0;
164 }
165
166 return (int) $q->posts[0];
167 }
168
169 /**
170 * Try to locate an existing preview page by slug.
171 *
172 * @return int Page ID or 0.
173 */
174 function wpbc_bfb_activation__find_preview_page_by_slug() {
175
176 $slug = wpbc_bfb_activation__get_preview_page_slug();
177
178 $page = get_page_by_path( $slug, OBJECT, 'page' );
179 if ( $page instanceof WP_Post ) {
180 return (int) $page->ID;
181 }
182
183 return 0;
184 }
185
186
187 /**
188 * Force a safe template for the BFB Preview page.
189 *
190 * Why:
191 * - The Preview page is a technical/service page.
192 * - It should not inherit decorative page templates like "Page with wide Image".
193 * - For block themes, prefer a clean template like "page-no-title" or "page".
194 * - For classic themes, use the default page template. // FixIn: 10.15.2.1
195 *
196 * @param int $page_id Page ID.
197 *
198 * @return bool
199 */
200 function wpbc_bfb_preview__force_safe_template( $page_id ) {
201
202 $page_id = absint( $page_id );
203
204 if ( $page_id <= 0 ) {
205 return false;
206 }
207
208 /*
209 * Always clear any previously assigned template first.
210 * This is important when an existing Preview page was previously using
211 * an unwanted template, for example "Page with wide Image".
212 */
213 delete_post_meta( $page_id, '_wp_page_template' );
214
215 // Block themes: prefer a cleaner built-in page template, if available.
216 if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() && function_exists( 'get_block_templates' ) ) {
217
218 $theme_slug = get_stylesheet();
219 $templates = get_block_templates(
220 array(
221 'post_type' => 'page',
222 ),
223 'wp_template'
224 );
225 $safe_template_slug = '';
226
227 foreach ( $templates as $template ) {
228
229 if ( empty( $template->slug ) || empty( $template->theme ) ) {
230 continue;
231 }
232
233 if ( $theme_slug !== $template->theme ) {
234 continue;
235 }
236
237 if ( 'page-no-title' === $template->slug ) {
238 $safe_template_slug = 'page-no-title';
239 break;
240 }
241
242 if ( ( '' === $safe_template_slug ) && ( 'page' === $template->slug ) ) {
243 $safe_template_slug = 'page';
244 }
245 }
246
247 if ( '' !== $safe_template_slug ) {
248 $result = wp_update_post(
249 array(
250 'ID' => $page_id,
251 'page_template' => $safe_template_slug,
252 ),
253 true
254 );
255
256 return ( ! is_wp_error( $result ) );
257 }
258 }
259
260 return true;
261 }
262
263
264 /**
265 * The preview page has status 'publish', because the secure the output by your nonce + cap
266 *
267 * Preview security is already enforced by:
268 *
269 * wpbc_bfb_preview=1 + token + nonce
270 *
271 * is_user_logged_in() + current_user_can( wpbc_bfb_get_manage_cap() )
272 *
273 * So the preview page itself does not need to be private.
274 *
275 * @return false|int
276 */
277 function wpbc_bfb_activation__create_preview_page_raw() {
278
279 $page_data = array(
280 'post_title' => __( 'Booking Form Preview', 'booking' ),
281 'post_content' => '', // Content will be injected dynamically at preview time by bfb-preview.php.
282 'post_status' => 'publish',
283 'post_type' => 'page',
284 'post_name' => wpbc_bfb_activation__get_preview_page_slug(),
285 'comment_status' => 'closed',
286 'ping_status' => 'closed',
287 );
288
289 $page_id = wp_insert_post( $page_data, true );
290
291 if ( ( ! is_wp_error( $page_id ) ) && ( ! empty( $page_id ) ) ) {
292 // Success.
293 wpbc_bfb_preview__force_safe_template( $page_id );
294 } else {
295 if ( is_wp_error( $page_id ) ) {
296 return false;
297 }
298 if ( ! $page_id ) {
299 return false;
300 }
301 $page_id = false;
302 }
303
304 return (int) $page_id;
305 }
306
307
308 /**
309 * Create the "Booking Form Preview" page and store option.
310 *
311 * @return int|false Page ID on success, false on failure.
312 */
313 function wpbc_bfb_activation__create_preview_page() {
314
315 $prev_user_id = wpbc_bfb_activation__maybe_switch_to_admin_user();
316
317 $page_id = wpbc_bfb_activation__create_preview_page_raw();
318
319 // Restore user context.
320 wpbc_bfb_activation__restore_user( $prev_user_id );
321
322 if ( empty( $page_id ) || is_wp_error( $page_id ) ) {
323 return false;
324 }
325
326 $page_id = (int) $page_id;
327
328 // Mark page for recovery if option is deleted later.
329 add_post_meta( $page_id, wpbc_bfb_activation__get_preview_page_meta_key(), '1', true );
330
331 // Store the page ID in option (same key used by preview service).
332 update_option( wpbc_bfb_activation__get_preview_page_option_key(), $page_id );
333
334 return $page_id;
335 }
336
337 /**
338 * Ensure preview page exists (activation-time).
339 *
340 * - Validates stored option page ID.
341 * - If missing, tries to find by meta marker.
342 * - If missing, tries to find by slug.
343 * - If still missing, creates a new private page.
344 *
345 * @return int|false Page ID, or false on failure.
346 */
347 function wpbc_bfb_activation__ensure_preview_page_exists() {
348
349 $option_key = wpbc_bfb_activation__get_preview_page_option_key();
350 $page_id = (int) get_option( $option_key );
351
352 // 1) Option points to a valid page.
353 if ( wpbc_bfb_activation__is_valid_page_id( $page_id ) ) {
354
355 // Enforce publish status (best effort).
356 $page = get_post( $page_id );
357 if ( $page instanceof WP_Post && 'publish' !== $page->post_status ) {
358 wp_update_post( array(
359 'ID' => (int) $page_id,
360 'post_status' => 'publish',
361 ) );
362 }
363
364 // Ensure meta marker exists.
365 wpbc_bfb_preview__force_safe_template( (int) $page_id );
366 add_post_meta( (int) $page_id, wpbc_bfb_activation__get_preview_page_meta_key(), '1', true );
367
368 return (int) $page_id;
369 }
370
371 // 2) Try recovery by meta marker.
372 $found_id = wpbc_bfb_activation__find_preview_page_by_meta();
373 if ( $found_id > 0 && wpbc_bfb_activation__is_valid_page_id( $found_id ) ) {
374 $found_page = get_post( $found_id );
375 if ( $found_page instanceof WP_Post && 'publish' !== $found_page->post_status ) {
376 wp_update_post( array(
377 'ID' => (int) $found_id,
378 'post_status' => 'publish',
379 ) );
380 }
381 wpbc_bfb_preview__force_safe_template( (int) $found_id );
382 update_option( $option_key, (int) $found_id );
383 return (int) $found_id;
384 }
385
386 // 3) Try recovery by slug.
387 $found_id = wpbc_bfb_activation__find_preview_page_by_slug();
388 if ( $found_id > 0 && wpbc_bfb_activation__is_valid_page_id( $found_id ) ) {
389 $found_page = get_post( $found_id );
390 if ( $found_page instanceof WP_Post && 'publish' !== $found_page->post_status ) {
391 wp_update_post( array(
392 'ID' => (int) $found_id,
393 'post_status' => 'publish',
394 ) );
395 }
396 wpbc_bfb_preview__force_safe_template( (int) $found_id );
397 // Mark it as ours (so next time meta lookup works).
398 add_post_meta( (int) $found_id, wpbc_bfb_activation__get_preview_page_meta_key(), '1', true );
399 update_option( $option_key, (int) $found_id );
400 return (int) $found_id;
401 }
402
403 // 4) Create.
404 return wpbc_bfb_activation__create_preview_page();
405 }
406
407 /**
408 * Activation hook entry: ensure the preview page exists.
409 *
410 * @return void
411 */
412 function wpbc_bfb_activation__preview_page() {
413 wpbc_bfb_activation__ensure_preview_page_exists();
414 }
415 add_bk_action( 'wpbc_free_version_activation', 'wpbc_bfb_activation__preview_page' );
416
417
418 /**
419 * A c t i v a t e - Create new DB Table for Booking Form Builder structures.
420 *
421 * This table stores:
422 * - Canonical form builder structure as JSON (structure_json).
423 * - Additional settings as JSON (settings_json).
424 * - Optional precompiled HTML can be added later (not in this schema).
425 * - Ownership via owner_user_id (for MultiUser).
426 *
427 * @return void
428 */
429 function wpbc_bfb_activation__form_structures_table() {
430
431 global $wpdb;
432
433 $charset_collate = ( ! empty( $wpdb->charset ) ) ? 'DEFAULT CHARACTER SET ' . $wpdb->charset : '';
434 $charset_collate .= ( ! empty( $wpdb->collate ) ) ? ' COLLATE ' . $wpdb->collate : '';
435
436 if ( ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
437
438
439
440 $simple_sql = "CREATE TABLE {$wpdb->prefix}booking_form_structures (
441 booking_form_id bigint(20) unsigned NOT NULL auto_increment,
442 form_slug VARCHAR(191) NOT NULL,
443 status VARCHAR(32) NOT NULL,
444 owner_user_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
445
446 scope varchar(64) NOT NULL default 'global',
447 version int(11) NOT NULL default 1,
448 booking_resource_id BIGINT UNSIGNED NULL,
449
450 engine varchar(32) NOT NULL default 'bfb',
451 engine_version varchar(16) NOT NULL default '1.0',
452 structure_json LONGTEXT NOT NULL,
453 settings_json LONGTEXT NULL,
454 advanced_form LONGTEXT NULL,
455 content_form LONGTEXT NULL,
456
457 is_default TINYINT(1) NOT NULL DEFAULT 0,
458 title VARCHAR(255) NOT NULL,
459 description TEXT NULL,
460 picture_url text NULL,
461
462 created_at DATETIME NOT NULL,
463 updated_at DATETIME NOT NULL,
464
465 created_by bigint(20) unsigned DEFAULT NULL,
466 updated_by bigint(20) unsigned DEFAULT NULL,
467 PRIMARY KEY (booking_form_id),
468 UNIQUE KEY form_slug_status (form_slug, status, owner_user_id)
469 ) {$charset_collate}";
470
471 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
472 $wpdb->query( $simple_sql );
473
474 do_action( 'wpbc_bfb_activation__form_structures_table__after_create' );
475
476 wpbc_bfb__import_old_booking_forms();
477 } else {
478 do_action( 'wpbc_bfb_activation__form_structures_table__table_already_exists' );
479 }
480 }
481 add_bk_action( 'wpbc_free_version_activation', 'wpbc_bfb_activation__form_structures_table' );
482
483
484 /**
485 * D e a c t i v a t e - Drop Booking Form Builder structures table.
486 *
487 * @return void
488 */
489 function wpbc_bfb_deactivation__form_structures_table() {
490
491 global $wpdb;
492
493
494
495 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
496 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}booking_form_structures" );
497
498 delete_bk_option( 'wpbc_bfb_legacy_import_done_for_pro' );
499 }
500 add_bk_action( 'wpbc_free_version_deactivation', 'wpbc_bfb_deactivation__form_structures_table' );
501
502
503 /**
504 * Import legacy "standard" booking form as initial BFB structure.
505 *
506 * @return void
507 */
508 function wpbc_bfb_is_brand_new_install__before_version_update() {
509
510 $stored_version = get_option( 'booking_version_num', false );
511
512 return ( false === $stored_version );
513 }
514
515 /**
516 * Maybe create the initial standard BFB form from a bundled template.
517 *
518 * Used only during brand new plugin activation, before booking_version_num
519 * gets updated. Upgrades keep migrating the existing legacy configuration.
520 *
521 * @return bool
522 */
523 function wpbc_bfb_maybe_create_initial_standard_form_from_template() {
524
525 if ( ! wpbc_bfb_is_brand_new_install__before_version_update() ) {
526 return false;
527 }
528
529 if ( ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
530 return false;
531 }
532
533 if ( function_exists( 'wpbc_get_bfb_template_record_by_key' ) ) {
534 $template_record = wpbc_get_bfb_template_record_by_key( 'time_appointments_3_steps_review_with_hints' );
535 } else {
536 $template_record = array();
537 }
538
539 if ( empty( $template_record ) || ! is_array( $template_record ) ) {
540 return false;
541 }
542
543 $template_record['form_slug'] = 'standard';
544 $template_record['status'] = 'published';
545 $template_record['scope'] = 'global';
546 $template_record['owner_user_id'] = 0;
547 $template_record['booking_resource_id'] = null;
548 $template_record['is_default'] = 1;
549 $template_record['title'] = __( 'Standard', 'booking' );
550 $template_record['description'] = '';
551 $template_record['picture_url'] = isset( $template_record['picture_url'] ) ? (string) $template_record['picture_url'] : '';
552 if ( function_exists( 'wpbc_bfb_resolve_picture_url' ) ) {
553 $template_record['picture_url'] = wpbc_bfb_resolve_picture_url( $template_record['picture_url'] );
554 }
555
556 $booking_form_id = WPBC_BFB_Form_Storage::save_form( $template_record );
557
558 return ! empty( $booking_form_id );
559 }
560
561 /**
562 * Import legacy "standard" booking form as initial BFB structure.
563 *
564 * @return void
565 */
566 function wpbc_bfb__import_old_booking_forms() {
567
568 if ( wpbc_bfb_maybe_create_initial_standard_form_from_template() ) {
569 return;
570 }
571
572 // Get actual booking form structure.
573 $builder_structure_arr = wpbc_simple_form__export_to_bfb_structure();
574
575 $resource_id = wpbc_get_default_resource(); // FixIn: 2026-03-07.
576 $formdata = '';
577 $custom_form_name = 'standard';
578
579 $advanced_form = wpbc_get__booking_form_fields__configuration( $resource_id, $custom_form_name );
580 $content_form = wpbc_get__booking_form_data_configuration( $resource_id, $formdata );
581
582 $form_config = array(
583 'form_name' => 'standard',
584 'engine' => 'bfb',
585 'engine_version' => '1.0',
586 'structure_json' => wpbc_form_config__encode_json( $builder_structure_arr ),
587 'settings' => array(),
588 'advanced_form' => $advanced_form,
589 'content_form' => $content_form,
590 'owner_user_id' => 0,
591 'title' => 'Standard',
592 'description' => '',
593 'scope' => 'global',
594 'status' => 'published',
595 'is_default' => 1,
596 'booking_resource_id' => null,
597 );
598
599 // We do not need to update legacy options (booking_form, etc...) in BFB.
600 $sync_legacy = false;
601 // == One Saving point ==
602 $booking_form_id = wpbc_form_config_save( $form_config, array( 'sync_legacy' => (bool) $sync_legacy ) );
603
604 }
605
606
607 /**
608 * Remove BFB Preview page from rendered nav menus.
609 *
610 * @param array $sorted_menu_items Menu item objects.
611 * @param stdClass $args Menu args.
612 *
613 * @return array
614 */
615 function wpbc_bfb_preview__exclude_from_nav_menus( $sorted_menu_items, $args ) {
616
617 $page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );
618
619 if ( $page_id <= 0 ) {
620 return $sorted_menu_items;
621 }
622
623 $filtered_items = array();
624
625 foreach ( $sorted_menu_items as $menu_item ) {
626
627 $object_id = isset( $menu_item->object_id ) ? absint( $menu_item->object_id ) : 0;
628 $object = isset( $menu_item->object ) ? (string) $menu_item->object : '';
629
630 if ( ( 'page' === $object ) && ( $page_id === $object_id ) ) {
631 continue;
632 }
633
634 $filtered_items[] = $menu_item;
635 }
636
637 return $filtered_items;
638 }
639 add_filter( 'wp_nav_menu_objects', 'wpbc_bfb_preview__exclude_from_nav_menus', 10, 2 );
640
641
642 /**
643 * Exclude BFB Preview page from wp_list_pages() outputs.
644 *
645 * @param array $exclude_array Excluded page IDs.
646 *
647 * @return array
648 */
649 function wpbc_bfb_preview__exclude_from_page_lists( $exclude_array ) {
650
651 $page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );
652
653 if ( $page_id > 0 ) {
654 $exclude_array[] = $page_id;
655 }
656
657 return array_unique( array_map( 'absint', $exclude_array ) );
658 }
659 add_filter( 'wp_list_pages_excludes', 'wpbc_bfb_preview__exclude_from_page_lists' );
660
661
662 /**
663 * Remove BFB Preview page from get_pages() results.
664 *
665 * This is important for block themes, because the core Page List block
666 * renders its items from get_pages().
667 *
668 * @param array $pages Array of page objects.
669 * @param array $parsed_args Parsed get_pages() args.
670 *
671 * @return array
672 */
673 function wpbc_bfb_preview__exclude_from_get_pages( $pages, $parsed_args ) {
674
675 $page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );
676
677 if ( $page_id <= 0 ) {
678 return $pages;
679 }
680
681 $filtered_pages = array();
682
683 foreach ( $pages as $page_obj ) {
684
685 if ( empty( $page_obj ) || empty( $page_obj->ID ) ) {
686 $filtered_pages[] = $page_obj;
687 continue;
688 }
689
690 if ( absint( $page_obj->ID ) === $page_id ) {
691 continue;
692 }
693
694 $filtered_pages[] = $page_obj;
695 }
696
697 return $filtered_pages;
698 }
699 add_filter( 'get_pages', 'wpbc_bfb_preview__exclude_from_get_pages', 10, 2 );
700
701
702 /**
703 * Remove BFB Preview page from rendered Navigation Link blocks.
704 *
705 * This handles block-theme menus where the Preview page was manually
706 * inserted as a Navigation Link item.
707 *
708 * @param string $block_content Rendered block HTML.
709 * @param array $block Parsed block data.
710 * @param WP_Block $instance Block instance.
711 *
712 * @return string
713 */
714 function wpbc_bfb_preview__exclude_from_navigation_link_block( $block_content, $block, $instance ) {
715
716 $page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );
717
718 if ( $page_id <= 0 ) {
719 return $block_content;
720 }
721
722 if ( empty( $block['attrs'] ) || ! is_array( $block['attrs'] ) ) {
723 return $block_content;
724 }
725
726 $attrs = $block['attrs'];
727 $preview_url = get_permalink( $page_id );
728
729 $block_id = isset( $attrs['id'] ) ? absint( $attrs['id'] ) : 0;
730 $block_type = isset( $attrs['type'] ) ? (string) $attrs['type'] : '';
731 $block_kind = isset( $attrs['kind'] ) ? (string) $attrs['kind'] : '';
732 $block_url = isset( $attrs['url'] ) ? (string) $attrs['url'] : '';
733
734 if ( $block_id === $page_id ) {
735 return '';
736 }
737
738 if (
739 ( 'page' === $block_type )
740 &&
741 ( ( 'post-type' === $block_kind ) || ( '' === $block_kind ) )
742 &&
743 ( ! empty( $block_id ) )
744 &&
745 ( $block_id === $page_id )
746 ) {
747 return '';
748 }
749
750 if ( ( ! empty( $preview_url ) ) && ( ! empty( $block_url ) ) ) {
751
752 $normalized_preview_url = untrailingslashit( $preview_url );
753 $normalized_block_url = untrailingslashit( $block_url );
754
755 if ( $normalized_preview_url === $normalized_block_url ) {
756 return '';
757 }
758 }
759
760 return $block_content;
761 }
762 add_filter( 'render_block_core/navigation-link', 'wpbc_bfb_preview__exclude_from_navigation_link_block', 10, 3 );
763
764
765 /**
766 * Remove BFB Preview page from rendered Page List Item blocks.
767 *
768 * This is important for block themes like Twenty Twenty-Four,
769 * because the Navigation block can use a Page List block that renders
770 * individual core/page-list-item blocks.
771 *
772 * @param string $block_content Rendered block HTML.
773 * @param array $block Parsed block data.
774 * @param WP_Block $instance Block instance.
775 *
776 * @return string
777 */
778 function wpbc_bfb_preview__exclude_from_page_list_item_block( $block_content, $block, $instance ) {
779
780 $page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );
781
782 if ( $page_id <= 0 ) {
783 return $block_content;
784 }
785
786 if ( empty( $block['attrs'] ) || ! is_array( $block['attrs'] ) ) {
787 return $block_content;
788 }
789
790 $attrs = $block['attrs'];
791 $preview_url = get_permalink( $page_id );
792
793 $item_id = isset( $attrs['id'] ) ? absint( $attrs['id'] ) : 0;
794 $item_link = isset( $attrs['link'] ) ? (string) $attrs['link'] : '';
795
796 if ( $item_id === $page_id ) {
797 return '';
798 }
799
800 if ( ( ! empty( $preview_url ) ) && ( ! empty( $item_link ) ) ) {
801 if ( untrailingslashit( $preview_url ) === untrailingslashit( $item_link ) ) {
802 return '';
803 }
804 }
805
806 return $block_content;
807 }
808 add_filter( 'render_block_core/page-list-item', 'wpbc_bfb_preview__exclude_from_page_list_item_block', 10, 3 );
809
810
811 // FixIn: 10.15.3.1.
812 /**
813 * Check whether current request is the BFB Preview page request.
814 *
815 * @return bool
816 */
817 function wpbc_bfb_is_preview_request() {
818
819 if ( empty( $_GET['wpbc_bfb_preview'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
820 return false;
821 }
822
823 return ( '1' === sanitize_text_field( wp_unslash( $_GET['wpbc_bfb_preview'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
824 }
825
826 /**
827 * Add noindex / noarchive robots directives for BFB Preview.
828 *
829 * @param array $robots Robots directives.
830 *
831 * @return array
832 */
833 function wpbc_bfb_preview__wp_robots( $robots ) {
834
835 if ( ! wpbc_bfb_is_preview_request() ) {
836 return $robots;
837 }
838
839 return wp_robots_sensitive_page( $robots );
840 }
841 add_filter( 'wp_robots', 'wpbc_bfb_preview__wp_robots' );
842
843 /**
844 * Send no-cache headers for BFB Preview responses.
845 *
846 * @return void
847 */
848 function wpbc_bfb_preview__nocache_headers() {
849
850 if ( ! wpbc_bfb_is_preview_request() ) {
851 return;
852 }
853
854 if ( ! headers_sent() ) {
855 nocache_headers();
856 }
857 }
858 add_action( 'template_redirect', 'wpbc_bfb_preview__nocache_headers', 1 );
859
860 /**
861 * Import booking forms on activation of Pro versions of Booking Calendar.
862 *
863 * $mode = 'current_context'; // Import booking forms only for the == Current User == (usually - "Regular User").
864 * $mode = 'all_global'; // Import booking forms for == Super Booking Admin == user ( user_id = 0 ). or for pro versions in all other situations.
865 * $mode = 'all_users'; // Import booking forms for == All Users ==.
866 *
867 * @return void
868 */
869 function wpbc_bfb_import_legacy_forms__on_activation() {
870
871 if ( ! is_admin() ) {
872 return;
873 }
874
875 $import_version = '11.0.0';
876 if ( $import_version === get_option( 'wpbc_bfb_legacy_import_done_for_pro', '' ) ) {
877 return;
878 }
879
880 if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
881 return;
882 }
883
884 delete_transient( 'wpbc_pro_versions__late_activation_60' );
885
886 $summary = wpbc_bfb_import_legacy_forms(
887 array(
888 'mode' => ( class_exists( 'wpdev_bk_multiuser' ) ) ? 'all_users' : 'all_global',
889 'import_standard' => true,
890 'import_custom' => true,
891 'skip_if_exists' => ( wpbc_is_this_demo() ) ? false : true,
892 'set_bfb_form_not_defined' => true,
893 )
894 );
895 update_option( 'wpbc_bfb_legacy_import_done_for_pro', $import_version );
896 }
897 add_action( 'init', 'wpbc_bfb_import_legacy_forms__on_activation', 1000 );
898
899
900 /**
901 * Schedule one deferred legacy-form import after Pro activation. The import runs on a later request while this transient exists.
902 *
903 * @return void
904 */
905 function wpbc_pro_versions__late_activation(){
906
907 // Get any existing copy of our transient data
908 if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
909 // It wasn't there, so regenerate the data and save the transient
910 $is_in_action_late_activation = true;
911 set_transient( 'wpbc_pro_versions__late_activation_60', $is_in_action_late_activation, HOUR_IN_SECONDS );
912 }
913 }
914 add_bk_action( 'wpbc_other_versions_activation', 'wpbc_pro_versions__late_activation' );
915