wp-smushit
Last commit date
assets
11 years ago
extras
11 years ago
languages
11 years ago
lib
11 years ago
license.txt
17 years ago
readme.txt
11 years ago
uninstall.php
11 years ago
wp-smush.php
11 years ago
wp-smushit.php
11 years ago
wp-smush.php
899 lines
| 1 | <?php |
| 2 | /* |
| 3 | Plugin Name: WP Smush |
| 4 | Plugin URI: http://wordpress.org/extend/plugins/wp-smushit/ |
| 5 | Description: Reduce image file sizes and improve performance using the <a href="https://premium.wpmudev.org/">WPMU DEV</a> Smush API within WordPress. |
| 6 | Author: WPMU DEV |
| 7 | Version: 2.0 |
| 8 | Author URI: http://premium.wpmudev.org/ |
| 9 | Textdomain: wp_smush |
| 10 | */ |
| 11 | |
| 12 | /* |
| 13 | This plugin was originally developed by Alex Dunae. |
| 14 | http://dialect.ca/ |
| 15 | */ |
| 16 | |
| 17 | /* |
| 18 | Copyright 2007-2015 Incsub (http://incsub.com) |
| 19 | |
| 20 | This program is free software; you can redistribute it and/or modify |
| 21 | it under the terms of the GNU General Public License (Version 2 - GPLv2) as published by |
| 22 | the Free Software Foundation. |
| 23 | |
| 24 | This program is distributed in the hope that it will be useful, |
| 25 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 27 | GNU General Public License for more details. |
| 28 | |
| 29 | You should have received a copy of the GNU General Public License |
| 30 | along with this program; if not, write to the Free Software |
| 31 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 32 | */ |
| 33 | |
| 34 | |
| 35 | /** |
| 36 | * Constants |
| 37 | */ |
| 38 | define( 'WP_SMUSH_VERSON', "2.0" ); |
| 39 | /** |
| 40 | * Plugin base name |
| 41 | */ |
| 42 | define( 'WP_SMUSH_BASENAME', plugin_basename( __FILE__ ) ); |
| 43 | |
| 44 | define( 'WP_SMUSH_API', 'https://smushpro.wpmudev.org/1.0/' ); |
| 45 | define( 'WP_SMUSH_DOMAIN', 'wp_smush' ); |
| 46 | define( 'WP_SMUSH_UA', 'WP Smush/' . WP_SMUSH_VERSON . '; ' . network_home_url() ); |
| 47 | define( 'WP_SMUSH_DIR', plugin_dir_path( __FILE__ ) ); |
| 48 | define( 'WP_SMUSH_URL', plugin_dir_url( __FILE__ ) ); |
| 49 | define( 'WP_SMUSH_MAX_BYTES', 1000000 ); |
| 50 | define( 'WP_SMUSH_PREMIUM_MAX_BYTES', 8000000 ); |
| 51 | define( 'WP_SMUSH_PREFIX', 'wp-smush-' ); |
| 52 | if ( ! defined( 'WP_SMUSH_TIMEOUT' ) ) { |
| 53 | define( 'WP_SMUSH_TIMEOUT', 30 ); |
| 54 | } |
| 55 | |
| 56 | require_once WP_SMUSH_DIR . "/lib/class-wp-smush-migrate.php"; |
| 57 | |
| 58 | if ( ! class_exists( 'WpSmush' ) ) { |
| 59 | |
| 60 | class WpSmush { |
| 61 | |
| 62 | var $version = WP_SMUSH_VERSON; |
| 63 | |
| 64 | /** |
| 65 | * Meta key for api validity |
| 66 | * |
| 67 | */ |
| 68 | const VALIDITY_KEY = "wp-smush-valid"; |
| 69 | |
| 70 | /** |
| 71 | * Api server url to check api key validity |
| 72 | * |
| 73 | */ |
| 74 | const API_SERVER = 'https://premium.wpmudev.org/wdp-un.php?action=smushit_check'; |
| 75 | |
| 76 | /** |
| 77 | * Meta key to save smush result to db |
| 78 | * |
| 79 | * |
| 80 | */ |
| 81 | const SMUSHED_META_KEY = 'wp-smpro-smush-data'; |
| 82 | |
| 83 | /** |
| 84 | * Meta key to save migrated version |
| 85 | * |
| 86 | */ |
| 87 | const MIGRATED_VERSION = "wp-smush-migrated-version"; |
| 88 | |
| 89 | /** |
| 90 | * Constructor |
| 91 | */ |
| 92 | function __construct() { |
| 93 | /** |
| 94 | * Hooks |
| 95 | */ |
| 96 | //Check if auto is enabled |
| 97 | $auto_smush = get_option( WP_SMUSH_PREFIX . 'auto' ); |
| 98 | |
| 99 | //Keep the uto smush on by default |
| 100 | if ( $auto_smush === false ) { |
| 101 | $auto_smush = 1; |
| 102 | } |
| 103 | |
| 104 | if ( $auto_smush ) { |
| 105 | add_filter( 'wp_generate_attachment_metadata', array( $this, 'filter_generate_attachment_metadata' ), 10, 2 ); |
| 106 | } |
| 107 | add_filter( 'manage_media_columns', array( $this, 'columns' ) ); |
| 108 | add_action( 'manage_media_custom_column', array( $this, 'custom_column' ), 10, 2 ); |
| 109 | add_action( 'admin_init', array( $this, 'admin_init' ) ); |
| 110 | add_action( "admin_init", array( $this, "migrate" ) ); |
| 111 | |
| 112 | } |
| 113 | |
| 114 | function admin_init() { |
| 115 | load_plugin_textdomain( WP_SMUSH_DOMAIN, false, dirname( WP_SMUSH_BASENAME ) . '/languages/' ); |
| 116 | wp_enqueue_script( 'common' ); |
| 117 | } |
| 118 | |
| 119 | /** |
| 120 | * Process an image with Smush. |
| 121 | * |
| 122 | * Returns an array of the $file $results. |
| 123 | * |
| 124 | * @param string $file Full absolute path to the image file |
| 125 | * @param string $file_url Optional full URL to the image file |
| 126 | * |
| 127 | * @returns array |
| 128 | */ |
| 129 | function do_smushit( $attachment_id, $file_path = '', $file_url = '' ) { |
| 130 | $errors = new WP_Error(); |
| 131 | if ( empty( $file_path ) ) { |
| 132 | $errors->add( "empty_path", __( "File path is empty", WP_SMUSH_DOMAIN ) ); |
| 133 | } |
| 134 | |
| 135 | if ( empty( $file_url ) ) { |
| 136 | $errors->add( "empty_url", __( "File URL is empty", WP_SMUSH_DOMAIN ) ); |
| 137 | } |
| 138 | |
| 139 | // check that the file exists |
| 140 | if ( ! file_exists( $file_path ) || ! is_file( $file_path ) ) { |
| 141 | $errors->add( "file_not_found", sprintf( __( "Could not find %s", WP_SMUSH_DOMAIN ), $file_path ) ); |
| 142 | } |
| 143 | |
| 144 | // check that the file is writable |
| 145 | if ( ! is_writable( dirname( $file_path ) ) ) { |
| 146 | $errors->add( "not_writable", sprintf( __( "%s is not writable", WP_SMUSH_DOMAIN ), dirname( $file_path ) ) ); |
| 147 | } |
| 148 | |
| 149 | $file_size = filesize( $file_path ); |
| 150 | |
| 151 | //Check if premium user |
| 152 | $max_size = $this->is_premium() ? WP_SMUSH_PREMIUM_MAX_BYTES : WP_SMUSH_MAX_BYTES; |
| 153 | |
| 154 | //Check if file exists |
| 155 | if ( $file_size == 0 ) { |
| 156 | $errors->add( "image_not_found", sprintf( __( 'Skipped (%s), image not found.', WP_SMUSH_DOMAIN ), $this->format_bytes( $file_size ) ) ); |
| 157 | } |
| 158 | |
| 159 | //Check size limit |
| 160 | if ( $file_size > $max_size ) { |
| 161 | $errors->add( "size_limit", sprintf( __( 'Skipped (%s), size limit exceeded.', WP_SMUSH_DOMAIN ), $this->format_bytes( $file_size ) ) ); |
| 162 | } |
| 163 | |
| 164 | if ( count( $errors->get_error_messages() ) ) { |
| 165 | return $errors; |
| 166 | } |
| 167 | |
| 168 | /** Send image for smushing, and fetch the response */ |
| 169 | $response = $this->_post( $file_path, $file_size ); |
| 170 | |
| 171 | if ( ! $response['success'] ) { |
| 172 | $errors->add( "false_response", $response['message'] ); |
| 173 | } |
| 174 | //If there is no data |
| 175 | if ( empty( $response['data'] ) ) { |
| 176 | $errors->add( "no_data", __( 'Unknown API error', WP_SMUSH_DOMAIN ) ); |
| 177 | } |
| 178 | |
| 179 | if ( count( $errors->get_error_messages() ) ) { |
| 180 | return $errors; |
| 181 | } |
| 182 | |
| 183 | //If there are no savings, or image returned is bigger in size |
| 184 | if ( ( ! empty( $response['data']->bytes_saved ) && intval( $response['data']->bytes_saved ) <= 0 ) |
| 185 | || empty( $response['data']->image ) |
| 186 | ) { |
| 187 | return $response; |
| 188 | } |
| 189 | $tempfile = $file_path . ".tmp"; |
| 190 | |
| 191 | //Add the file as tmp |
| 192 | file_put_contents( $tempfile, $response['data']->image ); |
| 193 | |
| 194 | //handle backups if enabled |
| 195 | $backup = get_option( WP_SMUSH_PREFIX . 'backup' ); |
| 196 | if ( $backup && $this->is_premium() ) { |
| 197 | $path = pathinfo( $file_path ); |
| 198 | $backup_name = trailingslashit( $path['dirname'] ) . $path['filename'] . ".bak." . $path['extension']; |
| 199 | @copy( $file_path, $backup_name ); |
| 200 | } |
| 201 | |
| 202 | //replace the file |
| 203 | $success = @rename( $tempfile, $file_path ); |
| 204 | |
| 205 | //if tempfile still exists, unlink it |
| 206 | if ( file_exists( $tempfile ) ) { |
| 207 | unlink( $tempfile ); |
| 208 | } |
| 209 | |
| 210 | //If file renaming was successful |
| 211 | if ( ! $success ) { |
| 212 | copy( $tempfile, $file_path ); |
| 213 | unlink( $tempfile ); |
| 214 | } |
| 215 | |
| 216 | return $response; |
| 217 | } |
| 218 | |
| 219 | /** |
| 220 | * Fills $placeholder array with values from $data array without creating new keys |
| 221 | * |
| 222 | * @param array $placeholders |
| 223 | * @param array $data |
| 224 | * |
| 225 | * @return array |
| 226 | */ |
| 227 | private function _array_fill_placeholders( array $placeholders, array $data ) { |
| 228 | return array_merge( $placeholders, array_intersect_key( $data, $placeholders ) ); |
| 229 | } |
| 230 | |
| 231 | /** |
| 232 | * Returns signature for single size of the smush api message to be saved to db; |
| 233 | * |
| 234 | * @return array |
| 235 | */ |
| 236 | private function _get_size_signature() { |
| 237 | return array( |
| 238 | 'percent' => - 1, |
| 239 | 'bytes' => - 1, |
| 240 | 'size_before' => - 1, |
| 241 | 'size_after' => - 1, |
| 242 | 'time' => - 1 |
| 243 | ); |
| 244 | } |
| 245 | |
| 246 | /** |
| 247 | * Read the image paths from an attachment's meta data and process each image |
| 248 | * with wp_smushit(). |
| 249 | * |
| 250 | * This method also adds a `wp_smushit` meta key for use in the media library. |
| 251 | * Called after `wp_generate_attachment_metadata` is completed. |
| 252 | * |
| 253 | * @param $meta |
| 254 | * @param null $ID |
| 255 | * @param bool $force_resmush |
| 256 | * |
| 257 | * @return mixed |
| 258 | */ |
| 259 | function resize_from_meta_data( $meta, $ID = null, $force_resmush = true ) { |
| 260 | |
| 261 | //Flag to check, if original size image needs to be smushed or not |
| 262 | $smush_full = true; |
| 263 | $errors = new WP_Error(); |
| 264 | $stats = array( |
| 265 | "stats" => array_merge( $this->_get_size_signature(), array( |
| 266 | 'api_version' => - 1, |
| 267 | 'lossy' => - 1 |
| 268 | ) |
| 269 | ), |
| 270 | 'sizes' => array() |
| 271 | ); |
| 272 | |
| 273 | $size_before = $size_after = $compression = $total_time = $bytes_saved = 0; |
| 274 | |
| 275 | if ( $ID && wp_attachment_is_image( $ID ) === false ) { |
| 276 | return $meta; |
| 277 | } |
| 278 | |
| 279 | //File path and URL for original image |
| 280 | $attachment_file_path = get_attached_file( $ID ); |
| 281 | $attachment_file_url = wp_get_attachment_url( $ID ); |
| 282 | |
| 283 | // If images has other registered size, smush them first |
| 284 | if ( ! empty( $meta['sizes'] ) ) { |
| 285 | |
| 286 | foreach ( $meta['sizes'] as $size_key => $size_data ) { |
| 287 | |
| 288 | //if there is a large size, then we will set a flag to leave the original untouched |
| 289 | if ( $size_key == 'large' ) { |
| 290 | $smush_full = false; |
| 291 | } |
| 292 | |
| 293 | // We take the original image. The 'sizes' will all match the same URL and |
| 294 | // path. So just get the dirname and replace the filename. |
| 295 | |
| 296 | $attachment_file_path_size = trailingslashit( dirname( $attachment_file_path ) ) . $size_data['file']; |
| 297 | $attachment_file_url_size = trailingslashit( dirname( $attachment_file_url ) ) . $size_data['file']; |
| 298 | |
| 299 | //Store details for each size key |
| 300 | $response = $this->do_smushit( $ID, $attachment_file_path_size, $attachment_file_url_size ); |
| 301 | |
| 302 | if ( is_wp_error( $response ) ) { |
| 303 | return $response; |
| 304 | } |
| 305 | |
| 306 | if ( ! empty( $response['data'] ) ) { |
| 307 | $stats['sizes'][ $size_key ] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $response['data'] ); |
| 308 | } |
| 309 | |
| 310 | //Total Stats, store all data in bytes |
| 311 | if ( isset( $response['data'] ) ) { |
| 312 | list( $size_before, $size_after, $total_time, $compression, $bytes_saved ) |
| 313 | = $this->_update_stats_data( $response['data'], $size_before, $size_after, $total_time, $bytes_saved ); |
| 314 | } else { |
| 315 | $errors->add( "image_size_error" . $size_key, sprintf( __( "Size '%s' not processed correctly", WP_SMUSH_DOMAIN ), $size_key ) ); |
| 316 | } |
| 317 | |
| 318 | if ( empty( $stats['stats']['api_version'] ) ) { |
| 319 | $stats['stats']['api_version'] = $response['data']->api_version; |
| 320 | $stats['stats']['lossy'] = $response['data']->lossy; |
| 321 | } |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | //If original size is supposed to be smushed |
| 326 | if ( $smush_full ) { |
| 327 | |
| 328 | $full_image_response = $this->do_smushit( $ID, $attachment_file_path, $attachment_file_url ); |
| 329 | |
| 330 | if ( is_wp_error( $full_image_response ) ) { |
| 331 | return $full_image_response; |
| 332 | } |
| 333 | |
| 334 | if ( ! empty( $full_image_response['data'] ) ) { |
| 335 | $stats['sizes']['full'] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $full_image_response['data'] ); |
| 336 | } else { |
| 337 | $errors->add( "image_size_error", __( "Size 'full' not processed correctly", WP_SMUSH_DOMAIN ) ); |
| 338 | } |
| 339 | |
| 340 | //Update stats |
| 341 | if ( isset( $full_image_response['data'] ) ) { |
| 342 | list( $size_before, $size_after, $total_time, $compression, $bytes_saved ) |
| 343 | = $this->_update_stats_data( $full_image_response['data'], $size_before, $size_after, $total_time, $bytes_saved ); |
| 344 | } else { |
| 345 | $errors->add( "image_size_error", __( "Size 'full' not processed correctly", WP_SMUSH_DOMAIN ) ); |
| 346 | } |
| 347 | |
| 348 | } |
| 349 | |
| 350 | $has_errors = (bool) count( $errors->get_error_messages() ); |
| 351 | |
| 352 | //Store stats |
| 353 | |
| 354 | list( $stats['stats']['size_before'], $stats['stats']['size_after'], $stats['stats']['time'], $stats['stats']['percent'], $stats['stats']['bytes'] ) = |
| 355 | array( $size_before, $size_after, $total_time, $compression, $bytes_saved ); |
| 356 | |
| 357 | |
| 358 | //Set smush status for all the images, store it in wp-smpro-smush-data |
| 359 | if ( ! $has_errors ) { |
| 360 | update_post_meta( $ID, self::SMUSHED_META_KEY, $stats ); |
| 361 | } |
| 362 | |
| 363 | //return stats |
| 364 | return $has_errors ? $errors : $stats['stats']; |
| 365 | } |
| 366 | |
| 367 | /** |
| 368 | * Read the image paths from an attachment's meta data and process each image |
| 369 | * with wp_smushit() |
| 370 | * |
| 371 | * Filters wp_generate_attachment_metadata |
| 372 | * @param $meta |
| 373 | * @param null $ID |
| 374 | * |
| 375 | * @return mixed |
| 376 | */ |
| 377 | function filter_generate_attachment_metadata( $meta, $ID = null ){ |
| 378 | //Flag to check, if original size image needs to be smushed or not |
| 379 | $smush_full = true; |
| 380 | $errors = new WP_Error(); |
| 381 | $stats = array( |
| 382 | "stats" => array_merge( $this->_get_size_signature(), array( |
| 383 | 'api_version' => - 1, |
| 384 | 'lossy' => - 1 |
| 385 | ) |
| 386 | ), |
| 387 | 'sizes' => array() |
| 388 | ); |
| 389 | |
| 390 | $size_before = $size_after = $compression = $total_time = $bytes_saved = 0; |
| 391 | |
| 392 | if ( $ID && wp_attachment_is_image( $ID ) === false ) { |
| 393 | return $meta; |
| 394 | } |
| 395 | |
| 396 | //File path and URL for original image |
| 397 | $attachment_file_path = get_attached_file( $ID ); |
| 398 | $attachment_file_url = wp_get_attachment_url( $ID ); |
| 399 | |
| 400 | // If images has other registered size, smush them first |
| 401 | if ( ! empty( $meta['sizes'] ) ) { |
| 402 | |
| 403 | foreach ( $meta['sizes'] as $size_key => $size_data ) { |
| 404 | |
| 405 | //if there is a large size, then we will set a flag to leave the original untouched |
| 406 | if ( $size_key == 'large' ) { |
| 407 | $smush_full = false; |
| 408 | } |
| 409 | |
| 410 | // We take the original image. The 'sizes' will all match the same URL and |
| 411 | // path. So just get the dirname and replace the filename. |
| 412 | |
| 413 | $attachment_file_path_size = trailingslashit( dirname( $attachment_file_path ) ) . $size_data['file']; |
| 414 | $attachment_file_url_size = trailingslashit( dirname( $attachment_file_url ) ) . $size_data['file']; |
| 415 | |
| 416 | //Store details for each size key |
| 417 | $response = $this->do_smushit( $ID, $attachment_file_path_size, $attachment_file_url_size ); |
| 418 | |
| 419 | if ( is_wp_error( $response ) ) { |
| 420 | return $meta; |
| 421 | } |
| 422 | |
| 423 | if ( ! empty( $response['data'] ) ) { |
| 424 | $stats['sizes'][ $size_key ] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $response['data'] ); |
| 425 | } |
| 426 | |
| 427 | //Total Stats, store all data in bytes |
| 428 | if ( isset( $response['data'] ) ) { |
| 429 | list( $size_before, $size_after, $total_time, $compression, $bytes_saved ) |
| 430 | = $this->_update_stats_data( $response['data'], $size_before, $size_after, $total_time, $bytes_saved ); |
| 431 | } else { |
| 432 | $errors->add( "image_size_error" . $size_key, sprintf( __( "Size '%s' not processed correctly", WP_SMUSH_DOMAIN ), $size_key ) ); |
| 433 | } |
| 434 | |
| 435 | if ( empty( $stats['stats']['api_version'] ) ) { |
| 436 | $stats['stats']['api_version'] = $response['data']->api_version; |
| 437 | $stats['stats']['lossy'] = $response['data']->lossy; |
| 438 | } |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | //If original size is supposed to be smushed |
| 443 | if ( $smush_full ) { |
| 444 | |
| 445 | $full_image_response = $this->do_smushit( $ID, $attachment_file_path, $attachment_file_url ); |
| 446 | |
| 447 | if ( is_wp_error( $full_image_response ) ) { |
| 448 | return $meta; |
| 449 | } |
| 450 | |
| 451 | if ( ! empty( $full_image_response['data'] ) ) { |
| 452 | $stats['sizes']['full'] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $full_image_response['data'] ); |
| 453 | } else { |
| 454 | $errors->add( "image_size_error", __( "Size 'full' not processed correctly", WP_SMUSH_DOMAIN ) ); |
| 455 | } |
| 456 | |
| 457 | //Update stats |
| 458 | if ( isset( $full_image_response['data'] ) ) { |
| 459 | list( $size_before, $size_after, $total_time, $compression, $bytes_saved ) |
| 460 | = $this->_update_stats_data( $full_image_response['data'], $size_before, $size_after, $total_time, $bytes_saved ); |
| 461 | } else { |
| 462 | $errors->add( "image_size_error", __( "Size 'full' not processed correctly", WP_SMUSH_DOMAIN ) ); |
| 463 | } |
| 464 | |
| 465 | } |
| 466 | |
| 467 | $has_errors = (bool) count( $errors->get_error_messages() ); |
| 468 | |
| 469 | //Store stats |
| 470 | |
| 471 | list( $stats['stats']['size_before'], $stats['stats']['size_after'], $stats['stats']['time'], $stats['stats']['percent'], $stats['stats']['bytes'] ) = |
| 472 | array( $size_before, $size_after, $total_time, $compression, $bytes_saved ); |
| 473 | |
| 474 | |
| 475 | //Set smush status for all the images, store it in wp-smpro-smush-data |
| 476 | if ( ! $has_errors ) { |
| 477 | update_post_meta( $ID, self::SMUSHED_META_KEY, $stats ); |
| 478 | } |
| 479 | |
| 480 | //return stats |
| 481 | return $has_errors ? $meta : $stats['stats']; |
| 482 | } |
| 483 | |
| 484 | /** |
| 485 | * Post an image to Smush. |
| 486 | * |
| 487 | * @param string $file_url URL of the file to send to Smush |
| 488 | * |
| 489 | * @return array Returns array containing success status, and stats |
| 490 | */ |
| 491 | function _post( $file_path, $file_size ) { |
| 492 | global $log; |
| 493 | |
| 494 | $data = false; |
| 495 | |
| 496 | $file = @fopen( $file_path, 'r' ); |
| 497 | $file_data = fread( $file, $file_size ); |
| 498 | $headers = array( |
| 499 | 'accept' => 'application/json', // The API returns JSON |
| 500 | 'content-type' => 'application/binary', // Set content type to binary |
| 501 | ); |
| 502 | |
| 503 | //Check if premium member, add API key |
| 504 | $api_key = $this->_get_api_key(); |
| 505 | if ( ! empty( $api_key ) ) { |
| 506 | $headers['apikey'] = $api_key; |
| 507 | } |
| 508 | |
| 509 | //Check if lossy compression allowed and add it to headers |
| 510 | $lossy = get_option( WP_SMUSH_PREFIX . 'lossy' ); |
| 511 | |
| 512 | if ( $lossy && $this->is_premium() ) { |
| 513 | $headers['lossy'] = 'true'; |
| 514 | } else { |
| 515 | $headers['lossy'] = 'false'; |
| 516 | } |
| 517 | |
| 518 | $args = array( |
| 519 | 'headers' => $headers, |
| 520 | 'body' => $file_data, |
| 521 | 'timeout' => WP_SMUSH_TIMEOUT, |
| 522 | 'user-agent' => WP_SMUSH_UA |
| 523 | ); |
| 524 | $result = wp_remote_post( WP_SMUSH_API, $args ); |
| 525 | |
| 526 | //Close file connection |
| 527 | fclose( $file ); |
| 528 | unset( $file_data );//free memory |
| 529 | if ( is_wp_error( $result ) ) { |
| 530 | //Handle error |
| 531 | $data['message'] = sprintf( __( 'Error posting to API: %s', WP_SMUSH_DOMAIN ), $result->get_error_message() ); |
| 532 | $data['success'] = false; |
| 533 | unset( $result ); //free memory |
| 534 | return $data; |
| 535 | } else if ( '200' != wp_remote_retrieve_response_code( $result ) ) { |
| 536 | //Handle error |
| 537 | $data['message'] = sprintf( __( 'Error posting to API: %s %s', WP_SMUSHIT_DOMAIN ), wp_remote_retrieve_response_code( $result ), wp_remote_retrieve_response_message( $result ) ); |
| 538 | $data['success'] = false; |
| 539 | unset( $result ); //free memory |
| 540 | |
| 541 | return $data; |
| 542 | } |
| 543 | |
| 544 | //If there is a response and image was successfully optimised |
| 545 | $response = json_decode( $result['body'] ); |
| 546 | if ( $response && $response->success == true ) { |
| 547 | |
| 548 | //If there is any savings |
| 549 | if ( $response->data->bytes_saved > 0 ) { |
| 550 | $image = base64_decode( $response->data->image ); //base64_decode is necessary to send binary img over JSON, no security problems here! |
| 551 | $image_md5 = md5( $response->data->image ); |
| 552 | if ( $response->data->image_md5 != $image_md5 ) { |
| 553 | //Handle error |
| 554 | $data['message'] = __( 'Smush data corrupted, try again.', WP_SMUSH_DOMAIN ); |
| 555 | $data['success'] = false; |
| 556 | unset( $image );//free memory |
| 557 | } else { |
| 558 | $data['success'] = true; |
| 559 | $data['data'] = $response->data; |
| 560 | $data['data']->image = $image; |
| 561 | unset( $image );//free memory |
| 562 | } |
| 563 | } else { |
| 564 | //just return the data |
| 565 | $data['success'] = true; |
| 566 | $data['data'] = $response->data; |
| 567 | } |
| 568 | } else { |
| 569 | //Server side error, get message from response |
| 570 | $data['message'] = ! empty( $response->data ) ? $response->data : __( "Image couldn't be smushed", WP_SMUSH_DOMAIN ); |
| 571 | $data['success'] = false; |
| 572 | } |
| 573 | |
| 574 | unset( $result );//free memory |
| 575 | unset( $response );//free memory |
| 576 | return $data; |
| 577 | } |
| 578 | |
| 579 | |
| 580 | /** |
| 581 | * Print column header for Smush results in the media library using |
| 582 | * the `manage_media_columns` hook. |
| 583 | */ |
| 584 | function columns( $defaults ) { |
| 585 | $defaults['smushit'] = 'WP Smush'; |
| 586 | |
| 587 | return $defaults; |
| 588 | } |
| 589 | |
| 590 | /** |
| 591 | * Return the filesize in a humanly readable format. |
| 592 | * Taken from http://www.php.net/manual/en/function.filesize.php#91477 |
| 593 | */ |
| 594 | function format_bytes( $bytes, $precision = 2 ) { |
| 595 | $units = array( 'B', 'KB', 'MB', 'GB', 'TB' ); |
| 596 | $bytes = max( $bytes, 0 ); |
| 597 | $pow = floor( ( $bytes ? log( $bytes ) : 0 ) / log( 1024 ) ); |
| 598 | $pow = min( $pow, count( $units ) - 1 ); |
| 599 | $bytes /= pow( 1024, $pow ); |
| 600 | |
| 601 | return round( $bytes, $precision ) . ' ' . $units[ $pow ]; |
| 602 | } |
| 603 | |
| 604 | /** |
| 605 | * Print column data for Smush results in the media library using |
| 606 | * the `manage_media_custom_column` hook. |
| 607 | */ |
| 608 | function custom_column( $column_name, $id ) { |
| 609 | if ( 'smushit' == $column_name ) { |
| 610 | $this->set_status( $id ); |
| 611 | } |
| 612 | } |
| 613 | |
| 614 | /** |
| 615 | * Check if user is premium member, check for api key |
| 616 | * |
| 617 | * @return mixed|string |
| 618 | */ |
| 619 | function is_premium() { |
| 620 | |
| 621 | //no api key set, always false |
| 622 | $api_key = $this->_get_api_key(); |
| 623 | if ( empty( $api_key ) ) { |
| 624 | return false; |
| 625 | } |
| 626 | |
| 627 | $key = "wp-smush-valid-$api_key"; //add apikey to transient key in case it changes |
| 628 | |
| 629 | if ( false === ( $valid = get_site_transient( $key ) ) ) { |
| 630 | // call api |
| 631 | $url = self::API_SERVER . '&key=' . urlencode( $api_key ); |
| 632 | |
| 633 | $request = wp_remote_get( $url, array( |
| 634 | "timeout" => 3 |
| 635 | ) |
| 636 | ); |
| 637 | |
| 638 | if ( ! is_wp_error( $request ) && '200' == wp_remote_retrieve_response_code( $request ) ) { |
| 639 | $result = json_decode( wp_remote_retrieve_body( $request ) ); |
| 640 | if ( $result && $result->success ) { |
| 641 | $valid = true; |
| 642 | set_site_transient( $key, 1, 12 * HOUR_IN_SECONDS ); |
| 643 | } else { |
| 644 | $valid = false; |
| 645 | set_site_transient( $key, 0, 30 * MINUTE_IN_SECONDS ); //cache failure much shorter |
| 646 | } |
| 647 | |
| 648 | } else { |
| 649 | $valid = false; |
| 650 | set_site_transient( $key, 0, 5 * MINUTE_IN_SECONDS ); //cache network failure even shorter, we don't want a request every pageload |
| 651 | } |
| 652 | |
| 653 | } |
| 654 | |
| 655 | return (bool) $valid; |
| 656 | } |
| 657 | |
| 658 | /** |
| 659 | * Returns api key |
| 660 | * |
| 661 | * @return mixed |
| 662 | */ |
| 663 | private function _get_api_key() { |
| 664 | if ( defined( 'WPMUDEV_APIKEY' ) ) { |
| 665 | $api_key = WPMUDEV_APIKEY; |
| 666 | } else { |
| 667 | $api_key = get_site_option( 'wpmudev_apikey' ); |
| 668 | } |
| 669 | |
| 670 | return $api_key; |
| 671 | } |
| 672 | |
| 673 | |
| 674 | /** |
| 675 | * Checks if image is already smushed |
| 676 | * |
| 677 | * @param int $id |
| 678 | * @param array $data |
| 679 | * |
| 680 | * @return bool|mixed |
| 681 | */ |
| 682 | function is_smushed( $id, $data = null ) { |
| 683 | |
| 684 | //For new images |
| 685 | $wp_is_smushed = get_post_meta( $id, 'wp-is-smushed', true ); |
| 686 | |
| 687 | //Not smushed, backward compatibility, check attachment metadata |
| 688 | if ( ! $wp_is_smushed && $data !== null ) { |
| 689 | if ( isset( $data['wp_smushit'] ) && ! empty( $data['wp_smushit'] ) ) { |
| 690 | $wp_is_smushed = true; |
| 691 | } |
| 692 | } |
| 693 | |
| 694 | return $wp_is_smushed; |
| 695 | } |
| 696 | |
| 697 | /** |
| 698 | * Returns size saved from the api call response |
| 699 | * |
| 700 | * @param string $message |
| 701 | * |
| 702 | * @return string|bool |
| 703 | */ |
| 704 | function get_saved_size( $message ) { |
| 705 | if ( preg_match( '/\((.*)\)/', $message, $matches ) ) { |
| 706 | return isset( $matches[1] ) ? $matches[1] : false; |
| 707 | } |
| 708 | |
| 709 | return false; |
| 710 | } |
| 711 | |
| 712 | /** |
| 713 | * Set send button status |
| 714 | * |
| 715 | * @param $id |
| 716 | * @param bool $echo |
| 717 | * @param bool $text_only |
| 718 | * |
| 719 | * @return string|void |
| 720 | */ |
| 721 | function set_status( $id, $echo = true, $text_only = false ) { |
| 722 | $status_txt = $button_txt = ''; |
| 723 | $show_button = false; |
| 724 | $wp_smush_data = get_post_meta( $id, self::SMUSHED_META_KEY, true ); |
| 725 | // if the image is smushed |
| 726 | if ( ! empty( $wp_smush_data ) ) { |
| 727 | |
| 728 | $bytes = isset( $wp_smush_data['stats']['bytes'] ) ? $wp_smush_data['stats']['bytes'] : 0; |
| 729 | $bytes_readable = ! empty( $bytes ) ? $this->format_bytes( $bytes ) : ''; |
| 730 | $percent = isset( $wp_smush_data['stats']['percent'] ) ? $wp_smush_data['stats']['percent'] : 0; |
| 731 | $percent = $percent < 0 ? 0 : $percent; |
| 732 | |
| 733 | if ( isset( $wp_smush_data['stats']['size_before'] ) && $wp_smush_data['stats']['size_before'] == 0 ) { |
| 734 | $status_txt = __( 'Error processing request', WP_SMUSH_DOMAIN ); |
| 735 | $show_button = true; |
| 736 | } else { |
| 737 | if ( $bytes == 0 || $percent == 0 ) { |
| 738 | $status_txt = __( 'Already Optimized', WP_SMUSH_DOMAIN ); |
| 739 | } elseif ( ! empty( $percent ) && ! empty( $bytes_readable ) ) { |
| 740 | $status_txt = sprintf( __( "Reduced by %s ( %01.1f%% )", WP_SMUSH_DOMAIN ), $bytes_readable, number_format_i18n( $percent, 2, '.', '' ) ); |
| 741 | } |
| 742 | } |
| 743 | |
| 744 | // the button text |
| 745 | $button_txt = __( 'Re-smush', WP_SMUSH_DOMAIN ); |
| 746 | } else { |
| 747 | |
| 748 | // the status |
| 749 | $status_txt = __( 'Not processed', WP_SMUSH_DOMAIN ); |
| 750 | |
| 751 | // we need to show the smush button |
| 752 | $show_button = true; |
| 753 | |
| 754 | // the button text |
| 755 | $button_txt = __( 'Smush Now!', WP_SMUSH_DOMAIN ); |
| 756 | } |
| 757 | if ( $text_only ) { |
| 758 | return $status_txt; |
| 759 | } |
| 760 | |
| 761 | $text = $this->column_html( $id, $status_txt, $button_txt, $show_button, $wp_smush_data, $echo ); |
| 762 | if ( ! $echo ) { |
| 763 | return $text; |
| 764 | } |
| 765 | } |
| 766 | |
| 767 | /** |
| 768 | * Print the column html |
| 769 | * |
| 770 | * @param string $id Media id |
| 771 | * @param string $status_txt Status text |
| 772 | * @param string $button_txt Button label |
| 773 | * @param boolean $show_button Whether to shoe the button |
| 774 | * |
| 775 | * @return null |
| 776 | */ |
| 777 | function column_html( $id, $status_txt = "", $button_txt = "", $show_button = true, $smushed = false, $echo = true ) { |
| 778 | $allowed_images = array( 'image/jpeg', 'image/jpg', 'image/png', 'image/gif' ); |
| 779 | // don't proceed if attachment is not image, or if image is not a jpg, png or gif |
| 780 | if ( ! wp_attachment_is_image( $id ) || ! in_array( get_post_mime_type( $id ), $allowed_images ) ) { |
| 781 | return; |
| 782 | } |
| 783 | $html = ' |
| 784 | <p class="smush-status">' . $status_txt . '</p>'; |
| 785 | // if we aren't showing the button |
| 786 | if ( ! $show_button ) { |
| 787 | if ( $echo ) { |
| 788 | echo $html; |
| 789 | |
| 790 | return; |
| 791 | } else { |
| 792 | if ( ! $smushed ) { |
| 793 | $class = ' currently-smushing'; |
| 794 | } else { |
| 795 | $class = ' smushed'; |
| 796 | } |
| 797 | |
| 798 | return '<div class="smush-wrap' . $class . '">' . $html . '</div>'; |
| 799 | } |
| 800 | } |
| 801 | if ( ! $echo ) { |
| 802 | $html .= ' |
| 803 | <button class="button button-primary wp-smush-send" data-id="' . $id . '"> |
| 804 | <span>' . $button_txt . '</span> |
| 805 | </button>'; |
| 806 | if ( ! $smushed ) { |
| 807 | $class = ' unsmushed'; |
| 808 | } else { |
| 809 | $class = ' smushed'; |
| 810 | } |
| 811 | |
| 812 | return '<div class="smush-wrap' . $class . '">' . $html . '</div>'; |
| 813 | } else { |
| 814 | $html .= '<button class="button wp-smush-send" data-id="' . $id . '"> |
| 815 | <span>' . $button_txt . '</span> |
| 816 | </button>'; |
| 817 | echo $html; |
| 818 | } |
| 819 | } |
| 820 | |
| 821 | /** |
| 822 | * Migrates smushit api message to the latest structure |
| 823 | * |
| 824 | * |
| 825 | * @return void |
| 826 | */ |
| 827 | function migrate() { |
| 828 | |
| 829 | if ( ! version_compare( $this->version, "1.7.1", "lte" ) ) { |
| 830 | return; |
| 831 | } |
| 832 | |
| 833 | $migrated_version = get_option( self::MIGRATED_VERSION ); |
| 834 | |
| 835 | if ( $migrated_version === $this->version ) { |
| 836 | return; |
| 837 | } |
| 838 | |
| 839 | global $wpdb; |
| 840 | |
| 841 | $q = $wpdb->prepare( "SELECT * FROM `" . $wpdb->postmeta . "` WHERE `meta_key`=%s AND `meta_value` LIKE %s ", "_wp_attachment_metadata", "%wp_smushit%" ); |
| 842 | $results = $wpdb->get_results( $q ); |
| 843 | |
| 844 | if ( count( $results ) < 1 ) { |
| 845 | return; |
| 846 | } |
| 847 | |
| 848 | $migrator = new WpSmushMigrate(); |
| 849 | foreach ( $results as $attachment_meta ) { |
| 850 | $migrated_message = $migrator->migrate_api_message( maybe_unserialize( $attachment_meta->meta_value ) ); |
| 851 | if ( $migrated_message !== array() ) { |
| 852 | update_post_meta( $attachment_meta->post_id, self::SMUSHED_META_KEY, $migrated_message ); |
| 853 | } |
| 854 | } |
| 855 | |
| 856 | update_option( self::MIGRATED_VERSION, $this->version ); |
| 857 | |
| 858 | } |
| 859 | |
| 860 | /** |
| 861 | * @param Object $response_data |
| 862 | * @param $size_before |
| 863 | * @param $size_after |
| 864 | * @param $total_time |
| 865 | * @param $bytes_saved |
| 866 | * |
| 867 | * @return array |
| 868 | */ |
| 869 | private function _update_stats_data( $response_data, $size_before, $size_after, $total_time, $bytes_saved ) { |
| 870 | $size_before += ! empty( $response_data->before_size ) ? (int) $response_data->before_size : 0; |
| 871 | $size_after += ( ! empty( $response_data->after_size ) && $response_data->after_size > 0 ) ? (int) $response_data->after_size : (int) $response_data->before_size; |
| 872 | $total_time += ! empty( $response_data->time ) ? (float) $response_data->time : 0; |
| 873 | $bytes_saved += ( ! empty( $response_data->bytes_saved ) && $response_data->bytes_saved > 0 ) ? $response_data->bytes_saved : 0; |
| 874 | $compression = ( $bytes_saved > 0 && $size_before > 0 ) ? ( ( $bytes_saved / $size_before ) * 100 ) : 0; |
| 875 | |
| 876 | return array( $size_before, $size_after, $total_time, $compression, $bytes_saved ); |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | global $WpSmush; |
| 881 | $WpSmush = new WpSmush(); |
| 882 | |
| 883 | } |
| 884 | |
| 885 | //Include Admin classes |
| 886 | require_once( WP_SMUSH_DIR . '/lib/class-wp-smush-bulk.php' ); |
| 887 | require_once( WP_SMUSH_DIR . '/lib/class-wp-smush-admin.php' ); |
| 888 | //include_once( WP_SMUSH_DIR . '/extras/dash-notice/wpmudev-dash-notification.php' ); |
| 889 | |
| 890 | //register items for the dashboard plugin |
| 891 | global $wpmudev_notices; |
| 892 | $wpmudev_notices[] = array( |
| 893 | 'id' => 912164, |
| 894 | 'name' => 'WP Smush Pro', |
| 895 | 'screens' => array( |
| 896 | 'media_page_wp-smush-bulk', |
| 897 | 'upload' |
| 898 | ) |
| 899 | ); |