From a3eadd6999412ed02e2c2463ef2a017a4795195c Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 14:45:12 +0100 Subject: [PATCH 01/10] feat: enhance InspectorHints to support wrapping for specific content in MageWire Templates --- .../Decorator/InspectorHints.php | 28 +++++++++++++++++-- .../TemplateEngine/Plugin/InspectorHints.php | 21 +++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index c74199e..e3a3e57 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -61,12 +61,33 @@ public function __construct( public function render(BlockInterface $block, $templateFile, array $dictionary = []): string { $result = $this->subject->render($block, $templateFile, $dictionary); + $trimmedResult = trim($result); // Only inject attributes if there's actual HTML content - if (empty(trim($result))) { + if (empty($trimmedResult)) { return $result; } + // Do not wrap if content looks like JSON + if (str_starts_with($trimmedResult, '{') || str_starts_with($trimmedResult, '[')) { + return $result; + } + + // Do not wrap if content is a script tag + if (stripos($trimmedResult, '') === (strlen($trimmedResult) - 9)) { + return $result; + } + + // Do not wrap if content seems to be a Magewire component (to prevent DOM diffing issues) + if (str_contains($result, 'wire:id="')) { + return $result; + } + + // Do not wrap if content seems to be a template for JS templating engines (e.g. Mustache/Hogan) + if (str_contains($result, '{{') && str_contains($result, '}}')) { + return $result; + } + return $this->injectInspectorAttributes($result, $block, $templateFile); } @@ -115,9 +136,10 @@ private function injectInspectorAttributes(string $html, BlockInterface $block, // Escape any comment terminators in JSON to prevent breaking out of comment $jsonMetadata = str_replace('-->', '-->', $jsonMetadata); - // Wrap content with comment markers + // Wrap content with comment markers without creating new lines + // New lines can break JavaScript strings if this block is rendered inside a JS variable $wrappedHtml = sprintf( - "\n%s\n", + "%s", $jsonMetadata, $html, $wrapperId diff --git a/src/Model/TemplateEngine/Plugin/InspectorHints.php b/src/Model/TemplateEngine/Plugin/InspectorHints.php index 31e74cc..01f08ea 100644 --- a/src/Model/TemplateEngine/Plugin/InspectorHints.php +++ b/src/Model/TemplateEngine/Plugin/InspectorHints.php @@ -6,6 +6,7 @@ use Magento\Developer\Helper\Data as DevHelper; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\Request\Http; use Magento\Framework\App\State; use Magento\Framework\View\TemplateEngineFactory; use Magento\Framework\View\TemplateEngineInterface; @@ -32,25 +33,30 @@ class InspectorHints private State $state; + private Http $request; + /** * @param ScopeConfigInterface $scopeConfig * @param StoreManagerInterface $storeManager * @param DevHelper $devHelper * @param InspectorHintsFactory $inspectorHintsFactory * @param State $state + * @param Http $request */ public function __construct( ScopeConfigInterface $scopeConfig, StoreManagerInterface $storeManager, DevHelper $devHelper, InspectorHintsFactory $inspectorHintsFactory, - State $state + State $state, + Http $request ) { $this->scopeConfig = $scopeConfig; $this->storeManager = $storeManager; $this->devHelper = $devHelper; $this->inspectorHintsFactory = $inspectorHintsFactory; $this->state = $state; + $this->request = $request; } /** @@ -70,6 +76,19 @@ public function afterCreate( return $invocationResult; } + // Disable for AJAX/API requests (including Magewire) + if ($this->request->isXmlHttpRequest()) { + return $invocationResult; + } + + // Additional check for Magewire if not sent as XHR or checkout page + $requestUri = $this->request->getRequestUri(); + if ($requestUri) { + if (strpos($requestUri, 'magewire') !== false) { + return $invocationResult; + } + } + // Check if inspector is enabled in configuration $storeCode = $this->storeManager->getStore()->getCode(); if (!$this->scopeConfig->isSetFlag(self::XML_PATH_INSPECTOR_ENABLED, ScopeInterface::SCOPE_STORE, $storeCode)) { From 4c107a231c60f9022c7a41da7390f98ce28b5570 Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 15:10:25 +0100 Subject: [PATCH 02/10] feat: enhance InspectorHints to ignore wrapping for Magewire components --- src/Model/TemplateEngine/Decorator/InspectorHints.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index e3a3e57..a61afcf 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -79,7 +79,10 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = } // Do not wrap if content seems to be a Magewire component (to prevent DOM diffing issues) - if (str_contains($result, 'wire:id="')) { + // Check for common Magewire/Livewire data attributes + if (stripos($result, 'wire:id') !== false || + stripos($result, 'wire:initial-data') !== false || + stripos($result, 'x-data="initMagewire') !== false) { return $result; } From 0a352b3f7dfda775d3de994ed05159d666680eea Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 15:10:43 +0100 Subject: [PATCH 03/10] style: fix formatting in condition for Magewire component detection --- src/Model/TemplateEngine/Decorator/InspectorHints.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index a61afcf..197380b 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -80,7 +80,7 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = // Do not wrap if content seems to be a Magewire component (to prevent DOM diffing issues) // Check for common Magewire/Livewire data attributes - if (stripos($result, 'wire:id') !== false || + if (stripos($result, 'wire:id') !== false || stripos($result, 'wire:initial-data') !== false || stripos($result, 'x-data="initMagewire') !== false) { return $result; From 093983cad905a5a265812cbab1f2006e067a88de Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 15:17:06 +0100 Subject: [PATCH 04/10] feat: enhance InspectorHints to prevent wrapping for script and JSON paths --- src/Model/TemplateEngine/Decorator/InspectorHints.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index 197380b..2dec8a2 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -73,11 +73,16 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = return $result; } - // Do not wrap if content is a script tag - if (stripos($trimmedResult, '') === (strlen($trimmedResult) - 9)) { + // Do not wrap if content is a script tag (start allows attributes or multiple tags) + if (stripos($trimmedResult, ' Date: Tue, 27 Jan 2026 15:26:50 +0100 Subject: [PATCH 05/10] feat: enhance Magewire detection in InspectorHints for diverse requests --- .../TemplateEngine/Plugin/InspectorHints.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Model/TemplateEngine/Plugin/InspectorHints.php b/src/Model/TemplateEngine/Plugin/InspectorHints.php index 01f08ea..b1f6163 100644 --- a/src/Model/TemplateEngine/Plugin/InspectorHints.php +++ b/src/Model/TemplateEngine/Plugin/InspectorHints.php @@ -82,11 +82,18 @@ public function afterCreate( } // Additional check for Magewire if not sent as XHR or checkout page + // Check diverse Request URI and Path Info variations to catch all Magewire output $requestUri = $this->request->getRequestUri(); - if ($requestUri) { - if (strpos($requestUri, 'magewire') !== false) { - return $invocationResult; - } + $pathInfo = $this->request->getPathInfo(); + + if (($requestUri && stripos($requestUri, 'magewire') !== false) || + ($pathInfo && stripos($pathInfo, 'magewire') !== false)) { + return $invocationResult; + } + + // Also check regex for partial matches if simple strings fail + if (preg_match('/magewire|livewire/i', (string)$requestUri)) { + return $invocationResult; } // Check if inspector is enabled in configuration From 91f7f50edb7138a287d30df4b1fb953dfc8fcf3d Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 15:36:43 +0100 Subject: [PATCH 06/10] feat: enhance InspectorHints to better handle Magewire components --- .../TemplateEngine/Decorator/InspectorHints.php | 12 +++++++----- src/Model/TemplateEngine/Plugin/InspectorHints.php | 12 ++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index 2dec8a2..2ed9120 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -83,11 +83,13 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = return $result; } - // Do not wrap if content seems to be a Magewire component (to prevent DOM diffing issues) - // Check for common Magewire/Livewire data attributes - if (stripos($result, 'wire:id') !== false || - stripos($result, 'wire:initial-data') !== false || - stripos($result, 'x-data="initMagewire') !== false) { + // Do not wrap if content seems to be a Magewire/Livewire component (to prevent DOM diffing issues) + // Check for any wire: attributes or Magewire initialization + if (stripos($result, 'wire:') !== false || + stripos($result, 'livewire') !== false || + stripos($result, 'magewire') !== false || + stripos($result, 'x-data="initMagewire') !== false || + stripos($result, '@entangle') !== false) { return $result; } diff --git a/src/Model/TemplateEngine/Plugin/InspectorHints.php b/src/Model/TemplateEngine/Plugin/InspectorHints.php index b1f6163..10f30b7 100644 --- a/src/Model/TemplateEngine/Plugin/InspectorHints.php +++ b/src/Model/TemplateEngine/Plugin/InspectorHints.php @@ -81,18 +81,18 @@ public function afterCreate( return $invocationResult; } - // Additional check for Magewire if not sent as XHR or checkout page - // Check diverse Request URI and Path Info variations to catch all Magewire output + // Disable for Hyva Checkout (Magewire-based) - check both URI and PathInfo $requestUri = $this->request->getRequestUri(); $pathInfo = $this->request->getPathInfo(); - if (($requestUri && stripos($requestUri, 'magewire') !== false) || - ($pathInfo && stripos($pathInfo, 'magewire') !== false)) { + // Block entire /checkout/ route (Hyva Checkout uses Magewire) + if (($requestUri && stripos($requestUri, '/checkout') !== false) || + ($pathInfo && stripos($pathInfo, '/checkout') !== false)) { return $invocationResult; } - // Also check regex for partial matches if simple strings fail - if (preg_match('/magewire|livewire/i', (string)$requestUri)) { + // Block any magewire/livewire endpoints + if (preg_match('/\/(magewire|livewire)\//i', (string)$requestUri)) { return $invocationResult; } From fbd9aa9f9f4f37104754784df7d0b08d97abdff0 Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 15:43:20 +0100 Subject: [PATCH 07/10] feat: block magewire/livewire AJAX endpoints in InspectorHints --- src/Model/TemplateEngine/Plugin/InspectorHints.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Model/TemplateEngine/Plugin/InspectorHints.php b/src/Model/TemplateEngine/Plugin/InspectorHints.php index 10f30b7..6455c67 100644 --- a/src/Model/TemplateEngine/Plugin/InspectorHints.php +++ b/src/Model/TemplateEngine/Plugin/InspectorHints.php @@ -81,18 +81,9 @@ public function afterCreate( return $invocationResult; } - // Disable for Hyva Checkout (Magewire-based) - check both URI and PathInfo + // Block any magewire/livewire AJAX endpoints only $requestUri = $this->request->getRequestUri(); - $pathInfo = $this->request->getPathInfo(); - - // Block entire /checkout/ route (Hyva Checkout uses Magewire) - if (($requestUri && stripos($requestUri, '/checkout') !== false) || - ($pathInfo && stripos($pathInfo, '/checkout') !== false)) { - return $invocationResult; - } - - // Block any magewire/livewire endpoints - if (preg_match('/\/(magewire|livewire)\//i', (string)$requestUri)) { + if ($requestUri && preg_match('/\/(magewire|livewire)\//i', $requestUri)) { return $invocationResult; } From 9d30e3315d8f9a8135fdf444fb7677d62adbc58f Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 15:57:46 +0100 Subject: [PATCH 08/10] feat: enhance InspectorHints to prevent wrapping for JSON and Magewire --- .../TemplateEngine/Decorator/InspectorHints.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index 2ed9120..8ce2a3f 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -68,8 +68,10 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = return $result; } - // Do not wrap if content looks like JSON - if (str_starts_with($trimmedResult, '{') || str_starts_with($trimmedResult, '[')) { + // Do not wrap if content looks like JSON (also check for common JSON patterns) + if (str_starts_with($trimmedResult, '{') || + str_starts_with($trimmedResult, '[') || + (str_starts_with($trimmedResult, '"') && str_contains($trimmedResult, '":{"'))) { return $result; } @@ -78,8 +80,15 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = return $result; } - // Do not wrap if template path suggests partial/JS/JSON - if (strpos($templateFile, '/js/') !== false || strpos($templateFile, '/json/') !== false) { + // Do not wrap if template path suggests partial/JS/JSON or Magewire/Hyva Checkout components + // Only block Hyva Checkout specifically, not all checkout templates + $lowerTemplatePath = strtolower($templateFile); + if (strpos($lowerTemplatePath, '/js/') !== false || + strpos($lowerTemplatePath, '/json/') !== false || + strpos($lowerTemplatePath, '/magewire/') !== false || + strpos($lowerTemplatePath, '/livewire/') !== false || + (strpos($lowerTemplatePath, 'hyva') !== false && strpos($lowerTemplatePath, 'checkout') !== false) || + strpos($lowerTemplatePath, 'component.phtml') !== false) { return $result; } From 1b0d1f472ad9011ddad9ef7f846ba15326968de0 Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 16:06:39 +0100 Subject: [PATCH 09/10] feat: refine wrapping logic for JSON and Magewire components --- .../TemplateEngine/Decorator/InspectorHints.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index 8ce2a3f..d6595d7 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -69,7 +69,7 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = } // Do not wrap if content looks like JSON (also check for common JSON patterns) - if (str_starts_with($trimmedResult, '{') || + if (str_starts_with($trimmedResult, '{') || str_starts_with($trimmedResult, '[') || (str_starts_with($trimmedResult, '"') && str_contains($trimmedResult, '":{"'))) { return $result; @@ -80,15 +80,13 @@ public function render(BlockInterface $block, $templateFile, array $dictionary = return $result; } - // Do not wrap if template path suggests partial/JS/JSON or Magewire/Hyva Checkout components - // Only block Hyva Checkout specifically, not all checkout templates + // Do not wrap if template path suggests partial/JS/JSON or direct Magewire component files + // Only block very specific risky paths, rely on content checks for Magewire detection $lowerTemplatePath = strtolower($templateFile); - if (strpos($lowerTemplatePath, '/js/') !== false || + if (strpos($lowerTemplatePath, '/js/') !== false || strpos($lowerTemplatePath, '/json/') !== false || strpos($lowerTemplatePath, '/magewire/') !== false || - strpos($lowerTemplatePath, '/livewire/') !== false || - (strpos($lowerTemplatePath, 'hyva') !== false && strpos($lowerTemplatePath, 'checkout') !== false) || - strpos($lowerTemplatePath, 'component.phtml') !== false) { + strpos($lowerTemplatePath, '/livewire/') !== false) { return $result; } From 7f5bcc0a0d26f6ae99fa2aafb1e5db1f699ee147 Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Tue, 27 Jan 2026 16:10:26 +0100 Subject: [PATCH 10/10] feat: update cursor behavior for inspectable and non-inspectable elements --- src/view/frontend/web/js/inspector.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/view/frontend/web/js/inspector.js b/src/view/frontend/web/js/inspector.js index 60ea1be..a60fe92 100644 --- a/src/view/frontend/web/js/inspector.js +++ b/src/view/frontend/web/js/inspector.js @@ -399,7 +399,7 @@ document.addEventListener('alpine:init', () => { this.isPickerActive = true; document.addEventListener('mousemove', this.mouseMoveHandler); document.addEventListener('click', this.clickHandler, false); // Don't use capture - document.body.style.cursor = 'crosshair'; + // Cursor is set dynamically in handleMouseMove based on inspectability }, /** @@ -443,16 +443,26 @@ document.addEventListener('alpine:init', () => { // Don't update if mouse is over the floating button if (this.floatingButton && this.floatingButton.contains(e.target)) { + document.body.style.cursor = 'crosshair'; return; } // Don't update if mouse is over the info badge if (this.infoBadge && this.infoBadge.contains(e.target)) { + document.body.style.cursor = 'crosshair'; return; } const element = this.findInspectableElement(e.target); + // Update cursor based on inspectability + if (element) { + document.body.style.cursor = 'crosshair'; + } else if (e.target && !e.target.classList.contains('mageforge-inspector') && !e.target.closest('.mageforge-inspector')) { + // Show"not-allowed" cursor for non-inspectable elements (protected Magewire components) + document.body.style.cursor = 'not-allowed'; + } + // Clear any existing hover timeout if (this.hoverTimeout) { clearTimeout(this.hoverTimeout);