PluginProbe
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder / 3.6.0
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder v3.6.0
3.6.0 3.5.0 trunk 1.0.10 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.6.1 1.0.7 1.0.8 1.0.9 1.1 1.1.1 1.2 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5 1.5.1 All 110 releases
buttonizer-multifunctional-button / app / Migration / ConnectionAdopter.php

ConnectionAdopter.php in Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder 3.6.0, at app/Migration/ConnectionAdopter.php

146 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * SOFTWARE LICENSE INFORMATION
4 *
5 * Copyright (c) 2017 Buttonizer, all rights reserved.
6 *
7 * This file is part of Buttonizer
8 *
9 * For detailed information regarding to the licensing of
10 * this software, please review the license.txt or visit:
11 * https://buttonizer.pro/license/
12 */
13
14 namespace Buttonizer\Migration;
15
16 use Buttonizer\Core\Utils\ApiRequest;
17 use Buttonizer\Core\Utils\Settings;
18
19 # No script kiddies
20 defined('ABSPATH') or die('No script kiddies please!');
21
22 /**
23 * Moves a source plugin's cloud connection into Buttonizer.
24 *
25 * This is what makes the handover invisible: the user was already signed in
26 * through the source plugin, and Buttonizer picks up the same token, the same
27 * site and the same account instead of asking them to connect again.
28 *
29 * Core's SiblingPlugins::copyConnectionFromSibling() does roughly the same,
30 * but it targets whichever sibling happens to answer first and copies only
31 * five settings — everything else the user configured (GDPR consent, dashboard
32 * permissions, admin bar) is silently dropped. This adopts one specific source
33 * and carries those settings over too.
34 */
35 class ConnectionAdopter
36 {
37 /** Connection was copied from the source plugin. */
38 const RESULT_ADOPTED = 'connection_adopted';
39
40 /** Buttonizer was already connected; the target's connection wins. */
41 const RESULT_TARGET_ALREADY_CONNECTED = 'target_already_connected';
42
43 /** Nothing usable to adopt. */
44 const RESULT_SOURCE_NOT_CONNECTED = 'source_not_connected';
45
46 /** The source was never connected, so there was nothing to move. */
47 const RESULT_NOTHING_TO_ADOPT = 'nothing_to_adopt';
48
49 /** The copy did not produce a usable connection. */
50 const RESULT_FAILED = 'adoption_failed';
51
52 /**
53 * Adopt the source plugin's connection.
54 *
55 * @param SourcePlugin $source Source plugin descriptor.
56 *
57 * @return array{adopted: bool, result: string}
58 */
59 public static function adopt(SourcePlugin $source): array
60 {
61 $token = Detector::readToken($source);
62 $sourceSettings = get_option($source->settingsOption(), []);
63
64 // A site id is as required as the token: without it nothing renders on
65 // the frontend, and writing finished_setup anyway would leave
66 // Buttonizer believing it is set up when it is not.
67 if (
68 empty($token) ||
69 !is_array($sourceSettings) ||
70 empty($sourceSettings['finished_setup']) ||
71 empty($sourceSettings['site_id'])
72 ) {
73 return self::result(false, self::RESULT_SOURCE_NOT_CONNECTED);
74 }
75
76 // Buttonizer already has its own connection. Two sites on one install is
77 // rare (a site is a domain), and the agreed rule is that the target
78 // keeps its account — so leave it alone and continue the handover.
79 if (self::isTargetConnected()) {
80 return self::result(true, self::RESULT_TARGET_ALREADY_CONNECTED);
81 }
82
83 ApiRequest::saveApiToken($token);
84
85 Settings::setSetting('finished_setup', true);
86 Settings::setSetting('installed_at', $sourceSettings['installed_at'] ?? new \DateTime('now'));
87 Settings::setSetting('last_synced_at', new \DateTime('now'));
88 Settings::setSetting('site_id', $sourceSettings['site_id']);
89
90 // Carry over what the user configured in the source plugin. Skipping
91 // this is how wait_until_consent gets lost, which silently turns a
92 // GDPR-compliant install into a non-compliant one.
93 foreach ($source->settingsToCarryOver() as $key) {
94 if (array_key_exists($key, $sourceSettings)) {
95 Settings::setSetting($key, $sourceSettings[$key]);
96 }
97 }
98
99 Settings::saveUpdatedSettings();
100
101 // Account data, so the dashboard opens signed in instead of empty
102 $account = get_option($source->accountOption(), []);
103
104 if (!empty($account)) {
105 update_option(BUTTONIZER_NAME . '_account', $account);
106 }
107
108 if (!self::isTargetConnected()) {
109 return self::result(false, self::RESULT_FAILED);
110 }
111
112 return self::result(true, self::RESULT_ADOPTED);
113 }
114
115 /**
116 * Is Buttonizer itself connected and usable?
117 *
118 * Deliberately strict: this is the gate that decides whether the source
119 * plugin may be deactivated, so a missing token or site id must read as
120 * "not connected".
121 */
122 public static function isTargetConnected(): bool
123 {
124 if (Settings::getSetting('finished_setup', false) === false) {
125 return false;
126 }
127
128 if (empty(Settings::getSetting('site_id', null))) {
129 return false;
130 }
131
132 return ApiRequest::getApiToken() !== false;
133 }
134
135 /**
136 * @return array{adopted: bool, result: string}
137 */
138 private static function result(bool $adopted, string $result): array
139 {
140 return [
141 'adopted' => $adopted,
142 'result' => $result,
143 ];
144 }
145 }
146