PluginProbe
Squeeze – Image Optimization & Compression, WEBP Conversion / 1.7.9
Squeeze – Image Optimization & Compression, WEBP Conversion v1.7.9
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.9, at inc/settings.php

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