PluginProbe
Squeeze – Image Optimization & Compression, WEBP Conversion / 1.5
Squeeze – Image Optimization & Compression, WEBP Conversion v1.5
1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 trunk 1.0 1.1 1.2 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5 1.5.1 1.5.2 1.6 All 42 releases
squeeze / src / handlers.php

handlers.php in Squeeze – Image Optimization & Compression, WEBP Conversion 1.5, at src/handlers.php

908 lines 30.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Exit if accessed directly.
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 add_action('wp_ajax_squeeze_update_attachment', 'squeeze_update_attachment');
8 /**
9 * Update attachment with compressed image
10 * https://gist.github.com/cyberwani/ad5452b040001878d692c3165836ebff
11 */
12 function squeeze_update_attachment() {
13 check_ajax_referer( 'squeeze-nonce', '_ajax_nonce' );
14 if (!current_user_can('upload_files')) {
15 wp_send_json_error(''.esc_html__('You do not have permission to upload files', 'squeeze'));
16 }
17 if (isset($_POST["base64"]) && !empty($_POST["base64"])) {
18
19 $base64 = sanitize_text_field($_POST["base64"]);
20 $sizes = $_POST["base64Sizes"]; // DO NOT SANITIZE because it's an array
21 $base64_webp = sanitize_text_field($_POST["base64Webp"]);
22 $sizes_webp = $_POST["base64SizesWebp"];
23 $file_format = sanitize_text_field($_POST["format"]);
24 $filename = sanitize_text_field($_POST["filename"]);
25 $extension = pathinfo($filename, PATHINFO_EXTENSION);
26
27 if (!in_array($extension, explode(',', SQUEEZE_ALLOWED_IMAGE_FORMATS))) {
28 wp_send_json_error(''.esc_html__('Invalid image format', 'squeeze'));
29 }
30
31 $attach_id = (int) $_POST["attachmentID"];
32 $meta_data = wp_get_attachment_metadata($attach_id);
33 $url = sanitize_url($_POST["url"]);
34 $process = sanitize_text_field($_POST["process"]); // process: all, uncompressed, path
35
36 $options = get_option( 'squeeze_options' );
37 $is_backup_original = isset($options['backup_original']) ? $options['backup_original'] : squeeze_get_default_value('backup_original');
38
39 // Upload dir.
40 if ($attach_id > 0) {
41 $upload_dir = str_replace($filename, "", wp_get_original_image_path($attach_id)); // get upload dir from attachment path
42 } else {
43 $upload_url = str_replace($filename, "", $url);
44 $upload_dir = str_replace(home_url(), ABSPATH, $upload_url);
45 }
46 $upload_path = str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . DIRECTORY_SEPARATOR;
47 $upload_webp_path = squeeze_convert_image_path_to_webp_path($upload_path);
48 if (!file_exists($upload_webp_path)) {
49 wp_mkdir_p($upload_webp_path);
50 }
51
52 $img = str_replace('data:image/'.$file_format.';base64,', '', $base64);
53 $img = str_replace(' ', '+', $img);
54 $decoded = base64_decode($img);
55
56 $img_webp = str_replace('data:image/webp;base64,', '', $base64_webp);
57 $img_webp = str_replace(' ', '+', $img_webp);
58 $decoded_webp = base64_decode($img_webp);
59
60 if ($is_backup_original && $process !== 'path') {
61 // backup original
62 $backup_filename = preg_replace("/(\.(?!.*\.))/", '.bak.', $filename); // add .bak. before extension
63
64 if ( !file_exists($upload_path . $backup_filename) ) {
65 $upload_backup_file = copy($upload_path . $filename, $upload_path . $backup_filename);
66
67 if (!$upload_backup_file) {
68 wp_send_json_error(''.esc_html__('Backup original image failed', 'squeeze') . ': '. $upload_path . $backup_filename);
69 }
70 }
71 }
72
73 // Save the image in the uploads directory.
74
75 global $wp_filesystem;
76 // Initialize the WP filesystem, no more using 'file-put-contents' function
77 if (empty($wp_filesystem)) {
78 require_once (ABSPATH . '/wp-admin/includes/file.php');
79 WP_Filesystem();
80 }
81
82 $sizes['original']['original_size'] = filesize($upload_path . $filename);
83 $upload_file = $wp_filesystem->put_contents($upload_path . $filename, $decoded);
84 $sizes['original']['compressed_size'] = strlen($decoded);
85
86 if (!$upload_file) {
87 wp_send_json_error(''.esc_html__('Upload image failed', 'squeeze'). ': '. $upload_path . '::' . $filename . '::' . $upload_dir . '::' . $upload_url);
88 }
89
90 $filename_webp = $filename.'.webp';
91 $upload_file_webp = $wp_filesystem->put_contents($upload_webp_path . $filename_webp, $decoded_webp);
92
93 if (!$upload_file_webp) {
94 wp_send_json_error(''.esc_html__('Upload WEBP image failed', 'squeeze'). ': '. $upload_webp_path . '::' . $filename_webp . '::' . $upload_dir . '::' . $upload_url);
95 }
96
97 // upload thumbnails
98 if ($process !== 'path') {
99
100 foreach ($sizes as $size_name => $size_data) {
101 if ($size_name === 'original') {
102 continue;
103 }
104 $size_base64 = sanitize_text_field($size_data['base64']);
105 $size_base64 = str_replace('data:image/'.$file_format.';base64,', '', $size_base64);
106 $size_base64 = str_replace(' ', '+', $size_base64);
107 $size_decoded = base64_decode($size_base64);
108 $size_filename = basename(sanitize_url($size_data['url']));
109
110 if ($size_name === 'full') {
111 $size_name = 'scaled';
112 unset($sizes['full']);
113 }
114
115 $sizes[$size_name]['original_size'] = filesize($upload_path . $size_filename);
116
117 $upload_size_file = $wp_filesystem->put_contents($upload_path . $size_filename, $size_decoded);
118
119 if (!$upload_size_file) {
120 wp_send_json_error(''.esc_html__('Attachment not updated', 'squeeze'). ': ' . $upload_path . $size_filename);
121 } else {
122 $sizes[$size_name]['compressed_size'] = strlen($size_decoded);
123 }
124 }
125
126 foreach ($sizes_webp as $size_name => $size_data) {
127 if ($size_name === 'original') {
128 continue;
129 }
130 $size_base64 = sanitize_text_field($size_data['base64']);
131 $size_base64 = str_replace('data:image/webp;base64,', '', $size_base64);
132 $size_base64 = str_replace(' ', '+', $size_base64);
133 $size_decoded = base64_decode($size_base64);
134 $size_filename = basename(sanitize_url($size_data['url']));
135 $size_filename = $size_filename.'.webp';
136
137 $upload_size_file = $wp_filesystem->put_contents($upload_webp_path . $size_filename, $size_decoded);
138
139 if (!$upload_size_file) {
140 wp_send_json_error(''.esc_html__('Attachment WEBP not updated', 'squeeze'). ': ' . $upload_webp_path . $size_filename);
141 }
142 }
143
144 update_post_meta($attach_id, "squeeze_is_compressed", true);
145
146 $response_msg = squeeze_get_comparison_table($sizes); //$filename. ',<br>' . rtrim($response_msg, ',<br> ');
147 $response_msg = '<strong>�
148 '.esc_html__('Squeezed successfully', 'squeeze') . '!</strong> ' . $response_msg;
149
150 $uncompressed_images = squeeze_get_stats_option('uncompressed_images');
151 $uncompressed_images--;
152 update_option('squeeze_stats', array('uncompressed_images' => $uncompressed_images));
153
154 wp_send_json_success($response_msg);
155 } else {
156 wp_send_json_success('�
157 '.esc_html__('Squeezed successfully', 'squeeze'));
158 }
159
160 }
161 wp_die();
162 }
163
164 /**
165 * Get comparison table of original and compressed image
166 */
167 function squeeze_get_comparison_table($sizes) {
168 $table = '<div class="squeeze-comparison-table">';
169 $table .= '<table class="wp-list-table widefat striped">';
170 $table .= '<thead><tr><th>'.esc_html__('Size Name', 'squeeze').'</th><th>'.esc_html__('Original Size', 'squeeze').'</th><th>'.esc_html__('Squeezed Size', 'squeeze').'</th><th>'.esc_html__('Savings', 'squeeze').' (%)</th></tr></thead>';
171 $table .= '<tbody>';
172
173 foreach ($sizes as $size_name => $size_data) {
174 $size_filename = basename(sanitize_url($size_data['url']));
175 $original_size = $size_data['original_size'];
176 $compressed_size = $size_data['compressed_size'];
177 $savings = $original_size - $compressed_size;
178 $savings_percent = round(($savings / $original_size) * 100, 2);
179 $savings_class = $savings > 0 ? 'squeeze-savings-positive' : 'squeeze-savings-negative';
180
181 $table .= '<tr>';
182 $table .= '<td><strong>'.$size_name.'</strong></td>';
183 $table .= '<td>'.size_format($original_size, 0).'</td>';
184 $table .= '<td>'.size_format($compressed_size, 0).'</td>';
185 $table .= '<td><span class="squeeze-savings-label '.$savings_class.'">'.$savings_percent.'%</span></td>';
186 $table .= '</tr>';
187 }
188
189 $table .= '</tbody></table></div>';
190
191 return $table;
192 }
193
194 add_action('wp_ajax_squeeze_restore_attachment', 'squeeze_restore_attachment');
195 /**
196 * Restore original attachment
197 */
198 function squeeze_restore_attachment() {
199 check_ajax_referer( 'squeeze-nonce', '_ajax_nonce' );
200 if (isset($_POST["attachmentID"]) && !empty($_POST["attachmentID"]) && wp_get_attachment_url($_POST["attachmentID"])) {
201 $attach_id = (int) $_POST["attachmentID"];
202 $can_restore = squeeze_can_restore($attach_id);
203
204 if ($can_restore) {
205 $is_restore_attachment = _squeeze_restore_attachment($attach_id);
206
207 if ($is_restore_attachment) {
208 wp_send_json_success('�
209 '.esc_html__('Restored successfully', 'squeeze'));
210 } else {
211 wp_send_json_error(' '.esc_html__('Attachment not restored', 'squeeze'));
212 }
213
214 }
215 } else {
216 wp_send_json_error(' '.esc_html__('Attachment not found', 'squeeze'));
217 }
218 wp_die();
219 }
220
221 add_action('wp_ajax_squeeze_get_attachment', 'squeeze_get_attachment');
222 /**
223 * Get attachment data
224 */
225 function squeeze_get_attachment() {
226 check_ajax_referer( 'squeeze-nonce', '_ajax_nonce' );
227
228 if (isset($_POST["attachmentID"]) && !empty($_POST["attachmentID"]) && wp_get_attachment_url($_POST["attachmentID"])) {
229 $attach_id = (int) $_POST["attachmentID"];
230 $sizes = wp_get_attachment_metadata($attach_id);
231 $sizes = $sizes['sizes'];
232 $full_image = wp_get_attachment_image_src($attach_id, 'full');
233 $sizes['full'] = array(
234 'url' => $full_image[0],
235 'width' => $full_image[1],
236 'height' => $full_image[2],
237 );
238 foreach ($sizes as $size_name => $size_data) {
239 $sizes[$size_name]['url'] = wp_get_attachment_image_url($attach_id, $size_name);
240 }
241 $attach_data = array(
242 'id' => $attach_id,
243 'url' => wp_get_original_image_url($attach_id), //TBD
244 'mime' => get_post_mime_type($attach_id),
245 'name' => get_the_title($attach_id),
246 'filename' => basename( wp_get_original_image_path( $attach_id ) ),
247 'sizes' => $sizes,
248 );
249
250 wp_send_json_success($attach_data);
251
252 } else {
253 wp_send_json_error(' '.esc_html__('Attachment not found', 'squeeze'));
254 }
255
256 wp_die();
257 }
258
259 add_action('wp_ajax_squeeze_get_attachment_by_path', 'squeeze_get_attachment_by_path');
260 /**
261 * Get attachment data by path
262 */
263 function squeeze_get_attachment_by_path() {
264 check_ajax_referer( 'squeeze-nonce', '_ajax_nonce' );
265
266 if (isset($_POST["path"]) && !empty($_POST["path"])) {
267 $pathes = sanitize_text_field($_POST["path"]);
268 $pathes = json_decode(stripslashes($pathes), true);
269 $attach_data = array();
270
271 foreach ($pathes as $path) {
272 $path = str_replace(['\\\\', '\\'], '/', $path); // replace double and then single backslashes with slashes
273 if (substr($path, -1) !== '/') {
274 $path .= '/';
275 }
276 if (substr($path, 0, 1) !== '/') {
277 $path = '/' . $path;
278 }
279
280 $images = glob( ABSPATH . $path . '*.{'.SQUEEZE_ALLOWED_IMAGE_FORMATS.'}', GLOB_BRACE);
281
282 if (empty($images)) {
283 continue;
284 }
285
286 foreach ($images as $image) {
287 $attach_id = attachment_url_to_postid($image);
288 $attach_mime = image_type_to_mime_type(exif_imagetype($image));
289 $attach_url = str_replace(ABSPATH, home_url(), $image);
290 $attach_name = pathinfo($image, PATHINFO_FILENAME);
291 $attach_data[] = array(
292 'id' => $attach_id,
293 'url' => $attach_url,
294 'mime' => $attach_mime,
295 'name' => $attach_name,
296 'filename' => basename( $image ),
297 );
298 }
299 }
300
301 // Save pathes to cache
302 set_transient('squeeze_bulk_path', $pathes, MONTH_IN_SECONDS);
303
304 if (empty($attach_data)) {
305 wp_send_json_error(' '.esc_html__('Images were not found in the selected directories', 'squeeze'));
306 }
307
308 wp_send_json_success($attach_data);
309
310 } else {
311 wp_send_json_error(' '.esc_html__('Path not found', 'squeeze'));
312 }
313
314 wp_die();
315 }
316
317 /**
318 * Check if attachment can be restored
319 *
320 * @param int $attach_id
321 * @return bool
322 */
323 function squeeze_can_restore($attach_id) {
324 $original_img_path = wp_get_original_image_path((int) $attach_id);
325 $backup_img_path = preg_replace("/(\.(?!.*\.))/", '.bak.', $original_img_path);
326 $can_restore = file_exists($backup_img_path);
327
328 return $can_restore;
329 }
330
331 /**
332 * Handle restore attachment
333 * Internal function
334 *
335 * @param int $attach_id
336 * @return bool
337 */
338 function _squeeze_restore_attachment($attach_id, $is_bulk = false) {
339 $original_img_path = wp_get_original_image_path($attach_id);
340 $backup_img_path = preg_replace("/(\.(?!.*\.))/", '.bak.', $original_img_path);
341 $upload_restore_file = copy($backup_img_path, $original_img_path);
342
343 if (!$upload_restore_file) {
344 if ($is_bulk) {
345 wp_die(' '.esc_html__('Restore original image failed', 'squeeze'));
346 } else {
347 wp_send_json_error(' '.esc_html__('Restore original image failed', 'squeeze'));
348 }
349 return false;
350 }
351
352 // create thumbnails from original image
353 $attach_data = wp_create_image_subsizes($original_img_path, $attach_id);
354
355 $is_update_attachment = delete_post_meta($attach_id, "squeeze_is_compressed");
356
357 if ($is_update_attachment) {
358 wp_delete_file($backup_img_path); // delete backup file
359
360 $original_filename = pathinfo($original_img_path, PATHINFO_BASENAME);
361
362 // delete webp file
363 $webp_path = $original_img_path.'.webp';
364 $webp_path = squeeze_convert_image_path_to_webp_path($original_img_path);
365 wp_delete_file($webp_path);
366
367 // delete webp thumbnails
368 foreach ($attach_data['sizes'] as $size_name => $size_data) {
369 $webp_path = str_replace($original_filename, $size_data['file'].'.webp', $original_img_path);
370 $webp_path = squeeze_convert_image_path_to_webp_path($webp_path);
371 wp_delete_file($webp_path);
372 }
373
374 // delete scaled webp file
375 $webp_scaled_filename = pathinfo($attach_data['file'], PATHINFO_BASENAME);
376 $webp_scaled_path = str_replace($original_filename, $webp_scaled_filename.'.webp', $original_img_path);
377 $webp_scaled_path = squeeze_convert_image_path_to_webp_path($webp_scaled_path);
378 wp_delete_file($webp_scaled_path);
379
380 $uncompressed_images = squeeze_get_stats_option('uncompressed_images');
381 $uncompressed_images++;
382 update_option('squeeze_stats', array('uncompressed_images' => $uncompressed_images));
383 return true;
384 } else {
385 return false;
386 }
387 }
388
389 add_action('delete_attachment', 'squeeze_delete_backup_attachment');
390 /**
391 * Delete backup image when attachment is deleted
392 *
393 * @param int $attach_id
394 */
395 function squeeze_delete_backup_attachment($attach_id) {
396 $original_img_path = wp_get_original_image_path((int) $attach_id);
397 $backup_img_path = preg_replace("/(\.(?!.*\.))/", '.bak.', $original_img_path);
398
399 if (file_exists($backup_img_path)) {
400 return wp_delete_file($backup_img_path);
401 }
402
403 return false;
404 }
405
406 add_action('delete_attachment', 'squeeze_delete_webp_images');
407 /**
408 * Delete WEBP images when original image is deleted
409 */
410 function squeeze_delete_webp_images($attach_id) {
411 $result = false;
412 $original_img_path = wp_get_original_image_path((int) $attach_id);
413 $original_filename = pathinfo($original_img_path, PATHINFO_BASENAME);
414
415 // delete webp file
416 $webp_path = $original_img_path.'.webp';
417 $webp_path = squeeze_convert_image_path_to_webp_path($webp_path);
418
419 if (file_exists($webp_path)) {
420 $result = wp_delete_file($webp_path);
421 }
422
423 // delete webp thumbnails
424 $attach_data = wp_get_attachment_metadata($attach_id);
425 foreach ($attach_data['sizes'] as $size_name => $size_data) {
426 $webp_path = str_replace($original_filename, $size_data['file'].'.webp', $original_img_path);
427 $webp_path = squeeze_convert_image_path_to_webp_path($webp_path);
428
429 if (file_exists($webp_path)) {
430 $result = wp_delete_file($webp_path);
431 }
432 }
433
434 // delete scaled webp file
435 $webp_scaled_filename = pathinfo($attach_data['file'], PATHINFO_BASENAME);
436 $webp_scaled_path = str_replace($original_filename, $webp_scaled_filename.'.webp', $original_img_path);
437 $webp_scaled_path = squeeze_convert_image_path_to_webp_path($webp_scaled_path);
438
439 if (file_exists($webp_scaled_path)) {
440 $result = wp_delete_file($webp_scaled_path);
441 }
442
443 return $result;
444 }
445
446 add_filter('bulk_actions-upload', 'squeeze_bulk_actions');
447 /**
448 * Add bulk action to media library
449 *
450 * @param array $actions
451 * @return array
452 */
453 function squeeze_bulk_actions($actions) {
454 $actions['squeeze_bulk_restore'] = esc_html__('Restore Original Image', 'squeeze');
455 $actions['squeeze_bulk_compress'] = esc_html__('Squeeze Image', 'squeeze');
456 $actions['squeeze_bulk_delete_backup'] = esc_html__('Delete Backup Image', 'squeeze');
457 $actions['squeeze_bulk_delete_webp'] = esc_html__('Delete WEBP Image', 'squeeze');
458 return $actions;
459 }
460
461 add_filter('handle_bulk_actions-upload', 'squeeze_handle_bulk_actions', 10, 3);
462 /**
463 * Handle bulk action
464 *
465 * @param string $redirect_to
466 * @param string $doaction
467 * @param array $post_ids
468 * @return string
469 */
470 function squeeze_handle_bulk_actions($redirect_to, $doaction, $post_ids) {
471 if ($doaction === 'squeeze_bulk_restore') {
472 $restored_ids_count = 0;
473 foreach ($post_ids as $post_id) {
474 $can_restore = squeeze_can_restore($post_id);
475
476 if ($can_restore) {
477 $is_restore_attachment = _squeeze_restore_attachment($post_id, true);
478 if ($is_restore_attachment) {
479 $restored_ids_count += 1;
480 }
481 }
482 }
483
484 $redirect_to = add_query_arg('squeeze_bulk_restored', $restored_ids_count, $redirect_to);
485 }
486
487 if ($doaction === 'squeeze_bulk_compress') {
488 foreach ($post_ids as $post_id) {
489 $redirect_to = add_query_arg('squeeze_bulk_compressed', count($post_ids), $redirect_to);
490 }
491 }
492
493 if ($doaction === 'squeeze_bulk_delete_backup') {
494 $deleted_ids_count = 0;
495 foreach ($post_ids as $post_id) {
496 $is_delete_backup = squeeze_delete_backup_attachment($post_id);
497 if ($is_delete_backup) {
498 $deleted_ids_count += 1;
499 }
500 }
501
502 $redirect_to = add_query_arg('squeeze_bulk_deleted', $deleted_ids_count, $redirect_to);
503 }
504
505 if ($doaction === 'squeeze_bulk_delete_webp') {
506 $deleted_ids_count = 0;
507 foreach ($post_ids as $post_id) {
508 $is_delete_webp = squeeze_delete_webp_images($post_id);
509 if ($is_delete_webp) {
510 $deleted_ids_count += 1;
511 }
512 }
513
514 $redirect_to = add_query_arg('squeeze_bulk_webp_deleted', $deleted_ids_count, $redirect_to);
515 }
516
517
518 return $redirect_to;
519 }
520
521 add_action('admin_notices', 'squeeze_bulk_action_admin_notice');
522 /**
523 * Display admin notice after bulk action
524 */
525 function squeeze_bulk_action_admin_notice() {
526 if (!empty($_REQUEST['squeeze_bulk_restored'])) {
527 $message = sprintf(
528 /* translators: %d: number of attachments restored */
529 _n(
530 '%d attachment restored.',
531 '%d attachments restored.',
532 $_REQUEST['squeeze_bulk_restored'],
533 'squeeze'
534 ),
535 number_format_i18n($_REQUEST['squeeze_bulk_restored'])
536 );
537 printf('<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html($message));
538 }
539 if (!empty($_REQUEST['squeeze_bulk_compressed'])) {
540 $message = sprintf(
541 /* translators: %d: number of attachments squeezed */
542 _n(
543 '%d attachment squeezed.',
544 '%d attachments squeezed.',
545 $_REQUEST['squeeze_bulk_compressed'],
546 'squeeze'
547 ),
548 number_format_i18n($_REQUEST['squeeze_bulk_compressed'])
549 );
550 printf('<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html($message));
551 }
552 if (!empty($_REQUEST['squeeze_bulk_deleted'])) {
553 $message = sprintf(
554 /* translators: %d: number of backup images deleted */
555 _n(
556 '%d backup image deleted.',
557 '%d backup images deleted.',
558 $_REQUEST['squeeze_bulk_deleted'],
559 'squeeze'
560 ),
561 number_format_i18n($_REQUEST['squeeze_bulk_deleted'])
562 );
563 printf('<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html($message));
564 }
565 if (!empty($_REQUEST['squeeze_bulk_webp_deleted'])) {
566 $message = sprintf(
567 /* translators: %d: number of webp images deleted */
568 _n(
569 '%d WEBP image deleted.',
570 '%d WEBP images deleted.',
571 $_REQUEST['squeeze_bulk_webp_deleted'],
572 'squeeze'
573 ),
574 number_format_i18n($_REQUEST['squeeze_bulk_webp_deleted'])
575 );
576 printf('<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html($message));
577 }
578 }
579
580 add_filter('image_size_names_choose', 'squeeze_custom_image_sizes');
581 /**
582 * Add custom image sizes to media library
583 *
584 * @param array $sizes
585 * @return array
586 */
587 function squeeze_custom_image_sizes($sizes) {
588 $available_sizes = wp_get_registered_image_subsizes();
589
590 foreach ($available_sizes as $size_name => $size_data) {
591 $sizes[$size_name] = $size_data['width'] . 'x' . $size_data['height'];
592 }
593
594 return $sizes;
595 }
596
597 function squeeze_get_total_images_count() {
598 $total_images = squeeze_get_stats_option('total_images');
599
600 if ($total_images > 0) {
601 return $total_images;
602 }
603
604 $query_all = new WP_Query(array(
605 'post_type' => 'attachment',
606 'post_status' => 'inherit',
607 'post_mime_type' => SQUEEZE_ALLOWED_IMAGE_MIME_TYPES,
608 'posts_per_page' => -1,
609 'fields' => 'ids',
610 ));
611
612 $total_images = $query_all->found_posts;
613
614 $stats['total_images'] = $total_images;
615 update_option('squeeze_stats', $stats);
616
617 return $total_images;
618 }
619
620 function squeeze_get_uncompressed_images_count() {
621 $uncompressed_images = squeeze_get_stats_option('uncompressed_images');
622
623 if ($uncompressed_images > 0) {
624 return $uncompressed_images;
625 }
626
627 $query_uncompressed = new WP_Query(array(
628 'post_type' => 'attachment',
629 'post_status' => 'inherit',
630 'post_mime_type' => SQUEEZE_ALLOWED_IMAGE_MIME_TYPES,
631 'posts_per_page' => -1,
632 'fields' => 'ids',
633 'meta_query' => array(
634 'relation' => 'OR',
635 array(
636 'key' => 'squeeze_is_compressed',
637 'compare' => 'NOT EXISTS',
638 ),
639 array(
640 'key' => 'squeeze_is_compressed',
641 'compare' => '!=',
642 'value' => '1',
643 ),
644 ),
645 ));
646
647 $uncompressed_images = $query_uncompressed->found_posts;
648
649 $stats['uncompressed_images'] = $uncompressed_images;
650 update_option('squeeze_stats', $stats);
651
652 return $uncompressed_images;
653 }
654
655 function squeeze_get_stats_option($option) {
656 $stats = get_option('squeeze_stats');
657 $option_value = isset($stats[$option]) ? $stats[$option] : 0;
658
659 return $option_value;
660 }
661
662 function squeeze_get_uncompressed_images($paged = 1) {
663 $query_uncompressed = new WP_Query(array(
664 'post_type' => 'attachment',
665 'post_status' => 'inherit',
666 'post_mime_type' => SQUEEZE_ALLOWED_IMAGE_MIME_TYPES,
667 'posts_per_page' => SQUEEZE_MEDIA_PER_PAGE,
668 'paged' => $paged,
669 'fields' => 'ids',
670 'meta_query' => array(
671 'relation' => 'OR',
672 array(
673 'key' => 'squeeze_is_compressed',
674 'compare' => 'NOT EXISTS',
675 ),
676 array(
677 'key' => 'squeeze_is_compressed',
678 'compare' => '!=',
679 'value' => '1',
680 ),
681 ),
682 ));
683
684 return $query_uncompressed->posts;
685 }
686
687 function squeeze_get_total_images($paged = 1) {
688 $query_all = new WP_Query(array(
689 'post_type' => 'attachment',
690 'post_status' => 'inherit',
691 'post_mime_type' => SQUEEZE_ALLOWED_IMAGE_MIME_TYPES,
692 'posts_per_page' => SQUEEZE_MEDIA_PER_PAGE,
693 'paged' => $paged,
694 'fields' => 'ids',
695 ));
696
697 return $query_all->posts;
698 }
699
700 add_action('wp_ajax_squeeze_get_next_attachments', 'squeeze_get_next_attachments');
701 function squeeze_get_next_attachments() {
702 check_ajax_referer( 'squeeze-nonce', '_ajax_nonce' );
703
704 $per_page = SQUEEZE_MEDIA_PER_PAGE;
705 $page = isset($_POST['page']) ? (int) $_POST['page'] : 1;
706 $type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : 'uncompressed';
707 if ($type === 'uncompressed') {
708 $next_images = squeeze_get_uncompressed_images($page);
709 } else {
710 $next_images = squeeze_get_total_images($page);
711 }
712
713 wp_send_json_success($next_images);
714 }
715
716 add_action('pre-html-upload-ui', 'squeeze_single_file_upload_notice', 10);
717 /**
718 * Display notice for single file upload
719 */
720 function squeeze_single_file_upload_notice() {
721 global $current_screen;
722
723 if ($current_screen->id === 'media') {
724 ?>
725 <div class="notice notice-info hide-if-js squeeze-single-file-upload-notice">
726 <p><?php esc_html_e('Single file upload is not supported for the image compression by Squeeze. Please use multi-file uploader or bulk squeeze.', 'squeeze'); ?></p>
727 </div>
728 <?php
729 }
730 }
731
732
733 add_action('wp_ajax_squeeze_get_directories', 'squeeze_get_directories_callback');
734 /**
735 * Get directories in uploads directory
736 */
737 function squeeze_get_directories_callback() {
738 check_ajax_referer( 'squeeze-nonce', '_ajax_nonce' );
739
740 $parent_directory = isset($_POST['parentDir']) ? sanitize_text_field($_POST['parentDir']) : '';
741 $base_dir = $parent_directory ? ABSPATH . $parent_directory : WP_CONTENT_DIR;
742 $directories = scandir($base_dir);
743
744 if (!$parent_directory) {
745 $directories[] = $base_dir;
746 }
747
748 $result = array_filter($directories, function ($dir) use ($base_dir) {
749 if ($dir === $base_dir) {
750 return true;
751 }
752 return is_dir($base_dir . '/' . $dir) && !in_array($dir, ['.', '..']);
753 });
754
755 $output = array_map(function ($dir) use ($base_dir) {
756 if ($dir === $base_dir) {
757 $path = str_replace(ABSPATH, '/', $dir . '/');
758 $parent_path = dirname($base_dir);
759 $parent_path = str_replace(ABSPATH, '/', $parent_path . '/');
760
761 return [
762 'name' => 'wp-content',
763 'path' => $path,
764 'is_writeable' => false,//wp_is_writable($base_dir),
765 'parent' => $parent_path,
766 ];
767 }
768
769 $path = str_replace(ABSPATH, '/', $base_dir . '/' . $dir . '/');
770 $parent_path = dirname($base_dir . '/' . $dir);
771 $parent_path = str_replace(ABSPATH, '/', $parent_path . '/');
772
773 // Remove double slashes from path
774 $path = preg_replace('/\/+/', '/', $path);
775 $parent_path = preg_replace('/\/+/', '/', $parent_path);
776
777 return [
778 'name' => $dir,
779 'path' => $path,
780 'is_writeable' => wp_is_writable($base_dir . '/' . $dir),
781 'parent' => $parent_path,
782 ];
783 }, $result);
784
785 usort($output, function($a, $b) {
786 if ($a['name'] === 'wp-content') {
787 return -1;
788 } elseif ($b['name'] === 'wp-content') {
789 return 1;
790 }
791 return strcmp($a['name'], $b['name']);
792 });
793
794 wp_send_json($output);
795 }
796
797 add_filter('mod_rewrite_rules', 'squeeze_add_webp_rewrite_rules');
798 /**
799 * Add WebP rewrite rules to .htaccess
800 */
801 function squeeze_add_webp_rewrite_rules($rules) {
802 $options = get_option( 'squeeze_options' );
803 $is_auto_webp = isset($options['auto_webp']) ? $options['auto_webp'] : squeeze_get_default_value('auto_webp');
804
805 if (!$is_auto_webp) {
806 return $rules;
807 }
808
809 // Check if the server is Apache and htaccess is writable
810 if (!function_exists('apache_get_modules') || !in_array('mod_rewrite', apache_get_modules())) {
811 return $rules;
812 }
813
814 // Get the WordPress installation subdirectory, if applicable
815 $wordpress_subdirectory = wp_parse_url(home_url(), PHP_URL_PATH);
816
817 // Check if WordPress is installed in a subdirectory (not just the root)
818 if (strlen($wordpress_subdirectory) > 1) {
819 // Ensure the subdirectory is used correctly in the rules
820 $rewrite_base = $wordpress_subdirectory . '/';
821 } else {
822 // If WordPress is installed in the root, no subdirectory path is needed
823 $rewrite_base = '/';
824 }
825
826 $webp_rules = "\n# Serve WebP images from the wp-content/squeeze-webp folder if available\n";
827 $webp_rules .= "RewriteCond %{HTTP_ACCEPT} image/webp\n"; // Check if browser supports WebP
828 $webp_rules .= "RewriteCond %{REQUEST_URI} \.(jpg|jpeg|png)$ [NC]\n"; // Check if request is for JPG, JPEG, or PNG
829 $webp_rules .= "RewriteCond %{DOCUMENT_ROOT}".$rewrite_base."wp-content/squeeze-webp/$1.$2.webp -f\n"; // Check if WebP file exists
830 $webp_rules .= "RewriteRule ^wp-content/(.+)\.(jpg|jpeg|png)$ wp-content/squeeze-webp/$1.$2.webp [T=image/webp,E=webp_request,L]\n"; // Serve WebP file
831 $webp_rules .= "\n";
832
833 return $webp_rules . $rules;
834 }
835
836 /**
837 * Convert image path to WebP path
838 * Replaces wp-content/uploads with wp-content/squeeze-webp/uploads
839 */
840 function squeeze_convert_image_path_to_webp_path($image_path) {
841 $webp_path = preg_replace('/wp-content[\/\\\\]uploads/', 'wp-content'.DIRECTORY_SEPARATOR.'squeeze-webp'.DIRECTORY_SEPARATOR.'uploads', $image_path);
842 return $webp_path;
843 }
844
845 /*
846 add_filter('the_content', 'squeeze_replace_image_urls_with_webp', 99);
847 add_filter('the_excerpt', 'squeeze_replace_image_urls_with_webp', 99);
848 add_filter('post_thumbnail_html', 'squeeze_replace_image_urls_with_webp', 99);
849 add_filter('widget_text', 'squeeze_replace_image_urls_with_webp', 99);
850 // */
851
852 add_action('init', 'squeeze_output_fuffer_start', 1);
853
854 function squeeze_replace_image_urls_with_webp($content) {
855
856 if (!squeeze_is_webp_replace_urls()) {
857 return $content;
858 }
859
860 // Regular expression to find JPG and PNG images in src and srcset attributes.
861 $pattern = '/(\/\/.*?\/wp-content\/)([^"\s]+\.(jpg|jpeg|png))(\?[^"\s]*)?/i';
862
863 // Callback function to replace the URLs.
864 $callback = function ($matches) {
865 $file_extension = strtolower(pathinfo($matches[0], PATHINFO_EXTENSION));
866
867 if ($file_extension === 'webp') {
868 return $matches[0];
869 }
870
871 $protocol = is_ssl() ? 'https:' : 'http:';
872 $webp_url = squeeze_convert_image_path_to_webp_path($matches[0]) . '.webp'; // WebP URL like 'example.com/wp-content/squeeze-webp/uploads/2024/12/test.jpg.webp'
873
874 // Check if the WEBP file exists on the server.
875 $webp_file_path = str_replace(home_url(), ABSPATH, $protocol.$webp_url); // Convert URL to file path.
876
877 //return $webp_file_path.'::'.$webp_url;
878
879 if (file_exists($webp_file_path)) {
880 return $webp_url; // Use WEBP version if it exists.
881 }
882
883 return $matches[0]; // Fallback to the original URL if WEBP file doesn't exist.
884 };
885
886 // Replace URLs in the content, including src and srcset attributes.
887 $content = preg_replace_callback($pattern, $callback, $content);
888
889 return $content;
890 }
891
892 function squeeze_output_fuffer_start() {
893 if (!is_admin() || (function_exists("wp_doing_ajax") && wp_doing_ajax()) || (defined( 'DOING_AJAX' ) && DOING_AJAX)) {
894 ob_start('squeeze_replace_image_urls_with_webp');
895 }
896 }
897
898 function squeeze_is_webp_replace_urls() {
899 $options = get_option( 'squeeze_options' );
900 $is_auto_webp = isset($options['auto_webp']) ? $options['auto_webp'] : squeeze_get_default_value('auto_webp');
901 $is_webp_replace_urls = isset($options['webp_replace_urls']) ? $options['webp_replace_urls'] : squeeze_get_default_value('webp_replace_urls');
902
903 if (!$is_auto_webp || !$is_webp_replace_urls) {
904 return false;
905 }
906
907 return true;
908 }