PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 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 All 205 releases
← All changes | includes/page-form-builder/save-load/bfb-activate.php +365 -44 11.3 → 11.9 View file →
@@ -275,8 +275,13 @@
275 275 * @return false|int
276 276 */
277 277 function wpbc_bfb_activation__create_preview_page_raw() {
278 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 +
279 284 $page_data = array(
280 285 'post_title' => __( 'Booking Form Preview', 'booking' ),
281 286 'post_content' => '', // Content will be injected dynamically at preview time by bfb-preview.php.
282 287 'post_status' => 'publish',
@@ -409,8 +414,14 @@
409 414 *
410 415 * @return void
411 416 */
412 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 +
413 424 wpbc_bfb_activation__ensure_preview_page_exists();
414 425 }
415 426 add_bk_action( 'wpbc_free_version_activation', 'wpbc_bfb_activation__preview_page' );
416 427
@@ -500,17 +511,20 @@
500 511 add_bk_action( 'wpbc_free_version_deactivation', 'wpbc_bfb_deactivation__form_structures_table' );
501 512
502 513
503 514 /**
504 - * Import legacy "standard" booking form as initial BFB structure.
515 + * Check the shared activation decision before provisioning a Standard form.
505 516 *
506 - * @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.
507 523 */
508 524 function wpbc_bfb_is_brand_new_install__before_version_update() {
509 525
510 - $stored_version = get_option( 'booking_version_num', false );
511 -
512 - return ( false === $stored_version );
526 + return function_exists( 'wpbc_is_plugin_initial_install' ) && wpbc_is_plugin_initial_install();
513 527 }
514 528
515 529 /**
516 530 * Let the initial standard BFB form follow the global calendar days-selection setting.
@@ -550,8 +564,22 @@
550 564 return $template_record;
551 565 }
552 566
553 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 +/**
554 582 * Maybe create the initial standard BFB form from a bundled template.
555 583 *
556 584 * Used only during brand new plugin activation, before booking_version_num
557 585 * gets updated. Upgrades keep migrating the existing legacy configuration.
@@ -568,11 +596,16 @@
568 596 return false;
569 597 }
570 598
571 599 if ( function_exists( 'wpbc_get_bfb_template_record_by_key' ) ) {
572 - // Default Booking Form Template - Just after Booking Calendar activation!
573 - // $template_record = wpbc_get_bfb_template_record_by_key( 'time_appointments_3_steps_review_with_hints' ); // Time appointments.
574 - $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 + }
575 608 } else {
576 609 $template_record = array();
577 610 }
578 611
@@ -599,55 +632,318 @@
599 632
600 633 return ! empty( $booking_form_id );
601 634 }
602 635
636 +
603 637 /**
604 - * Import legacy "standard" booking form as initial BFB structure.
638 + * Get the dedicated bundled template for the current live-demo edition.
605 639 *
606 - * @return void
640 + * @param int $owner_user_id Optional MultiUser owner ID.
641 + *
642 + * @return string Template key, or an empty string outside a supported demo.
607 643 */
608 -function wpbc_bfb__import_old_booking_forms() {
644 +function wpbc_bfb_live_demo__get_template_key( $owner_user_id = 0 ) {
609 645
610 - if ( wpbc_bfb_maybe_create_initial_standard_form_from_template() ) {
611 - return;
646 + if ( ! function_exists( 'wpbc_is_this_demo' ) || ! wpbc_is_this_demo() ) {
647 + return '';
612 648 }
613 649
614 - // Get actual booking form structure.
615 - $builder_structure_arr = wpbc_simple_form__export_to_bfb_structure();
650 + $owner_user_id = absint( $owner_user_id );
616 651
617 - $resource_id = wpbc_get_default_resource(); // FixIn: 2026-03-07.
618 - $formdata = '';
619 - $custom_form_name = 'standard';
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 + }
620 667
621 - $advanced_form = wpbc_get__booking_form_fields__configuration( $resource_id, $custom_form_name );
622 - $content_form = wpbc_get__booking_form_data_configuration( $resource_id, $formdata );
668 + return '';
669 +}
623 670
624 - $form_config = array(
625 - 'form_name' => 'standard',
626 - 'engine' => 'bfb',
627 - 'engine_version' => '1.0',
628 - 'structure_json' => wpbc_form_config__encode_json( $builder_structure_arr ),
629 - 'settings' => array(),
630 - 'advanced_form' => $advanced_form,
631 - 'content_form' => $content_form,
632 - 'owner_user_id' => 0,
633 - 'title' => 'Standard',
634 - 'description' => '',
635 - 'scope' => 'global',
636 - 'status' => 'published',
637 - 'is_default' => 1,
638 - 'booking_resource_id' => null,
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',
639 779 );
640 780
641 - // We do not need to update legacy options (booking_form, etc...) in BFB.
642 - $sync_legacy = false;
643 - // == One Saving point ==
644 - $booking_form_id = wpbc_form_config_save( $form_config, array( 'sync_legacy' => (bool) $sync_legacy ) );
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 );
645 788
789 + return is_array( $owner_templates ) ? $owner_templates : array();
646 790 }
647 791
648 792
649 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 +/**
921 + * Import legacy "standard" booking form as initial BFB structure.
922 + *
923 + * @return void
924 + */
925 +function wpbc_bfb__import_old_booking_forms() {
926 +
927 + if ( wpbc_bfb_maybe_create_initial_standard_form_from_template() ) {
928 + return;
929 + }
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 +
945 +/**
650 946 * Remove BFB Preview page from rendered nav menus.
651 947 *
652 948 * @param array $sorted_menu_items Menu item objects.
653 949 * @param stdClass $args Menu args.
@@ -913,18 +1209,37 @@
913 1209 if ( ! is_admin() ) {
914 1210 return;
915 1211 }
916 1212
917 - $import_version = '11.0.0';
918 - if ( $import_version === get_option( 'wpbc_bfb_legacy_import_done_for_pro', '' ) ) {
1213 + if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
919 1214 return;
920 1215 }
921 1216
922 - if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
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 + }
923 1236 return;
924 1237 }
925 1238
926 - delete_transient( 'wpbc_pro_versions__late_activation_60' );
1239 + if ( $import_version === get_option( 'wpbc_bfb_legacy_import_done_for_pro', '' ) ) {
1240 + return;
1241 + }
927 1242
928 1243 $summary = wpbc_bfb_import_legacy_forms(
929 1244 array(
930 1245 'mode' => ( class_exists( 'wpdev_bk_multiuser' ) ) ? 'all_users' : 'all_global',
@@ -929,9 +1244,9 @@
929 1244 array(
930 1245 'mode' => ( class_exists( 'wpdev_bk_multiuser' ) ) ? 'all_users' : 'all_global',
931 1246 'import_standard' => true,
932 1247 'import_custom' => true,
933 - 'skip_if_exists' => ( wpbc_is_this_demo() ) ? false : true,
1248 + 'skip_if_exists' => true,
934 1249 'set_bfb_form_not_defined' => true,
935 1250 )
936 1251 );
937 1252 update_option( 'wpbc_bfb_legacy_import_done_for_pro', $import_version );
@@ -944,8 +1259,14 @@
944 1259 *
945 1260 * @return void
946 1261 */
947 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 + }
948 1269
949 1270 // Get any existing copy of our transient data
950 1271 if ( false === ( $is_in_action_late_activation = get_transient( 'wpbc_pro_versions__late_activation_60' ) ) ) {
951 1272 // It wasn't there, so regenerate the data and save the transient