PluginProbe ʕ •ᴥ•ʔ
Smush – Image Optimization, Compression, Lazy Load, WebP & CDN / 1.6.0
Smush – Image Optimization, Compression, Lazy Load, WebP & CDN v1.6.0
4.1.0 4.0.3 4.0.2 2.8.1 2.9.1 3.0.0 3.0.1 3.0.2 3.1.1 3.10.1 3.10.2 3.10.3 3.11.1 3.12.3 3.12.4 3.12.5 3.12.6 3.13.0 3.13.1 3.13.2 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.15.2 3.15.3 3.15.4 3.15.5 3.16.2 3.16.4 3.16.5 3.16.6 3.17.0 3.17.1 3.18.0 3.18.1 3.2.0.1 3.2.1 3.2.2.1 3.2.4 3.20.0 3.21.1 3.22.1 3.22.3 3.23.0 3.23.1 3.23.2 3.23.3 3.23.4 3.24.0 3.24.0-beta.2 3.3.0 3.3.1 3.3.2 3.4.1 3.4.2 3.6.1 3.6.3 3.7.0 3.7.1 3.7.2 3.7.3 3.8.2 3.8.3 3.8.4 3.8.5 3.8.7 3.8.8 3.9.0 3.9.1 3.9.11 3.9.2 3.9.4 3.9.5 3.9.8 3.9.9 trunk 1.0.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.2 1.2.1 1.2.10 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.5.1 1.6.5.2 1.6.5.3 1.6.5.4 1.7 1.7.1 1.7.1.1 2.0 2.0.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.6.2 2.0.6.3 2.0.6.5 2.0.7 2.0.7.1 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2 2.2.1 2.2.2 2.3 2.3.1 2.4 2.4.2 2.4.3 2.4.4 2.4.5 2.5.2 2.5.3 2.6.1 2.6.2 2.6.3 2.7 2.7.1 2.7.4 2.7.4.1 2.7.5 2.7.6 2.7.8 2.7.8.1 2.7.9.1 2.8.0 2.8.0.1
wp-smushit / wp-smushit.php
wp-smushit Last commit date
JSON 17 years ago bulk.php 14 years ago license.txt 17 years ago readme.txt 13 years ago screenshot-1.jpg 17 years ago settings.php 13 years ago wp-smushit.php 14 years ago
wp-smushit.php
391 lines
1 <?php
2 /*
3 Plugin Name: WP Smush.it
4 Plugin URI: http://dialect.ca/code/wp-smushit/
5 Description: Reduce image file sizes and improve performance using the <a href="http://smush.it/">Smush.it</a> API within WordPress.
6 Author: Dialect
7 Version: 1.6.0
8 Author URI: http://dialect.ca/
9 */
10
11 if ( !function_exists('json_encode') ) {
12 require_once('JSON/JSON.php');
13 }
14
15 if ( !function_exists('download_url') ) {
16 require_once(ABSPATH . 'wp-admin/includes/file.php');
17 }
18
19 /**
20 * Constants
21 */
22 define('SMUSHIT_REQ_URL', 'http://www.smushit.com/ysmush.it/ws.php?img=%s');
23 define('SMUSHIT_BASE_URL', 'http://www.smushit.com/');
24
25 define('WP_SMUSHIT_DOMAIN', 'wp_smushit');
26 define('WP_SMUSHIT_UA', 'WP Smush.it/1.6.0 (+http://dialect.ca/code/wp-smushit)');
27 define('WP_SMUSHIT_PLUGIN_DIR', dirname(plugin_basename(__FILE__)));
28
29 define('WP_SMUSHIT_AUTO', intval(get_option('wp_smushit_smushit_auto', 0)));
30 require( dirname(__FILE__) . '/settings.php' );
31
32 /**
33 * Hooks
34 */
35
36 if (WP_SMUSHIT_AUTO == WP_SMUSHIT_AUTO_OK) {
37 add_filter('wp_generate_attachment_metadata', 'wp_smushit_resize_from_meta_data', 10, 2);
38 }
39 add_filter('manage_media_columns', 'wp_smushit_columns');
40 add_action('manage_media_custom_column', 'wp_smushit_custom_column', 10, 2);
41 add_action('admin_init', 'wp_smushit_admin_init');
42 add_action('admin_action_wp_smushit_manual', 'wp_smushit_manual');
43
44 /**
45 * Plugin admin functions
46 */
47 function wp_smushit_admin_init() {
48 load_plugin_textdomain(WP_SMUSHIT_DOMAIN);
49 wp_enqueue_script('common');
50 }
51
52 function wp_smushit_admin_menu() {
53 add_media_page( 'Bulk Smush.it', 'Bulk Smush.it', 'edit_others_posts', 'wp-smushit-bulk', 'wp_smushit_bulk_preview');
54 }
55 add_action( 'admin_menu', 'wp_smushit_admin_menu' );
56
57
58 function wp_smushit_bulk_preview() {
59 if ( function_exists( 'apache_setenv' ) ) {
60 @apache_setenv('no-gzip', 1);
61 }
62 @ini_set('output_buffering','on');
63 @ini_set('zlib.output_compression', 0);
64 @ini_set('implicit_flush', 1);
65
66 $attachments = null;
67 $auto_start = false;
68
69 if ( isset($_REQUEST['ids'])) {
70 $attachments = get_posts( array(
71 'numberposts' => -1,
72 'include' => explode(',', $_REQUEST['ids']),
73 'post_type' => 'attachment',
74 'post_mime_type' => 'image'
75 ));
76 $auto_start = true;
77 } else {
78 $attachments = get_posts( array(
79 'numberposts' => -1,
80 'post_type' => 'attachment',
81 'post_mime_type' => 'image'
82 ));
83 }
84
85
86 require( dirname(__FILE__) . '/bulk.php' );
87 }
88
89 /**
90 * Manually process an image from the Media Library
91 */
92 function wp_smushit_manual() {
93 if ( FALSE === current_user_can('upload_files') ) {
94 wp_die(__('You don\'t have permission to work with uploaded files.', WP_SMUSHIT_DOMAIN));
95 }
96
97 if ( FALSE === isset($_GET['attachment_ID'])) {
98 wp_die(__('No attachment ID was provided.', WP_SMUSHIT_DOMAIN));
99 }
100
101 $attachment_ID = intval($_GET['attachment_ID']);
102
103 $original_meta = wp_get_attachment_metadata( $attachment_ID );
104
105 $new_meta = wp_smushit_resize_from_meta_data( $original_meta, $attachment_ID );
106 wp_update_attachment_metadata( $attachment_ID, $new_meta );
107
108 $sendback = wp_get_referer();
109 $sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
110 wp_redirect($sendback);
111 exit(0);
112 }
113
114 /**
115 * Process an image with Smush.it.
116 *
117 * Returns an array of the $file $results.
118 *
119 * @param string $file Full absolute path to the image file
120 * @param string $file_url Optional full URL to the image file
121 * @returns array
122 */
123 function wp_smushit($file, $file_url = null) {
124 // don't run on localhost, IPv4 and IPv6 checks
125 // if( in_array($_SERVER['SERVER_ADDR'], array('127.0.0.1', '::1')) )
126 // return array($file, __('Not processed (local file)', WP_SMUSHIT_DOMAIN));
127
128 // canonicalize path - disabled 2011-02-1 troubleshooting 'Could not find...' errors.
129 // From the PHP docs: "The running script must have executable permissions on
130 // all directories in the hierarchy, otherwise realpath() will return FALSE."
131 // $file_path = realpath($file);
132
133 $file_path = $file;
134 // check that the file exists
135 if ( FALSE === file_exists($file_path) || FALSE === is_file($file_path) ) {
136 $msg = sprintf(__("Could not find <span class='code'>%s</span>", WP_SMUSHIT_DOMAIN), $file_path);
137 return array($file, $msg);
138 }
139
140 // check that the file is writable
141 if ( FALSE === is_writable($file_path) ) {
142 $msg = sprintf(__("<span class='code'>%s</span> is not writable", WP_SMUSHIT_DOMAIN), $file_path);
143 return array($file, $msg);
144 }
145
146 // check that the file is within the WP_CONTENT_DIR
147 $upload_dir = wp_upload_dir();
148 $wp_upload_dir = $upload_dir['basedir'];
149 $wp_upload_url = $upload_dir['baseurl'];
150 if ( 0 !== stripos(realpath($file_path), realpath(ABSPATH)) ) {
151 $msg = sprintf(__("<span class='code'>%s</span> must be within the content directory (<span class='code'>%s</span>)", WP_SMUSHIT_DOMAIN), htmlentities($file_path), $wp_upload_dir);
152
153 return array($file, $msg);
154 }
155
156 if ( !$file_url ) {
157 // determine the public URL
158 $file_url = str_replace( $wp_upload_dir, $wp_upload_url, $file );
159 }
160
161 $data = wp_smushit_post($file_url);
162
163 if ( FALSE === $data )
164 return array($file, __('Error posting to Smush.it', WP_SMUSHIT_DOMAIN));
165
166 // make sure the response looks like JSON -- added 2008-12-19 when
167 // Smush.it was returning PHP warnings before the JSON output
168 if ( strpos( trim($data), '{' ) != 0 ) {
169 return array($file, __('Bad response from Smush.it', WP_SMUSHIT_DOMAIN));
170 }
171
172 // read the JSON response
173 if ( function_exists('json_decode') ) {
174 $data = json_decode( $data );
175 } else {
176 $json = new Services_JSON();
177 $data = $json->decode($data);
178 }
179
180 if ( -1 === intval($data->dest_size) )
181 return array($file, __('No savings', WP_SMUSHIT_DOMAIN));
182
183 if ( !$data->dest ) {
184 $err = ($data->error ? 'Smush.it error: ' . $data->error : 'unknown error');
185 $err .= " while processing <span class='code'>$file_url</span> (<span class='code'>$file_path</span>)";
186 return array($file, __($err, WP_SMUSHIT_DOMAIN) );
187 }
188
189 $processed_url = $data->dest;
190
191 // The smush.it web service does not append the domain;
192 // smushit.com web service does
193 if ( 0 !== stripos($processed_url, 'http://') ) {
194 $processed_url = SMUSHIT_BASE_URL . $processed_url;
195 }
196
197 $temp_file = download_url($processed_url);
198
199 if ( is_wp_error($temp_file) ) {
200 @unlink($tmp);
201 $results_msg = sprintf(__("Error downloading file (%s)", WP_SMUSHIT_DOMAIN),
202 $temp_file->get_error_message());
203 return array($file, $results_msg );
204 }
205
206 @rename( $temp_file, $file_path );
207
208 $savings = intval($data->src_size) - intval($data->dest_size);
209 $savings_str = wp_smushit_format_bytes($savings, 1);
210 $savings_str = str_replace(' ', '&nbsp;', $savings_str);
211
212 $results_msg = sprintf(__("Reduced by %01.1f%% (%s)", WP_SMUSHIT_DOMAIN),
213 $data->percent,
214 $savings_str);
215
216 return array($file, $results_msg);
217 }
218
219 function wp_smushit_should_resmush($previous_status) {
220 if ( !$previous_status || empty($previous_status) ) {
221 return TRUE;
222 }
223
224 if ( stripos($previous_status, 'no savings') !== FALSE || stripos($previous_status, 'reduced') !== FALSE ) {
225 return FALSE;
226 }
227
228 // otherwise an error
229 return TRUE;
230 }
231
232
233 /**
234 * Read the image paths from an attachment's meta data and process each image
235 * with wp_smushit().
236 *
237 * This method also adds a `wp_smushit` meta key for use in the media library.
238 *
239 * Called after `wp_generate_attachment_metadata` is completed.
240 */
241 function wp_smushit_resize_from_meta_data($meta, $ID = null, $force_resmush = true) {
242 $file_path = $meta['file'];
243 $store_absolute_path = true;
244 $upload_dir = wp_upload_dir();
245 $upload_path = trailingslashit( $upload_dir['basedir'] );
246
247 // WordPress >= 2.6.2: determine the absolute $file_path (http://core.trac.wordpress.org/changeset/8796)
248 if ( FALSE === strpos($file, $upload_path) ) {
249 $store_absolute_path = false;
250 $file_path = $upload_path . $file_path;
251 }
252
253 if ( $force_resmush || wp_smushit_should_resmush( @$meta['wp_smushit'] ) ) {
254 list($file, $msg) = wp_smushit($file_path);
255 $meta['wp_smushit'] = $msg;
256 }
257
258 // strip absolute path for Wordpress >= 2.6.2
259 if ( FALSE === $store_absolute_path ) {
260 $meta['file'] = str_replace($upload_path, '', $meta['file']);
261 }
262
263 // no resized versions, so we can exit
264 if ( !isset($meta['sizes']) )
265 return $meta;
266
267 // meta sizes don't contain a path, so we calculate one
268 $base_dir = trailingslashit( dirname($file_path) );
269
270 foreach($meta['sizes'] as $size => $data) {
271 if ( !$force_resmush && wp_smushit_should_resmush( @$meta['sizes'][$size]['wp_smushit'] ) === FALSE ) {
272 continue;
273 }
274
275 list($smushed_file, $results) = wp_smushit( $base_dir . wp_basename( $data['file'] ) );
276 $meta['sizes'][$size]['wp_smushit'] = $results;
277 }
278 return $meta;
279 }
280
281
282 /**
283 * Post an image to Smush.it.
284 *
285 * @param string $file_url URL of the file to send to Smush.it
286 * @return string|boolean Returns the JSON response on success or else FALSE
287 */
288 function wp_smushit_post($file_url) {
289 $req = sprintf( SMUSHIT_REQ_URL, urlencode( $file_url ) );
290
291 $data = false;
292
293 if ( function_exists('wp_remote_get') ) {
294 $response = wp_remote_get($req, array('user-agent' => WP_SMUSHIT_UA, 'timeout' => 20));
295
296 if( is_wp_error( $response ) ) {
297 wp_smushit_temporarily_disable();
298 $msg = 'Automatic smushing has been disabled temporarily due to an error. ' . $response->get_error_message();
299 wp_die( $msg );
300 }
301
302 $data = wp_remote_retrieve_body($response);
303 } else {
304 wp_die( __('WP Smush.it requires WordPress 2.8 or greater', WP_SMUSHIT_DOMAIN) );
305 }
306
307 return $data;
308 }
309
310
311 /**
312 * Print column header for Smush.it results in the media library using
313 * the `manage_media_columns` hook.
314 */
315 function wp_smushit_columns($defaults) {
316 $defaults['smushit'] = 'Smush.it';
317 return $defaults;
318 }
319
320 /**
321 * Return the filesize in a humanly readable format.
322 * Taken from http://www.php.net/manual/en/function.filesize.php#91477
323 */
324 function wp_smushit_format_bytes($bytes, $precision = 2) {
325 $units = array('B', 'KB', 'MB', 'GB', 'TB');
326 $bytes = max($bytes, 0);
327 $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
328 $pow = min($pow, count($units) - 1);
329 $bytes /= pow(1024, $pow);
330 return round($bytes, $precision) . ' ' . $units[$pow];
331 }
332
333 /**
334 * Print column data for Smush.it results in the media library using
335 * the `manage_media_custom_column` hook.
336 */
337 function wp_smushit_custom_column($column_name, $id) {
338 if( $column_name == 'smushit' ) {
339 $data = wp_get_attachment_metadata($id);
340 if ( isset($data['wp_smushit']) && !empty($data['wp_smushit']) ) {
341 print $data['wp_smushit'];
342 printf("<br><a href=\"admin.php?action=wp_smushit_manual&amp;attachment_ID=%d\">%s</a>",
343 $id,
344 __('Re-smush', WP_SMUSHIT_DOMAIN));
345 } else {
346 print __('Not processed', WP_SMUSHIT_DOMAIN);
347 printf("<br><a href=\"admin.php?action=wp_smushit_manual&amp;attachment_ID=%d\">%s</a>",
348 $id,
349 __('Smush.it now!', WP_SMUSHIT_DOMAIN));
350 }
351 }
352 }
353
354 add_action( 'admin_head-upload.php', 'wp_smushit_add_bulk_actions_via_javascript' );
355
356 // Borrowed from http://www.viper007bond.com/wordpress-plugins/regenerate-thumbnails/
357 function wp_smushit_add_bulk_actions_via_javascript() { ?>
358 <script type="text/javascript">
359 jQuery(document).ready(function($){
360 $('select[name^="action"] option:last-child').before('<option value="bulk_smushit">Bulk Smush.it</option>');
361 });
362 </script>
363 <?php }
364
365
366 add_action( 'admin_action_bulk_smushit', 'wp_smushit_bulk_action_handler' );
367
368 // Handles the bulk actions POST
369 // Borrowed from http://www.viper007bond.com/wordpress-plugins/regenerate-thumbnails/
370 function wp_smushit_bulk_action_handler() {
371 check_admin_referer( 'bulk-media' );
372
373 if ( empty( $_REQUEST['media'] ) || ! is_array( $_REQUEST['media'] ) )
374 return;
375
376 $ids = implode( ',', array_map( 'intval', $_REQUEST['media'] ) );
377
378
379 // Can't use wp_nonce_url() as it escapes HTML entities
380 wp_redirect( add_query_arg( '_wpnonce', wp_create_nonce( 'wp-smushit-bulk' ), admin_url( 'upload.php?page=wp-smushit-bulk&goback=1&ids=' . $ids ) ) );
381 exit();
382 }
383
384 if ( function_exists( 'wp_basename' ) === false ) {
385 /**
386 * Introduced in WP 3.1... this is copied verbatim from wp-includes/formatting.php.
387 */
388 function wp_basename( $path, $suffix = '' ) {
389 return urldecode( basename( str_replace( '%2F', '/', urlencode( $path ) ), $suffix ) );
390 }
391 }