: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* After the bulk optimization has been finished.
if ( 0 === this.ids.length ) {
jQuery('.bulk-smush-wrapper .wp-smush-all-done').removeClass( 'sui-hidden' );
jQuery( '.wp-smush-bulk-wrapper' ).addClass( 'sui-hidden' );
// Hide the progress bar if scan is finished.
jQuery( '.wp-smush-bulk-progress-bar-wrapper' ).addClass( 'sui-hidden' );
// Reset the progress when we finish so the next smushing starts from zero.
this._updateProgress( 0, 0 );
// Enable re-Smush and scan button.
jQuery( '.wp-resmush.wp-smush-action' ).removeProp(
showAnimatedUpsellNotice() {
if ( ! this.errors.length ) {
// Only show animated upsell if exists an animated error in first 5 errors.
// Note, this.errors will be reset each we resume so let detect animated error from elements.
const bulkErrors = document.querySelector('.smush-bulk-errors');
const firstAnimatedError = bulkErrors.querySelector( '[data-error-code="animated"]' );
if ( ! firstAnimatedError ) {
const first5Errors = Array.prototype.slice.call(bulkErrors.childNodes, 0, 5 );
return first5Errors.includes( firstAnimatedError );
maybeShowCDNActivationNotice() {
if ( ! wp_smush_msgs.smush_cdn_activation_notice || ! this.showAnimatedUpsellNotice() ) {
WP_Smush.helpers.renderActivationCDNNotice( wp_smush_msgs.smush_cdn_activation_notice );
maybeShowUnlimitedUpsellNotice() {
const unlimitedUpsellNotice = document.querySelector('.wp-smush-global-upsell');
if ( ! unlimitedUpsellNotice ) {
unlimitedUpsellNotice.classList.remove( 'sui-hidden' );
maybeShowBulkErrorActions() {
if ( ! this.errors.length ) {
const bulkErrorActionsElement = document.querySelector('.smush-bulk-errors-actions');
if ( ! bulkErrorActionsElement ) {
bulkErrorActionsElement.classList.remove('sui-hidden');
* Free Smush limit exceeded.
const progress = jQuery( '.wp-smush-bulk-progress-bar-wrapper' );
progress.addClass( 'wp-smush-exceed-limit' ).removeClass('sui-hidden');
.find( '.sui-progress-block .wp-smush-cancel-bulk' )
.removeClass( 'sui-hidden' );
.find( '.sui-progress-block .wp-smush-all' )
.addClass( 'sui-hidden' );
.find( 'i.sui-icon-loader' )
.addClass( 'sui-icon-info' )
.removeClass( 'sui-icon-loader' )
.removeClass( 'sui-loading' );
.getElementById( 'bulk-smush-resume-button' )
.classList.remove( 'sui-hidden' );
this.showBulkFreeLimitReachedNotice();
showBulkFreeLimitReachedNotice() {
const bulkFreeLimitReachedNotice = document.getElementById( 'smush-limit-reached-notice' );
if ( bulkFreeLimitReachedNotice ) {
bulkFreeLimitReachedNotice.classList.remove( 'sui-hidden' );
hideBulkFreeLimitReachedNotice() {
const bulkFreeLimitReachedNotice = document.getElementById( 'smush-limit-reached-notice' );
if ( bulkFreeLimitReachedNotice ) {
bulkFreeLimitReachedNotice.classList.add( 'sui-hidden' );
* Adds the stats for the current image to existing stats.
* @param {Array} imageStats
* @param {string} imageStats.count
* @param {boolean} imageStats.is_lossy
* @param {Array} imageStats.savings_resize
* @param {Array} imageStats.savings_conversion
* @param {string} imageStats.size_before
* @param {string} imageStats.size_after
static updateLocalizedStats( imageStats, type ) {
// Increase the Smush count.
if ( 'undefined' === typeof window.wp_smushit_data ) {
// No need to increase attachment count, resize, conversion savings for directory Smush.
if ( 'media' === type ) {
wp_smushit_data.count_smushed = parseInt( wp_smushit_data.count_smushed ) + 1;
// Increase Smushed image count.
wp_smushit_data.count_images = parseInt( wp_smushit_data.count_images ) + parseInt( imageStats.count );
// Increase super Smush count, if applicable.
if ( imageStats.is_lossy ) {
wp_smushit_data.count_supersmushed = parseInt( wp_smushit_data.count_supersmushed ) + 1;
// Add to resize savings.
wp_smushit_data.savings_resize =
'undefined' !== typeof imageStats.savings_resize.bytes
? parseInt( wp_smushit_data.savings_resize ) + parseInt( imageStats.savings_resize.bytes )
: parseInt( wp_smushit_data.savings_resize );
wp_smushit_data.count_resize =
'undefined' !== typeof imageStats.savings_resize.bytes
? parseInt( wp_smushit_data.count_resize ) + 1
: wp_smushit_data.count_resize;
// Add to conversion savings.
wp_smushit_data.savings_conversion =
'undefined' !== typeof imageStats.savings_conversion &&
'undefined' !== typeof imageStats.savings_conversion.bytes
? parseInt( wp_smushit_data.savings_conversion ) + parseInt( imageStats.savings_conversion.bytes )
: parseInt( wp_smushit_data.savings_conversion );
} else if ( 'directory_smush' === type ) {
//Increase smushed image count
wp_smushit_data.count_images = parseInt( wp_smushit_data.count_images ) + 1;
} else if ( 'nextgen' === type ) {
wp_smushit_data.count_smushed = parseInt( wp_smushit_data.count_smushed ) + 1;
wp_smushit_data.count_supersmushed = parseInt( wp_smushit_data.count_supersmushed ) + 1;
// Increase Smushed image count.
wp_smushit_data.count_images = parseInt( wp_smushit_data.count_images ) + parseInt( imageStats.count );
// If we have savings. Update savings.
if ( imageStats.size_before > imageStats.size_after ) {
wp_smushit_data.size_before =
'undefined' !== typeof imageStats.size_before
? parseInt( wp_smushit_data.size_before ) + parseInt( imageStats.size_before )
: parseInt( wp_smushit_data.size_before );
wp_smushit_data.size_after =
'undefined' !== typeof imageStats.size_after
? parseInt( wp_smushit_data.size_after ) + parseInt( imageStats.size_after )
: parseInt( wp_smushit_data.size_after );
// Add stats for resizing. Update savings.
if ( 'undefined' !== typeof imageStats.savings_resize ) {
wp_smushit_data.size_before =
'undefined' !== typeof imageStats.savings_resize.size_before
? parseInt( wp_smushit_data.size_before ) + parseInt( imageStats.savings_resize.size_before )
: parseInt( wp_smushit_data.size_before );
wp_smushit_data.size_after =
'undefined' !== typeof imageStats.savings_resize.size_after
? parseInt( wp_smushit_data.size_after ) + parseInt( imageStats.savings_resize.size_after )
: parseInt( wp_smushit_data.size_after );
// Add stats for conversion. Update savings.
if ( 'undefined' !== typeof imageStats.savings_conversion ) {
wp_smushit_data.size_before =
'undefined' !== typeof imageStats.savings_conversion.size_before
? parseInt( wp_smushit_data.size_before ) + parseInt( imageStats.savings_conversion.size_before )
: parseInt( wp_smushit_data.size_before );
wp_smushit_data.size_after =
'undefined' !== typeof imageStats.savings_conversion.size_after
? parseInt( wp_smushit_data.size_after ) + parseInt( imageStats.savings_conversion.size_after )
: parseInt( wp_smushit_data.size_after );
if ( ! this.is_bulk_resmush && ! this.is_bulk ) {
// Update localized stats.
'undefined' !== typeof _res.data &&
'undefined' !== typeof _res.data.stats
Smush.updateLocalizedStats( _res.data.stats, this.smush_type );
if ( ! this.is_bulk_resmush ) {
// Handle progress for normal bulk smush.
( ( this.smushed + this.errors.length ) / this.total ) * 100;
// If the request was successful, update the progress bar.
// Handle progress for super Smush progress bar.
if ( wp_smushit_data.resmush.length > 0 ) {
jQuery( '.wp-smush-images-remaining' ).html(
wp_smushit_data.resmush.length
0 === wp_smushit_data.resmush.length &&
// If all images are re-Smushed, show the All Smushed message.
jQuery('.bulk-resmush-wrapper .wp-smush-all-done').removeClass( 'sui-hidden' );
'.wp-smush-resmush-wrap, .wp-smush-bulk-progress-bar-wrapper'
).addClass( 'sui-hidden' );
// Handle progress for normal bulk Smush. Set progress bar width.
'undefined' !== typeof this.ids &&
'undefined' !== typeof this.total &&
( ( this.smushed + this.errors.length ) / this.total ) *
// Reset the lossless images count in case of pending images for resmush ( Nextgen only ).
'nextgen' === this.smush_type &&
wp_smushit_data.resmush.length > 0 &&
(this.smushed + this.errors.length <= 1)
wp_smushit_data.count_images -= (wp_smushit_data.resmush.length + 1);
// No more images left. Show bulk wrapper and Smush notice.
if ( 0 === this.ids.length ) {
// TODO: Check it with BO and maybe move these into progress bar module for reusing.
jQuery('.bulk-smush-wrapper .wp-smush-all-done').removeClass( 'sui-hidden' );
jQuery( '.wp-smush-bulk-wrapper' ).addClass( 'sui-hidden' );
// Increase the progress bar and counter.
this.smushed + this.errors.length,
WP_Smush.helpers.precise_round( progress, 1 )
// Avoid updating the stats twice when the bulk smush ends on Smush's page.
if (0 !== this.ids.length || 'nextgen' === this.smush_type) {
// Update stats and counts.
Smush.updateStats(this.smush_type);
* @param {number} count Number of images optimized.
* @param {string} width Percentage complete.
_updateProgress( count, width ) {
if ( ! this.is_bulk && ! this.is_bulk_resmush ) {
jQuery( 'span.wp-smush-images-percent' ).html( width + '%' );
jQuery( '.bulk-smush-wrapper .wp-smush-progress-inner' ).css(
jQuery( '.bulk-smush-wrapper .sui-progress-state-text' )
.find( 'span:first-child' )
.find( 'span:last-child' )
* Whether to send the ajax requests further or not.
* @return {*|boolean} Should continue or not.
return this.continueSmush && this.ids.length > 0 && this.is_bulk;
let continueSmush = this.button.attr( 'continue_smush' );
if ( 'undefined' === typeof continueSmush ) {
if ( 'false' === continueSmush || ! continueSmush ) {
return continueSmush && this.ids.length > 0 && this.is_bulk;
this.deferred = jQuery.Deferred();
this.deferred.errors = [];
this.continueSmush = true;
// TODO: errors will reset after bulk smush limit is reached and user clicks continue.
// Smushed and total we take from the progress bar... I don't like this :-(
const progressBar = jQuery(
'.bulk-smush-wrapper .sui-progress-state-text'
progressBar.find( 'span:first-child' ).html()
this.total = parseInt( progressBar.find( 'span:last-child' ).html() );
jQuery('.wp-smush-restore').prop('disabled', true);
* Send ajax request for optimizing single and bulk, call update_progress on ajax response.
* @return {*} Ajax call response.
callAjax(newBulkSmushStarted = false) {
* This here little piece of code allows to track auto continue clicks and halts bulk Smush until the page
* @see https://wordpress.org/plugins/wp-nonstop-smushit/
'undefined' !== typeof perf &&
10 > performance.now() - perf
let nonceValue = window.wp_smush_msgs.nonce;
// Remove from array while processing so we can continue where left off.
this.current_id = this.is_bulk
: this.button.data( 'id' );
// Remove the ID from respective variable as well.
Smush.updateSmushIds( this.current_id );
const nonceField = this.button.parent().find( '#_wp_smush_nonce' );
if ( nonceField.length > 0 ) {
nonceValue = nonceField.val();
this.request = Smush.ajax(
// If no response or success is false, do not process further. Increase the error count except if bulk request limit exceeded.
'undefined' === typeof res.success ||
( 'undefined' !== typeof res.success &&
'undefined' !== typeof res.data &&
'limit_exceeded' !== res.data.error )
self.errors.push( self.current_id );
const error = res.data.error;
/** @param {string} res.data.file_name */
const errorMsg = WP_Smush.helpers.prepareBulkSmushErrorRow(
self.log.removeClass('sui-hidden');
// Print the error on screen.
self.log.find( '.smush-bulk-errors' ).append( errorMsg );
if ( self.errors.length > 4 ) {
self.log.find( '.smush-bulk-errors' ).addClass('overflow-box');
jQuery( '.smush-bulk-errors-actions' ).removeClass( 'sui-hidden' );
'undefined' !== typeof res.success &&
// Increment the smushed count if image smushed without errors.
// Check whether to show the warning notice or not.
Smush.membershipValidity( res.data );
* Bulk Smush limit exceeded: Stop ajax requests, remove progress bar, append the last image ID
* back to Smush variable, and reset variables to allow the user to continue bulk Smush.
'undefined' !== typeof res.data &&
'limit_exceeded' === res.data.error &&
'resolved' !== self.deferred.state()
// Hide bulk running message.
const bulkRunning = document.getElementById(
'wp-smush-running-notice'
bulkRunning.classList.add( 'sui-hidden' );
// Add a data attribute to the Smush button, to stop sending ajax.
// self.button.attr( 'continue_smush', false );
self.continueSmush = false;
// Reinsert the current ID.
wp_smushit_data.unsmushed.unshift( self.current_id );
self.ids.unshift( self.current_id );
perf = performance.now();
} else if ( self.is_bulk ) {
self.updateProgress( res );
Smush.updateScoreProgress();
if (0 === self.ids.length && self.is_bulk ) {
self.onBulkSmushCompleted();
if ( ! self.continue() || ! self.is_bulk ) {
this.deferred.errors = this.errors;