'booking_version_num', 'option-is_delete_if_deactive' => 'booking_is_delete_if_deactive', 'option-activation_process' => 'booking_activation_process', 'transient-wpbc_activation_redirect' => '_booking_activation_redirect', 'message-delete_data' => 'Warning! All plugin data will be deleted when plugin had deactivated.
' . sprintf( 'If you want to save your plugin data, please uncheck the %s"Delete plugin data"%s at the', '', '' ), 'link_settings' => 'Settings', 'link_whats_new' => 'Whats New', ); $init_option = $this->get_init_option_names(); $this->init_option = wp_parse_args( $init_option, $default_init_option_names ); // WordPress > Plugins > "Activate" link. register_activation_hook( WPBC_FILE, array( $this, 'wpbc_activate_initial' ) ); // WordPress > Plugins > "Deactivate" link. register_deactivation_hook( WPBC_FILE, array( $this, 'wpbc_deactivate' ) ); // Upgrade during bulk upgrade of plugins. add_filter( 'upgrader_post_install', array( $this, 'wpbc_install_in_bulk_upgrade' ), 10, 2 ); // Settings link at the plugin page. add_filter( 'plugin_action_links', array( $this, 'plugin_links' ), 10, 2 ); // Warning message in plugin info. add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 4 ); // TODO: 2025-06-06 - required to be commented, if we use the Pro version as separate plugin. $this->check_if_need_to_update(); // Check upgrade, if was no activation process } /** * Must be overloaded in child CLASS * * * Important! for correct loading of trasnaltions later, we must do not use here loacale of plugin. So here will be untranslated strings!!! * * Exmaple: * return array( 'option-version_num' => 'booking_version_num' , 'option-is_delete_if_deactive' => 'booking_is_delete_if_deactive' , 'option-activation_process' => 'booking_activation_process' , 'transient-wpbc_activation_redirect' => '_booking_activation_redirect' , 'message-delete_data' => 'Warning !!! ' . 'All plugin data will be deleted when plugin had deactivated.' . '
' . sprintf( 'If you want to save your plugin data, please uncheck the %s"Delete plugin data"%s at the settings page.', '', '') , 'link_settings' => 'Settings' , 'link_whats_new' => 'Whats New' ); */ abstract function get_init_option_names(); /** * Must be overloaded in child CLASS * Exmaple: * return false */ abstract function is_update_from_lower_to_high_version(); // ----------------------------------------------------------------------------------------------------------------- // /** Update info of plugin at the plugins section */ function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $context ) { $this_plugin = plugin_basename( WPBC_FILE ); if ($plugin_file == $this_plugin ) { $is_delete_if_deactive = get_bk_option( $this->init_option['option-is_delete_if_deactive'] ); // check if ($is_delete_if_deactive == 'On') { ?>
init_option['message-delete_data']; ?>
Free + ' . ucfirst( $version ) . ''; } else { $plugin_meta[0] .= ' | ' . __( 'Version type', 'booking' ) . ': ' . ucfirst( $version ) . ''; } /* [$plugin_meta] => Array ( [0] => Version 2.8.35 [1] => By wpdevelop [2] => Visit plugin site ) [$plugin_file] => booking/WPBC.php [$plugin_data] => Array ( [Name] => Booking Calendar [PluginURI] => https://wpbookingcalendar.com/demo/ [Version] => 2.8.35 [Description] => Online booking and availability checking service for your site. [Author] => wpdevelop [AuthorURI] => https://wpbookingcalendar.com/ [TextDomain] => [DomainPath] => [Network] => [Title] => Booking Calendar [AuthorName] => wpdevelop ) [$context] => all /**/ // Echo plugin description here return $plugin_meta; } else return $plugin_meta; } // Adds Settings link to plugins settings function plugin_links($links, $file) { $this_plugin = plugin_basename( WPBC_FILE ); if ( $file == $this_plugin ) { array_unshift( $links, $this->init_option['link_settings'] ); //array_unshift( $links, $this->init_option['link_whats_new'] ); array_unshift( $links, $this->init_option['link_faq'] ); $links = array_merge( $links, array( '' . esc_attr__( 'Start Setup Wizard', 'booking' ) . '' ) ); if ( ! class_exists( 'wpdev_bk_personal' ) ) { if ( wpbc_is_updated_paid_to_free() ) { array_unshift( $links, '' . esc_attr__( 'Request Pro Version', 'booking' ) . '' ); } else { array_unshift( $links, $this->init_option['link_up'] ); } } else { if ( ! class_exists( 'wpdev_bk_multiuser' ) ) { array_unshift( $links, $this->init_option['link_upgrade'] ); } } } return $links; } //
// ----------------------------------------------------------------------------------------------------------------- /** * Check about ability to upgrade, if was no activation process * * @return void */ private function check_if_need_to_update() { if ( is_admin() ) { $wpbc_version_num = get_option( $this->init_option['option-version_num'] ); if ( false === $wpbc_version_num ) { $wpbc_version_num = '0'; } $is_make_activation = false; if ( version_compare( WP_BK_VERSION_NUM, $wpbc_version_num ) > 0 ) { $is_make_activation = true; } else { // Check if we was update from free to paid or from lower to higher versions, and do not make normal activation. In this case we need to make update. // TODO: 2025-11-23 - Commented, if we use the Pro version as separate plugin. // $is_make_activation = $this->is_update_from_lower_to_high_version(); } // Run the installed version's activation on the next request after files change. if ( $is_make_activation ) { add_action( 'init', array( $this, 'wpbc_activate_detected_update' ), 1030 ); } } } /** * Run activation work after WordPress successfully replaces this plugin. * * WordPress continues running the previously loaded PHP code during the * updater request. The completed-update context bridges that request to the * newly installed code so the next request can distinguish an interactive * Plugins-screen update from a non-interactive updater. * * @param bool|WP_Error $return_val Installation result. * @param array $hook_extra WordPress upgrader context. * * @return bool|WP_Error Unchanged installation result. */ public function wpbc_install_in_bulk_upgrade( $return_val, $hook_extra ) { if ( is_wp_error( $return_val ) ) { return $return_val; } $updated_plugin = isset( $hook_extra['plugin'] ) && is_scalar( $hook_extra['plugin'] ) ? plugin_basename( sanitize_text_field( (string) $hook_extra['plugin'] ) ) : ''; if ( plugin_basename( WPBC_FILE ) === $updated_plugin ) { $this->wpbc_activate(); if ( class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ) { WPBC_Setup_Wizard_First_Install_State::record_completed_plugin_update( WPBC_FILE, WP_BK_VERSION_NUM ); } } return $return_val; } /** * User clicked on "Activate" link at Plugins Menu. * * Genuine-install state is captured before activation creates canonical * tables and options. A dedicated versioned intent lets the following request * distinguish first-install onboarding from update/reactivation What's New, * while the released boolean redirect transient remains backward compatible. * * @return void */ public function wpbc_activate_initial() { $is_initial_install = function_exists( 'wpbc_is_plugin_initial_install' ) ? wpbc_is_plugin_initial_install() : false; // Activate the plugin. $this->wpbc_activate(); $this->wpbc_schedule_activation_redirect( $is_initial_install, 'activation' ); } /** * Run activation after the installed plugin version changes. * * A matching updater handoff suppresses navigation for automatic and other * non-interactive updates, while an interactive update opens What's New. When * no handoff exists, the files were replaced outside the standard upgrader * and retain the released one-time What's New behavior. * * @return void */ public function wpbc_activate_detected_update() { $update_context = class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ? WPBC_Setup_Wizard_First_Install_State::get_plugin_update_context( WPBC_FILE, WP_BK_VERSION_NUM ) : false; $this->wpbc_activate(); if ( class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ) { WPBC_Setup_Wizard_First_Install_State::clear_plugin_update_context( WPBC_FILE ); } if ( is_array( $update_context ) && WPBC_Setup_Wizard_First_Install_State::UPDATE_SOURCE_SUPPRESSED === $update_context['source'] ) { return; } $is_manual_update = is_array( $update_context ) && WPBC_Setup_Wizard_First_Install_State::UPDATE_SOURCE_MANUAL === $update_context['source']; $redirect_user_id = $is_manual_update && isset( $update_context['user_id'] ) ? absint( $update_context['user_id'] ) : null; $this->wpbc_schedule_activation_redirect( false, $is_manual_update ? 'manual_update' : 'detected_file_update', $redirect_user_id, $is_manual_update ? WPBC_Setup_Wizard_First_Install_State::MANUAL_UPDATE_INTENT_TTL : 30, ! $is_manual_update ); } /** * Schedule one allowed post-activation navigation intent. * * @param bool $is_initial_install Whether activation began from an empty installation. * @param string $source Activation or update source identifier. * @param int|null $user_id User who should receive the redirect, or null for the current user. * @param int $intent_ttl Structured redirect lifetime in seconds. * @param bool $write_legacy Whether to retain the released boolean redirect for older consumers. * * @return void */ private function wpbc_schedule_activation_redirect( $is_initial_install, $source, $user_id = null, $intent_ttl = 30, $write_legacy = true ) { $is_restricted = class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ? WPBC_Setup_Wizard_First_Install_State::is_automatic_onboarding_restricted() : ( is_network_admin() // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only activation context detection. || isset( $_GET['activate-multi'] ) || wpbc_is_this_demo() || ( defined( 'WPBC_IS_PLAYGROUND' ) && true === WPBC_IS_PLAYGROUND ) || defined( 'IFRAME_REQUEST' ) ); if ( $is_restricted ) { return; } if ( class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ) { $redirect_intent = WPBC_Setup_Wizard_First_Install_State::create_activation_redirect_intent( $is_initial_install, WP_BK_VERSION_NUM, $source, $user_id ); set_transient( WPBC_Setup_Wizard_First_Install_State::ACTIVATION_INTENT_TRANSIENT, $redirect_intent, absint( $intent_ttl ) ); } if ( $write_legacy ) { // Keep the released boolean payload for older paid editions and Welcome consumers. set_transient( $this->init_option['transient-wpbc_activation_redirect'], true, 30 ); } } // ----------------------------------------------------------------------------------------------------------------- /** * Run Activate */ public function wpbc_activate() { WPBC_Action_Scheduler_Compatibility::raise_memory_limit(); WPBC_Action_Scheduler_Compatibility::raise_time_limit( 300 ); update_bk_option( $this->init_option['option-activation_process'], 'On' ); make_bk_action( 'wpbc_activation' ); // S T A R T. update_bk_option( $this->init_option['option-version_num'], WP_BK_VERSION_NUM ); update_bk_option( $this->init_option['option-activation_process'], 'Off' ); } /** * Run Deactivate */ public function wpbc_deactivate() { wpbc_set_plugin_deactivation_state( true ); WPBC_Action_Scheduler_Compatibility::raise_memory_limit(); WPBC_Action_Scheduler_Compatibility::raise_time_limit( 300 ); $is_delete_if_deactive = get_bk_option( $this->init_option['option-is_delete_if_deactive'] ); // check. if ( 'On' === $is_delete_if_deactive ) { make_bk_action( 'wpbc_deactivation' ); // F I N I S H. delete_bk_option( $this->init_option['option-version_num'] ); delete_bk_option( $this->init_option['option-activation_process'] ); } } }