PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / uninstall / UninstallModal.php

UninstallModal.php in 404 Solution trunk, at includes/uninstall/UninstallModal.php

194 lines 9.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 if (!defined('ABSPATH')) {
5 exit;
6 }
7
8 /**
9 * Handles the deactivation modal popup display.
10 *
11 * Owns the bootstrap/enqueue path (registers WP hooks, queues modal JS/CSS
12 * on plugins.php, renders the modal markup via the external HTML template).
13 * AJAX persistence is delegated to ABJ_404_Solution_Ajax_UninstallPrefs,
14 * diagnostic snapshot collection to ABJ_404_Solution_UninstallDiagnostics,
15 * and email-fallback dispatch to ABJ_404_Solution_UninstallFeedbackEmail.
16 *
17 * @since 2.36.11
18 */
19 class ABJ_404_Solution_UninstallModal {
20
21 /**
22 * Initialize the deactivation modal functionality.
23 * @return void
24 */
25 public static function init(): void {
26 // Enqueue assets only on plugins.php page
27 add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueueAssets'));
28
29 // Register AJAX handler for saving preferences
30 add_action('wp_ajax_abj404_save_uninstall_prefs', array(__CLASS__, 'handleAjaxSavePreferences'));
31 }
32
33 /**
34 * Enqueue modal assets (JavaScript, CSS) on plugins.php page.
35 *
36 * @param string $hook Current admin page hook
37 * @return void
38 */
39 public static function enqueueAssets(string $hook): void {
40 // Only load on plugins.php page
41 if ($hook !== 'plugins.php') {
42 return;
43 }
44
45 // Only for administrators who can manage plugins
46 if (!current_user_can('activate_plugins')) {
47 return;
48 }
49
50 // Enqueue jQuery UI Dialog (WordPress core)
51 wp_enqueue_script('jquery-ui-dialog');
52 wp_enqueue_style('wp-jquery-ui-dialog');
53
54 // Enqueue custom JavaScript
55 wp_enqueue_script(
56 'abj404-uninstall-modal',
57 plugin_dir_url(ABJ404_FILE) . 'includes/js/uninstall-modal.js',
58 array('jquery', 'jquery-ui-dialog'),
59 '1.0.0',
60 true
61 );
62
63 // Get redirect count for display in modal
64 $redirectCount = ABJ_404_Solution_UninstallDiagnostics::getRedirectCount();
65
66 // Pass data to JavaScript
67 wp_localize_script('abj404-uninstall-modal', 'abj404UninstallModal', array(
68 'nonce' => wp_create_nonce('abj404_uninstall_nonce'),
69 'pluginSlug' => self::getPluginSlug(),
70 'redirectCount' => $redirectCount,
71 'i18n' => array(
72 'dialogTitle' => __('404 Solution - Deactivation Options', '404-solution'),
73 'btnCancel' => __('Cancel', '404-solution'),
74 'btnSkipFeedback' => __('Deactivate without feedback', '404-solution'),
75 'btnDeactivate' => __('Email Feedback & Deactivate', '404-solution'),
76 'btnSaving' => __('Processing...', '404-solution'),
77 'btnDeactivating' => __('Deactivating', '404-solution'),
78 )
79 ));
80
81 // Enqueue modal-specific stylesheet (extracted from inline CSS).
82 wp_enqueue_style(
83 'abj404-uninstall-modal',
84 plugin_dir_url(ABJ404_FILE) . 'includes/css/uninstall-modal.css',
85 array('wp-jquery-ui-dialog'),
86 '1.0.0'
87 );
88
89 // Output modal HTML in footer
90 add_action('admin_footer', array(__CLASS__, 'outputModalHTML'));
91 }
92
93 /**
94 * Output the modal HTML structure by loading the external template
95 * and substituting i18n placeholders.
96 *
97 * @return void
98 */
99 public static function outputModalHTML(): void {
100 $redirectCount = ABJ_404_Solution_UninstallDiagnostics::getRedirectCount();
101
102 $templatePath = dirname(__DIR__) . '/html/uninstallModal.html';
103 if (class_exists('ABJ_404_Solution_Functions')) {
104 $html = ABJ_404_Solution_FileSystemService::readFileContents($templatePath);
105 } else {
106 $html = is_readable($templatePath) ? (string) file_get_contents($templatePath) : '';
107 }
108
109 $replacements = array(
110 '{{LABEL_BEFORE_DEACTIVATING}}' => __('Before deactivating, choose what happens to your data:', '404-solution'),
111 '{{LABEL_KEEP_REDIRECTS}}' => sprintf(_n('Keep my redirect (%d)', 'Keep my redirects (%d)', $redirectCount, '404-solution'), $redirectCount),
112 '{{LABEL_KEEP_REDIRECTS_DESC}}' => __('— saves them for later if you reinstall', '404-solution'),
113 '{{LABEL_KEEP_LOGS}}' => __('Keep 404 logs', '404-solution'),
114 '{{LABEL_KEEP_LOGS_DESC}}' => __('— historical data preserved', '404-solution'),
115 '{{LABEL_CACHE_NOTE}}' => __('Cache tables are always deleted (can be rebuilt)', '404-solution'),
116 '{{LABEL_HELP_IMPROVE}}' => __('Help us improve (Optional)', '404-solution'),
117 '{{REASON_TEMPORARY}}' => __('Temporary deactivation for debugging', '404-solution'),
118 '{{REASON_NOT_WORKING}}' => __('The plugin is not working as expected', '404-solution'),
119 '{{REASON_FOUND_BETTER}}' => __('I found a better plugin', '404-solution'),
120 '{{REASON_NO_LONGER_NEEDED}}' => __('I no longer need this functionality', '404-solution'),
121 '{{REASON_TOO_COMPLICATED}}' => __('Too complicated to configure', '404-solution'),
122 '{{REASON_PERFORMANCE}}' => __('Performance issues', '404-solution'),
123 '{{REASON_OTHER}}' => __('Other reason', '404-solution'),
124 '{{LABEL_NOT_WORKING_HEADER}}' => __('What specifically isn\'t working?', '404-solution'),
125 '{{ISSUE_REDIRECTS_NOT_TRIGGERING}}' => __('Redirects not triggering/working', '404-solution'),
126 '{{ISSUE_SETTINGS_NOT_SAVING}}' => __('Settings not saving', '404-solution'),
127 '{{ISSUE_ADMIN_ERRORS}}' => __('Admin pages showing errors', '404-solution'),
128 '{{ISSUE_SUGGESTIONS_NOT_APPEARING}}' => __('Suggestions not appearing', '404-solution'),
129 '{{ISSUE_PLUGIN_CONFLICTS}}' => __('Conflicts with other plugins', '404-solution'),
130 '{{ISSUE_OTHER_ISSUE}}' => __('Other issue (please specify below)', '404-solution'),
131 '{{LABEL_PERFORMANCE_HEADER}}' => __('What type of performance issue?', '404-solution'),
132 '{{ISSUE_SLOW_ADMIN}}' => __('Slow admin dashboard', '404-solution'),
133 '{{ISSUE_SLOW_FRONTEND}}' => __('Slow frontend page loads', '404-solution'),
134 '{{ISSUE_HIGH_DATABASE}}' => __('High database usage', '404-solution'),
135 '{{ISSUE_MEMORY_ISSUES}}' => __('Memory issues', '404-solution'),
136 '{{ISSUE_OTHER_PERFORMANCE}}' => __('Other (please specify below)', '404-solution'),
137 '{{LABEL_CONFUSING_HEADER}}' => __('What was confusing?', '404-solution'),
138 '{{ISSUE_SETTINGS_CONFUSING}}' => __('Settings are confusing', '404-solution'),
139 '{{ISSUE_TOO_MANY_OPTIONS}}' => __('Too many options', '404-solution'),
140 '{{ISSUE_UNCLEAR_DOCS}}' => __('Unclear documentation', '404-solution'),
141 '{{ISSUE_OTHER_CONFUSION}}' => __('Other (please specify below)', '404-solution'),
142 '{{LABEL_BETTER_PLUGIN_PROMPT}}' => __('Which plugin are you switching to?', '404-solution'),
143 '{{PLACEHOLDER_BETTER_PLUGIN}}' => esc_attr(__('Plugin name (optional)', '404-solution')),
144 '{{LABEL_OTHER_REASON_PROMPT}}' => __('Please tell us more (optional):', '404-solution'),
145 '{{PLACEHOLDER_OTHER_REASON}}' => esc_attr(__('What\'s your reason for deactivating?', '404-solution')),
146 '{{LABEL_ADDITIONAL_DETAILS}}' => __('Additional details (optional):', '404-solution'),
147 '{{PLACEHOLDER_ADDITIONAL_DETAILS}}' => esc_attr(__('Any other information about the issue...', '404-solution')),
148 '{{LABEL_YOUR_EMAIL}}' => __('Your email (optional):', '404-solution'),
149 '{{PLACEHOLDER_FEEDBACK_EMAIL}}' => esc_attr(__('For follow-up if needed', '404-solution')),
150 '{{LABEL_INCLUDE_DIAGNOSTICS}}' => __('Include technical details (site URL, system info, plugin counts, and a sanitized log excerpt) to help diagnose the issue', '404-solution'),
151 /* translators: %s is a literal relative file path to the plugin's privacy policy stub, rendered as <code>. */
152 '{{PRIVACY_NOTE}}' => sprintf(
153 esc_html__('Privacy details (retention, erasure path, processing region): %s', '404-solution'),
154 '<code>docs/privacy.md</code>'
155 ),
156 );
157
158 echo strtr($html, $replacements);
159 }
160
161 /**
162 * Back-compat entry point: delegates to Ajax_UninstallPrefs.
163 * Production hook (wp_ajax_abj404_save_uninstall_prefs) and existing
164 * tests reference this static method directly.
165 *
166 * @return void
167 */
168 public static function handleAjaxSavePreferences(): void {
169 ABJ_404_Solution_Ajax_UninstallPrefs::handle();
170 }
171
172 /**
173 * Back-compat entry point: delegates to UninstallFeedbackEmail::send().
174 * FeedbackEmailFallback::sendNow() calls this for type='uninstall'.
175 *
176 * @param array<string, mixed> $payload FeedbackTransport-built payload.
177 * @return bool True if wp_mail() reported success, false otherwise.
178 */
179 public static function sendFeedbackEmail(array $payload): bool {
180 return ABJ_404_Solution_UninstallFeedbackEmail::send($payload);
181 }
182
183 /**
184 * Get the plugin slug for JavaScript.
185 *
186 * @return string Plugin directory slug
187 */
188 private static function getPluginSlug(): string {
189 $pluginPath = plugin_basename(ABJ404_FILE);
190 $parts = explode('/', $pluginPath);
191 return $parts[0];
192 }
193 }
194