PluginProbe
Squeeze – Image Optimization & Compression, WEBP Conversion / 1.7.12
Squeeze – Image Optimization & Compression, WEBP Conversion v1.7.12
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 / settings.php

settings.php in Squeeze – Image Optimization & Compression, WEBP Conversion 1.7.12, at inc/settings.php

2,074 lines 101.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SqueezeFree;
4
5 // Exit if accessed directly.
6 if ( !defined( 'ABSPATH' ) ) {
7 exit;
8 }
9 class SqueezeSettings extends SqueezeInit {
10 public function __construct() {
11 add_action( 'admin_menu', [$this, 'options_page'] );
12 add_action( 'admin_menu', [$this, 'options_bulk_page'] );
13 add_action( 'admin_init', [$this, 'register_settings'] );
14 add_action(
15 'update_option_squeeze_options',
16 [$this, 'restore_defaults'],
17 10,
18 2
19 );
20 add_action(
21 'update_option_squeeze_options',
22 [$this, 'flush_rewrite_rules'],
23 10,
24 2
25 );
26 add_filter(
27 'attachment_fields_to_edit',
28 [$this, 'add_custom_field_to_attachment'],
29 10,
30 2
31 );
32 add_filter( 'manage_media_columns', [$this, 'add_media_columns'] );
33 add_action(
34 'manage_media_custom_column',
35 [$this, 'media_custom_column'],
36 10,
37 2
38 );
39 add_filter( 'manage_upload_sortable_columns', [$this, 'sortable_columns'] );
40 add_action( 'pre_get_posts', [$this, 'sortable_columns_orderby'] );
41 add_action( 'restrict_manage_posts', [$this, 'media_filter_dropdown'] );
42 add_action( 'pre_get_posts', [$this, 'media_filter_query'] );
43 add_filter(
44 'ajax_query_attachments_args',
45 [$this, 'media_filter_ajax_query'],
46 10,
47 1
48 );
49 add_filter(
50 'posts_results',
51 [$this, 'media_filter_exclude_excluded'],
52 10,
53 2
54 );
55 add_action(
56 'update_option_squeeze_options',
57 [$this, 'handle_excluded_images_option_change'],
58 10,
59 2
60 );
61 add_action( 'admin_footer', [$this, 'svg_sprite_output'] );
62 add_action( 'admin_notices', [$this, 'incompatibility_notices'] );
63 add_action( 'edit_form_after_title', [$this, 'add_preview_button_placeholder'], 10 );
64 }
65
66 public function options_page() {
67 add_submenu_page(
68 'options-general.php',
69 __( 'Squeeze Settings', 'squeeze' ),
70 __( 'Squeeze', 'squeeze' ),
71 'manage_options',
72 'squeeze',
73 [$this, 'options_page_html']
74 );
75 }
76
77 public function options_bulk_page() {
78 add_submenu_page(
79 'upload.php',
80 __( 'Bulk / Directory Squeeze', 'squeeze' ),
81 __( 'Bulk / Directory Squeeze', 'squeeze' ),
82 'manage_options',
83 'squeeze-bulk',
84 [$this, 'options_bulk_page_html']
85 );
86 }
87
88 public function options_bulk_page_html() {
89 // check user capabilities
90 if ( !current_user_can( 'manage_options' ) ) {
91 return;
92 }
93 $is_single_page_squeeze = false;
94 $uncompressed_count = self::$SqueezeHelpers->get_uncompressed_images_count();
95 $uncompressed_pages = ceil( $uncompressed_count / self::$MEDIA_PER_PAGE );
96 $total_count = self::$SqueezeHelpers->get_total_images_count();
97 $total_pages = ceil( $total_count / self::$MEDIA_PER_PAGE );
98 $compressed_count = $total_count - $uncompressed_count;
99 $compressed_percentage = ( $total_count > 0 ? round( $compressed_count / $total_count * 100, 2 ) : 0 );
100 //$total_count = array_sum((array)wp_count_attachments("image"));
101 $not_compressed_posts = implode( ",", self::$SqueezeHelpers->get_uncompressed_images() );
102 $all_posts = implode( ",", self::$SqueezeHelpers->get_total_images() );
103 $directory_path = ( get_transient( 'squeeze_bulk_path' ) ? get_transient( 'squeeze_bulk_path' ) : array('/wp-content/uploads/') );
104 $directory_path = array_map( array(self::$SqueezeHelpers, 'normalize_bulk_directory_storage_path'), (array) $directory_path );
105 $directory_path_json = wp_json_encode( $directory_path );
106 $is_direct_webp = self::$SqueezeHelpers->get_option( 'direct_webp' );
107 ?>
108 <div class="wrap">
109 <h1>
110 <?php
111 echo esc_html( get_admin_page_title() );
112 ?>
113 </h1>
114 <?php
115 if ( !$is_single_page_squeeze ) {
116 ?>
117 <p class="squeeze-bulk-lede description">
118 <?php
119 esc_html_e( 'Compress and convert images in bulk. "Squeeze" means optimize file size (and optionally change format) for items in your Media Library or a folder you choose.', 'squeeze' );
120 ?>
121 </p>
122 <?php
123 }
124 ?>
125 <section class="squeeze-box">
126 <div class="squeeze-box-bulk-stack">
127 <?php
128 if ( !$is_single_page_squeeze ) {
129 ?>
130 <div class="squeeze-box-bulk-workflows">
131 <section id="squeeze-bulk-section-library" class="squeeze-bulk-section squeeze-bulk-section--library" aria-labelledby="squeeze-heading-library">
132 <header class="squeeze-bulk-section__head">
133 <h2 id="squeeze-heading-library"><?php
134 esc_html_e( 'Bulk Media Library Squeeze', 'squeeze' );
135 ?></h2>
136 <p class="squeeze-bulk-section__meta"><?php
137 esc_html_e( 'Uses attachments in the library; backups follow your plugin settings.', 'squeeze' );
138 ?></p>
139 </header>
140 <div class="squeeze-bulk-section__body">
141 <?php
142 if ( $is_direct_webp ) {
143 ?>
144 <div class="squeeze-banner squeeze-banner--notice">
145 <svg class="squeeze-icon" aria-hidden="true">
146 <use xlink:href="#info-icon"></use>
147 </svg>
148 <div class="squeeze-banner__content">
149 <p class="squeeze-banner__title"><?php
150 printf( __( 'Direct WebP conversion is on <a href="%s" target="_blank">(change)</a>', 'squeeze' ), esc_url( admin_url( 'options-general.php?page=squeeze#squeeze_basic' ) ) );
151 ?></p>
152 <p><?php
153 esc_html_e( 'After conversion, image URLs may change. Check themes and content for hard-coded .jpg / .png links (image blocks, custom HTML, CSS, or shortcodes) so nothing breaks.', 'squeeze' );
154 ?></p>
155 </div>
156 </div>
157 <?php
158 }
159 ?>
160
161 <div class="squeeze-bulk-media-stats squeeze-bulk-media-stats--linear" style="--squeeze-progress-pct: <?php
162 echo esc_attr( $compressed_percentage );
163 ?>;">
164 <div class="squeeze-bulk-media-stats-linear-head">
165 <div class="squeeze-bulk-media-stats-chart-value squeeze-bulk-media-stats-chart-value--linear">
166 <span class="squeeze-bulk-media-stats-chart-pct"><?php
167 echo esc_html( $compressed_percentage );
168 ?>%</span>
169 <span class="squeeze-bulk-media-stats-chart-pct-label"><?php
170 esc_html_e( 'complete', 'squeeze' );
171 ?></span>
172 </div>
173 <div class="squeeze-bulk-media-stats-item squeeze-bulk-media-stats-item--inline">
174 <span class="squeeze-bulk-media-stats-item-label"><?php
175 esc_html_e( 'Squeezed images', 'squeeze' );
176 ?></span>
177 <span class="squeeze-bulk-media-stats-item-value"><?php
178 echo esc_html( $compressed_count );
179 ?> / <?php
180 echo esc_html( $total_count );
181 ?></span>
182 </div>
183 </div>
184 <div class="squeeze-bulk-media-stats-chart squeeze-bulk-media-stats-chart--linear" aria-hidden="true">
185 <div class="squeeze-bulk-media-stats-chart-track">
186 <div class="squeeze-bulk-media-stats-chart-fill"></div>
187 </div>
188 </div>
189 <div class="squeeze-bulk-media-stats-legend">
190 <span class="squeeze-bulk-media-stats-legend-item">
191 <span class="squeeze-bulk-media-stats-legend-swatch squeeze-bulk-media-stats-legend-swatch--done" aria-hidden="true"></span>
192 <?php
193 esc_html_e( 'Processed (success)', 'squeeze' );
194 ?>
195 </span>
196 <span class="squeeze-bulk-media-stats-legend-item">
197 <span class="squeeze-bulk-media-stats-legend-swatch squeeze-bulk-media-stats-legend-swatch--rest" aria-hidden="true"></span>
198 <?php
199 esc_html_e( 'Remaining or needs attention', 'squeeze' );
200 ?>
201 </span>
202 </div>
203 </div>
204 </div>
205 <div id="squeeze-bulk-paused-banner" class="squeeze-banner squeeze-banner--notice squeeze-bulk-paused-banner" hidden aria-live="polite">
206 <svg class="squeeze-icon" aria-hidden="true">
207 <use xlink:href="#pause-button-icon"></use>
208 </svg>
209 <div class="squeeze-banner__content">
210 <p class="squeeze-banner__title"><?php
211 esc_html_e( 'Bulk squeezing paused', 'squeeze' );
212 ?></p>
213 <p id="squeeze-bulk-paused-banner-text"></p>
214 </div>
215 </div>
216 <div class="squeeze-bulk-section__actions squeeze-bulk-media-actions">
217 <div class="squeeze-bulk-media-actions__item">
218 <button name="squeeze_bulk" class="button button-primary button-hero" type="button" title="<?php
219 esc_attr_e( 'Compress only images that have not been squeezed yet. Click again while running to pause.', 'squeeze' );
220 ?>" <?php
221 echo ( $uncompressed_count === 0 ? 'hidden disabled data-default-hidden="true"' : '' );
222 ?>>
223 <svg class="squeeze-icon" aria-hidden="true">
224 <use xlink:href="#play-button-round-icon"></use>
225 </svg>
226 <?php
227 esc_html_e( 'Squeeze new images', 'squeeze' );
228 ?>
229 </button>
230 <p class="squeeze-bulk-field-hint squeeze-bulk-field-hint--tight"><?php
231 esc_html_e( 'Compress only images that have not been squeezed yet. Click again while running to pause.', 'squeeze' );
232 ?></p>
233 </div>
234 <div class="squeeze-bulk-media-actions__item">
235 <button name="squeeze_bulk_again" class="button button-secondary button-large" type="button" title="<?php
236 esc_attr_e( 'Run compression again on every library image, including ones already squeezed. Use after changing quality or WebP settings.', 'squeeze' );
237 ?>">
238 <svg class="squeeze-icon" aria-hidden="true">
239 <use xlink:href="#repeat-icon"></use>
240 </svg>
241 <?php
242 esc_html_e( 'Re-squeeze all images', 'squeeze' );
243 ?>
244 </button>
245 <p class="squeeze-bulk-field-hint squeeze-bulk-field-hint--tight"><?php
246 esc_html_e( 'Run compression again on every library image, including ones already squeezed. Use after changing quality or WebP settings.', 'squeeze' );
247 ?></p>
248 </div>
249 </div>
250 </section>
251
252 <section id="squeeze-bulk-section-directory" class="squeeze-bulk-section squeeze-bulk-section--directory" aria-labelledby="squeeze-heading-directory">
253 <header class="squeeze-bulk-section__head">
254 <h2 id="squeeze-heading-directory"><?php
255 esc_html_e( 'Directory Squeeze', 'squeeze' );
256 ?></h2>
257 <p class="squeeze-bulk-section__meta"><?php
258 esc_html_e( 'Filesystem folder — not limited to Media Library. No automatic backup in this mode.', 'squeeze' );
259 ?></p>
260 </header>
261 <div class="squeeze-bulk-section__body">
262 <div class="squeeze-banner squeeze-banner--warning">
263 <svg class="squeeze-icon" aria-hidden="true">
264 <use xlink:href="#info-icon"></use>
265 </svg>
266 <div class="squeeze-banner__content">
267 <p class="squeeze-banner__title"><?php
268 esc_html_e( 'Back up before you run', 'squeeze' );
269 ?></p>
270 <p><?php
271 esc_html_e( 'Automatic backup from the plugin is not available here. Manually back up the folder or your site before squeezing.', 'squeeze' );
272 ?></p>
273 <ul>
274 <li><?php
275 esc_html_e( 'Use your host snapshot or a backup plugin.', 'squeeze' );
276 ?></li>
277 <li><?php
278 esc_html_e( 'Test on a copy first if you are unsure.', 'squeeze' );
279 ?></li>
280 </ul>
281 </div>
282 </div>
283
284 <input type="hidden" name="squeeze_bulk_path" value="<?php
285 echo esc_attr( $directory_path_json );
286 ?>" />
287
288 <div class="squeeze-bulk-field">
289 <label class="squeeze-bulk-field-label"><?php
290 esc_html_e( 'Directory path', 'squeeze' );
291 ?></label>
292 <p id="squeeze-directory-path-hint" class="squeeze-bulk-field-hint"><?php
293 esc_html_e( 'Relative to site root.', 'squeeze' );
294 ?></p>
295 <div class="squeeze-path-list" aria-describedby="squeeze-directory-path-hint">
296 <?php
297 $squeeze_bulk_path_count = count( $directory_path );
298 foreach ( $directory_path as $path ) {
299 ?>
300 <div class="squeeze-path-list__item">
301 <input name="squeeze-path-list__item[]" type="text" class="squeeze-path-list__input" value="<?php
302 echo esc_attr( $path );
303 ?>" readonly />
304 <?php
305 if ( $squeeze_bulk_path_count > 1 ) {
306 ?>
307 <button name="squeeze_remove_path_button" class="squeeze-path-list__remove button" type="button" title="<?php
308 esc_attr_e( 'Clear the path field', 'squeeze' );
309 ?>">
310 <?php
311 esc_html_e( 'Clear path', 'squeeze' );
312 ?>
313 </button>
314 <?php
315 }
316 ?>
317 </div>
318 <?php
319 }
320 ?>
321 </div>
322 <p class="squeeze-bulk-field-hint squeeze-bulk-field-hint--tight"><?php
323 esc_html_e( 'Clear path only empties the field — it does not delete files on disk.', 'squeeze' );
324 ?></p>
325 </div>
326
327 <div class="squeeze-bulk-section__secondary-actions">
328 <button name="squeeze_select_path_button" class="button button-secondary button-large" type="button">
329 <svg class="squeeze-icon" aria-hidden="true">
330 <use xlink:href="#open-folder-outline-icon"></use>
331 </svg>
332 <?php
333 esc_attr_e( 'Select Directory', 'squeeze' );
334 ?>
335 </button>
336 </div>
337 <dialog id="squeeze-path-dialog">
338 <div class="squeeze-box-header">
339 <h2><?php
340 esc_html_e( "Select Directory for Squeeze", "squeeze" );
341 ?></h2>
342 <button name="squeeze_close_path_dialog_button" class="button button-link" type="button">
343 <svg class="squeeze-icon" aria-hidden="true">
344 <use xlink:href="#close-round-icon"></use>
345 </svg>
346 </button>
347 </div>
348
349 <div id="squeeze-bulk-directory-list">
350 <svg class="squeeze-icon" aria-hidden="true">
351 <use xlink:href="#reload-sync-icon"></use>
352 </svg>
353 <?php
354 esc_html_e( "Loading directories...", "squeeze" );
355 ?>
356 </div>
357
358 <div class="squeeze-box-footer">
359 <button disabled name="squeeze_save_path_button" class="button button-secondary button-large" type="button">
360 <svg class="squeeze-icon" aria-hidden="true">
361 <use xlink:href="#open-folder-outline-icon"></use>
362 </svg>
363 <?php
364 esc_attr_e( 'Select Directory', 'squeeze' );
365 ?>
366 </button>
367 </div>
368 </dialog>
369 </div>
370 <div class="squeeze-bulk-section__actions squeeze-bulk-media-actions">
371 <button name="squeeze_bulk_path_button" class="button button-primary button-hero" type="button">
372 <svg class="squeeze-icon" aria-hidden="true">
373 <use xlink:href="#play-button-round-icon"></use>
374 </svg>
375 <?php
376 esc_attr_e( 'Run Directory Squeeze', 'squeeze' );
377 ?>
378 </button>
379 </div>
380 </section>
381 </div>
382 <?php
383 }
384 ?>
385
386 <?php
387 ?>
388
389
390 <div class="squeeze-box-bulk-stack__footer">
391 <div class="squeeze-box-content">
392 <p class="squeeze-hint">
393 <?php
394 $images_formats = self::$SqueezeHelpers->get_image_formats();
395 $images_formats = implode( ', ', $images_formats );
396 esc_html_e( 'Processed formats:', 'squeeze' );
397 echo esc_html( '&nbsp;' . $images_formats . '. ' );
398 printf( __( 'You can change the image formats for squeezing on the <a href="%s" target="_blank">settings page.</a>', 'squeeze' ), esc_url( admin_url( 'options-general.php?page=squeeze' ) ) );
399 ?>
400 </p>
401 </div>
402 </div>
403
404 </div>
405 </section>
406 <section class="squeeze-box" name="squeeze_bulk_log" id="squeeze_bulk_log" contenteditable="false">
407 <div class="squeeze-log-placeholder">
408 <?php
409 esc_html_e( 'Start Squeezing your images and watch the progress here.', 'squeeze' );
410 ?>
411 </div>
412 <div id="squeeze-log-data"></div>
413 <div id="squeeze-anchor"></div><!-- to force scroll to the bottom -->
414 <input type="hidden" value="<?php
415 echo wp_kses_data( $not_compressed_posts );
416 ?>" name="squeeze_bulk_ids" />
417 <input type="hidden" value="<?php
418 echo wp_kses_data( $all_posts );
419 ?>" name="squeeze_bulk_all_ids" />
420 <input type="hidden" value="<?php
421 echo wp_kses_data( $total_pages );
422 ?>" name="squeeze_bulk_total_pages" />
423 <input type="hidden" value="<?php
424 echo wp_kses_data( $uncompressed_pages );
425 ?>" name="squeeze_bulk_uncompressed_pages" />
426 <input type="hidden" value="<?php
427 echo wp_kses_data( $total_count );
428 ?>" name="squeeze_bulk_total_images" />
429 <input type="hidden" value="<?php
430 echo wp_kses_data( $uncompressed_count );
431 ?>" name="squeeze_bulk_uncompressed_images" />
432 </section>
433 </div>
434 <?php
435 }
436
437 public function options_page_html() {
438 // check user capabilities
439 if ( !current_user_can( 'manage_options' ) ) {
440 return;
441 }
442 $modules = self::$SqueezeHelpers->apache_get_modules();
443 if ( !is_array( $modules ) || !in_array( 'mod_rewrite', $modules ) ) {
444 $is_auto_webp = self::$SqueezeHelpers->get_option( 'auto_webp' );
445 $is_webp_replace_urls = self::$SqueezeHelpers->get_option( 'webp_replace_urls' );
446 if ( $is_auto_webp && !$is_webp_replace_urls ) {
447 add_settings_error(
448 'squeeze_notices',
449 'squeeze_notices',
450 __( 'The Apache mod_rewrite module is not enabled on your server OR your server is not running Apache.', 'squeeze' ) . '<br>' . __( 'To serve WebP, enable mod_rewrite, or switch to "Rewrite <img> src to WebP URLs in HTML" delivery.', 'squeeze' ),
451 'warning'
452 );
453 }
454 }
455 ?>
456 <div class="wrap">
457 <h1>
458 <?php
459 echo esc_html( get_admin_page_title() );
460 ?>
461 </h1>
462 <nav class="nav-tab-wrapper">
463 <a href="#squeeze_basic" class="nav-tab nav-tab-active"><?php
464 esc_html_e( 'Basic Settings', 'squeeze' );
465 ?></a>
466 <a href="#squeeze_jpeg" class="nav-tab"><?php
467 esc_html_e( 'JPEG Settings', 'squeeze' );
468 ?></a>
469 <a href="#squeeze_png" class="nav-tab"><?php
470 esc_html_e( 'PNG Settings', 'squeeze' );
471 ?></a>
472 <a href="#squeeze_webp" class="nav-tab"><?php
473 esc_html_e( 'WEBP Settings', 'squeeze' );
474 ?></a>
475 <a href="#squeeze_avif" class="nav-tab"><?php
476 esc_html_e( 'AVIF Settings', 'squeeze' );
477 ?></a>
478 <a href="#squeeze_docs" class="nav-tab"><?php
479 esc_html_e( 'Documentation', 'squeeze' );
480 ?></a>
481 <?php
482 ?>
483 <a href="#squeeze_upgrade" class="nav-tab"><?php
484 esc_html_e( 'Upgrade', 'squeeze' );
485 ?></a>
486 <?php
487 ?>
488 <?php
489 ?>
490 </nav>
491 <div class="tab-content">
492 <form action="options.php" method="post" class="squeeze-settings-form">
493 <?php
494 settings_errors( 'squeeze_notices' );
495 settings_fields( 'squeeze_options' );
496 //do_settings_sections( 'squeeze_options' );
497 ?>
498
499 <section id="squeeze_basic" class="squeeze-settings-basic">
500 <div class="squeeze-settings-layout">
501 <div class="squeeze-settings-main">
502 <div class="squeeze-card squeeze-card--settings">
503 <div class="squeeze-card-header">
504 <h2 class="squeeze-card-title"><?php
505 esc_html_e( 'Quick start', 'squeeze' );
506 ?></h2>
507 <p class="squeeze-card-desc"><?php
508 esc_html_e( 'Core options used on most sites.', 'squeeze' );
509 ?></p>
510 </div>
511 <table class="form-table squeeze-form-table--card" role="presentation">
512 <?php
513 do_settings_fields( 'squeeze_options', 'squeeze_basic_quick' );
514 ?>
515 </table>
516 </div>
517 <div class="squeeze-card squeeze-card--settings">
518 <div class="squeeze-card-header">
519 <h2 class="squeeze-card-title"><?php
520 esc_html_e( 'WebP delivery', 'squeeze' );
521 ?></h2>
522 <p class="squeeze-card-desc"><?php
523 esc_html_e( 'Choose how WebP files are stored and served. Pick one strategy.', 'squeeze' );
524 ?></p>
525 </div>
526 <div class="squeeze-webp-delivery-fullwidth" role="group" aria-label="<?php
527 esc_attr_e( 'WebP delivery mode', 'squeeze' );
528 ?>">
529 <?php
530 $this->render_webp_delivery_field();
531 ?>
532 </div>
533 <?php
534 ?>
535 </div>
536 <div class="squeeze-card squeeze-card--settings">
537 <div class="squeeze-card-header">
538 <h2 class="squeeze-card-title"><?php
539 esc_html_e( 'Thumbnails & limits', 'squeeze' );
540 ?></h2>
541 <p class="squeeze-card-desc"><?php
542 esc_html_e( 'Which generated sizes to squeeze, resize limits, and timeout.', 'squeeze' );
543 ?></p>
544 </div>
545 <table class="form-table squeeze-form-table--card" role="presentation">
546 <?php
547 do_settings_fields( 'squeeze_options', 'squeeze_basic_thumbs' );
548 ?>
549 <?php
550 do_settings_fields( 'squeeze_options', 'squeeze_basic_limits' );
551 ?>
552 </table>
553 </div>
554 <div class="squeeze-card squeeze-card--settings">
555 <div class="squeeze-card-header">
556 <h2 class="squeeze-card-title"><?php
557 esc_html_e( 'Exclusions', 'squeeze' );
558 ?></h2>
559 <p class="squeeze-card-desc"><?php
560 esc_html_e( 'Skip matching files during bulk or upload squeeze.', 'squeeze' );
561 ?></p>
562 </div>
563 <table class="form-table squeeze-form-table--card" role="presentation">
564 <?php
565 do_settings_fields( 'squeeze_options', 'squeeze_basic_exclusions' );
566 ?>
567 </table>
568 </div>
569 <table class="form-table squeeze-form-table--hidden" role="presentation" aria-hidden="true">
570 <?php
571 do_settings_fields( 'squeeze_options', 'squeeze_basic_hidden' );
572 ?>
573 </table>
574 </div>
575 <aside class="squeeze-settings-sidebar" aria-label="<?php
576 esc_attr_e( 'Summary and help', 'squeeze' );
577 ?>">
578 <?php
579 $this->render_basic_settings_sidebar();
580 ?>
581 </aside>
582 </div>
583 </section>
584 <section id="squeeze_jpeg">
585 <div class="squeeze-box squeeze-box--settings">
586 <div class="squeeze-box-header">
587 <div class="squeeze-box-header__col">
588 <h2><?php
589 esc_html_e( 'JPEG Settings', 'squeeze' );
590 ?></h2>
591 <?php
592 $this->setting_jpeg_desc();
593 ?>
594 </div>
595 </div>
596 <table class="form-table" role="presentation">
597 <?php
598 do_settings_fields( 'squeeze_options', 'squeeze_jpeg_settings' );
599 ?>
600 </table>
601 </div>
602 <div class="squeeze-box">
603 <div class="squeeze-box-header">
604 <div class="squeeze-box-header__col">
605 <h2><?php
606 esc_html_e( 'JPEG Advanced Settings', 'squeeze' );
607 ?></h2>
608 <?php
609 $this->setting_jpeg_advanced_desc();
610 ?>
611 </div>
612 </div>
613 <table class="form-table" role="presentation">
614 <?php
615 do_settings_fields( 'squeeze_options', 'squeeze_jpeg_advanced_settings' );
616 ?>
617 </table>
618 </div>
619 </section>
620 <section id="squeeze_png">
621 <div class="squeeze-box squeeze-box--settings">
622 <div class="squeeze-box-header">
623 <div class="squeeze-box-header__col">
624 <h2><?php
625 esc_html_e( 'PNG Settings', 'squeeze' );
626 ?></h2>
627 <?php
628 $this->setting_png_desc();
629 ?>
630 </div>
631 </div>
632 <table class="form-table" role="presentation">
633 <?php
634 do_settings_fields( 'squeeze_options', 'squeeze_png_settings' );
635 ?>
636 </table>
637 </div>
638 </section>
639 <section id="squeeze_webp">
640 <div class="squeeze-box squeeze-box--settings">
641 <div class="squeeze-box-header">
642 <div class="squeeze-box-header__col">
643 <h2><?php
644 esc_html_e( 'WEBP Settings', 'squeeze' );
645 ?></h2>
646 <?php
647 $this->setting_webp_desc();
648 ?>
649 </div>
650 </div>
651 <table class="form-table" role="presentation">
652 <?php
653 do_settings_fields( 'squeeze_options', 'squeeze_webp_settings' );
654 ?>
655 </table>
656 </div>
657 </section>
658 <section id="squeeze_avif">
659 <div class="squeeze-box squeeze-box--settings">
660 <div class="squeeze-box-header">
661 <div class="squeeze-box-header__col">
662 <h2><?php
663 esc_html_e( 'AVIF Settings', 'squeeze' );
664 ?></h2>
665 <?php
666 $this->setting_avif_desc();
667 ?>
668 </div>
669 </div>
670 <table class="form-table" role="presentation">
671 <?php
672 do_settings_fields( 'squeeze_options', 'squeeze_avif_settings' );
673 ?>
674 </table>
675 </div>
676 </section>
677 <section id="squeeze_docs">
678 <div class="squeeze-box squeeze-box--settings">
679 <div class="squeeze-box-header">
680 <div class="squeeze-box-header__col">
681 <h2><?php
682 esc_html_e( 'Documentation', 'squeeze' );
683 ?></h2>
684 <?php
685 echo '<p>' . esc_html__( 'Documentation for Squeeze plugin.', 'squeeze' ) . '</p>';
686 ?>
687 </div>
688 </div>
689 <table class="form-table" role="presentation">
690 <tbody>
691 <tr>
692 <th scope="row" colspan="2">
693 <?php
694 echo '<p>' . sprintf( __( 'For more information, please visit the <a href="%s" target="_blank">official documentation website</a>.', 'squeeze' ) . '&nbsp;↗', esc_url( self::$DOCS_URL ) ) . '</p>';
695 ?>
696 </th>
697 </tr>
698 </tbody>
699 </table>
700 </div>
701 </section>
702 <?php
703 ?>
704 <section id="squeeze_upgrade">
705 <div class="squeeze-box squeeze-box--settings">
706 <div class="squeeze-box-header">
707 <div class="squeeze-box-header__col">
708 <h2><?php
709 esc_html_e( 'Upgrade', 'squeeze' );
710 ?></h2>
711 <?php
712 $this->setting_upgrade_desc();
713 ?>
714 </div>
715 </div>
716 <div class="squeeze-upgrade-features">
717 <?php
718 $features = [['icon-compare.svg', __( 'Image Comparison', 'squeeze' ), __( 'Compare original and Squeezed image directly in the Media Library.', 'squeeze' )], ['icon-resize.svg', __( 'Resize Original Image', 'squeeze' ), __( 'Set maximum width and height for the original image.', 'squeeze' )], ['icon-bulk-page.svg', __( 'Bulk Squeeze from a Page', 'squeeze' ), __( 'Compress all images from a specific page.', 'squeeze' )]];
719 foreach ( $features as $feature ) {
720 ?>
721 <div class="squeeze-box--fieldset">
722 <img src="<?php
723 echo esc_url( self::$PLUGIN_URL . 'assets/images/' . $feature[0] );
724 ?>" alt="<?php
725 echo esc_attr( $feature[1] );
726 ?>" />
727 <h3><?php
728 echo esc_html( $feature[1] );
729 ?></h3>
730 <p><?php
731 echo esc_html( $feature[2] );
732 ?></p>
733 </div>
734 <?php
735 }
736 ?>
737 </div>
738 <div class="squeeze-box-footer">
739 <h3 style="text-align: center;">
740 <?php
741 echo sprintf( __( 'To upgrade to the Premium version, <a href="%s" target="_blank">click here</a>.', 'squeeze' ), esc_url( self::CHECKOUT_URL ) );
742 ?>&nbsp;
743 </h3>
744 </div>
745 </div>
746 </section>
747 <?php
748 ?>
749
750 <?php
751 ?>
752
753 <p class="submit squeeze-settings-submit">
754 <input type="submit" name="submit" id="submit" class="button button-primary" value="<?php
755 esc_attr_e( 'Save Changes', 'squeeze' );
756 ?>">
757 <input name="squeeze_restore_button" class="button button-secondary" type="button" value="<?php
758 esc_attr_e( 'Restore defaults', 'squeeze' );
759 ?>" />
760 </p>
761 </form>
762 </div>
763 </div>
764 <?php
765 }
766
767 public function register_settings() {
768 $auto_webp = self::$SqueezeHelpers->get_option( 'auto_webp' );
769 $webp_lossless = self::$SqueezeHelpers->get_option( 'webp_lossless' );
770 register_setting( 'squeeze_options', 'squeeze_options', [$this, 'options_validate'] );
771 add_settings_section(
772 'squeeze_basic_quick',
773 '',
774 '__return_false',
775 'squeeze_options'
776 );
777 add_settings_field(
778 'squeeze_setting_auto_compress',
779 __( 'Squeeze on upload', 'squeeze' ),
780 [$this, 'options_callback'],
781 'squeeze_options',
782 'squeeze_basic_quick',
783 array(
784 'label_for' => 'auto_compress',
785 'class' => 'squeeze_setting_auto_compress squeeze-settings-row',
786 'type' => 'checkbox',
787 )
788 );
789 add_settings_field(
790 'squeeze_setting_backup_original',
791 __( 'Backup original image', 'squeeze' ),
792 [$this, 'options_callback'],
793 'squeeze_options',
794 'squeeze_basic_quick',
795 array(
796 'label_for' => 'backup_original',
797 'class' => 'squeeze_setting_backup_original squeeze-settings-row',
798 'type' => 'checkbox',
799 )
800 );
801 add_settings_field(
802 'squeeze_setting_clear_data_on_uninstall',
803 __( 'Delete plugin data on uninstall', 'squeeze' ) . self::$SqueezeHelpers->get_hint( __( 'When enabled, uninstalling Squeeze removes its settings, stats, and compression status metadata. Image files are never deleted.', 'squeeze' ) ),
804 [$this, 'options_callback'],
805 'squeeze_options',
806 'squeeze_basic_quick',
807 array(
808 'label_for' => 'clear_data_on_uninstall',
809 'class' => 'squeeze_setting_clear_data_on_uninstall squeeze-settings-row',
810 'type' => 'checkbox',
811 )
812 );
813 add_settings_field(
814 'squeeze_setting_compress_formats',
815 __( 'Image formats', 'squeeze' ) . self::$SqueezeHelpers->get_hint( __( 'Select which image formats you want to be squeezed.', 'squeeze' ) ),
816 [$this, 'options_callback'],
817 'squeeze_options',
818 'squeeze_basic_quick',
819 array(
820 'label_for' => 'compress_formats',
821 'class' => 'squeeze_setting_compress_formats squeeze-settings-row',
822 'type' => 'formats_checkbox_group',
823 )
824 );
825 add_settings_section(
826 'squeeze_basic_webp',
827 '',
828 '__return_false',
829 'squeeze_options'
830 );
831 add_settings_section(
832 'squeeze_basic_thumbs',
833 '',
834 '__return_false',
835 'squeeze_options'
836 );
837 add_settings_field(
838 'squeeze_setting_compress_thumbs',
839 __( 'Squeeze thumbnails', 'squeeze' ) . self::$SqueezeHelpers->get_hint( __( 'Choose which image thumbnail sizes you want to squeeze along with the original image.', 'squeeze' ) ),
840 [$this, 'options_callback'],
841 'squeeze_options',
842 'squeeze_basic_thumbs',
843 array(
844 'label_for' => 'compress_thumbs',
845 'class' => 'squeeze_setting_compress_thumbs squeeze-settings-row',
846 'type' => 'thumbs_checkbox_group',
847 )
848 );
849 add_settings_section(
850 'squeeze_basic_limits',
851 '',
852 '__return_false',
853 'squeeze_options'
854 );
855 add_settings_field(
856 'squeeze_setting_max_width',
857 __( 'Max. image width', 'squeeze' ) . self::$SqueezeHelpers->get_hint( __( 'Limit a width of an original image. Leave this field empty if you do not want to crop the image by width.', 'squeeze' ) ),
858 [$this, 'options_callback'],
859 'squeeze_options',
860 'squeeze_basic_limits',
861 array(
862 'label_for' => 'max_width',
863 'class' => 'squeeze_setting_max_width squeeze-settings-row',
864 'type' => 'placeholder',
865 )
866 );
867 add_settings_field(
868 'squeeze_setting_max_height',
869 __( 'Max. image height', 'squeeze' ) . self::$SqueezeHelpers->get_hint( __( 'Limit a height of an original image. Leave this field empty if you do not want to crop the image by height.', 'squeeze' ) ),
870 [$this, 'options_callback'],
871 'squeeze_options',
872 'squeeze_basic_limits',
873 array(
874 'label_for' => 'max_height',
875 'class' => 'squeeze_setting_max_height squeeze-settings-row',
876 'type' => 'placeholder',
877 )
878 );
879 add_settings_field(
880 'squeeze_setting_timeout',
881 __( 'Squeeze timeout', 'squeeze' ) . self::$SqueezeHelpers->get_hint( __( 'Time limit for squeezing an image. If you get an error during image squeezing, try to increase this value.', 'squeeze' ) ),
882 [$this, 'options_callback'],
883 'squeeze_options',
884 'squeeze_basic_limits',
885 array(
886 'label_for' => 'timeout',
887 'class' => 'squeeze_setting_timeout squeeze-settings-row squeeze-inline-limit',
888 'type' => 'number',
889 'units' => 'sec',
890 'min' => 1,
891 )
892 );
893 add_settings_section(
894 'squeeze_basic_exclusions',
895 '',
896 '__return_false',
897 'squeeze_options'
898 );
899 add_settings_field(
900 'squeeze_setting_excluded_images',
901 __( 'Excluded images', 'squeeze' ) . self::$SqueezeHelpers->get_hint( __( 'Enter a list of images that you want to exclude from squeezing. Both full URLs and partial strings can be used. One URL per line.', 'squeeze' ) ),
902 [$this, 'options_callback'],
903 'squeeze_options',
904 'squeeze_basic_exclusions',
905 array(
906 'label_for' => 'excluded_images',
907 'class' => 'squeeze_setting_excluded_images squeeze-settings-row',
908 'type' => 'textarea',
909 )
910 );
911 add_settings_section(
912 'squeeze_basic_hidden',
913 '',
914 '__return_false',
915 'squeeze_options'
916 );
917 add_settings_field(
918 'squeeze_setting_restore_defaults',
919 '',
920 [$this, 'options_callback'],
921 'squeeze_options',
922 'squeeze_basic_hidden',
923 array(
924 'label_for' => 'restore_defaults',
925 'class' => 'squeeze_setting_restore_defaults',
926 'type' => 'hidden',
927 )
928 );
929 add_settings_section(
930 'squeeze_jpeg_settings',
931 __( 'JPEG Settings', 'squeeze' ),
932 'squeeze_setting_jpeg_desc',
933 'squeeze_options',
934 array(
935 'section_class' => 'squeeze_jpeg',
936 )
937 );
938 add_settings_field(
939 'squeeze_setting_jpeg_quality',
940 __( 'Quality', 'squeeze' ),
941 [$this, 'options_callback'],
942 'squeeze_options',
943 'squeeze_jpeg_settings',
944 array(
945 'label_for' => 'jpeg_quality',
946 'class' => 'squeeze_setting_jpeg_quality',
947 'type' => 'range',
948 )
949 );
950 add_settings_field(
951 'squeeze_setting_jpeg_smoothing',
952 __( 'Smoothing', 'squeeze' ),
953 [$this, 'options_callback'],
954 'squeeze_options',
955 'squeeze_jpeg_settings',
956 array(
957 'label_for' => 'jpeg_smoothing',
958 'class' => 'squeeze_setting_jpeg_smoothing',
959 'type' => 'range',
960 )
961 );
962 add_settings_field(
963 'squeeze_setting_jpeg_baseline',
964 __( 'Pointless spec compliance', 'squeeze' ),
965 [$this, 'options_callback'],
966 'squeeze_options',
967 'squeeze_jpeg_advanced_settings',
968 array(
969 'label_for' => 'jpeg_baseline',
970 'class' => 'squeeze_setting_jpeg_baseline',
971 'type' => 'checkbox',
972 )
973 );
974 // deactivated, because throws error when enabled
975 //add_settings_field('squeeze_setting_jpeg_arithmetic', __('Arithmetic', 'squeeze'), [$this, 'options_callback'], 'squeeze_options', 'squeeze_jpeg_advanced_settings', array('label_for' => 'jpeg_arithmetic', 'class' => 'squeeze_setting_jpeg_arithmetic', 'type' => 'checkbox'));
976 add_settings_field(
977 'squeeze_setting_jpeg_progressive',
978 __( 'Progressive rendering', 'squeeze' ),
979 [$this, 'options_callback'],
980 'squeeze_options',
981 'squeeze_jpeg_advanced_settings',
982 array(
983 'label_for' => 'jpeg_progressive',
984 'class' => 'squeeze_setting_jpeg_progressive',
985 'type' => 'checkbox',
986 )
987 );
988 add_settings_field(
989 'squeeze_setting_jpeg_optimize_coding',
990 __( 'Optimize Huffman table', 'squeeze' ),
991 [$this, 'options_callback'],
992 'squeeze_options',
993 'squeeze_jpeg_advanced_settings',
994 array(
995 'label_for' => 'jpeg_optimize_coding',
996 'class' => 'squeeze_setting_jpeg_optimize_coding',
997 'type' => 'checkbox',
998 )
999 );
1000 add_settings_field(
1001 'squeeze_setting_jpeg_color_space',
1002 __( 'Channels', 'squeeze' ),
1003 [$this, 'options_callback'],
1004 'squeeze_options',
1005 'squeeze_jpeg_advanced_settings',
1006 array(
1007 'label_for' => 'jpeg_color_space',
1008 'class' => 'squeeze_setting_jpeg_color_space',
1009 'type' => 'select',
1010 'options' => array(
1011 '3' => 'YCbCr',
1012 '1' => 'Grayscale',
1013 '2' => 'RGB',
1014 ),
1015 )
1016 );
1017 add_settings_field(
1018 'squeeze_setting_jpeg_quant_table',
1019 __( 'Quantization', 'squeeze' ),
1020 [$this, 'options_callback'],
1021 'squeeze_options',
1022 'squeeze_jpeg_advanced_settings',
1023 array(
1024 'label_for' => 'jpeg_quant_table',
1025 'class' => 'squeeze_setting_jpeg_quant_table',
1026 'type' => 'select',
1027 'options' => array(
1028 '0' => 'JPEG Annex K',
1029 '1' => 'Flat',
1030 '2' => 'MSSIM-tuned Kodak',
1031 '3' => 'ImageMagick',
1032 '4' => 'PSNR-HVS-M-tuned Kodak',
1033 '5' => 'Klein et al',
1034 '6' => 'Watson et al',
1035 '7' => 'Ahumada et al',
1036 '8' => 'Peterson et al',
1037 ),
1038 )
1039 );
1040 add_settings_field(
1041 'squeeze_setting_jpeg_trellis_multipass',
1042 __( 'Trellis multipass', 'squeeze' ),
1043 [$this, 'options_callback'],
1044 'squeeze_options',
1045 'squeeze_jpeg_advanced_settings',
1046 array(
1047 'label_for' => 'jpeg_trellis_multipass',
1048 'class' => 'squeeze_setting_jpeg_trellis_multipass',
1049 'type' => 'checkbox',
1050 )
1051 );
1052 add_settings_field(
1053 'squeeze_setting_jpeg_trellis_opt_zero',
1054 __( 'Optimize zero block runs', 'squeeze' ),
1055 [$this, 'options_callback'],
1056 'squeeze_options',
1057 'squeeze_jpeg_advanced_settings',
1058 array(
1059 'label_for' => 'jpeg_trellis_opt_zero',
1060 'class' => 'squeeze_setting_jpeg_trellis_opt_zero',
1061 'type' => 'checkbox',
1062 )
1063 );
1064 add_settings_field(
1065 'squeeze_setting_jpeg_trellis_opt_table',
1066 __( 'Optimize after trellis quantization', 'squeeze' ),
1067 [$this, 'options_callback'],
1068 'squeeze_options',
1069 'squeeze_jpeg_advanced_settings',
1070 array(
1071 'label_for' => 'jpeg_trellis_opt_table',
1072 'class' => 'squeeze_setting_jpeg_trellis_opt_table',
1073 'type' => 'checkbox',
1074 )
1075 );
1076 add_settings_field(
1077 'squeeze_setting_jpeg_trellis_loops',
1078 __( 'Trellis quantization passes', 'squeeze' ),
1079 [$this, 'options_callback'],
1080 'squeeze_options',
1081 'squeeze_jpeg_advanced_settings',
1082 array(
1083 'label_for' => 'jpeg_trellis_loops',
1084 'class' => 'squeeze_setting_jpeg_trellis_loops',
1085 'type' => 'range',
1086 'min' => 1,
1087 'max' => 50,
1088 )
1089 );
1090 add_settings_field(
1091 'squeeze_setting_jpeg_auto_subsample',
1092 __( 'Auto subsample chroma', 'squeeze' ),
1093 [$this, 'options_callback'],
1094 'squeeze_options',
1095 'squeeze_jpeg_advanced_settings',
1096 array(
1097 'label_for' => 'jpeg_auto_subsample',
1098 'class' => 'squeeze_setting_jpeg_auto_subsample',
1099 'type' => 'checkbox',
1100 )
1101 );
1102 add_settings_field(
1103 'squeeze_setting_jpeg_chroma_subsample',
1104 __( 'Subsample chroma by', 'squeeze' ),
1105 [$this, 'options_callback'],
1106 'squeeze_options',
1107 'squeeze_jpeg_advanced_settings',
1108 array(
1109 'label_for' => 'jpeg_chroma_subsample',
1110 'class' => 'squeeze_setting_jpeg_chroma_subsample',
1111 'type' => 'range',
1112 'min' => 1,
1113 'max' => 4,
1114 )
1115 );
1116 add_settings_field(
1117 'squeeze_setting_jpeg_separate_chroma_quality',
1118 __( 'Separate chroma quality', 'squeeze' ),
1119 [$this, 'options_callback'],
1120 'squeeze_options',
1121 'squeeze_jpeg_advanced_settings',
1122 array(
1123 'label_for' => 'jpeg_separate_chroma_quality',
1124 'class' => 'squeeze_setting_jpeg_separate_chroma_quality',
1125 'type' => 'checkbox',
1126 )
1127 );
1128 add_settings_field(
1129 'squeeze_setting_jpeg_chroma_quality',
1130 __( 'Chroma quality', 'squeeze' ),
1131 [$this, 'options_callback'],
1132 'squeeze_options',
1133 'squeeze_jpeg_advanced_settings',
1134 array(
1135 'label_for' => 'jpeg_chroma_quality',
1136 'class' => 'squeeze_setting_jpeg_chroma_quality',
1137 'type' => 'range',
1138 )
1139 );
1140 add_settings_section(
1141 'squeeze_png_settings',
1142 __( 'PNG Settings', 'squeeze' ),
1143 'squeeze_setting_png_desc',
1144 'squeeze_options',
1145 array(
1146 'section_class' => 'squeeze_png',
1147 )
1148 );
1149 add_settings_field(
1150 'squeeze_setting_png_quality',
1151 __( 'Quality', 'squeeze' ),
1152 [$this, 'options_callback'],
1153 'squeeze_options',
1154 'squeeze_png_settings',
1155 array(
1156 'label_for' => 'png_quality',
1157 'class' => 'squeeze_setting_png_quality',
1158 'type' => 'range',
1159 'min' => 0.01,
1160 'max' => 1,
1161 'step' => 0.01,
1162 )
1163 );
1164 add_settings_section(
1165 'squeeze_webp_settings',
1166 __( 'WEBP Settings', 'squeeze' ),
1167 'squeeze_setting_webp_desc',
1168 'squeeze_options',
1169 array(
1170 'section_class' => 'squeeze_webp',
1171 )
1172 );
1173 add_settings_field(
1174 'squeeze_setting_webp_method',
1175 __( 'Effort', 'squeeze' ),
1176 [$this, 'options_callback'],
1177 'squeeze_options',
1178 'squeeze_webp_settings',
1179 array(
1180 'label_for' => 'webp_method',
1181 'class' => 'squeeze_setting_webp_method',
1182 'type' => 'range',
1183 'min' => 0,
1184 'max' => 6,
1185 )
1186 );
1187 add_settings_field(
1188 'squeeze_setting_webp_quality',
1189 __( 'Quality', 'squeeze' ),
1190 [$this, 'options_callback'],
1191 'squeeze_options',
1192 'squeeze_webp_settings',
1193 array(
1194 'label_for' => 'webp_quality',
1195 'class' => 'squeeze_setting_webp_quality',
1196 'type' => 'range',
1197 'min' => 0,
1198 'max' => 100,
1199 'hidden' => ( $webp_lossless ? true : '' ),
1200 )
1201 );
1202 add_settings_field(
1203 'squeeze_setting_webp_lossless',
1204 __( 'Lossless', 'squeeze' ),
1205 [$this, 'options_callback'],
1206 'squeeze_options',
1207 'squeeze_webp_settings',
1208 array(
1209 'label_for' => 'webp_lossless',
1210 'class' => 'squeeze_setting_webp_lossless',
1211 'type' => 'checkbox',
1212 )
1213 );
1214 add_settings_field(
1215 'squeeze_setting_webp_near_lossless',
1216 __( 'Near lossless', 'squeeze' ),
1217 [$this, 'options_callback'],
1218 'squeeze_options',
1219 'squeeze_webp_settings',
1220 array(
1221 'label_for' => 'webp_near_lossless',
1222 'class' => 'squeeze_setting_webp_near_lossless',
1223 'type' => 'range',
1224 'min' => 0,
1225 'max' => 100,
1226 )
1227 );
1228 add_settings_section(
1229 'squeeze_avif_settings',
1230 __( 'AVIF Settings', 'squeeze' ),
1231 'squeeze_setting_avif_desc',
1232 'squeeze_options',
1233 array(
1234 'section_class' => 'squeeze_avif',
1235 )
1236 );
1237 add_settings_field(
1238 'squeeze_setting_avif_cqLevel',
1239 __( 'Quality', 'squeeze' ),
1240 [$this, 'options_callback'],
1241 'squeeze_options',
1242 'squeeze_avif_settings',
1243 array(
1244 'label_for' => 'avif_cqLevel',
1245 'class' => 'squeeze_setting_avif_cqLevel',
1246 'type' => 'range',
1247 'min' => 1,
1248 'max' => 100,
1249 )
1250 );
1251 }
1252
1253 /**
1254 * Map stored options to a single WebP delivery mode for the settings UI.
1255 *
1256 * @param array $options squeeze_options array.
1257 * @return string direct|sidecar|sidecar_replace (internal keys; UI labels use "Separate WebP folder".)
1258 */
1259 protected function get_webp_delivery_mode( $options ) {
1260 $direct = !empty( $options['direct_webp'] );
1261 $auto = !empty( $options['auto_webp'] );
1262 $replace = !empty( $options['webp_replace_urls'] );
1263 if ( $direct ) {
1264 return 'direct';
1265 }
1266 if ( $auto && $replace ) {
1267 return 'sidecar_replace';
1268 }
1269 if ( $auto ) {
1270 return 'sidecar';
1271 }
1272 return 'direct';
1273 }
1274
1275 /**
1276 * Unified WebP delivery control (radios + collapsible examples).
1277 */
1278 public function render_webp_delivery_field() {
1279 $options = get_option( 'squeeze_options' );
1280 if ( !is_array( $options ) ) {
1281 $options = array();
1282 }
1283 $mode = $this->get_webp_delivery_mode( $options );
1284 $advanced_open = 'direct' !== $mode;
1285 ?>
1286 <div class="squeeze-webp-delivery-ui">
1287 <fieldset class="squeeze-webp-modes" role="radiogroup">
1288 <legend class="screen-reader-text"><?php
1289 esc_html_e( 'WebP delivery mode', 'squeeze' );
1290 ?></legend>
1291 <label class="squeeze-webp-mode-card<?php
1292 echo ( $mode === 'direct' ? ' is-selected' : '' );
1293 ?>">
1294 <input type="radio" class="squeeze-webp-mode-input" name="squeeze_options[webp_delivery_mode]" value="direct" <?php
1295 checked( $mode, 'direct' );
1296 ?> />
1297 <span class="squeeze-webp-mode-badge"><?php
1298 esc_html_e( 'Recommended', 'squeeze' );
1299 ?></span>
1300 <span class="squeeze-webp-mode-title"><?php
1301 esc_html_e( 'Direct WebP', 'squeeze' );
1302 ?></span>
1303 <span class="squeeze-webp-mode-desc"><?php
1304 esc_html_e( 'Replace originals with .webp on disk. Lowest storage; URLs change to .webp.', 'squeeze' );
1305 ?></span>
1306 </label>
1307 <details class="squeeze-webp-advanced"<?php
1308 echo ( $advanced_open ? ' open' : '' );
1309 ?>>
1310 <summary class="squeeze-webp-advanced-summary"><?php
1311 esc_html_e( 'Advanced delivery methods', 'squeeze' );
1312 ?></summary>
1313 <div class="squeeze-webp-advanced-body">
1314 <p class="squeeze-webp-advanced-intro"><?php
1315 esc_html_e( 'Keep JPEG/PNG originals and serve WebP via a separate folder. Prefer Direct WebP unless you have a specific hosting constraint.', 'squeeze' );
1316 ?></p>
1317 <div class="squeeze-webp-advanced-modes">
1318 <label class="squeeze-webp-mode-card<?php
1319 echo ( $mode === 'sidecar_replace' ? ' is-selected' : '' );
1320 ?>">
1321 <input type="radio" class="squeeze-webp-mode-input" name="squeeze_options[webp_delivery_mode]" value="sidecar_replace" <?php
1322 checked( $mode, 'sidecar_replace' );
1323 ?> />
1324 <span class="squeeze-webp-mode-badge"><?php
1325 esc_html_e( 'PHP / any host', 'squeeze' );
1326 ?></span>
1327 <span class="squeeze-webp-mode-title"><?php
1328 esc_html_e( 'Rewrite <img> src to WebP URLs in HTML', 'squeeze' );
1329 ?></span>
1330 <span class="squeeze-webp-mode-desc"><?php
1331 esc_html_e( 'Keeps JPEG/PNG in uploads and WebP copies under squeeze-webp. Squeeze changes src and srcset in the page HTML to the WebP path. Best when .htaccess rewrites are missing (Nginx, CDN, etc.).', 'squeeze' );
1332 ?></span>
1333 </label>
1334 <label class="squeeze-webp-mode-card<?php
1335 echo ( $mode === 'sidecar' ? ' is-selected' : '' );
1336 ?>">
1337 <input type="radio" class="squeeze-webp-mode-input" name="squeeze_options[webp_delivery_mode]" value="sidecar" <?php
1338 checked( $mode, 'sidecar' );
1339 ?> />
1340 <span class="squeeze-webp-mode-badge"><?php
1341 esc_html_e( 'Apache / .htaccess', 'squeeze' );
1342 ?></span>
1343 <span class="squeeze-webp-mode-title"><?php
1344 esc_html_e( 'Keep JPEG/PNG URLs — server serves WebP', 'squeeze' );
1345 ?></span>
1346 <span class="squeeze-webp-mode-desc"><?php
1347 esc_html_e( 'Keeps originals in uploads; WebP files go to squeeze-webp. Page HTML still shows .jpg/.png URLs. The server rewrite rules send WebP bytes when the browser supports it — no HTML changes.', 'squeeze' );
1348 ?></span>
1349 </label>
1350 </div>
1351 <?php
1352 if ( \Squeeze\SqueezeOffloadMedia::is_active() ) {
1353 ?>
1354 <div class="squeeze-notice squeeze-notice--warning squeeze-offload-htaccess-warning<?php
1355 echo ( $mode !== 'sidecar' ? ' squeeze-notice--hidden' : '' );
1356 ?>" role="alert">
1357 <span class="squeeze-notice-icon" aria-hidden="true">⚠️</span>
1358 <div class="squeeze-notice-body">
1359 <strong><?php
1360 esc_html_e( 'Not compatible with WP Offload Media', 'squeeze' );
1361 ?></strong>
1362 <p><?php
1363 esc_html_e( 'The "Keep JPEG/PNG URLs — server serves WebP" mode relies on Apache .htaccess rewrite rules that only work for requests reaching your origin server. When WP Offload Media is active, image URLs point to an external CDN (S3, GCS, DigitalOcean Spaces, etc.) and those requests never pass through your .htaccess — so WebP files will not be served.', 'squeeze' );
1364 ?></p>
1365 <p><?php
1366 echo wp_kses( __( 'Please switch to <strong>Direct WebP</strong> conversion — it converts images to WebP in-place and WP Offload Media handles uploading automatically.', 'squeeze' ), array(
1367 'strong' => array(),
1368 ) );
1369 ?></p>
1370 </div>
1371 </div>
1372 <div class="squeeze-notice squeeze-notice--warning squeeze-offload-sidecar-warning<?php
1373 echo ( $mode !== 'sidecar_replace' ? ' squeeze-notice--hidden' : '' );
1374 ?>" role="alert">
1375 <span class="squeeze-notice-icon" aria-hidden="true">⚠️</span>
1376 <div class="squeeze-notice-body">
1377 <strong><?php
1378 esc_html_e( 'Not compatible with WP Offload Media', 'squeeze' );
1379 ?></strong>
1380 <p><?php
1381 esc_html_e( 'The "Rewrite <img> src to WebP URLs in HTML" mode is not compatible with WP Offload Media. WebP sidecar files are stored in a local squeeze-webp/ folder and are never pushed to your external storage provider (S3, GCS, DigitalOcean Spaces, etc.), so they cannot be served from your CDN URL.', 'squeeze' );
1382 ?></p>
1383 <p><?php
1384 echo wp_kses( __( 'Please switch to <strong>Direct WebP</strong> conversion — it converts images to WebP in-place and WP Offload Media handles uploading automatically.', 'squeeze' ), array(
1385 'strong' => array(),
1386 ) );
1387 ?></p>
1388 </div>
1389 </div>
1390 <?php
1391 }
1392 ?>
1393 <details class="squeeze-webp-example">
1394 <summary><?php
1395 esc_html_e( 'Show example: Rewrite <img> src to WebP URLs in HTML', 'squeeze' );
1396 ?></summary>
1397 <div class="squeeze-webp-example-inner">
1398 <pre class="squeeze-webp-code-sample"><span class="squeeze-webp-pre-callout"><?php
1399 echo esc_html( __( 'Before: the page outputs a normal uploads URL for the JPEG.', 'squeeze' ) );
1400 ?></span>
1401 &lt;img src="//yoursite.example/wp-content/uploads/2025/07/photo.jpg" alt="" /&gt;
1402
1403 <span class="squeeze-webp-pre-callout"><?php
1404 echo esc_html( __( 'After: the same img tag in the markup, but PHP rewrites src to the WebP path under squeeze-webp when that file exists.', 'squeeze' ) );
1405 ?></span>
1406 &lt;img src="//yoursite.example/wp-content/squeeze-webp/uploads/2025/07/photo.jpg.webp" alt="" /&gt;</pre>
1407 </div>
1408 </details>
1409 <details class="squeeze-webp-example">
1410 <summary><?php
1411 esc_html_e( 'Show example: Keep JPEG/PNG URLs — server serves WebP', 'squeeze' );
1412 ?></summary>
1413 <div class="squeeze-webp-example-inner">
1414 <pre class="squeeze-webp-code-sample"><span class="squeeze-webp-pre-callout"><?php
1415 echo esc_html( __( 'The published HTML keeps the usual uploads URL on the img (still ends in .jpg or .png).', 'squeeze' ) );
1416 ?></span>
1417 &lt;img src="//yoursite.example/wp-content/uploads/2025/07/photo.jpg" alt="" /&gt;
1418
1419 <span class="squeeze-webp-pre-callout"><?php
1420 echo esc_html( __( 'When the browser advertises WebP and your server rewrite rules apply, that same URL can be served as a WebP response from the file under squeeze-webp, without changing the markup.', 'squeeze' ) );
1421 ?></span>
1422
1423 <span class="squeeze-webp-pre-heading"><?php
1424 echo esc_html( __( 'On disk (after optimization)', 'squeeze' ) );
1425 ?></span>
1426 /wp-content/uploads/2025/07/image.jpg <span class="squeeze-webp-size squeeze-webp-size--before">~500 KB</span> <span class="squeeze-webp-pre-note"><?php
1427 echo esc_html( __( 'original', 'squeeze' ) );
1428 ?></span>
1429 /wp-content/squeeze-webp/uploads/2025/07/image.jpg.webp <span class="squeeze-webp-size squeeze-webp-size--after">~50 KB</span> <span class="squeeze-webp-pre-note"><?php
1430 echo esc_html( __( 'sidecar WebP', 'squeeze' ) );
1431 ?></span></pre>
1432 </div>
1433 </details>
1434 </div>
1435 </details>
1436 </fieldset>
1437 <details class="squeeze-webp-example">
1438 <summary><?php
1439 esc_html_e( 'Show example: Direct WebP (file sizes)', 'squeeze' );
1440 ?></summary>
1441 <div class="squeeze-webp-example-inner">
1442 <pre class="squeeze-webp-code-sample"><span class="squeeze-webp-pre-callout"><?php
1443 echo esc_html( __( 'Direct WebP: on disk, files use the .webp extension instead of .jpg / .png for the same attachment paths.', 'squeeze' ) );
1444 ?></span>
1445 <span class="squeeze-webp-pre-heading"><?php
1446 echo esc_html( __( 'Before', 'squeeze' ) );
1447 ?></span>
1448 /wp-content/uploads/2025/07/image.jpg <span class="squeeze-webp-size squeeze-webp-size--before">~500 KB</span>
1449 /wp-content/uploads/2025/07/image-300x300.jpg <span class="squeeze-webp-size squeeze-webp-size--before">~230 KB</span>
1450
1451 <span class="squeeze-webp-pre-heading"><?php
1452 echo esc_html( __( 'After', 'squeeze' ) );
1453 ?></span>
1454 /wp-content/uploads/2025/07/image.webp <span class="squeeze-webp-size squeeze-webp-size--after">~50 KB</span>
1455 /wp-content/uploads/2025/07/image-300x300.webp <span class="squeeze-webp-size squeeze-webp-size--after">~20 KB</span></pre>
1456 </div>
1457 </details>
1458 </div>
1459 <?php
1460 }
1461
1462 /**
1463 * Sidebar summary on Basic settings (read-only hints).
1464 */
1465 public function render_basic_settings_sidebar() {
1466 $options = get_option( 'squeeze_options' );
1467 if ( !is_array( $options ) ) {
1468 $options = array();
1469 }
1470 $mode = $this->get_webp_delivery_mode( $options );
1471 $mode_label = __( 'Direct WebP', 'squeeze' );
1472 if ( 'sidecar' === $mode ) {
1473 $mode_label = __( 'Keep JPEG/PNG URLs — server serves WebP', 'squeeze' );
1474 } elseif ( 'sidecar_replace' === $mode ) {
1475 $mode_label = __( 'Rewrite <img> src to WebP URLs in HTML', 'squeeze' );
1476 }
1477 $upload_on = !empty( $options['auto_compress'] );
1478 $backup_on = !empty( $options['backup_original'] );
1479 ?>
1480 <div class="squeeze-card squeeze-card--aside">
1481 <div class="squeeze-card-header">
1482 <h2 class="squeeze-card-title"><?php
1483 esc_html_e( 'Current profile', 'squeeze' );
1484 ?></h2>
1485 </div>
1486 <div class="squeeze-card-body">
1487 <?php
1488 $profile_bits = array('<strong>' . esc_html( $mode_label ) . '</strong>');
1489 if ( $upload_on ) {
1490 $profile_bits[] = esc_html__( 'Squeeze on upload', 'squeeze' );
1491 }
1492 if ( $backup_on ) {
1493 $profile_bits[] = esc_html__( 'Backup on', 'squeeze' );
1494 }
1495 echo '<p>' . wp_kses( implode( ' · ', $profile_bits ), array(
1496 'strong' => array(),
1497 ) ) . '</p>';
1498 ?>
1499 <ul class="squeeze-aside-list">
1500 <?php
1501 if ( 'direct' === $mode ) {
1502 ?>
1503 <li><?php
1504 esc_html_e( 'Best for storage savings on new uploads.', 'squeeze' );
1505 ?></li>
1506 <li><?php
1507 esc_html_e( 'If you deactivate the plugin, hard-coded .jpg/.png links may need updating.', 'squeeze' );
1508 ?></li>
1509 <?php
1510 } elseif ( 'sidecar' === $mode ) {
1511 ?>
1512 <li><?php
1513 esc_html_e( 'HTML keeps normal .jpg/.png URLs; WebP is chosen by the server when the browser supports it.', 'squeeze' );
1514 ?></li>
1515 <li><?php
1516 esc_html_e( 'Needs working .htaccess rewrite rules (Apache mod_rewrite or equivalent).', 'squeeze' );
1517 ?></li>
1518 <?php
1519 } elseif ( 'sidecar_replace' === $mode ) {
1520 ?>
1521 <li><?php
1522 esc_html_e( 'Originals stay in uploads; page HTML points at WebP under squeeze-webp.', 'squeeze' );
1523 ?></li>
1524 <li><?php
1525 esc_html_e( 'Works without .htaccess — PHP rewrites image URLs on each page load.', 'squeeze' );
1526 ?></li>
1527 <?php
1528 }
1529 ?>
1530 </ul>
1531 </div>
1532 </div>
1533 <div class="squeeze-card squeeze-card--aside">
1534 <div class="squeeze-card-header">
1535 <h2 class="squeeze-card-title"><?php
1536 esc_html_e( 'Documentation', 'squeeze' );
1537 ?></h2>
1538 </div>
1539 <div class="squeeze-card-body">
1540 <p>
1541 <a href="<?php
1542 echo esc_url( self::$DOCS_URL );
1543 ?>" target="_blank" rel="noopener noreferrer"><?php
1544 esc_html_e( 'Squeeze documentation', 'squeeze' );
1545 ?></a>
1546 </p>
1547 </div>
1548 </div>
1549 <?php
1550 }
1551
1552 public function options_validate( $input ) {
1553 $previous_options = get_option( 'squeeze_options' );
1554 if ( !is_array( $previous_options ) ) {
1555 $previous_options = array();
1556 }
1557 $previous_webp_mode = $this->get_webp_delivery_mode( $previous_options );
1558 if ( isset( $input['webp_delivery_mode'] ) && is_string( $input['webp_delivery_mode'] ) ) {
1559 $mode = sanitize_text_field( wp_unslash( $input['webp_delivery_mode'] ) );
1560 unset($input['webp_delivery_mode']);
1561 switch ( $mode ) {
1562 case 'sidecar':
1563 case 'sidecar_picture':
1564 $input['direct_webp'] = false;
1565 $input['auto_webp'] = true;
1566 $input['webp_replace_urls'] = false;
1567 break;
1568 case 'sidecar_replace':
1569 $input['direct_webp'] = false;
1570 $input['auto_webp'] = true;
1571 $input['webp_replace_urls'] = true;
1572 break;
1573 case 'direct':
1574 default:
1575 $input['direct_webp'] = true;
1576 $input['auto_webp'] = false;
1577 $input['webp_replace_urls'] = false;
1578 break;
1579 }
1580 }
1581 $input['jpeg_quality'] = absint( $input['jpeg_quality'] );
1582 $input['jpeg_smoothing'] = ( isset( $input['jpeg_smoothing'] ) ? absint( $input['jpeg_smoothing'] ) : self::$SqueezeHelpers->get_default_value( 'jpeg_smoothing' ) );
1583 $input['jpeg_color_space'] = ( isset( $input['jpeg_color_space'] ) ? absint( $input['jpeg_color_space'] ) : self::$SqueezeHelpers->get_default_value( 'jpeg_color_space' ) );
1584 $input['jpeg_quant_table'] = ( isset( $input['jpeg_quant_table'] ) ? absint( $input['jpeg_quant_table'] ) : self::$SqueezeHelpers->get_default_value( 'jpeg_quant_table' ) );
1585 $input['jpeg_trellis_loops'] = ( isset( $input['jpeg_trellis_loops'] ) ? absint( $input['jpeg_trellis_loops'] ) : self::$SqueezeHelpers->get_default_value( 'jpeg_trellis_loops' ) );
1586 $input['jpeg_chroma_subsample'] = ( isset( $input['jpeg_chroma_subsample'] ) ? absint( $input['jpeg_chroma_subsample'] ) : self::$SqueezeHelpers->get_default_value( 'jpeg_chroma_subsample' ) );
1587 $input['jpeg_chroma_quality'] = ( isset( $input['jpeg_chroma_quality'] ) ? absint( $input['jpeg_chroma_quality'] ) : self::$SqueezeHelpers->get_default_value( 'jpeg_chroma_quality' ) );
1588 $input['png_level'] = ( isset( $input['png_level'] ) ? absint( $input['png_level'] ) : self::$SqueezeHelpers->get_default_value( 'png_level' ) );
1589 $input['png_quality'] = ( isset( $input['png_quality'] ) ? floatval( $input['png_quality'] ) : self::$SqueezeHelpers->get_default_value( 'png_quality' ) );
1590 $input['webp_method'] = ( isset( $input['webp_method'] ) ? absint( $input['webp_method'] ) : self::$SqueezeHelpers->get_default_value( 'webp_method' ) );
1591 $input['webp_quality'] = ( isset( $input['webp_quality'] ) ? absint( $input['webp_quality'] ) : self::$SqueezeHelpers->get_default_value( 'webp_quality' ) );
1592 $input['webp_near_lossless'] = ( isset( $input['webp_near_lossless'] ) ? absint( $input['webp_near_lossless'] ) : self::$SqueezeHelpers->get_default_value( 'webp_near_lossless' ) );
1593 $input['avif_cqLevel'] = ( isset( $input['avif_cqLevel'] ) ? absint( $input['avif_cqLevel'] ) : self::$SqueezeHelpers->get_default_value( 'avif_cqLevel' ) );
1594 $input['jpeg_baseline'] = ( isset( $input['jpeg_baseline'] ) ? boolval( $input['jpeg_baseline'] ) : '0' );
1595 //$input[ 'jpeg_arithmetic' ] = isset($input[ 'jpeg_arithmetic' ]) ? boolval($input[ 'jpeg_arithmetic' ]) : '0';
1596 $input['jpeg_progressive'] = ( isset( $input['jpeg_progressive'] ) ? boolval( $input['jpeg_progressive'] ) : '0' );
1597 $input['jpeg_optimize_coding'] = ( isset( $input['jpeg_optimize_coding'] ) ? boolval( $input['jpeg_optimize_coding'] ) : '0' );
1598 $input['jpeg_trellis_multipass'] = ( isset( $input['jpeg_trellis_multipass'] ) ? boolval( $input['jpeg_trellis_multipass'] ) : '0' );
1599 $input['jpeg_trellis_opt_zero'] = ( isset( $input['jpeg_trellis_opt_zero'] ) ? boolval( $input['jpeg_trellis_opt_zero'] ) : '0' );
1600 $input['jpeg_trellis_opt_table'] = ( isset( $input['jpeg_trellis_opt_table'] ) ? boolval( $input['jpeg_trellis_opt_table'] ) : '0' );
1601 $input['jpeg_auto_subsample'] = ( isset( $input['jpeg_auto_subsample'] ) ? boolval( $input['jpeg_auto_subsample'] ) : '0' );
1602 $input['jpeg_separate_chroma_quality'] = ( isset( $input['jpeg_separate_chroma_quality'] ) ? boolval( $input['jpeg_separate_chroma_quality'] ) : '0' );
1603 $input['png_interlace'] = ( isset( $input['png_interlace'] ) ? boolval( $input['png_interlace'] ) : '0' );
1604 $input['webp_lossless'] = ( isset( $input['webp_lossless'] ) ? boolval( $input['webp_lossless'] ) : '0' );
1605 $input['auto_compress'] = ( isset( $input['auto_compress'] ) ? boolval( $input['auto_compress'] ) : '0' );
1606 // TBD: maybe get default value from the database
1607 $input['auto_webp'] = ( isset( $input['auto_webp'] ) ? boolval( $input['auto_webp'] ) : '0' );
1608 $input['webp_replace_urls'] = ( isset( $input['webp_replace_urls'] ) && $input['auto_webp'] ? boolval( $input['webp_replace_urls'] ) : '0' );
1609 $input['direct_webp'] = ( isset( $input['direct_webp'] ) ? boolval( $input['direct_webp'] ) : '0' );
1610 $new_webp_mode = $this->get_webp_delivery_mode( $input );
1611 if ( $previous_webp_mode !== $new_webp_mode ) {
1612 add_settings_error(
1613 'squeeze_notices',
1614 'webp_delivery_mode_changed',
1615 __( 'WebP delivery mode changed. Existing files are not migrated automatically — re-squeeze images after switching. Leftover JPEG/PNG + WebP pairs or orphaned files under squeeze-webp may remain until cleaned up.', 'squeeze' ),
1616 'warning'
1617 );
1618 }
1619 if ( isset( $input['cdn_url'] ) ) {
1620 $cdn_raw = trim( wp_unslash( (string) $input['cdn_url'] ) );
1621 $input['cdn_url'] = ( $cdn_raw === '' ? '' : esc_url_raw( $cdn_raw ) );
1622 } else {
1623 $input['cdn_url'] = '';
1624 }
1625 $input['backup_original'] = ( isset( $input['backup_original'] ) ? boolval( $input['backup_original'] ) : '0' );
1626 $input['clear_data_on_uninstall'] = ( isset( $input['clear_data_on_uninstall'] ) ? boolval( $input['clear_data_on_uninstall'] ) : '0' );
1627 $input['compress_formats'] = ( isset( $input['compress_formats'] ) && is_array( $input['compress_formats'] ) ? $this->validate_image_formats( $input['compress_formats'], $input['direct_webp'] ) : array() );
1628 $input['compress_thumbs'] = ( isset( $input['compress_thumbs'] ) && is_array( $input['compress_thumbs'] ) ? $input['compress_thumbs'] : array() );
1629 $input['max_width'] = ( isset( $input['max_width'] ) && $input['max_width'] > 0 ? absint( $input['max_width'] ) : '' );
1630 $input['max_height'] = ( isset( $input['max_height'] ) && $input['max_height'] > 0 ? absint( $input['max_height'] ) : '' );
1631 $input['excluded_images'] = ( isset( $input['excluded_images'] ) ? $input['excluded_images'] : '' );
1632 $input['timeout'] = ( isset( $input['timeout'] ) && $input['timeout'] > 0 ? absint( $input['timeout'] ) : 1 );
1633 $input['restore_defaults'] = ( isset( $input['restore_defaults'] ) ? $input['restore_defaults'] : '0' );
1634 if ( !isset( $input['restore_defaults'] ) || $input['restore_defaults'] !== '1' ) {
1635 add_settings_error(
1636 'squeeze_notices',
1637 'settings_updated',
1638 __( 'Settings have been updated.', 'squeeze' ),
1639 'success'
1640 );
1641 }
1642 unset($input['webp_picture_markup']);
1643 return $input;
1644 }
1645
1646 protected function validate_image_formats( $input, $is_direct_webp = false ) {
1647 $formats = self::ALLOWED_IMAGE_FORMATS;
1648 if ( !isset( $input ) || !is_array( $input ) ) {
1649 return array();
1650 }
1651 // remove all formats that are not in the allowed formats list
1652 $input = array_filter( $input, function ( $format ) use($formats) {
1653 //check by key
1654 return array_key_exists( $format, $formats );
1655 }, ARRAY_FILTER_USE_KEY );
1656 // if direct webp conversion is enabled, webp format is mandatory
1657 if ( $is_direct_webp && !array_key_exists( 'webp', $input ) ) {
1658 $input['webp'] = 'on';
1659 }
1660 return $input;
1661 }
1662
1663 public function options_callback( $args ) {
1664 $label_for = ( isset( $args['label_for'] ) ? $args['label_for'] : '' );
1665 if ( empty( $label_for ) ) {
1666 return;
1667 }
1668 $type = ( isset( $args['type'] ) ? $args['type'] : 'text' );
1669 $class = ( isset( $args['class'] ) ? $args['class'] : '' );
1670 $default = self::$SqueezeHelpers->get_default_value( $label_for );
1671 $options = get_option( 'squeeze_options' );
1672 $is_hidden = ( isset( $args['hidden'] ) && $args['hidden'] ? 'hidden' : '' );
1673 $extra_classes = [];
1674 if ( $is_hidden ) {
1675 $extra_classes[] = 'squeeze-hidden';
1676 }
1677 $extra_classes = implode( ' ', $extra_classes );
1678 switch ( $type ) {
1679 case 'text':
1680 $value = ( isset( $options[$label_for] ) ? $options[$label_for] : $default );
1681 $placeholder = ( isset( $args['placeholder'] ) ? $args['placeholder'] : '' );
1682 echo "<input class='" . esc_attr( $extra_classes ) . "' id='squeeze_setting_" . esc_attr( $label_for ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "]' type='text' value='" . esc_attr( $value ) . "' placeholder='" . esc_attr( $placeholder ) . "' />";
1683 break;
1684 case 'number':
1685 $value = ( isset( $options[$label_for] ) ? $options[$label_for] : $default );
1686 $units = ( isset( $args['units'] ) ? $args['units'] : '' );
1687 $min = ( isset( $args['min'] ) ? $args['min'] : '' );
1688 $max = ( isset( $args['max'] ) ? $args['max'] : '' );
1689 echo "<input class='" . esc_attr( $extra_classes ) . "' id='squeeze_setting_" . esc_attr( $label_for ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "]' type='number' value='" . esc_attr( $value ) . "' " . (( $min !== '' && $min !== null ? "min='" . esc_attr( $min ) . "'" : "" )) . " " . (( $max !== '' && $max !== null ? "max='" . esc_attr( $max ) . "'" : "" )) . " />";
1690 if ( $units ) {
1691 echo "<span class='squeeze-setting-units'>" . esc_html( $units ) . "</span>";
1692 }
1693 break;
1694 case 'range':
1695 $value = ( isset( $options[$label_for] ) ? $options[$label_for] : $default );
1696 $min = ( isset( $args['min'] ) ? $args['min'] : 0 );
1697 $max = ( isset( $args['max'] ) ? $args['max'] : 100 );
1698 $step = ( isset( $args['step'] ) ? $args['step'] : 1 );
1699 echo "<input class='" . esc_attr( $extra_classes ) . "' id='squeeze_setting_" . esc_attr( $label_for ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "]' min='" . (int) $min . "' max='" . (int) $max . "' step='" . floatval( $step ) . "' type='range' value='" . esc_attr( $value ) . "' />";
1700 echo '<output id="squeeze_setting_' . esc_attr( $label_for ) . '_value"></output>';
1701 ?>
1702 <script>
1703 (function () {
1704 const value = document.querySelector("#squeeze_setting_<?php
1705 echo esc_attr( $label_for );
1706 ?>_value")
1707 const input = document.querySelector("#squeeze_setting_<?php
1708 echo esc_attr( $label_for );
1709 ?>")
1710 value.textContent = input.value
1711 input.addEventListener("input", (event) => {
1712 value.textContent = event.target.value
1713 })
1714 })()
1715 </script>
1716 <?php
1717 break;
1718 case 'checkbox':
1719 $value = ( isset( $options[$label_for] ) ? (bool) $options[$label_for] : $default );
1720 //echo (bool)$options[ $label_for ];
1721 echo "<input class='squeeze-ios8-switch " . esc_attr( $extra_classes ) . "' id='squeeze_setting_" . esc_attr( $label_for ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "]' type='checkbox' " . checked( $value, true, false ) . " />";
1722 echo '<label for="squeeze_setting_' . esc_attr( $label_for ) . '"></label>';
1723 break;
1724 case 'select':
1725 $value = ( isset( $options[$label_for] ) ? $options[$label_for] : $default );
1726 echo "<select class='" . esc_attr( $extra_classes ) . "' id='squeeze_setting_" . esc_attr( $label_for ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "]'>";
1727 foreach ( $args['options'] as $key => $option ) {
1728 echo "<option value='" . esc_attr( $key ) . "'" . selected( $value, $key, false ) . ">" . esc_html( $option ) . "</option>";
1729 }
1730 echo "</select>";
1731 break;
1732 case 'thumbs_checkbox_group':
1733 $thumbs = array();
1734 $value = ( isset( $options[$label_for] ) ? (array) $options[$label_for] : $default );
1735 $available_sizes = wp_get_registered_image_subsizes();
1736 foreach ( $available_sizes as $key => $size ) {
1737 $thumbs[$key] = ucwords( str_replace( '_', ' ', $key ) ) . ' (' . $size['width'] . 'x' . $size['height'] . ')';
1738 }
1739 // Add the scaled image size option
1740 $big_image_size_threshold = apply_filters( 'big_image_size_threshold', 2560 );
1741 $thumbs['full'] = 'Scaled (' . $big_image_size_threshold . 'x' . $big_image_size_threshold . ')';
1742 echo '<div class="squeeze-thumb-toolbar">';
1743 echo '<button type="button" class="button button-small" id="squeeze-thumbs-select-all">' . esc_html__( 'Select all', 'squeeze' ) . '</button>';
1744 echo '<button type="button" class="button button-small" id="squeeze-thumbs-clear-all">' . esc_html__( 'Clear all', 'squeeze' ) . '</button>';
1745 echo '<button type="button" class="button button-small" id="squeeze-thumbs-wp-defaults">' . esc_html__( 'WordPress defaults', 'squeeze' ) . '</button>';
1746 echo '</div>';
1747 echo '<div class="squeeze-box squeeze-box--fieldset squeeze-thumb-grid-wrap">';
1748 echo '<div class="squeeze-box-content squeeze-thumb-grid">';
1749 foreach ( $thumbs as $key => $option ) {
1750 echo '<div class="squeeze-suboption squeeze-thumb-grid-item">';
1751 echo "<input class='squeeze-ios8-switch' id='squeeze_setting_" . esc_attr( $label_for ) . "_" . esc_attr( $key ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "][" . esc_attr( $key ) . "]' type='checkbox' " . checked( array_key_exists( $key, $value ), true, false ) . " /> ";
1752 echo "<label for='squeeze_setting_" . esc_attr( $label_for ) . "_" . esc_attr( $key ) . "'>" . esc_html( $option ) . "</label>";
1753 echo '</div>';
1754 }
1755 echo '</div>';
1756 echo '</div>';
1757 break;
1758 case 'formats_checkbox_group':
1759 $is_direct_webp = ( isset( $options['direct_webp'] ) ? (bool) $options['direct_webp'] : false );
1760 $formats = self::ALLOWED_IMAGE_FORMATS;
1761 $value = ( isset( $options[$label_for] ) ? (array) $options[$label_for] : $default );
1762 echo '<div class="squeeze-box squeeze-box--fieldset squeeze-format-chips-wrap">';
1763 echo '<div class="squeeze-box-content squeeze-format-chips">';
1764 foreach ( $formats as $key => $option ) {
1765 echo '<div class="squeeze-suboption squeeze-format-chip ' . (( $is_direct_webp && $key === 'webp' ? 'squeeze-disabled' : '' )) . '">';
1766 echo "<input class='squeeze-ios8-switch' id='squeeze_setting_" . esc_attr( $label_for ) . "_" . esc_attr( $key ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "][" . esc_attr( $key ) . "]' type='checkbox' " . checked( array_key_exists( $key, $value ), true, false ) . " /> ";
1767 echo "<label for='squeeze_setting_" . esc_attr( $label_for ) . "_" . esc_attr( $key ) . "'>" . esc_html( $key ) . "</label>";
1768 if ( $is_direct_webp && $key === 'webp' ) {
1769 echo '<span class="squeeze-hint">' . __( '(mandatory when Direct WebP is enabled)', 'squeeze' ) . '</span>';
1770 }
1771 echo '</div>';
1772 }
1773 echo '</div>';
1774 echo '</div>';
1775 break;
1776 case 'hidden':
1777 $value = ( isset( $options[$label_for] ) ? $options[$label_for] : $default );
1778 echo "<input id='squeeze_setting_" . esc_attr( $label_for ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "]' type='hidden' value='" . esc_attr( $value ) . "' />";
1779 break;
1780 case 'textarea':
1781 $value = ( isset( $options[$label_for] ) ? $options[$label_for] : $default );
1782 echo "<textarea class='" . esc_attr( $extra_classes ) . "' id='squeeze_setting_" . esc_attr( $label_for ) . "' name='squeeze_options[" . esc_attr( $label_for ) . "]'>" . esc_textarea( $value ) . "</textarea>";
1783 break;
1784 case 'placeholder':
1785 echo '<p>' . sprintf( __( 'This feature is available only in the <a href="%s">premium version</a>.', 'squeeze' ), esc_url( self::$UPGRADE_URL ) ) . '</p>';
1786 break;
1787 }
1788 }
1789
1790 public function setting_basic_desc() {
1791 echo '<p>' . esc_html__( 'Basic squeezing settings.', 'squeeze' ) . '</p>';
1792 }
1793
1794 public function setting_jpeg_desc() {
1795 echo '<p>' . esc_html__( 'Squeezing settings for JPEG images.', 'squeeze' ) . '</p>';
1796 }
1797
1798 public function setting_jpeg_advanced_desc() {
1799 echo '<p>' . esc_html__( 'More precise settings for experienced users.', 'squeeze' ) . '</p>';
1800 }
1801
1802 public function setting_png_desc() {
1803 echo '<p>' . esc_html__( 'Squeezing settings for PNG images.', 'squeeze' ) . '</p>';
1804 }
1805
1806 public function setting_webp_desc() {
1807 echo '<p>' . esc_html__( 'Squeezing settings for WebP images.', 'squeeze' ) . '</p>';
1808 }
1809
1810 public function setting_avif_desc() {
1811 echo '<p>' . esc_html__( 'Squeezing settings for Avif images.', 'squeeze' ) . '</p>';
1812 }
1813
1814 public function setting_upgrade_desc() {
1815 echo '<p>' . esc_html__( 'Upgrade to premium version for more features.', 'squeeze' ) . '</p>';
1816 }
1817
1818 public function setting_license_desc() {
1819 }
1820
1821 public function restore_defaults( $old_value, $value ) {
1822 if ( isset( $value['restore_defaults'] ) && $value['restore_defaults'] === '1' ) {
1823 $result = delete_option( 'squeeze_options', "" );
1824 if ( $result ) {
1825 add_settings_error(
1826 'squeeze_notices',
1827 'settings_restored',
1828 __( 'Settings have been restored.', 'squeeze' ),
1829 'success'
1830 );
1831 } else {
1832 add_settings_error(
1833 'squeeze_notices',
1834 'settings_not_restored',
1835 __( 'Settings have not been restored.', 'squeeze' ),
1836 'error'
1837 );
1838 }
1839 }
1840 }
1841
1842 public function flush_rewrite_rules( $old_value, $value ) {
1843 if ( isset( $value['auto_webp'] ) && $value['auto_webp'] !== $old_value['auto_webp'] ) {
1844 flush_rewrite_rules();
1845 add_settings_error(
1846 'squeeze_notices',
1847 'rewrite_rules_flushed',
1848 __( 'Rewrite rules have been flushed.', 'squeeze' ),
1849 'success'
1850 );
1851 }
1852 }
1853
1854 public function add_custom_field_to_attachment( $form_fields, $post ) {
1855 $all_formats = self::ALLOWED_IMAGE_FORMATS;
1856 $all_mimes = self::$SqueezeHelpers->get_image_formats( true, $all_formats );
1857 if ( in_array( $post->post_mime_type, $all_mimes ) ) {
1858 $selected_mimes = self::$SqueezeHelpers->get_image_formats( true );
1859 $is_compressed = get_post_meta( $post->ID, 'squeeze_is_compressed', true );
1860 $compression_failed = get_post_meta( $post->ID, 'squeeze_compression_failed', true );
1861 $can_restore = self::$SqueezeHelpers->can_restore( $post->ID );
1862 $is_excluded = false;
1863 $url = wp_get_original_image_url( $post->ID );
1864 if ( $url ) {
1865 $excluded_images = self::$SqueezeHelpers->get_excluded_images();
1866 $is_excluded = self::$SqueezeHelpers->is_excluded_image( $url, $excluded_images );
1867 }
1868 $form_fields['squeeze_is_compressed'] = array(
1869 'label' => __( 'Squeeze', 'squeeze' ),
1870 'input' => 'html',
1871 'html' => ( !in_array( $post->post_mime_type, $selected_mimes ) ? '<span class="squeeze_status"><span style="padding-top: 0; line-height: 1; color: gray;" class="dashicons dashicons-info"></span>&nbsp;' . __( 'Image format is not selected for compression in the plugin settings', 'squeeze' ) . '</span><br>' : (( $is_excluded ? '<span class="squeeze_status"><span style="padding-top: 0; line-height: 1; color: #6c757d;" class="dashicons dashicons-hidden"></span>&nbsp;' . __( 'Image is excluded from compression', 'squeeze' ) . ' (' . esc_html__( 'found substring: ', 'squeeze' ) . $is_excluded['exclude_reason'] . ')</span>' : (( $compression_failed === 'larger_than_original' ? '<p><span class="squeeze_status"><span style="padding-top: 0; line-height: 1; color: #FFA500;" class="dashicons dashicons-warning"></span>&nbsp;' . sprintf( __( 'Could not compress — result was larger than original. Try <a href="%s" target="_blank">adjusting compression settings</a>, then re-squeeze.', 'squeeze' ), self::$SETTINGS_URL . '#squeeze_' . pathinfo( get_attached_file( $post->ID ), PATHINFO_EXTENSION ) ) . '</span></p>' . (( $can_restore ? '<p><button name="squeeze_restore" type="button" class="button button-secondary squeeze-restore-button" data-attachment="' . $post->ID . '">' . __( 'Restore original image', 'squeeze' ) . '</button></p>' : '' )) . '<p><button name="squeeze_compress_single" type="button" class="button button-secondary squeeze-compress-button" data-attachment="' . $post->ID . '">' . __( 'Re-Squeeze image', 'squeeze' ) . '</button></p>' : (( $is_compressed ? '<p><span class="squeeze_status"><span style="padding-top: 0; line-height: 1; color: #6BCB77;" class="dashicons dashicons-performance"></span>&nbsp;' . __( 'Squeezed', 'squeeze' ) . '</span></p>' . (( $can_restore ? '
1872 <p><button name="squeeze_restore" type="button" class="button button-secondary squeeze-restore-button" data-attachment="' . $post->ID . '">' . __( 'Restore original image', 'squeeze' ) . '</button></p>' : '' )) . '
1873 <p><button name="squeeze_compress_again" type="button" class="button button-primary squeeze-compress-button" data-attachment="' . $post->ID . '">' . __( 'Re-Squeeze image', 'squeeze' ) . '</button></p>' : '<p><span class="squeeze_status"><span style="padding-top: 0; line-height: 1; color: #FFD93D; scale: -1 1;" class="dashicons dashicons-performance"></span>&nbsp;' . __( 'Not squeezed', 'squeeze' ) . '</span></p>
1874 <p><button name="squeeze_compress_single" type="button" class="button button-primary squeeze-compress-button" data-attachment="' . $post->ID . '">' . __( 'Squeeze Now', 'squeeze' ) . '</button></p>' )) )) )) ),
1875 );
1876 }
1877 return $form_fields;
1878 }
1879
1880 public function add_media_columns( $posts_columns ) {
1881 $posts_columns['squeeze'] = __( 'Squeeze', 'squeeze' );
1882 return $posts_columns;
1883 }
1884
1885 public function media_custom_column( $column_name, $post_id ) {
1886 if ( 'squeeze' !== $column_name ) {
1887 return;
1888 }
1889 $form_fields = $this->add_custom_field_to_attachment( array(), get_post( $post_id ) );
1890 if ( $form_fields ) {
1891 echo wp_kses_post( $form_fields['squeeze_is_compressed']['html'] );
1892 }
1893 }
1894
1895 public function sortable_columns( $columns ) {
1896 $columns['squeeze'] = 'squeeze';
1897 return $columns;
1898 }
1899
1900 public function sortable_columns_orderby( $query ) {
1901 if ( !is_admin() || !$query->is_main_query() ) {
1902 return;
1903 }
1904 $orderby = $query->get( 'orderby' );
1905 if ( 'squeeze' === $orderby ) {
1906 // Define the allowed image formats
1907 $allowed_formats = self::$SqueezeHelpers->get_image_formats( true );
1908 // include all media
1909 $query->set( 'meta_query', array(
1910 'relation' => 'OR',
1911 array(
1912 'key' => 'squeeze_is_compressed',
1913 'compare' => 'NOT EXISTS',
1914 ),
1915 array(
1916 'key' => 'squeeze_is_compressed',
1917 'compare' => 'EXISTS',
1918 ),
1919 ) );
1920 // Add the meta_query to filter by specific image formats
1921 //$query->set('post_mime_type', $allowed_formats);
1922 $query->set( 'orderby', 'meta_value' );
1923 }
1924 }
1925
1926 public function media_filter_dropdown() {
1927 global $wp_query;
1928 $post_type = 'attachment';
1929 if ( isset( $_GET['post_type'] ) ) {
1930 $post_type = sanitize_text_field( wp_unslash( $_GET['post_type'] ) );
1931 }
1932 if ( 'attachment' !== $post_type ) {
1933 return;
1934 }
1935 $selected = ( isset( $_GET['squeeze_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['squeeze_filter'] ) ) : '' );
1936 $options = array(
1937 'all' => __( 'Squeeze: All images', 'squeeze' ),
1938 'non-squeezed' => __( 'Non Squeezed Images', 'squeeze' ),
1939 );
1940 echo '<select name="squeeze_filter" id="squeeze-filter">';
1941 foreach ( $options as $value => $label ) {
1942 printf(
1943 '<option value="%s"%s>%s</option>',
1944 esc_attr( $value ),
1945 selected( $selected, $value, false ),
1946 esc_html( $label )
1947 );
1948 }
1949 echo '</select>';
1950 }
1951
1952 public function media_filter_query( $query ) {
1953 global $current_screen;
1954 if ( !is_admin() || !empty( $current_screen ) && 'upload' !== $current_screen->base || 'attachment' !== $query->get( 'post_type' ) ) {
1955 return $query;
1956 }
1957 if ( isset( $_GET['squeeze_filter'] ) ) {
1958 $squeeze_filter = sanitize_text_field( wp_unslash( $_GET['squeeze_filter'] ) );
1959 if ( 'non-squeezed' === $squeeze_filter ) {
1960 $query->set( 'meta_query', self::$SqueezeHelpers->get_non_squeezed_media_meta_query() );
1961 $query->set( 'squeeze_exclude_excluded', true );
1962 $query->set( 'orderby', 'meta_value' );
1963 $query->set( 'post_mime_type', self::$SqueezeHelpers->get_image_formats( true ) );
1964 }
1965 }
1966 return $query;
1967 }
1968
1969 public function media_filter_ajax_query( $query ) {
1970 if ( !isset( $_POST['query']['squeeze_filter'] ) ) {
1971 return $query;
1972 }
1973 $squeeze_filter = sanitize_text_field( wp_unslash( $_POST['query']['squeeze_filter'] ) );
1974 if ( 'non-squeezed' === $squeeze_filter ) {
1975 $query['meta_query'] = self::$SqueezeHelpers->get_non_squeezed_media_meta_query();
1976 $query['squeeze_exclude_excluded'] = true;
1977 $query['orderby'] = 'meta_value';
1978 $query['post_mime_type'] = self::$SqueezeHelpers->get_image_formats( true );
1979 }
1980 return $query;
1981 }
1982
1983 public function media_filter_exclude_excluded( $posts, $query ) {
1984 if ( empty( $posts ) || !$query instanceof \WP_Query ) {
1985 return $posts;
1986 }
1987 if ( !$query->get( 'squeeze_exclude_excluded' ) ) {
1988 return $posts;
1989 }
1990 if ( empty( self::$SqueezeHelpers->get_excluded_images() ) ) {
1991 return $posts;
1992 }
1993 return array_values( array_filter( $posts, function ( $post ) {
1994 return !self::$SqueezeHelpers->is_attachment_excluded( $post->ID );
1995 } ) );
1996 }
1997
1998 public function handle_excluded_images_option_change( $old_value, $new_value ) {
1999 $old_excluded = ( isset( $old_value['excluded_images'] ) ? $old_value['excluded_images'] : '' );
2000 $new_excluded = ( isset( $new_value['excluded_images'] ) ? $new_value['excluded_images'] : '' );
2001 if ( $old_excluded === $new_excluded ) {
2002 return;
2003 }
2004 self::$SqueezeHelpers->clear_excluded_images_cache();
2005 self::$SqueezeHelpers->clear_options_cache();
2006 self::$SqueezeHelpers->invalidate_uncompressed_stats_cache();
2007 }
2008
2009 public function svg_sprite_output() {
2010 global $pagenow;
2011 if ( $pagenow === 'upload.php' && isset( $_GET['page'] ) && $_GET['page'] === 'squeeze-bulk' ) {
2012 include self::$PLUGIN_DIR . 'assets/images/sprite.svg';
2013 }
2014 }
2015
2016 public function add_preview_button_placeholder( $post ) {
2017 if ( !wp_attachment_is_image( $post->ID ) ) {
2018 return;
2019 }
2020 echo '<div class="squeeze-preview-button is-placeholder">';
2021 echo '<input type="checkbox" disabled class="squeeze-ios8-switch" id="squeeze-ios8-switch"><label for="squeeze-ios8-switch" title="' . esc_attr__( "Image comparison with Squeeze", "squeeze" ) . '">' . esc_html__( "Compare Squeeze", "squeeze" ) . ' ';
2022 echo sprintf( __( '(<a href="%s" target="_blank">premium only</a>)', 'squeeze' ), esc_url( self::$UPGRADE_URL ) ) . '</label>';
2023 echo '</div>';
2024 }
2025
2026 public function incompatibility_notices() {
2027 // Bail if we're not in the admin or the screen helper isn't available.
2028 if ( !is_admin() || !function_exists( 'get_current_screen' ) ) {
2029 return;
2030 }
2031 $screen = get_current_screen();
2032 // List of screen IDs where we want the warning.
2033 $target_screens = array(
2034 'settings_page_squeeze',
2035 // options-general.php?page=squeeze
2036 'media_page_squeeze-bulk',
2037 // upload.php?page=squeeze-bulk
2038 'upload',
2039 // the core Media → Library (list table)
2040 'media',
2041 // the core Media → Add New
2042 'plugins',
2043 );
2044 if ( !$screen || !in_array( $screen->id, $target_screens, true ) ) {
2045 return;
2046 }
2047 // check if webp-express/webp-express.php plugin is active and show a notice
2048 if ( is_plugin_active( 'webp-express/webp-express.php' ) ) {
2049 ?>
2050 <div class="notice notice-warning is-dismissible">
2051 <p>
2052 <?php
2053 echo __( 'The WebP Express plugin is active. Please deactivate it in order to use correct WebP serving from <strong>Squeeze plugin</strong>.', 'squeeze' );
2054 ?>
2055 </p>
2056 </div>
2057 <?php
2058 }
2059 // check if image-converter-webp/image-converter-webp.php plugin is active and show a notice
2060 if ( is_plugin_active( 'image-converter-webp/image-converter-webp.php' ) ) {
2061 ?>
2062 <div class="notice notice-warning is-dismissible">
2063 <p>
2064 <?php
2065 echo __( 'The Image Converter for WebP plugin is active. Please deactivate it in order to use correct WebP serving from <strong>Squeeze plugin</strong>.', 'squeeze' );
2066 ?>
2067 </p>
2068 </div>
2069 <?php
2070 }
2071 }
2072
2073 }
2074