diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd08d9459f7..041a666d724 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3616,9 +3616,9 @@ importers: projects/packages/podcast: dependencies: - '@wordpress/components': - specifier: 32.6.0 - version: 32.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@automattic/jetpack-components': + specifier: workspace:* + version: link:../../js-packages/components '@wordpress/element': specifier: 6.44.0 version: 6.44.0 @@ -3629,6 +3629,9 @@ importers: specifier: 0.11.0 version: 0.11.0(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) devDependencies: + '@automattic/jetpack-base-styles': + specifier: workspace:* + version: link:../../js-packages/base-styles '@automattic/jetpack-wp-build-polyfills': specifier: workspace:* version: link:../wp-build-polyfills @@ -3641,12 +3644,18 @@ importers: '@types/react': specifier: 18.3.28 version: 18.3.28 + '@wordpress/base-styles': + specifier: 6.20.0 + version: 6.20.0 '@wordpress/browserslist-config': specifier: 6.44.0 version: 6.44.0 '@wordpress/build': specifier: 0.13.0 - version: 0.13.0(@babel/core@7.29.0)(browserslist@4.28.2) + version: 0.13.0(@babel/core@7.29.0)(@wordpress/theme@0.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(browserslist@4.28.2) + '@wordpress/theme': + specifier: 0.11.0 + version: 0.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) browserslist: specifier: ^4.24.0 version: 4.28.2 @@ -24143,6 +24152,30 @@ snapshots: - browserslist - supports-color + '@wordpress/build@0.13.0(@babel/core@7.29.0)(@wordpress/theme@0.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(browserslist@4.28.2)': + dependencies: + '@emotion/babel-plugin': 11.13.5 + autoprefixer: 10.4.27(postcss@8.5.10) + browserslist-to-esbuild: 2.1.1(browserslist@4.28.2) + change-case: 4.1.2 + chokidar: 4.0.3 + cssnano: 7.1.4(postcss@8.5.10) + esbuild: 0.27.4 + esbuild-plugin-babel: 0.2.3(@babel/core@7.29.0) + esbuild-sass-plugin: 3.3.1(esbuild@0.27.4)(sass-embedded@1.97.3) + fast-glob: 3.3.3 + moment-timezone: 0.5.48 + postcss: 8.5.10 + postcss-modules: 6.0.1(postcss@8.5.10) + rtlcss: 4.3.0 + sass-embedded: 1.97.3 + optionalDependencies: + '@wordpress/theme': 0.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + transitivePeerDependencies: + - '@babel/core' + - browserslist + - supports-color + '@wordpress/build@0.13.0(@babel/core@7.29.0)(browserslist@4.28.2)': dependencies: '@emotion/babel-plugin': 11.13.5 diff --git a/projects/packages/jetpack-mu-wpcom/changelog/arcangelini-podcast-make-it-better b/projects/packages/jetpack-mu-wpcom/changelog/arcangelini-podcast-make-it-better new file mode 100644 index 00000000000..c8022d7ce2c --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/arcangelini-podcast-make-it-better @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Internal: rename the new Podcast slug to 'podcast' in the Jetpack submenu reorder list; legacy 'podcasting' entry untouched. + + diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-menu/wpcom-admin-menu.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-menu/wpcom-admin-menu.php index 38aad8eab7d..3d710a04c0f 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-menu/wpcom-admin-menu.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-menu/wpcom-admin-menu.php @@ -466,7 +466,7 @@ function () { 'search', 'subscribers', 'newsletter', - 'jetpack-podcast', + 'podcast', 'podcasting', 'traffic', 'jetpack#/settings', diff --git a/projects/packages/podcast/changelog/arcangelini-podcast-make-it-better b/projects/packages/podcast/changelog/arcangelini-podcast-make-it-better new file mode 100644 index 00000000000..d23e3f2f3e5 --- /dev/null +++ b/projects/packages/podcast/changelog/arcangelini-podcast-make-it-better @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Slim down wp-build wiring to the Backup pattern: drop bridge_wp_build_enqueue and fix_boot_import_map_ordering, alias $screen->id via current_screen instead. diff --git a/projects/packages/podcast/package.json b/projects/packages/podcast/package.json index f3eeedc12ad..1beb9bfdac8 100644 --- a/projects/packages/podcast/package.json +++ b/projects/packages/podcast/package.json @@ -27,18 +27,21 @@ "extends @wordpress/browserslist-config" ], "dependencies": { - "@wordpress/components": "32.6.0", + "@automattic/jetpack-components": "workspace:*", "@wordpress/element": "6.44.0", "@wordpress/i18n": "6.17.0", "@wordpress/ui": "0.11.0" }, "devDependencies": { + "@automattic/jetpack-base-styles": "workspace:*", "@automattic/jetpack-wp-build-polyfills": "workspace:*", "@babel/core": "7.29.0", "@babel/runtime": "7.29.2", "@types/react": "18.3.28", + "@wordpress/base-styles": "6.20.0", "@wordpress/browserslist-config": "6.44.0", "@wordpress/build": "0.13.0", + "@wordpress/theme": "0.11.0", "browserslist": "^4.24.0" }, "optionalDependencies": { diff --git a/projects/packages/podcast/routes/dashboard/package.json b/projects/packages/podcast/routes/dashboard/package.json index f130ca6154a..54f202cc4e7 100644 --- a/projects/packages/podcast/routes/dashboard/package.json +++ b/projects/packages/podcast/routes/dashboard/package.json @@ -3,8 +3,8 @@ "version": "1.0.0", "private": true, "dependencies": { + "@automattic/jetpack-components": "workspace:*", "@types/react": "18.3.28", - "@wordpress/components": "32.6.0", "@wordpress/element": "6.44.0", "@wordpress/i18n": "6.17.0", "@wordpress/ui": "0.11.0" diff --git a/projects/packages/podcast/routes/dashboard/route.scss b/projects/packages/podcast/routes/dashboard/route.scss new file mode 100644 index 00000000000..668d953f4d6 --- /dev/null +++ b/projects/packages/podcast/routes/dashboard/route.scss @@ -0,0 +1,6 @@ +@use "@automattic/jetpack-base-styles/admin-page-layout" as *; + +body.jetpack_page_jetpack-podcast { + + @include jetpack-admin-page-layout; +} diff --git a/projects/packages/podcast/routes/dashboard/stage.tsx b/projects/packages/podcast/routes/dashboard/stage.tsx index 92f5ceebfb9..f87f7df247a 100644 --- a/projects/packages/podcast/routes/dashboard/stage.tsx +++ b/projects/packages/podcast/routes/dashboard/stage.tsx @@ -1,14 +1,8 @@ -/** - * Podcast dashboard stage: page chrome + tab navigation. - * - * Placeholder scaffolding only — each tab panel renders a stub. PR 4 in the - * untangle train wires the full AdminPage + jetpack-components integration - * along with the real tab contents. - */ - +import AdminPage from '@automattic/jetpack-components/admin-page'; import { useState, useCallback } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { Tabs } from '@wordpress/ui'; +import './route.scss'; const TAB_VALUES = [ 'settings', 'episodes', 'distribution', 'stats' ] as const; type TabName = ( typeof TAB_VALUES )[ number ]; @@ -26,19 +20,25 @@ const Stage = () => { }, [] ); return ( -
-

Podcast

-

- { __( 'Publish a podcast and reach your fans, anywhere they listen.', 'jetpack-podcast' ) } -

- - - - { __( 'Settings', 'jetpack-podcast' ) } - { __( 'Episodes', 'jetpack-podcast' ) } - { __( 'Distribution', 'jetpack-podcast' ) } - { __( 'Stats', 'jetpack-podcast' ) } - + + + + { __( 'Settings', 'jetpack-podcast' ) } + { __( 'Episodes', 'jetpack-podcast' ) } + { __( 'Distribution', 'jetpack-podcast' ) } + { __( 'Stats', 'jetpack-podcast' ) } + +
+ } + >

{ __( 'Settings — placeholder.', 'jetpack-podcast' ) }

@@ -51,8 +51,8 @@ const Stage = () => {

{ __( 'Stats — placeholder.', 'jetpack-podcast' ) }

- - + + ); }; diff --git a/projects/packages/podcast/src/class-admin-page.php b/projects/packages/podcast/src/class-admin-page.php index 4aa92d26859..d924b2f8f19 100644 --- a/projects/packages/podcast/src/class-admin-page.php +++ b/projects/packages/podcast/src/class-admin-page.php @@ -14,53 +14,27 @@ * `jetpack_podcast_untangle` filter is enabled. Until that filter flips, every * entry point here is a no-op so the legacy podcasting experience keeps * running unchanged. - * - * Menu registration is owned by `wpcom-admin-menu.php` (in the - * `jetpack-mu-wpcom` package), which calls `add_wp_admin_submenu()` at - * `admin_menu` priority 999999 — late enough that the Jetpack parent menu - * already exists. wpcom-admin-menu runs on both Simple and Atomic, so a single - * registration path covers both. Standalone Jetpack is excluded by the host - * gate in `Podcast::init()`. - * - * The wp-build chassis is loaded inline from `init()` and routed onto our - * user-facing slug via `bridge_wp_build_enqueue()` — mirroring - * `Automattic\Jetpack\Scan_Page\Jetpack_Scan`. */ class Admin_Page { - /** - * URL-facing menu slug. - * - * @var string - */ const ADMIN_PAGE_SLUG = 'jetpack-podcast'; /** - * Internal slug emitted by `@wordpress/build` (`wpPlugin.pages[0]` - * plus the `-wp-admin` suffix the build template appends). Used to - * find the auto-generated render / enqueue functions. - * - * @var string + * Slug emitted by `@wordpress/build`. wp-build's auto-generated enqueue + * callback only fires when `$screen->id` matches this value, so we alias + * the screen id via `current_screen` without changing the user-facing URL. */ - const WP_BUILD_SLUG = 'jetpack-podcast-dashboard-wp-admin'; + const WP_BUILD_SLUG = 'jetpack-podcast-dashboard'; /** - * Whether the class has already wired its admin hooks. + * Whether `init()` has already wired its hooks. * * @var bool */ private static $initialized = false; /** - * Wire the admin hooks. Called from `Podcast::init()` once the - * `jetpack_podcast_untangle` filter and host gates have been satisfied. - * - * Menu registration itself is handled by `wpcom-admin-menu.php` calling - * `add_wp_admin_submenu()` at `admin_menu` priority 999999. Here we set - * up the wp-build chassis at plugins_loaded time so: - * - `WP_Build_Polyfills::register()` registers BEFORE `wp_default_scripts` - * fires (otherwise `@wordpress/boot` never lands in the import map). - * - The wp-build render function is defined before the menu callback runs. + * Wire admin hooks. Idempotent. */ public static function init() { if ( self::$initialized ) { @@ -68,23 +42,25 @@ public static function init() { } self::$initialized = true; - self::load_wp_build(); - self::bridge_wp_build_enqueue(); - self::fix_boot_import_map_ordering(); + add_action( 'admin_menu', array( __CLASS__, 'maybe_load_wp_build' ), 1 ); } /** * Register the Podcast submenu under Jetpack on Simple and Atomic. * * Called from `wpcom-admin-menu.php` at priority 999999 once the Jetpack - * parent menu exists. Bails when the untangle filter is off so the legacy - * "Podcasting" Calypso link in `wpcom-admin-menu.php` keeps rendering. + * parent menu exists. */ public static function add_wp_admin_submenu() { if ( ! self::is_enabled() ) { return; } + $wp_build_render = 'jetpack_podcast_jetpack_podcast_dashboard_wp_admin_render_page'; + $callback = function_exists( $wp_build_render ) + ? $wp_build_render + : array( __CLASS__, 'render' ); + $page_suffix = add_submenu_page( 'jetpack', /** "Podcast" is a product name, do not translate. */ @@ -92,7 +68,7 @@ public static function add_wp_admin_submenu() { 'Podcast', 'manage_options', self::ADMIN_PAGE_SLUG, - self::get_render_callback() + $callback ); if ( $page_suffix ) { @@ -102,134 +78,60 @@ public static function add_wp_admin_submenu() { /** * Wire admin-init actions once we know the Podcast page is loading. - * - * Subsequent PRs in the untangle train layer script-data + Tracks here. - * The wp-build dashboard manages its own enqueue pipeline (bridged via - * `bridge_wp_build_enqueue()`). */ public static function admin_init() { // Intentionally empty for now. } /** - * Bridge wp-build's auto-generated enqueue function — which checks for - * `?page=jetpack-podcast-dashboard-wp-admin` — to our user-facing slug - * `?page=jetpack-podcast`. Hooked at priority 9 so the wp-build copy - * (registered at priority 10) sees the original `$_GET['page']` and skips - * its own enqueue. - * - * Mirrors `Automattic\Jetpack\Scan_Page\Jetpack_Scan::bridge_wp_build_enqueue`. + * Hooked at admin_menu priority 1 so polyfills register before + * `wp_default_scripts` fires and the wp-build render function is defined + * before `add_wp_admin_submenu()` runs at priority 999999. */ - private static function bridge_wp_build_enqueue() { - add_action( - 'admin_enqueue_scripts', - static function ( $hook_suffix ) { - // phpcs:ignore WordPress.Security.NonceVerification.Recommended - if ( ! isset( $_GET['page'] ) || self::ADMIN_PAGE_SLUG !== $_GET['page'] ) { - return; - } - - $enqueue_fn = 'jetpack_podcast_jetpack_podcast_dashboard_wp_admin_enqueue_scripts'; - if ( ! function_exists( $enqueue_fn ) ) { - return; - } + public static function maybe_load_wp_build() { + if ( ! self::is_enabled() || ! self::is_podcast_admin_request() ) { + return; + } - // phpcs:disable WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized - $original = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : null; - $_GET['page'] = self::WP_BUILD_SLUG; - // @phan-suppress-next-line PhanUndeclaredFunctionInCallable -- Function is generated by @wordpress/build into build/pages/jetpack-podcast-dashboard/page-wp-admin.php, which is outside Phan's analysis scope. The function_exists() guard above protects the call at runtime. - call_user_func( $enqueue_fn, $hook_suffix ); - if ( null === $original ) { - unset( $_GET['page'] ); - } else { - $_GET['page'] = $original; - } - // phpcs:enable WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized - }, - 9 - ); + self::load_wp_build(); + add_action( 'current_screen', array( __CLASS__, 'alias_screen_id_for_wp_build' ) ); } /** - * Fix import map ordering for the wp-build boot script. - * - * In wp-admin, `_wp_footer_scripts` (classic scripts) and - * `print_import_map` both hook into `admin_print_footer_scripts` at - * priority 10, but `_wp_footer_scripts` is registered first. This causes - * the inline `import("@wordpress/boot")` to execute before the import - * map exists. - * - * This fix moves the `import()` call from the classic inline script to a - * `