Repository navigation
Debug Helper: Add a Package Provenance module - #50995
Conversation
admin-bar badge + floating panel showing which runtime serves each WordPress package (core, Gutenberg plugin, wp-build polyfills, app)
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! Debug Helper plugin: No scheduled milestone found for this plugin. If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack. |
dim rows by text color instead of opacity so provider badges stay legible; brighten the badge palette one step
paint after window load and recompute on open (footer scripts print after admin_footer, so early DOM checks under-reported loaded state); classify /wp-admin/ and mu-plugins sources; list all registered module ids, not only @-prefixed; escape names and versions; admin-only badge; precise dimmed semantics per type
each ver opens the exact URL the runtime serves in a new tab; rows without a version get a glyph link
dhasilva
left a comment
There was a problem hiding this comment.
Nice module — self-contained, opt-in, and it follows the existing debug-helper conventions closely (same hook pair and priorities as WPCOM_API_Request_Tracker_Module, @phan-constructor-used-for-side-effects, kebab-case file/class naming, logical CSS properties throughout). phpcs, parallel-lint, and phan on projects/plugins/debug-helper are all clean for the new file, and .phan/baseline.php is untouched. Changelog is present and valid.
No blockers. Three accuracy findings, all sharing one root cause: the panel re-derives what WordPress already resolved at print time, rather than reusing the resolved value.
1. [suggestion] Version column is blank exactly where WP substitutes the WP version
(string) $dependency->ver collapses false and null to '', but core treats them oppositely (wp-includes/class-wp-scripts.php:299-303):
if ( null === $obj->ver ) { $ver = ''; } // no ?ver= at all
else { $ver = $obj->ver ? $obj->ver : $this->default_version; } // false → WP versionCore registers a fair number of wp-* handles with false — wp-util, wp-backbone, wp-sanitize, wp-lists, wp-pointer, wp-api-request, wp-color-picker (script-loader.php:784, 841, 853, 875, 1062, 1073, 1496). Those rows render an empty version cell and a link with no ver param, while the served file is …?ver=<wp_version>.
Script modules have the identical rule in WP_Script_Modules::get_src() (class-wp-script-modules.php:790-794), so
'ver' => null === $dependency->ver
? ''
: (string) ( $dependency->ver ? $dependency->ver : wp_scripts()->default_version ),2. [suggestion] The version link bypasses WP_Scripts::$base_url and the script_loader_src filter
Core registers packages with root-relative srcs (/wp-includes/js/dist/…) and WP_Scripts::do_item() prepends $this->base_url (= site_url()) at print time (class-wp-scripts.php:411-413), then runs the result through script_loader_src. The panel links to the unresolved path, so on a subdirectory install the link 404s, and on any site using script_loader_src (CDN rewrites, cache busting) both the link and the provider() classification describe a URL the browser never fetched.
Cheapest fix reuses work compute() already does — when the printed tag exists, read its real URL:
const el = document.getElementById( handle + '-js' );
const url = el ? el.src : ( info.src ? info.src + … : '' ); // reconstruct only as fallback3. [suggestion] Concatenated core scripts render dimmed even though they loaded
In wp-admin without SCRIPT_DEBUG, $concatenate_scripts defaults to true, and any handle under /wp-includes/js/ or /wp-admin/js/ with no textdomain, no inline before/after, and no delayed strategy is folded into a single load-scripts.php?load[]=… tag with no per-handle id (class-wp-scripts.php:365-390). Core packages that don't depend on wp-i18n (wp-hooks, wp-dom-ready, wp-priority-queue, …) take that path — and since core registers packages in the footer, the info.printed fallback is also false at admin_footer time. Net effect: loaded packages show dimmed.
tools/docker/bin/run.sh:45 sets SCRIPT_DEBUG true, which masks this in the monorepo Docker env; a stock install or a JN site will show it.
Either fix works:
- Move
render()toadmin_print_footer_scriptsat a late priority (after_wp_footer_scripts,wp-admin/includes/admin-filters.php:61).wp_scripts()->doneis then authoritative and the import map is already in the DOM, which demotes the client-side probing to a pure fallback — and it also gives you finding 2 for free if you additionally record real URLs via a latescript_loader_srcfilter. - Or parse
load[]=handles out of anyload-scripts.phptag insidecompute().
Minor notes (non-blocking)
- The
Fixes #line at the top of the description is left dangling with no issue number — worth filling or dropping. - On fullscreen block-editor screens the admin bar is visually hidden, so the badge exists in the DOM but can't be clicked and the panel is unreachable — on the screen with the richest
wp-*surface. Not a regression, just a gap worth knowing about. role="dialog"with no focus management, Escape-to-close, or close button. Fine for a dev tool; flagging only for completeness.
Checked: PR description, changelog, conventions, bugs, security (JSON island escaping and the esc/escAttr helpers look correct), error handling, backward compat, cross-package version skew (none — debug-helper has "require": {} and the module references no \Automattic\Jetpack\* symbols), phan suppressions, feature gating, a11y/RTL, PHP/WP compat.
Generated by Claude.
…package-provenance
fixes blank versions, unresolved urls and dimmed concatenated rows
|
All three fixed. Thanks for the detail, especially the concatenation one. I would not have caught it in Docker. 1. Blank versions. New 2. Unresolved URLs. A 3. Dimmed concatenated rows. Verified on a Jurassic Ninja site with I also added a help screen to the panel: registration order, the force-replace rules, and the path-to-badge table. That logic only lived in the code. Dropped the dangling |
chihsuan
left a comment
There was a problem hiding this comment.
Tested this locally and it works exactly as described!
Lovely little plugin addition. LGTM 🚀
Proposed changes
wp-*classic script handle and@-prefixed script module on the current screen.admin_print_footer_scripts, sowp_scripts()->doneis complete and ascript_loader_srcfilter has already recorded the URL each handle was served from. That is what the provider badge classifies, so a CDN or cache-busting rewrite shows up instead of staying hidden, and handles core folds intoload-scripts.phpare still reported as loaded even though they print no per-handle tag. Script modules come from the browser's live import map.Related product discussion/links
@wordpress/*monorepo #50509, where which runtime provideswp-theme/wp-private-apis/wp-rich-text/@wordpress/widget-primitiveson each WordPress + Gutenberg combination decides whether the dashboards work. This module replaces a console snippet with a one-click view.Does this pull request change what data or activity we track or use?
No. The module renders locally on the admin screen and sends nothing anywhere.
Testing instructions
wp plugin activate debug-helperin the Docker environment).wp option update jetpack_debug_helper_active_modules --format=json '["package-provenance"]'.📦 WP <version> · GB <version|off>badge appears on the right side of the admin bar.themeorpolyfill).wp-theme,wp-private-apis,wp-rich-text) and the script modules should appear with a POLYFILL or CORE provider depending on your WordPress version, and with GUTENBERG when the Gutenberg plugin is active.SCRIPT_DEBUGisfalse, so the Docker environment does not cover it (tools/docker/bin/run.shsets it totrue). On a stock install or a Jurassic Ninja site, filter forwp-hooksorwp-dom-ready: core folds them intoload-scripts.phpwith no per-handle tag, and they must render normally rather than dimmed. On the same site, handles core registers withfalseas the version (wp-util,wp-backbone,wp-api-request,wp-theme-plugin-editor) must show the WordPress version rather than an empty cell.