From 2b2671d5f2303399d678c21509159802e90a1ea8 Mon Sep 17 00:00:00 2001 From: Alexia Soare <108459992+Alexia-Soare@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:44:05 +0300 Subject: [PATCH] fix: scope logo palette inline script to avoid global collisions Wrap the toggle script in an IIFE so `html` and friends no longer leak as page globals, and filter the MutationObserver to `data-neve-theme`. Fixes the `html.getAttribute is not a function` error thrown when a third-party script clobbers the global `html`. Fixes #4541 Co-Authored-By: Claude Fable 5 --- header-footer-grid/Core/Components/Logo.php | 15 +++--- tests/js/logo-toggle-script.test.mjs | 53 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 tests/js/logo-toggle-script.test.mjs diff --git a/header-footer-grid/Core/Components/Logo.php b/header-footer-grid/Core/Components/Logo.php index 0132501238..77dfed2a39 100644 --- a/header-footer-grid/Core/Components/Logo.php +++ b/header-footer-grid/Core/Components/Logo.php @@ -248,8 +248,9 @@ public function toggle_script() { $variants_json = wp_json_encode( $variants ); $script = << errors.push(e)); + const dom = new JSDOM( + '', + { runScripts: 'outside-only', virtualConsole } + ); + dom.window.eval(js); + return { window: dom.window, errors }; +} + +const tick = () => new Promise((r) => setTimeout(r, 0)); + +// 1. No page globals leaked. +{ + const { window } = makePage(); + assert.equal(window.html, undefined, 'script leaks global "html"'); + assert.equal(window.setCurrentTheme, undefined, 'script leaks global "setCurrentTheme"'); +} + +// 2. Survives a clobbered window.html + unrelated root attribute change. +{ + const { window, errors } = makePage(); + window.html = 'not-an-element'; + window.document.documentElement.setAttribute('data-test', '1'); + await tick(); + assert.deepEqual(errors, [], `observer threw: ${errors[0]}`); +} + +// 3. Still swaps the logo on data-neve-theme change (even after the clobber). +{ + const { window, errors } = makePage(); + window.html = 'not-an-element'; + window.document.documentElement.setAttribute('data-neve-theme', 'dark'); + await tick(); + assert.deepEqual(errors, [], `observer threw: ${errors[0]}`); + assert.equal(window.document.querySelector('.neve-site-logo').src, 'http://x/dark.png', 'logo did not swap to dark variant'); +} + +console.log('logo-toggle-script: all assertions passed');