From 9b5828a4a059bcdd7a73219dcad0ed417dda478f Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Tue, 2 Jun 2026 12:28:31 -0300 Subject: [PATCH] Admin UI: ship shared WPDS design-tokens stylesheet on Jetpack admin pages Register a single token-only stylesheet sourced from @wordpress/theme's design-tokens.css and enqueue it on every Jetpack admin page, so var(--wpds-*) values resolve at runtime instead of falling back to hand-written hex on the legacy _inc Dashboard, Settings, and Debugger pages. admin-ui owns and registers the handle (enqueued on its modernized dashboards); the Jetpack plugin enqueues the same handle on the is_jetpack_admin_page() gate to cover the wrap_ui pages that aren't registered through Admin_Menu. The handle is registered once and deduped, so it's a single source on both chokepoints. --- pnpm-lock.yaml | 9 ++ .../add-wpds-design-tokens-stylesheet | 4 + projects/packages/admin-ui/package.json | 3 + .../admin-ui/src/class-admin-menu.php | 87 +++++++++++++++++++ .../packages/admin-ui/src/design-tokens.css | 13 +++ projects/packages/admin-ui/webpack.config.js | 3 + .../changelog/enqueue-wpds-design-tokens | 4 + .../plugins/jetpack/class.jetpack-admin.php | 32 +++++++ 8 files changed, 155 insertions(+) create mode 100644 projects/packages/admin-ui/changelog/add-wpds-design-tokens-stylesheet create mode 100644 projects/packages/admin-ui/src/design-tokens.css create mode 100644 projects/plugins/jetpack/changelog/enqueue-wpds-design-tokens diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8a41c4643e4..52538e776d7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1960,6 +1960,15 @@ importers: '@wordpress/browserslist-config': specifier: 6.46.0 version: 6.46.0 + '@wordpress/theme': + specifier: 0.13.0 + version: 0.13.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) sass-embedded: specifier: 1.97.3 version: 1.97.3 diff --git a/projects/packages/admin-ui/changelog/add-wpds-design-tokens-stylesheet b/projects/packages/admin-ui/changelog/add-wpds-design-tokens-stylesheet new file mode 100644 index 000000000000..1f837fd98fe9 --- /dev/null +++ b/projects/packages/admin-ui/changelog/add-wpds-design-tokens-stylesheet @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Add a shared, token-only WPDS design-tokens stylesheet and enqueue it on Jetpack admin pages so `var(--wpds-*)` values resolve at runtime. diff --git a/projects/packages/admin-ui/package.json b/projects/packages/admin-ui/package.json index 0876fa9cf1d9..3e8741071645 100644 --- a/projects/packages/admin-ui/package.json +++ b/projects/packages/admin-ui/package.json @@ -28,6 +28,9 @@ "@automattic/jetpack-base-styles": "workspace:*", "@automattic/jetpack-webpack-config": "workspace:*", "@wordpress/browserslist-config": "6.46.0", + "@wordpress/theme": "0.13.0", + "react": "18.3.1", + "react-dom": "18.3.1", "sass-embedded": "1.97.3", "sass-loader": "16.0.5", "webpack": "5.105.2", diff --git a/projects/packages/admin-ui/src/class-admin-menu.php b/projects/packages/admin-ui/src/class-admin-menu.php index 3c5b2230c35d..b098f6d13a78 100644 --- a/projects/packages/admin-ui/src/class-admin-menu.php +++ b/projects/packages/admin-ui/src/class-admin-menu.php @@ -35,6 +35,17 @@ class Admin_Menu { */ const UPGRADE_MENU_FALLBACK_URL = 'https://jetpack.com/upgrade/'; + /** + * Handle for the shared, token-only WPDS design-tokens stylesheet. + * + * Registered once and enqueued on every Jetpack admin page so that + * `var(--wpds-*)` values resolve at runtime instead of falling back to + * their hand-written hex defaults. + * + * @var string + */ + const DESIGN_TOKENS_HANDLE = 'jetpack-admin-ui-design-tokens'; + /** * Whether this class has been initialized * @@ -49,6 +60,15 @@ class Admin_Menu { */ private static $menu_items = array(); + /** + * Hook suffixes of the pages registered through this class. + * + * Used to scope the design-tokens stylesheet to Jetpack admin pages. + * + * @var array + */ + private static $page_hooks = array(); + /** * Optional connection manager dependency. * @@ -68,6 +88,7 @@ public static function init() { add_action( 'admin_menu', array( __CLASS__, 'admin_menu_hook_callback' ), 1000 ); // Jetpack uses 998. add_action( 'network_admin_menu', array( __CLASS__, 'admin_menu_hook_callback' ), 1000 ); // Jetpack uses 998. add_action( 'admin_enqueue_scripts', array( __CLASS__, 'add_upgrade_menu_item_styles' ) ); + add_action( 'admin_enqueue_scripts', array( __CLASS__, 'maybe_enqueue_design_tokens' ) ); } } @@ -202,6 +223,9 @@ public static function add_menu( $page_title, $menu_title, $capability, $menu_sl */ $hook = 'jetpack_page_' . $menu_slug; + // Track the page hook so the design-tokens stylesheet can be scoped to it. + self::$page_hooks[] = $hook; + // Hide WordPress core admin notices on this Jetpack page. The load- // action only fires when the matching screen is being rendered, so this // stays scoped to Jetpack pages and reaches every page registered here. @@ -471,6 +495,69 @@ public static function add_upgrade_menu_item_styles() { self::enqueue_upgrade_menu_tracks_script( $asset ); } + /** + * Enqueues the shared, token-only WPDS design-tokens stylesheet. + * + * Single entry point for any consumer that needs WPDS `var(--wpds-*)` values + * to resolve at runtime on a Jetpack admin page. Registers the handle on + * first use (idempotent) and enqueues it; the caller is responsible for + * scoping the call to the right page(s). Since admin-ui is a dependency of + * the Jetpack plugin and the modernized packages, both the plugin's + * legacy/wrap_ui gate and this package's own dashboards call through here, + * so the handle has a single owner and there is no duplicated enqueue logic. + * + * @return void + */ + public static function enqueue_design_tokens() { + self::register_design_tokens_style(); + wp_enqueue_style( self::DESIGN_TOKENS_HANDLE ); + } + + /** + * Registers the shared, token-only WPDS design-tokens stylesheet. + * + * The stylesheet only defines `:root{--wpds-*}` custom properties (no + * component or class styles), giving every Jetpack admin page a single + * runtime source for design tokens. It is safe to call repeatedly: + * wp_register_style() is a no-op once the handle is registered. + * + * @return void + */ + private static function register_design_tokens_style() { + if ( wp_style_is( self::DESIGN_TOKENS_HANDLE, 'registered' ) ) { + return; + } + + $asset_file = dirname( __DIR__ ) . '/build/design-tokens.asset.php'; + $asset = file_exists( $asset_file ) ? require $asset_file : array(); + + wp_register_style( + self::DESIGN_TOKENS_HANDLE, + plugins_url( '../build/design-tokens.css', __FILE__ ), + $asset['dependencies'] ?? array(), + $asset['version'] ?? self::PACKAGE_VERSION + ); + } + + /** + * Enqueues the design tokens on the pages registered through this class. + * + * This is the admin_enqueue_scripts callback for the modernized Jetpack + * dashboards. Scoped to self::$page_hooks so the tokens load wherever a + * modernized dashboard renders, regardless of plan or connection state; the + * actual enqueue is delegated to the reusable enqueue_design_tokens() API. + * + * @param string $hook_suffix The current admin page's hook suffix. + * @return void + */ + public static function maybe_enqueue_design_tokens( $hook_suffix ) { + if ( ! in_array( $hook_suffix, self::$page_hooks, true ) ) { + return; + } + + self::enqueue_design_tokens(); + } + /** * Enqueues Tracks for the upgrade submenu item. * diff --git a/projects/packages/admin-ui/src/design-tokens.css b/projects/packages/admin-ui/src/design-tokens.css new file mode 100644 index 000000000000..516bb7fbce5f --- /dev/null +++ b/projects/packages/admin-ui/src/design-tokens.css @@ -0,0 +1,13 @@ +/** + * Token-only WPDS design-tokens stylesheet. + * + * Re-exports the `:root{--wpds-*}` custom-property definitions from + * @wordpress/theme so they can be enqueued as a standalone WP style handle on + * every Jetpack admin page. The import is resolved and inlined by css-loader at + * build time (a local entry file is used rather than pointing the webpack entry + * straight at the package, which would get externalized to a non-existent + * `wp-theme/design-tokens.css` script handle). + * + * Keep this token-only: do not add component or class selectors here. + */ +@import "@wordpress/theme/design-tokens.css"; diff --git a/projects/packages/admin-ui/webpack.config.js b/projects/packages/admin-ui/webpack.config.js index d9021426baeb..185ccc5fd075 100644 --- a/projects/packages/admin-ui/webpack.config.js +++ b/projects/packages/admin-ui/webpack.config.js @@ -18,6 +18,9 @@ module.exports = { entry: { 'admin-ui-upgrade-menu-tracking': [ './src/admin-ui-upgrade-menu-tracking.js' ], 'admin-ui-upgrade-menu': [ './src/admin-ui-upgrade-menu.scss' ], + // Token-only stylesheet (`:root{--wpds-*}`) shipped from @wordpress/theme so every + // Jetpack admin page has a runtime source for WPDS design tokens. See class-admin-menu.php. + 'design-tokens': [ './src/design-tokens.css' ], }, plugins: [ ...jetpackWebpackConfig.StandardPlugins() ], module: { diff --git a/projects/plugins/jetpack/changelog/enqueue-wpds-design-tokens b/projects/plugins/jetpack/changelog/enqueue-wpds-design-tokens new file mode 100644 index 000000000000..738646cf7489 --- /dev/null +++ b/projects/plugins/jetpack/changelog/enqueue-wpds-design-tokens @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Enqueue the shared WPDS design-tokens stylesheet on Jetpack admin pages so design tokens resolve at runtime on the Dashboard, Settings, and Debugger. diff --git a/projects/plugins/jetpack/class.jetpack-admin.php b/projects/plugins/jetpack/class.jetpack-admin.php index 091ee200447e..6dbd70599bf8 100644 --- a/projects/plugins/jetpack/class.jetpack-admin.php +++ b/projects/plugins/jetpack/class.jetpack-admin.php @@ -115,6 +115,11 @@ function () { add_filter( 'update_footer', array( $this, 'maybe_remove_admin_footer_version' ), 11 ); add_filter( 'admin_body_class', array( $this, 'add_jetpack_admin_body_class' ) ); add_action( 'admin_head', array( $this, 'add_footer_removal_styles' ) ); + + // Make WPDS design tokens resolve at runtime on the legacy/wrap_ui Jetpack + // admin pages (Dashboard, Settings, Debugger) that don't ship their own + // `:root{--wpds-*}` source. Delegates to Admin_Menu's shared enqueue API. + add_action( 'admin_enqueue_scripts', array( $this, 'maybe_enqueue_design_tokens' ) ); } /** @@ -653,6 +658,33 @@ public function add_footer_removal_styles() { echo ''; } + /** + * Enqueues the shared WPDS design-tokens stylesheet on the legacy/wrap_ui pages. + * + * This is the admin_enqueue_scripts callback for the legacy Jetpack admin + * pages. The admin-ui package owns the handle and enqueues it on the + * modernized dashboards it registers; the legacy/wrap_ui pages (Dashboard, + * Settings, Debugger) aren't registered through Admin_Menu, so we cover them + * here via the central is_jetpack_admin_page() gate. The actual enqueue is + * delegated to the reusable Admin_Menu::enqueue_design_tokens() API so there + * is a single owner of the handle and no duplicated register/enqueue logic. + * + * @return void + */ + public function maybe_enqueue_design_tokens() { + if ( ! $this->is_jetpack_admin_page() ) { + return; + } + + // Guard against an older admin-ui being loaded ahead of this one by the + // package autoloader's version-precedence resolution. + if ( ! method_exists( Admin_Menu::class, 'enqueue_design_tokens' ) ) { + return; + } + + Admin_Menu::enqueue_design_tokens(); + } + /** * Remove the admin footer text on Jetpack pages. *