PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / 1.5.0
TinyPNG – JPEG, PNG & WebP image compression v1.5.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-plugin.php
tiny-compress-images / src Last commit date
config 11 years ago languages 10 years ago scripts 10 years ago styles 10 years ago cacert.pem 11 years ago class-tiny-compress-curl.php 10 years ago class-tiny-compress-fopen.php 10 years ago class-tiny-compress.php 10 years ago class-tiny-exception.php 11 years ago class-tiny-metadata.php 10 years ago class-tiny-notices.php 11 years ago class-tiny-php.php 11 years ago class-tiny-plugin.php 10 years ago class-tiny-settings.php 10 years ago class-tiny-wp-base.php 10 years ago
class-tiny-plugin.php
298 lines
1 <?php
2 /*
3 * Tiny Compress Images - WordPress plugin.
4 * Copyright (C) 2015 Voormedia 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
21 class Tiny_Plugin extends Tiny_WP_Base {
22 const MEDIA_COLUMN = self::NAME;
23 const MEDIA_COLUMN_HEADER = 'Compression';
24
25 private $settings;
26
27 public static function jpeg_quality() {
28 return 95;
29 }
30
31 public function __construct() {
32 parent::__construct();
33
34 $this->settings = new Tiny_Settings();
35 if (is_admin()) {
36 add_action('admin_menu', $this->get_method('admin_menu'));
37 }
38 }
39
40 public function set_compressor($compressor) {
41 $this->settings->set_compressor($compressor);
42 }
43
44 public function init() {
45 add_filter('jpeg_quality', $this->get_static_method('jpeg_quality'));
46 add_filter('wp_editor_set_quality', $this->get_static_method('jpeg_quality'));
47 add_filter('wp_generate_attachment_metadata', $this->get_method('compress_attachment'), 10, 2);
48 load_plugin_textdomain(self::NAME, false, dirname(plugin_basename(__FILE__)) . '/languages');
49 }
50
51 public function admin_init() {
52 add_filter('manage_media_columns', $this->get_method('add_media_columns'));
53 add_action('manage_media_custom_column', $this->get_method('render_media_column'), 10, 2);
54 add_action('wp_ajax_tiny_compress_image', $this->get_method('compress_image'));
55 add_action('admin_action_tiny_bulk_compress', $this->get_method('bulk_compress'));
56 add_action('admin_enqueue_scripts', $this->get_method('enqueue_scripts'));
57 $plugin = plugin_basename(dirname(dirname(__FILE__)) . '/tiny-compress-images.php');
58 add_filter("plugin_action_links_$plugin", $this->get_method('add_plugin_links'));
59 }
60
61 public function admin_menu() {
62 add_management_page(
63 self::translate('Compress JPEG & PNG Images'), self::translate('Compress All Images'),
64 'upload_files', 'tiny-bulk-compress', $this->get_method('bulk_compress_page')
65 );
66
67 }
68
69 public function add_plugin_links($current_links) {
70 $additional[] = sprintf('<a href="options-media.php#%s">%s</a>', self::NAME,
71 self::translate_escape('Settings'));
72 return array_merge($additional, $current_links);
73 }
74
75 public function enqueue_scripts($hook) {
76 wp_enqueue_style(self::NAME .'_admin', plugins_url('/styles/admin.css', __FILE__),
77 array(), self::plugin_version());
78
79 $handle = self::NAME .'_admin';
80 wp_register_script($handle, plugins_url('/scripts/admin.js', __FILE__),
81 array(), self::plugin_version(), true);
82
83 // Wordpress < 3.3 does not handle multi dimensional arrays
84 wp_localize_script($handle, 'tinyCompress', array(
85 'nonce' => wp_create_nonce('tiny-compress'),
86 'wpVersion' => self::wp_version(),
87 'pluginVersion' => self::plugin_version(),
88 'L10nAllDone' => self::translate('All images are processed'),
89 'L10nBulkAction' => self::translate('Compress Images'),
90 'L10nCompressing' => self::translate('Compressing'),
91 'L10nCompressions' => self::translate('compressions'),
92 'L10nError' => self::translate('Error'),
93 'L10nInternalError' => self::translate('Internal error'),
94 'L10nOutOf' => self::translate('out of'),
95 'L10nWaiting' => self::translate('Waiting'),
96 ));
97 wp_enqueue_script($handle);
98 }
99
100 private function compress($metadata, $attachment_id) {
101 $mime_type = get_post_mime_type($attachment_id);
102 $tiny_metadata = new Tiny_Metadata($attachment_id, $metadata);
103
104 if ($this->settings->get_compressor() === null || strpos($mime_type, 'image/') !== 0) {
105 return array($tiny_metadata, null);
106 }
107
108 $success = 0;
109 $failed = 0;
110
111 $compressor = $this->settings->get_compressor();
112 $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
113 $uncompressed_sizes = $tiny_metadata->get_uncompressed_sizes($active_tinify_sizes);
114
115 foreach ($uncompressed_sizes as $uncompressed_size) {
116 try {
117 $tiny_metadata->add_request($uncompressed_size);
118 $tiny_metadata->update();
119 $resize = $tiny_metadata->is_resizable($uncompressed_size) ? $this->settings->get_resize_options() : false;
120 $response = $compressor->compress_file($tiny_metadata->get_filename($uncompressed_size), $resize);
121 $tiny_metadata->add_response($response, $uncompressed_size);
122 $success++;
123 } catch (Tiny_Exception $e) {
124 $tiny_metadata->add_exception($e, $uncompressed_size);
125 $failed++;
126 }
127 }
128 $tiny_metadata->update();
129
130 return array($tiny_metadata, array('success' => $success, 'failed' => $failed));
131 }
132
133 public function compress_attachment($metadata, $attachment_id) {
134 list($tiny_metadata, $result) = $this->compress($metadata, $attachment_id);
135 return $tiny_metadata->update_wp_metadata($metadata);
136 }
137
138 public function compress_image() {
139 if (!$this->check_ajax_referer()) {
140 exit();
141 }
142 $json = !empty($_POST['json']) && $_POST['json'];
143 if (!current_user_can('upload_files')) {
144 $message = self::translate("You don't have permission to work with uploaded files") . '.';
145 echo $json ? json_encode(array('error' => $message)) : $message;
146 exit();
147 }
148 if (empty($_POST['id'])) {
149 $message = self::translate("Not a valid media file") . '.';
150 echo $json ? json_encode(array('error' => $message)) : $message;
151 exit();
152 }
153 $id = intval($_POST['id']);
154 $metadata = wp_get_attachment_metadata($id);
155 if (!is_array($metadata)) {
156 $message = self::translate("Could not find metadata of media file") . '.';
157 echo $json ? json_encode(array('error' => $message)) : $message;
158 exit;
159 }
160
161 list($tiny_metadata, $result) = $this->compress($metadata, $id);
162 wp_update_attachment_metadata($id, $tiny_metadata->update_wp_metadata($metadata));
163
164 if ($json) {
165 $result['message'] = $tiny_metadata->get_latest_error();
166 $result['status'] = $this->settings->get_status();
167 $result['thumbnail'] = $tiny_metadata->get_url('thumbnail');
168 echo json_encode($result);
169 } else {
170 echo $this->render_compress_details($tiny_metadata);
171 }
172
173 exit();
174 }
175
176 public function bulk_compress() {
177 check_admin_referer('bulk-media');
178
179 if (empty($_REQUEST['media']) || !is_array( $_REQUEST['media'])) {
180 return;
181 }
182
183 $ids = implode('-', array_map('intval', $_REQUEST['media']));
184 wp_redirect(add_query_arg(
185 '_wpnonce',
186 wp_create_nonce('tiny-bulk-compress'),
187 admin_url("tools.php?page=tiny-bulk-compress&ids=$ids")
188 ));
189 exit();
190 }
191
192 public function add_media_columns($columns) {
193 $columns[self::MEDIA_COLUMN] = self::translate(self::MEDIA_COLUMN_HEADER);
194 return $columns;
195 }
196
197 public function render_media_column($column, $id) {
198 if ($column === self::MEDIA_COLUMN) {
199 $this->render_compress_details(new Tiny_Metadata($id));
200 }
201 }
202
203 private function render_compress_details($tiny_metadata) {
204 $missing = $tiny_metadata->get_uncompressed_sizes($this->settings->get_active_tinify_sizes());
205 $success = count($tiny_metadata->get_success_sizes());
206 $total = count($missing) + $success;
207 $progress = count($tiny_metadata->get_in_progress_sizes());
208
209 $duplicates = count($this->settings->get_active_tinify_sizes()) - $total;
210 $success += $duplicates;
211 $total += $duplicates;
212
213 if (count($missing) > 0) {
214 printf(self::translate_escape('Compressed %d out of %d sizes'), $success, $total);
215 $original = $tiny_metadata->get_value();
216 if (isset($original['output']['resized'])) {
217 echo '<br/>';
218 printf(self::translate_escape('Resized original to %dx%d'), $original['output']['width'], $original['output']['height']);
219 }
220 echo '<br/>';
221 if (($error = $tiny_metadata->get_latest_error())) {
222 echo '<span class="error">' . self::translate_escape('Latest error') . ': '. self::translate_escape($error) .'</span><br/>';
223 }
224 echo '<button type="button" class="tiny-compress" data-id="' . $tiny_metadata->get_id() . '">' .
225 self::translate_escape('Compress') . '</button>';
226 echo '<div class="spinner hidden"></div>';
227 } elseif ($progress > 0) {
228 printf(self::translate_escape('Compressing %d sizes...'), count($this->settings->get_active_tinify_sizes()));
229 } else {
230 printf(self::translate_escape('Compressed %d out of %d sizes'), $success, $total);
231 $original = $tiny_metadata->get_value();
232 if (isset($original['output']['resized'])) {
233 echo '<br/>';
234 printf(self::translate_escape('Resized original to %dx%d'), $original['output']['width'], $original['output']['height']);
235 }
236 $savings = $tiny_metadata->get_savings();
237 if ($savings['count'] > 0) {
238 echo '<br/>';
239 echo self::translate_escape('Total size') . ': ' . size_format($savings['input']) . '<br/>';
240 echo self::translate_escape('Compressed size') . ': ' . size_format($savings['output']);
241 }
242 }
243 }
244
245 public function bulk_compress_page() {
246 global $wpdb;
247
248 echo '<div class="wrap" id="tiny-bulk-compress">';
249 echo '<h2>' . self::translate('Compress JPEG & PNG Images') . '</h2>';
250 if (empty($_POST['tiny-bulk-compress']) && empty($_REQUEST['ids'])) {
251 $result = $wpdb->get_results("SELECT COUNT(*) AS `count` FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' ORDER BY ID DESC", ARRAY_A);
252 $image_count = $result[0]['count'];
253 $sizes_count = count($this->settings->get_active_tinify_sizes());
254
255 echo '<p>' . self::translate_escape("Use this tool to compress all images in your media library") . '. ';
256 echo self::translate_escape("Only images that have not been compressed will be compressed") . '.</p>';
257 echo '<p>' . sprintf(self::translate_escape("We have found %d images in your media library and for each image %d sizes will be compressed"), $image_count, $sizes_count) . '. ';
258 echo sprintf(self::translate_escape('This results in %d compressions at most'), $image_count*$sizes_count) . '.</p>';
259 echo '<p>' . self::translate_escape("To begin, just press the button below") . '.</p>';
260
261 echo '<form method="POST" action="?page=tiny-bulk-compress">';
262 echo '<input type="hidden" name="_wpnonce" value="' . wp_create_nonce('tiny-bulk-compress') . '">';
263 echo '<input type="hidden" name="tiny-bulk-compress" value="1">';
264 echo '<p><button class="button button-primary button-large" type="submit">' .
265 self::translate_escape('Compress All Images') . '</p>';
266 echo '</form>';
267 } else {
268 check_admin_referer('tiny-bulk-compress');
269
270 if (!empty($_REQUEST['ids'])) {
271 $ids = implode(',', array_map('intval', explode('-', $_REQUEST['ids'])));
272 $cond = "AND ID IN($ids)";
273 } else {
274 $cond = "";
275 }
276
277 // Get all ids and names of the images and not the whole objects which will only fill memory
278 $items = $wpdb->get_results("SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' $cond ORDER BY ID DESC", ARRAY_A);
279
280 echo '<p>';
281 echo self::translate_escape("Please be patient while the images are being compressed") . '. ';
282 echo self::translate_escape("This can take a while if you have many images") . '. ';
283 echo self::translate_escape("Do not navigate away from this page because it will stop the process") . '. ';
284 echo self::translate_escape("You will be notified via this page when the processing is done") . '.';
285 echo "</p>";
286
287 echo '<div id="tiny-status"><p>'. self::translate_escape('Compressions this month') . sprintf(' <span>%d</span></p></div>', $this->settings->get_status());
288 echo '<div id="tiny-progress"><p>'. self::translate_escape('Processing') . ' <span>0</span> ' . self::translate_escape('out of') . sprintf(' %d </p></div>', count($items));
289 echo '<div id="media-items">';
290 echo '</div>';
291
292 echo '<script type="text/javascript">jQuery(function() { tinyBulkCompress('. json_encode($items) . ')})</script>';
293 }
294
295 echo '</div>';
296 }
297 }
298