PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.7.7
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.7.7
1.7.7 1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
image-optimization / modules / deactivation / module.php

module.php in Image Optimizer – Compress Images and Convert to WebP or AVIF 1.7.7, at modules/deactivation/module.php

274 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImageOptimization\Modules\Deactivation;
4
5 use ImageOptimization\Classes\Logger;
6 use ImageOptimization\Classes\Module_Base;
7 use ImageOptimization\Classes\Utils;
8 use ImageOptimization\Classes\Client\Client;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 /**
15 * Class Module
16 */
17 class Module extends Module_Base {
18
19 const SERVICE_ENDPOINT = 'feedback/deactivation';
20
21 /**
22 * Get module name.
23 * Retrieve the module name.
24 *
25 * @access public
26 * @return string Module name.
27 */
28 public function get_name(): string {
29 return 'deactivation';
30 }
31
32 /**
33 * Check if we should show the deactivation feedback modal
34 *
35 * @return bool
36 */
37 private function should_show_feedback(): bool {
38 global $pagenow;
39
40 return 'plugins.php' === $pagenow && Utils::user_is_admin();
41 }
42
43 /**
44 * Enqueue deactivation feedback assets
45 */
46 public function enqueue_deactivation_assets(): void {
47 if ( ! $this->should_show_feedback() ) {
48 return;
49 }
50
51 // Enqueue thickbox for modal
52 add_thickbox();
53
54 wp_enqueue_script(
55 'deactivation-io',
56 $this->get_js_assets_url( 'deactivation' ),
57 [],
58 IMAGE_OPTIMIZATION_VERSION,
59 true
60 );
61
62 wp_enqueue_style(
63 'deactivation-io',
64 $this->get_css_assets_url( 'style-deactivation' ),
65 [],
66 IMAGE_OPTIMIZATION_VERSION,
67 );
68
69 wp_localize_script(
70 'deactivation-io',
71 'imageOptimizationDeactivationFeedback',
72 [
73 'nonce' => wp_create_nonce( 'image_optimization_deactivation_feedback' ),
74 'ajaxurl' => admin_url( 'admin-ajax.php' ),
75 ]
76 );
77 }
78
79 /**
80 * Add deactivation feedback modal HTML to footer
81 */
82 public function add_deactivation_modal(): void {
83 if ( ! $this->should_show_feedback() ) {
84 return;
85 }
86 ?>
87 <div id="image-optimization-deactivation-modal" class="image-optimization-deactivation-modal">
88 <div class="image-optimization-deactivation-content">
89 <h4>
90 <?php esc_html_e( 'If you have a moment, please share why you are deactivating Image Optimization:', 'image-optimization' ); ?>
91 </h4>
92
93 <div class="image-optimization-feedback-options">
94 <div class="image-optimization-feedback-option">
95 <label for="io_reason_no_longer_needed">
96 <input type="radio" name="image_optimization_deactivation_reason" value="no_longer_needed" id="io_reason_no_longer_needed">
97 <?php esc_html_e( 'I no longer need this plugin', 'image-optimization' ); ?>
98 </label>
99 </div>
100
101 <div class="image-optimization-feedback-option">
102 <label for="io_reason_too_expensive">
103 <input type="radio" name="image_optimization_deactivation_reason" value="too_expensive" id="io_reason_too_expensive">
104 <?php esc_html_e( 'It\'s too expensive', 'image-optimization' ); ?>
105 </label>
106 </div>
107
108 <div class="image-optimization-feedback-option">
109 <label for="io_reason_no_results">
110 <input type="radio" name="image_optimization_deactivation_reason" value="no_results" id="io_reason_no_results">
111 <?php esc_html_e( 'The plugin didn\'t provide the results I was hoping for', 'image-optimization' ); ?>
112 </label>
113 </div>
114
115 <div class="image-optimization-feedback-option">
116 <label for="io_reason_unclear">
117 <input type="radio" name="image_optimization_deactivation_reason" value="unclear_how_to_use" id="io_reason_unclear">
118 <?php esc_html_e( 'I wasn\'t sure how to use the plugin', 'image-optimization' ); ?>
119 </label>
120 <div class="image-optimization-feedback-text-field" id="io_text_field_unclear">
121 <label for="io_unclear_details"><?php esc_html_e( 'Optional: Was anything unclear or confusing?', 'image-optimization' ); ?></label>
122 <textarea id="io_unclear_details" name="io_unclear_details" rows="3" placeholder="<?php esc_attr_e( 'Please share details...', 'image-optimization' ); ?>"></textarea>
123 </div>
124 </div>
125
126 <div class="image-optimization-feedback-option">
127 <label for="io_reason_technical">
128 <input type="radio" name="image_optimization_deactivation_reason" value="technical_issues" id="io_reason_technical">
129 <?php esc_html_e( 'I had technical issues or conflicts with my site', 'image-optimization' ); ?>
130 </label>
131 </div>
132
133 <div class="image-optimization-feedback-option">
134 <label for="io_reason_switched">
135 <input type="radio" name="image_optimization_deactivation_reason" value="switched_solution" id="io_reason_switched">
136 <?php esc_html_e( 'I switched to a different solution', 'image-optimization' ); ?>
137 </label>
138 <div class="image-optimization-feedback-text-field" id="io_text_field_switched">
139 <label for="io_switched_details"><?php esc_html_e( 'Optional: Please share which solution:', 'image-optimization' ); ?></label>
140 <input type="text" id="io_switched_details" name="io_switched_details" placeholder="<?php esc_attr_e( 'Solution name...', 'image-optimization' ); ?>">
141 </div>
142 </div>
143
144 <div class="image-optimization-feedback-option">
145 <label for="io_reason_other">
146 <input type="radio" name="image_optimization_deactivation_reason" value="other" id="io_reason_other">
147 <?php esc_html_e( 'Other', 'image-optimization' ); ?>
148 </label>
149 <div class="image-optimization-feedback-text-field" id="io_text_field_other">
150 <label for="io_other_details"><?php esc_html_e( 'Optional: Please share the reason:', 'image-optimization' ); ?></label>
151 <textarea id="io_other_details" name="io_other_details" rows="3" placeholder="<?php esc_attr_e( 'Please explain...', 'image-optimization' ); ?>"></textarea>
152 </div>
153 </div>
154 </div>
155
156 <div class="image-optimization-deactivation-buttons">
157 <button type="button" id="image-optimization-skip-deactivate" class="image-optimization-btn">
158 <?php esc_html_e( 'Skip & Deactivate', 'image-optimization' ); ?>
159 </button>
160 <button type="button" id="image-optimization-submit-deactivate" class="image-optimization-btn image-optimization-btn-primary">
161 <?php esc_html_e( 'Submit & Deactivate', 'image-optimization' ); ?>
162 </button>
163 </div>
164 </div>
165 </div>
166 <?php
167 }
168
169 /**
170 * Handle AJAX feedback submission
171 */
172 public function handle_deactivation_feedback(): void {
173 // Verify nonce
174 $nonce = sanitize_text_field( wp_unslash( $_POST['nonce'] ?? '' ) );
175
176 if ( ! wp_verify_nonce( $nonce, 'image_optimization_deactivation_feedback' ) ) {
177 wp_send_json_error( esc_html__( 'Security check failed', 'image-optimization' ) );
178 return;
179 }
180
181 // Check user capabilities
182 if ( ! Utils::user_is_admin() ) {
183 wp_send_json_error( esc_html__( 'Insufficient permissions', 'image-optimization' ) );
184 return;
185 }
186
187 $reason = sanitize_text_field( wp_unslash( $_POST['reason'] ?? '' ) );
188 $additional_data = '';
189
190 // Safely handle additional_data if it exists
191 if ( isset( $_POST['additional_data'] ) ) {
192 $additional_data = sanitize_textarea_field( wp_unslash( $_POST['additional_data'] ) );
193 }
194
195 if ( empty( $reason ) ) {
196 wp_send_json_success( [ 'message' => 'No reason provided' ] );
197 return;
198 }
199
200 // Send feedback to external service
201 $feedback_sent = $this->send_feedback_to_service( $reason, $additional_data );
202
203 if ( $feedback_sent ) {
204 wp_send_json_success( [ 'message' => 'Feedback sent successfully' ] );
205 } else {
206 // Still return success to not block deactivation, but log the error
207 Logger::log( Logger::LEVEL_ERROR, 'Failed to send deactivation feedback to service' );
208 wp_send_json_success( [ 'message' => 'Feedback logged locally' ] );
209 }
210 }
211
212 /**
213 * Send feedback to external service
214 *
215 * @param string $reason The deactivation reason
216 * @param string $additional_data Additional feedback data from text fields
217 * @return bool Whether the feedback was sent successfully
218 */
219 private function send_feedback_to_service( string $reason, string $additional_data = '' ): bool {
220 $feedback_data = $this->prepare_feedback_data( $reason, $additional_data );
221
222 $response = Client::get_instance()->make_request(
223 'POST',
224 self::SERVICE_ENDPOINT,
225 $feedback_data
226 );
227
228 if ( empty( $response ) || is_wp_error( $response ) ) {
229 $error_message = is_wp_error( $response ) ? $response->get_error_message() : 'Unknown error';
230 Logger::log( Logger::LEVEL_ERROR, 'Failed to post feedback: ' . $error_message );
231 return false;
232 }
233
234 return true;
235 }
236
237 /**
238 * Prepare feedback data for the service
239 *
240 * @param string $reason The deactivation reason
241 * @param string $additional_data Additional feedback data from text fields
242 * @return array Formatted feedback data
243 */
244 private function prepare_feedback_data( string $reason, string $additional_data = '' ): array {
245 $data = [
246 'app' => 'image-optimizer',
247 'app_version' => IMAGE_OPTIMIZATION_VERSION,
248 'selected_answer' => $reason,
249 'site_url' => home_url(),
250 'wp_version' => get_bloginfo( 'version' ),
251 'php_version' => PHP_VERSION,
252 'timestamp' => current_time( 'mysql' ),
253 'user_agent' => sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ),
254 'locale' => get_locale(),
255 ];
256
257 // Add additional data if provided
258 if ( ! empty( $additional_data ) ) {
259 $data['feedback_text'] = $additional_data;
260 }
261
262 return $data;
263 }
264
265 /**
266 * Constructor
267 */
268 public function __construct() {
269 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_deactivation_assets' ] );
270 add_action( 'admin_footer', [ $this, 'add_deactivation_modal' ] );
271 add_action( 'wp_ajax_image_optimization_deactivation_feedback', [ $this, 'handle_deactivation_feedback' ] );
272 }
273 }
274