PluginProbe
Squeeze – Image Optimization & Compression, WEBP Conversion / 1.6
Squeeze – Image Optimization & Compression, WEBP Conversion v1.6
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 / inc / helpers.php

helpers.php in Squeeze – Image Optimization & Compression, WEBP Conversion 1.6, at inc/helpers.php

412 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Squeeze;
3
4 // Exit if accessed directly.
5 if (!defined('ABSPATH')) {
6 exit;
7 }
8
9 class SqueezeHelpers extends SqueezeInit {
10 public function __construct() {
11 //parent::__construct(); // will cause infinite loop in SquuezeInit
12 }
13
14 public function get_upload_path($attach_id, $filename, $url) {
15 if ($attach_id > 0) {
16 $upload_dir = str_replace($filename, "", wp_get_original_image_path($attach_id));
17 } else {
18 $upload_url = str_replace($filename, "", $url);
19 $upload_dir = str_replace(home_url(), ABSPATH, $upload_url);
20 }
21 return str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . DIRECTORY_SEPARATOR;
22 }
23
24 public function backup_original_image($upload_path, $filename) {
25 $backup_filename = preg_replace("/(\.(?!.*\.))/", '.bak.', $filename);
26 if (!file_exists($upload_path . $backup_filename)) {
27 $upload_backup_file = copy($upload_path . $filename, $upload_path . $backup_filename);
28 if (!$upload_backup_file) {
29 return new \WP_Error('squeeze_backup_original_image_failed', ''.esc_html__('Backup original image failed', 'squeeze') . ': '. $upload_path . $backup_filename);
30 }
31
32 return $upload_backup_file;
33 }
34
35 return true;
36 }
37
38 public function decode_base64_image($base64, $file_format) {
39 $img = str_replace('data:image/'.$file_format.';base64,', '', $base64);
40 $img = str_replace(' ', '+', $img);
41 return base64_decode($img);
42 }
43
44 public function upload_image($upload_path, $filename, $decoded_image) {
45 global $wp_filesystem;
46 if (empty($wp_filesystem)) {
47 require_once(ABSPATH . '/wp-admin/includes/file.php');
48 WP_Filesystem();
49 }
50 $upload_file = $wp_filesystem->put_contents($upload_path . $filename, $decoded_image);
51 if (!$upload_file) {
52 return new \WP_Error('squeeze_upload_image_failed', ''.esc_html__('Upload image failed', 'squeeze') . ': upload_path:' . $upload_path . ':: filename:' . $filename);
53 }
54
55 return $upload_file;
56 }
57
58 public function upload_image_thumbs($upload_path, $sizes, $file_format) {
59 if (!is_array($sizes) || empty($sizes)) {
60 return new \WP_Error('squeeze_upload_image_thumbs_failed', ''.esc_html__('No image data found', 'squeeze'));
61 }
62 global $wp_filesystem;
63 if (empty($wp_filesystem)) {
64 require_once(ABSPATH . '/wp-admin/includes/file.php');
65 WP_Filesystem();
66 }
67 foreach ($sizes as $size_name => $size_data) {
68 if ($size_name === 'original') {
69 continue;
70 }
71 $size_base64 = sanitize_text_field($size_data['base64']);
72 $size_decoded = $this->decode_base64_image($size_base64, $file_format);
73 $size_filename = basename(sanitize_url($size_data['url']));
74 if ($size_name === 'full') {
75 $size_name = 'scaled';
76 unset($sizes['full']);
77 }
78 $sizes[$size_name]['original_size'] = filesize($upload_path . $size_filename);
79 $upload_size_file = $wp_filesystem->put_contents($upload_path . $size_filename, $size_decoded);
80 if (!$upload_size_file) {
81 return new \WP_Error('squeeze_upload_image_thumbs_failed', ''.esc_html__('Upload image failed', 'squeeze') . ': upload_path:' . $upload_path . ':: filename:' . $size_filename);
82 } else {
83 $sizes[$size_name]['compressed_size'] = strlen($size_decoded);
84 }
85 }
86 return $sizes;
87 }
88
89 public function upload_webp($upload_path, $base64_webp, $filename) {
90 if (!$base64_webp) {
91 return new \WP_Error('squeeze_upload_webp_failed', ''.esc_html__('No WebP data found', 'squeeze'));
92 }
93
94 $upload_webp_path = $this->convert_image_path_to_webp_path($upload_path);
95 if (!file_exists($upload_webp_path)) {
96 wp_mkdir_p($upload_webp_path);
97 }
98 $decoded_webp = $this->decode_base64_image($base64_webp, 'webp');
99 $filename_webp = $filename.'.webp';
100 $upload_file_webp = $this->upload_image($upload_webp_path, $filename_webp, $decoded_webp);
101
102 return $upload_file_webp;
103 }
104
105 public function upload_webp_thumbs($upload_path, $sizes_webp) {
106 if (!is_array($sizes_webp) || empty($sizes_webp)) {
107 return new \WP_Error('squeeze_upload_webp_thumbs_failed', ''.esc_html__('No WebP data found', 'squeeze'));
108 }
109
110 $upload_webp_path = $this->convert_image_path_to_webp_path($upload_path);
111 if (!file_exists($upload_webp_path)) {
112 wp_mkdir_p($upload_webp_path);
113 }
114 foreach ($sizes_webp as $size_name => $size_data) {
115 if ($size_name === 'original') {
116 continue;
117 }
118 $size_base64 = sanitize_text_field($size_data['base64']);
119 $size_decoded = $this->decode_base64_image($size_base64, 'webp');
120 $size_filename = basename(sanitize_url($size_data['url']));
121 $size_filename = $size_filename.'.webp';
122 $upload_size_file = $this->upload_image($upload_webp_path, $size_filename, $size_decoded);
123 }
124 return $sizes_webp;
125 }
126
127 public function convert_image_path_to_webp_path($image_path) {
128 $webp_path = preg_replace('/wp-content[\/\\\\]/', 'wp-content'.DIRECTORY_SEPARATOR.'squeeze-webp'.DIRECTORY_SEPARATOR, $image_path);
129 return $webp_path;
130 }
131
132 public function can_restore($attach_id) {
133 $original_img_path = wp_get_original_image_path((int) $attach_id);
134 $backup_img_path = preg_replace("/(\.(?!.*\.))/", '.bak.', $original_img_path);
135 $can_restore = file_exists($backup_img_path);
136
137 return $can_restore;
138 }
139
140 public function restore_attachment($attach_id, $is_bulk = false) {
141 $original_img_path = wp_get_original_image_path($attach_id);
142 $backup_img_path = preg_replace("/(\.(?!.*\.))/", '.bak.', $original_img_path);
143
144 if (!copy($backup_img_path, $original_img_path)) {
145 $error_message = '' . esc_html__('Restore original image failed', 'squeeze');
146 if ($is_bulk) {
147 wp_die($error_message);
148 } else {
149 return new \WP_Error('squeeze_restore_attachment_failed', $error_message);
150 }
151 return false;
152 }
153
154 $attach_data = wp_create_image_subsizes($original_img_path, $attach_id);
155 if (!delete_post_meta($attach_id, "squeeze_is_compressed")) {
156 return false;
157 }
158
159 wp_delete_file($backup_img_path);
160 $this->delete_webp_images($original_img_path, $attach_data);
161
162 $uncompressed_images = $this->get_stats_option('uncompressed_images');
163 update_option('squeeze_stats', array('uncompressed_images' => ++$uncompressed_images));
164 return true;
165 }
166
167 public function delete_webp_images($original_img_path, $attach_data) {
168 $result = false;
169 $original_filename = pathinfo($original_img_path, PATHINFO_BASENAME);
170
171 $webp_path = $this->convert_image_path_to_webp_path($original_img_path);
172 $result = wp_delete_file($webp_path . '.webp');
173
174 foreach ($attach_data['sizes'] as $size_data) {
175 $webp_thumb_path = str_replace($original_filename, $size_data['file'] . '.webp', $original_img_path);
176 $result = wp_delete_file($this->convert_image_path_to_webp_path($webp_thumb_path));
177 }
178
179 $webp_scaled_filename = pathinfo($attach_data['file'], PATHINFO_BASENAME);
180 $webp_scaled_path = str_replace($original_filename, $webp_scaled_filename . '.webp', $original_img_path);
181 $result = wp_delete_file($this->convert_image_path_to_webp_path($webp_scaled_path));
182
183 return $result;
184 }
185
186 public function get_stats_option($option) {
187 $stats = get_option('squeeze_stats');
188 $option_value = isset($stats[$option]) ? $stats[$option] : 0;
189
190 return $option_value;
191 }
192
193 public function get_option($option) {
194 $options = get_option('squeeze_options');
195 $option_value = isset($options[$option]) ? $options[$option] : $this->get_default_value($option);
196
197 return $option_value;
198 }
199
200 public function get_comparison_table($sizes) {
201 if (!is_array($sizes) || empty($sizes)) {
202 return '';
203 }
204
205 $table = '<div class="squeeze-comparison-table">';
206 $table .= '<table class="wp-list-table widefat striped">';
207 $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>';
208 $table .= '<tbody>';
209
210 foreach ($sizes as $size_name => $size_data) {
211 $size_filename = basename(sanitize_url($size_data['url']));
212 $original_size = $size_data['original_size'];
213 $compressed_size = $size_data['compressed_size'];
214 $savings = $original_size - $compressed_size;
215 $savings_percent = round(($savings / $original_size) * 100, 2);
216 $savings_class = $savings > 0 ? 'squeeze-savings-positive' : 'squeeze-savings-negative';
217
218 $table .= '<tr>';
219 $table .= '<td><strong>'.$size_name.'</strong></td>';
220 $table .= '<td>'.size_format($original_size, 0).'</td>';
221 $table .= '<td>'.size_format($compressed_size, 0).'</td>';
222 $table .= '<td><span class="squeeze-savings-label '.$savings_class.'">'.$savings_percent.'%</span></td>';
223 $table .= '</tr>';
224 }
225
226 $table .= '</tbody></table></div>';
227
228 return $table;
229 }
230
231 public function is_webp_replace_urls() {
232 $is_auto_webp = $this->get_option('auto_webp');
233 $is_webp_replace_urls = $this->get_option('webp_replace_urls');
234
235 if (!$is_auto_webp || !$is_webp_replace_urls) {
236 return false;
237 }
238
239 return true;
240 }
241
242 public function get_image_formats($return_mimes = false) {
243 $allowed_image_formats = $this->get_option('compress_formats');
244 $allowed_image_formats = array_keys($allowed_image_formats);
245
246 if ($return_mimes) {
247 $allowed_image_formats = array_map(function($format) {
248 return 'image/'.$format;
249 }, $allowed_image_formats);
250 }
251
252 return $allowed_image_formats;
253 }
254
255 public function get_total_images_count() {
256 $total_images = $this->get_stats_option('total_images');
257
258 if ($total_images > 0) {
259 return $total_images;
260 }
261
262 $query_all = new \WP_Query(array(
263 'post_type' => 'attachment',
264 'post_status' => 'inherit',
265 'post_mime_type' => $this->get_image_formats(true),
266 'posts_per_page' => -1,
267 'fields' => 'ids',
268 ));
269
270 $total_images = $query_all->found_posts;
271
272 $stats['total_images'] = $total_images;
273 update_option('squeeze_stats', $stats);
274
275 return $total_images;
276 }
277
278 public function get_uncompressed_images_count() {
279 $uncompressed_images = $this->get_stats_option('uncompressed_images');
280
281 if ($uncompressed_images > 0) {
282 return $uncompressed_images;
283 }
284
285 $query_uncompressed = new \WP_Query(array(
286 'post_type' => 'attachment',
287 'post_status' => 'inherit',
288 'post_mime_type' => $this->get_image_formats(true),
289 'posts_per_page' => -1,
290 'fields' => 'ids',
291 'meta_query' => array(
292 'relation' => 'OR',
293 array(
294 'key' => 'squeeze_is_compressed',
295 'compare' => 'NOT EXISTS',
296 ),
297 array(
298 'key' => 'squeeze_is_compressed',
299 'compare' => '!=',
300 'value' => '1',
301 ),
302 ),
303 ));
304
305 $uncompressed_images = $query_uncompressed->found_posts;
306
307 $stats['uncompressed_images'] = $uncompressed_images;
308 update_option('squeeze_stats', $stats);
309
310 return $uncompressed_images;
311 }
312
313 public function get_uncompressed_images($paged = 1) {
314 $query_uncompressed = new \WP_Query(array(
315 'post_type' => 'attachment',
316 'post_status' => 'inherit',
317 'post_mime_type' => $this->get_image_formats(true),
318 'posts_per_page' => self::$MEDIA_PER_PAGE,
319 'paged' => $paged,
320 'fields' => 'ids',
321 'meta_query' => array(
322 'relation' => 'OR',
323 array(
324 'key' => 'squeeze_is_compressed',
325 'compare' => 'NOT EXISTS',
326 ),
327 array(
328 'key' => 'squeeze_is_compressed',
329 'compare' => '!=',
330 'value' => '1',
331 ),
332 ),
333 ));
334
335 return $query_uncompressed->posts;
336 }
337
338 public function get_total_images($paged = 1) {
339 $args = array(
340 'post_type' => 'attachment',
341 'post_status' => 'inherit',
342 'post_mime_type' => $this->get_image_formats(true),
343 'posts_per_page' => self::$MEDIA_PER_PAGE,
344 'paged' => $paged,
345 'fields' => 'ids',
346 );
347
348 $query_all = new \WP_Query($args);
349
350 return $query_all->posts;
351 }
352
353 public function get_hint($hint, $class = 'squeeze-hint') {
354 return '<span class="' . esc_attr($class) . '">' . esc_html($hint) . '</span>';
355 }
356
357 public function get_default_value ( $option, $all = false ) {
358 $options_defaults = apply_filters('squeeze_options_default',
359 array(
360 // JPEG settings
361 'jpeg_quality' => 80,
362 'jpeg_baseline' => false,
363 'jpeg_arithmetic' => false,
364 'jpeg_progressive' => true,
365 'jpeg_optimize_coding' => true,
366 'jpeg_smoothing' => 0,
367 'jpeg_color_space' => 3,
368 'jpeg_quant_table' => 3,
369 'jpeg_trellis_multipass' => false,
370 'jpeg_trellis_opt_zero' => false,
371 'jpeg_trellis_opt_table' => false,
372 'jpeg_trellis_loops' => 1,
373 'jpeg_auto_subsample' => true,
374 'jpeg_chroma_subsample' => 2,
375 'jpeg_separate_chroma_quality' => false,
376 'jpeg_chroma_quality' => 75,
377
378 // PNG settings
379 'png_level' => 2,
380 'png_interlace' => false,
381
382 // WEBP settings
383 'webp_method' => 4,
384 'webp_quality' => 80,
385 'webp_lossless' => false,
386 'webp_near_lossless' => 100,
387
388 // AVIF settings
389 'avif_cqLevel' => 70,
390
391 // General settings
392 'auto_compress' => true,
393 'auto_webp' => false, // needs to be false by default, because user has to save settings first in order to flush rewrite rules
394 'webp_replace_urls' => false,
395 'cdn_url' => '',
396 'backup_original' => true,
397 'compress_formats' => self::ALLOWED_IMAGE_FORMATS,
398 'compress_thumbs' => array('large' => 'on', 'full' => 'on'),
399 'max_width' => '',
400 'max_height' => '',
401 'excluded_images' => '',
402 'timeout' => 60,
403 'restore_defaults' => false, // special option to trigger restore defaults
404 )
405 );
406 if ($all) {
407 return $options_defaults;
408 }
409 return in_array($option, array_keys($options_defaults)) ? $options_defaults[ $option ] : false;
410 }
411 }
412