: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
import tracker from '../utils/tracker';
troubleshootClicked = false;
resumeBulkSmushCount = 0;
missedEventsKey = 'wp_smush_missed_events';
if ( ! tracker.allowToTrack() ) {
this.registerTroubleshootClickEvent();
// Scan Interrupted Event from Scan Modal.
this.trackScanInterruptedEventOnStopScanningModal();
this.trackScanInterruptedEventOnRetryScanModal();
// Bulk Smush Interrupted Event from Bulk Smush Modal.
this.trackBulkSmushInterruptedEventOnStopBulkSmushModal();
this.trackBulkSmushInterruptedEventOnRetryBulkSmushModal();
this.registerBulkSmushResumeClickEvent();
// Bulk Smush Interrupted Event when exit ajax bulk smush.
this.trackBulkSmushInterruptedEventWhenExitingAjaxBulkSmush();
// Interrupted Event from Inline Notice.
this.trackInterruptedEventFromInlineNotice();
// Interrupted Event from Loopback Error Modal.
this.trackInterruptedEventFromLoopbackErrorModal();
this.maybeTrackMissedEventsOnLoad();
const ultraUpsellLinks = document.querySelectorAll( '.wp-smush-upsell-ultra-compression' );
if ( ! ultraUpsellLinks ) {
const getLocation = ( ultraLink ) => {
settings: 'bulksmush_settings',
dashboard: 'dash_summary',
bulk: 'bulksmush_summary',
directory: 'directory_summary',
'lazy-load': 'lazy_summary',
const locationId = ultraLink.classList.contains( 'wp-smush-ultra-compression-link' ) ? 'settings' : this.getCurrentPageSlug();
return locations[ locationId ] || 'bulksmush_settings';
ultraUpsellLinks.forEach( ( ultraLink ) => {
const eventName = 'ultra_upsell_modal';
ultraLink.addEventListener( 'click', ( e ) => {
tracker.track( eventName, {
Location: getLocation( e.target ),
'Modal Action': 'direct_cta',
const upsellLinks = document.querySelectorAll( '[href*="utm_source=smush"]' );
upsellLinks.forEach( ( upsellLink ) => {
upsellLink.addEventListener( 'click', ( e ) => {
const params = new URL( e.target.href ).searchParams;
const campaign = params.get( 'utm_campaign' );
const upsellLocations = {
summary_cdn: 'dash_summary',
'smush-dashboard-cdn-upsell': 'dash_widget',
smush_bulksmush_cdn: 'bulk_smush_progress',
smush_cdn_upgrade_button: 'cdn_page',
smush_bulksmush_library_gif_cdn: 'media_library',
smush_bulk_smush_complete_global: 'bulk_smush_complete',
summary_local_webp: 'dash_summary',
'smush-dashboard-local-webp-upsell': 'dash_widget',
// smush_webp_upgrade_button: 'webp_page',// Handled inside React WebP - free-content.jsx
if ( ! ( campaign in upsellLocations ) ) {
const Location = upsellLocations[ campaign ];
const matches = campaign.match( /(cdn|webp)/i );
const upsellModule = matches && matches[ 0 ];
const eventName = 'webp' === upsellModule ? 'local_webp_upsell' : 'cdn_upsell';
tracker.track( eventName, { Location } );
trackScanInterruptedEventOnStopScanningModal() {
const stopScanningModal = document.getElementById( 'smush-stop-scanning-dialog' );
if ( ! stopScanningModal ) {
const closeButtons = stopScanningModal.querySelectorAll( '[data-modal-close]' );
closeButtons.forEach( ( closeButton ) => {
closeButton.addEventListener( 'click', ( e ) => {
const action = e.target.dataset?.action || 'Close';
this.trackScanInterruptedEvent( {
Trigger: 'cancel_in_progress',
trackBulkSmushInterruptedEventOnStopBulkSmushModal() {
const stopBulkSmushModal = document.getElementById( 'smush-stop-bulk-smush-modal' );
if ( ! stopBulkSmushModal ) {
const closeButtons = stopBulkSmushModal.querySelectorAll( '[data-modal-close]' );
closeButtons.forEach( ( closeButton ) => {
closeButton.addEventListener( 'click', ( e ) => {
const action = e.target.dataset?.action || 'Close';
this.trackBulkSmushInterruptedEvent( {
Trigger: 'cancel_in_progress',
trackScanInterruptedEventOnRetryScanModal() {
const retryScanModal = document.getElementById( 'smush-retry-scan-notice' );
if ( ! retryScanModal ) {
const retryButton = retryScanModal.querySelector( '.smush-retry-scan-notice-button' );
retryButton.addEventListener( 'click', ( e ) => {
const recheckImagesBtn = document.querySelector( '.wp-smush-scan' );
if ( recheckImagesBtn ) {
this.trackScanInterruptedEvent( {
const event = 'Scan Interrupted';
const properties = this.getScanInterruptedEventProperties( {
tracker.track( event, properties ).catch( () => {
window.location.href = e.target.href;
const closeButtons = retryScanModal.querySelectorAll( '[data-modal-close]' );
closeButtons.forEach( ( closeButton ) => {
closeButton.addEventListener( 'click', ( e ) => {
const action = e.target.dataset?.action || 'Close';
this.trackScanInterruptedEvent( {
trackBulkSmushInterruptedEventOnRetryBulkSmushModal() {
const retryBulkModal = document.getElementById( 'smush-retry-bulk-smush-notice' );
if ( ! retryBulkModal ) {
const retryButton = retryBulkModal.querySelector( '.smush-retry-bulk-smush-notice-button' );
retryButton.addEventListener( 'click', () => {
this.trackBulkSmushInterruptedEvent( {
const closeButtons = retryBulkModal.querySelectorAll( '[data-modal-close]' );
closeButtons.forEach( ( closeButton ) => {
closeButton.addEventListener( 'click', ( e ) => {
const action = e.target.dataset?.action || 'Close';
this.trackBulkSmushInterruptedEvent( {
trackScanInterruptedEvent( properties ) {
return tracker.track( 'Scan Interrupted', this.getScanInterruptedEventProperties( properties ) );
getScanInterruptedEventProperties( properties ) {
Troubleshoot: this.troubleshootClicked ? 'Yes' : 'No',
trackBulkSmushInterruptedEventWhenExitingAjaxBulkSmush() {
if ( this.canUseBackgroundOptimization() ) {
const progressBar = document.querySelector( '.wp-smush-bulk-progress-bar-wrapper' );
window.addEventListener( 'beforeunload', () => {
const ajaxBulkSmushObject = window.WP_Smush?.bulk?.bulkSmush;
const isBulkSmushInProgressing = ajaxBulkSmushObject && ajaxBulkSmushObject.ids.length > 0 && ! progressBar.classList.contains( 'sui-hidden' );
if ( ! isBulkSmushInProgressing ) {
const isFreeExceeded = progressBar.classList.contains( 'wp-smush-exceed-limit' );
const event = 'Bulk Smush Interrupted';
const properties = this.getBulkSmushInterruptedEventProperties(
Trigger: isFreeExceeded ? 'exit_50_limit' : 'exit_in_progress',
'Retry Attempts': this.resumeBulkSmushCount,
tracker.track( event, properties ).catch( () => {
cacheMissedEvent( eventData ) {
if ( window.localStorage ) {
// As now we only use it for one event, so let's keep it as a simple array.
window.localStorage.setItem( this.missedEventsKey, JSON.stringify( [ eventData ] ) );
if ( ! window.localStorage ) {
const properties = window.localStorage.getItem( this.missedEventsKey );
return JSON.parse( properties );
if ( window.localStorage ) {
window.localStorage.removeItem( this.missedEventsKey );
canUseBackgroundOptimization() {
return 'undefined' !== typeof window.wp_smushit_data?.bo_stats;
trackBulkSmushInterruptedEvent( properties ) {
return tracker.track( 'Bulk Smush Interrupted', this.getBulkSmushInterruptedEventProperties( properties ) );
getBulkSmushInterruptedEventProperties( properties ) {
Troubleshoot: this.troubleshootClicked ? 'Yes' : 'No',
this.getBulkSmushProcessStats(),
getBulkSmushProcessStats() {
if ( this.canUseBackgroundOptimization() ) {
const ajaxBulkSmushObject = window.WP_Smush?.bulk?.bulkSmush;
const totalEnqueuedImages = ajaxBulkSmushObject?.total || 0;
const processedImages = ajaxBulkSmushObject?.smushed + ajaxBulkSmushObject?.errors.length;
const completionPercentage = totalEnqueuedImages > 0 ? Math.ceil( processedImages * 100 / totalEnqueuedImages ) : 0;
'Retry Attempts': this.resumeBulkSmushCount,
'Total Enqueued Images': totalEnqueuedImages,
'Completion Percentage': completionPercentage,
trackInterruptedEventFromInlineNotice() {
this.trackInterruptedEventFromInlineNoticeOnDashboard();
this.trackBulkSmushInterruptedEventFromInlineNoticeOnBulkSmush();
this.trackScanInterruptedEventFromInlineNoticeOnBulkSmush();
trackInterruptedEventFromInlineNoticeOnDashboard() {
const dashboardBulkElement = document.getElementById( 'smush-box-dashboard-bulk' );
if ( ! dashboardBulkElement ) {
this.trackBulkSmushInterruptedEventFromInlineNoticeOnDashboard( dashboardBulkElement );
this.trackScanInterruptedEventFromInlineNoticeOnDashboard( dashboardBulkElement );
trackBulkSmushInterruptedEventFromInlineNoticeOnDashboard( dashboardBulkElement ) {
const triggerBulkSmushButton = dashboardBulkElement.querySelector( '.wp-smush-retry-bulk-smush-link' );
if ( ! triggerBulkSmushButton ) {
triggerBulkSmushButton.addEventListener( 'click', ( e ) => {
const event = 'Bulk Smush Interrupted';
const properties = this.getBulkSmushInterruptedEventProperties(
Trigger: 'failed_notice',
tracker.track( event, properties ).catch( () => {
window.location.href = e.target.href;
trackBulkSmushInterruptedInlineNoticeEvent() {
return this.trackBulkSmushInterruptedEvent( {
Trigger: 'failed_notice',
trackBulkSmushInterruptedEventFromInlineNoticeOnBulkSmush() {
const triggerBulkSmushButton = document.querySelector( '.wp-smush-inline-retry-bulk-smush-notice .wp-smush-trigger-bulk-smush' );
if ( ! triggerBulkSmushButton ) {
triggerBulkSmushButton.addEventListener( 'click', () => {
this.trackBulkSmushInterruptedInlineNoticeEvent();
trackScanInterruptedEventFromInlineNoticeOnDashboard( dashboardBulkElement ) {
const triggerScanButton = dashboardBulkElement.querySelector( '.wp-smush-retry-scan-link' );
if ( ! triggerScanButton ) {
triggerScanButton.addEventListener( 'click', ( e ) => {
const event = 'Scan Interrupted';
const properties = this.getScanInterruptedEventProperties( {
Trigger: 'failed_notice',
tracker.track( event, properties ).catch( () => {
window.location.href = e.target.href;
trackScanInterruptedEventFromInlineNoticeOnBulkSmush() {
const recheckImagesNotice = document.querySelector( '.wp-smush-recheck-images-notice-box' );
if ( ! recheckImagesNotice ) {
const triggerBackgroundScanImagesLink = recheckImagesNotice.querySelector( '.wp-smush-trigger-background-scan' );
if ( triggerBackgroundScanImagesLink ) {
triggerBackgroundScanImagesLink.addEventListener( 'click', () => {
// We are using the same frame for failed scan notice and generic required scan notice,
// so we need to verify the failed notice before tracking the event.
const containTroubleshootingLink = triggerBackgroundScanImagesLink?.previousElementSibling?.querySelector( 'a' );
if ( ! containTroubleshootingLink ) {
this.trackScanInterruptedEvent( {
Trigger: 'failed_notice',
trackInterruptedEventFromLoopbackErrorModal() {
const loopbackErrorModal = document.getElementById( 'smush-loopback-error-dialog' );
if ( ! loopbackErrorModal ) {
const loopbackErrorDocsLink = loopbackErrorModal.querySelector( 'a[href*="#loopback-request-issue"]' );
let isTroubleshootClicked = false;
if ( loopbackErrorDocsLink ) {
loopbackErrorDocsLink.addEventListener( 'click', () => {
isTroubleshootClicked = true;
const trackLoopbackErrorEvent = ( action, processType ) => {
Trigger: 'loopback_error',
Troubleshoot: isTroubleshootClicked ? 'Yes' : 'No',
if ( 'scan' === processType ) {
this.trackScanInterruptedEvent( properties );
this.trackBulkSmushInterruptedEvent( properties );
const closeButtons = loopbackErrorModal.querySelectorAll( '[data-modal-close]' );
closeButtons.forEach( ( closeButton ) => {
closeButton.addEventListener( 'click', ( e ) => {
const action = e.target.dataset?.action || 'Close';
const processType = loopbackErrorModal.dataset?.processType || 'scan';
trackLoopbackErrorEvent( action, processType );
registerTroubleshootClickEvent() {
const troubleshootLinks = document.querySelectorAll( 'a[href*="#troubleshooting-guide"]' );
if ( ! troubleshootLinks ) {
troubleshootLinks.forEach( ( troubleshootLink ) => {
troubleshootLink.addEventListener( 'click', () => {
this.troubleshootClicked = true;
maybeTrackMissedEventsOnLoad() {
window.addEventListener( 'load', () => {
const missedEvents = this.getMissedEvents();
if ( 0 === missedEvents.length ) {
this.clearMissedEvents();
missedEvents.forEach( ( missedEvent ) => {
tracker.track( missedEvent.event, missedEvent.properties );