# booking/11.4.3/includes/page-form-builder/save-load/bfb-activate.php

Booking Calendar, version 11.4.3. 1,237 lines.

- Page: https://pluginprobe.com/plugins/booking/11.4.3/code/includes/page-form-builder/save-load/bfb-activate.php
- Raw: https://pluginprobe.com/plugins/booking/11.4.3/raw/includes/page-form-builder/save-load/bfb-activate.php
- Modified: 2026-07-13T07:52:42+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/booking/11.4.3/code/includes/page-form-builder/save-load/bfb-activate.php#L10-L20`.

```php
<?php
/**
 * Booking Form Builder - Activation helpers.
 *
 * Responsibilities:
 * 1) Create BFB DB table (wp_booking_form_structures) on activation (if missing).
 * 2) Ensure the "Booking Form Preview" page exists during activation.
 *
 * @package     Booking Calendar.
 * @author      wpdevelop, oplugins
 * @web-site    https://wpbookingcalendar.com/
 * @email       info@wpbookingcalendar.com
 *
 * @since       11.0.x
 * @file        ../includes/page-form-builder/save-load/bfb-activate.php
 * @modified    2026-02-23
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Return option key where preview page ID is stored.
 *
 * Must match WPBC_BFB_Preview_Service::get_page_option_key().
 *
 * @return string
 */
function wpbc_bfb_activation__get_preview_page_option_key() {
	return 'wpbc_bfb_preview_page_id';
}

/**
 * Return meta key used to mark the preview page (for recovery).
 *
 * @return string
 */
function wpbc_bfb_activation__get_preview_page_meta_key() {
	return '_wpbc_bfb_preview_page';
}

/**
 * Return canonical slug for the preview page.
 *
 * @return string
 */
function wpbc_bfb_activation__get_preview_page_slug() {
	return 'wpbc-bfb-preview';
}

/**
 * Try to find an administrator user ID (best-effort).
 *
 * @return int Admin user ID, or 0 if not found.
 */
function wpbc_bfb_activation__get_any_admin_user_id() {

	$users = get_users( array(
		'role'   => 'administrator',
		'number' => 1,
		'fields' => array( 'ID' ),
	) );

	if ( empty( $users ) ) {
		return 0;
	}

	if ( is_object( $users[0] ) && isset( $users[0]->ID ) ) {
		return (int) $users[0]->ID;
	}

	if ( is_array( $users[0] ) && isset( $users[0]['ID'] ) ) {
		return (int) $users[0]['ID'];
	}

	return 0;
}

/**
 * Temporarily switch current user to an admin user if the current user
 * cannot create private pages (activation edge-cases like WP-CLI).
 *
 * @return int Previous user ID (0 if none). Caller should restore with wp_set_current_user().
 */
function wpbc_bfb_activation__maybe_switch_to_admin_user() {

	$prev_user_id = (int) get_current_user_id();

	// If current user can create pages, do nothing.
	if ( $prev_user_id > 0 && user_can( $prev_user_id, 'publish_pages' ) ) {
		return $prev_user_id;
	}

	$admin_id = wpbc_bfb_activation__get_any_admin_user_id();
	if ( $admin_id > 0 ) {
		wp_set_current_user( $admin_id );
	}

	return $prev_user_id;
}

/**
 * Restore previous user after temporary switch.
 *
 * @param int $prev_user_id Previous user ID.
 *
 * @return void
 */
function wpbc_bfb_activation__restore_user( $prev_user_id ) {

	$prev_user_id = (int) $prev_user_id;

	// Restore to previous user if we had one; otherwise, reset to 0.
	if ( $prev_user_id > 0 ) {
		wp_set_current_user( $prev_user_id );
	} else {
		wp_set_current_user( 0 );
	}
}

/**
 * Validate that a page ID is a real WP page.
 *
 * @param int $page_id Page ID.
 *
 * @return bool
 */
function wpbc_bfb_activation__is_valid_page_id( $page_id ) {

	$page_id = (int) $page_id;

	if ( $page_id <= 0 ) {
		return false;
	}

	$page = get_post( $page_id );

	return ( $page instanceof WP_Post && 'page' === $page->post_type );
}

/**
 * Try to locate an existing preview page by meta marker.
 *
 * @return int Page ID or 0.
 */
function wpbc_bfb_activation__find_preview_page_by_meta() {

	$meta_key = wpbc_bfb_activation__get_preview_page_meta_key();

	$q = new WP_Query( array(
		'post_type'        => 'page',
		'post_status'      => array( 'private', 'publish', 'draft', 'pending' ),
		'posts_per_page'   => 1,
		'fields'           => 'ids',
		'no_found_rows'    => true,
		'suppress_filters' => true,          // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters
		'meta_key'         => $meta_key,     // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
		'meta_value'       => '1',           // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
	) );

	if ( empty( $q->posts ) ) {
		return 0;
	}

	return (int) $q->posts[0];
}

/**
 * Try to locate an existing preview page by slug.
 *
 * @return int Page ID or 0.
 */
function wpbc_bfb_activation__find_preview_page_by_slug() {

	$slug = wpbc_bfb_activation__get_preview_page_slug();

	$page = get_page_by_path( $slug, OBJECT, 'page' );
	if ( $page instanceof WP_Post ) {
		return (int) $page->ID;
	}

	return 0;
}


/**
 * Force a safe template for the BFB Preview page.
 *
 * Why:
 * - The Preview page is a technical/service page.
 * - It should not inherit decorative page templates like "Page with wide Image".
 * - For block themes, prefer a clean template like "page-no-title" or "page".
 * - For classic themes, use the default page template.  // FixIn: 10.15.2.1
 *
 * @param int $page_id Page ID.
 *
 * @return bool
 */
function wpbc_bfb_preview__force_safe_template( $page_id ) {

	$page_id = absint( $page_id );

	if ( $page_id <= 0 ) {
		return false;
	}

	/*
	 * Always clear any previously assigned template first.
	 * This is important when an existing Preview page was previously using
	 * an unwanted template, for example "Page with wide Image".
	 */
	delete_post_meta( $page_id, '_wp_page_template' );

	// Block themes: prefer a cleaner built-in page template, if available.
	if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() && function_exists( 'get_block_templates' ) ) {

		$theme_slug        = get_stylesheet();
		$templates         = get_block_templates(
			array(
				'post_type' => 'page',
			),
			'wp_template'
		);
		$safe_template_slug = '';

		foreach ( $templates as $template ) {

			if ( empty( $template->slug ) || empty( $template->theme ) ) {
				continue;
			}

			if ( $theme_slug !== $template->theme ) {
				continue;
			}

			if ( 'page-no-title' === $template->slug ) {
				$safe_template_slug = 'page-no-title';
				break;
			}

			if ( ( '' === $safe_template_slug ) && ( 'page' === $template->slug ) ) {
				$safe_template_slug = 'page';
			}
		}

		if ( '' !== $safe_template_slug ) {
			$result = wp_update_post(
				array(
					'ID'            => $page_id,
					'page_template' => $safe_template_slug,
				),
				true
			);

			return ( ! is_wp_error( $result ) );
		}
	}

	return true;
}


/**
 * The preview page has status 'publish', because the secure the output by your nonce + cap
 *
 * Preview security is already enforced by:
 *
 * wpbc_bfb_preview=1 + token + nonce
 *
 * is_user_logged_in() + current_user_can( wpbc_bfb_get_manage_cap() )
 *
 * So the preview page itself does not need to be private.
 *
 * @return false|int
 */
function wpbc_bfb_activation__create_preview_page_raw() {

	$page_data = array(
		'post_title'     => __( 'Booking Form Preview', 'booking' ),
		'post_content'   => '', // Content will be injected dynamically at preview time  by bfb-preview.php.
		'post_status'    => 'publish',
		'post_type'      => 'page',
		'post_name'      => wpbc_bfb_activation__get_preview_page_slug(),
		'comment_status' => 'closed',
		'ping_status'    => 'closed',
	);

	$page_id = wp_insert_post( $page_data, true );

	if ( ( ! is_wp_error( $page_id ) ) && ( ! empty( $page_id ) ) ) {
		// Success.
		wpbc_bfb_preview__force_safe_template( $page_id );
	} else {
		if ( is_wp_error( $page_id ) ) {
			return false;
		}
		if ( ! $page_id ) {
			return false;
		}
		$page_id = false;
	}

	return (int) $page_id;
}


/**
 * Create the "Booking Form Preview" page and store option.
 *
 * @return int|false Page ID on success, false on failure.
 */
function wpbc_bfb_activation__create_preview_page() {

	$prev_user_id = wpbc_bfb_activation__maybe_switch_to_admin_user();

	$page_id = wpbc_bfb_activation__create_preview_page_raw();

	// Restore user context.
	wpbc_bfb_activation__restore_user( $prev_user_id );

	if ( empty( $page_id ) || is_wp_error( $page_id ) ) {
		return false;
	}

	$page_id = (int) $page_id;

	// Mark page for recovery if option is deleted later.
	add_post_meta( $page_id, wpbc_bfb_activation__get_preview_page_meta_key(), '1', true );

	// Store the page ID in option (same key used by preview service).
	update_option( wpbc_bfb_activation__get_preview_page_option_key(), $page_id );

	return $page_id;
}

/**
 * Ensure preview page exists (activation-time).
 *
 * - Validates stored option page ID.
 * - If missing, tries to find by meta marker.
 * - If missing, tries to find by slug.
 * - If still missing, creates a new private page.
 *
 * @return int|false Page ID, or false on failure.
 */
function wpbc_bfb_activation__ensure_preview_page_exists() {

	$option_key = wpbc_bfb_activation__get_preview_page_option_key();
	$page_id    = (int) get_option( $option_key );

	// 1) Option points to a valid page.
	if ( wpbc_bfb_activation__is_valid_page_id( $page_id ) ) {

		// Enforce publish status (best effort).
		$page = get_post( $page_id );
		if ( $page instanceof WP_Post && 'publish' !== $page->post_status ) {
			wp_update_post( array(
				'ID'          => (int) $page_id,
				'post_status' => 'publish',
			) );
		}

		// Ensure meta marker exists.
		wpbc_bfb_preview__force_safe_template( (int) $page_id );
		add_post_meta( (int) $page_id, wpbc_bfb_activation__get_preview_page_meta_key(), '1', true );

		return (int) $page_id;
	}

	// 2) Try recovery by meta marker.
	$found_id = wpbc_bfb_activation__find_preview_page_by_meta();
	if ( $found_id > 0 && wpbc_bfb_activation__is_valid_page_id( $found_id ) ) {
		$found_page = get_post( $found_id );
		if ( $found_page instanceof WP_Post && 'publish' !== $found_page->post_status ) {
			wp_update_post( array(
				'ID'          => (int) $found_id,
				'post_status' => 'publish',
			) );
		}
		wpbc_bfb_preview__force_safe_template( (int) $found_id );
		update_option( $option_key, (int) $found_id );
		return (int) $found_id;
	}

	// 3) Try recovery by slug.
	$found_id = wpbc_bfb_activation__find_preview_page_by_slug();
	if ( $found_id > 0 && wpbc_bfb_activation__is_valid_page_id( $found_id ) ) {
		$found_page = get_post( $found_id );
		if ( $found_page instanceof WP_Post && 'publish' !== $found_page->post_status ) {
			wp_update_post( array(
				'ID'          => (int) $found_id,
				'post_status' => 'publish',
			) );
		}
		wpbc_bfb_preview__force_safe_template( (int) $found_id );
		// Mark it as ours (so next time meta lookup works).
		add_post_meta( (int) $found_id, wpbc_bfb_activation__get_preview_page_meta_key(), '1', true );
		update_option( $option_key, (int) $found_id );
		return (int) $found_id;
	}

	// 4) Create.
	return wpbc_bfb_activation__create_preview_page();
}

/**
 * Activation hook entry: ensure the preview page exists.
 *
 * @return void
 */
function wpbc_bfb_activation__preview_page() {
	wpbc_bfb_activation__ensure_preview_page_exists();
}
add_bk_action( 'wpbc_free_version_activation', 'wpbc_bfb_activation__preview_page' );


/**
 *  A c t i v a t e  - Create new DB Table for Booking Form Builder structures.
 *
 * This table stores:
 *  - Canonical form builder structure as JSON (structure_json).
 *  - Additional settings as JSON (settings_json).
 *  - Optional precompiled HTML can be added later (not in this schema).
 *  - Ownership via owner_user_id (for MultiUser).
 *
 * @return void
 */
function wpbc_bfb_activation__form_structures_table() {

	global $wpdb;

	$charset_collate  = ( ! empty( $wpdb->charset ) ) ? 'DEFAULT CHARACTER SET ' . $wpdb->charset : '';
	$charset_collate .= ( ! empty( $wpdb->collate ) ) ? ' COLLATE ' . $wpdb->collate : '';

	if ( ! wpbc_is_table_exists( 'booking_form_structures' ) ) {



		$simple_sql = "CREATE TABLE {$wpdb->prefix}booking_form_structures (
			booking_form_id bigint(20) unsigned NOT NULL auto_increment,
			form_slug VARCHAR(191) NOT NULL,
			status VARCHAR(32) NOT NULL,
			owner_user_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,

			scope varchar(64) NOT NULL default 'global',
			version int(11) NOT NULL default 1,
			booking_resource_id BIGINT UNSIGNED NULL,

			engine varchar(32) NOT NULL default 'bfb',
			engine_version varchar(16) NOT NULL default '1.0',
			structure_json LONGTEXT NOT NULL,
			settings_json LONGTEXT NULL,
			advanced_form LONGTEXT NULL,
			content_form LONGTEXT NULL,

			is_default TINYINT(1) NOT NULL DEFAULT 0,
			title VARCHAR(255) NOT NULL,
			description TEXT NULL,
			picture_url text NULL,

			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,

			created_by bigint(20) unsigned DEFAULT NULL,
			updated_by bigint(20) unsigned DEFAULT NULL,
			PRIMARY KEY  (booking_form_id),
			UNIQUE KEY form_slug_status (form_slug, status, owner_user_id)
		) {$charset_collate}";

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$wpdb->query( $simple_sql );

		do_action( 'wpbc_bfb_activation__form_structures_table__after_create' );

		wpbc_bfb__import_old_booking_forms();
	} else {
		do_action( 'wpbc_bfb_activation__form_structures_table__table_already_exists' );
	}
}
add_bk_action( 'wpbc_free_version_activation', 'wpbc_bfb_activation__form_structures_table' );


/**
 * D e a c t i v a t e  - Drop Booking Form Builder structures table.
 *
 * @return void
 */
function wpbc_bfb_deactivation__form_structures_table() {

	global $wpdb;



	// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
	$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}booking_form_structures" );

	delete_bk_option( 'wpbc_bfb_legacy_import_done_for_pro' );
}
add_bk_action( 'wpbc_free_version_deactivation', 'wpbc_bfb_deactivation__form_structures_table' );


/**
 * Import legacy "standard" booking form as initial BFB structure.
 *
 * @return void
 */
function wpbc_bfb_is_brand_new_install__before_version_update() {

	$stored_version = get_option( 'booking_version_num', false );

	return ( false === $stored_version );
}

/**
 * Let the initial standard BFB form follow the global calendar days-selection setting.
 *
 * Some bundled templates intentionally override days selection for their own use case.
 * The installed "standard" form should not carry that template-level override, because
 * the global Settings > Calendar page is the canonical default for a new site.
 *
 * @param array $template_record Form Builder template record.
 *
 * @return array
 */
function wpbc_bfb_activation__set_standard_form_default_days_selection( $template_record ) {

	if ( empty( $template_record ) || ! is_array( $template_record ) ) {
		return $template_record;
	}

	$settings = array();
	if ( ! empty( $template_record['settings_json'] ) ) {
		$decoded = json_decode( (string) $template_record['settings_json'], true );
		if ( is_array( $decoded ) ) {
			$settings = $decoded;
		}
	}

	if ( empty( $settings['options'] ) || ! is_array( $settings['options'] ) ) {
		$settings['options'] = array();
	}

	$settings['options']['booking_type_of_day_selections'] = '';

	$template_record['settings_json'] = function_exists( 'wpbc_form_config__encode_json' )
		? wpbc_form_config__encode_json( $settings )
		: wp_json_encode( $settings );

	return $template_record;
}

/**
 * Maybe create the initial standard BFB form from a bundled template.
 *
 * Used only during brand new plugin activation, before booking_version_num
 * gets updated. Upgrades keep migrating the existing legacy configuration.
 *
 * @return bool
 */
function wpbc_bfb_maybe_create_initial_standard_form_from_template() {

	if ( ! wpbc_bfb_is_brand_new_install__before_version_update() ) {
		return false;
	}

	if ( ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
		return false;
	}

	if ( function_exists( 'wpbc_get_bfb_template_record_by_key' ) ) {
		// Default Booking Form Template - Just  after Booking Calendar activation!
		// $template_record = wpbc_get_bfb_template_record_by_key( 'time_appointments_3_steps_review_with_hints' );     // Time appointments.
		$template_record = wpbc_get_bfb_template_record_by_key( 'dates_2_columns_sidebar_hints' );                      // Full  Days - 2 Columns - with  dates hints.
	} else {
		$template_record = array();
	}

	if ( empty( $template_record ) || ! is_array( $template_record ) ) {
		return false;
	}

	$template_record = wpbc_bfb_activation__set_standard_form_default_days_selection( $template_record );

	$template_record['form_slug']           = 'standard';
	$template_record['status']              = 'published';
	$template_record['scope']               = 'global';
	$template_record['owner_user_id']       = 0;
	$template_record['booking_resource_id'] = null;
	$template_record['is_default']          = 1;
	$template_record['title']               = __( 'Standard', 'booking' );
	$template_record['description']         = '';
	$template_record['picture_url']         = isset( $template_record['picture_url'] ) ? (string) $template_record['picture_url'] : '';
	if ( function_exists( 'wpbc_bfb_resolve_picture_url' ) ) {
		$template_record['picture_url'] = wpbc_bfb_resolve_picture_url( $template_record['picture_url'] );
	}

	$booking_form_id = WPBC_BFB_Form_Storage::save_form( $template_record );

	return ! empty( $booking_form_id );
}


/**
 * Get the dedicated bundled template for the current live-demo edition.
 *
 * @param int $owner_user_id Optional MultiUser owner ID.
 *
 * @return string Template key, or an empty string outside a supported demo.
 */
function wpbc_bfb_live_demo__get_template_key( $owner_user_id = 0 ) {

	if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
		return '';
	}

	$owner_user_id = absint( $owner_user_id );

	if ( class_exists( 'wpdev_bk_multiuser' ) ) {
		return ( $owner_user_id > 0 ) ? 'demo_multiuser_owner_1' : 'demo_multiuser';
	}
	if ( class_exists( 'wpdev_bk_biz_l' ) ) {
		return 'demo_business_large';
	}
	if ( class_exists( 'wpdev_bk_biz_m' ) ) {
		return 'demo_business_medium';
	}
	if ( class_exists( 'wpdev_bk_biz_s' ) ) {
		return 'demo_business_small';
	}
	if ( class_exists( 'wpdev_bk_personal' ) ) {
		return 'demo_personal';
	}

	return '';
}


/**
 * Get the global Form Style used by the current live-demo edition.
 *
 * @return string Form Style preset key.
 */
function wpbc_bfb_live_demo__get_form_style() {

	if ( class_exists( 'wpdev_bk_multiuser' ) || class_exists( 'wpdev_bk_biz_l' ) ) {
		return 'light_bordered';
	}
	if ( class_exists( 'wpdev_bk_biz_m' ) ) {
		return 'light_soft';
	}
	if ( class_exists( 'wpdev_bk_biz_s' ) ) {
		return 'light_bordered';
	}
	if ( class_exists( 'wpdev_bk_personal' ) ) {
		return 'light_none';
	}

	return 'light_bordered';
}


/**
 * Provision a live-demo standard form from a real bundled BFB template.
 *
 * Normal owner activation is idempotent and preserves an existing form. The
 * explicit demo reset path may request replacement to restore fixture data.
 *
 * @param int    $owner_user_id Owner ID, or 0 for the global/Super Admin form.
 * @param string $template_key  Optional explicit bundled template key.
 * @param bool   $replace       Whether to replace an existing standard form.
 *
 * @return int|false Booking form ID on success, false on failure.
 */
function wpbc_bfb_live_demo__provision_standard_form( $owner_user_id = 0, $template_key = '', $replace = false ) {

	if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
		return false;
	}
	if ( ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
		return false;
	}
	if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
		return false;
	}

	$owner_user_id = absint( $owner_user_id );
	$template_key  = sanitize_key( (string) $template_key );
	if ( '' === $template_key ) {
		$template_key = wpbc_bfb_live_demo__get_template_key( $owner_user_id );
	}
	if ( '' === $template_key ) {
		return false;
	}

	$existing = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', $owner_user_id, 'published' );
	if ( ! empty( $existing->booking_form_id ) && ! $replace ) {
		return (int) $existing->booking_form_id;
	}

	$template_record = function_exists( 'wpbc_get_bfb_template_record_by_key' )
		? wpbc_get_bfb_template_record_by_key( $template_key )
		: array();

	if (
		empty( $template_record ) ||
		! is_array( $template_record ) ||
		empty( $template_record['structure_json'] ) ||
		empty( $template_record['engine'] ) ||
		'bfb' !== (string) $template_record['engine']
	) {
		return false;
	}

	$template_record['form_slug']           = 'standard';
	$template_record['status']              = 'published';
	$template_record['scope']               = ( $owner_user_id > 0 ) ? 'user' : 'global';
	$template_record['owner_user_id']       = $owner_user_id;
	$template_record['booking_resource_id'] = null;
	$template_record['is_default']          = 1;
	$template_record['title']               = __( 'Standard', 'booking' );
	$template_record['description']         = '';
	$template_record['picture_url']         = isset( $template_record['picture_url'] ) ? (string) $template_record['picture_url'] : '';

	if ( function_exists( 'wpbc_bfb_resolve_picture_url' ) ) {
		$template_record['picture_url'] = wpbc_bfb_resolve_picture_url( $template_record['picture_url'] );
	}

	$booking_form_id = WPBC_BFB_Form_Storage::save_form( $template_record );

	return ! empty( $booking_form_id ) ? (int) $booking_form_id : false;
}


/**
 * Return regular-owner fixtures used by the MultiUser live demo.
 *
 * @return array Owner user ID => bundled template key.
 */
function wpbc_bfb_live_demo__get_multiuser_owner_template_map() {

	$owner_templates = array(
		3 => 'demo_multiuser_owner_1',
		4 => 'demo_multiuser_owner_2',
		5 => 'demo_multiuser_owner_3',
	);

	/**
	 * Allow a private demo installation to use different owner IDs while
	 * retaining the same centralized provisioning flow.
	 *
	 * @param array $owner_templates Owner user ID => template key.
	 */
	$owner_templates = apply_filters( 'wpbc_bfb_live_demo_multiuser_owner_templates', $owner_templates );

	return is_array( $owner_templates ) ? $owner_templates : array();
}


/**
 * Apply all standard-form fixtures required by the active live demo.
 *
 * This is the canonical final activation step. It intentionally replaces demo
 * fixtures, but never runs on customer installations.
 *
 * @return bool True when every applicable fixture was saved.
 */
function wpbc_bfb_live_demo__provision_all_standard_forms() {

	if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
		return false;
	}

	// Pro-only reactivation does not necessarily rerun the Free activation
	// callback that normally synchronizes bundled template rows.
	if ( function_exists( 'wpbc_bfb_activation__seed_templates' ) ) {
		wpbc_bfb_activation__seed_templates();
	}

	$is_success = ( false !== wpbc_bfb_live_demo__provision_standard_form( 0, '', true ) );

	// Form Style is a site-wide setting, not part of an individual form row.
	// Write directly to the global option so the result is deterministic even
	// when finalization runs from a regular MultiUser administrator session.
	update_option( 'booking_form_style', wpbc_bfb_live_demo__get_form_style() );

	if ( class_exists( 'wpdev_bk_multiuser' ) ) {
		foreach ( wpbc_bfb_live_demo__get_multiuser_owner_template_map() as $owner_user_id => $template_key ) {
			$owner_user_id = absint( $owner_user_id );
			$template_key  = sanitize_key( (string) $template_key );
			if ( $owner_user_id <= 0 || '' === $template_key ) {
				$is_success = false;
				continue;
			}

			if ( function_exists( 'get_userdata' ) && ! get_userdata( $owner_user_id ) ) {
				$is_success = false;
				continue;
			}

			if ( false === wpbc_bfb_live_demo__provision_standard_form( $owner_user_id, $template_key, true ) ) {
				$is_success = false;
			}
		}
	}

	return $is_success;
}


/**
 * Ensure that a regular MultiUser owner has an independent standard BFB form.
 *
 * Existing owner forms are never overwritten. On normal installations the
 * current global standard form is cloned, preserving the Super Admin's chosen
 * Builder structure. Live demos use their dedicated bundled fixture instead.
 *
 * @param int $owner_user_id Regular MultiUser owner ID.
 *
 * @return int|false Booking form ID on success, false on failure.
 */
function wpbc_bfb_ensure_standard_form_for_owner( $owner_user_id ) {

	$owner_user_id = absint( $owner_user_id );
	if ( $owner_user_id <= 0 || ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
		return false;
	}
	if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
		return false;
	}

	$existing = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', $owner_user_id, 'published' );
	if ( ! empty( $existing->booking_form_id ) ) {
		return (int) $existing->booking_form_id;
	}

	if ( function_exists( 'wpbc_is_this_demo' ) && wpbc_is_this_demo() ) {
		return wpbc_bfb_live_demo__provision_standard_form( $owner_user_id, '', false );
	}

	$global_standard = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', 0, 'published' );
	$form_record     = ! empty( $global_standard ) ? get_object_vars( $global_standard ) : array();

	if ( empty( $form_record['structure_json'] ) && function_exists( 'wpbc_get_bfb_template_record_by_key' ) ) {
		$form_record = wpbc_get_bfb_template_record_by_key( 'dates_2_columns_sidebar_hints' );
	}
	if (
		empty( $form_record ) ||
		! is_array( $form_record ) ||
		empty( $form_record['structure_json'] ) ||
		empty( $form_record['engine'] ) ||
		'bfb' !== (string) $form_record['engine']
	) {
		return false;
	}

	unset(
		$form_record['booking_form_id'],
		$form_record['created_at'],
		$form_record['created_by'],
		$form_record['updated_at'],
		$form_record['updated_by']
	);

	$form_record['form_slug']           = 'standard';
	$form_record['status']              = 'published';
	$form_record['scope']               = 'user';
	$form_record['owner_user_id']       = $owner_user_id;
	$form_record['booking_resource_id'] = null;
	$form_record['is_default']          = 1;
	$form_record['title']               = __( 'Standard', 'booking' );
	$form_record['description']         = '';

	$booking_form_id = WPBC_BFB_Form_Storage::save_form( $form_record );

	return ! empty( $booking_form_id ) ? (int) $booking_form_id : false;
}

/**
 * Import legacy "standard" booking form as initial BFB structure.
 *
 * @return void
 */
function wpbc_bfb__import_old_booking_forms() {

	if ( wpbc_bfb_maybe_create_initial_standard_form_from_template() ) {
		return;
	}

	if ( function_exists( 'wpbc_bfb_import_legacy_forms' ) ) {
		wpbc_bfb_import_legacy_forms(
			array(
				'mode'                     => 'all_global',
				'import_standard'          => true,
				'import_custom'            => true,
				'skip_if_exists'           => true,
				'set_bfb_form_not_defined' => false,
			)
		);
	}
}


/**
 * Remove BFB Preview page from rendered nav menus.
 *
 * @param array    $sorted_menu_items Menu item objects.
 * @param stdClass $args              Menu args.
 *
 * @return array
 */
function wpbc_bfb_preview__exclude_from_nav_menus( $sorted_menu_items, $args ) {

	$page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );

	if ( $page_id <= 0 ) {
		return $sorted_menu_items;
	}

	$filtered_items = array();

	foreach ( $sorted_menu_items as $menu_item ) {

		$object_id = isset( $menu_item->object_id ) ? absint( $menu_item->object_id ) : 0;
		$object    = isset( $menu_item->object ) ? (string) $menu_item->object : '';

		if ( ( 'page' === $object ) && ( $page_id === $object_id ) ) {
			continue;
		}

		$filtered_items[] = $menu_item;
	}

	return $filtered_items;
}
add_filter( 'wp_nav_menu_objects', 'wpbc_bfb_preview__exclude_from_nav_menus', 10, 2 );


/**
 * Exclude BFB Preview page from wp_list_pages() outputs.
 *
 * @param array $exclude_array Excluded page IDs.
 *
 * @return array
 */
function wpbc_bfb_preview__exclude_from_page_lists( $exclude_array ) {

	$page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );

	if ( $page_id > 0 ) {
		$exclude_array[] = $page_id;
	}

	return array_unique( array_map( 'absint', $exclude_array ) );
}
add_filter( 'wp_list_pages_excludes', 'wpbc_bfb_preview__exclude_from_page_lists' );


/**
 * Remove BFB Preview page from get_pages() results.
 *
 * This is important for block themes, because the core Page List block
 * renders its items from get_pages().
 *
 * @param array $pages       Array of page objects.
 * @param array $parsed_args Parsed get_pages() args.
 *
 * @return array
 */
function wpbc_bfb_preview__exclude_from_get_pages( $pages, $parsed_args ) {

	$page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );

	if ( $page_id <= 0 ) {
		return $pages;
	}

	$filtered_pages = array();

	foreach ( $pages as $page_obj ) {

		if ( empty( $page_obj ) || empty( $page_obj->ID ) ) {
			$filtered_pages[] = $page_obj;
			continue;
		}

		if ( absint( $page_obj->ID ) === $page_id ) {
			continue;
		}

		$filtered_pages[] = $page_obj;
	}

	return $filtered_pages;
}
add_filter( 'get_pages', 'wpbc_bfb_preview__exclude_from_get_pages', 10, 2 );


/**
 * Remove BFB Preview page from rendered Navigation Link blocks.
 *
 * This handles block-theme menus where the Preview page was manually
 * inserted as a Navigation Link item.
 *
 * @param string   $block_content Rendered block HTML.
 * @param array    $block         Parsed block data.
 * @param WP_Block $instance      Block instance.
 *
 * @return string
 */
function wpbc_bfb_preview__exclude_from_navigation_link_block( $block_content, $block, $instance ) {

	$page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );

	if ( $page_id <= 0 ) {
		return $block_content;
	}

	if ( empty( $block['attrs'] ) || ! is_array( $block['attrs'] ) ) {
		return $block_content;
	}

	$attrs       = $block['attrs'];
	$preview_url = get_permalink( $page_id );

	$block_id    = isset( $attrs['id'] ) ? absint( $attrs['id'] ) : 0;
	$block_type  = isset( $attrs['type'] ) ? (string) $attrs['type'] : '';
	$block_kind  = isset( $attrs['kind'] ) ? (string) $attrs['kind'] : '';
	$block_url   = isset( $attrs['url'] ) ? (string) $attrs['url'] : '';

	if ( $block_id === $page_id ) {
		return '';
	}

	if (
		( 'page' === $block_type )
		&&
		( ( 'post-type' === $block_kind ) || ( '' === $block_kind ) )
		&&
		( ! empty( $block_id ) )
		&&
		( $block_id === $page_id )
	) {
		return '';
	}

	if ( ( ! empty( $preview_url ) ) && ( ! empty( $block_url ) ) ) {

		$normalized_preview_url = untrailingslashit( $preview_url );
		$normalized_block_url   = untrailingslashit( $block_url );

		if ( $normalized_preview_url === $normalized_block_url ) {
			return '';
		}
	}

	return $block_content;
}
add_filter( 'render_block_core/navigation-link', 'wpbc_bfb_preview__exclude_from_navigation_link_block', 10, 3 );


/**
 * Remove BFB Preview page from rendered Page List Item blocks.
 *
 * This is important for block themes like Twenty Twenty-Four,
 * because the Navigation block can use a Page List block that renders
 * individual core/page-list-item blocks.
 *
 * @param string   $block_content Rendered block HTML.
 * @param array    $block         Parsed block data.
 * @param WP_Block $instance      Block instance.
 *
 * @return string
 */
function wpbc_bfb_preview__exclude_from_page_list_item_block( $block_content, $block, $instance ) {

	$page_id = absint( get_option( wpbc_bfb_activation__get_preview_page_option_key() ) );

	if ( $page_id <= 0 ) {
		return $block_content;
	}

	if ( empty( $block['attrs'] ) || ! is_array( $block['attrs'] ) ) {
		return $block_content;
	}

	$attrs       = $block['attrs'];
	$preview_url = get_permalink( $page_id );

	$item_id   = isset( $attrs['id'] ) ? absint( $attrs['id'] ) : 0;
	$item_link = isset( $attrs['link'] ) ? (string) $attrs['link'] : '';

	if ( $item_id === $page_id ) {
		return '';
	}

	if ( ( ! empty( $preview_url ) ) && ( ! empty( $item_link ) ) ) {
		if ( untrailingslashit( $preview_url ) === untrailingslashit( $item_link ) ) {
			return '';
		}
	}

	return $block_content;
}
add_filter( 'render_block_core/page-list-item', 'wpbc_bfb_preview__exclude_from_page_list_item_block', 10, 3 );


// FixIn: 10.15.3.1.
/**
 * Check whether current request is the BFB Preview page request.
 *
 * @return bool
 */
function wpbc_bfb_is_preview_request() {

	if ( empty( $_GET['wpbc_bfb_preview'] ) ) {                              // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return false;
	}

	return ( '1' === sanitize_text_field( wp_unslash( $_GET['wpbc_bfb_preview'] ) ) );   // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}

/**
 * Add noindex / noarchive robots directives for BFB Preview.
 *
 * @param array $robots Robots directives.
 *
 * @return array
 */
function wpbc_bfb_preview__wp_robots( $robots ) {

	if ( ! wpbc_bfb_is_preview_request() ) {
		return $robots;
	}

	return wp_robots_sensitive_page( $robots );
}
add_filter( 'wp_robots', 'wpbc_bfb_preview__wp_robots' );

/**
 * Send no-cache headers for BFB Preview responses.
 *
 * @return void
 */
function wpbc_bfb_preview__nocache_headers() {

	if ( ! wpbc_bfb_is_preview_request() ) {
		return;
	}

	if ( ! headers_sent() ) {
		nocache_headers();
	}
}
add_action( 'template_redirect', 'wpbc_bfb_preview__nocache_headers', 1 );

/**
 * Import booking forms on activation  of Pro versions of Booking Calendar.
 *
 *    $mode = 'current_context';    // Import booking forms  only  for the == Current User == (usually - "Regular User").
 *    $mode = 'all_global';         // Import booking forms for == Super Booking Admin == user ( user_id = 0 ).  or for pro versions in all  other situations.
 *    $mode = 'all_users';          // Import booking forms for == All Users ==.
 *
 * @return void
 */
function wpbc_bfb_import_legacy_forms__on_activation() {

	if ( ! is_admin() ) {
		return;
	}

	if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
		return;
	}

	delete_transient( 'wpbc_pro_versions__late_activation_60' );

	$import_version = '11.3.1';

	// Live demos use dedicated BFB fixtures as their canonical source. Importing
	// legacy options here would overwrite the fixtures installed during the
	// activation request, especially because the old demo importer used
	// skip_if_exists=false.
	if ( wpbc_is_this_demo() ) {
		if ( wpbc_bfb_live_demo__provision_all_standard_forms() ) {
			update_option( 'wpbc_bfb_legacy_import_done_for_pro', $import_version );
		} else {
			// Keep a bounded retry available if activation dependencies were not
			// ready yet on this request.
			$retry_count = is_numeric( $is_in_action_late_activation ) ? absint( $is_in_action_late_activation ) : 0;
			if ( $retry_count < 3 ) {
				set_transient( 'wpbc_pro_versions__late_activation_60', $retry_count + 1, HOUR_IN_SECONDS );
			}
		}
		return;
	}

	if ( $import_version === get_option( 'wpbc_bfb_legacy_import_done_for_pro', '' ) ) {
		return;
	}

	$summary = wpbc_bfb_import_legacy_forms(
		array(
			'mode'                     => ( class_exists( 'wpdev_bk_multiuser' ) ) ? 'all_users' : 'all_global',
			'import_standard'          => true,
			'import_custom'            => true,
			'skip_if_exists'           => true,
			'set_bfb_form_not_defined' => true,
		)
	);
	update_option( 'wpbc_bfb_legacy_import_done_for_pro', $import_version );
}
add_action( 'init', 'wpbc_bfb_import_legacy_forms__on_activation', 1000 );


/**
 * Schedule one deferred legacy-form import after Pro activation.  The import runs on a later request while this transient exists.
 *
 * @return void
 */
function wpbc_pro_versions__late_activation(){

	// A regular MultiUser owner activation runs the Pro activation callbacks in
	// its own context. It must not schedule a later demo-wide reset.
	if ( false !== apply_bk_filter( 'wpbc_is_user_in_activation_process' ) ) {
		return;
	}

	// Get any existing copy of our transient data
	if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
		// It wasn't there, so regenerate the data and save the transient
		$is_in_action_late_activation = true;
		set_transient( 'wpbc_pro_versions__late_activation_60', $is_in_action_late_activation, HOUR_IN_SECONDS );
	}
}
add_bk_action( 'wpbc_other_versions_activation', 'wpbc_pro_versions__late_activation' );

```
