PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / 3.6.8
TinyPNG – JPEG, PNG & WebP image compression v3.6.8
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-plugin.php
tiny-compress-images / src Last commit date
compatibility 5 months ago config 5 months ago css 5 months ago data 4 years ago images 4 years ago js 5 months ago vendor 1 year ago views 5 months ago class-tiny-bulk-optimization.php 5 months ago class-tiny-cli.php 5 months ago class-tiny-compress-client.php 5 months ago class-tiny-compress-fopen.php 5 months ago class-tiny-compress.php 5 months ago class-tiny-diagnostics.php 5 months ago class-tiny-exception.php 5 months ago class-tiny-helpers.php 5 months ago class-tiny-image-size.php 5 months ago class-tiny-image.php 5 months ago class-tiny-logger.php 5 months ago class-tiny-notices.php 5 months ago class-tiny-php.php 5 months ago class-tiny-picture.php 5 months ago class-tiny-plugin.php 5 months ago class-tiny-settings.php 5 months ago class-tiny-source-base.php 5 months ago class-tiny-source-image.php 5 months ago class-tiny-source-picture.php 5 months ago class-tiny-wp-base.php 5 months ago
class-tiny-plugin.php
901 lines
1 <?php
2 /*
3 * Tiny Compress Images - WordPress plugin.
4 * Copyright (C) 2015-2023 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_Plugin extends Tiny_WP_Base {
21 const VERSION = '3.6.8';
22 const MEDIA_COLUMN = self::NAME;
23 const DATETIME_FORMAT = 'Y-m-d G:i:s';
24
25 private static $version;
26
27 private $settings;
28 private $twig;
29
30 public static function jpeg_quality() {
31 return 85;
32 }
33
34 public static function version() {
35 /* Avoid using get_plugin_data() because it is not loaded early enough
36 in xmlrpc.php. */
37 return self::VERSION;
38 }
39
40 public function __construct() {
41 parent::__construct();
42 $this->settings = new Tiny_Settings();
43 }
44
45 public function set_compressor( $compressor ) {
46 $this->settings->set_compressor( $compressor );
47 }
48
49 public function init() {
50 add_filter(
51 'jpeg_quality',
52 $this->get_static_method( 'jpeg_quality' )
53 );
54
55 add_filter(
56 'wp_editor_set_quality',
57 $this->get_static_method( 'jpeg_quality' )
58 );
59
60 add_filter(
61 'wp_generate_attachment_metadata',
62 $this->get_method( 'process_attachment' ),
63 10,
64 2
65 );
66
67 add_action( 'delete_attachment', $this->get_method( 'clean_attachment' ), 10, 2 );
68
69 load_plugin_textdomain(
70 self::NAME,
71 false,
72 dirname( plugin_basename( __FILE__ ) ) . '/languages'
73 );
74
75 if ( $this->settings->get_conversion_enabled() ) {
76 /**
77 * Controls wether the page should replace <img> with <picture> elements
78 * converted sources.
79 *
80 * @since 3.7.0
81 */
82 $should_replace = apply_filters( 'tiny_replace_with_picture', true );
83 if ( $should_replace ) {
84 new Tiny_Picture( ABSPATH, array( get_site_url() ) );
85 }
86 }
87 }
88
89 public function cli_init() {
90 Tiny_CLI::register_command( $this->settings );
91 }
92
93 public function ajax_init() {
94 add_filter(
95 'wp_ajax_tiny_async_optimize_upload_new_media',
96 $this->get_method( 'compress_on_upload' )
97 );
98
99 add_action(
100 'wp_ajax_tiny_compress_image_from_library',
101 $this->get_method( 'compress_image_from_library' )
102 );
103
104 add_action(
105 'wp_ajax_tiny_compress_image_for_bulk',
106 $this->get_method( 'compress_image_for_bulk' )
107 );
108
109 add_action(
110 'wp_ajax_tiny_get_optimization_statistics',
111 $this->get_method( 'ajax_optimization_statistics' )
112 );
113
114 add_action(
115 'wp_ajax_tiny_get_compression_status',
116 $this->get_method( 'ajax_compression_status' )
117 );
118
119 add_action(
120 'wp_ajax_tiny_mark_image_as_compressed',
121 $this->get_method( 'mark_image_as_compressed' )
122 );
123
124 /* When touching any functionality linked to image compressions when
125 uploading images make sure it also works with XML-RPC. See README. */
126 add_filter(
127 'wp_ajax_nopriv_tiny_rpc',
128 $this->get_method( 'process_rpc_request' )
129 );
130
131 if ( $this->settings->compress_wr2x_images() ) {
132 add_action(
133 'wr2x_upload_retina',
134 $this->get_method( 'compress_original_retina_image' ),
135 10,
136 2
137 );
138
139 add_action(
140 'wr2x_retina_file_added',
141 $this->get_method( 'compress_retina_image' ),
142 10,
143 3
144 );
145
146 add_action(
147 'wr2x_retina_file_removed',
148 $this->get_method( 'remove_retina_image' ),
149 10,
150 2
151 );
152 }
153 }
154
155 public function admin_init() {
156 add_action(
157 'wp_dashboard_setup',
158 $this->get_method( 'add_dashboard_widget' )
159 );
160
161 add_action(
162 'admin_enqueue_scripts',
163 $this->get_method( 'enqueue_scripts' )
164 );
165
166 add_action(
167 'admin_action_tiny_bulk_action',
168 $this->get_method( 'media_library_bulk_action' )
169 );
170
171 add_action(
172 'admin_action_-1',
173 $this->get_method( 'media_library_bulk_action' )
174 );
175
176 add_action(
177 'admin_action_tiny_bulk_mark_compressed',
178 $this->get_method( 'media_library_bulk_action' )
179 );
180
181 add_filter(
182 'manage_media_columns',
183 $this->get_method( 'add_media_columns' )
184 );
185
186 add_action(
187 'manage_media_custom_column',
188 $this->get_method( 'render_media_column' ),
189 10,
190 2
191 );
192
193 add_action(
194 'attachment_submitbox_misc_actions',
195 $this->get_method( 'show_media_info' )
196 );
197
198 $plugin = plugin_basename(
199 dirname( __DIR__ ) . '/tiny-compress-images.php'
200 );
201
202 add_filter(
203 "plugin_action_links_$plugin",
204 $this->get_method( 'add_plugin_links' )
205 );
206
207 $this->tiny_compatibility();
208
209 add_thickbox();
210 Tiny_Logger::init();
211 }
212
213 public function admin_menu() {
214 add_media_page(
215 __( 'Bulk Optimization', 'tiny-compress-images' ),
216 esc_html__( 'Bulk TinyPNG', 'tiny-compress-images' ),
217 'upload_files',
218 'tiny-bulk-optimization',
219 $this->get_method( 'render_bulk_optimization_page' )
220 );
221 }
222
223 public function add_plugin_links( $current_links ) {
224 $additional = array(
225 'settings' => sprintf(
226 '<a href="options-general.php?page=tinify">%s</a>',
227 esc_html__( 'Settings', 'tiny-compress-images' )
228 ),
229 'bulk' => sprintf(
230 '<a href="upload.php?page=tiny-bulk-optimization">%s</a>',
231 esc_html__( 'Bulk TinyPNG', 'tiny-compress-images' )
232 ),
233 );
234 return array_merge( $additional, $current_links );
235 }
236
237 public function tiny_compatibility() {
238 if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
239 $tiny_wpml_compatibility = new Tiny_WPML();
240 }
241
242 if ( Tiny_AS3CF::is_active() ) {
243 $tiny_as3cf = new Tiny_AS3CF( $this->settings );
244 }
245 }
246
247 public function compress_original_retina_image( $attachment_id, $path ) {
248 $tiny_image = new Tiny_Image( $this->settings, $attachment_id );
249 $tiny_image->compress_retina( 'original_wr2x', $path );
250 }
251
252 public function compress_retina_image( $attachment_id, $path, $size_name ) {
253 $tiny_image = new Tiny_Image( $this->settings, $attachment_id );
254 $tiny_image->compress_retina( $size_name . '_wr2x', $path );
255 }
256
257 public function remove_retina_image( $attachment_id, $path ) {
258 $tiny_image = new Tiny_Image( $this->settings, $attachment_id );
259 $tiny_image->remove_retina_metadata();
260 }
261
262 public function enqueue_scripts( $hook ) {
263 wp_enqueue_style(
264 self::NAME . '_admin',
265 plugins_url( '/css/admin.css', __FILE__ ),
266 array(),
267 self::version()
268 );
269
270 wp_enqueue_style(
271 self::NAME . '_chart',
272 plugins_url( '/css/optimization-chart.css', __FILE__ ),
273 array(),
274 self::version()
275 );
276
277 wp_register_script(
278 self::NAME . '_admin',
279 plugins_url( '/js/admin.js', __FILE__ ),
280 array(),
281 self::version(),
282 true
283 );
284
285 // WordPress < 3.3 does not handle multidimensional arrays
286 wp_localize_script(
287 self::NAME . '_admin',
288 'tinyCompress',
289 array(
290 'nonce' => wp_create_nonce( 'tiny-compress' ),
291 'wpVersion' => self::wp_version(),
292 'pluginVersion' => self::version(),
293 'L10nAllDone' => __(
294 'All images are processed',
295 'tiny-compress-images'
296 ),
297 'L10nNoActionTaken' => __(
298 'No action taken',
299 'tiny-compress-images'
300 ),
301 'L10nDuplicate' => __(
302 'Image was already processed',
303 'tiny-compress-images'
304 ),
305 'L10nBulkAction' => __( 'Compress Images', 'tiny-compress-images' ),
306 'L10nBulkMarkCompressed' => __(
307 'Mark as Compressed',
308 'tiny-compress-images'
309 ),
310 'L10nCancelled' => __( 'Cancelled', 'tiny-compress-images' ),
311 'L10nCompressing' => __( 'Compressing', 'tiny-compress-images' ),
312 'L10nCompressed' => __( 'compressed', 'tiny-compress-images' ),
313 'L10nConverted' => __( 'converted', 'tiny-compress-images' ),
314 'L10nFile' => __( 'File', 'tiny-compress-images' ),
315 'L10nSizesOptimized' => __(
316 'Sizes optimized',
317 'tiny-compress-images'
318 ),
319 'L10nInitialSize' => __( 'Initial size', 'tiny-compress-images' ),
320 'L10nCurrentSize' => __( 'Current size', 'tiny-compress-images' ),
321 'L10nSavings' => __( 'Savings', 'tiny-compress-images' ),
322 'L10nStatus' => __( 'Status', 'tiny-compress-images' ),
323 'L10nShowMoreDetails' => __(
324 'Show more details',
325 'tiny-compress-images'
326 ),
327 'L10nError' => __( 'Error', 'tiny-compress-images' ),
328 'L10nLatestError' => __( 'Latest error', 'tiny-compress-images' ),
329 'L10nInternalError' => __( 'Internal error', 'tiny-compress-images' ),
330 'L10nOutOf' => __( 'out of', 'tiny-compress-images' ),
331 'L10nWaiting' => __( 'Waiting', 'tiny-compress-images' ),
332 )
333 );
334
335 wp_enqueue_script( self::NAME . '_admin' );
336
337 if ( 'media_page_tiny-bulk-optimization' == $hook ) {
338 wp_enqueue_style(
339 self::NAME . '_tiny_bulk_optimization',
340 plugins_url( '/css/bulk-optimization.css', __FILE__ ),
341 array(),
342 self::version()
343 );
344
345 wp_enqueue_style(
346 self::NAME . '_chart',
347 plugins_url( '/css/optimization-chart.css', __FILE__ ),
348 array(),
349 self::version()
350 );
351
352 wp_register_script(
353 self::NAME . '_tiny_bulk_optimization',
354 plugins_url( '/js/bulk-optimization.js', __FILE__ ),
355 array(),
356 self::version(),
357 true
358 );
359
360 wp_enqueue_script( self::NAME . '_tiny_bulk_optimization' );
361 }
362 }
363
364 public function process_attachment( $metadata, $attachment_id ) {
365 if ( $this->settings->auto_compress_enabled() ) {
366 if (
367 $this->settings->background_compress_enabled()
368 ) {
369 $this->async_compress_on_upload( $metadata, $attachment_id );
370 } else {
371 return $this->blocking_compress_on_upload( $metadata, $attachment_id );
372 }
373 }
374
375 return $metadata;
376 }
377
378 public function blocking_compress_on_upload( $metadata, $attachment_id ) {
379 if ( ! empty( $metadata ) ) {
380 $tiny_image = new Tiny_Image( $this->settings, $attachment_id, $metadata );
381
382 Tiny_Logger::debug(
383 'blocking compress on upload',
384 array(
385 'image_id' => $attachment_id,
386 )
387 );
388
389 $result = $tiny_image->compress();
390 return $tiny_image->get_wp_metadata();
391 } else {
392 return $metadata;
393 }
394 }
395
396 public function async_compress_on_upload( $metadata, $attachment_id ) {
397 $context = 'wp';
398 $action = 'tiny_async_optimize_upload_new_media';
399 $_ajax_nonce = wp_create_nonce( 'new_media-' . $attachment_id );
400 $body = compact( 'action', '_ajax_nonce', 'metadata', 'attachment_id', 'context' );
401
402 $args = array(
403 'timeout' => 0.01,
404 'blocking' => false,
405 'body' => $body,
406 'cookies' => isset( $_COOKIE ) && is_array( $_COOKIE ) ? $_COOKIE : array(),
407 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
408 );
409
410 if ( defined( 'XMLRPC_REQUEST' ) && get_current_user_id() ) {
411 /* We generate a hash to be used for the transient we use to store the current user. */
412 $rpc_hash = md5( maybe_serialize( $body ) );
413
414 $args['body']['tiny_rpc_action'] = $args['body']['action'];
415 /* We set a different action to make sure that all RPC requests are first validated. */
416 $args['body']['action'] = 'tiny_rpc';
417 $args['body']['tiny_rpc_hash'] = $rpc_hash;
418 $args['body']['tiny_rpc_nonce'] = wp_create_nonce( 'tiny_rpc_' . $rpc_hash );
419
420 /*
421 We can't use cookies here, so we save the user id in a transient
422 so that we can retrieve it again when processing the RPC request.
423 We should be able to use a relatively short timeout, as the request
424 should be processed directly afterwards.
425 */
426 set_transient( 'tiny_rpc_' . $rpc_hash, get_current_user_id(), 10 );
427 }
428
429 Tiny_Logger::debug(
430 'remote post',
431 array(
432 'image_id' => $attachment_id,
433 )
434 );
435
436 if ( getenv( 'WORDPRESS_HOST' ) !== false ) {
437 wp_remote_post( getenv( 'WORDPRESS_HOST' ) . '/wp-admin/admin-ajax.php', $args );
438 } else {
439 wp_remote_post( admin_url( 'admin-ajax.php' ), $args );
440 }
441 }
442
443 public function process_rpc_request() {
444 if (
445 empty( $_POST['tiny_rpc_action'] ) ||
446 empty( $_POST['tiny_rpc_hash'] ) ||
447 32 !== strlen( $_POST['tiny_rpc_hash'] )
448 ) {
449 exit();
450 }
451
452 $rpc_hash = sanitize_key( $_POST['tiny_rpc_hash'] );
453 $user_id = absint( get_transient( 'tiny_rpc_' . $rpc_hash ) );
454 $user = $user_id ? get_userdata( $user_id ) : false;
455
456 /* We no longer need the transient. */
457 delete_transient( 'tiny_rpc_' . $rpc_hash );
458
459 if ( ! $user || ! $user->exists() ) {
460 exit();
461 }
462 wp_set_current_user( $user_id );
463
464 if ( ! check_ajax_referer( 'tiny_rpc_' . $rpc_hash, 'tiny_rpc_nonce', false ) ) {
465 exit();
466 }
467
468 /* Now that everything is checked, perform the actual action. */
469 $action = $_POST['tiny_rpc_action'];
470 unset(
471 $_POST['action'],
472 $_POST['tiny_rpc_action'],
473 $_POST['tiny_rpc_id'],
474 $_POST['tiny_rpc_nonce']
475 );
476 do_action( 'wp_ajax_' . $action );
477 }
478
479 public function compress_on_upload() {
480 if ( ! wp_verify_nonce( $_POST['_ajax_nonce'], 'new_media-' . $_POST['attachment_id'] ) ) {
481 exit;
482 }
483 if ( current_user_can( 'upload_files' ) ) {
484 $attachment_id = intval( $_POST['attachment_id'] );
485 $metadata = $_POST['metadata'];
486 if ( is_array( $metadata ) ) {
487 $tiny_image = new Tiny_Image( $this->settings, $attachment_id, $metadata );
488
489 Tiny_Logger::debug(
490 'compress on upload',
491 array(
492 'image_id' => $attachment_id,
493 )
494 );
495
496 $result = $tiny_image->compress();
497 // The wp_update_attachment_metadata call is thrown because the
498 // dimensions of the original image can change. This will then
499 // trigger other plugins and can result in unexpected behaviour and
500 // further changes to the image. This may require another approach.
501 // Note that as of WP 5.3 it is advised to not hook into this filter
502 // anymore, so other plugins are less likely to be triggered.
503 wp_update_attachment_metadata( $attachment_id, $tiny_image->get_wp_metadata() );
504 }
505 }
506 exit();
507 }
508
509 /**
510 * Validates AJAX request for attachment operations.
511 *
512 * @since 3.0.0
513 *
514 * @return array Either error array ['error' => 'message']
515 * or success array ['data' => [$id, $metadata]]
516 */
517 private function validate_ajax_attachment_request() {
518 if ( ! $this->check_ajax_referer() ) {
519 exit();
520 }
521 if ( ! current_user_can( 'upload_files' ) ) {
522 return array(
523 'error' => esc_html__(
524 "You don't have permission to upload files.",
525 'tiny-compress-images'
526 ),
527 );
528 }
529 if ( empty( $_POST['id'] ) ) {
530 return array(
531 'error' => esc_html__(
532 'Not a valid media file.',
533 'tiny-compress-images'
534 ),
535 );
536 }
537 $id = intval( $_POST['id'] );
538 $metadata = wp_get_attachment_metadata( $id );
539 if ( ! is_array( $metadata ) ) {
540 return array(
541 'error' => esc_html__(
542 'Could not find metadata of media file.',
543 'tiny-compress-images'
544 ),
545 );
546 }
547
548 return array(
549 'data' => array( $id, $metadata ),
550 );
551 }
552
553 public function compress_image_from_library() {
554 $response = $this->validate_ajax_attachment_request();
555 if ( isset( $response['error'] ) ) {
556 echo $response['error'];
557 exit();
558 }
559 list($id, $metadata) = $response['data'];
560
561 Tiny_Logger::debug(
562 'compress from library',
563 array(
564 'image_id' => $id,
565 )
566 );
567
568 $tiny_image = new Tiny_Image( $this->settings, $id, $metadata );
569 $result = $tiny_image->compress();
570
571 // The wp_update_attachment_metadata call is thrown because the
572 // dimensions of the original image can change. This will then
573 // trigger other plugins and can result in unexpected behaviour and
574 // further changes to the image. This may require another approach.
575 // Note that as of WP 5.3 it is advised to not hook into this filter
576 // anymore, so other plugins are less likely to be triggered.
577 wp_update_attachment_metadata( $id, $tiny_image->get_wp_metadata() );
578
579 echo $this->render_compress_details( $tiny_image );
580
581 exit();
582 }
583
584 public function compress_image_for_bulk() {
585 $response = $this->validate_ajax_attachment_request();
586 if ( isset( $response['error'] ) ) {
587 echo json_encode( $response );
588 exit();
589 }
590
591 list($id, $metadata) = $response['data'];
592 $tiny_image_before = new Tiny_Image( $this->settings, $id, $metadata );
593 $image_statistics_before = $tiny_image_before->get_statistics(
594 $this->settings->get_sizes(),
595 $this->settings->get_active_tinify_sizes()
596 );
597 $size_before = $image_statistics_before['compressed_total_size'];
598
599 $tiny_image = new Tiny_Image( $this->settings, $id, $metadata );
600
601 Tiny_Logger::debug(
602 'compress from bulk',
603 array(
604 'image_id' => $id,
605 )
606 );
607
608 $result = $tiny_image->compress();
609 $image_statistics = $tiny_image->get_statistics(
610 $this->settings->get_sizes(),
611 $this->settings->get_active_tinify_sizes()
612 );
613 wp_update_attachment_metadata( $id, $tiny_image->get_wp_metadata() );
614
615 $current_library_size = intval( $_POST['current_size'] );
616 $size_after = $image_statistics['compressed_total_size'];
617 $new_library_size = $current_library_size + $size_after - $size_before;
618
619 $result['message'] = $tiny_image->get_latest_error();
620 $result['image_sizes_compressed'] = $image_statistics['image_sizes_compressed'];
621 $result['image_sizes_converted'] = $image_statistics['image_sizes_converted'];
622 $result['image_sizes_optimized'] = $image_statistics['image_sizes_compressed'];
623
624 $result['initial_total_size'] = size_format(
625 $image_statistics['initial_total_size'],
626 1
627 );
628
629 $result['optimized_total_size'] = size_format(
630 $image_statistics['compressed_total_size'],
631 1
632 );
633
634 $result['savings'] = $tiny_image->get_savings( $image_statistics );
635 $result['status'] = $this->settings->get_status();
636 $result['thumbnail'] = wp_get_attachment_image(
637 $id,
638 array( '30', '30' ),
639 true,
640 array(
641 'class' => 'pinkynail',
642 'alt' => '',
643 )
644 );
645 $result['size_change'] = $size_after - $size_before;
646 $result['human_readable_library_size'] = size_format( $new_library_size, 2 );
647
648 echo json_encode( $result );
649
650 exit();
651 }
652
653 public function ajax_optimization_statistics() {
654 if ( $this->check_ajax_referer() && current_user_can( 'upload_files' ) ) {
655 $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings );
656 echo json_encode( $stats );
657 }
658 exit();
659 }
660
661 public function ajax_compression_status() {
662 $response = $this->validate_ajax_attachment_request();
663
664 if ( isset( $response['error'] ) ) {
665 echo $response['error'];
666 exit();
667 }
668 list($id, $metadata) = $response['data'];
669
670 $tiny_image = new Tiny_Image( $this->settings, $id, $metadata );
671
672 echo $this->render_compress_details( $tiny_image );
673
674 exit();
675 }
676
677 public function media_library_bulk_action() {
678 $valid_actions = array( 'tiny_bulk_action', 'tiny_bulk_mark_compressed' );
679 $action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
680 $action2 = isset( $_REQUEST['action2'] ) ? $_REQUEST['action2'] : '';
681
682 if (
683 ! in_array( $action, $valid_actions, true ) &&
684 ! in_array( $action2, $valid_actions, true )
685 ) {
686 return;
687 }
688 if ( empty( $_REQUEST['media'] ) || ( ! $_REQUEST['media'] ) ) {
689 $_REQUEST['action'] = '';
690 return;
691 }
692 check_admin_referer( 'bulk-media' );
693 $ids = implode( '-', array_map( 'intval', $_REQUEST['media'] ) );
694 $location = 'upload.php?mode=list&ids=' . $ids;
695
696 $location = add_query_arg( 'action', $_REQUEST['action'], $location );
697
698 if ( ! empty( $_REQUEST['paged'] ) ) {
699 $location = add_query_arg( 'paged', absint( $_REQUEST['paged'] ), $location );
700 }
701 if ( ! empty( $_REQUEST['s'] ) ) {
702 $location = add_query_arg( 's', $_REQUEST['s'], $location );
703 }
704 if ( ! empty( $_REQUEST['m'] ) ) {
705 $location = add_query_arg( 'm', $_REQUEST['m'], $location );
706 }
707
708 wp_redirect( admin_url( $location ) );
709 exit();
710 }
711
712 public function add_media_columns( $columns ) {
713 $columns[ self::MEDIA_COLUMN ] = esc_html__( 'Compression', 'tiny-compress-images' );
714 return $columns;
715 }
716
717 public function render_media_column( $column, $id ) {
718 if ( self::MEDIA_COLUMN === $column ) {
719 $tiny_image = new Tiny_Image( $this->settings, $id );
720 if ( $tiny_image->file_type_allowed() ) {
721 echo '<div class="tiny-ajax-container">';
722 $this->render_compress_details( $tiny_image );
723 echo '</div>';
724 }
725 }
726 }
727
728 public function show_media_info() {
729 global $post;
730 $tiny_image = new Tiny_Image( $this->settings, $post->ID );
731 if ( $tiny_image->file_type_allowed() ) {
732 echo '<div class="misc-pub-section tiny-compress-images">';
733 echo '<h4>';
734 esc_html_e( 'JPEG, PNG, & WebP optimization', 'tiny-compress-images' );
735 echo '</h4>';
736 echo '<div class="tiny-ajax-container">';
737 $this->render_compress_details( $tiny_image );
738 echo '</div>';
739 echo '</div>';
740 }
741 }
742
743 private function render_compress_details( $tiny_image ) {
744 $in_progress = $tiny_image->filter_image_sizes( 'in_progress' );
745 if ( count( $in_progress ) > 0 ) {
746 include __DIR__ . '/views/compress-details-processing.php';
747 } else {
748 include __DIR__ . '/views/compress-details.php';
749 }
750 }
751
752 public function get_estimated_bulk_cost( $estimated_credit_use ) {
753 return Tiny_Compress::estimate_cost(
754 $estimated_credit_use,
755 $this->settings->get_compression_count()
756 );
757 }
758
759 public function render_bulk_optimization_page() {
760 $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings );
761
762 $estimated_costs = $this->get_estimated_bulk_cost( $stats['estimated_credit_use'] );
763 $admin_colors = self::retrieve_admin_colors();
764
765 /* This makes sure that up to date information is retrieved from the API. */
766 $this->settings->get_compressor()->get_status();
767
768 $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
769 $remaining_credits = $this->settings->get_remaining_credits();
770 $is_on_free_plan = $this->settings->is_on_free_plan();
771 $email_address = $this->settings->get_email_address();
772
773 include __DIR__ . '/views/bulk-optimization.php';
774 }
775
776 public function add_dashboard_widget() {
777 wp_enqueue_style(
778 self::NAME . '_chart',
779 plugins_url( '/css/optimization-chart.css', __FILE__ ),
780 array(),
781 self::version()
782 );
783
784 wp_enqueue_style(
785 self::NAME . '_dashboard_widget',
786 plugins_url( '/css/dashboard-widget.css', __FILE__ ),
787 array(),
788 self::version()
789 );
790
791 wp_register_script(
792 self::NAME . '_dashboard_widget',
793 plugins_url( '/js/dashboard-widget.js', __FILE__ ),
794 array(),
795 self::version(),
796 true
797 );
798
799 /* This might be deduplicated with the admin script localization, but
800 the order of including scripts is sometimes different. So in that
801 case we need to make sure that the order of inclusion is correc.t */
802 wp_localize_script(
803 self::NAME . '_dashboard_widget',
804 'tinyCompressDashboard',
805 array(
806 'nonce' => wp_create_nonce( 'tiny-compress' ),
807 )
808 );
809
810 wp_enqueue_script( self::NAME . '_dashboard_widget' );
811
812 wp_add_dashboard_widget(
813 $this->get_prefixed_name( 'dashboard_widget' ),
814 esc_html__( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ),
815 $this->get_method( 'add_widget_view' )
816 );
817 }
818
819 public function add_widget_view() {
820 $admin_colors = self::retrieve_admin_colors();
821 include __DIR__ . '/views/dashboard-widget.php';
822 }
823
824 private static function retrieve_admin_colors() {
825 global $_wp_admin_css_colors;
826 $admin_colour_scheme = get_user_option( 'admin_color', get_current_user_id() );
827 $admin_colors = array( '#0074aa', '#1685b5', '#78ca44', '#0086ba' ); // default
828 if ( isset( $_wp_admin_css_colors[ $admin_colour_scheme ] ) ) {
829 if ( isset( $_wp_admin_css_colors[ $admin_colour_scheme ]->colors ) ) {
830 $admin_colors = $_wp_admin_css_colors[ $admin_colour_scheme ]->colors;
831 }
832 }
833 if ( '#e5e5e5' == $admin_colors[0] && '#999' == $admin_colors[1] ) {
834 $admin_colors[0] = '#bbb';
835 }
836 if ( '#5589aa' == $admin_colors[0] && '#cfdfe9' == $admin_colors[1] ) {
837 $admin_colors[1] = '#85aec5';
838 }
839 if ( '#7c7976' == $admin_colors[0] && '#c6c6c6' == $admin_colors[1] ) {
840 $admin_colors[1] = '#adaba9';
841 $admin_colors[2] = '#adaba9';
842 }
843 if ( self::wp_version() > 3.7 ) {
844 if ( 'fresh' == $admin_colour_scheme ) {
845 $admin_colors = array( '#0074aa', '#1685b5', '#78ca44', '#0086ba' ); // better
846 }
847 }
848 return $admin_colors;
849 }
850
851 public function friendly_user_name() {
852 $user = wp_get_current_user();
853 $name = ucfirst( empty( $user->first_name ) ? $user->display_name : $user->first_name );
854 return $name;
855 }
856
857 /**
858 * Will clean up converted files (if any) when the original is deleted
859 *
860 * Hooked to the `delete_attachment` action.
861 * @see https://developer.wordpress.org/reference/hooks/deleted_post/
862 *
863 * @param [int] $post_id
864 *
865 * @return void
866 */
867 public function clean_attachment( $post_id ) {
868 $tiny_image = new Tiny_Image( $this->settings, $post_id );
869 $tiny_image->delete_converted_image();
870 }
871
872 public static function request_review() {
873 $review_url =
874 'https://wordpress.org/support/plugin/tiny-compress-images/reviews/#new-post';
875 $review_block = esc_html__( 'Enjoying TinyPNG?', 'tiny-compress-images' );
876 $review_block .= ' ';
877 $review_block .= sprintf(
878 '<a href="%s" target="_blank">%s</a>',
879 esc_url( $review_url ),
880 esc_html__( 'Write a review', 'tiny-compress-images' )
881 );
882 return $review_block;
883 }
884
885 public function mark_image_as_compressed() {
886 $response = $this->validate_ajax_attachment_request();
887 if ( isset( $response['error'] ) ) {
888 echo $response['error'];
889 exit();
890 }
891
892 list($id, $metadata) = $response['data'];
893 $tiny_image = new Tiny_Image( $this->settings, $id, $metadata );
894 $tiny_image->mark_as_compressed();
895
896 echo $this->render_compress_details( $tiny_image );
897
898 exit();
899 }
900 }
901