PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
11.8.4 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 All 204 releases
← All changes | includes/page-form-builder/save-load/bfb-activate.php +391 -363 11.511.8.4 View file →
@@ -1,4 +1,4 @@
1 1 <?php
2 2 /**
3 3 * Booking Form Builder - Activation helpers.
4 4 *
@@ -273,16 +273,16 @@
273 273 * So the preview page itself does not need to be private.
274 274 *
275 275 * @return false|int
276 276 */
277 -function wpbc_bfb_activation__create_preview_page_raw() {
278 -
279 - /* Reuse an existing preview page on demos, but never auto-create one. */
280 - if ( function_exists( 'wpbc_is_this_demo' ) && wpbc_is_this_demo() ) {
281 - return false;
282 - }
283 -
284 - $page_data = array(
277 +function wpbc_bfb_activation__create_preview_page_raw() {
278 +
279 + /* Reuse an existing preview page on demos, but never auto-create one. */
280 + if ( function_exists( 'wpbc_is_this_demo' ) && wpbc_is_this_demo() ) {
281 + return false;
282 + }
283 +
284 + $page_data = array(
285 285 'post_title' => __( 'Booking Form Preview', 'booking' ),
286 286 'post_content' => '', // Content will be injected dynamically at preview time by bfb-preview.php.
287 287 'post_status' => 'publish',
288 288 'post_type' => 'page',
@@ -414,8 +414,14 @@
414 414 *
415 415 * @return void
416 416 */
417 417 function wpbc_bfb_activation__preview_page() {
418 + // Activation callbacks also run during version upgrades. Keep page creation
419 + // strictly inside the verified first-install boundary.
420 + if ( ! function_exists( 'wpbc_should_create_activation_pages' ) || ! wpbc_should_create_activation_pages() ) {
421 + return;
422 + }
423 +
418 424 wpbc_bfb_activation__ensure_preview_page_exists();
419 425 }
420 426 add_bk_action( 'wpbc_free_version_activation', 'wpbc_bfb_activation__preview_page' );
421 427
@@ -505,17 +511,20 @@
505 511 add_bk_action( 'wpbc_free_version_deactivation', 'wpbc_bfb_deactivation__form_structures_table' );
506 512
507 513
508 514 /**
509 - * Import legacy "standard" booking form as initial BFB structure.
515 + * Check the shared activation decision before provisioning a Standard form.
510 516 *
511 - * @return void
517 + * The wrapper name is retained for compatibility with existing Form Builder
518 + * callers and tests. The core detector additionally requires the canonical
519 + * booking table to be absent, so a missing version option on an established
520 + * installation cannot be mistaken for a new install.
521 + *
522 + * @return bool True only during a genuine first-install activation request.
512 523 */
513 524 function wpbc_bfb_is_brand_new_install__before_version_update() {
514 525
515 - $stored_version = get_option( 'booking_version_num', false );
516 -
517 - return ( false === $stored_version );
526 + return function_exists( 'wpbc_is_plugin_initial_install' ) && wpbc_is_plugin_initial_install();
518 527 }
519 528
520 529 /**
521 530 * Let the initial standard BFB form follow the global calendar days-selection setting.
@@ -555,8 +564,22 @@
555 564 return $template_record;
556 565 }
557 566
558 567 /**
568 + * Get the bundled template key used for a brand-new Standard form.
569 + *
570 + * Every customer edition starts with the spacious vertical full-day form. The
571 + * surrounding activation gate limits this choice to a genuine first install,
572 + * so upgrades, reactivations, and existing forms remain unchanged.
573 + *
574 + * @return string Stable bundled template key for a genuine first install.
575 + */
576 +function wpbc_bfb_activation__get_initial_standard_template_key() {
577 +
578 + return 'dates_vertical_hints_full_days';
579 +}
580 +
581 +/**
559 582 * Maybe create the initial standard BFB form from a bundled template.
560 583 *
561 584 * Used only during brand new plugin activation, before booking_version_num
562 585 * gets updated. Upgrades keep migrating the existing legacy configuration.
@@ -562,9 +585,9 @@
562 585 * gets updated. Upgrades keep migrating the existing legacy configuration.
563 586 *
564 587 * @return bool
565 588 */
566 -function wpbc_bfb_maybe_create_initial_standard_form_from_template() {
589 +function wpbc_bfb_maybe_create_initial_standard_form_from_template() {
567 590
568 591 if ( ! wpbc_bfb_is_brand_new_install__before_version_update() ) {
569 592 return false;
570 593 }
@@ -573,11 +596,16 @@
573 596 return false;
574 597 }
575 598
576 599 if ( function_exists( 'wpbc_get_bfb_template_record_by_key' ) ) {
577 - // Default Booking Form Template - Just after Booking Calendar activation!
578 - // $template_record = wpbc_get_bfb_template_record_by_key( 'time_appointments_3_steps_review_with_hints' ); // Time appointments.
579 - $template_record = wpbc_get_bfb_template_record_by_key( 'dates_2_columns_sidebar_hints' ); // Full Days - 2 Columns - with dates hints.
600 + $template_key = wpbc_bfb_activation__get_initial_standard_template_key();
601 + $template_record = wpbc_get_bfb_template_record_by_key( $template_key );
602 +
603 + // Preserve a usable first-install form if a registry filter removes the
604 + // new starter template.
605 + if ( empty( $template_record ) && 'dates_2_columns_sidebar_hints' !== $template_key ) {
606 + $template_record = wpbc_get_bfb_template_record_by_key( 'dates_2_columns_sidebar_hints' );
607 + }
580 608 } else {
581 609 $template_record = array();
582 610 }
583 611
@@ -601,320 +629,320 @@
601 629 }
602 630
603 631 $booking_form_id = WPBC_BFB_Form_Storage::save_form( $template_record );
604 632
605 - return ! empty( $booking_form_id );
606 -}
607 -
608 -
609 -/**
610 - * Get the dedicated bundled template for the current live-demo edition.
611 - *
612 - * @param int $owner_user_id Optional MultiUser owner ID.
613 - *
614 - * @return string Template key, or an empty string outside a supported demo.
615 - */
616 -function wpbc_bfb_live_demo__get_template_key( $owner_user_id = 0 ) {
617 -
618 - if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
619 - return '';
620 - }
621 -
622 - $owner_user_id = absint( $owner_user_id );
623 -
624 - if ( class_exists( 'wpdev_bk_multiuser' ) ) {
625 - return ( $owner_user_id > 0 ) ? 'demo_multiuser_owner_1' : 'demo_multiuser';
626 - }
627 - if ( class_exists( 'wpdev_bk_biz_l' ) ) {
628 - return 'demo_business_large';
629 - }
630 - if ( class_exists( 'wpdev_bk_biz_m' ) ) {
631 - return 'demo_business_medium';
632 - }
633 - if ( class_exists( 'wpdev_bk_biz_s' ) ) {
634 - return 'demo_business_small';
635 - }
636 - if ( class_exists( 'wpdev_bk_personal' ) ) {
637 - return 'demo_personal';
638 - }
639 -
640 - return '';
641 -}
642 -
643 -
644 -/**
645 - * Get the global Form Style used by the current live-demo edition.
646 - *
647 - * @return string Form Style preset key.
648 - */
649 -function wpbc_bfb_live_demo__get_form_style() {
650 -
651 - if ( class_exists( 'wpdev_bk_multiuser' ) || class_exists( 'wpdev_bk_biz_l' ) ) {
652 - return 'light_bordered';
653 - }
654 - if ( class_exists( 'wpdev_bk_biz_m' ) ) {
655 - return 'light_soft';
656 - }
657 - if ( class_exists( 'wpdev_bk_biz_s' ) ) {
658 - return 'light_bordered';
659 - }
660 - if ( class_exists( 'wpdev_bk_personal' ) ) {
661 - return 'light_none';
662 - }
663 -
664 - return 'light_bordered';
665 -}
666 -
667 -
668 -/**
669 - * Provision a live-demo standard form from a real bundled BFB template.
670 - *
671 - * Normal owner activation is idempotent and preserves an existing form. The
672 - * explicit demo reset path may request replacement to restore fixture data.
673 - *
674 - * @param int $owner_user_id Owner ID, or 0 for the global/Super Admin form.
675 - * @param string $template_key Optional explicit bundled template key.
676 - * @param bool $replace Whether to replace an existing standard form.
677 - *
678 - * @return int|false Booking form ID on success, false on failure.
679 - */
680 -function wpbc_bfb_live_demo__provision_standard_form( $owner_user_id = 0, $template_key = '', $replace = false ) {
681 -
682 - if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
683 - return false;
684 - }
685 - if ( ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
686 - return false;
687 - }
688 - if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
689 - return false;
690 - }
691 -
692 - $owner_user_id = absint( $owner_user_id );
693 - $template_key = sanitize_key( (string) $template_key );
694 - if ( '' === $template_key ) {
695 - $template_key = wpbc_bfb_live_demo__get_template_key( $owner_user_id );
696 - }
697 - if ( '' === $template_key ) {
698 - return false;
699 - }
700 -
701 - $existing = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', $owner_user_id, 'published' );
702 - if ( ! empty( $existing->booking_form_id ) && ! $replace ) {
703 - return (int) $existing->booking_form_id;
704 - }
705 -
706 - $template_record = function_exists( 'wpbc_get_bfb_template_record_by_key' )
707 - ? wpbc_get_bfb_template_record_by_key( $template_key )
708 - : array();
709 -
710 - if (
711 - empty( $template_record ) ||
712 - ! is_array( $template_record ) ||
713 - empty( $template_record['structure_json'] ) ||
714 - empty( $template_record['engine'] ) ||
715 - 'bfb' !== (string) $template_record['engine']
716 - ) {
717 - return false;
718 - }
719 -
720 - $template_record['form_slug'] = 'standard';
721 - $template_record['status'] = 'published';
722 - $template_record['scope'] = ( $owner_user_id > 0 ) ? 'user' : 'global';
723 - $template_record['owner_user_id'] = $owner_user_id;
724 - $template_record['booking_resource_id'] = null;
725 - $template_record['is_default'] = 1;
726 - $template_record['title'] = __( 'Standard', 'booking' );
727 - $template_record['description'] = '';
728 - $template_record['picture_url'] = isset( $template_record['picture_url'] ) ? (string) $template_record['picture_url'] : '';
729 -
730 - if ( function_exists( 'wpbc_bfb_resolve_picture_url' ) ) {
731 - $template_record['picture_url'] = wpbc_bfb_resolve_picture_url( $template_record['picture_url'] );
732 - }
733 -
734 - $booking_form_id = WPBC_BFB_Form_Storage::save_form( $template_record );
735 -
736 - return ! empty( $booking_form_id ) ? (int) $booking_form_id : false;
737 -}
738 -
739 -
740 -/**
741 - * Return regular-owner fixtures used by the MultiUser live demo.
742 - *
743 - * @return array Owner user ID => bundled template key.
744 - */
745 -function wpbc_bfb_live_demo__get_multiuser_owner_template_map() {
746 -
747 - $owner_templates = array(
748 - 3 => 'demo_multiuser_owner_1',
749 - 4 => 'demo_multiuser_owner_2',
750 - 5 => 'demo_multiuser_owner_3',
751 - );
752 -
753 - /**
754 - * Allow a private demo installation to use different owner IDs while
755 - * retaining the same centralized provisioning flow.
756 - *
757 - * @param array $owner_templates Owner user ID => template key.
758 - */
759 - $owner_templates = apply_filters( 'wpbc_bfb_live_demo_multiuser_owner_templates', $owner_templates );
760 -
761 - return is_array( $owner_templates ) ? $owner_templates : array();
762 -}
763 -
764 -
765 -/**
766 - * Apply all standard-form fixtures required by the active live demo.
767 - *
768 - * This is the canonical final activation step. It intentionally replaces demo
769 - * fixtures, but never runs on customer installations.
770 - *
771 - * @return bool True when every applicable fixture was saved.
772 - */
773 -function wpbc_bfb_live_demo__provision_all_standard_forms() {
774 -
775 - if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
776 - return false;
777 - }
778 -
779 - // Pro-only reactivation does not necessarily rerun the Free activation
780 - // callback that normally synchronizes bundled template rows.
781 - if ( function_exists( 'wpbc_bfb_activation__seed_templates' ) ) {
782 - wpbc_bfb_activation__seed_templates();
783 - }
784 -
785 - $is_success = ( false !== wpbc_bfb_live_demo__provision_standard_form( 0, '', true ) );
786 -
787 - // Form Style is a site-wide setting, not part of an individual form row.
788 - // Write directly to the global option so the result is deterministic even
789 - // when finalization runs from a regular MultiUser administrator session.
790 - update_option( 'booking_form_style', wpbc_bfb_live_demo__get_form_style() );
791 -
792 - // Live demos intentionally showcase the shared accent experience. Customer
793 - // installations keep the backward-compatible disabled default.
794 - $form_accent_defaults = function_exists( 'wpbc_bfb_settings__get_default_form_accent_options' )
795 - ? wpbc_bfb_settings__get_default_form_accent_options()
796 - : array( 'booking_form_accent_color' => WPBC_DEFAULT_FORM_ACCENT_COLOR );
797 - update_option( 'booking_form_accent_enabled', 'On' );
798 - update_option( 'booking_form_accent_color', $form_accent_defaults['booking_form_accent_color'] );
799 -
800 - if ( class_exists( 'wpdev_bk_multiuser' ) ) {
801 - foreach ( wpbc_bfb_live_demo__get_multiuser_owner_template_map() as $owner_user_id => $template_key ) {
802 - $owner_user_id = absint( $owner_user_id );
803 - $template_key = sanitize_key( (string) $template_key );
804 - if ( $owner_user_id <= 0 || '' === $template_key ) {
805 - $is_success = false;
806 - continue;
807 - }
808 -
809 - if ( function_exists( 'get_userdata' ) && ! get_userdata( $owner_user_id ) ) {
810 - $is_success = false;
811 - continue;
812 - }
813 -
814 - if ( false === wpbc_bfb_live_demo__provision_standard_form( $owner_user_id, $template_key, true ) ) {
815 - $is_success = false;
816 - }
817 - }
818 - }
819 -
820 - return $is_success;
821 -}
822 -
823 -
824 -/**
825 - * Ensure that a regular MultiUser owner has an independent standard BFB form.
826 - *
827 - * Existing owner forms are never overwritten. On normal installations the
828 - * current global standard form is cloned, preserving the Super Admin's chosen
829 - * Builder structure. Live demos use their dedicated bundled fixture instead.
830 - *
831 - * @param int $owner_user_id Regular MultiUser owner ID.
832 - *
833 - * @return int|false Booking form ID on success, false on failure.
834 - */
835 -function wpbc_bfb_ensure_standard_form_for_owner( $owner_user_id ) {
836 -
837 - $owner_user_id = absint( $owner_user_id );
838 - if ( $owner_user_id <= 0 || ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
839 - return false;
840 - }
841 - if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
842 - return false;
843 - }
844 -
845 - $existing = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', $owner_user_id, 'published' );
846 - if ( ! empty( $existing->booking_form_id ) ) {
847 - return (int) $existing->booking_form_id;
848 - }
849 -
850 - if ( function_exists( 'wpbc_is_this_demo' ) && wpbc_is_this_demo() ) {
851 - return wpbc_bfb_live_demo__provision_standard_form( $owner_user_id, '', false );
852 - }
853 -
854 - $global_standard = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', 0, 'published' );
855 - $form_record = ! empty( $global_standard ) ? get_object_vars( $global_standard ) : array();
856 -
857 - if ( empty( $form_record['structure_json'] ) && function_exists( 'wpbc_get_bfb_template_record_by_key' ) ) {
858 - $form_record = wpbc_get_bfb_template_record_by_key( 'dates_2_columns_sidebar_hints' );
859 - }
860 - if (
861 - empty( $form_record ) ||
862 - ! is_array( $form_record ) ||
863 - empty( $form_record['structure_json'] ) ||
864 - empty( $form_record['engine'] ) ||
865 - 'bfb' !== (string) $form_record['engine']
866 - ) {
867 - return false;
868 - }
869 -
870 - unset(
871 - $form_record['booking_form_id'],
872 - $form_record['created_at'],
873 - $form_record['created_by'],
874 - $form_record['updated_at'],
875 - $form_record['updated_by']
876 - );
877 -
878 - $form_record['form_slug'] = 'standard';
879 - $form_record['status'] = 'published';
880 - $form_record['scope'] = 'user';
881 - $form_record['owner_user_id'] = $owner_user_id;
882 - $form_record['booking_resource_id'] = null;
883 - $form_record['is_default'] = 1;
884 - $form_record['title'] = __( 'Standard', 'booking' );
885 - $form_record['description'] = '';
886 -
887 - $booking_form_id = WPBC_BFB_Form_Storage::save_form( $form_record );
888 -
889 - return ! empty( $booking_form_id ) ? (int) $booking_form_id : false;
890 -}
633 + return ! empty( $booking_form_id );
634 +}
891 635
636 +
892 637 /**
638 + * Get the dedicated bundled template for the current live-demo edition.
639 + *
640 + * @param int $owner_user_id Optional MultiUser owner ID.
641 + *
642 + * @return string Template key, or an empty string outside a supported demo.
643 + */
644 +function wpbc_bfb_live_demo__get_template_key( $owner_user_id = 0 ) {
645 +
646 + if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
647 + return '';
648 + }
649 +
650 + $owner_user_id = absint( $owner_user_id );
651 +
652 + if ( class_exists( 'wpdev_bk_multiuser' ) ) {
653 + return ( $owner_user_id > 0 ) ? 'demo_multiuser_owner_1' : 'demo_multiuser';
654 + }
655 + if ( class_exists( 'wpdev_bk_biz_l' ) ) {
656 + return 'demo_business_large';
657 + }
658 + if ( class_exists( 'wpdev_bk_biz_m' ) ) {
659 + return 'demo_business_medium';
660 + }
661 + if ( class_exists( 'wpdev_bk_biz_s' ) ) {
662 + return 'demo_business_small';
663 + }
664 + if ( class_exists( 'wpdev_bk_personal' ) ) {
665 + return 'demo_personal';
666 + }
667 +
668 + return '';
669 +}
670 +
671 +
672 +/**
673 + * Get the global Form Style used by the current live-demo edition.
674 + *
675 + * @return string Form Style preset key.
676 + */
677 +function wpbc_bfb_live_demo__get_form_style() {
678 +
679 + if ( class_exists( 'wpdev_bk_multiuser' ) || class_exists( 'wpdev_bk_biz_l' ) ) {
680 + return 'light_bordered';
681 + }
682 + if ( class_exists( 'wpdev_bk_biz_m' ) ) {
683 + return 'light_soft';
684 + }
685 + if ( class_exists( 'wpdev_bk_biz_s' ) ) {
686 + return 'light_bordered';
687 + }
688 + if ( class_exists( 'wpdev_bk_personal' ) ) {
689 + return 'light_none';
690 + }
691 +
692 + return 'light_bordered';
693 +}
694 +
695 +
696 +/**
697 + * Provision a live-demo standard form from a real bundled BFB template.
698 + *
699 + * Normal owner activation is idempotent and preserves an existing form. The
700 + * explicit demo reset path may request replacement to restore fixture data.
701 + *
702 + * @param int $owner_user_id Owner ID, or 0 for the global/Super Admin form.
703 + * @param string $template_key Optional explicit bundled template key.
704 + * @param bool $replace Whether to replace an existing standard form.
705 + *
706 + * @return int|false Booking form ID on success, false on failure.
707 + */
708 +function wpbc_bfb_live_demo__provision_standard_form( $owner_user_id = 0, $template_key = '', $replace = false ) {
709 +
710 + if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
711 + return false;
712 + }
713 + if ( ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
714 + return false;
715 + }
716 + if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
717 + return false;
718 + }
719 +
720 + $owner_user_id = absint( $owner_user_id );
721 + $template_key = sanitize_key( (string) $template_key );
722 + if ( '' === $template_key ) {
723 + $template_key = wpbc_bfb_live_demo__get_template_key( $owner_user_id );
724 + }
725 + if ( '' === $template_key ) {
726 + return false;
727 + }
728 +
729 + $existing = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', $owner_user_id, 'published' );
730 + if ( ! empty( $existing->booking_form_id ) && ! $replace ) {
731 + return (int) $existing->booking_form_id;
732 + }
733 +
734 + $template_record = function_exists( 'wpbc_get_bfb_template_record_by_key' )
735 + ? wpbc_get_bfb_template_record_by_key( $template_key )
736 + : array();
737 +
738 + if (
739 + empty( $template_record ) ||
740 + ! is_array( $template_record ) ||
741 + empty( $template_record['structure_json'] ) ||
742 + empty( $template_record['engine'] ) ||
743 + 'bfb' !== (string) $template_record['engine']
744 + ) {
745 + return false;
746 + }
747 +
748 + $template_record['form_slug'] = 'standard';
749 + $template_record['status'] = 'published';
750 + $template_record['scope'] = ( $owner_user_id > 0 ) ? 'user' : 'global';
751 + $template_record['owner_user_id'] = $owner_user_id;
752 + $template_record['booking_resource_id'] = null;
753 + $template_record['is_default'] = 1;
754 + $template_record['title'] = __( 'Standard', 'booking' );
755 + $template_record['description'] = '';
756 + $template_record['picture_url'] = isset( $template_record['picture_url'] ) ? (string) $template_record['picture_url'] : '';
757 +
758 + if ( function_exists( 'wpbc_bfb_resolve_picture_url' ) ) {
759 + $template_record['picture_url'] = wpbc_bfb_resolve_picture_url( $template_record['picture_url'] );
760 + }
761 +
762 + $booking_form_id = WPBC_BFB_Form_Storage::save_form( $template_record );
763 +
764 + return ! empty( $booking_form_id ) ? (int) $booking_form_id : false;
765 +}
766 +
767 +
768 +/**
769 + * Return regular-owner fixtures used by the MultiUser live demo.
770 + *
771 + * @return array Owner user ID => bundled template key.
772 + */
773 +function wpbc_bfb_live_demo__get_multiuser_owner_template_map() {
774 +
775 + $owner_templates = array(
776 + 3 => 'demo_multiuser_owner_1',
777 + 4 => 'demo_multiuser_owner_2',
778 + 5 => 'demo_multiuser_owner_3',
779 + );
780 +
781 + /**
782 + * Allow a private demo installation to use different owner IDs while
783 + * retaining the same centralized provisioning flow.
784 + *
785 + * @param array $owner_templates Owner user ID => template key.
786 + */
787 + $owner_templates = apply_filters( 'wpbc_bfb_live_demo_multiuser_owner_templates', $owner_templates );
788 +
789 + return is_array( $owner_templates ) ? $owner_templates : array();
790 +}
791 +
792 +
793 +/**
794 + * Apply all standard-form fixtures required by the active live demo.
795 + *
796 + * This is the canonical final activation step. It intentionally replaces demo
797 + * fixtures, but never runs on customer installations.
798 + *
799 + * @return bool True when every applicable fixture was saved.
800 + */
801 +function wpbc_bfb_live_demo__provision_all_standard_forms() {
802 +
803 + if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
804 + return false;
805 + }
806 +
807 + // Pro-only reactivation does not necessarily rerun the Free activation
808 + // callback that normally synchronizes bundled template rows.
809 + if ( function_exists( 'wpbc_bfb_activation__seed_templates' ) ) {
810 + wpbc_bfb_activation__seed_templates();
811 + }
812 +
813 + $is_success = ( false !== wpbc_bfb_live_demo__provision_standard_form( 0, '', true ) );
814 +
815 + // Form Style is a site-wide setting, not part of an individual form row.
816 + // Write directly to the global option so the result is deterministic even
817 + // when finalization runs from a regular MultiUser administrator session.
818 + update_option( 'booking_form_style', wpbc_bfb_live_demo__get_form_style() );
819 +
820 + // Live demos intentionally showcase the shared accent experience. Customer
821 + // installations keep the backward-compatible disabled default.
822 + $form_accent_defaults = function_exists( 'wpbc_bfb_settings__get_default_form_accent_options' )
823 + ? wpbc_bfb_settings__get_default_form_accent_options()
824 + : array( 'booking_form_accent_color' => WPBC_DEFAULT_FORM_ACCENT_COLOR );
825 + update_option( 'booking_form_accent_enabled', 'On' );
826 + update_option( 'booking_form_accent_color', $form_accent_defaults['booking_form_accent_color'] );
827 +
828 + if ( class_exists( 'wpdev_bk_multiuser' ) ) {
829 + foreach ( wpbc_bfb_live_demo__get_multiuser_owner_template_map() as $owner_user_id => $template_key ) {
830 + $owner_user_id = absint( $owner_user_id );
831 + $template_key = sanitize_key( (string) $template_key );
832 + if ( $owner_user_id <= 0 || '' === $template_key ) {
833 + $is_success = false;
834 + continue;
835 + }
836 +
837 + if ( function_exists( 'get_userdata' ) && ! get_userdata( $owner_user_id ) ) {
838 + $is_success = false;
839 + continue;
840 + }
841 +
842 + if ( false === wpbc_bfb_live_demo__provision_standard_form( $owner_user_id, $template_key, true ) ) {
843 + $is_success = false;
844 + }
845 + }
846 + }
847 +
848 + return $is_success;
849 +}
850 +
851 +
852 +/**
853 + * Ensure that a regular MultiUser owner has an independent standard BFB form.
854 + *
855 + * Existing owner forms are never overwritten. On normal installations the
856 + * current global standard form is cloned, preserving the Super Admin's chosen
857 + * Builder structure. Live demos use their dedicated bundled fixture instead.
858 + *
859 + * @param int $owner_user_id Regular MultiUser owner ID.
860 + *
861 + * @return int|false Booking form ID on success, false on failure.
862 + */
863 +function wpbc_bfb_ensure_standard_form_for_owner( $owner_user_id ) {
864 +
865 + $owner_user_id = absint( $owner_user_id );
866 + if ( $owner_user_id <= 0 || ! class_exists( 'WPBC_BFB_Form_Storage' ) ) {
867 + return false;
868 + }
869 + if ( function_exists( 'wpbc_is_table_exists' ) && ! wpbc_is_table_exists( 'booking_form_structures' ) ) {
870 + return false;
871 + }
872 +
873 + $existing = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', $owner_user_id, 'published' );
874 + if ( ! empty( $existing->booking_form_id ) ) {
875 + return (int) $existing->booking_form_id;
876 + }
877 +
878 + if ( function_exists( 'wpbc_is_this_demo' ) && wpbc_is_this_demo() ) {
879 + return wpbc_bfb_live_demo__provision_standard_form( $owner_user_id, '', false );
880 + }
881 +
882 + $global_standard = WPBC_BFB_Form_Storage::get_current_form_by_key( 'standard', 0, 'published' );
883 + $form_record = ! empty( $global_standard ) ? get_object_vars( $global_standard ) : array();
884 +
885 + if ( empty( $form_record['structure_json'] ) && function_exists( 'wpbc_get_bfb_template_record_by_key' ) ) {
886 + $form_record = wpbc_get_bfb_template_record_by_key( 'dates_2_columns_sidebar_hints' );
887 + }
888 + if (
889 + empty( $form_record ) ||
890 + ! is_array( $form_record ) ||
891 + empty( $form_record['structure_json'] ) ||
892 + empty( $form_record['engine'] ) ||
893 + 'bfb' !== (string) $form_record['engine']
894 + ) {
895 + return false;
896 + }
897 +
898 + unset(
899 + $form_record['booking_form_id'],
900 + $form_record['created_at'],
901 + $form_record['created_by'],
902 + $form_record['updated_at'],
903 + $form_record['updated_by']
904 + );
905 +
906 + $form_record['form_slug'] = 'standard';
907 + $form_record['status'] = 'published';
908 + $form_record['scope'] = 'user';
909 + $form_record['owner_user_id'] = $owner_user_id;
910 + $form_record['booking_resource_id'] = null;
911 + $form_record['is_default'] = 1;
912 + $form_record['title'] = __( 'Standard', 'booking' );
913 + $form_record['description'] = '';
914 +
915 + $booking_form_id = WPBC_BFB_Form_Storage::save_form( $form_record );
916 +
917 + return ! empty( $booking_form_id ) ? (int) $booking_form_id : false;
918 +}
919 +
920 +/**
893 921 * Import legacy "standard" booking form as initial BFB structure.
894 922 *
895 923 * @return void
896 924 */
897 -function wpbc_bfb__import_old_booking_forms() {
898 -
899 - if ( wpbc_bfb_maybe_create_initial_standard_form_from_template() ) {
900 - return;
901 - }
902 -
903 - if ( function_exists( 'wpbc_bfb_import_legacy_forms' ) ) {
904 - wpbc_bfb_import_legacy_forms(
905 - array(
906 - 'mode' => 'all_global',
907 - 'import_standard' => true,
908 - 'import_custom' => true,
909 - 'skip_if_exists' => true,
910 - 'set_bfb_form_not_defined' => false,
911 - )
912 - );
913 - }
914 -}
925 +function wpbc_bfb__import_old_booking_forms() {
915 926
927 + if ( wpbc_bfb_maybe_create_initial_standard_form_from_template() ) {
928 + return;
929 + }
916 930
931 + if ( function_exists( 'wpbc_bfb_import_legacy_forms' ) ) {
932 + wpbc_bfb_import_legacy_forms(
933 + array(
934 + 'mode' => 'all_global',
935 + 'import_standard' => true,
936 + 'import_custom' => true,
937 + 'skip_if_exists' => true,
938 + 'set_bfb_form_not_defined' => false,
939 + )
940 + );
941 + }
942 +}
943 +
944 +
917 945 /**
918 946 * Remove BFB Preview page from rendered nav menus.
919 947 *
920 948 * @param array $sorted_menu_items Menu item objects.
@@ -1175,50 +1203,50 @@
1175 1203 * $mode = 'all_users'; // Import booking forms for == All Users ==.
1176 1204 *
1177 1205 * @return void
1178 1206 */
1179 -function wpbc_bfb_import_legacy_forms__on_activation() {
1207 +function wpbc_bfb_import_legacy_forms__on_activation() {
1180 1208
1181 1209 if ( ! is_admin() ) {
1182 1210 return;
1183 1211 }
1184 1212
1185 - if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
1186 - return;
1187 - }
1188 -
1189 - delete_transient( 'wpbc_pro_versions__late_activation_60' );
1190 -
1191 - $import_version = '11.3.1';
1192 -
1193 - // Live demos use dedicated BFB fixtures as their canonical source. Importing
1194 - // legacy options here would overwrite the fixtures installed during the
1195 - // activation request, especially because the old demo importer used
1196 - // skip_if_exists=false.
1197 - if ( wpbc_is_this_demo() ) {
1198 - if ( wpbc_bfb_live_demo__provision_all_standard_forms() ) {
1199 - update_option( 'wpbc_bfb_legacy_import_done_for_pro', $import_version );
1200 - } else {
1201 - // Keep a bounded retry available if activation dependencies were not
1202 - // ready yet on this request.
1203 - $retry_count = is_numeric( $is_in_action_late_activation ) ? absint( $is_in_action_late_activation ) : 0;
1204 - if ( $retry_count < 3 ) {
1205 - set_transient( 'wpbc_pro_versions__late_activation_60', $retry_count + 1, HOUR_IN_SECONDS );
1206 - }
1207 - }
1208 - return;
1209 - }
1210 -
1211 - if ( $import_version === get_option( 'wpbc_bfb_legacy_import_done_for_pro', '' ) ) {
1212 - return;
1213 - }
1214 -
1215 - $summary = wpbc_bfb_import_legacy_forms(
1213 + if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
1214 + return;
1215 + }
1216 +
1217 + delete_transient( 'wpbc_pro_versions__late_activation_60' );
1218 +
1219 + $import_version = '11.3.1';
1220 +
1221 + // Live demos use dedicated BFB fixtures as their canonical source. Importing
1222 + // legacy options here would overwrite the fixtures installed during the
1223 + // activation request, especially because the old demo importer used
1224 + // skip_if_exists=false.
1225 + if ( wpbc_is_this_demo() ) {
1226 + if ( wpbc_bfb_live_demo__provision_all_standard_forms() ) {
1227 + update_option( 'wpbc_bfb_legacy_import_done_for_pro', $import_version );
1228 + } else {
1229 + // Keep a bounded retry available if activation dependencies were not
1230 + // ready yet on this request.
1231 + $retry_count = is_numeric( $is_in_action_late_activation ) ? absint( $is_in_action_late_activation ) : 0;
1232 + if ( $retry_count < 3 ) {
1233 + set_transient( 'wpbc_pro_versions__late_activation_60', $retry_count + 1, HOUR_IN_SECONDS );
1234 + }
1235 + }
1236 + return;
1237 + }
1238 +
1239 + if ( $import_version === get_option( 'wpbc_bfb_legacy_import_done_for_pro', '' ) ) {
1240 + return;
1241 + }
1242 +
1243 + $summary = wpbc_bfb_import_legacy_forms(
1216 1244 array(
1217 1245 'mode' => ( class_exists( 'wpdev_bk_multiuser' ) ) ? 'all_users' : 'all_global',
1218 1246 'import_standard' => true,
1219 1247 'import_custom' => true,
1220 - 'skip_if_exists' => true,
1248 + 'skip_if_exists' => true,
1221 1249 'set_bfb_form_not_defined' => true,
1222 1250 )
1223 1251 );
1224 1252 update_option( 'wpbc_bfb_legacy_import_done_for_pro', $import_version );
@@ -1230,17 +1258,17 @@
1230 1258 * Schedule one deferred legacy-form import after Pro activation. The import runs on a later request while this transient exists.
1231 1259 *
1232 1260 * @return void
1233 1261 */
1234 -function wpbc_pro_versions__late_activation(){
1235 -
1236 - // A regular MultiUser owner activation runs the Pro activation callbacks in
1237 - // its own context. It must not schedule a later demo-wide reset.
1238 - if ( false !== apply_bk_filter( 'wpbc_is_user_in_activation_process' ) ) {
1239 - return;
1240 - }
1241 -
1242 - // Get any existing copy of our transient data
1262 +function wpbc_pro_versions__late_activation(){
1263 +
1264 + // A regular MultiUser owner activation runs the Pro activation callbacks in
1265 + // its own context. It must not schedule a later demo-wide reset.
1266 + if ( false !== apply_bk_filter( 'wpbc_is_user_in_activation_process' ) ) {
1267 + return;
1268 + }
1269 +
1270 + // Get any existing copy of our transient data
1243 1271 if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
1244 1272 // It wasn't there, so regenerate the data and save the transient
1245 1273 $is_in_action_late_activation = true;
1246 1274 set_transient( 'wpbc_pro_versions__late_activation_60', $is_in_action_late_activation, HOUR_IN_SECONDS );