PluginProbe ʕ •ᴥ•ʔ
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More / 4.0.9
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More v4.0.9
4.2.0 4.1.0 4.0.9 4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 trunk 1.0.0 2.0.0 2.0.1 2.0.2 2.0.3 3.0 3.0.1 3.0.2 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.2.0 3.2.1 3.2.2 3.2.4 3.2.5 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1
superb-blocks / src / admin / controllers / class-plugin-reset-controller.php
superb-blocks / src / admin / controllers Last commit date
wizard 3 weeks ago class-dashboard-controller.php 3 weeks ago class-license-resolve-controller.php 3 weeks ago class-newsletter-signup-controller.php 3 weeks ago class-notice-controller.php 3 weeks ago class-plugin-reset-controller.php 3 weeks ago class-review-controller.php 3 weeks ago class-rewrite-check-controller.php 3 weeks ago class-settings-controller.php 3 weeks ago class-troubleshooting-controller.php 3 weeks ago
class-plugin-reset-controller.php
172 lines
1 <?php
2
3 namespace SuperbAddons\Admin\Controllers;
4
5 defined('ABSPATH') || exit();
6
7 use Exception;
8 use SuperbAddons\Data\Controllers\KeyController;
9 use SuperbAddons\Data\Controllers\LogController;
10 use SuperbAddons\Data\Controllers\Option;
11 use SuperbAddons\Gutenberg\Controllers\GutenbergEnhancementsController;
12 use SuperbAddons\Library\Controllers\FavoritesController;
13 use SuperbAddons\Gutenberg\Form\FormFileHandler;
14 use SuperbAddons\Gutenberg\Form\FormGoogleAuth;
15 use SuperbAddons\Gutenberg\Form\FormRegistry;
16 use SuperbAddons\Gutenberg\Form\FormSettings;
17 use SuperbAddons\Gutenberg\Form\FormSubmissionCPT;
18 use SuperbAddons\Gutenberg\Form\FormSubmissionHandler;
19 use SuperbAddons\Gutenberg\Popup\PopupRegistry;
20 use SuperbAddons\Tours\Controllers\TourController;
21
22 class PluginResetController
23 {
24 /**
25 * Completely wipe every trace of plugin data from this site.
26 *
27 * Order matters: license removal must run before its option row is deleted
28 * so the remote server is notified; the form registry must be read before
29 * its option row is deleted so every dynamic config option gets cleaned up.
30 *
31 * @param bool $include_submissions When true, also deletes every stored form submission CPT post.
32 * @return bool
33 */
34 public static function RemoveAllPluginData($include_submissions = false)
35 {
36 // 1. License first — notify remote server before the option row is deleted locally.
37 // Guarded so we don't make a pointless remote call when no key is registered.
38 if (KeyController::HasRegisteredKey()) {
39 try {
40 KeyController::RemoveKey();
41 } catch (Exception $e) {
42 // RemoveKey already logs internally; swallow so a network failure
43 // does not block the rest of the local cleanup.
44 }
45 }
46
47 // 2. Unschedule cron hooks.
48 $cron_hooks = array(
49 'superbaddons_share_error_logs',
50 'superb_blocks_template_restoration_cleanup',
51 'spb_form_spam_purge',
52 'spb_form_retention_purge',
53 );
54 foreach ($cron_hooks as $hook) {
55 wp_clear_scheduled_hook($hook);
56 }
57
58 // 3. Iterate form registry BEFORE deleting it so we can clean up every
59 // dynamic spb_form_cfg_{form_id} option row.
60 $form_registry = get_option(FormRegistry::OPTION_KEY, array());
61 if (is_array($form_registry)) {
62 foreach ($form_registry as $form_id => $_unused) {
63 delete_option(FormRegistry::CONFIG_PREFIX . sanitize_key($form_id));
64 }
65 }
66
67 // 4. Delete every option row the plugin has ever written.
68 $option_keys = array(
69 // Core plugin options (with constants where available)
70 Option::KEY_DOMAIN,
71 Option::SETTINGS,
72 Option::COMPATIBILITY_SETTINGS,
73 Option::DISABLED_BLOCKS,
74 Option::GLOBAL_ENHANCEMENTS,
75 // Core plugin options without constants
76 'superbaddonslibrary_service_version',
77 'superbaddonslibrary_gutenberg_patterns',
78 'superbaddonslibrary_gutenberg_pages',
79 'superbaddonslibrary_elementor_sections',
80 'superbaddons_errorlogs',
81 'superbaddons_wizard_completed_themes',
82 'superbaddons_wizard_navigation_post_id',
83 'superbaddons_elementor_tour_id',
84 'superbaddons_pre_activation',
85 'superbaddons_engagement',
86 'superbaddons_css_block_target_valid_labels',
87 // Form settings
88 FormSettings::OPTION_HCAPTCHA_SITE_KEY,
89 FormSettings::OPTION_HCAPTCHA_SECRET_KEY,
90 FormSettings::OPTION_RECAPTCHA_SITE_KEY,
91 FormSettings::OPTION_RECAPTCHA_SECRET_KEY,
92 FormSettings::OPTION_TURNSTILE_SITE_KEY,
93 FormSettings::OPTION_TURNSTILE_SECRET_KEY,
94 FormSettings::OPTION_MAILCHIMP_API_KEY,
95 FormSettings::OPTION_BREVO_API_KEY,
96 FormSettings::OPTION_GOOGLE_SHEETS_CLIENT_EMAIL,
97 FormSettings::OPTION_GOOGLE_SHEETS_PRIVATE_KEY,
98 FormSettings::OPTION_WEBHOOK_SECRETS,
99 'superbaddons_form_role_permissions',
100 'superbaddons_form_access_control_enabled',
101 'superbaddons_form_default_email',
102 'superbaddons_form_data_retention',
103 // Registries (delete AFTER iterating above)
104 FormRegistry::OPTION_KEY,
105 PopupRegistry::OPTION_KEY,
106 );
107 foreach ($option_keys as $option_key) {
108 delete_option($option_key);
109 }
110
111 // 5. Delete transients.
112 $transient_keys = array(
113 'superbaddons_activation_redirect',
114 'superbaddons_wizard_recommender_transient',
115 'superbaddons_wizard_woocommerce_transient',
116 'superb_blocks_template_restoration',
117 'superbaddons_template_part_preview',
118 FormGoogleAuth::TRANSIENT_KEY,
119 );
120 foreach ($transient_keys as $transient_key) {
121 delete_transient($transient_key);
122 }
123
124 // 5b. Purge namespaced commerce transients (product/stock/search caches).
125 // Keys look like: _transient_superb_commerce_product_123_1700000000 etc.
126 // Direct query: no WP API exists for bulk-deleting transients by prefix; iterating get_option() to find them would itself bypass caching and is far slower. Pattern is a constant string with literal underscores escaped so they aren't treated as LIKE wildcards. Caching does not apply to a DELETE; this runs once during plugin reset.
127 global $wpdb;
128 if (isset($wpdb) && is_object($wpdb)) {
129 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
130 $wpdb->query(
131 "DELETE FROM {$wpdb->options}
132 WHERE option_name LIKE '_transient_superb_commerce\\_%'
133 OR option_name LIKE '_transient_timeout_superb_commerce\\_%'"
134 );
135 }
136
137 // 6. Delete user meta (site-wide).
138 AdminNoticeController::Cleanup();
139 NewsletterSignupController::Cleanup();
140 delete_metadata('user', 0, TourController::TOUR_DASHBOARD_WELCOME_META, false, true);
141 delete_metadata('user', 0, TourController::TOUR_BLOCK_THEME_META, false, true);
142 delete_metadata('user', 0, GutenbergEnhancementsController::ENHANCEMENTS_OPTION, false, true);
143 delete_metadata('user', 0, FavoritesController::FAVORITES_META_KEY, false, true);
144
145 // 7. Optionally wipe every stored form submission.
146 if ($include_submissions) {
147 $submission_ids = get_posts(array(
148 'post_type' => FormSubmissionCPT::POST_TYPE,
149 'post_status' => 'any',
150 'posts_per_page' => -1,
151 'fields' => 'ids',
152 'no_found_rows' => true,
153 'update_post_meta_cache' => false,
154 'update_post_term_cache' => false,
155 ));
156 if (!empty($submission_ids)) {
157 FormSubmissionHandler::BulkDelete($submission_ids);
158 }
159 // Remove the upload directory trees (scaffolding, empty date
160 // subdirs, and any files orphaned by crashed requests), then
161 // retire the randomized directory token; the next upload mints a
162 // fresh directory. Both are kept when submissions are kept, since
163 // stored file paths live under the current token's directory.
164 // Directory removal must run before the token option is deleted.
165 FormFileHandler::DeleteUploadDirectories();
166 delete_option(FormFileHandler::UPLOAD_DIR_TOKEN_OPTION);
167 }
168
169 return true;
170 }
171 }
172