/home/arranoyd/magicraft/wp-content/plugins/wp-smushit/lib/class-wp-smush.php
<?php
//Helper Class
require_once WP_SMUSH_DIR . "lib/class-wp-smush-helper.php";
//Settings Class
require_once WP_SMUSH_DIR . "lib/class-wp-smush-settings.php";
//Migration Class
require_once WP_SMUSH_DIR . "lib/class-wp-smush-migrate.php";
//Stats
require_once WP_SMUSH_DIR . "lib/class-wp-smush-db.php";
//Include Resize class
require_once WP_SMUSH_DIR . 'lib/class-wp-smush-resize.php';
//Include PNG to JPG Converter
require_once WP_SMUSH_DIR . 'lib/class-wp-smush-png_jpg.php';
//Include Social Sharing
require_once WP_SMUSH_DIR . 'lib/class-wp-smush-share.php';
//Include Image backup class
require_once WP_SMUSH_DIR . 'lib/class-wp-smush-backup.php';
//Include Smush Async class
require_once WP_SMUSH_DIR . 'lib/class-wp-smush-async.php';
if ( ! class_exists( 'WpSmush' ) ) {
class WpSmush {
var $version = WP_SMUSH_VERSION;
/**
* @var Stores the value of is_pro function
*/
private $is_pro;
/**
* Api server url to check api key validity
*
*/
var $api_server = 'https://premium.wpmudev.org/api/smush/v1/check/';
/**
* Meta key to save smush result to db
*
*
*/
var $smushed_meta_key = 'wp-smpro-smush-data';
/**
* Meta key to save migrated version
*
*/
var $migrated_version_key = "wp-smush-migrated-version";
/**
* Super Smush is enabled or not
* @var bool
*/
var $lossy_enabled = false;
/**
* Whether to Smush the original Image
* @var bool
*/
var $smush_original = false;
/**
* Whether to Preserver the exif data or not
* @var bool
*/
var $keep_exif = false;
/** @var Attachment id for the Image being smushed currently */
var $attachment_id;
/**
* Attachment type, being smushed currently
*
* @var string Possible values, "wp", "nextgen"
*
*/
var $media_type = 'wp';
/**
* Constructor
*/
function __construct() {
//Redirect to Settings page
add_action( 'activated_plugin', array( $this, 'wp_smush_redirect' ) );
/**
* Smush image (Auto Smush ) when `wp_update_attachment_metadata` filter is fired
*/
add_filter( 'wp_update_attachment_metadata', array(
$this,
'smush_image'
), 15, 2 );
//Delete Backup files
add_action( 'delete_attachment', array(
$this,
'delete_images'
), 12 );
//Optimise WP Retina 2x images
add_action( 'wr2x_retina_file_added', array( $this, 'smush_retina_image' ), 20, 3 );
//Add Smush Columns
add_filter( 'manage_media_columns', array( $this, 'columns' ) );
add_action( 'manage_media_custom_column', array( $this, 'custom_column' ), 10, 2 );
add_filter( 'manage_upload_sortable_columns', array( $this, 'sortable_column' ) );
//Manage column sorting
add_action( 'pre_get_posts', array( $this, 'smushit_orderby' ) );
//Enqueue Scripts, And Initialize variables
add_action( 'admin_init', array( $this, 'admin_init' ) );
//Load NextGen Gallery, S3, if hooked too late or early, auto smush doesn't works, also Load after settings have been saved on init action
add_action( 'plugins_loaded', array( $this, 'load_modules' ), 90 );
//Send Smush Stats for pro members
add_filter( 'wpmudev_api_project_extra_data-912164', array( $this, 'send_smush_stats' ) );
//Send Smush Stats for pro members
add_action( 'wp_ajax_smush_show_warning', array( $this, 'show_warning_ajax' ) );
//Instanitate the Async class
add_action( 'plugins_loaded', array( $this, 'wp_smush_async' ) );
//Handle the Async optimisation
add_action( 'wp_async_wp_generate_attachment_metadata', array( $this, 'wp_smush_handle_async' ) );
//Handle the Async optimisation
add_action( 'wp_async_wp_save_image_editor_file', array( $this, 'wp_smush_handle_editor_async' ), '', 2 );
// Handle other file uploads optimisation
add_action( 'add_attachment', array( $this, 'wp_smush_handle_other_uploads' ) );
}
/**
* Initialise the setting variables
*/
function initialise() {
global $wpsmush_settings;
//Check if Lossy enabled
$opt_lossy = WP_SMUSH_PREFIX . 'lossy';
$this->lossy_enabled = $this->validate_install() && $wpsmush_settings->get_setting( $opt_lossy, false );
//Check if Smush Original enabled
$opt_original = WP_SMUSH_PREFIX . 'original';
$this->smush_original = $this->validate_install() && $wpsmush_settings->get_setting( $opt_original, false );
//Check Whether to keep exif or not
$opt_keep_exif = WP_SMUSH_PREFIX . 'keep_exif';
$this->keep_exif = $wpsmush_settings->get_setting( $opt_keep_exif, false );
}
function admin_init() {
global $wpsmush_dir;
//Handle Notice dismiss
$this->dismiss_smush_upgrade();
//Perform Migration if required
$this->migrate();
//Initialize variables
$this->initialise();
//Create a clas object, if doesn't exists
if ( empty( $wpsmush_dir ) && class_exists( 'WpSmushDir' ) ) {
$wpsmush_dir = new WpSmushDir();
}
$wpsmush_dir->create_table();
}
/**
* Process an image with Smush.
*
* @param string $file_path Absolute path to the image
*
* @return array|bool
*
*/
function do_smushit( $file_path = '' ) {
$errors = new WP_Error();
$dir_name = dirname( $file_path );
//Check if file exists and the directory is writable
if ( empty( $file_path ) ) {
$errors->add( "empty_path", __( "File path is empty", 'wp-smushit' ) );
} elseif ( ! file_exists( $file_path ) || ! is_file( $file_path ) ) {
// check that the file exists
$errors->add( "file_not_found", sprintf( __( "Could not find %s", 'wp-smushit' ), $file_path ) );
} elseif ( ! is_writable( $dir_name ) ) {
// check that the file is writable
$errors->add( "not_writable", sprintf( __( "%s is not writable", 'wp-smushit' ), $dir_name ) );
}
$file_size = file_exists( $file_path ) ? filesize( $file_path ) : '';
//Check if premium user
$max_size = $this->validate_install() ? WP_SMUSH_PREMIUM_MAX_BYTES : WP_SMUSH_MAX_BYTES;
//Check if file exists
if ( $file_size == 0 ) {
$errors->add( "image_not_found", '<p>' . sprintf( __( 'Skipped (%s), image not found. Attachment: %s', 'wp-smushit' ), size_format( $file_size, 1 ), basename( $file_path ) ) . '</p>' );
} elseif ( $file_size > $max_size ) {
//Check size limit
$errors->add( "size_limit", '<p>' . sprintf( __( 'Skipped (%s), size limit exceeded. Attachment: %s', 'wp-smushit' ), size_format( $file_size, 1 ), basename( $file_path ) ) . '</p>' );
}
if ( count( $errors->get_error_messages() ) ) {
return $errors;
}
// save original file permissions
clearstatcache();
$perms = fileperms( $file_path ) & 0777;
/** Send image for smushing, and fetch the response */
$response = $this->_post( $file_path, $file_size );
if ( ! $response['success'] ) {
$errors->add( "false_response", $response['message'] );
} else if ( empty( $response['data'] ) ) {
//If there is no data
$errors->add( "no_data", __( 'Unknown API error', 'wp-smushit' ) );
}
if ( count( $errors->get_error_messages() ) ) {
return $errors;
}
//If there are no savings, or image returned is bigger in size
if ( ( ! empty( $response['data']->bytes_saved ) && intval( $response['data']->bytes_saved ) <= 0 )
|| empty( $response['data']->image )
) {
return $response;
}
$tempfile = $file_path . ".tmp";
//Add the file as tmp
file_put_contents( $tempfile, $response['data']->image );
//replace the file
$success = @rename( $tempfile, $file_path );
//if tempfile still exists, unlink it
if ( file_exists( $tempfile ) ) {
@unlink( $tempfile );
}
//If file renaming failed
if ( ! $success ) {
@copy( $tempfile, $file_path );
@unlink( $tempfile );
}
//Some servers are having issue with file permission, this should fix it
if ( empty( $perms ) || ! $perms ) {
//Source: WordPress Core
$stat = stat( dirname( $file_path ) );
$perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
}
@ chmod( $file_path, $perms );
return $response;
}
/**
* Fills $placeholder array with values from $data array
*
* @param array $placeholders
* @param array $data
*
* @return array
*/
function _array_fill_placeholders( array $placeholders, array $data ) {
$placeholders['percent'] = $data['compression'];
$placeholders['bytes'] = $data['bytes_saved'];
$placeholders['size_before'] = $data['before_size'];
$placeholders['size_after'] = $data['after_size'];
$placeholders['time'] = $data['time'];
return $placeholders;
}
/**
* Returns signature for single size of the smush api message to be saved to db;
*
* @return array
*/
function _get_size_signature() {
return array(
'percent' => 0,
'bytes' => 0,
'size_before' => 0,
'size_after' => 0,
'time' => 0
);
}
/**
* Optimises the image sizes
*
* Note: Function name is bit confusing, it is for optimisation, and calls the resizing function as well
*
* Read the image paths from an attachment's meta data and process each image
* with wp_smushit().
*
* @param $meta
* @param null $ID
*
* @return mixed
*/
function resize_from_meta_data( $meta, $ID = null ) {
global $wpsmush_settings, $wpsmush_helper, $wpsmushit_admin;
//Flag to check, if original size image should be smushed or not
$original = $wpsmush_settings->get_setting( WP_SMUSH_PREFIX . 'original', false );
$smush_full = ( $this->validate_install() && $original == 1 ) ? true : false;
$errors = new WP_Error();
$stats = array(
"stats" => array_merge( $this->_get_size_signature(), array(
'api_version' => - 1,
'lossy' => - 1,
'keep_exif' => false
)
),
'sizes' => array()
);
$size_before = $size_after = $compression = $total_time = $bytes_saved = 0;
if ( $ID && wp_attachment_is_image( $ID ) === false ) {
return $meta;
}
//Set attachment id and Media type
$this->attachment_id = $ID;
$this->media_type = "wp";
//File path and URL for original image
$attachment_file_path = $wpsmush_helper->get_attached_file( $ID );
// If images has other registered size, smush them first
if ( ! empty( $meta['sizes'] ) ) {
//if smush original is set to false, otherwise smush
//Check for large size, we will set a flag to leave the original untouched
if ( ! $smush_full ) {
if ( array_key_exists( 'large', $meta['sizes'] ) ) {
$smush_full = false;
} else {
$smush_full = true;
}
}
if ( class_exists( 'finfo' ) ) {
$finfo = new finfo( FILEINFO_MIME_TYPE );
} else {
$finfo = false;
}
foreach ( $meta['sizes'] as $size_key => $size_data ) {
//Check if registered size is supposed to be Smushed or not
if ( 'full' != $size_key && $wpsmushit_admin->skip_image_size( $size_key ) ) {
continue;
}
// We take the original image. The 'sizes' will all match the same URL and
// path. So just get the dirname and replace the filename.
$attachment_file_path_size = path_join( dirname( $attachment_file_path ), $size_data['file'] );
/**
* Allows S3 to hook over here and check if the given file path exists else download the file
*/
do_action('smush_file_exists', $attachment_file_path_size, $ID, $size_data );
if ( $finfo ) {
$ext = is_file( $attachment_file_path_size ) ? $finfo->file( $attachment_file_path_size ) : '';
} elseif ( function_exists( 'mime_content_type' ) ) {
$ext = mime_content_type( $attachment_file_path_size );
} else {
$ext = false;
}
if ( $ext ) {
$valid_mime = array_search(
$ext,
array(
'jpg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
),
true
);
if ( false === $valid_mime ) {
continue;
}
}
/**
* Allows to skip a image from smushing
*
* @param bool , Smush image or not
* @$size string, Size of image being smushed
*/
$smush_image = apply_filters( 'wp_smush_media_image', true, $size_key );
if ( ! $smush_image ) {
continue;
}
//Store details for each size key
$response = $this->do_smushit( $attachment_file_path_size );
if ( is_wp_error( $response ) ) {
return $response;
}
//If there are no stats
if ( empty( $response['data'] ) ) {
continue;
}
//If the image size grew after smushing, skip it
if ( $response['data']->after_size > $response['data']->before_size ) {
continue;
}
//All Clear, Store the stat
//@todo: Move the existing stats code over here, we don't need to do the stats part twice
$stats['sizes'][ $size_key ] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $response['data'] );
if ( empty( $stats['stats']['api_version'] ) || $stats['stats']['api_version'] == - 1 ) {
$stats['stats']['api_version'] = $response['data']->api_version;
$stats['stats']['lossy'] = $response['data']->lossy;
$stats['stats']['keep_exif'] = ! empty( $response['data']->keep_exif ) ? $response['data']->keep_exif : 0;
}
}
//Upfront Integration
$stats = $this->smush_upfront_images( $ID, $stats );
} else {
$smush_full = true;
}
/**
* Allows to skip a image from smushing
*
* @param bool , Smush image or not
* @$size string, Size of image being smushed
*/
$smush_full_image = apply_filters( 'wp_smush_media_image', true, 'full' );
//Whether to update the image stats or not
$store_stats = true;
//If original size is supposed to be smushed
if ( $smush_full && $smush_full_image ) {
$full_image_response = $this->do_smushit( $attachment_file_path );
if ( is_wp_error( $full_image_response ) ) {
return $full_image_response;
}
//If there are no stats
if ( empty( $full_image_response['data'] ) ) {
$store_stats = false;
}
//If the image size grew after smushing, skip it
if ( $full_image_response['data']->after_size > $full_image_response['data']->before_size ) {
$store_stats = false;
}
if ( $store_stats ) {
$stats['sizes']['full'] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $full_image_response['data'] );
}
//Api version and lossy, for some images, full image i skipped and for other images only full exists
//so have to add code again
if ( empty( $stats['stats']['api_version'] ) || $stats['stats']['api_version'] == - 1 ) {
$stats['stats']['api_version'] = $full_image_response['data']->api_version;
$stats['stats']['lossy'] = $full_image_response['data']->lossy;
$stats['stats']['keep_exif'] = ! empty( $full_image_response['data']->keep_exif ) ? $full_image_response['data']->keep_exif : 0;
}
}
$has_errors = (bool) count( $errors->get_error_messages() );
//Set smush status for all the images, store it in wp-smpro-smush-data
if ( ! $has_errors ) {
$existing_stats = get_post_meta( $ID, $this->smushed_meta_key, true );
if ( ! empty( $existing_stats ) ) {
//Update stats for each size
if ( isset( $existing_stats['sizes'] ) && ! empty( $stats['sizes'] ) ) {
foreach ( $existing_stats['sizes'] as $size_name => $size_stats ) {
//if stats for a particular size doesn't exists
if ( empty( $stats['sizes'][ $size_name ] ) ) {
$stats['sizes'][ $size_name ] = $existing_stats['sizes'][ $size_name ];
} else {
$existing_stats_size = (object) $existing_stats['sizes'][ $size_name ];
//store the original image size
$stats['sizes'][ $size_name ]->size_before = ( ! empty( $existing_stats_size->size_before ) && $existing_stats_size->size_before > $stats['sizes'][ $size_name ]->size_before ) ? $existing_stats_size->size_before : $stats['sizes'][ $size_name ]->size_before;
//Update compression percent and bytes saved for each size
$stats['sizes'][ $size_name ]->bytes = $stats['sizes'][ $size_name ]->bytes + $existing_stats_size->bytes;
$stats['sizes'][ $size_name ]->percent = $this->calculate_percentage( $stats['sizes'][ $size_name ], $existing_stats_size );
}
}
}
}
//Sum Up all the stats
$stats = $this->total_compression( $stats );
//If there was any compression and there was no error in smushing
if ( isset( $stats['stats']['bytes'] ) && $stats['stats']['bytes'] >= 0 && ! $has_errors ) {
/**
* Runs if the image smushing was successful
*
* @param int $ID Image Id
*
* @param array $stats Smush Stats for the image
*
*/
do_action( 'wp_smush_image_optimised', $ID, $stats );
}
update_post_meta( $ID, $this->smushed_meta_key, $stats );
}
unset( $stats );
//Unset Response
if ( ! empty( $response ) ) {
unset( $response );
}
return $meta;
}
/**
* Read the image paths from an attachment's meta data and process each image
* with wp_smushit()
*
* @uses resize_from_meta_data
*
* @param $meta
* @param null $ID
*
* @return mixed
*/
function smush_image( $meta, $ID = null ) {
//Check if Async is Enabled, Do not run
if ( defined( 'WP_SMUSH_ASYNC' ) && WP_SMUSH_ASYNC ) {
return $meta;
}
//Return directly if not a image
if ( ! wp_attachment_is_image( $ID ) ) {
return $meta;
}
//Check if we're restoring the image Or already smushing the image
if ( get_transient( "wp-smush-restore-$ID" ) || get_transient( "smush-in-progress-$ID" ) || get_transient( "wp-smush-restore-$ID" ) ) {
return $meta;
}
/**
* Filter: wp_smush_image
*
* Whether to smush the given attachment id or not
*
* @param $skip bool, whether to Smush image or not
*
* @param $Attachment Id, Attachment id of the image being processed
*
*/
if ( ! apply_filters( 'wp_smush_image', true, $ID ) ) {
return false;
}
//Set a transient to avoid multiple request
set_transient( 'smush-in-progress-' . $ID, true, WP_SMUSH_TIMEOUT );
global $wpsmush_resize, $wpsmush_pngjpg, $wpsmush_settings;
//Check if auto is enabled
$auto_smush = $this->is_auto_smush_enabled();
//Optionally Resize Images
$meta = $wpsmush_resize->auto_resize( $ID, $meta );
//Auto Smush the new image
if ( $auto_smush ) {
//Optionally Convert PNGs to JPG
$meta = $wpsmush_pngjpg->png_to_jpg( $ID, $meta );
/** Fix for Hostgator */
//Check for use of http url, (Hostgator mostly)
$use_http = wp_cache_get( WP_SMUSH_PREFIX . 'use_http', 'smush' );
if ( ! $use_http ) {
$use_http = $wpsmush_settings->get_setting( WP_SMUSH_PREFIX . 'use_http', false );
wp_cache_add( WP_SMUSH_PREFIX . 'use_http', $use_http, 'smush' );
}
if ( $use_http ) {
//HTTP Url
define( 'WP_SMUSH_API_HTTP', 'http://smushpro.wpmudev.org/1.0/' );
}
$this->resize_from_meta_data( $meta, $ID );
} else {
//remove the smush metadata
delete_post_meta( $ID, $this->smushed_meta_key );
}
//Delete Transient
delete_transient( 'smush-in-progress-' . $ID );
return $meta;
}
/**
* Posts an image to Smush.
*
* @param $file_path path of file to send to Smush
* @param $file_size
*
* @return bool|array array containing success status, and stats
*/
function _post( $file_path, $file_size ) {
global $wpsmushit_admin, $wpsmush_settings;
$data = false;
$file_data = file_get_contents( $file_path );
$headers = array(
'accept' => 'application/json', // The API returns JSON
'content-type' => 'application/binary', // Set content type to binary
);
//Check if premium member, add API key
$api_key = $this->_get_api_key();
if ( ! empty( $api_key ) ) {
$headers['apikey'] = $api_key;
}
if ( $this->lossy_enabled && $this->validate_install() ) {
$headers['lossy'] = 'true';
} else {
$headers['lossy'] = 'false';
}
$headers['exif'] = $this->keep_exif ? 'true' : 'false';
$api_url = defined( 'WP_SMUSH_API_HTTP' ) ? WP_SMUSH_API_HTTP : WP_SMUSH_API;
$args = array(
'headers' => $headers,
'body' => $file_data,
'timeout' => WP_SMUSH_TIMEOUT,
'user-agent' => WP_SMUSH_UA,
);
//Temporary Increase the limit
@ini_set('memory_limit','256M');
$result = wp_remote_post( $api_url, $args );
unset( $file_data );//free memory
if ( is_wp_error( $result ) ) {
$er_msg = $result->get_error_message();
//Hostgator Issue
if ( ! empty( $er_msg ) && strpos( $er_msg, 'SSL CA cert' ) !== false ) {
//Update DB for using http protocol
$wpsmush_settings->update_setting( WP_SMUSH_PREFIX . 'use_http', 1 );
}
//Handle error
$data['message'] = sprintf( __( 'Error posting to API: %s', 'wp-smushit' ), $result->get_error_message() );
$data['success'] = false;
unset( $result ); //free memory
return $data;
} else if ( '200' != wp_remote_retrieve_response_code( $result ) ) {
//Handle error
$data['message'] = sprintf( __( 'Error posting to API: %s %s', 'wp-smushit' ), wp_remote_retrieve_response_code( $result ), wp_remote_retrieve_response_message( $result ) );
$data['success'] = false;
unset( $result ); //free memory
return $data;
}
//If there is a response and image was successfully optimised
$response = json_decode( $result['body'] );
if ( $response && $response->success == true ) {
//If there is any savings
if ( $response->data->bytes_saved > 0 ) {
$image = base64_decode( $response->data->image ); //base64_decode is necessary to send binary img over JSON, no security problems here!
$image_md5 = md5( $response->data->image );
if ( $response->data->image_md5 != $image_md5 ) {
//Handle error
$data['message'] = __( 'Smush data corrupted, try again.', 'wp-smushit' );
$data['success'] = false;
unset( $image );//free memory
} else {
$data['success'] = true;
$data['data'] = $response->data;
$data['data']->image = $image;
unset( $image );//free memory
}
} else {
//just return the data
$data['success'] = true;
$data['data'] = $response->data;
}
//If is_premium is set in response, send it over to check for member validity
if ( ! empty( $response->data ) && isset( $response->data->is_premium ) ) {
$wpsmushit_admin->api_headers['is_premium'] = $response->data->is_premium;
}
} else {
//Server side error, get message from response
$data['message'] = ! empty( $response->data ) ? $response->data : __( "Image couldn't be smushed", 'wp-smushit' );
$data['success'] = false;
}
unset( $result );//free memory
unset( $response );//free memory
return $data;
}
/**
* Print column header for Smush results in the media library using
* the `manage_media_columns` hook.
*/
function columns( $defaults ) {
$defaults['smushit'] = 'WP Smush';
return $defaults;
}
/**
* Return the filesize in a humanly readable format.
* Taken from http://www.php.net/manual/en/function.filesize.php#91477
*/
function format_bytes( $bytes, $precision = 1 ) {
$units = array( 'B', 'KB', 'MB', 'GB', 'TB' );
$bytes = max( $bytes, 0 );
$pow = floor( ( $bytes ? log( $bytes ) : 0 ) / log( 1024 ) );
$pow = min( $pow, count( $units ) - 1 );
$bytes /= pow( 1024, $pow );
return round( $bytes, $precision ) . $units[ $pow ];
}
/**
* Print column data for Smush results in the media library using
* the `manage_media_custom_column` hook.
*/
function custom_column( $column_name, $id ) {
if ( 'smushit' == $column_name ) {
$this->set_status( $id );
}
}
/**
* Check if user is premium member, check for api key
*
* @return mixed|string
*/
function validate_install() {
if ( isset( $this->is_pro ) ) {
return $this->is_pro;
}
//no api key set, always false
$api_key = $this->_get_api_key();
if ( empty( $api_key ) ) {
return false;
}
//Flag to check if we need to revalidate the key
$revalidate = false;
$api_auth = get_site_option( 'wp_smush_api_auth' );
//Check if need to revalidate
if ( ! $api_auth || empty( $api_auth ) || empty( $api_auth[ $api_key ] ) ) {
$revalidate = true;
} else {
$last_checked = $api_auth[ $api_key ]['timestamp'];
$valid = $api_auth[ $api_key ]['validity'];
$diff = current_time( 'timestamp' ) - $last_checked;
//Difference in hours
$diff_h = $diff / 3600;
//Difference in minutes
$diff_m = $diff / 60;
switch ( $valid ) {
case 'valid':
//if last checked was more than 12 hours
if ( $diff_h > 12 ) {
$revalidate = true;
}
break;
case 'invalid':
//if last checked was more than 24 hours
if ( $diff_h > 24 ) {
$revalidate = true;
}
break;
case 'network_failure':
//if last checked was more than 5 minutes
if ( $diff_m > 5 ) {
$revalidate = true;
}
break;
}
}
//If we are suppose to validate api, update the results in options table
if ( $revalidate ) {
if ( empty( $api_auth[ $api_key ] ) ) {
//For api key resets
$api_auth[ $api_key ] = array();
//Storing it as valid, unless we really get to know from api call
$api_auth[ $api_key ]['validity'] = 'valid';
}
//Aaron suggested to Update timestamp before making the api call, to avoid any concurrent calls, clever ;)
$api_auth[ $api_key ]['timestamp'] = current_time( 'timestamp' );
update_site_option( 'wp_smush_api_auth', $api_auth );
// call api
$url = $this->api_server . $api_key;
$request = wp_remote_get( $url, array(
"user-agent" => WP_SMUSH_UA,
"timeout" => 10
)
);
if ( ! is_wp_error( $request ) && '200' == wp_remote_retrieve_response_code( $request ) ) {
$result = json_decode( wp_remote_retrieve_body( $request ) );
if ( ! empty( $result->success ) && $result->success ) {
$valid = 'valid';
} else {
$valid = 'invalid';
}
} else {
$valid = 'network_failure';
}
//Reset Value
$api_auth = array();
//Add a fresh Timestamp
$timestamp = current_time( 'timestamp' );
$api_auth[ $api_key ] = array( 'validity' => $valid, 'timestamp' => $timestamp );
//Update API validity
update_site_option( 'wp_smush_api_auth', $api_auth );
}
$this->is_pro = ( 'valid' == $valid );
return $this->is_pro;
}
/**
* Returns api key
*
* @return mixed
*/
function _get_api_key() {
if ( defined( 'WPMUDEV_APIKEY' ) && WPMUDEV_APIKEY ) {
$api_key = WPMUDEV_APIKEY;
} else {
$api_key = get_site_option( 'wpmudev_apikey' );
}
return $api_key;
}
/**
* Returns size saved from the api call response
*
* @param string $message
*
* @return string|bool
*/
function get_saved_size( $message ) {
if ( preg_match( '/\((.*)\)/', $message, $matches ) ) {
return isset( $matches[1] ) ? $matches[1] : false;
}
return false;
}
/**
* Set send button status
*
* @param $id
* @param bool $echo
* @param bool $text_only Returns the stats text instead of button
* @param bool $wrapper required for `column_html`, to include the wrapper div or not
*
* @return string|void
*/
function set_status( $id, $echo = true, $text_only = false, $wrapper = true ) {
$status_txt = $button_txt = $stats = '';
$show_button = $show_resmush = false;
$wp_smush_data = get_post_meta( $id, $this->smushed_meta_key, true );
$wp_resize_savings = get_post_meta( $id, WP_SMUSH_PREFIX . 'resize_savings', true );
$conversion_savings = get_post_meta( $id, WP_SMUSH_PREFIX . 'pngjpg_savings', true );
$combined_stats = $this->combined_stats( $wp_smush_data, $wp_resize_savings );
$combined_stats = $this->combine_conversion_stats( $combined_stats, $conversion_savings );
$attachment_data = wp_get_attachment_metadata( $id );
// if the image is smushed
if ( ! empty( $wp_smush_data ) ) {
$image_count = count( $wp_smush_data['sizes'] );
$bytes = isset( $combined_stats['stats']['bytes'] ) ? $combined_stats['stats']['bytes'] : 0;
$bytes_readable = ! empty( $bytes ) ? size_format( $bytes, 1 ) : '';
$percent = isset( $combined_stats['stats']['percent'] ) ? $combined_stats['stats']['percent'] : 0;
$percent = $percent < 0 ? 0 : $percent;
if ( isset( $wp_smush_data['stats']['size_before'] ) && $wp_smush_data['stats']['size_before'] == 0 && ! empty( $wp_smush_data['sizes'] ) ) {
$status_txt = __( 'Already Optimized', 'wp-smushit' );
$show_button = false;
} else {
if ( $bytes == 0 || $percent == 0 ) {
$status_txt = __( 'Already Optimized', 'wp-smushit' );
//Show resmush link, if the settings were changed
$show_resmush = $this->show_resmush( $id, $wp_smush_data );
if ( $show_resmush ) {
$status_txt .= '<br />' . $this->get_resmsuh_link( $id );
}
} elseif ( ! empty( $percent ) && ! empty( $bytes_readable ) ) {
$status_txt = $image_count > 1 ? sprintf( __( "%d images reduced ", 'wp-smushit' ), $image_count ) : __( "Reduced ", 'wp-smushit' );
$stats_percent = number_format_i18n( $percent, 2, '.', '' );
$stats_percent = $stats_percent > 0 ? sprintf( "( %01.1f%% )", $stats_percent ) : '';
$status_txt .= sprintf( __( "by %s %s", 'wp-smushit' ), $bytes_readable, $stats_percent );
$file_path = get_attached_file( $id );
$size = file_exists( $file_path ) ? filesize( $file_path ) : 0;
if ( $size > 0 ) {
$size = size_format( $size, 1 );
$image_size = sprintf( __( "<br /> Image Size: %s", "wp-smushit" ), $size );
$status_txt .= $image_size;
}
$show_resmush = $this->show_resmush( $id, $wp_smush_data );
if ( $show_resmush ) {
$status_txt .= '<br />' . $this->get_resmsuh_link( $id );
}
//Restore Image: Check if we need to show the restore image option
$show_restore = $this->show_restore_option( $id, $attachment_data );
if ( $show_restore ) {
if ( $show_resmush ) {
//Show Separator
$status_txt .= ' | ';
} else {
//Show the link in next line
$status_txt .= '<br />';
}
$status_txt .= $this->get_restore_link( $id );
}
//Detailed Stats: Show detailed stats if available
if ( ! empty( $wp_smush_data['sizes'] ) ) {
if ( $show_resmush || $show_restore ) {
//Show Separator
$status_txt .= ' | ';
} else {
//Show the link in next line
$status_txt .= '<br />';
}
//Detailed Stats Link
$status_txt .= sprintf( '<a href="#" class="wp-smush-action smush-stats-details wp-smush-title" tooltip="%s">%s [<span class="stats-toggle">+</span>]</a>', esc_html__( "Detailed stats for all the image sizes", "wp-smushit" ), esc_html__( "Smush stats", 'wp-smushit' ) );
//Stats
$stats = $this->get_detailed_stats( $id, $wp_smush_data, $attachment_data );
if ( ! $text_only ) {
$status_txt .= $stats;
}
}
}
}
/** Super Smush Button */
//IF current compression is lossy
if ( ! empty( $wp_smush_data ) && ! empty( $wp_smush_data['stats'] ) ) {
$lossy = ! empty( $wp_smush_data['stats']['lossy'] ) ? $wp_smush_data['stats']['lossy'] : '';
$is_lossy = $lossy == 1 ? true : false;
}
//Check image type
$image_type = get_post_mime_type( $id );
//Check if premium user, compression was lossless, and lossy compression is enabled
//If we are displaying the resmush option already, no need to show the Super Smush button
if ( ! $show_resmush && $this->validate_install() && ! $is_lossy && $this->lossy_enabled && $image_type != 'image/gif' ) {
// the button text
$button_txt = __( 'Super-Smush', 'wp-smushit' );
$show_button = true;
}
} elseif ( get_transient( 'smush-in-progress-' . $id ) ) {
// the status
$status_txt = __( 'Smushing in progress..', 'wp-smushit' );
//Set WP Smush data to true in order to show the text
$wp_smush_data = true;
// we need to show the smush button
$show_button = false;
// the button text
$button_txt = '';
} else {
// the status
$status_txt = __( 'Not processed', 'wp-smushit' );
// we need to show the smush button
$show_button = true;
// the button text
$button_txt = __( 'Smush Now!', 'wp-smushit' );
}
if ( $text_only ) {
//For ajax response
return array(
'status' => $status_txt,
'stats' => $stats,
'show_warning' => intval( $this->show_warning() )
);
}
//If we are not showing smush button, append progree bar, else it is already there
if ( ! $show_button ) {
$status_txt .= $this->progress_bar();
}
$text = $this->column_html( $id, $status_txt, $button_txt, $show_button, $wp_smush_data, $echo, $wrapper );
if ( ! $echo ) {
return $text;
}
}
/**
* Print the column html
*
* @param string $id Media id
* @param string $status_txt Status text
* @param string $button_txt Button label
* @param boolean $show_button Whether to shoe the button
* @param bool $smushed Whether image is smushed or not
* @param bool $echo If true, it directly outputs the HTML
* @param bool $wrapper Whether to return the button with wrapper div or not
*
* @return string|void
*/
function column_html( $id, $status_txt = "", $button_txt = "", $show_button = true, $smushed = false, $echo = true, $wrapper = true ) {
$allowed_images = array( 'image/jpeg', 'image/jpg', 'image/png', 'image/gif' );
// don't proceed if attachment is not image, or if image is not a jpg, png or gif
if ( ! wp_attachment_is_image( $id ) || ! in_array( get_post_mime_type( $id ), $allowed_images ) ) {
return;
}
$class = $smushed ? '' : ' hidden';
$html = '<p class="smush-status' . $class . '">' . $status_txt . '</p>';
// if we aren't showing the button
if ( ! $show_button ) {
if ( $echo ) {
echo $html;
return;
} else {
if ( ! $smushed ) {
$class = ' currently-smushing';
} else {
$class = ' smushed';
}
return $wrapper ? '<div class="smush-wrap' . $class . '">' . $html . '</div>' : $html;
}
}
if ( ! $echo ) {
$button_class = $wrapper ? 'button button-primary wp-smush-send' : 'button wp-smush-send';
$html .= '
<button class="' . $button_class . '" data-id="' . $id . '">
<span>' . $button_txt . '</span>
</button>';
if ( ! $smushed ) {
$class = ' unsmushed';
} else {
$class = ' smushed';
}
$html .= $this->progress_bar();
$html = $wrapper ? '<div class="smush-wrap' . $class . '">' . $html . '</div>' : $html;
return $html;
} else {
$html .= '<button class="button wp-smush-send" data-id="' . $id . '">
<span>' . $button_txt . '</span>
</button>';
$html = $html . $this->progress_bar();
echo $html;
}
}
/**
* Migrates smushit api message to the latest structure
*
*
* @return void
*/
function migrate() {
if ( ! version_compare( $this->version, "1.7.1", "lte" ) ) {
return;
}
$migrated_version = get_site_option( $this->migrated_version_key );
if ( $migrated_version === $this->version ) {
return;
}
global $wpdb;
$q = $wpdb->prepare( "SELECT * FROM `" . $wpdb->postmeta . "` WHERE `meta_key`=%s AND `meta_value` LIKE %s ", "_wp_attachment_metadata", "%wp_smushit%" );
$results = $wpdb->get_results( $q );
if ( count( $results ) < 1 ) {
return;
}
$migrator = new WpSmushMigrate();
foreach ( $results as $attachment_meta ) {
$migrated_message = $migrator->migrate_api_message( maybe_unserialize( $attachment_meta->meta_value ) );
if ( $migrated_message !== array() ) {
update_post_meta( $attachment_meta->post_id, $this->smushed_meta_key, $migrated_message );
}
}
update_site_option( $this->migrated_version_key, $this->version );
}
/**
* Updates the smush stats for a single image size
*
* @param $id
* @param $stats
* @param $image_size
*/
function update_smush_stats_single( $id, $smush_stats, $image_size = '' ) {
//Return, if we don't have image id or stats for it
if ( empty( $id ) || empty( $smush_stats ) || empty( $image_size ) ) {
return false;
}
$data = $smush_stats['data'];
//Get existing Stats
$stats = get_post_meta( $id, $this->smushed_meta_key, true );
//Update existing Stats
if ( ! empty( $stats ) ) {
//Update stats for each size
if ( isset( $stats['sizes'] ) ) {
//if stats for a particular size doesn't exists
if ( empty( $stats['sizes'][ $image_size ] ) ) {
//Update size wise details
$stats['sizes'][ $image_size ] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $data );
} else {
//Update compression percent and bytes saved for each size
$stats['sizes'][ $image_size ]->bytes = $stats['sizes'][ $image_size ]->bytes + $data->bytes_saved;
$stats['sizes'][ $image_size ]->percent = $stats['sizes'][ $image_size ]->percent + $data->compression;
}
}
} else {
//Create new stats
$stats = array(
"stats" => array_merge( $this->_get_size_signature(), array(
'api_version' => - 1,
'lossy' => - 1
)
),
'sizes' => array()
);
$stats['stats']['api_version'] = $data->api_version;
$stats['stats']['lossy'] = $data->lossy;
$stats['stats']['keep_exif'] = ! empty( $data->keep_exif ) ? $data->keep_exif : 0;
//Update size wise details
$stats['sizes'][ $image_size ] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $data );
}
//Calculate the total compression
$stats = $this->total_compression( $stats );
update_post_meta( $id, $this->smushed_meta_key, $stats );
}
/**
* Smush Retina images for WP Retina 2x, Update Stats
*
* @param $id
* @param $retina_file
* @param $image_size
*/
function smush_retina_image( $id, $retina_file, $image_size ) {
//Initialize attachment id and media type
$this->attachment_id = $id;
$this->media_type = "wp";
/**
* Allows to Enable/Disable WP Retina 2x Integration
*/
$smush_retina_images = apply_filters( 'smush_retina_images', true );
//Check if Smush retina images is enbled
if ( ! $smush_retina_images ) {
return;
}
//Check for Empty fields
if ( empty( $id ) || empty( $retina_file ) || empty( $image_size ) ) {
return;
}
//Do not smush if auto smush is turned off
if ( ! $this->is_auto_smush_enabled() ) {
return;
}
/**
* Allows to skip a image from smushing
*
* @param bool , Smush image or not
* @$size string, Size of image being smushed
*/
$smush_image = apply_filters( 'wp_smush_media_image', true, $image_size );
if ( ! $smush_image ) {
return;
}
$stats = $this->do_smushit( $retina_file );
//If we squeezed out something, Update stats
if ( ! is_wp_error( $stats ) && ! empty( $stats['data'] ) && isset( $stats['data'] ) && $stats['data']->bytes_saved > 0 ) {
$image_size = $image_size . '@2x';
$this->update_smush_stats_single( $id, $stats, $image_size );
}
}
/**
* Return a list of images not smushed and reason
*
* @param $image_id
* @param $size_stats
* @param $attachment_metadata
*
* @return array
*/
function get_skipped_images( $image_id, $size_stats, $attachment_metadata ) {
$skipped = array();
//Get a list of all the sizes, Show skipped images
$media_size = get_intermediate_image_sizes();
//Full size
$full_image = get_attached_file( $image_id );
//If full image was not smushed, reason 1. Large Size logic, 2. Free and greater than 1Mb
if ( ! array_key_exists( 'full', $size_stats ) ) {
//For free version, Check the image size
if ( ! $this->validate_install() ) {
//For free version, check if full size is greater than 1 Mb, show the skipped status
$file_size = file_exists( $full_image ) ? filesize( $full_image ) : '';
if ( ! empty( $file_size ) && ( $file_size / WP_SMUSH_MAX_BYTES ) > 1 ) {
$skipped[] = array(
'size' => 'full',
'reason' => 'size_limit'
);
} else {
$skipped[] = array(
'size' => 'full',
'reason' => 'large_size'
);
}
} else {
//Paid version, Check if we have large size
if ( array_key_exists( 'large', $size_stats ) ) {
$skipped[] = array(
'size' => 'full',
'reason' => 'large_size'
);
}
}
}
//For other sizes, check if the image was generated and not available in stats
if ( is_array( $media_size ) ) {
foreach ( $media_size as $size ) {
if ( array_key_exists( $size, $attachment_metadata['sizes'] ) && ! array_key_exists( $size, $size_stats ) && ! empty( $size['file'] ) ) {
//Image Path
$img_path = path_join( dirname( $full_image ), $size['file'] );
$image_size = file_exists( $img_path ) ? filesize( $img_path ) : '';
if ( ! empty( $image_size ) && ( $image_size / WP_SMUSH_MAX_BYTES ) > 1 ) {
$skipped[] = array(
'size' => 'full',
'reason' => 'size_limit'
);
}
}
}
}
return $skipped;
}
/**
* Skip messages respective to their ids
*
* @param $msg_id
*
* @return bool
*/
function skip_reason( $msg_id ) {
$count = count( get_intermediate_image_sizes() );
$smush_orgnl_txt = sprintf( esc_html__( "When you upload an image to WordPress it automatically creates %s thumbnail sizes that are commonly used in your pages. WordPress also stores the original full-size image, but because these are not usually embedded on your site we don’t Smush them. Pro users can override this.", 'wp_smushit' ), $count );
$skip_msg = array(
'large_size' => $smush_orgnl_txt,
'size_limit' => esc_html__( "Image couldn't be smushed as it exceeded the 1Mb size limit, Pro users can smush images with size upto 32Mb.", "wp-smushit" )
);
$skip_rsn = ! empty( $skip_msg[ $msg_id ] ) ? esc_html__( " Skipped", 'wp-smushit', 'wp-smushit' ) : '';
$skip_rsn = ! empty( $skip_rsn ) ? $skip_rsn . '<span tooltip="' . $skip_msg[ $msg_id ] . '"><i class="dashicons dashicons-editor-help"></i></span>' : '';
return $skip_rsn;
}
/**
* Shows the image size and the compression for each of them
*
* @param $image_id
* @param $wp_smush_data
*
* @return string
*/
function get_detailed_stats( $image_id, $wp_smush_data, $attachment_metadata ) {
global $wpsmushit_admin;
$stats = '<div id="smush-stats-' . $image_id . '" class="smush-stats-wrapper hidden">
<table class="wp-smush-stats-holder">
<thead>
<tr>
<th><strong>' . esc_html__( 'Image size', 'wp-smushit' ) . '</strong></th>
<th><strong>' . esc_html__( 'Savings', 'wp-smushit' ) . '</strong></th>
</tr>
</thead>
<tbody>';
$size_stats = $wp_smush_data['sizes'];
//Reorder Sizes as per the maximum savings
uasort( $size_stats, array( $this, "cmp" ) );
if ( ! empty( $attachment_metadata['sizes'] ) ) {
//Get skipped images
$skipped = $this->get_skipped_images( $image_id, $size_stats, $attachment_metadata );
if ( ! empty( $skipped ) ) {
foreach ( $skipped as $img_data ) {
$skip_class = $img_data['reason'] == 'size_limit' ? ' error' : '';
$stats .= '<tr>
<td>' . strtoupper( $img_data['size'] ) . '</td>
<td class="smush-skipped' . $skip_class . '">' . $this->skip_reason( $img_data['reason'] ) . '</td>
</tr>';
}
}
}
//Show Sizes and their compression
foreach ( $size_stats as $size_key => $size_value ) {
$dimensions = '';
//Get the dimensions for the image size if available
if ( ! empty( $wpsmushit_admin->image_sizes ) && ! empty( $wpsmushit_admin->image_sizes[ $size_key ] ) ) {
$dimensions = $wpsmushit_admin->image_sizes[ $size_key ]['width'] . 'x' . $wpsmushit_admin->image_sizes[ $size_key ]['height'];
}
$dimensions = ! empty( $dimensions ) ? sprintf( " <br /> (%s)", $dimensions ) : '';
if ( $size_value->bytes > 0 ) {
$percent = round( $size_value->percent, 1 );
$percent = $percent > 0 ? ' ( ' . $percent . '% )' : '';
$stats .= '<tr>
<td>' . strtoupper( $size_key ) . $dimensions . '</td>
<td>' . size_format( $size_value->bytes, 1 ) . $percent . '</td>
</tr>';
}
}
$stats .= '</tbody>
</table>
</div>';
return $stats;
}
/**
* Compare Values
*
* @param $a
* @param $b
*
* @return int
*/
function cmp( $a, $b ) {
return $a->bytes < $b->bytes;
}
/**
* Load Plugin Modules
*
*/
function load_modules() {
$this->load_nextgen();
//Load S3
if( has_action('aws_init') ) {
add_action( 'aws_init', array( $this, 'load_s3' ), 120 );
}
}
/**
* Check if NextGen is active or not
* Include and instantiate classes
*/
function load_nextgen() {
if ( ! class_exists( 'C_NextGEN_Bootstrap' ) ) {
return;
}
global $wpsmush_settings;
//Check if integration is Enabled or not
//Smush NextGen key
$opt_nextgen = WP_SMUSH_PREFIX . 'nextgen';
$opt_nextgen_val = $wpsmush_settings->get_setting( $opt_nextgen, false );
if ( ! $opt_nextgen_val ) {
return;
}
require_once( WP_SMUSH_DIR . '/lib/class-wp-smush-nextgen.php' );
require_once( WP_SMUSH_DIR . '/lib/nextgen-integration/class-wp-smush-nextgen-admin.php' );
require_once( WP_SMUSH_DIR . '/lib/nextgen-integration/class-wp-smush-nextgen-stats.php' );
require_once( WP_SMUSH_DIR . '/lib/nextgen-integration/class-wp-smush-nextgen-bulk.php' );
global $wpsmushnextgen, $wpsmushnextgenadmin, $wpsmushnextgenstats;
//Initialize Nextgen support
if( !is_object( $wpsmushnextgen ) ) {
$wpsmushnextgen = new WpSmushNextGen();
}
$wpsmushnextgenstats = new WpSmushNextGenStats();
$wpsmushnextgenadmin = new WpSmushNextGenAdmin();
new WPSmushNextGenBulk();
}
/**
* Load S3 module if the respective plugin is active
*/
function load_s3() {
//If we don't have free or pro verison for WP S3 Offload, return
if ( ! class_exists( 'Amazon_S3_And_CloudFront' ) && ! class_exists( 'Amazon_S3_And_CloudFront_Pro' ) ) {
return;
}
//Include Smush Async class
require_once WP_SMUSH_DIR . 'lib/class-wp-smush-s3.php';
}
/**
* Add the Smushit Column to sortable list
*
* @param $columns
*
* @return mixed
*/
function sortable_column( $columns ) {
$columns['smushit'] = 'smushit';
return $columns;
}
/**
* Orderby query for smush columns
*/
function smushit_orderby( $query ) {
global $current_screen;
//Filter only media screen
if ( ! is_admin() || ( ! empty( $current_screen ) && $current_screen->base != 'upload' ) ) {
return;
}
$orderby = $query->get( 'orderby' );
if ( isset( $orderby ) && 'smushit' == $orderby ) {
$query->set( 'meta_query', array(
'relation' => 'OR',
array(
'key' => $this->smushed_meta_key,
'compare' => 'EXISTS'
),
array(
'key' => $this->smushed_meta_key,
'compare' => 'NOT EXISTS'
)
) );
$query->set( 'orderby', 'meta_value_num' );
}
return $query;
}
/**
* If any of the image size have a backup file, show the restore option
*
* @param $attachment_data
*
* @return bool
*/
function show_restore_option( $image_id, $attachment_data ) {
global $wpsmushit_admin;
//No Attachment data, don't go ahead
if ( empty( $attachment_data ) ) {
return false;
}
//Get the image path for all sizes
$file = get_attached_file( $image_id );
$uf_file = get_attached_file( $image_id, true );
//Get stored backup path, if any
$backup_sizes = get_post_meta( $image_id, '_wp_attachment_backup_sizes', true );
//Check if we've a backup path
if( !empty( $backup_sizes ) && ( !empty( $backup_sizes['smush-full']) || !empty( $backup_sizes['smush_png_path']) ) ) {
//Check for PNG backup
$backup = !empty( $backup_sizes['smush_png_path'] ) ? $backup_sizes['smush_png_path'] : '';
//Check for original full size image backup
$backup = empty( $backup ) && !empty( $backup_sizes['smush-full'] ) ? $backup_sizes['smush-full'] : $backup;
$backup = !empty( $backup['file'] ) ? $backup['file'] : '';
}
//If we still don't have a backup path, use traditional method to get it
if( empty( $backup ) ) {
//Check backup for Full size
$backup = $wpsmushit_admin->get_image_backup_path( $file );
}else{
//Get the full path for file backup
$backup = str_replace( wp_basename( $file ), wp_basename( $backup ), $file );
}
$file_exists = apply_filters( 'smush_backup_exists', file_exists( $backup ), $image_id, $backup );
if( $file_exists ) {
return true;
}
//Additional Backup Check for JPEGs converted from PNG
$pngjpg_savings = get_post_meta( $image_id, WP_SMUSH_PREFIX . 'pngjpg_savings', true );
if ( ! empty( $pngjpg_savings ) ) {
//Get the original File path and check if it exists
$backup = get_post_meta( $image_id, WP_SMUSH_PREFIX . 'original_file', true );
$backup = $this->original_file( $backup );
if ( ! empty( $backup ) && is_file( $backup ) ) {
return true;
}
}
return false;
}
/**
* Returns a restore link for given image id
*
* @param $image_id
*
* @return bool|string
*/
function get_restore_link( $image_id, $type = 'wp' ) {
if ( empty( $image_id ) ) {
return false;
}
$class = 'wp-smush-action wp-smush-title';
$class .= 'wp' == $type ? ' wp-smush-restore' : ' wp-smush-nextgen-restore';
$ajax_nonce = wp_create_nonce( "wp-smush-restore-" . $image_id );
return sprintf( '<a href="#" tooltip="%s" data-id="%d" data-nonce="%s" class="%s">%s</a>', esc_html__( "Restore original image.", "wp-smushit" ), $image_id, $ajax_nonce, $class, esc_html__( "Restore image", "wp-smushit" ) );
}
/**
* Returns the HTML for progress bar
*
* @return string
*/
function progress_bar() {
return '<div class="wp-smush-progress animate hidden"><span></span></div>';
}
/**
* If auto smush is set to true or not, default is true
*
* @return int|mixed|void
*/
function is_auto_smush_enabled() {
global $wpsmush_settings;
$auto_smush = $wpsmush_settings->get_setting( WP_SMUSH_PREFIX . 'auto', false );
//Keep the auto smush on by default
if ( $auto_smush === false ) {
$auto_smush = 1;
}
return $auto_smush;
}
/**
* Generates a Resmush link for a image
*
* @param $image_id
*
* @return bool|string
*/
function get_resmsuh_link( $image_id, $type = 'wp' ) {
if ( empty( $image_id ) ) {
return false;
}
$class = 'wp-smush-action wp-smush-title';
$class .= 'wp' == $type ? ' wp-smush-resmush' : ' wp-smush-nextgen-resmush';
$ajax_nonce = wp_create_nonce( "wp-smush-resmush-" . $image_id );
return sprintf( '<a href="#" tooltip="%s" data-id="%d" data-nonce="%s" class="%s">%s</a>', esc_html__( "Smush image including original file.", "wp-smushit" ), $image_id, $ajax_nonce, $class, esc_html__( "Resmush image", "wp-smushit" ) );
}
/**
* Returns the backup path for attachment
*
* @param $attachment_path
*
* @return bool|string
*
*/
function get_image_backup_path( $attachment_path ) {
//If attachment id is not available, return false
if ( empty( $attachment_path ) ) {
return false;
}
$path = pathinfo( $attachment_path );
//If we don't have complete filename return false
if ( empty( $path['extension'] ) ) {
return false;
}
$backup_name = trailingslashit( $path['dirname'] ) . $path['filename'] . ".bak." . $path['extension'];
return $backup_name;
}
/**
* Deletes all the backup files when an attachment is deleted
* Update Resmush List
* Update Super Smush image count
*
* @param $image_id
*/
function delete_images( $image_id ) {
global $wpsmush_db;
//Update the savings cache
$wpsmush_db->resize_savings( true );
//Update the savings cache
$wpsmush_db->conversion_savings( true );
//If no image id provided
if ( empty( $image_id ) ) {
return false;
}
//Check and Update resmush list
if ( $resmush_list = get_option( 'wp-smush-resmush-list' ) ) {
global $wpsmushit_admin;
$wpsmushit_admin->update_resmush_list( $image_id, 'wp-smush-resmush-list' );
}
/** Delete Backups **/
//Check if we have any smush data for image
$this->delete_backup_files( $image_id );
}
/**
* Return Global stats
*
* @return array|bool|mixed
*/
function send_smush_stats() {
global $wpsmushit_admin;
$stats = $wpsmushit_admin->global_stats_from_ids();
return $stats;
}
/**
* Smushes the upfront images and Updates the respective stats
*
* @param $attachment_id
* @param $stats
*
* @return mixed
*/
function smush_upfront_images( $attachment_id, $stats ) {
//Check if upfront is active or not
if ( empty( $attachment_id ) || ! class_exists( 'Upfront' ) ) {
return $stats;
}
//Set attachment id and Media type
$this->attachment_id = $attachment_id;
$this->media_type = "upfront";
//Get post meta to check for Upfront images
$upfront_images = get_post_meta( $attachment_id, 'upfront_used_image_sizes', true );
//If there is no upfront meta for the image
if ( ! $upfront_images || empty( $upfront_images ) || ! is_array( $upfront_images ) ) {
return $stats;
}
//Loop over all the images in upfront meta
foreach ( $upfront_images as $element_id => $image ) {
if ( isset( $image['is_smushed'] ) && 1 == $image['is_smushed'] ) {
continue;
}
//Get the image path and smush it
if ( isset( $image['path'] ) && file_exists( $image['path'] ) ) {
$res = $this->do_smushit( $image['path'] );
//If sizes key is not yet initialised
if ( empty( $stats['sizes'] ) ) {
$stats['sizes'] = array();
}
//If the smushing was successful
if ( ! is_wp_error( $res ) && ! empty( $res['data'] ) ) {
if ( $res['data']->bytes_saved > 0 ) {
//Update attachment stats
$stats['sizes'][ $element_id ] = (object) $this->_array_fill_placeholders( $this->_get_size_signature(), (array) $res['data'] );
}
//Update upfront stats for the element id
$upfront_images[ $element_id ]['is_smushed'] = 1;
}
}
}
//Finally Update the upfront meta key
update_post_meta( $attachment_id, 'upfront_used_image_sizes', $upfront_images );
return $stats;
}
/**
* Checks the current settings and returns the value whether to enable or not the resmush option
*
* @param $id
* @param $wp_smush_data
*
* @return bool
*/
function show_resmush( $id = '', $wp_smush_data ) {
//Resmush: Show resmush link, Check if user have enabled smushing the original and full image was skipped
//Or: If keep exif is unchecked and the smushed image have exif
//PNG To JPEG
if ( $this->smush_original ) {
//IF full image was not smushed
if ( ! empty( $wp_smush_data ) && empty( $wp_smush_data['sizes']['full'] ) ) {
return true;
}
}
//EXIF Check
if ( ! $this->keep_exif ) {
//If Keep Exif was set to true initially, and since it is set to false now
if ( isset( $wp_smush_data['stats']['keep_exif'] ) && $wp_smush_data['stats']['keep_exif'] == 1 ) {
return true;
}
}
//PNG to JPEG
global $wpsmush_pngjpg;
if ( $wpsmush_pngjpg->can_be_converted( $id ) ) {
return true;
}
return false;
}
/**
* Calculate saving percentage from existing and current stats
*
* @param $stats
* @param $existing_stats
*
* @return float
*/
function calculate_percentage( $stats = '', $existing_stats = '' ) {
if ( empty( $stats ) || empty( $existing_stats ) ) {
return 0;
}
$size_before = ! empty( $stats->size_before ) ? $stats->size_before : $existing_stats->size_before;
$size_after = ! empty( $stats->size_after ) ? $stats->size_after : $existing_stats->size_after;
$savings = $size_before - $size_after;
if ( $savings > 0 ) {
$percentage = ( $savings / $size_before ) * 100;
$percentage = $percentage > 0 ? round( $percentage, 2 ) : $percentage;
return $percentage;
}
return 0;
}
/**
* Calculate saving percentage for a given size stats
*
* @param $stats
*
* @return float|int
*/
function calculate_percentage_from_stats( $stats ) {
if ( empty( $stats ) || ! isset( $stats->size_before, $stats->size_after ) ) {
return 0;
}
$savings = $stats->size_before - $stats->size_after;
if ( $savings > 0 ) {
$percentage = ( $savings / $stats->size_before ) * 100;
$percentage = $percentage > 0 ? round( $percentage, 2 ) : $percentage;
return $percentage;
}
}
/**
* Redirects the user to Plugin settings page on Plugin activation
*
* @param $plugin Plugin Name
*
* @return bool
*/
function wp_smush_redirect( $plugin ) {
global $wpsmush_db;
//Run for only our plugin
if ( $plugin != WP_SMUSH_BASENAME ) {
return false;
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return true;
}
//Skip if bulk activation, Or if we have to skip redirection
if ( isset( $_GET['activate-multi'] ) || get_site_option( 'wp-smush-skip-redirect' ) ) {
return false;
}
//If images are already smushed
if ( $wpsmush_db->smushed_count( false ) > 0 ) {
return false;
}
$url = admin_url( 'upload.php' );
$url = add_query_arg(
array(
'page' => 'wp-smush-bulk'
),
$url
);
//Store that we need not redirect again
add_site_option( 'wp-smush-skip-redirect', true );
exit( wp_redirect( $url ) );
}
/**
* Clear up all the backup files for the image, if any
*
* @param $image_id
*/
function delete_backup_files( $image_id ) {
$smush_meta = get_post_meta( $image_id, $this->smushed_meta_key, true );
if ( empty( $smush_meta ) ) {
//Return if we don't have any details
return;
}
//Get the attachment details
$meta = wp_get_attachment_metadata( $image_id );
//Attachment file path
$file = get_attached_file( $image_id );
//Get the backup path
$backup_name = $this->get_image_backup_path( $file );
//If file exists, corresponding to our backup path, delete it
@ unlink( $backup_name );
//Check meta for rest of the sizes
if ( ! empty( $meta ) && ! empty( $meta['sizes'] ) ) {
foreach ( $meta['sizes'] as $size ) {
//Get the file path
if ( empty( $size['file'] ) ) {
continue;
}
//Image Path and Backup path
$image_size_path = path_join( dirname( $file ), $size['file'] );
$image_bckup_path = $this->get_image_backup_path( $image_size_path );
@unlink( $image_bckup_path );
}
}
}
/**
* Manually Dismiss Smush Upgrade notice
*/
function dismiss_smush_upgrade() {
if ( isset( $_GET['remove_smush_upgrade_notice'] ) && 1 == $_GET['remove_smush_upgrade_notice'] ) {
global $wpsmushit_admin;
$wpsmushit_admin->dismiss_upgrade_notice( false );
}
}
/**
* Iterate over all the size stats and calculate the total stats
*
* @param $stats
*
* @return mixed
*/
function total_compression( $stats ) {
$stats['stats']['size_before'] = $stats['stats']['size_after'] = $stats['stats']['time'] = 0;
foreach ( $stats['sizes'] as $size_stats ) {
$stats['stats']['size_before'] += ! empty( $size_stats->size_before ) ? $size_stats->size_before : 0;
$stats['stats']['size_after'] += ! empty( $size_stats->size_after ) ? $size_stats->size_after : 0;
$stats['stats']['time'] += ! empty( $size_stats->time ) ? $size_stats->time : 0;
}
$stats['stats']['bytes'] = ! empty( $stats['stats']['size_before'] ) && $stats['stats']['size_before'] > $stats['stats']['size_after'] ? $stats['stats']['size_before'] - $stats['stats']['size_after'] : 0;
if ( ! empty( $stats['stats']['bytes'] ) && ! empty( $stats['stats']['size_before'] ) ) {
$stats['stats']['percent'] = ( $stats['stats']['bytes'] / $stats['stats']['size_before'] ) * 100;
}
return $stats;
}
/**
* Smush and Resizing Stats Combined together
*
* @param $smush_stats
* @param $resize_savings
*
* @return array Array of all the stats
*/
function combined_stats( $smush_stats, $resize_savings ) {
if ( empty( $smush_stats ) || empty( $resize_savings ) ) {
return $smush_stats;
}
//Full Image
if ( ! empty( $smush_stats['sizes']['full'] ) ) {
$smush_stats['sizes']['full']->bytes = ! empty( $resize_savings['bytes'] ) ? $smush_stats['sizes']['full']->bytes + $resize_savings['bytes'] : $smush_stats['sizes']['full']->bytes;
$smush_stats['sizes']['full']->size_before = ! empty( $resize_savings['size_before'] ) && ( $resize_savings['size_before'] > $smush_stats['sizes']['full']->size_before ) ? $resize_savings['size_before'] : $smush_stats['sizes']['full']->size_before;
$smush_stats['sizes']['full']->percent = ! empty( $smush_stats['sizes']['full']->bytes ) && $smush_stats['sizes']['full']->size_before > 0 ? ( $smush_stats['sizes']['full']->bytes / $smush_stats['sizes']['full']->size_before ) * 100 : $smush_stats['sizes']['full']->percent;
$smush_stats['sizes']['full']->percent = round( $smush_stats['sizes']['full']->percent, 1 );
}
$smush_stats = $this->total_compression( $smush_stats );
return $smush_stats;
}
/**
* Combine Savings from PNG to JPG conversion with smush stats
*
* @param $stats Savings from Smushing the image
* @param $conversion_savings Savings from converting the PNG to JPG
*
* @return Object Total Savings
*/
function combine_conversion_stats( $stats, $conversion_savings ) {
if ( empty( $stats ) || empty( $conversion_savings ) ) {
return $stats;
}
foreach ( $conversion_savings as $size_k => $savings ) {
if ( ! empty( $stats['sizes'][ $size_k ] ) && ! empty( $savings ) ) {
$stats['sizes'][ $size_k ]->bytes = $stats['sizes'][ $size_k ]->bytes + $savings['bytes'];
$stats['sizes'][ $size_k ]->size_before = $stats['sizes'][ $size_k ]->size_before > $savings['size_before'] ? $stats['sizes'][ $size_k ]->size_before : $savings['size_before'];
$stats['sizes'][ $size_k ]->percent = ! empty( $stats['sizes'][ $size_k ]->bytes ) && $stats['sizes'][ $size_k ]->size_before > 0 ? ( $stats['sizes'][ $size_k ]->bytes / $stats['sizes'][ $size_k ]->size_before ) * 100 : $stats['sizes'][ $size_k ]->percent;
$stats['sizes'][ $size_k ]->percent = round( $stats['sizes'][ $size_k ]->percent, 1 );
}
}
$stats = $this->total_compression( $stats );
return $stats;
}
/**
* Original File path
*
* @param string $original_file
*
* @return string File Path
*
*/
function original_file( $original_file = '' ) {
$uploads = wp_get_upload_dir();
$upload_path = $uploads['basedir'];
return path_join( $upload_path, $original_file );
}
/**
* Check whether to show warning or not for Pro users, if they don't have a valid install
*
* @return bool
*
*/
function show_warning() {
//If it's a free setup, Go back right away!
if ( ! $this->validate_install() ) {
return false;
}
global $wpsmushit_admin;
// Return. If we don't have any headers
if ( ! isset( $wpsmushit_admin->api_headers ) ) {
return false;
}
//Show warning, if function says it's premium and api says not premium
if ( isset( $wpsmushit_admin->api_headers['is_premium'] ) && ! intval( $wpsmushit_admin->api_headers['is_premium'] ) ) {
return true;
}
return false;
}
/**
* Send JSON response whether to show or not the warning
*/
function show_warning_ajax() {
$show = $this->show_warning();
wp_send_json( intval( $show ) );
}
/**
* Initialize the Smush Async class
*/
function wp_smush_async() {
//Don't load the Async task, if user not logged in or not in backend
if ( ! is_user_logged_in() || ! is_admin() ) {
return;
}
//Check if Async is disabled
if ( defined( 'WP_SMUSH_ASYNC' ) && ! WP_SMUSH_ASYNC ) {
return;
}
//Instantiate Class
new WpSmushAsync();
new WpSmushEditorAsync();
}
/**
* Send a smush request for the attachment
*
* @param $id Attachment ID
*/
function wp_smush_handle_async( $id ) {
//If we don't have image id, or the smush is already in progress for the image, return
if ( empty( $id ) || get_transient( 'smush-in-progress-' . $id ) || get_transient( "wp-smush-restore-$id" ) ) {
return;
}
//If auto Smush is disabled
if ( ! $this->is_auto_smush_enabled() ) {
return;
}
/**
* Filter: wp_smush_image
*
* Whether to smush the given attachment id or not
*
* @param $skip bool, whether to Smush image or not
*
* @param $Attachment Id, Attachment id of the image being processed
*
*/
if ( ! apply_filters( 'wp_smush_image', true, $id ) ) {
return;
}
global $wpsmushit_admin;
$wpsmushit_admin->smush_single( $id, true );
}
/**
* Send a smush request for the attachment
*
* @param $id Attachment ID
*/
function wp_smush_handle_editor_async( $id, $post_data ) {
//If we don't have image id, or the smush is already in progress for the image, return
if ( empty( $id ) || get_transient( "smush-in-progress-$id" ) || get_transient( "wp-smush-restore-$id" ) ) {
return;
}
//If auto Smush is disabled
if ( ! $this->is_auto_smush_enabled() ) {
return;
}
/**
* Filter: wp_smush_image
*
* Whether to smush the given attachment id or not
*
* @param $skip bool, whether to Smush image or not
*
* @param $Attachment Id, Attachment id of the image being processed
*
*/
if ( ! apply_filters( 'wp_smush_image', true, $id ) ) {
return;
}
//If filepath is not set or file doesn't exists
if ( ! isset( $post_data['filepath'] ) || ! file_exists( $post_data['filepath'] ) ) {
return;
}
//Send image for smushing
$res = $this->do_smushit( $post_data['filepath'] );
//Exit if smushing wasn't successful
if ( is_wp_error( $res) || empty( $res['success'] ) || ! $res['success'] ) {
return;
}
//Update stats if it's the full size image
//Return if it's not the full image size
if ( $post_data['filepath'] != get_attached_file( $post_data['postid'] ) ) {
return;
}
//Get the existing Stats
$smush_stats = get_post_meta( $post_data['postid'], $this->smushed_meta_key, true );
$stats_full = ! empty( $smush_stats['sizes'] ) && ! empty( $smush_stats['sizes']['full'] ) ? $smush_stats['sizes']['full'] : '';
if ( empty( $stats_full ) ) {
return;
}
//store the original image size
$stats_full->size_before = ( ! empty( $stats_full->size_before ) && $stats_full->size_before > $res['data']->before_size ) ? $stats_full->size_before : $res['data']->before_size;
$stats_full->size_after = $res['data']->after_size;
//Update compression percent and bytes saved for each size
$stats_full->bytes = $stats_full->size_before - $stats_full->size_after;
$stats_full->percent = $this->calculate_percentage_from_stats( $stats_full );
$smush_stats['sizes']['full'] = $stats_full;
//Update Stats
update_post_meta( $post_data['postid'], $this->smushed_meta_key, $smush_stats );
}
/**
* Support uploads/import through other methods.
*
* Handle image optimization for other upload sources, using
* WP upload functions. For eg: WP RSS Aggregator importing images.
* Note: This is not an async task.
*
* @param $id Attchment ID.
*/
function wp_smush_handle_other_uploads( $id ) {
// Our async task runs when action is upload-attachment and post_id found. So do not run on these conditions.
if ( empty( $id ) || ( ! empty( $_POST['action'] ) && 'upload-attachment' == $_POST['action'] ) || ( ! empty( $_POST ) && isset( $_POST['post_id'] ) ) ) {
return;
}
// Do not continue if attachment is not an image.
if ( ! wp_attachment_is_image( $id ) ) {
return;
}
// Run additional checks then smush.
$this->wp_smush_handle_async( $id );
}
}
global $WpSmush;
$WpSmush = new WpSmush();
}
//Include Admin classes
require_once( WP_SMUSH_DIR . 'lib/class-wp-smush-admin.php' );
//Include Directory Smush
require_once WP_SMUSH_DIR . 'lib/class-wp-smush-dir.php';