← All changes
|
includes/admin/onboarding/class-charitable-setup.php
+97
-11
1.8.12.3
→
1.8.13
View file →
| @@ -84,17 +84,8 @@ | ||
| 84 | 84 | ), |
| 85 | 85 | ); |
| 86 | 86 | |
| 87 | 87 | /** |
| 88 | - * The private app_server_url property. | |
| 89 | - * | |
| 90 | - * @since 1.8.4 | |
| 91 | - * | |
| 92 | - * @var string | |
| 93 | - */ | |
| 94 | - private $app_server_url = 'https://app.wpcharitable.com/'; | |
| 95 | - | |
| 96 | - /** | |
| 97 | 88 | * The private $stripe_redirect_url property. |
| 98 | 89 | * |
| 99 | 90 | * @var string |
| 100 | 91 | */ |
| @@ -139,8 +130,13 @@ | ||
| 139 | 130 | // Register the resume-banner dismiss listener unconditionally — it |
| 140 | 131 | // must fire during admin-ajax, which the guards below bail out of. |
| 141 | 132 | add_action( 'charitable_dashboard_notification_dismissed', [ $this, 'maybe_clear_onboarding_state_on_dismiss' ] ); |
| 142 | 133 | |
| 134 | + // Records that the user actually departed for the setup wizard. Like the | |
| 135 | + // hook above, this MUST be registered before the wp_doing_ajax() bail | |
| 136 | + // below, or it would never fire on admin-ajax.php. | |
| 137 | + add_action( 'wp_ajax_charitable_onboarding_started', [ $this, 'ajax_mark_onboarding_started' ] ); | |
| 138 | + | |
| 143 | 139 | // If user is in admin ajax or doing cron, return. |
| 144 | 140 | if ( wp_doing_ajax() || wp_doing_cron() ) { |
| 145 | 141 | return; |
| 146 | 142 | } |
| @@ -280,8 +276,45 @@ | ||
| 280 | 276 | delete_option( 'charitable_started_onboarding' ); |
| 281 | 277 | } |
| 282 | 278 | |
| 283 | 279 | /** |
| 280 | + * Record that the user has actually departed for the setup wizard. | |
| 281 | + * | |
| 282 | + * Fired by a beacon sent when the welcome screen's call-to-action is | |
| 283 | + * clicked. That button links straight out to the centrally hosted wizard, | |
| 284 | + * so there is no server-side moment at which we would otherwise notice the | |
| 285 | + * departure. | |
| 286 | + * | |
| 287 | + * `charitable_started_onboarding` is what `resume_onboarding()` reads to | |
| 288 | + * decide someone is mid-setup and pull them back to the welcome screen. It | |
| 289 | + * used to be set on activation, which meant every new install was treated | |
| 290 | + * as mid-setup whether or not the user ever went to the wizard. Setting it | |
| 291 | + * here instead makes the option mean what its name says. | |
| 292 | + * | |
| 293 | + * Deliberately best-effort: if the beacon does not arrive (JavaScript | |
| 294 | + * disabled, browser without sendBeacon, request dropped mid-navigation) the | |
| 295 | + * user still reaches the wizard normally and simply is not offered the | |
| 296 | + * resume prompt afterwards. Losing a prompt is an acceptable failure; a | |
| 297 | + * broken call-to-action on the first screen of a new install is not. | |
| 298 | + * | |
| 299 | + * @since 1.8.12.4 | |
| 300 | + * | |
| 301 | + * @return void | |
| 302 | + */ | |
| 303 | + public function ajax_mark_onboarding_started() { | |
| 304 | + | |
| 305 | + check_ajax_referer( 'charitable_onboarding_started', 'nonce' ); | |
| 306 | + | |
| 307 | + if ( ! charitable_current_user_can( 'administrator' ) ) { | |
| 308 | + wp_send_json_error( null, 403 ); | |
| 309 | + } | |
| 310 | + | |
| 311 | + update_option( 'charitable_started_onboarding', 1 ); | |
| 312 | + | |
| 313 | + wp_send_json_success(); | |
| 314 | + } | |
| 315 | + | |
| 316 | + /** | |
| 284 | 317 | * Onboarding welcome screen redirect. |
| 285 | 318 | * |
| 286 | 319 | * This function checks if a new install or update has just occurred. If so, |
| 287 | 320 | * then we redirect the user to the appropriate page. |
| @@ -326,9 +359,17 @@ | ||
| 326 | 359 | $upgrade = get_option( 'charitable_version_upgraded_from', [] ); |
| 327 | 360 | |
| 328 | 361 | if ( ! $upgrade || 1 === count( $upgrade ) ) { |
| 329 | 362 | // Initial install. |
| 330 | - update_option( 'charitable_started_onboarding', 1 ); | |
| 363 | + // | |
| 364 | + // NOTE: `charitable_started_onboarding` is deliberately NOT set here. | |
| 365 | + // Being redirected to the welcome screen is not the same as having | |
| 366 | + // started the wizard, and `resume_onboarding()` treats that option as | |
| 367 | + // "this user is mid-setup" and redirects them back here from other | |
| 368 | + // admin pages until it is cleared. Setting it on activation therefore | |
| 369 | + // nagged every new install, including people who never clicked | |
| 370 | + // through. It is now set only when the user actually leaves for the | |
| 371 | + // wizard - see `ajax_mark_onboarding_started()`. | |
| 331 | 372 | wp_safe_redirect( admin_url( 'admin.php?page=charitable&wpchar_lite=lite&setup=welcome&f=1' ) ); |
| 332 | 373 | exit; |
| 333 | 374 | } |
| 334 | 375 | } |
| @@ -369,8 +410,53 @@ | ||
| 369 | 410 | ); |
| 370 | 411 | |
| 371 | 412 | wp_enqueue_style( 'charitable-admin-user-onboarding' ); |
| 372 | 413 | |
| 414 | + if ( $this->is_welcome_page() ) : | |
| 415 | + | |
| 416 | + /* | |
| 417 | + * The welcome screen's call-to-action links straight out to the | |
| 418 | + * centrally hosted wizard, so nothing server-side observes the | |
| 419 | + * departure. Send a beacon on click so | |
| 420 | + * `charitable_started_onboarding` is set only for users who | |
| 421 | + * genuinely leave for the wizard, rather than for everyone who | |
| 422 | + * merely activated the plugin. | |
| 423 | + * | |
| 424 | + * Inline rather than a new asset file: it is a few lines, the | |
| 425 | + * existing onboarding script is only registered on the setup page | |
| 426 | + * and pulls in the confetti library, and a new file would need a | |
| 427 | + * minified twin to match the $min convention here. | |
| 428 | + */ | |
| 429 | + wp_register_script( 'charitable-onboarding-departure', '', array(), $version, true ); | |
| 430 | + wp_enqueue_script( 'charitable-onboarding-departure' ); | |
| 431 | + | |
| 432 | + wp_add_inline_script( | |
| 433 | + 'charitable-onboarding-departure', | |
| 434 | + '(function(){' . | |
| 435 | + 'var d=' . wp_json_encode( | |
| 436 | + array( | |
| 437 | + 'url' => admin_url( 'admin-ajax.php' ), | |
| 438 | + 'nonce' => wp_create_nonce( 'charitable_onboarding_started' ), | |
| 439 | + ) | |
| 440 | + ) . ';' . | |
| 441 | + 'document.addEventListener("DOMContentLoaded",function(){' . | |
| 442 | + 'var a=document.querySelector(".charitable-user-onboarding-wrap a.charitable-button-link");' . | |
| 443 | + 'if(!a){return;}' . | |
| 444 | + 'a.addEventListener("click",function(){' . | |
| 445 | + 'try{' . | |
| 446 | + 'var f=new FormData();' . | |
| 447 | + 'f.append("action","charitable_onboarding_started");' . | |
| 448 | + 'f.append("nonce",d.nonce);' . | |
| 449 | + 'if(navigator.sendBeacon){navigator.sendBeacon(d.url,f);}' . | |
| 450 | + 'else{fetch(d.url,{method:"POST",body:f,credentials:"same-origin",keepalive:true}).catch(function(){});}' . | |
| 451 | + '}catch(e){}' . | |
| 452 | + '});' . // Never preventDefault: navigation to the wizard must proceed regardless. | |
| 453 | + '});' . | |
| 454 | + '})();' | |
| 455 | + ); | |
| 456 | + | |
| 457 | + endif; | |
| 458 | + | |
| 373 | 459 | if ( $this->is_setup_page() ) : |
| 374 | 460 | |
| 375 | 461 | wp_register_script( |
| 376 | 462 | 'charitable-admin-user-onboarding', |
| @@ -1035,9 +1121,9 @@ | ||
| 1035 | 1121 | 'return' => rawurlencode( |
| 1036 | 1122 | base64_encode( get_admin_url( null, 'admin.php') ) // phpcs:ignore |
| 1037 | 1123 | ), |
| 1038 | 1124 | ), |
| 1039 | - $this->app_server_url . 'optin-charitable_tracking' | |
| 1125 | + charitable_onboarding_app_url() . '/optin-charitable_tracking' | |
| 1040 | 1126 | ); |
| 1041 | 1127 | |
| 1042 | 1128 | // Send the POST request. |
| 1043 | 1129 | $response = wp_remote_get( |