: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* NextGen integration: NextGen class
* @package Smush\Core\Integrations
* @author Umesh Kumar <umesh@incsub.com>
* @copyright (c) 2016, Incsub (http://incsub.com)
namespace Smush\Core\Integrations;
use C_Component_Registry;
if ( ! defined( 'WPINC' ) ) {
class NextGen extends Abstract_Integration {
* Contains the total Stats, for displaying it on bulk page
public function __construct() {
$this->module = 'nextgen';
$this->enabled = class_exists( '\C_NextGEN_Bootstrap' );
$is_pro = WP_Smush::is_pro();
// Hook at the end of setting row to output a error div.
add_action( 'smush_setting_column_right_inside', array( $this, 'additional_notice' ) );
// Do not continue if not PRO member or NextGen plugin not installed.
if ( ! $is_pro || ! $this->enabled || ! $this->is_enabled() ) {
add_action( 'smush_setting_column_tag', array( $this, 'add_pro_tag' ) );
add_action( 'admin_init', array( $this, 'init_modules' ) );
// Auto Smush image, if enabled, runs after NextGen is finished uploading the image.
// Allows to override whether to auto smush NextGen image or not.
$auto_smush = apply_filters( 'smush_nextgen_auto', WP_Smush::get_instance()->core()->mod->smush->is_auto_smush_enabled() );
add_action( 'ngg_added_new_image', array( $this, 'auto_smush' ) );
// Update Total Image count.
add_action( 'ngg_added_new_image', array( $this, 'update_stats_image_count' ), 10 );
// Single Smush/Manual Smush: Handles the Single/Manual smush request for NextGen Gallery.
add_action( 'wp_ajax_smush_manual_nextgen', array( $this, 'manual_nextgen' ) );
// Restore Image: Handles the single/Manual restore image request for NextGen Gallery.
add_action( 'wp_ajax_smush_restore_nextgen_image', array( $this, 'restore_image' ) );
// Resmush Image: Handles the single/Manual resmush image request for NextGen Gallery.
add_action( 'wp_ajax_smush_resmush_nextgen_image', array( $this, 'resmush_image' ) );
// Bulk Smush NextGen images.
add_action( 'wp_ajax_wp_smushit_nextgen_bulk', array( $this, 'smush_bulk' ) );
/**************************************
* OVERWRITE PARENT CLASS FUNCTIONALITY
* Filters the setting variable to add NextGen setting title and description
* @param array $settings Settings.
public function register( $settings ) {
$settings[ $this->module ] = array(
'label' => esc_html__( 'Enable NextGen Gallery integration', 'wp-smushit' ),
'short_label' => esc_html__( 'NextGen Gallery', 'wp-smushit' ),
'desc' => esc_html__( 'Allow smushing images directly through NextGen Gallery settings.', 'wp-smushit' ),
* Disable module functionality if not PRO.
public function setting_status() {
return ! WP_Smush::is_pro() ? true : ! $this->enabled;
/**************************************
* Initialize the stats and admin modules, once admin is ready.
public function init_modules() {
$this->ng_stats = new NextGen\Stats();
$this->ng_admin = new NextGen\Admin( $this->ng_stats );
* Check if NextGen integration is active.
public function is_enabled() {
return $this->settings->get( 'nextgen' );
* Bulk Smush for Nextgen.
* @throws Exception Exception.
public function smush_bulk() {
check_ajax_referer( 'wp-smush-ajax', '_nonce' );
if ( ! Helper::is_user_allowed( 'manage_options' ) ) {
wp_die( esc_html__( 'Unauthorized', 'wp-smushit' ), 403 );
if ( empty( $_GET['attachment_id'] ) ) {
'error_message' => esc_html__( 'No attachment ID was received', 'wp-smushit' ),
'file_name' => 'undefined',
$atchmnt_id = (int) $_GET['attachment_id'];
$smush = $this->smush_image( $atchmnt_id, '', true );
if ( is_wp_error( $smush ) ) {
$error_message = $smush->get_error_message();
// Check for timeout error and suggest to filter timeout.
if ( strpos( $error_message, 'timed out' ) ) {
$error_message = esc_html__( 'Smush request timed out. You can try setting a higher value ( > 60 ) for `WP_SMUSH_TIMEOUT`.', 'wp-smushit' );
$error = isset( $error ) ? $error : 'other';
$file_name = $this->get_nextgen_image_from_id( $atchmnt_id );
'error_message' => $error_message,
'file_name' => isset( $file_name->filename ) ? $file_name->filename : 'undefined',
// Check if a re-Smush request, update the re-Smush list.
if ( ! empty( $_REQUEST['is_bulk_resmush'] ) ) {
$this->ng_stats->get_reoptimize_list()->remove_id( $atchmnt_id );
$stats['is_lossy'] = ! empty( $smush['stats'] ) ? $smush['stats']['lossy'] : 0;
// Size before and after smush.
$stats['size_before'] = ! empty( $smush['stats'] ) ? $smush['stats']['size_before'] : 0;
$stats['size_after'] = ! empty( $smush['stats'] ) ? $smush['stats']['size_after'] : 0;
// Get the re-Smush IDs list.
$this->ng_admin->resmush_ids = $this->ng_stats->get_reoptimize_list()->get_ids();
$resmush_count = ! empty( $this->ng_admin->resmush_ids ) ? count( $this->ng_admin->resmush_ids ) : 0;
$smushed_images = $this->ng_stats->get_ngg_images( 'smushed' );
// Remove re-Smush IDs from smushed images list.
if ( $resmush_count > 0 && is_array( $this->ng_admin->resmush_ids ) ) {
foreach ( $smushed_images as $image_k => $image ) {
if ( in_array( $image_k, $this->ng_admin->resmush_ids, true ) ) {
unset( $smushed_images[ $image_k ] );
// Get the image count and smushed images count.
$image_count = ! empty( $smush ) && ! empty( $smush['sizes'] ) ? count( $smush['sizes'] ) : 0;
$smushed_count = is_array( $smushed_images ) ? count( $smushed_images ) : 0;
$stats['smushed'] = ! empty( $this->ng_admin->resmush_ids ) ? $smushed_count - $resmush_count : $smushed_count;
$stats['count'] = $image_count;
* Show additional notice if the required plugins are not installed.
* @param string $name Setting name.
public function additional_notice( $name ) {
if ( $this->module === $name && ! $this->enabled ) {
<div class="sui-toggle-content">
<div class="sui-notice-content">
<div class="sui-notice-message">
<i class="sui-notice-icon sui-icon-info" aria-hidden="true"></i>
<p><?php esc_html_e( 'To use this feature you need to be using NextGen Gallery.', 'wp-smushit' ); ?></p>
* Get the NextGen Image object from attachment id
* @param string $pid NextGen Gallery Image ID.
public function get_nextgen_image_from_id( $pid ) {
// Registry Object for NextGen Gallery.
$registry = C_Component_Registry::get_instance();
// Gallery Storage Object.
$storage = $registry->get_utility( 'I_Gallery_Storage' );
return $storage->object->_image_mapper->find( $pid );
* @param string $file_path File path.
public function get_file_type( $file_path ) {
if ( empty( $file_path ) || ! file_exists( $file_path ) ) {
if ( function_exists( 'exif_imagetype' ) ) {
$image_type = exif_imagetype( $file_path );
if ( ! empty( $image_type ) ) {
$image_mime = image_type_to_mime_type( $image_type );
$image_details = getimagesize( $file_path );
$image_mime = ! empty( $image_details ) && is_array( $image_details ) ? $image_details['mime'] : '';
* Performs the actual smush process
* @usedby: `manual_nextgen`, `auto_smush`, `smush_bulk`
* @param string $pid NextGen Gallery Image id.
* @param string $image Nextgen gallery image object.
* @param bool $is_bulk Whether it's called by bulk smush or not.
* @return mixed Stats / Status / Error
public function smush_image( $pid = '', $image = '', $is_bulk = false ) {
// Get image, if we have image id.
$image = $this->get_nextgen_image_from_id( $pid );
} elseif ( ! empty( $image ) ) {
$pid = $this->get_nextgen_id_from_image( $image );
$metadata = ! empty( $image ) ? $image->meta_data : '';
if ( empty( $metadata ) ) {
* We use error_msg for single images to append to the div and error_message to
* append to bulk smush errors list.
'error' => 'no_metadata',
'error_msg' => '<p class="wp-smush-error-message">' . esc_html__( "We couldn't find the metadata for the image, possibly the image has been deleted.", 'wp-smushit' ) . '</p>',
'error_message' => esc_html__( "We couldn't find the metadata for the image, possibly the image has been deleted.", 'wp-smushit' ),
'file_name' => isset( $image->filename ) ? $image->filename : 'undefined',
$registry = C_Component_Registry::get_instance();
$storage = $registry->get_utility( 'I_Gallery_Storage' );
$metadata = $this->resize_image( $pid, $image, $metadata, $storage );
$image->meta_data = $metadata;
nggdb::update_image_meta( $image->pid, $image->meta_data );
// Smush the main image and its sizes.
$smush = $this->resize_from_meta_data( $image );
if ( ! is_wp_error( $smush ) ) {
$status = $this->ng_admin->show_stats( $pid, $smush );
if ( is_wp_error( $smush ) ) {
* Refreshes the total image count from the stats when a new image is added to nextgen gallery
* Should be called only if image count need to be updated, use total_count(), otherwise
public function update_stats_image_count() {
NextGen\Stats::total_count( true );
* Handles the smushing of each image and its registered sizes
* Calls the function to update the compression stats
public function manual_nextgen() {
$pid = ! empty( $_GET['attachment_id'] ) ? absint( (int) $_GET['attachment_id'] ) : '';
$nonce = ! empty( $_GET['_nonce'] ) ? wp_unslash( $_GET['_nonce'] ) : '';
if ( ! wp_verify_nonce( $nonce, 'wp_smush_nextgen' ) ) {
'error' => 'nonce_verification_failed',
// Check for media upload permission.
if ( ! Helper::is_user_allowed( 'upload_files' ) ) {
'error_msg' => __( "You don't have permission to work with uploaded files.", 'wp-smushit' ),
'error_msg' => __( 'No attachment ID was provided.', 'wp-smushit' ),
$status = $this->smush_image( $pid );
if ( is_wp_error( $status ) ) {
* Not used for bulk smush.
wp_send_json_error( $status->get_error_message() );
wp_send_json_success( $status );
* Process auto smush request for NextGen gallery images.
* @param stdClass $image Image.
public function auto_smush( $image ) {
if ( ! $this->ng_stats || ! $this->ng_admin ) {
$this->smush_image( '', $image );
* Checks for file backup, if available for any of the size,
* @param string $pid NextGen gallery image ID.
* @param array $attachment_data Attachment data.
public function show_restore_option( $pid, $attachment_data ) {
$backup = WP_Smush::get_instance()->core()->mod->backup;
// Registry Object for NextGen Gallery.
$registry = C_Component_Registry::get_instance();
* Gallery Storage Object.
* @var C_Gallery_Storage $storage
$storage = $registry->get_utility( 'I_Gallery_Storage' );
$image = $storage->object->_image_mapper->find( $pid );
$attachment_file_path = $storage->get_image_abspath( $image, 'full' );
$backup_path = $backup->get_image_backup_path( $attachment_file_path );
// If one of the backup(Ours/NextGen) exists, show restore option.
if ( file_exists( $backup_path ) || file_exists( $attachment_file_path . '_backup' ) ) {
// Get Sizes, and check for backup.
if ( empty( $attachment_data['sizes'] ) ) {