: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Adds the Bulk Page and Smush Column to NextGen Gallery
* @package Smush\Core\Integrations\NextGen
* @author Umesh Kumar <umesh@incsub.com>
* @copyright (c) 2016, Incsub (http://incsub.com)
namespace Smush\Core\Integrations\NextGen;
use C_Component_Registry;
use Smush\App\Media_Library;
use Smush\Core\Integrations\NextGen;
if ( ! defined( 'WPINC' ) ) {
class Admin extends NextGen {
* Count of images ( Attachments ), Does not includes additional sizes that might have been created.
* @var int $smushed_count
public $smushed_count = 0;
* Includes the count of different sizes an image might have
* @var int $remaining_count
public $remaining_count = 0;
* @var int $super_smushed
public $super_smushed = 0;
public $smushed = array();
* Stores all lossless smushed IDs.
* @var array $resmush_ids
public $resmush_ids = array();
* @param Stats $stats Class object.
public function __construct( Stats $stats ) {
$this->ng_stats = $stats;
$this->settings = Settings::get_instance();
// Update the number of columns.
add_filter( 'ngg_manage_images_number_of_columns', array( $this, 'wp_smush_manage_images_number_of_columns' ) );
// Update resmush list, if a NextGen image is deleted.
add_action( 'ngg_delete_picture', array( $this, 'update_resmush_list' ) );
// Update Stats, if a NextGen image is deleted.
add_action( 'ngg_delete_picture', array( $this, 'update_nextgen_stats' ) );
// Update Stats, Lists - if a NextGen Gallery is deleted.
add_action( 'ngg_delete_gallery', array( $this->ng_stats, 'update_stats_cache' ) );
// Update the Super Smush count, after the smushing.
add_action( 'wp_smush_image_optimised_nextgen', array( $this, 'update_lists_after_optimizing' ), '', 2 );
// Reset smush data after restoring the image.
add_action( 'ngg_recovered_image', array( $this, 'reset_smushdata' ) );
add_action( 'wp_ajax_nextgen_get_stats', array( $this, 'ajax_get_stats' ) );
add_filter( 'wp_smush_nextgen_scan_stats', array( $this, 'scan_images' ) );
* Returns a column name for WP Smush.
* @param array $columns Current columns.
public function wp_smush_image_column_name( $columns ) {
// Latest next gen takes string, while the earlier WP Smush plugin shows there use to be a array.
if ( is_array( $columns ) ) {
$columns['wp_smush_image'] = esc_html__( 'Smush', 'wp-smushit' );
$columns = esc_html__( 'Smush', 'wp-smushit' );
* Returns Smush option / Stats, depending if image is already smushed or not.
* @param string $column_name Column name.
* @param object|int $id Image object or ID.
* @return array|bool|string|void
public function wp_smush_column_options( $column_name, $id ) {
// NExtGen Doesn't returns Column name, weird? yeah, right, it is proper because hook is called for the particular column.
if ( 'wp_smush_image' === $column_name || '' === $column_name ) {
// We're not using our in-house function Smush\Core\Integrations\Nextgen::get_nextgen_image_from_id()
// as we're already instializing the nextgen gallery object, we need $storage instance later.
// 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' );
// We'll get the image object in $id itself, else fetch it using Gallery Storage.
if ( is_object( $id ) ) {
$image = $storage->object->_image_mapper->find( $id );
// Check if it is supported image format, get image type to do that get the absolute path.
$file_path = $storage->get_image_abspath( $image, 'full' );
// Get image type from file path.
$image_type = $this->get_file_type( $file_path );
// If image type not supported.
if ( ! $image_type || ! in_array( $image_type, Core::$mime_types, true ) ) {
$image->meta_data = $this->get_combined_stats( $image->meta_data );
// Check Image metadata, if smushed, print the stats or super smush button.
if ( ! empty( $image->meta_data['wp_smush'] ) ) {
return $this->show_stats( $image->pid, $image->meta_data['wp_smush'], $image_type );
// Print the status of image, if Not smushed.
return $this->set_status( $image->pid );
* Localize Translations And Stats
public function localize() {
$upgrade_url = add_query_arg(
'utm_medium' => 'plugin',
'utm_campaign' => 'smush_bulksmush_issues_filesizelimit_notice',
'https://wpmudev.com/project/wp-smush-pro/'
if ( WP_Smush::is_pro() ) {
$error_in_bulk = esc_html__( '{{smushed}}/{{total}} images were successfully compressed, {{errors}} encountered issues.', 'wp-smushit' );
$error_in_bulk = sprintf(
/* translators: %1$s - opening link tag, %2$s - Close the link </a> */
esc_html__( '{{smushed}}/{{total}} images were successfully compressed, {{errors}} encountered issues. Are you hitting the 5MB "size limit exceeded" warning? %1$sUpgrade to Smush Pro%2$s to optimize unlimited image files.', 'wp-smushit' ),
'<a href="' . esc_url( $upgrade_url ) . '" target="_blank">',
'nonce' => wp_create_nonce( 'wp-smush-ajax' ),
'resmush' => esc_html__( 'Super-Smush', 'wp-smushit' ),
'smush_now' => esc_html__( 'Smush Now', 'wp-smushit' ),
'error_in_bulk' => $error_in_bulk,
'all_resmushed' => esc_html__( 'All images are fully optimized.', 'wp-smushit' ),
'restore' => esc_html__( 'Restoring image...', 'wp-smushit' ),
'smushing' => esc_html__( 'Smushing image...', 'wp-smushit' ),
wp_localize_script( $handle, 'wp_smush_msgs', $wp_smush_msgs );
$data = $this->ng_stats->get_global_stats();
wp_localize_script( $handle, 'wp_smushit_data', $data );
* Increase the count of columns for Nextgen Gallery Manage page.
* @param int $count Current columns count.
public function wp_smush_manage_images_number_of_columns( $count ) {
add_filter( "ngg_manage_images_column_{$count}_header", array( $this, 'wp_smush_image_column_name' ) );
add_filter( "ngg_manage_images_column_{$count}_content", array( $this, 'wp_smush_column_options' ), 10, 2 );
private function set_status( $pid ) {
$status_txt = __( 'Not processed', 'wp-smushit' );
// we need to show the smush button.
$button_txt = __( 'Smush', 'wp-smushit' );
// If we are not showing smush button, append progress bar, else it is already there.
$status_txt .= Media_Library::progress_bar();
return $this->column_html( $pid, $status_txt, $button_txt, $show_button );
* @param string $pid 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 Image compressed or not.
public function column_html( $pid, $status_txt = '', $button_txt = '', $show_button = true, $smushed = false ) {
$class = $smushed ? '' : ' sui-hidden';
$html = '<p class="smush-status' . $class . '">' . $status_txt . '</p>';
// if we aren't showing the button.
$html .= '<div class="sui-smush-media smush-status-links">';
$html .= wp_nonce_field( 'wp_smush_nextgen', '_wp_smush_nonce', '', false );
$html .= '<button class="button button-primary wp-smush-nextgen-send" data-id="' . $pid . '">
<span>' . $button_txt . '</span>
* Updates the resmush list for NextGen gallery, remove the given id
* @param int $attachment_id Attachment ID.
public function update_resmush_list( $attachment_id ) {
if ( $this->ng_stats->get_reoptimize_list()->has_id( $attachment_id ) ) {
return $this->ng_stats->get_reoptimize_list()->remove_id( $attachment_id );
return $this->ng_stats->get_reoptimize_list()->add_id( $attachment_id );
* Fetch the stats for the given attachment id, and subtract them from Global stats
* @param int $attachment_id Attachment ID.
public function update_nextgen_stats( $attachment_id ) {
if ( empty( $attachment_id ) ) {
$image_id = absint( (int) $attachment_id );
// Get the absolute path for original image.
$image = $this->get_nextgen_image_from_id( $image_id );
$metadata = ! empty( $image ) ? $image->meta_data : '';
$smush_stats = ! empty( $metadata['wp_smush'] ) ? $metadata['wp_smush'] : '';
if ( empty( $smush_stats ) ) {
$nextgen_stats = get_option( 'wp_smush_stats_nextgen', false );
if ( ! $nextgen_stats ) {
if ( ! empty( $nextgen_stats['size_before'] ) && ! empty( $nextgen_stats['size_after'] ) && $nextgen_stats['size_before'] > 0 && $nextgen_stats['size_after'] > 0 && $nextgen_stats['size_before'] >= $smush_stats['stats']['size_before'] ) {
$nextgen_stats['size_before'] = $nextgen_stats['size_before'] - $smush_stats['stats']['size_before'];
$nextgen_stats['size_after'] = $nextgen_stats['size_after'] - $smush_stats['stats']['size_after'];
$nextgen_stats['bytes'] = $nextgen_stats['size_before'] - $nextgen_stats['size_after'];
if ( 0 === $nextgen_stats['bytes'] && 0 === $nextgen_stats['size_before'] ) {
$nextgen_stats['percent'] = 0;
$nextgen_stats['percent'] = ( $nextgen_stats['bytes'] / $nextgen_stats['size_before'] ) * 100;
$nextgen_stats['human'] = size_format( $nextgen_stats['bytes'], 1 );
update_option( 'wp_smush_stats_nextgen', $nextgen_stats, false );
// Remove from Super Smush list.
$this->ng_stats->get_supper_smushed_list()->remove_id( $image_id );
* Update the Super Smush count for NextGen Gallery
* @param int $image_id Image ID.
* @param array $stats Stats.
public function update_lists_after_optimizing( $image_id, $stats ) {
if ( isset( $stats['stats']['lossy'] ) && 1 === (int) $stats['stats']['lossy'] ) {
$this->ng_stats->get_supper_smushed_list()->add_id( $image_id );
$this->update_resmush_list( $image_id );
* Initialize NextGen Gallery Stats
public function setup_image_counts() {
$this->total_count = $this->ng_stats->total_count();
$this->smushed_count = $this->ng_stats->get_smushed_count();
$this->image_count = $this->ng_stats->get_smushed_image_count();
$this->resmush_ids = $this->ng_stats->get_reoptimize_list()->get_ids();
$this->super_smushed = $this->ng_stats->get_supper_smushed_count();
$this->remaining_count = $this->ng_stats->get_remaining_count();
* Get the image count for nextgen images
* @param array $images Array of attachments to get the image count for.
* @param bool $exclude_resmush_ids Whether to exclude resmush ids or not.
public function get_image_count( $images = array(), $exclude_resmush_ids = true ) {
if ( empty( $images ) || ! is_array( $images ) ) {
// $image in here is expected to be metadata array
foreach ( $images as $image_k => $image ) {
// Get image object if not there already.
if ( ! is_array( $image ) ) {
$image = $this->get_nextgen_image_from_id( $image );
$image = ! empty( $image->meta_data ) ? $image->meta_data : '';
// If there are no smush stats, skip.
if ( empty( $image['wp_smush'] ) ) {
// If resmush ids needs to be excluded.
if ( $exclude_resmush_ids && ( ! empty( $this->resmush_ids ) && in_array( $image_k, $this->resmush_ids ) ) ) {
if ( ! empty( $image['wp_smush']['sizes'] ) ) {
$image_count += count( $image['wp_smush']['sizes'] );
* Combine the resizing stats and smush stats , One time operation - performed during the image optimization
* @param array $metadata Image metadata.
private function get_combined_stats( $metadata ) {
if ( empty( $metadata ) ) {
$smush_stats = ! empty( $metadata['wp_smush'] ) ? $metadata['wp_smush'] : '';
$resize_savings = ! empty( $metadata['wp_smush_resize_savings'] ) ? $metadata['wp_smush_resize_savings'] : '';
if ( empty( $resize_savings ) || empty( $smush_stats ) ) {
$smush_stats['stats']['bytes'] = ! empty( $resize_savings['bytes'] ) ? $smush_stats['stats']['bytes'] + $resize_savings['bytes'] : $smush_stats['stats']['bytes'];
$smush_stats['stats']['size_before'] = ! empty( $resize_savings['size_before'] ) ? $smush_stats['stats']['size_before'] + $resize_savings['size_before'] : $smush_stats['stats']['size_before'];
$smush_stats['stats']['size_after'] = ! empty( $resize_savings['size_after'] ) ? $smush_stats['stats']['size_after'] + $resize_savings['size_after'] : $smush_stats['stats']['size_after'];
$smush_stats['stats']['percent'] = ! empty( $resize_savings['size_before'] ) ? ( $smush_stats['stats']['bytes'] / $smush_stats['stats']['size_before'] ) * 100 : $smush_stats['stats']['percent'];
$smush_stats['stats']['percent'] = round( $smush_stats['stats']['percent'], 2 );
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'] ) ? $smush_stats['sizes']['full']['size_before'] + $resize_savings['size_before'] : $smush_stats['sizes']['full']['size_before'];
$smush_stats['sizes']['full']['size_after'] = ! empty( $resize_savings['size_after'] ) ? $smush_stats['sizes']['full']['size_after'] + $resize_savings['size_after'] : $smush_stats['sizes']['full']['size_after'];
$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'], 2 );
$smush_stats['sizes']['full'] = $resize_savings;
$metadata['wp_smush'] = $smush_stats;
* Reset smush data after restoring the image.
* @param stdClass $image Image object for NextGen gallery.
* @param false|string $attachment_file_path The full file path, if it's provided we will reset the dimension.
public function reset_smushdata( $image, $attachment_file_path = false ) {
if ( empty( $image->meta_data['wp_smush'] ) && empty( $image->meta_data['wp_smush_resize_savings'] ) ) {
$this->ng_stats->subtract_image_stats( $image );