Make WordPress Core

Opened 2 days ago

Last modified 31 hours ago

#65515 new defect (bug)

ThickBox ReferenceError: imgLoader is not defined due to "use strict" contamination in load-scripts.php

Reported by: bvedgie's profile bvedgie Owned by:
Milestone: 7.0.1 Priority: normal
Severity: normal Version: 7.0
Component: Script Loader Keywords: has-patch
Focuses: javascript Cc:

Description

In WordPress 7.0, clicking on "View details" for any plugin in the admin dashboard fails to open the ThickBox modal window. The dark overlay (#TB_overlay) appears, but the modal content window (#TB_window) is never generated, or the loading spinner hangs indefinitely.

The browser console throws a fatal JavaScript error pointing to load-scripts.php.

Environment:
WordPress Version: 7.0

Scripts involved:
load-scripts.php?c=0&load%5Bchunk_0%5D=wp-hooks,jquery-core,jquery-migrate,thickbox&ver=7.0

Context: WordPress Admin Dashboard (Plugins page)

Console Error Log:

jQuery.Deferred exception: imgLoader is not defined ReferenceError: imgLoader is not defined
    at HTMLDocument.<anonymous> (https://example.com/wp-admin/load-scripts.php?c=0&load%5Bchunk_0%5D=wp-hooks,jquery-core,jquery-migrate,thickbox&ver=7.0:25:12)
    at e (https://example.com/wp-admin/load-scripts.php?c=0&load%5Bchunk_0%5D=wp-hooks,jquery-core,jquery-migrate,thickbox&ver=7.0:4:27028)
    at t (https://example.com/wp-admin/load-scripts.php?c=0&load%5Bchunk_0%5D=wp-hooks,jquery-core,jquery-migrate,thickbox&ver=7.0:4:27330) undefined
Uncaught ReferenceError: imgLoader is not defined
    at HTMLDocument.<anonymous> (load-scripts.php?c=0&load%5Bchunk_0%5D=wp-hooks,jquery-core,jquery-migrate,thickbox&ver=7.0:25:12)

Root Cause Analysis:
In wp-includes/js/thickbox/thickbox.js, the variable imgLoader is declared implicitly without any keyword (e.g., imgLoader = new Image();), which instantiates it as a global variable.

In WordPress 7.0, modern core scripts bundled in the same chunk (such as wp-hooks or jquery-core) enforce JavaScript's "use strict"; mode.

When load-scripts.php concatenates these scripts into a single file, the "use strict"; directive scope spills over, forcing the browser to evaluate the legacy thickbox.js code under Strict Mode rules.

Under Strict Mode, implicit global variable declaration is a fatal error, throwing the ReferenceError: imgLoader is not defined and crashing the execution queue before the modal can render.

Steps to Reproduce:

  1. Ensure script concatenation is enabled (default behavior).
  2. Go to the Plugins > Installed Plugins page.
  3. Click on the "View details" link of any plugin.
  4. Observe the screen freezing on the grey overlay and check the browser Console for the ReferenceError.

Temporary Workaround:
Adding define( 'CONCATENATE_SCRIPTS', false ); to wp-config.php resolves the issue. This forces WordPress to load scripts in separate <script> tags, isolating thickbox.js from the strict mode directive of other core files.

Proposed Fix:
Explicitly declare the variable with a proper keyword inside wp-includes/js/thickbox/thickbox.js to ensure Strict Mode compliance like adding "var" before "imgLoader = new Image".
(Note: cannot write code as it prevent ticket creation.)

Alternatively, ensure that load-scripts.php properly encapsulates concatenated files within self-invoking functions (IIFE) to prevent "use strict"; directives from bleeding into legacy, non-strict dependencies.

Change History (4)

#1 follow-up: @westonruter
36 hours ago

  • Severity changed from blocker to normal

See also #57548 which proposes eliminating the concatenation altogether.

Is this truly a new issue in 7.0? If so, what commit was it introduced in?

#2 in reply to: ↑ 1 @siliconforks
35 hours ago

Replying to westonruter:

Is this truly a new issue in 7.0?

It looks like something did indeed change in 7.0. Compare these two versions:

https://github.com/WordPress/WordPress/blob/6.9.4/wp-includes/js/dist/hooks.js
https://github.com/WordPress/WordPress/blob/7.0/wp-includes/js/dist/hooks.js

The 7.0 version has "use strict" outside any function.

This ticket was mentioned in PR #12271 on WordPress/wordpress-develop by @khokansardar.


32 hours ago
#3

  • Keywords has-patch added; needs-patch removed

Fixes the WordPress 7.0 regression where ThickBox modals fail to open (e.g. "View details" on the Plugins screen), with the console error ReferenceError: imgLoader is not defined.

What the problem was:

  • Since the esbuild build switch (changeset 22294 / commit 22294af4ed), wp-includes/js/dist/hooks.js begins with a top-level "use strict";.
  • load-scripts.php concatenates requested scripts head-to-tail with wp-hooks first, so that directive becomes the directive prologue for the entire concatenated file, forcing strict mode on every script after it.
  • Legacy non-strict scripts like ThickBox assign implicit globals (imgLoader, imgPreloader, TB_WIDTH, ajaxContentW, ...), which throw ReferenceError in strict mode and abort the modal.

What the fix does:

  • Begins the concatenated output with an empty statement ($out = ";\n";), so a leading "use strict"; is no longer the first statement and is evaluated as a harmless expression instead of enabling strict mode for the whole file.

Approach and why:

  • The root cause is strict-mode contamination at the concatenation layer, not a single thickbox.js variable. Fixing only imgLoader would move the crash to the next implicit global on the same code path and leave every other bundled legacy script exposed.
  • This one-line change restores the pre-7.0 behaviour (concatenated admin scripts ran in sloppy mode) and fixes all affected scripts at once.
  • It is a no-op when CONCATENATE_SCRIPTS is disabled, since files are then served standalone; that path already runs hooks.js in strict mode, confirming no shipped script relies on strict mode for correctness.

Trac ticket: https://core.trac.wordpress.org/ticket/65515

## Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.8
Used for: Ticket analysis, regression bisection and root-cause verification. All changes were reviewed, validated against the codebase and verified with runtime reproduction, and are taken responsibility for by me.

#4 @sabernhardt
31 hours ago

  • Milestone changed from Awaiting Review to 7.0.1

Further history:

Note: See TracTickets for help on using tickets.