PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / 3.8.0
TinyPNG – JPEG, PNG & WebP image compression v3.8.0
3.8.0 3.7.0 3.6.14 trunk 1.0.0 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.4.0 1.5.0 1.6.0 1.7.0 1.7.1 1.7.2 2.0.0 2.0.1 2.0.2 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 3.0.0 3.0.1 3.1.0 3.2.0 3.2.1 3.3 3.4 3.4.1 3.4.2 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.6.0 3.6.1 3.6.10 3.6.11 3.6.12 3.6.13 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
tiny-compress-images / src / class-tiny-settings.php
tiny-compress-images / src Last commit date
compatibility 2 months ago config 2 months ago css 7 months ago data 4 years ago images 4 years ago js 1 week ago vendor 6 months ago views 1 week ago class-tiny-apache-rewrite.php 2 months ago class-tiny-bulk-optimization.php 2 months ago class-tiny-cli.php 2 months ago class-tiny-compress-client.php 1 week ago class-tiny-compress-fopen.php 2 months ago class-tiny-compress.php 1 week ago class-tiny-conversion.php 4 months ago class-tiny-diagnostics.php 7 months ago class-tiny-exception.php 7 months ago class-tiny-helpers.php 2 months ago class-tiny-image-size.php 1 week ago class-tiny-image.php 1 week ago class-tiny-logger.php 2 months ago class-tiny-migrate.php 2 months ago class-tiny-notices.php 2 months ago class-tiny-php.php 2 months ago class-tiny-picture.php 2 months ago class-tiny-plugin.php 1 week ago class-tiny-settings.php 1 week ago class-tiny-source-base.php 1 week ago class-tiny-source-image.php 7 months ago class-tiny-source-picture.php 7 months ago class-tiny-wp-base.php 2 months ago
class-tiny-settings.php
1059 lines
1 <?php
2 /*
3 * Tiny Compress Images - WordPress plugin.
4 * Copyright (C) 2015-2018 Tinify B.V.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc., 51
18 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 class Tiny_Settings extends Tiny_WP_Base {
21
22
23 const DUMMY_SIZE = '_tiny_dummy';
24
25 private $sizes;
26 private $tinify_sizes;
27 private $compressor;
28 private $notices;
29
30 public function __construct() {
31 parent::__construct();
32 $this->notices = new Tiny_Notices( $this );
33 new Tiny_Diagnostics( $this );
34 }
35
36 private function init_compressor() {
37 $this->compressor = Tiny_Compress::create(
38 $this->get_api_key(),
39 $this->get_method( 'after_compress_callback' )
40 );
41 }
42
43 public function get_absolute_url() {
44 return get_admin_url( null, 'options-general.php?page=tinify' );
45 }
46
47 public function xmlrpc_init() {
48 try {
49 $this->init_compressor();
50 } catch ( Tiny_Exception $e ) {
51 Tiny_Logger::error( $e->getMessage() );
52 }
53 }
54
55 public function cli_init() {
56 try {
57 $this->init_compressor();
58 } catch ( Tiny_Exception $e ) {
59 Tiny_Logger::error( $e->getMessage() );
60 }
61 }
62
63 public function ajax_init() {
64 try {
65 $this->init_compressor();
66 } catch ( Tiny_Exception $e ) {
67 Tiny_Logger::error( $e->getMessage() );
68 }
69
70 add_action(
71 'wp_ajax_tiny_image_sizes_notice',
72 $this->get_method( 'image_sizes_notice' )
73 );
74
75 add_action(
76 'wp_ajax_tiny_account_status',
77 $this->get_method( 'account_status' )
78 );
79
80 add_action(
81 'wp_ajax_tiny_settings_create_api_key',
82 $this->get_method( 'create_api_key' )
83 );
84
85 add_action(
86 'wp_ajax_tiny_settings_update_api_key',
87 $this->get_method( 'update_api_key' )
88 );
89 }
90
91 public function rest_init() {
92 try {
93 $this->init_compressor();
94 } catch ( Tiny_Exception $e ) {
95 Tiny_Logger::error( $e->getMessage() );
96 }
97 }
98
99 public function admin_init() {
100 try {
101 $this->init_compressor();
102 } catch ( Tiny_Exception $e ) {
103 $this->notices->show(
104 'compressor_exception',
105 esc_html( $e->getMessage() ),
106 'error',
107 false
108 );
109 }
110
111 if ( current_user_can( 'manage_options' ) ) {
112 $this->setup_incomplete_checks();
113 }
114
115 $field = self::get_prefixed_name( 'api_key' );
116 register_setting( 'tinify', $field );
117
118 $field = self::get_prefixed_name( 'api_key_pending' );
119 register_setting( 'tinify', $field );
120
121 $field = self::get_prefixed_name( 'compression_timing' );
122 register_setting( 'tinify', $field );
123
124 $field = self::get_prefixed_name( 'sizes' );
125 register_setting( 'tinify', $field );
126
127 $field = self::get_prefixed_name( 'resize_original' );
128 register_setting( 'tinify', $field );
129
130 $field = self::get_prefixed_name( 'backup' );
131 register_setting( 'tinify', $field );
132
133 $field = self::get_prefixed_name( 'preserve_data' );
134 register_setting( 'tinify', $field );
135
136 $field = self::get_prefixed_name( 'convert_format' );
137 register_setting( 'tinify', $field );
138
139 $field = self::get_prefixed_name( 'logging_enabled' );
140 register_setting( 'tinify', $field );
141 }
142
143 public function admin_menu() {
144 /* Create link to new settings page from media settings page. */
145 add_settings_section(
146 'section_end',
147 '',
148 $this->get_method( 'render_settings_moved' ),
149 'media'
150 );
151
152 add_options_page(
153 __( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ),
154 esc_html__( 'TinyPNG', 'tiny-compress-images' ),
155 'manage_options',
156 'tinify',
157 array( $this, 'add_options_to_page' )
158 );
159 }
160
161 public function add_options_to_page() {
162 include __DIR__ . '/views/settings.php';
163 }
164
165 public function image_sizes_notice() {
166 check_ajax_referer( 'tiny-compress' );
167
168 if ( current_user_can( 'manage_options' ) ) {
169 $selected_sizes = isset( $_GET['image_sizes_selected'] ) ?
170 intval( $_GET['image_sizes_selected'] ) : 0;
171 $this->render_size_checkboxes_description(
172 $selected_sizes,
173 isset( $_GET['resize_original'] ),
174 isset( $_GET['compress_wr2x'] ),
175 self::get_conversion_enabled()
176 );
177 }
178 exit();
179 }
180
181 public function account_status() {
182 if ( current_user_can( 'manage_options' ) ) {
183 $this->render_account_status();
184 }
185 exit();
186 }
187
188 public function get_compressor() {
189 return $this->compressor;
190 }
191
192 public function set_compressor( $compressor ) {
193 $this->compressor = $compressor;
194 }
195
196 public function get_status() {
197 return intval( get_option( self::get_prefixed_name( 'status' ) ) );
198 }
199
200 public function disabled_required_functions() {
201 $required_functions = array( 'curl_exec' );
202 $disabled_required_functions = array();
203 $disabled_functions = explode( ',', ini_get( 'disable_functions' ) );
204
205 foreach ( $required_functions as $required_function ) {
206 if ( in_array( $required_function, $disabled_functions, true ) ) {
207 array_push( $disabled_required_functions, $required_function );
208 }
209 }
210
211 return $disabled_required_functions;
212 }
213
214 protected function get_api_key() {
215 if ( defined( 'TINY_API_KEY' ) ) {
216 return TINY_API_KEY;
217 } else {
218 return get_option( self::get_prefixed_name( 'api_key' ) );
219 }
220 }
221
222 protected function get_api_key_pending() {
223 if ( defined( 'TINY_API_KEY' ) ) {
224 return false;
225 } else {
226 return get_option( self::get_prefixed_name( 'api_key_pending' ) );
227 }
228 }
229
230 protected function clear_api_key_pending() {
231 delete_option( self::get_prefixed_name( 'api_key_pending' ) );
232 }
233
234 protected static function get_intermediate_size( $size ) {
235 /*
236 Inspired by
237 http://codex.wordpress.org/Function_Reference/get_intermediate_image_sizes */
238 global $_wp_additional_image_sizes;
239
240 $width = get_option( $size . '_size_w' );
241 $height = get_option( $size . '_size_h' );
242
243 /* Note: dimensions might be 0 to indicate no limit. */
244 if ( $width || $height ) {
245 return array( $width, $height );
246 }
247
248 if ( isset( $_wp_additional_image_sizes[ $size ] ) ) {
249 $sizes = $_wp_additional_image_sizes[ $size ];
250 return array(
251 isset( $sizes['width'] ) ? $sizes['width'] : null,
252 isset( $sizes['height'] ) ? $sizes['height'] : null,
253 );
254 }
255 return array( null, null );
256 }
257
258 /**
259 * Retrieves image sizes as a map of size and width, height and tinify meta data.
260 *
261 * The first entry will always be '0' (the original uploaded image), the second
262 * will always be 'original_unscaled' (the unscaled copy WordPress stores for images
263 * that exceed the big_image_size_threshold). Both entries share the same tinify setting.
264 *
265 * @return array<int|string, array{width: int|null, height: int|null, tinify: bool}>
266 */
267 public function get_sizes() {
268 if ( is_array( $this->sizes ) ) {
269 return $this->sizes;
270 }
271
272 $setting = get_option( self::get_prefixed_name( 'sizes' ) );
273
274 $size = Tiny_Image::ORIGINAL;
275 $original_tinify = ! is_array( $setting ) ||
276 ( isset( $setting[ $size ] ) && 'on' === $setting[ $size ] );
277 $this->sizes = array(
278 $size => array(
279 'width' => null,
280 'height' => null,
281 'tinify' => $original_tinify,
282 ),
283 Tiny_Image::ORIGINAL_UNSCALED => array(
284 'width' => null,
285 'height' => null,
286 'tinify' => $original_tinify,
287 ),
288 );
289
290 foreach ( get_intermediate_image_sizes() as $size ) {
291 if ( self::DUMMY_SIZE === $size ) {
292 continue;
293 }
294
295 list($width, $height) = self::get_intermediate_size( $size );
296 if ( $width || $height ) {
297 $this->sizes[ $size ] = array(
298 'width' => $width,
299 'height' => $height,
300 'tinify' => ! is_array( $setting ) ||
301 ( isset( $setting[ $size ] ) && 'on' === $setting[ $size ] ),
302 );
303 }
304 }
305
306 return $this->sizes;
307 }
308
309 public function get_active_tinify_sizes() {
310 if ( is_array( $this->tinify_sizes ) ) {
311 return $this->tinify_sizes;
312 }
313
314 $this->tinify_sizes = array();
315 foreach ( $this->get_sizes() as $size => $values ) {
316 if ( $values['tinify'] ) {
317 $this->tinify_sizes[] = $size;
318 }
319 }
320
321 return $this->tinify_sizes;
322 }
323
324 public function new_plugin_install() {
325 /* We merely have to check whether a newly added setting is already stored. */
326 $compression_timing = get_option( self::get_prefixed_name( 'compression_timing' ) );
327 return ! $compression_timing;
328 }
329
330 /**
331 * Checks if backup is enabled.
332 * backup is enabled when original will be compressed and setting is on.
333 *
334 * @return bool true if backup is enabled
335 */
336 public function get_backup_enabled() {
337 $sizes = $this->get_sizes();
338 if ( ! $sizes[ Tiny_Image::ORIGINAL ]['tinify'] ) {
339 return false;
340 }
341
342 $setting = get_option( self::get_prefixed_name( 'backup' ) );
343 return isset( $setting['enabled'] ) && 'on' === $setting['enabled'];
344 }
345
346 public function get_resize_enabled() {
347 /* This only applies if the original is being resized. */
348 $sizes = $this->get_sizes();
349 if ( ! $sizes[ Tiny_Image::ORIGINAL ]['tinify'] ) {
350 return false;
351 }
352
353 $setting = get_option( self::get_prefixed_name( 'resize_original' ) );
354 return isset( $setting['enabled'] ) && 'on' === $setting['enabled'];
355 }
356
357 public function get_compression_timing() {
358 $setting = get_option( self::get_prefixed_name( 'compression_timing' ) );
359 if ( isset( $setting ) && $setting ) {
360 return $setting;
361 } elseif ( $this->new_plugin_install() ) {
362 update_option( self::get_prefixed_name( 'compression_timing' ), 'background' );
363 return 'background';
364 } else {
365 update_option( self::get_prefixed_name( 'compression_timing' ), 'auto' );
366 return 'auto';
367 }
368 }
369
370 public function auto_compress_enabled() {
371 return $this->get_compression_timing() === 'auto' ||
372 $this->get_compression_timing() === 'background';
373 }
374
375 public function background_compress_enabled() {
376 return $this->get_compression_timing() === 'background';
377 }
378
379 public function get_preserve_enabled( $name ) {
380 $setting = get_option( self::get_prefixed_name( 'preserve_data' ) );
381 return isset( $setting[ $name ] ) && 'on' === $setting[ $name ];
382 }
383
384 /**
385 * Retrieves the preserve options for the original image
386 *
387 * @param string $size_name Name of the size
388 * @return array<string>|false false if size is not original, otherwise array of preserved keys
389 */
390 public function get_preserve_options( $size_name ) {
391 if ( ! Tiny_Image::is_original( $size_name ) &&
392 ! Tiny_Image::is_original_unscaled( $size_name )
393 ) {
394 return false;
395 }
396 $options = array();
397 $settings = get_option( self::get_prefixed_name( 'preserve_data' ) );
398 if ( $settings ) {
399 $keys = array_keys( $settings );
400 foreach ( $keys as &$key ) {
401 if ( 'on' === $settings[ $key ] ) {
402 array_push( $options, $key );
403 }
404 }
405 }
406 return $options;
407 }
408
409 public function get_resize_options( $size_name ) {
410 if ( ! Tiny_Image::is_original( $size_name ) ) {
411 return false;
412 }
413 if ( ! $this->get_resize_enabled() ) {
414 return false;
415 }
416 $setting = get_option( self::get_prefixed_name( 'resize_original' ) );
417 $width = intval( $setting['width'] );
418 $height = intval( $setting['height'] );
419 $method = $width > 0 && $height > 0 ? 'fit' : 'scale';
420 $options['method'] = $method;
421 if ( $width > 0 ) {
422 $options['width'] = $width;
423 }
424 if ( $height > 0 ) {
425 $options['height'] = $height;
426 }
427 return count( $options ) >= 2 ? $options : false;
428 }
429
430 /**
431 * Retrieves the configured settings for conversion.
432 *
433 * @return array{ convert: bool, convert_to: array{string} } The conversion options.
434 */
435 public function get_conversion_options() {
436 return array(
437 'convert' => $this->get_conversion_enabled(),
438 'convert_to' => $this->get_convertto_mimetype(),
439 );
440 }
441
442 /**
443 * Checks wether converting to optimized file format is enabled
444 *
445 * @return bool true if conversion is enabled, false otherwise
446 */
447 public function get_conversion_enabled() {
448 $conversion_enabled = self::get_convert_format_option( 'convert', 'off' );
449
450 return 'on' === $conversion_enabled;
451 }
452
453 /**
454 * Retrieve the mimetypes to convert to
455 *
456 * @return array{string} mimetypes to convert to
457 */
458 private function get_convertto_mimetype() {
459 $convert_to = self::get_convert_format_option( 'convert_to', 'smallest' );
460 if ( 'webp' == $convert_to ) {
461 return array( 'image/webp' );
462 }
463 if ( 'avif' == $convert_to ) {
464 return array( 'image/avif' );
465 }
466 return array( 'image/avif', 'image/webp' );
467 }
468
469 /**
470 * Retrieve the image delivery method.
471 *
472 * @return string The delivery method: 'picture' or 'htaccess'. Default is 'picture'.
473 */
474 public function get_conversion_delivery_method() {
475 return self::get_convert_format_option( 'delivery_method', 'picture' );
476 }
477
478 private function setup_incomplete_checks() {
479 if ( ! $this->get_api_key() ) {
480 $this->notices->api_key_missing_notice();
481 } elseif ( $this->get_api_key_pending() ) {
482 $this->notices->get_api_key_pending_notice();
483 }
484 }
485
486 public function render_settings_moved() {
487 echo '<div class="tinify-settings"><h3>';
488 esc_html_e( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' );
489 echo '</h3>';
490 $url = admin_url( 'options-general.php?page=tinify' );
491 $link = "<a href='" . $url . "'>";
492 $link .= esc_html__( 'settings', 'tiny-compress-images' );
493 $link .= '</a>';
494 printf(
495 wp_kses(
496 /* translators: %s: link saying settings */
497 __( 'The %s have moved.', 'tiny-compress-images' ),
498 array(
499 'a' => array(
500 'href' => array(),
501 ),
502 )
503 ),
504 wp_kses(
505 $link,
506 array(
507 'a' => array(
508 'href' => array(),
509 ),
510 )
511 )
512 );
513 echo '</div>';
514 }
515
516 public function render_compression_timing_settings() {
517 $heading = esc_html__(
518 'When should new images be compressed?',
519 'tiny-compress-images'
520 );
521 echo '<h4>' . esc_html( $heading ) . '</h4>';
522 echo '<div class="optimization-options">';
523
524 $name = self::get_prefixed_name( 'compression_timing' );
525 $compression_timing = $this->get_compression_timing();
526
527 $id = self::get_prefixed_name( 'background_compress_enabled' );
528 $checked = ( 'background' === $compression_timing );
529
530 $label = esc_html__(
531 'Compress new images in the background (Recommended)',
532 'tiny-compress-images'
533 );
534 $description = esc_html__(
535 'This is the fastest method, but can cause issues with some image related plugins.',
536 'tiny-compress-images'
537 );
538
539 $this->render_compression_timing_radiobutton(
540 $name,
541 $label,
542 $description,
543 'background',
544 $checked
545 );
546
547 $id = self::get_prefixed_name( 'auto_compress_enabled' );
548 $checked = ( 'auto' === $compression_timing );
549
550 $label = esc_html__(
551 'Compress new images during upload',
552 'tiny-compress-images'
553 );
554 $description = esc_html__(
555 'Uploads will take longer, but provides higher compatibility with other plugins.',
556 'tiny-compress-images'
557 );
558
559 $this->render_compression_timing_radiobutton(
560 $name,
561 $label,
562 $description,
563 'auto',
564 $checked
565 );
566
567 $id = self::get_prefixed_name( 'auto_compress_disabled' );
568 $checked = ( 'manual' === $compression_timing );
569
570 $label = esc_html__(
571 'Do not compress new images automatically',
572 'tiny-compress-images'
573 );
574 $description = esc_html__(
575 'Manually select the images you want to compress in the media library.',
576 'tiny-compress-images'
577 );
578
579 $this->render_compression_timing_radiobutton(
580 $name,
581 $label,
582 $description,
583 'manual',
584 $checked
585 );
586
587 echo '</div>';
588 }
589
590 public function render_sizes() {
591 $dummy_size_name = self::get_prefixed_name( 'sizes[' . self::DUMMY_SIZE . ']' );
592 echo '<input type="hidden" name="' .
593 esc_attr( $dummy_size_name ) . '" value="on"/>';
594
595 foreach ( $this->get_sizes() as $size => $option ) {
596 if ( Tiny_Image::is_original_unscaled( $size ) ) {
597 // unscaled is selected implicitly by original size
598 continue;
599 }
600 $this->render_size_checkboxes( $size, $option );
601 }
602 if ( self::wr2x_active() ) {
603 $this->render_size_checkboxes( 'wr2x', $this->get_wr2x_option() );
604 }
605 echo '<br>';
606 echo '<div id="tiny-image-sizes-notice">';
607
608 $this->render_size_checkboxes_description(
609 count( self::get_active_tinify_sizes() ),
610 self::get_resize_enabled(),
611 self::compress_wr2x_images(),
612 self::get_conversion_enabled()
613 );
614
615 echo '</div>';
616 }
617
618 private function render_size_checkboxes( $size, $option ) {
619 $id = self::get_prefixed_name( "sizes_$size" );
620 $name = self::get_prefixed_name( 'sizes[' . $size . ']' );
621 $checked = ! empty( $option['tinify'] );
622 if ( Tiny_Image::is_original( $size ) ) {
623 $label = esc_html__( 'Original image', 'tiny-compress-images' ) . ' (' .
624 esc_html__(
625 'overwritten by compressed image',
626 'tiny-compress-images'
627 ) . ')';
628 } elseif ( Tiny_Image::is_retina( $size ) ) {
629 $label = esc_html__( 'WP Retina 2x sizes', 'tiny-compress-images' );
630 } else {
631 $width = $option['width'];
632 if ( ! $width ) {
633 $width = '?';
634 }
635
636 $height = $option['height'];
637 if ( ! $height ) {
638 $height = '?';
639 }
640
641 $label = esc_html( ucfirst( str_replace( '_', ' ', $size ) ) )
642 . ' - ' . $width . 'x' . $height;
643 }
644 echo '<p>';
645 echo '<input type="checkbox" id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) .
646 '" value="on"' . checked( $checked, true, false ) . '/>';
647 echo '<label for="' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
648 echo '</p>';
649 }
650
651 public function render_size_checkboxes_description(
652 $active_sizes_count,
653 $resize_original_enabled,
654 $compress_wr2x,
655 $conversion_enabled
656 ) {
657 echo '<p>';
658 esc_html_e(
659 'Remember each selected size counts as a compression.',
660 'tiny-compress-images'
661 );
662 echo '</p>';
663 echo '<p>';
664 if ( $resize_original_enabled ) {
665 ++$active_sizes_count;
666 }
667 if ( $compress_wr2x ) {
668 $active_sizes_count *= 2;
669 }
670
671 if ( $conversion_enabled ) {
672 $active_sizes_count *= 2;
673 }
674
675 if ( $active_sizes_count < 1 ) {
676 esc_html_e(
677 'With these settings no images will be compressed.',
678 'tiny-compress-images'
679 );
680 } else {
681 $free_images_per_month = floor(
682 Tiny_Config::MONTHLY_FREE_COMPRESSIONS / $active_sizes_count
683 );
684
685 $strong = array(
686 'strong' => array(),
687 );
688
689 printf(
690 wp_kses(
691 /* translators: %1$s: number of images */
692 __(
693 // phpcs:ignore Generic.Files.LineLength
694 'With these settings you can compress <strong>at least %1$s images</strong> for free each month.',
695 'tiny-compress-images'
696 ),
697 $strong
698 ),
699 esc_html( $free_images_per_month )
700 );
701
702 if ( self::wr2x_active() ) {
703 echo '</p>';
704 echo '<p>';
705 esc_html_e(
706 'If selected, retina sizes will be compressed when generated by WP Retina 2x',
707 'tiny-compress-images'
708 );
709 echo '<br>';
710 esc_html_e(
711 'Each retina size will count as an additional compression.',
712 'tiny-compress-images'
713 );
714 }
715 } // End if().
716 echo '</p>';
717 }
718
719 public function render_compression_timing_radiobutton(
720 $name,
721 $label,
722 $desc,
723 $value,
724 $checked
725 ) {
726 $as3cf_local_files_present = Tiny_AS3CF::is_active()
727 && Tiny_AS3CF::remove_local_files_setting_enabled();
728 if ( 'background' == $value && $as3cf_local_files_present && $checked ) {
729 echo '<div class="notice notice-warning inline"><p>';
730 echo '<strong>' . esc_html__( 'Warning', 'tiny-compress-images' ) . '</strong> — ';
731 $message = esc_html__(
732 // phpcs:ignore Generic.Files.LineLength
733 'For compression to work you will need to configure WP Offload S3 to keep a copy of the images on the server.',
734 'tiny-compress-images'
735 );
736 echo esc_html( $message );
737 echo '</p></div>';
738 echo '<p class="tiny-radio disabled">';
739 } else {
740 echo '<p class="tiny-radio">';
741 }
742
743 $id = sprintf( self::get_prefixed_name( 'compression_timing_%s' ), $value );
744 $label = esc_html( $label );
745 $desc = esc_html( $desc );
746 echo '<input type="radio" id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) .
747 '" value="' . esc_attr( $value ) . '"' . checked( $checked, true, false ) . '/>';
748 echo '<label for="' . esc_attr( $id ) . '">' . esc_html( $label ) . '</label>';
749 echo '<br>';
750 echo '<span>' . esc_html( $desc ) . '</span>';
751 echo '</p>';
752 }
753
754 public function render_preserve_input( $name, $description ) {
755 $data = array(
756 'id' => sprintf( self::get_prefixed_name( 'preserve_data_%s' ), $name ),
757 'field' => sprintf( self::get_prefixed_name( 'preserve_data[%s]' ), $name ),
758 'checked' => $this->get_preserve_enabled( $name ),
759 'label' => $description,
760 );
761 include plugin_dir_path( __FILE__ ) . 'views/settings-original-image-preserve.php';
762 }
763
764 public function render_resize_input( $name ) {
765 $settings = get_option( self::get_prefixed_name( 'resize_original' ) );
766 $data = array(
767 'id' => sprintf( self::get_prefixed_name( 'resize_original_%s' ), $name ),
768 'field' => sprintf( self::get_prefixed_name( 'resize_original[%s]' ), $name ),
769 'value' => isset( $settings[ $name ] ) ? $settings[ $name ] : '2048',
770 );
771 include plugin_dir_path( __FILE__ ) . 'views/settings-original-image-original.php';
772 }
773
774 public function get_compression_count() {
775 $field = self::get_prefixed_name( 'status' );
776 return get_option( $field );
777 }
778
779 public function limit_reached() {
780 $this->compressor->get_compression_count();
781 return $this->compressor->limit_reached();
782 }
783
784 public function get_remaining_credits() {
785 $field = self::get_prefixed_name( 'remaining_credits' );
786 return get_option( $field );
787 }
788
789 public function get_paying_state() {
790 $field = self::get_prefixed_name( 'paying_state' );
791 return get_option( $field );
792 }
793
794 public function is_on_free_plan() {
795 return self::get_paying_state() === 'free';
796 }
797
798 public function get_email_address() {
799 $field = self::get_prefixed_name( 'email_address' );
800 return get_option( $field );
801 }
802
803 public function after_compress_callback( $compressor ) {
804 $count = $compressor->get_compression_count();
805 if ( ! is_null( $count ) ) {
806 $field = self::get_prefixed_name( 'status' );
807 update_option( $field, $count );
808 }
809 $remaining_credits = $compressor->get_remaining_credits();
810 if ( ! is_null( $remaining_credits ) ) {
811 $field = self::get_prefixed_name( 'remaining_credits' );
812 update_option( $field, $remaining_credits );
813 }
814 $paying_state = $compressor->get_paying_state();
815 if ( ! is_null( $paying_state ) ) {
816 $field = self::get_prefixed_name( 'paying_state' );
817 update_option( $field, $paying_state );
818 }
819 $email_address = $compressor->get_email_address();
820 if ( ! is_null( $email_address ) ) {
821 $field = self::get_prefixed_name( 'email_address' );
822 update_option( $field, $email_address );
823 }
824 if ( $compressor->limit_reached() ) {
825 $this->notices->add_limit_reached_notice( $email_address );
826 } else {
827 $this->notices->remove( 'limit-reached' );
828 }
829 }
830
831 public function render_account_status() {
832 $key = $this->get_api_key();
833 if ( empty( $key ) ) {
834 $compressor = $this->get_compressor();
835 if ( $compressor->can_create_key() ) {
836 include __DIR__ . '/views/account-status-create-advanced.php';
837 } else {
838 include __DIR__ . '/views/account-status-create-simple.php';
839 }
840 } else {
841 $status = $this->compressor->get_status();
842 $status->pending = false;
843 if ( $status->ok ) {
844 if ( $this->get_api_key_pending() ) {
845 $this->clear_api_key_pending();
846 }
847 } elseif ( $this->get_api_key_pending() ) {
848 $status->ok = true;
849 $status->pending = true;
850 $status->message = (
851 'An email has been sent to activate your account'
852 );
853 }
854 include __DIR__ . '/views/account-status-connected.php';
855 }
856 }
857
858 public function render_pending_status() {
859 $key = $this->get_api_key();
860 if ( empty( $key ) ) {
861 $compressor = $this->get_compressor();
862 if ( $compressor->can_create_key() ) {
863 include __DIR__ . '/views/account-status-create-advanced.php';
864 } else {
865 include __DIR__ . '/views/account-status-create-simple.php';
866 }
867 } else {
868 include __DIR__ . '/views/account-status-loading.php';
869 }
870 }
871
872 public function create_api_key() {
873 check_ajax_referer( 'tiny-compress', '_nonce' );
874
875 $compressor = $this->get_compressor();
876 if ( ! current_user_can( 'manage_options' ) ) {
877 $status = (object) array(
878 'ok' => false,
879 'message' => 'This feature requires certain user capabilities',
880 );
881 } elseif ( $compressor->can_create_key() ) {
882 if ( empty( $_POST['name'] ) ) {
883 $status = (object) array(
884 'ok' => false,
885 'message' => __(
886 'Please enter your name',
887 'tiny-compress-images'
888 ),
889 );
890 echo json_encode( $status );
891 exit();
892 }
893
894 if ( empty( $_POST['email'] ) ) {
895 $status = (object) array(
896 'ok' => false,
897 'message' => __(
898 'Please enter your email address',
899 'tiny-compress-images'
900 ),
901 );
902 echo json_encode( $status );
903 exit();
904 }
905
906 try {
907 $site = str_replace(
908 array( 'http://', 'https://' ),
909 '',
910 get_bloginfo( 'url' )
911 );
912 $identifier = 'WordPress plugin for ' . $site;
913 $link = $this->get_absolute_url();
914 $compressor->create_key(
915 sanitize_email( wp_unslash( $_POST['email'] ) ),
916 array(
917 'name' => sanitize_text_field( wp_unslash( $_POST['name'] ) ),
918 'identifier' => $identifier,
919 'link' => $link,
920 )
921 );
922
923 update_option( self::get_prefixed_name( 'api_key_pending' ), true );
924 update_option( self::get_prefixed_name( 'api_key' ), $compressor->get_key() );
925 update_option( self::get_prefixed_name( 'status' ), 0 );
926
927 $status = (object) array(
928 'ok' => true,
929 'message' => null,
930 );
931 } catch ( Tiny_Exception $err ) {
932 list($message) = explode( ' (HTTP', $err->getMessage(), 2 );
933 $status = (object) array(
934 'ok' => false,
935 'message' => $message,
936 );
937 }
938 } else {
939 $status = (object) array(
940 'ok' => false,
941 'message' => 'This feature is not available on your platform',
942 );
943 } // End if().
944
945 echo json_encode( $status );
946 exit();
947 }
948
949 public function update_api_key() {
950 check_ajax_referer( 'tiny-compress', '_nonce' );
951
952 $key = null;
953 if ( ! current_user_can( 'manage_options' ) ) {
954 $status = (object) array(
955 'ok' => false,
956 'message' => 'This feature requires certain user capabilities',
957 );
958 } elseif ( empty( $_POST['key'] ) ) {
959 /* Always save if key is blank, so the key can be deleted. */
960 $status = (object) array(
961 'ok' => true,
962 'message' => null,
963 );
964 } else {
965 $key = sanitize_text_field( wp_unslash( $_POST['key'] ) );
966 $status = Tiny_Compress::create( $key )->get_status();
967 }
968
969 if ( $status->ok ) {
970 update_option( self::get_prefixed_name( 'api_key_pending' ), false );
971 update_option( self::get_prefixed_name( 'api_key' ), $key );
972 }
973 echo json_encode( $status );
974 exit();
975 }
976
977 public static function wr2x_active() {
978 return function_exists( 'wr2x_get_retina' );
979 }
980
981 public function get_wr2x_option() {
982 $setting = get_option( self::get_prefixed_name( 'sizes' ) );
983 return array(
984 'width' => null,
985 'height' => null,
986 'tinify' => ( isset( $setting['wr2x'] ) && 'on' === $setting['wr2x'] ),
987 );
988 }
989
990 public function compress_wr2x_images() {
991 $option = $this->get_wr2x_option();
992 return self::wr2x_active() && $option['tinify'];
993 }
994
995
996 public function render_format_conversion() {
997 include __DIR__ . '/views/settings-conversion.php';
998 }
999
1000 private static function render_radiobutton(
1001 $group_name,
1002 $option_id,
1003 $option_value,
1004 $current_value,
1005 $label,
1006 $descr
1007 ) {
1008 $checked = ( $current_value === $option_value );
1009 echo '<p class="tiny-radio">';
1010 echo '<input type="radio" data-testid="' . esc_attr( $option_id ) . '" ';
1011 echo 'id="' . esc_attr( $option_id ) . '" name="' . esc_attr( $group_name ) .
1012 '" value="' . esc_attr( $option_value ) . '"' . checked( $checked, true, false ) . '/>';
1013 echo '<label for="' . esc_attr( $option_id ) . '">' . esc_html( $label );
1014 echo '<span>' . esc_html( $descr ) . '</span>';
1015 echo '</label>';
1016 echo '</p>';
1017 }
1018
1019
1020 /**
1021 * @return bool true if apache with mod_rewrite loaded
1022 */
1023 private static function can_render_delivery_method() {
1024 global $is_apache;
1025 if ( ! $is_apache ) {
1026 return false;
1027 }
1028
1029 if (
1030 ! function_exists( 'apache_mod_loaded' ) ||
1031 ! function_exists( 'apache_get_modules' )
1032 ) {
1033 return false;
1034 }
1035
1036 $modules = apache_get_modules();
1037 return in_array( 'mod_rewrite', $modules, true );
1038 }
1039
1040 /**
1041 * If possible, render the delivery method settings view.
1042 */
1043 public function render_delivery_method() {
1044 if ( ! self::can_render_delivery_method() ) {
1045 return;
1046 }
1047
1048 include __DIR__ . '/views/settings-conversion-delivery.php';
1049 }
1050
1051 private static function get_convert_format_option( $option, $default_value ) {
1052 $setting = get_option( self::get_prefixed_name( 'convert_format' ) );
1053 if ( isset( $setting[ $option ] ) && $setting[ $option ] ) {
1054 return $setting[ $option ];
1055 }
1056 return $default_value;
1057 }
1058 }
1059