PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 3.1.14
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v3.1.14
3.1.14 3.1.13 3.1.12 3.1.11 3.1.10 3.1.9 3.1.8 3.1.7 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 All 123 releases
← All changes | Inc/Core/Admin/PluginUninstall.php +172 -12 1.0.10 → 3.1.14 View file →
@@ -1,12 +1,12 @@
1 1 <?php
2 2 /**
3 3 * @package FireBox
4 - * @version 1.0.10 Free
4 + * @version 3.1.14 Free
5 5 *
6 6 * @author FirePlugins <[email protected]>
7 7 * @link https://www.fireplugins.com
8 - * @copyright Copyright © 2022 FirePlugins All Rights Reserved
8 + * @copyright Copyright © 2026 FirePlugins All Rights Reserved
9 9 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
10 10 */
11 11
12 12 namespace FireBox\Core\Admin;
@@ -15,36 +15,117 @@
15 15 {
16 16 exit; // Exit if accessed directly.
17 17 }
18 18
19 -require_once FBOX_PLUGIN_DIR . '/Inc/Framework/Inc/Admin/Includes/Uninstall.php';
19 +require_once FBOX_PLUGIN_DIR . 'Inc/Framework/Inc/Admin/Includes/Uninstall.php';
20 20
21 21 class PluginUninstall extends \Uninstall
22 22 {
23 23 /**
24 24 * Runs once we uninstall the plugin.
25 - *
25 + *
26 + * The uninstall hook fires once for the whole network, so on multisite this
27 + * walks every site — each holds its own tables, campaigns, options and
28 + * uploads — and applies the network's decision to all of them.
29 + *
26 30 * @return void
27 31 */
28 32 public function start()
29 33 {
34 + if (!is_multisite())
35 + {
36 + $this->uninstallCurrentSite();
37 +
38 + return;
39 + }
40 +
41 + /**
42 + * One decision for the network, taken from its main site.
43 + *
44 + * Only a network administrator can delete a network plugin, and there
45 + * is no screen where they can answer this for each site. Reading it per
46 + * site sounds fairer but does not work: the setting defaults to keeping
47 + * data, so every site that never changed it would hold on to its tables
48 + * and the delete would leave the network littered with them.
49 + */
50 + $keep_data = $this->networkKeepsData();
51 +
52 + wp_raise_memory_limit('admin');
53 +
54 + foreach (get_sites(['fields' => 'ids', 'number' => 0]) as $site_id)
55 + {
56 + /**
57 + * Give each site its own slice of the clock rather than letting the
58 + * whole network share one. Without this a large network walks into
59 + * max_execution_time part way through; with it, only a single
60 + * pathological site can.
61 + *
62 + * The loop is resumable either way — a site that finished no longer
63 + * has firebox_settings, so uninstallCurrentSite() returns straight
64 + * away and a retry carries on where this left off.
65 + */
66 + if (function_exists('set_time_limit'))
67 + {
68 + @set_time_limit(30); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
69 + }
70 +
71 + switch_to_blog($site_id);
72 + $this->uninstallCurrentSite($keep_data);
73 + restore_current_blog();
74 + }
75 +
76 + $this->deleteNetworkOptions();
77 + }
78 +
79 + /**
80 + * Removes FireBox from the current site.
81 + *
82 + * Safe to call while switched: the framework resolves the table prefix from
83 + * the current site, and every option read below is a site option.
84 + *
85 + * @param bool|null $keep_data Whether to keep this site's data. Null
86 + * reads the site's own setting, which is
87 + * what a single site does.
88 + *
89 + * @return void
90 + */
91 + public function uninstallCurrentSite($keep_data = null)
92 + {
93 + // No settings means FireBox was never set up here — nothing of ours to
94 + // remove, and nothing to read a decision from.
30 95 if (!$settings = get_option('firebox_settings'))
31 96 {
32 97 return;
33 98 }
34 99
35 - if (isset($settings['keep_data_on_uninstall']) && $settings['keep_data_on_uninstall'] == '1')
100 + // Disable usage tracking
101 + $tracking = new \FireBox\Core\UsageTracking\SendUsage();
102 + $tracking->stop();
103 +
104 + // Unschedule the log retention cleanup cron
105 + \FireBox\Core\FB\Log::unscheduleCleanup();
106 +
107 + if ($keep_data === null)
36 108 {
109 + $keep_data = isset($settings['keep_data_on_uninstall']) && $settings['keep_data_on_uninstall'] == '1';
110 + }
111 +
112 + if ($keep_data)
113 + {
37 114 return;
38 115 }
39 116
40 - // remove all db tables
41 - $this->pluginUninstall();
117 + require_once FBOX_PLUGIN_DIR . 'Inc/Framework/Inc/Helpers/Directory.php';
118 + require_once FBOX_PLUGIN_DIR . 'Inc/Framework/Inc/Helpers/WPHelper.php';
42 119
43 - // de-register post type
44 - unregister_post_type('firebox');
45 -
46 - // remove all custom post types data
120 + /**
121 + * Campaigns go first, while the tables are still there.
122 + *
123 + * Deleting one fires delete_post, and our handler clears that campaign's
124 + * logs and submissions. Dropping the tables first leaves that handler
125 + * querying tables that no longer exist, which fills debug.log with
126 + * database errors on every uninstall.
127 + */
47 128 $items = get_posts(['post_type' => 'firebox', 'post_status' => 'any', 'numberposts' => -1, 'fields' => 'ids']);
48 129
49 130 if ($items)
50 131 {
@@ -53,9 +134,88 @@
53 134 wp_delete_post($item, true);
54 135 }
55 136 }
56 137
138 + // remove all db tables
139 + $this->pluginUninstall();
140 +
141 + $this->removeCapabilities();
142 +
143 + // de-register post type
144 + unregister_post_type('firebox');
145 +
57 146 // remove all options
58 147 delete_option('firebox_version');
59 148 delete_option('firebox_settings');
149 + delete_option('firebox_import');
150 + delete_option('firebox_license_status');
151 + delete_option('firebox_license_key');
152 +
153 +
154 + delete_option('firebox_session_conditions_in_use');
155 + delete_option('firebox_boxes_cache');
156 + delete_option('firebox_onboarding_completed');
157 + delete_option('firebox_activation_redirect');
158 +
159 + // Remove first campaign timing data
160 + delete_option('firebox_first_campaign_tracking_started_at');
161 + delete_option('firebox_time_to_first_campaign_draft_seconds');
162 + delete_option('firebox_time_to_first_campaign_publish_seconds');
163 +
164 + // Delete /wp-content/uploads/firebox directory
165 + \FPFramework\Helpers\Directory::delete(\FPFramework\Helpers\WPHelper::getPluginUploadsDirectory('firebox'));
60 166 }
61 -}
167 +
168 + /**
169 + * Whether the network is keeping its data.
170 + *
171 + * Read from the main site, which is the network's own copy of the setting.
172 + * Defaults to keeping it when there is nothing to read.
173 + *
174 + * @return bool
175 + */
176 + private function networkKeepsData()
177 + {
178 + switch_to_blog(get_main_site_id());
179 + $settings = get_option('firebox_settings');
180 + restore_current_blog();
181 +
182 + if (!is_array($settings) || !isset($settings['keep_data_on_uninstall']))
183 + {
184 + return true;
185 + }
186 +
187 + return $settings['keep_data_on_uninstall'] == '1';
188 + }
189 +
190 + /**
191 + * Removes the options FireBox keeps at network level.
192 + *
193 + * @return void
194 + */
195 + private function deleteNetworkOptions()
196 + {
197 + delete_site_option('firebox_license_key');
198 + delete_site_option('firebox_license_status');
199 + delete_site_option('firebox_network_install_offset');
200 + delete_site_option('firebox_usage_tracking_site');
201 + }
202 +
203 + private function removeCapabilities()
204 + {
205 + $capabilities = \FireBox\Core\Admin\Capabilities::getCapabilities();
206 +
207 + // Remove capabilities from all roles
208 + foreach ($capabilities as $cap)
209 + {
210 + foreach (wp_roles()->roles as $role_name => $role_info)
211 + {
212 + $role = get_role($role_name);
213 +
214 + if ($role && $role->has_cap($cap))
215 + {
216 + $role->remove_cap($cap);
217 + }
218 + }
219 + }
220 + }
221 +}