PluginProbe
Extendify / 3.2.0
Extendify v3.2.0
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 0.6.0 All 127 releases
extendify / app / Shared / Services / PluginsActivation / SimplyBook.php

SimplyBook.php in Extendify 3.2.0, at app/Shared/Services/PluginsActivation/SimplyBook.php

101 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Extendify\Shared\Services\PluginsActivation;
4
5 defined('ABSPATH') || die('No direct access.');
6
7 class SimplyBook extends PluginActivation
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
13 public static function slug(): string
14 {
15 return 'simplybook';
16 }
17
18 protected static function simplybookNonce(): string
19 {
20 return \wp_create_nonce('simplybook_nonce');
21 }
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
48 public static function createAccount(\WP_REST_Request $request): \WP_REST_Response
49 {
50 if (!static::isActive()) {
51 return static::pluginNotActiveResponse();
52 }
53
54 // Reset onboarding data to have a fresh start
55 delete_option('simplybook_onboarding_completed');
56 static::dispatchOnboarding('retry_onboarding');
57
58 // Matches the callback URL lifetime they mint; nothing arrives later.
59 \set_transient(self::AWAITING_CALLBACK, true, 10 * MINUTE_IN_SECONDS);
60
61 $create = static::dispatchOnboarding('create_account', [
62 'email' => \sanitize_email($request->get_param('email')),
63 'terms-and-conditions' => (bool) $request->get_param('termsAgreed'),
64 'marketing-consent' => (bool) $request->get_param('marketingConsent'),
65 'captcha_token' => \sanitize_text_field($request->get_param('captcha_token')),
66 ]);
67 if ($create->is_error()) {
68 \delete_transient(self::AWAITING_CALLBACK);
69 return $create;
70 }
71
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;
86 }
87
88 \delete_transient(self::AWAITING_CALLBACK);
89 static::dispatchOnboarding('finish_onboarding');
90 }
91
92 protected static function dispatchOnboarding(string $action, array $body = []): \WP_REST_Response
93 {
94 $request = new \WP_REST_Request('POST', '/simplybook/v1/onboarding/' . $action);
95 $request->set_header('Content-Type', 'application/json');
96 $request->set_body(\wp_json_encode(array_merge($body, ['nonce' => static::simplybookNonce()])));
97
98 return \rest_do_request($request);
99 }
100 }
101