wp_create_nonce('abj404_uninstall_nonce'), 'pluginSlug' => self::getPluginSlug(), 'redirectCount' => $redirectCount, 'i18n' => array( 'dialogTitle' => __('404 Solution - Deactivation Options', '404-solution'), 'btnCancel' => __('Cancel', '404-solution'), 'btnDeactivate' => __('Deactivate Plugin', '404-solution'), 'btnSaving' => __('Saving...', '404-solution'), 'btnDeactivating' => __('Deactivating', '404-solution'), 'btnEmailDeactivate' => __('Email Feedback & Deactivate', '404-solution'), ) )); // Custom CSS for modal styling wp_add_inline_style('wp-jquery-ui-dialog', ' .abj404-uninstall-dialog .ui-dialog-titlebar { background: #d63638; color: white; } .abj404-uninstall-dialog .ui-dialog-titlebar-close { color: white; } .abj404-uninstall-dialog .ui-dialog-titlebar-close:hover { background: #b32d2e; } .abj404-uninstall-dialog .button-danger { background: #d63638; border-color: #d63638; color: white; } .abj404-uninstall-dialog .button-danger:hover { background: #b32d2e; border-color: #b32d2e; } .abj404-uninstall-content label { display: block; margin: 15px 0; cursor: pointer; } .abj404-uninstall-content label input[type="checkbox"], .abj404-uninstall-content label input[type="radio"] { margin-right: 8px; } .abj404-uninstall-content .description { margin: 5px 0 0 25px; color: #646970; font-size: 13px; } .abj404-uninstall-content h3 { margin-top: 20px; margin-bottom: 10px; border-bottom: 1px solid #dcdcde; padding-bottom: 8px; } .abj404-uninstall-content h3:first-child { margin-top: 0; } .abj404-uninstall-reasons { margin-left: 25px; } .abj404-uninstall-reasons label { margin: 8px 0; } #abj404-feedback-fields { margin-top: 10px; padding: 15px; background: #f6f7f7; border-radius: 4px; } #abj404-feedback-fields input, #abj404-feedback-fields textarea { margin-top: 8px; } '); // Output modal HTML in footer add_action('admin_footer', array(__CLASS__, 'outputModalHTML')); } /** * Output the modal HTML structure */ public static function outputModalHTML() { $redirectCount = self::getRedirectCount(); ?> __('Insufficient permissions', '404-solution'))); return; } // Get preferences from AJAX request // Use filter_var to properly handle boolean values sent from JavaScript $preferences = array( 'delete_redirects' => isset($_POST['delete_redirects']) && filter_var($_POST['delete_redirects'], FILTER_VALIDATE_BOOLEAN), 'delete_logs' => isset($_POST['delete_logs']) && filter_var($_POST['delete_logs'], FILTER_VALIDATE_BOOLEAN), 'delete_cache' => true, // Always delete cache tables 'send_feedback' => isset($_POST['send_feedback']) && filter_var($_POST['send_feedback'], FILTER_VALIDATE_BOOLEAN), 'uninstall_reason' => isset($_POST['uninstall_reason']) ? sanitize_text_field($_POST['uninstall_reason']) : '', 'feedback_email' => isset($_POST['feedback_email']) ? sanitize_email($_POST['feedback_email']) : '', 'feedback_details' => isset($_POST['feedback_details']) ? sanitize_textarea_field($_POST['feedback_details']) : '' ); // Debug logging (only in debug mode to avoid logging PII like email/feedback in production) if (defined('WP_DEBUG') && WP_DEBUG) { error_log('404 Solution: AJAX handler received deactivation preferences'); error_log('404 Solution: Raw POST send_feedback = ' . (isset($_POST['send_feedback']) ? $_POST['send_feedback'] : 'NOT SET')); error_log('404 Solution: Parsed send_feedback = ' . ($preferences['send_feedback'] ? 'true' : 'false')); error_log('404 Solution: Parsed preferences: ' . print_r($preferences, true)); } // Save preferences using site options for multisite compatibility // In multisite, use site_option for network-activated plugins, regular option for single-site $option_name = 'abj404_uninstall_preferences'; if (is_multisite() && self::isNetworkActivated()) { // Network-activated: Use site option (accessible across all sites) $saved = update_site_option($option_name, $preferences); } else { // Single-site or site-specific activation: Use regular option $saved = update_option($option_name, $preferences, false); // autoload=false } // Send feedback email if user provided any feedback // Send if: (radio button selected) OR (send feedback checkbox checked AND has details text) $has_reason = !empty($preferences['uninstall_reason']); $has_feedback_text = $preferences['send_feedback'] && !empty($preferences['feedback_details']); $should_send_email = $has_reason || $has_feedback_text; if (defined('WP_DEBUG') && WP_DEBUG) { error_log('404 Solution: has_reason=' . ($has_reason ? 'true' : 'false') . ', has_feedback_text=' . ($has_feedback_text ? 'true' : 'false') . ', should_send_email=' . ($should_send_email ? 'true' : 'false')); } $email_sent = false; if ($saved !== false && $should_send_email) { $email_sent = self::sendFeedbackEmail($preferences); } if ($saved !== false) { $message = __('Preferences saved successfully', '404-solution'); if ($should_send_email) { $message .= $email_sent ? ' ' . __('Feedback sent successfully.', '404-solution') : ' ' . __('Note: Feedback email could not be sent.', '404-solution'); } wp_send_json_success(array('message' => $message)); } else { wp_send_json_error(array('message' => __('Failed to save preferences', '404-solution'))); } } /** * Check if plugin is network-activated * * @return bool True if network-activated, false otherwise */ private static function isNetworkActivated() { if (!is_multisite()) { return false; } if (!function_exists('is_plugin_active_for_network')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } return is_plugin_active_for_network(plugin_basename(ABJ404_FILE)); } /** * Get the plugin slug for JavaScript * * @return string Plugin directory slug */ private static function getPluginSlug() { // Get plugin directory name from plugin file path $pluginPath = plugin_basename(ABJ404_FILE); $parts = explode('/', $pluginPath); return $parts[0]; } /** * Get the count of redirects for display * * @return int Number of redirects */ private static function getRedirectCount() { global $wpdb; $table_name = $wpdb->prefix . 'abj404_redirects'; // Check if table exists $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name; if (!$table_exists) { return 0; } $count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name WHERE status != " . ABJ404_STATUS_TRASH); return $count ? intval($count) : 0; } /** * Send feedback email to plugin author * * @param array $preferences User preferences including feedback * @return bool True if email sent successfully, false otherwise */ private static function sendFeedbackEmail($preferences) { // Get site information global $wp_version; $site_name = get_bloginfo('name'); $admin_email = get_option('admin_email'); // Get plugin information $redirect_count = self::getRedirectCount(); // Gather system information (excluding site URL for privacy) $system_info = array( 'WordPress Version' => $wp_version, 'PHP Version' => phpversion(), 'Plugin Version' => defined('ABJ404_VERSION') ? ABJ404_VERSION : 'Unknown', 'Multisite' => is_multisite() ? 'Yes' : 'No', 'Active Plugins' => self::getActivePluginsList(), 'Redirect Count' => $redirect_count ); // Build email subject $subject = sprintf('[404 Solution] Deactivation Feedback from %s', $site_name); // Build email body $body = "Deactivation feedback received:\n\n"; $body .= "═══════════════════════════════════════\n"; $body .= "USER FEEDBACK\n"; $body .= "═══════════════════════════════════════\n\n"; if (!empty($preferences['uninstall_reason'])) { $body .= "Reason: " . ucfirst(str_replace('_', ' ', $preferences['uninstall_reason'])) . "\n\n"; } if (!empty($preferences['feedback_details'])) { $body .= "Details:\n" . $preferences['feedback_details'] . "\n\n"; } if (!empty($preferences['feedback_email'])) { $body .= "User Email: " . $preferences['feedback_email'] . "\n\n"; } $body .= "═══════════════════════════════════════\n"; $body .= "SYSTEM INFORMATION\n"; $body .= "═══════════════════════════════════════\n\n"; foreach ($system_info as $label => $value) { $body .= sprintf("%-20s: %s\n", $label, $value); } $body .= "\n═══════════════════════════════════════\n"; $body .= "This feedback was sent automatically when the user deactivated the plugin.\n"; // Set email headers $headers = array( 'Content-Type: text/plain; charset=UTF-8', 'From: ' . $site_name . ' <' . $admin_email . '>' ); // Add reply-to if user provided email if (!empty($preferences['feedback_email'])) { $headers[] = 'Reply-To: ' . $preferences['feedback_email']; } // Send email to plugin author $to = defined('ABJ404_AUTHOR_EMAIL') ? ABJ404_AUTHOR_EMAIL : '404solution@ajexperience.com'; // Log email attempt (only in debug mode) if (defined('WP_DEBUG') && WP_DEBUG) { error_log('404 Solution: Attempting to send feedback email to ' . $to); error_log('404 Solution: Email subject: ' . $subject); error_log('404 Solution: Feedback checkbox was checked: send_feedback=' . ($preferences['send_feedback'] ? 'true' : 'false')); } // Hook to log wp_mail failures (only in debug mode) if (defined('WP_DEBUG') && WP_DEBUG) { add_action('wp_mail_failed', function($error) { error_log('404 Solution: wp_mail() FAILED - ' . $error->get_error_message()); }); } $result = wp_mail($to, $subject, $body, $headers); // Log result (only in debug mode) if (defined('WP_DEBUG') && WP_DEBUG) { if ($result) { error_log('404 Solution: wp_mail() returned TRUE - email sent successfully'); } else { error_log('404 Solution: wp_mail() returned FALSE - email send failed'); } } return $result; } /** * Get list of active plugins * * @return string Comma-separated list of active plugin names */ private static function getActivePluginsList() { if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $all_plugins = get_plugins(); $active_plugins = get_option('active_plugins', array()); $active_plugin_names = array(); foreach ($active_plugins as $plugin_path) { if (isset($all_plugins[$plugin_path])) { $active_plugin_names[] = $all_plugins[$plugin_path]['Name']; } } return !empty($active_plugin_names) ? implode(', ', array_slice($active_plugin_names, 0, 10)) . (count($active_plugin_names) > 10 ? '...' : '') : 'None'; } }