| @@ -1,4 +1,4 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | 3 | * @version 1.0 |
| 4 | 4 | * @package Booking Calendar |
| @@ -170,14 +170,14 @@ | ||
| 170 | 170 | //array_unshift( $links, $this->init_option['link_whats_new'] ); |
| 171 | 171 | array_unshift( $links, $this->init_option['link_faq'] ); |
| 172 | 172 | |
| 173 | 173 | |
| 174 | - $links = array_merge( $links, array( | |
| 175 | - '<a class="wpbc_plugins_links__start_tour" title="' . esc_attr( sprintf( __('We\'ll guide you through the steps to set up WP Booking Calendar on your site.','booking'), '<strong>WP Booking Calendar</strong>' ) ) . '" href="' | |
| 176 | - . esc_url( wpbc_get_settings_url() . '&wpbc_setup_wizard=reset&_wpnonce=' . wp_create_nonce( 'wpbc_settings_url_nonce' ) ) | |
| 177 | - //. esc_url( admin_url( add_query_arg( array( 'page' => 'wpbc-about' ), 'index.php' ) ) ) | |
| 178 | - . '">' . esc_attr__( 'Start Setup Wizard', 'booking' ) . '</a>' | |
| 179 | - ) | |
| 174 | + $links = array_merge( $links, array( | |
| 175 | + '<a class="wpbc_plugins_links__start_tour" title="' . esc_attr( sprintf( __('We\'ll guide you through the steps to set up WP Booking Calendar on your site.','booking'), '<strong>WP Booking Calendar</strong>' ) ) . '" href="' | |
| 176 | + . esc_url( wpbc_get_setup_wizard_page_url() ) | |
| 177 | + //. esc_url( admin_url( add_query_arg( array( 'page' => 'wpbc-about' ), 'index.php' ) ) ) | |
| 178 | + . '">' . esc_attr__( 'Start Setup Wizard', 'booking' ) . '</a>' | |
| 179 | + ) | |
| 180 | 180 | ); |
| 181 | 181 | |
| 182 | 182 | |
| 183 | 183 | if ( ! class_exists( 'wpdev_bk_personal' ) ) { |
| @@ -232,63 +232,157 @@ | ||
| 232 | 232 | // $is_make_activation = $this->is_update_from_lower_to_high_version(); |
| 233 | 233 | |
| 234 | 234 | } |
| 235 | 235 | |
| 236 | - // Add hook for initial activation. | |
| 237 | - if ( $is_make_activation ) { | |
| 238 | - // add_action( 'plugins_loaded', array( $this, 'wpbc_activate_initial' ), 1030 ); | |
| 239 | - add_action( 'init', array( $this, 'wpbc_activate_initial' ), 1030 ); | |
| 240 | - } | |
| 236 | + // Run the installed version's activation on the next request after files change. | |
| 237 | + if ( $is_make_activation ) { | |
| 238 | + add_action( 'init', array( $this, 'wpbc_activate_detected_update' ), 1030 ); | |
| 239 | + } | |
| 241 | 240 | } |
| 242 | 241 | } |
| 243 | 242 | |
| 244 | 243 | |
| 245 | 244 | /** |
| 246 | - * Upgrade during bulk upgrade of plugins | |
| 247 | - * | |
| 248 | - * @param type $return_val | |
| 249 | - * @param type $hook_extra | |
| 250 | - * | |
| 251 | - * @return type | |
| 252 | - */ | |
| 253 | - public function wpbc_install_in_bulk_upgrade( $return_val, $hook_extra ) { | |
| 245 | + * Run activation work after WordPress successfully replaces this plugin. | |
| 246 | + * | |
| 247 | + * WordPress continues running the previously loaded PHP code during the | |
| 248 | + * updater request. The completed-update context bridges that request to the | |
| 249 | + * newly installed code so the next request can distinguish an interactive | |
| 250 | + * Plugins-screen update from a non-interactive updater. | |
| 251 | + * | |
| 252 | + * @param bool|WP_Error $return_val Installation result. | |
| 253 | + * @param array $hook_extra WordPress upgrader context. | |
| 254 | + * | |
| 255 | + * @return bool|WP_Error Unchanged installation result. | |
| 256 | + */ | |
| 257 | + public function wpbc_install_in_bulk_upgrade( $return_val, $hook_extra ) { | |
| 254 | 258 | |
| 255 | 259 | if ( is_wp_error( $return_val ) ) { |
| 256 | 260 | return $return_val; |
| 257 | 261 | } |
| 258 | 262 | |
| 259 | - if ( isset( $hook_extra ) ) { | |
| 260 | - if ( isset( $hook_extra['plugin'] ) ) { | |
| 261 | - $file_name = basename( WPBC_FILE ); | |
| 262 | - $pos = strpos( $hook_extra['plugin'], trim( $file_name ) ); | |
| 263 | - if ( false !== $pos ) { | |
| 264 | - $this->wpbc_activate(); | |
| 265 | - } | |
| 266 | - } | |
| 267 | - } | |
| 263 | + $updated_plugin = isset( $hook_extra['plugin'] ) && is_scalar( $hook_extra['plugin'] ) | |
| 264 | + ? plugin_basename( sanitize_text_field( (string) $hook_extra['plugin'] ) ) | |
| 265 | + : ''; | |
| 266 | + if ( plugin_basename( WPBC_FILE ) === $updated_plugin ) { | |
| 267 | + $this->wpbc_activate(); | |
| 268 | + | |
| 269 | + if ( class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ) { | |
| 270 | + WPBC_Setup_Wizard_First_Install_State::record_completed_plugin_update( WPBC_FILE, WP_BK_VERSION_NUM ); | |
| 271 | + } | |
| 272 | + } | |
| 268 | 273 | |
| 269 | 274 | return $return_val; |
| 270 | 275 | } |
| 271 | 276 | |
| 272 | 277 | |
| 273 | - /** | |
| 274 | - * User clicked on "Activate" link at Plugins Menu. | |
| 275 | - * | |
| 276 | - * @return type | |
| 277 | - */ | |
| 278 | - public function wpbc_activate_initial() { | |
| 279 | - | |
| 280 | - // Activate the plugin. | |
| 281 | - $this->wpbc_activate(); | |
| 282 | - | |
| 283 | - // Bail if this demo or activating from network, or bulk. | |
| 284 | - if ( is_network_admin() || isset( $_GET['activate-multi'] ) || wpbc_is_this_demo() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing | |
| 285 | - return; | |
| 286 | - } | |
| 287 | - | |
| 288 | - // Add the transient to redirect - Showing Welcome screen. | |
| 289 | - set_transient( $this->init_option['transient-wpbc_activation_redirect'], true, 30 ); | |
| 290 | - } | |
| 278 | + /** | |
| 279 | + * User clicked on "Activate" link at Plugins Menu. | |
| 280 | + * | |
| 281 | + * Genuine-install state is captured before activation creates canonical | |
| 282 | + * tables and options. A dedicated versioned intent lets the following request | |
| 283 | + * distinguish first-install onboarding from update/reactivation What's New, | |
| 284 | + * while the released boolean redirect transient remains backward compatible. | |
| 285 | + * | |
| 286 | + * @return void | |
| 287 | + */ | |
| 288 | + public function wpbc_activate_initial() { | |
| 289 | + $is_initial_install = function_exists( 'wpbc_is_plugin_initial_install' ) | |
| 290 | + ? wpbc_is_plugin_initial_install() | |
| 291 | + : false; | |
| 292 | + | |
| 293 | + // Activate the plugin. | |
| 294 | + $this->wpbc_activate(); | |
| 295 | + | |
| 296 | + $this->wpbc_schedule_activation_redirect( $is_initial_install, 'activation' ); | |
| 297 | + } | |
| 298 | + | |
| 299 | + /** | |
| 300 | + * Run activation after the installed plugin version changes. | |
| 301 | + * | |
| 302 | + * A matching updater handoff suppresses navigation for automatic and other | |
| 303 | + * non-interactive updates, while an interactive update opens What's New. When | |
| 304 | + * no handoff exists, the files were replaced outside the standard upgrader | |
| 305 | + * and retain the released one-time What's New behavior. | |
| 306 | + * | |
| 307 | + * @return void | |
| 308 | + */ | |
| 309 | + public function wpbc_activate_detected_update() { | |
| 310 | + $update_context = class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) | |
| 311 | + ? WPBC_Setup_Wizard_First_Install_State::get_plugin_update_context( WPBC_FILE, WP_BK_VERSION_NUM ) | |
| 312 | + : false; | |
| 313 | + | |
| 314 | + $this->wpbc_activate(); | |
| 315 | + | |
| 316 | + if ( class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ) { | |
| 317 | + WPBC_Setup_Wizard_First_Install_State::clear_plugin_update_context( WPBC_FILE ); | |
| 318 | + } | |
| 319 | + | |
| 320 | + if ( | |
| 321 | + is_array( $update_context ) | |
| 322 | + && WPBC_Setup_Wizard_First_Install_State::UPDATE_SOURCE_SUPPRESSED === $update_context['source'] | |
| 323 | + ) { | |
| 324 | + return; | |
| 325 | + } | |
| 326 | + | |
| 327 | + $is_manual_update = is_array( $update_context ) | |
| 328 | + && WPBC_Setup_Wizard_First_Install_State::UPDATE_SOURCE_MANUAL === $update_context['source']; | |
| 329 | + $redirect_user_id = $is_manual_update && isset( $update_context['user_id'] ) ? absint( $update_context['user_id'] ) : null; | |
| 330 | + | |
| 331 | + $this->wpbc_schedule_activation_redirect( | |
| 332 | + false, | |
| 333 | + $is_manual_update ? 'manual_update' : 'detected_file_update', | |
| 334 | + $redirect_user_id, | |
| 335 | + $is_manual_update ? WPBC_Setup_Wizard_First_Install_State::MANUAL_UPDATE_INTENT_TTL : 30, | |
| 336 | + ! $is_manual_update | |
| 337 | + ); | |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * Schedule one allowed post-activation navigation intent. | |
| 342 | + * | |
| 343 | + * @param bool $is_initial_install Whether activation began from an empty installation. | |
| 344 | + * @param string $source Activation or update source identifier. | |
| 345 | + * @param int|null $user_id User who should receive the redirect, or null for the current user. | |
| 346 | + * @param int $intent_ttl Structured redirect lifetime in seconds. | |
| 347 | + * @param bool $write_legacy Whether to retain the released boolean redirect for older consumers. | |
| 348 | + * | |
| 349 | + * @return void | |
| 350 | + */ | |
| 351 | + private function wpbc_schedule_activation_redirect( $is_initial_install, $source, $user_id = null, $intent_ttl = 30, $write_legacy = true ) { | |
| 352 | + $is_restricted = class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) | |
| 353 | + ? WPBC_Setup_Wizard_First_Install_State::is_automatic_onboarding_restricted() | |
| 354 | + : ( | |
| 355 | + is_network_admin() | |
| 356 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only activation context detection. | |
| 357 | + || isset( $_GET['activate-multi'] ) | |
| 358 | + || wpbc_is_this_demo() | |
| 359 | + || ( defined( 'WPBC_IS_PLAYGROUND' ) && true === WPBC_IS_PLAYGROUND ) | |
| 360 | + || defined( 'IFRAME_REQUEST' ) | |
| 361 | + ); | |
| 362 | + if ( $is_restricted ) { | |
| 363 | + return; | |
| 364 | + } | |
| 365 | + | |
| 366 | + if ( class_exists( 'WPBC_Setup_Wizard_First_Install_State' ) ) { | |
| 367 | + $redirect_intent = WPBC_Setup_Wizard_First_Install_State::create_activation_redirect_intent( | |
| 368 | + $is_initial_install, | |
| 369 | + WP_BK_VERSION_NUM, | |
| 370 | + $source, | |
| 371 | + $user_id | |
| 372 | + ); | |
| 373 | + set_transient( | |
| 374 | + WPBC_Setup_Wizard_First_Install_State::ACTIVATION_INTENT_TRANSIENT, | |
| 375 | + $redirect_intent, | |
| 376 | + absint( $intent_ttl ) | |
| 377 | + ); | |
| 378 | + } | |
| 379 | + | |
| 380 | + if ( $write_legacy ) { | |
| 381 | + // Keep the released boolean payload for older paid editions and Welcome consumers. | |
| 382 | + set_transient( $this->init_option['transient-wpbc_activation_redirect'], true, 30 ); | |
| 383 | + } | |
| 384 | + } | |
| 291 | 385 | |
| 292 | 386 | // ----------------------------------------------------------------------------------------------------------------- |
| 293 | 387 | |
| 294 | 388 | /** |