: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Abstract Media Library Scanner.
import Fetcher from '../utils/fetcher';
import { scanProgressBar } from './progressbar';
import { GlobalStats } from './globalStats';
import loopbackTester from '../loopback-tester';
export default class MediaLibraryScanner {
this.autoSyncDuration = 1500;
this.progressTimeoutId = 0;
this.scanProgress = scanProgressBar( this.autoSyncDuration );
startScan( optimizeOnScanCompleted = false ) {
const processType = optimizeOnScanCompleted ? 'smush' : 'scan';
loopbackTester.performTest().then( ( res ) => {
const isLoopbackHealthy = res?.loopback;
if ( isLoopbackHealthy ) {
Fetcher.scanMediaLibrary.start( optimizeOnScanCompleted ).then( ( response ) => {
if ( ! response?.success ) {
this.showFailureNotice( response );
this.onStartFailure( response );
this.showProgressBar().autoSyncStatus();
this.showLoopbackErrorModal( processType );
this.onStartFailure( res );
} ).catch( ( error ) => {
console.error( 'Error:', error );
this.showLoopbackErrorModal( processType );
this.onStartFailure( error );
// Do nothing at the moment.
onStartFailure( response ) {
// Do nothing at the moment.
showFailureNotice( response ) {
WP_Smush.helpers.showNotice( response, {
showLoopbackErrorModal( processType ) {
const loopbackErrorModal = document.getElementById( 'smush-loopback-error-dialog' );
if ( ! loopbackErrorModal || ! window.SUI ) {
// Cache current process type.
loopbackErrorModal.dataset.processType = processType || 'scan';
WP_Smush.helpers.showModal( loopbackErrorModal.id );
this.onShowProgressBar();
this.scanProgress.reset().setOnCancelCallback( this.showStopScanningModal.bind( this ) ).open();
// Do nothing at the moment.
showStopScanningModal() {
this.onShowStopScanningModal();
'smush-stop-scanning-dialog',
onShowStopScanningModal() {
this.registerCancelProcessEvent();
registerCancelProcessEvent() {
const stopScanButton = document.querySelector( '.smush-stop-scanning-dialog-button' );
if ( ! stopScanButton ) {
stopScanButton.addEventListener( 'click', this.cancelProgress.bind( this ), { once: true } );
closeStopScanningModal() {
const stopScanningElement = document.querySelector( '#smush-stop-scanning-dialog' );
const isModalClosed = ( ! stopScanningElement ) || ! stopScanningElement.classList.contains( 'sui-content-fade-in' );
window.SUI.closeModal( 'smush-stop-scanning-dialog' );
this.onCloseProgressBar();
this.scanProgress.close();
// Do nothing at the moment.
updateProgress( stats ) {
const totalItems = this.getTotalItems( stats );
const processedItems = this.getProcessedItems( stats );
return this.scanProgress.update( processedItems, totalItems );
getProcessedItems( stats ) {
return stats?.processed_items || 0;
return stats?.total_items || 0;
this.scanProgress.setCancelButtonOnCancelling();
return Fetcher.scanMediaLibrary.cancel().then( ( response ) => {
if ( ! response?.success ) {
this.onCancelFailure( response );
this.onCancelled( response.data );
onCancelFailure( response ) {
WP_Smush.helpers.showNotice( response, {
this.scanProgress.resetCancelButtonOnFailure();
this.clearProgressTimeout();
this.closeStopScanningModal();
this.showRetryScanModal();
const retryScanModalElement = document.getElementById( 'smush-retry-scan-notice' );
if ( ! window.SUI || ! retryScanModalElement ) {
retryScanModalElement.querySelector( '.smush-retry-scan-notice-button' ).addEventListener( 'click', ( e ) => {
window.SUI.closeModal( 'smush-retry-scan-notice' );
const recheckImagesBtn = document.querySelector( '.wp-smush-scan' );
if ( ! recheckImagesBtn ) {
recheckImagesBtn.click();
'smush-retry-scan-notice',
this.clearProgressTimeout();
const globalStats = stats?.global_stats;
this.updateGlobalStatsAndBulkContent( globalStats );
this.closeStopScanningModal();
if ( this.progressTimeoutId ) {
clearTimeout( this.progressTimeoutId );
updateGlobalStatsAndBulkContent( globalStats ) {
GlobalStats.updateGlobalStatsFromSmushScriptData( globalStats );
GlobalStats.renderStats();
return Fetcher.scanMediaLibrary.getScanStatus();
const startTime = new Date().getTime();
this.getStatus().then( ( response ) => {
if ( ! response?.success ) {
const stats = response.data;
this.onDead( response.data );
this.beforeUpdateStatus( stats );
this.updateProgress( stats ).then( () => {
this.scanProgress.increaseDurationToHaveChangeOnProgress( new Date().getTime() - startTime );
const isCompleted = stats?.is_completed;
this.onCompleted( stats );
const isCancelled = stats?.is_cancelled;
this.onCancelled( stats );
this.progressTimeoutId = setTimeout( () => this.autoSyncStatus(), this.autoSyncDuration );
// Do nothing at the moment.
setInnerText( element, newText ) {
element.dataset.originalText = element.dataset.originalText || element.innerText.trim();
element.innerText = newText;
revertInnerText( element ) {
if ( ! element || ! element.dataset.originalText ) {
element.innerText = element.dataset.originalText.trim();
hideAnElement( element ) {
element.classList.add( 'sui-hidden' );
showAnElement( element ) {
element.classList.remove( 'sui-hidden' );