PluginProbe
Extendify / 3.2.2
Extendify v3.2.2
3.2.2 3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 All 128 releases
← All changes | app/Shared/Services/PluginsActivation/SimplyBook.php +49 -4 3.1.2 → 3.2.2 View file →
@@ -5,8 +5,12 @@
5 5 defined('ABSPATH') || die('No direct access.');
6 6
7 7 class SimplyBook extends PluginActivation
8 8 {
9 + // Plugin requires PHP 7.0; constant visibility modifiers are PHP 7.1+.
10 + // phpcs:ignore PSR12.Properties.ConstantVisibility.NotFound
11 + const AWAITING_CALLBACK = 'extendify_simplybook_awaiting_callback';
12 +
9 13 public static function slug(): string
10 14 {
11 15 return 'simplybook';
12 16 }
@@ -15,8 +19,33 @@
15 19 {
16 20 return \wp_create_nonce('simplybook_nonce');
17 21 }
18 22
23 + public static function scriptData(): array
24 + {
25 + // Only their React bundle carries the action, so it can't be read alongside the key.
26 + return [
27 + 'recaptchaSiteKey' => static::recaptchaSiteKey(),
28 + 'recaptchaAction' => 'create_company',
29 + ];
30 + }
31 +
32 + public static function isEligible(): bool
33 + {
34 + // simplybook_onboarding_completed is set before the account exists, so it would hide eligible sites.
35 + return empty(\get_option('simplybook_token_admin'));
36 + }
37 +
38 + // SimplyBook assesses the captcha itself, so a token minted with any other site key fails.
39 + protected static function recaptchaSiteKey(): string
40 + {
41 + $config = WP_PLUGIN_DIR . '/' . static::slug() . '/config/env.php';
42 + $env = is_readable($config) ? require $config : [];
43 + $key = $env['simplybook']['recaptcha']['site_key'] ?? '';
44 +
45 + return is_string($key) ? $key : '';
46 + }
47 +
19 48 public static function createAccount(\WP_REST_Request $request): \WP_REST_Response
20 49 {
21 50 if (!static::isActive()) {
22 51 return static::pluginNotActiveResponse();
@@ -25,8 +54,11 @@
25 54 // Reset onboarding data to have a fresh start
26 55 delete_option('simplybook_onboarding_completed');
27 56 static::dispatchOnboarding('retry_onboarding');
28 57
58 + // Matches the callback URL lifetime they mint; nothing arrives later.
59 + \set_transient(self::AWAITING_CALLBACK, true, 10 * MINUTE_IN_SECONDS);
60 +
29 61 $create = static::dispatchOnboarding('create_account', [
30 62 'email' => \sanitize_email($request->get_param('email')),
31 63 'terms-and-conditions' => (bool) $request->get_param('termsAgreed'),
32 64 'marketing-consent' => (bool) $request->get_param('marketingConsent'),
@@ -32,17 +64,30 @@
32 64 'marketing-consent' => (bool) $request->get_param('marketingConsent'),
33 65 'captcha_token' => \sanitize_text_field($request->get_param('captcha_token')),
34 66 ]);
35 67 if ($create->is_error()) {
68 + \delete_transient(self::AWAITING_CALLBACK);
36 69 return $create;
37 70 }
38 71
39 - $finish = static::dispatchOnboarding('finish_onboarding');
40 - if ($finish->is_error()) {
41 - return $finish;
72 + return new \WP_REST_Response(['success' => true], 200);
73 + }
74 +
75 + // Marking onboarding complete unregisters the route their token-saving callback arrives on.
76 + public static function register()
77 + {
78 + \add_action('simplybook_after_company_registered', [self::class, 'finishOnboarding'], 10, 0);
79 + }
80 +
81 + public static function finishOnboarding()
82 + {
83 + // Their own wizard finishes this itself, at the end of its step 2.
84 + if (!\get_transient(self::AWAITING_CALLBACK)) {
85 + return;
42 86 }
43 87
44 - return new \WP_REST_Response(['success' => true], 200);
88 + \delete_transient(self::AWAITING_CALLBACK);
89 + static::dispatchOnboarding('finish_onboarding');
45 90 }
46 91
47 92 protected static function dispatchOnboarding(string $action, array $body = []): \WP_REST_Response
48 93 {