From 4a1a98a750fd49158ce8e43f29c097c9897486f1 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 01:26:45 -0300 Subject: [PATCH 01/42] Add AdminHeader component to jetpack-components for unified admin page headers. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-header/index.tsx | 41 ++++++++++++++ .../components/admin-header/style.module.scss | 53 +++++++++++++++++++ .../components/admin-header/types.ts | 33 ++++++++++++ projects/js-packages/components/index.ts | 1 + 4 files changed, 128 insertions(+) create mode 100644 projects/js-packages/components/components/admin-header/index.tsx create mode 100644 projects/js-packages/components/components/admin-header/style.module.scss create mode 100644 projects/js-packages/components/components/admin-header/types.ts diff --git a/projects/js-packages/components/components/admin-header/index.tsx b/projects/js-packages/components/components/admin-header/index.tsx new file mode 100644 index 000000000000..b578c433da13 --- /dev/null +++ b/projects/js-packages/components/components/admin-header/index.tsx @@ -0,0 +1,41 @@ +import clsx from 'clsx'; +import JetpackLogo from '../jetpack-logo/index.tsx'; +import styles from './style.module.scss'; +import type { AdminHeaderProps } from './types.ts'; +import type { FC } from 'react'; + +/** + * Unified admin page header component. + * + * Renders a sticky header with logo, product title, optional tagline, + * actions, and tabs. Follows the `@wordpress/admin-ui` Page header pattern. + * + * @param {AdminHeaderProps} props - Component properties. + * @return {ReactNode} AdminHeader component. + */ +const AdminHeader: FC< AdminHeaderProps > = ( { + logo, + title, + tagline, + actions, + tabs, + className, +} ) => { + return ( +
+
+
+ + { logo || } + +

{ title }

+
+ { actions &&
{ actions }
} +
+ { tagline &&

{ tagline }

} + { tabs } +
+ ); +}; + +export default AdminHeader; diff --git a/projects/js-packages/components/components/admin-header/style.module.scss b/projects/js-packages/components/components/admin-header/style.module.scss new file mode 100644 index 000000000000..6cff7b2b9bf7 --- /dev/null +++ b/projects/js-packages/components/components/admin-header/style.module.scss @@ -0,0 +1,53 @@ +.admin-header { + padding: 16px 24px; + border-bottom: 1px solid #e0e0e0; + background: #fff; + position: sticky; + top: 0; + z-index: 1; +} + +.admin-header__title-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.admin-header__title { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; // allow truncation +} + +.admin-header__logo { + display: flex; + align-items: center; + flex-shrink: 0; +} + +.admin-header__product-name { + font-size: 15px; + font-weight: 500; + line-height: 32px; + margin: 0; + padding: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.admin-header__tagline { + margin: 4px 0 0; + font-size: 13px; + line-height: 1.4; + color: #757575; +} + +.admin-header__actions { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} diff --git a/projects/js-packages/components/components/admin-header/types.ts b/projects/js-packages/components/components/admin-header/types.ts new file mode 100644 index 000000000000..8fe76df341f2 --- /dev/null +++ b/projects/js-packages/components/components/admin-header/types.ts @@ -0,0 +1,33 @@ +import type { ReactNode } from 'react'; + +export type AdminHeaderProps = { + /** + * Custom logo element. Defaults to JetpackLogo icon (bolt only). + */ + logo?: ReactNode; + + /** + * Product title displayed next to the logo. + */ + title: string; + + /** + * Optional tagline displayed below the title row. + */ + tagline?: string; + + /** + * Optional action elements (buttons, links) displayed on the right side of the header. + */ + actions?: ReactNode; + + /** + * Optional tab navigation displayed below the title/tagline. + */ + tabs?: ReactNode; + + /** + * Additional CSS class name. + */ + className?: string; +}; diff --git a/projects/js-packages/components/index.ts b/projects/js-packages/components/index.ts index 5b2df114305e..9c9946a12b4e 100644 --- a/projects/js-packages/components/index.ts +++ b/projects/js-packages/components/index.ts @@ -34,6 +34,7 @@ export { default as NumberSlider } from './components/number-slider/index.tsx'; export { default as AdminSection } from './components/admin-section/basic/index.tsx'; export { default as AdminSectionHero } from './components/admin-section/hero/index.tsx'; export { default as AdminPage } from './components/admin-page/index.tsx'; +export { default as AdminHeader } from './components/admin-header/index.tsx'; export { default as DecorativeCard } from './components/decorative-card/index.tsx'; export { default as Col } from './components/layout/col/index.tsx'; export { default as Testimonials } from './components/testimonials/index.tsx'; From e3b4a14ce977bfdc412d479809b83c008bd940ac Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 01:26:54 -0300 Subject: [PATCH 02/42] Add unified header props to AdminPage with backward-compatible legacy fallback. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-page/index.tsx | 54 ++++++++++++------- .../components/components/admin-page/types.ts | 29 +++++++++- 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/projects/js-packages/components/components/admin-page/index.tsx b/projects/js-packages/components/components/admin-page/index.tsx index c543af519dc6..5745de92ec18 100644 --- a/projects/js-packages/components/components/admin-page/index.tsx +++ b/projects/js-packages/components/components/admin-page/index.tsx @@ -2,6 +2,7 @@ import restApi from '@automattic/jetpack-api'; import { __, sprintf } from '@wordpress/i18n'; import clsx from 'clsx'; import { useEffect, useCallback } from 'react'; +import AdminHeader from '../admin-header/index.tsx'; import JetpackFooter from '../jetpack-footer/index.tsx'; import JetpackLogo from '../jetpack-logo/index.tsx'; import Col from '../layout/col/index.tsx'; @@ -32,6 +33,11 @@ const AdminPage: FC< AdminPageProps > = ( { apiNonce = '', optionalMenuItems, header, + title, + tagline, + logo, + actions, + tabs, } ) => { useEffect( () => { restApi.setApiRoot( apiRoot ); @@ -62,25 +68,35 @@ const AdminPage: FC< AdminPageProps > = ( { return (
- { showHeader && ( - - - { header ? header : } - { sandboxedDomain && ( - - API Sandboxed - - ) } - - + { showHeader && title ? ( + + ) : ( + showHeader && ( + + + { header ? header : } + { sandboxedDomain && ( + + API Sandboxed + + ) } + + + ) ) } { children } diff --git a/projects/js-packages/components/components/admin-page/types.ts b/projects/js-packages/components/components/admin-page/types.ts index 7e9e6ad59bf3..9d7219dec823 100644 --- a/projects/js-packages/components/components/admin-page/types.ts +++ b/projects/js-packages/components/components/admin-page/types.ts @@ -18,10 +18,37 @@ export type AdminPageProps = { showHeader?: boolean; /** - * Custom header. Optional + * Custom header. Optional. + * @deprecated Use `title` and `tagline` props instead for the unified header. */ header?: ReactNode; + /** + * Product title displayed in the unified header (e.g. "Social", "Backup"). + * When provided, renders the new AdminHeader instead of the legacy header slot. + */ + title?: string; + + /** + * Optional tagline displayed below the title in the unified header. + */ + tagline?: string; + + /** + * Custom logo element for the unified header. Defaults to JetpackLogo icon. + */ + logo?: ReactNode; + + /** + * Action elements displayed on the right side of the unified header. + */ + actions?: ReactNode; + + /** + * Tab navigation displayed below the title/tagline in the unified header. + */ + tabs?: ReactNode; + /** * Whether or not to display the Footer */ From 422ea270854b2efc17db5af1cc8b6d9a89557d0b Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 01:27:02 -0300 Subject: [PATCH 03/42] Migrate publicize admin page to use unified AdminHeader via title prop. Co-Authored-By: Claude Opus 4.6 --- .../_inc/components/admin-page/index.tsx | 26 +++++++-- .../admin-page/test/page-header.test.jsx | 58 ------------------- 2 files changed, 22 insertions(+), 62 deletions(-) delete mode 100644 projects/packages/publicize/_inc/components/admin-page/test/page-header.test.jsx diff --git a/projects/packages/publicize/_inc/components/admin-page/index.tsx b/projects/packages/publicize/_inc/components/admin-page/index.tsx index c10b78feb15b..ca15dae8a312 100644 --- a/projects/packages/publicize/_inc/components/admin-page/index.tsx +++ b/projects/packages/publicize/_inc/components/admin-page/index.tsx @@ -8,6 +8,7 @@ import { } from '@automattic/jetpack-components'; import { useConnection } from '@automattic/jetpack-connection'; import { + getMyJetpackUrl, isJetpackSelfHostedSite, isSimpleSite, siteHasFeature, @@ -15,13 +16,13 @@ import { } from '@automattic/jetpack-script-data'; import { shouldUseInternalLinks } from '@automattic/jetpack-shared-extension-utils'; import { useSelect } from '@wordpress/data'; -import { useState, useCallback } from '@wordpress/element'; +import { createInterpolateElement, useState, useCallback } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; import { store as socialStore } from '../../social-store'; import { features, getSocialScriptData, hasSocialPaidFeatures } from '../../utils'; import ConnectionScreen from './connection-screen'; import Header from './header'; import InfoSection from './info-section'; -import AdminPageHeader from './page-header'; import './styles.module.scss'; import PricingPage from './pricing-page'; import SupportSection from './support-section'; @@ -65,7 +66,8 @@ export const SocialAdminPage = () => { return ( @@ -78,10 +80,26 @@ export const SocialAdminPage = () => { ); } + const licenseAction = + ! hasSocialPaidFeatures() && isJetpackSite + ? createInterpolateElement( + __( + 'Already have an existing plan or license key? Click here to get started', + 'jetpack-publicize-pkg' + ), + { + a: , + } + ) + : null; + return ( } + title={ __( 'Social', 'jetpack-publicize-pkg' ) } + // should we add a tagline? Page seems already crowded + // tagline={ __( 'Share your posts with your social media network.', 'jetpack-publicize-pkg' ) } + actions={ licenseAction } showFooter={ isJetpackSite } useInternalLinks={ shouldUseInternalLinks() } > diff --git a/projects/packages/publicize/_inc/components/admin-page/test/page-header.test.jsx b/projects/packages/publicize/_inc/components/admin-page/test/page-header.test.jsx deleted file mode 100644 index f74f6e861369..000000000000 --- a/projects/packages/publicize/_inc/components/admin-page/test/page-header.test.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { clearMockedScriptData, mockScriptData } from '../../../utils/test-utils'; -import AdminPageHeader from '../page-header'; - -describe( 'AdminPageHeader', () => { - beforeEach( () => { - mockScriptData(); - } ); - - afterEach( () => { - clearMockedScriptData(); - } ); - it( 'should show license text when no paid features and is Jetpack site', () => { - render( ); - expect( - screen.getByText( /Already have an existing plan or license key\?/i ) - ).toBeInTheDocument(); - expect( screen.getByRole( 'link' ) ).toHaveAttribute( - 'href', - expect.stringContaining( 'admin.php?page=my-jetpack#/add-license' ) - ); - } ); - - it( 'should not show license text when has paid features', () => { - mockScriptData( { - site: { - plan: { - features: { - active: [ 'social-enhanced-publishing' ], - }, - }, - }, - } ); - render( ); - expect( - screen.queryByText( /Already have an existing plan or license key\?/i ) - ).not.toBeInTheDocument(); - clearMockedScriptData(); - } ); - - it( 'should not show license text when not a Jetpack site', () => { - mockScriptData( { - site: { - host: 'wpcom', - plan: { - features: { - active: [ 'social-enhanced-publishing' ], - }, - }, - }, - } ); - render( ); - expect( - screen.queryByText( /Already have an existing plan or license key\?/i ) - ).not.toBeInTheDocument(); - clearMockedScriptData(); - } ); -} ); From afacc5fd9894e84568ca44279c3c04353e3cd838 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 01:32:32 -0300 Subject: [PATCH 04/42] Refactor AdminHeader to use VStack/HStack/Heading matching @wordpress/admin-ui pattern. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-header/index.tsx | 50 +++++++++++++------ .../components/admin-header/style.module.scss | 45 ++--------------- .../components/admin-header/types.ts | 14 +++++- 3 files changed, 51 insertions(+), 58 deletions(-) diff --git a/projects/js-packages/components/components/admin-header/index.tsx b/projects/js-packages/components/components/admin-header/index.tsx index b578c433da13..346904ff5bf2 100644 --- a/projects/js-packages/components/components/admin-header/index.tsx +++ b/projects/js-packages/components/components/admin-header/index.tsx @@ -1,3 +1,8 @@ +import { + __experimentalVStack as VStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis + __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis + __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis +} from '@wordpress/components'; import clsx from 'clsx'; import JetpackLogo from '../jetpack-logo/index.tsx'; import styles from './style.module.scss'; @@ -7,7 +12,7 @@ import type { FC } from 'react'; /** * Unified admin page header component. * - * Renders a sticky header with logo, product title, optional tagline, + * Renders a sticky header with logo, product title, optional subtitle, * actions, and tabs. Follows the `@wordpress/admin-ui` Page header pattern. * * @param {AdminHeaderProps} props - Component properties. @@ -16,25 +21,40 @@ import type { FC } from 'react'; const AdminHeader: FC< AdminHeaderProps > = ( { logo, title, - tagline, + subTitle, actions, - tabs, + tabs = null, className, + breadcrumbs = null, + badges = null, } ) => { + const classes = clsx( styles[ 'admin-header' ], className ); return ( -
-
-
- - { logo || } - -

{ title }

-
- { actions &&
{ actions }
} -
- { tagline &&

{ tagline }

} + + + + { title && ( + + { logo || } + + { title } + + + ) } + { breadcrumbs } + { badges } + + + { actions } + + + { subTitle &&

{ subTitle }

} { tabs } -
+ ); }; diff --git a/projects/js-packages/components/components/admin-header/style.module.scss b/projects/js-packages/components/components/admin-header/style.module.scss index 6cff7b2b9bf7..57710993684f 100644 --- a/projects/js-packages/components/components/admin-header/style.module.scss +++ b/projects/js-packages/components/components/admin-header/style.module.scss @@ -7,47 +7,10 @@ z-index: 1; } -.admin-header__title-row { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; -} - -.admin-header__title { - display: flex; - align-items: center; - gap: 8px; - min-width: 0; // allow truncation -} - -.admin-header__logo { - display: flex; - align-items: center; - flex-shrink: 0; -} - -.admin-header__product-name { - font-size: 15px; - font-weight: 500; - line-height: 32px; - margin: 0; - padding: 0; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.admin-header__tagline { - margin: 4px 0 0; +.admin-header .admin-header-subtitle { + padding-block-end: 8px; + color: #757575; font-size: 13px; line-height: 1.4; - color: #757575; -} - -.admin-header__actions { - display: flex; - align-items: center; - gap: 8px; - flex-shrink: 0; + margin: 0; } diff --git a/projects/js-packages/components/components/admin-header/types.ts b/projects/js-packages/components/components/admin-header/types.ts index 8fe76df341f2..cd2940a4b5b8 100644 --- a/projects/js-packages/components/components/admin-header/types.ts +++ b/projects/js-packages/components/components/admin-header/types.ts @@ -12,9 +12,19 @@ export type AdminHeaderProps = { title: string; /** - * Optional tagline displayed below the title row. + * Optional subtitle displayed below the title row. */ - tagline?: string; + subTitle?: string; + + /** + * Optional breadcrumb elements displayed next to the title. + */ + breadcrumbs?: ReactNode; + + /** + * Optional badge elements displayed next to the title. + */ + badges?: ReactNode; /** * Optional action elements (buttons, links) displayed on the right side of the header. From 5a883b640b38bbc766633658110cf30c8f8d37e9 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 01:32:40 -0300 Subject: [PATCH 05/42] Rename tagline prop to subTitle across AdminPage and publicize for admin-ui alignment. Co-Authored-By: Claude Opus 4.6 --- .../js-packages/components/components/admin-page/index.tsx | 4 ++-- .../js-packages/components/components/admin-page/types.ts | 2 +- .../packages/publicize/_inc/components/admin-page/index.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/js-packages/components/components/admin-page/index.tsx b/projects/js-packages/components/components/admin-page/index.tsx index 5745de92ec18..d0bad43689b2 100644 --- a/projects/js-packages/components/components/admin-page/index.tsx +++ b/projects/js-packages/components/components/admin-page/index.tsx @@ -34,7 +34,7 @@ const AdminPage: FC< AdminPageProps > = ( { optionalMenuItems, header, title, - tagline, + subTitle, logo, actions, tabs, @@ -72,7 +72,7 @@ const AdminPage: FC< AdminPageProps > = ( { diff --git a/projects/js-packages/components/components/admin-page/types.ts b/projects/js-packages/components/components/admin-page/types.ts index 9d7219dec823..a93767c9e63c 100644 --- a/projects/js-packages/components/components/admin-page/types.ts +++ b/projects/js-packages/components/components/admin-page/types.ts @@ -32,7 +32,7 @@ export type AdminPageProps = { /** * Optional tagline displayed below the title in the unified header. */ - tagline?: string; + subTitle?: string; /** * Custom logo element for the unified header. Defaults to JetpackLogo icon. diff --git a/projects/packages/publicize/_inc/components/admin-page/index.tsx b/projects/packages/publicize/_inc/components/admin-page/index.tsx index ca15dae8a312..c692bc892416 100644 --- a/projects/packages/publicize/_inc/components/admin-page/index.tsx +++ b/projects/packages/publicize/_inc/components/admin-page/index.tsx @@ -97,8 +97,8 @@ export const SocialAdminPage = () => { Date: Wed, 25 Feb 2026 02:08:28 -0300 Subject: [PATCH 06/42] Add @wordpress/admin-ui dependency to jetpack-components. Co-Authored-By: Claude Opus 4.6 --- pnpm-lock.yaml | 3 +++ projects/js-packages/components/package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b3ad564c82d..05d259cc9d07 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -536,6 +536,9 @@ importers: '@babel/runtime': specifier: ^7 version: 7.28.6 + '@wordpress/admin-ui': + specifier: 1.8.0 + version: 1.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/browserslist-config': specifier: 6.40.0 version: 6.40.0 diff --git a/projects/js-packages/components/package.json b/projects/js-packages/components/package.json index 412e98b59cbb..b10c6280eb22 100644 --- a/projects/js-packages/components/package.json +++ b/projects/js-packages/components/package.json @@ -53,6 +53,7 @@ "@automattic/jetpack-script-data": "workspace:*", "@automattic/number-formatters": "workspace:*", "@babel/runtime": "^7", + "@wordpress/admin-ui": "1.8.0", "@wordpress/browserslist-config": "6.40.0", "@wordpress/components": "32.2.0", "@wordpress/compose": "7.40.0", From 3664f981e899090528a9721d9de09aa5560bdb52 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 02:08:51 -0300 Subject: [PATCH 07/42] Refactor AdminHeader to wrap @wordpress/admin-ui Page component. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-header/index.tsx | 53 +++++++++---------- .../components/admin-header/style.module.scss | 3 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/projects/js-packages/components/components/admin-header/index.tsx b/projects/js-packages/components/components/admin-header/index.tsx index 346904ff5bf2..e896d011b636 100644 --- a/projects/js-packages/components/components/admin-header/index.tsx +++ b/projects/js-packages/components/components/admin-header/index.tsx @@ -1,7 +1,7 @@ +import { Page } from '@wordpress/admin-ui'; import { - __experimentalVStack as VStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis - __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis + __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis } from '@wordpress/components'; import clsx from 'clsx'; import JetpackLogo from '../jetpack-logo/index.tsx'; @@ -13,7 +13,7 @@ import type { FC } from 'react'; * Unified admin page header component. * * Renders a sticky header with logo, product title, optional subtitle, - * actions, and tabs. Follows the `@wordpress/admin-ui` Page header pattern. + * actions, and tabs. Wraps the `@wordpress/admin-ui` Page component. * * @param {AdminHeaderProps} props - Component properties. * @return {ReactNode} AdminHeader component. @@ -29,32 +29,31 @@ const AdminHeader: FC< AdminHeaderProps > = ( { badges = null, } ) => { const classes = clsx( styles[ 'admin-header' ], className ); + + // While admin-ui Page has a title prop, it fails to render both the logo and + // text. Internally it tries to accommodate both inside Heading. + // Composing here with Heading as it is on admin-ui Page. + const composedTitle = title ? ( + + { logo || } + + { title } + + + ) : undefined; + return ( - - - - { title && ( - - { logo || } - - { title } - - - ) } - { breadcrumbs } - { badges } - - - { actions } - - - { subTitle &&

{ subTitle }

} + { tabs } -
+ ); }; diff --git a/projects/js-packages/components/components/admin-header/style.module.scss b/projects/js-packages/components/components/admin-header/style.module.scss index 57710993684f..d57162ee328d 100644 --- a/projects/js-packages/components/components/admin-header/style.module.scss +++ b/projects/js-packages/components/components/admin-header/style.module.scss @@ -7,7 +7,8 @@ z-index: 1; } -.admin-header .admin-header-subtitle { +/* stylelint-disable-next-line selector-class-pattern */ +.admin-header :global(.admin-ui-page__header-subtitle) { padding-block-end: 8px; color: #757575; font-size: 13px; From ef758cdd4d6a154dd8ae57948e41ce0903834e8d Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 02:10:42 -0300 Subject: [PATCH 08/42] Remove unused AdminHeader style.module.scss, styles come from admin-ui. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-header/index.tsx | 4 +--- .../components/admin-header/style.module.scss | 17 ----------------- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 projects/js-packages/components/components/admin-header/style.module.scss diff --git a/projects/js-packages/components/components/admin-header/index.tsx b/projects/js-packages/components/components/admin-header/index.tsx index e896d011b636..a6a763e5eac7 100644 --- a/projects/js-packages/components/components/admin-header/index.tsx +++ b/projects/js-packages/components/components/admin-header/index.tsx @@ -3,9 +3,7 @@ import { __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis } from '@wordpress/components'; -import clsx from 'clsx'; import JetpackLogo from '../jetpack-logo/index.tsx'; -import styles from './style.module.scss'; import type { AdminHeaderProps } from './types.ts'; import type { FC } from 'react'; @@ -28,7 +26,7 @@ const AdminHeader: FC< AdminHeaderProps > = ( { breadcrumbs = null, badges = null, } ) => { - const classes = clsx( styles[ 'admin-header' ], className ); + const classes = className; // While admin-ui Page has a title prop, it fails to render both the logo and // text. Internally it tries to accommodate both inside Heading. diff --git a/projects/js-packages/components/components/admin-header/style.module.scss b/projects/js-packages/components/components/admin-header/style.module.scss deleted file mode 100644 index d57162ee328d..000000000000 --- a/projects/js-packages/components/components/admin-header/style.module.scss +++ /dev/null @@ -1,17 +0,0 @@ -.admin-header { - padding: 16px 24px; - border-bottom: 1px solid #e0e0e0; - background: #fff; - position: sticky; - top: 0; - z-index: 1; -} - -/* stylelint-disable-next-line selector-class-pattern */ -.admin-header :global(.admin-ui-page__header-subtitle) { - padding-block-end: 8px; - color: #757575; - font-size: 13px; - line-height: 1.4; - margin: 0; -} From a7f1b2a3cfd82ca82687da3eb60fc37fc23325b9 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 02:10:52 -0300 Subject: [PATCH 09/42] Delete unused publicize AdminPageHeader, replaced by unified AdminHeader. Co-Authored-By: Claude Opus 4.6 --- .../admin-page/page-header/index.jsx | 34 ------------------- .../components/admin-page/page-header/logo.js | 22 ------------ .../admin-page/page-header/styles.module.scss | 10 ------ 3 files changed, 66 deletions(-) delete mode 100644 projects/packages/publicize/_inc/components/admin-page/page-header/index.jsx delete mode 100644 projects/packages/publicize/_inc/components/admin-page/page-header/logo.js delete mode 100644 projects/packages/publicize/_inc/components/admin-page/page-header/styles.module.scss diff --git a/projects/packages/publicize/_inc/components/admin-page/page-header/index.jsx b/projects/packages/publicize/_inc/components/admin-page/page-header/index.jsx deleted file mode 100644 index bbeb0c2ae4f2..000000000000 --- a/projects/packages/publicize/_inc/components/admin-page/page-header/index.jsx +++ /dev/null @@ -1,34 +0,0 @@ -import { getMyJetpackUrl, isJetpackSelfHostedSite } from '@automattic/jetpack-script-data'; -import { createInterpolateElement } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { hasSocialPaidFeatures } from '../../../utils'; -import Logo from './logo'; -import styles from './styles.module.scss'; - -const AdminPageHeader = () => { - const isJetpackSite = isJetpackSelfHostedSite(); - - return ( -
- ); -}; - -export default AdminPageHeader; diff --git a/projects/packages/publicize/_inc/components/admin-page/page-header/logo.js b/projects/packages/publicize/_inc/components/admin-page/page-header/logo.js deleted file mode 100644 index fa319c65f09a..000000000000 --- a/projects/packages/publicize/_inc/components/admin-page/page-header/logo.js +++ /dev/null @@ -1,22 +0,0 @@ -const Logo = ( { height = 40 } ) => ( - - - - - - -); - -export default Logo; diff --git a/projects/packages/publicize/_inc/components/admin-page/page-header/styles.module.scss b/projects/packages/publicize/_inc/components/admin-page/page-header/styles.module.scss deleted file mode 100644 index 05a64bb759a4..000000000000 --- a/projects/packages/publicize/_inc/components/admin-page/page-header/styles.module.scss +++ /dev/null @@ -1,10 +0,0 @@ -.header { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - gap: calc(var(--horizontal-spacing) * 3); - - .logo { - flex-shrink: 0; - } -} From f47248b958bfecaa24e0d79b0ab1b05a15b41eb8 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 02:17:49 -0300 Subject: [PATCH 10/42] Add changelog entries for jetpack-components and publicize. Co-Authored-By: Claude Opus 4.6 --- .../components/changelog/update-normalize-admin-page-headers | 4 ++++ .../publicize/changelog/update-normalize-admin-page-headers | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 projects/js-packages/components/changelog/update-normalize-admin-page-headers create mode 100644 projects/packages/publicize/changelog/update-normalize-admin-page-headers diff --git a/projects/js-packages/components/changelog/update-normalize-admin-page-headers b/projects/js-packages/components/changelog/update-normalize-admin-page-headers new file mode 100644 index 000000000000..ad02bc7be2d0 --- /dev/null +++ b/projects/js-packages/components/changelog/update-normalize-admin-page-headers @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Add AdminHeader component wrapping @wordpress/admin-ui Page for unified admin page headers. diff --git a/projects/packages/publicize/changelog/update-normalize-admin-page-headers b/projects/packages/publicize/changelog/update-normalize-admin-page-headers new file mode 100644 index 000000000000..179dd8abc914 --- /dev/null +++ b/projects/packages/publicize/changelog/update-normalize-admin-page-headers @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Migrate admin page header to use unified AdminHeader component. From fbf0627db5559f62fa3c16def326ec0d3416bc6a Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Wed, 25 Feb 2026 11:22:20 -0300 Subject: [PATCH 11/42] Address review feedback: fix deprecated prop name, export types, remove redundant props and comments. Co-Authored-By: Claude Opus 4.6 --- projects/js-packages/components/components/admin-page/types.ts | 2 +- projects/js-packages/components/index.ts | 1 + .../packages/publicize/_inc/components/admin-page/index.tsx | 3 --- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/projects/js-packages/components/components/admin-page/types.ts b/projects/js-packages/components/components/admin-page/types.ts index a93767c9e63c..bec390ae496d 100644 --- a/projects/js-packages/components/components/admin-page/types.ts +++ b/projects/js-packages/components/components/admin-page/types.ts @@ -19,7 +19,7 @@ export type AdminPageProps = { /** * Custom header. Optional. - * @deprecated Use `title` and `tagline` props instead for the unified header. + * @deprecated Use `title` and `subTitle` props instead for the unified header. */ header?: ReactNode; diff --git a/projects/js-packages/components/index.ts b/projects/js-packages/components/index.ts index 9c9946a12b4e..7dc51e617bbc 100644 --- a/projects/js-packages/components/index.ts +++ b/projects/js-packages/components/index.ts @@ -35,6 +35,7 @@ export { default as AdminSection } from './components/admin-section/basic/index. export { default as AdminSectionHero } from './components/admin-section/hero/index.tsx'; export { default as AdminPage } from './components/admin-page/index.tsx'; export { default as AdminHeader } from './components/admin-header/index.tsx'; +export type { AdminHeaderProps } from './components/admin-header/types.ts'; export { default as DecorativeCard } from './components/decorative-card/index.tsx'; export { default as Col } from './components/layout/col/index.tsx'; export { default as Testimonials } from './components/testimonials/index.tsx'; diff --git a/projects/packages/publicize/_inc/components/admin-page/index.tsx b/projects/packages/publicize/_inc/components/admin-page/index.tsx index c692bc892416..cbe11e9f27c3 100644 --- a/projects/packages/publicize/_inc/components/admin-page/index.tsx +++ b/projects/packages/publicize/_inc/components/admin-page/index.tsx @@ -67,7 +67,6 @@ export const SocialAdminPage = () => { @@ -97,8 +96,6 @@ export const SocialAdminPage = () => { Date: Wed, 25 Feb 2026 12:37:18 -0300 Subject: [PATCH 12/42] add subtitle as in design MVP --- .../packages/publicize/_inc/components/admin-page/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/projects/packages/publicize/_inc/components/admin-page/index.tsx b/projects/packages/publicize/_inc/components/admin-page/index.tsx index cbe11e9f27c3..b0ef6e2d3ca1 100644 --- a/projects/packages/publicize/_inc/components/admin-page/index.tsx +++ b/projects/packages/publicize/_inc/components/admin-page/index.tsx @@ -67,6 +67,7 @@ export const SocialAdminPage = () => { @@ -96,6 +97,7 @@ export const SocialAdminPage = () => { Date: Wed, 25 Feb 2026 15:44:57 -0300 Subject: [PATCH 13/42] Bundle @wordpress/admin-ui CSS via proxy file to avoid DependencyExtractionPlugin externalization. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-header/admin-ui-styles.css | 8 ++++++++ .../components/components/admin-header/index.tsx | 1 + .../js-packages/components/tools/copy-scss-to-build.mjs | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 projects/js-packages/components/components/admin-header/admin-ui-styles.css diff --git a/projects/js-packages/components/components/admin-header/admin-ui-styles.css b/projects/js-packages/components/components/admin-header/admin-ui-styles.css new file mode 100644 index 000000000000..b9b1bf26cef7 --- /dev/null +++ b/projects/js-packages/components/components/admin-header/admin-ui-styles.css @@ -0,0 +1,8 @@ +/* Proxy file to import @wordpress/admin-ui styles. + * + * Importing the CSS via @import inside a .css file avoids the + * @wordpress/dependency-extraction-webpack-plugin externalization that + * breaks direct JS `import '@wordpress/admin-ui/build-style/style.css'`. + * css-loader resolves @import independently of the externals plugin. + */ +@import "@wordpress/admin-ui/build-style/style.css"; diff --git a/projects/js-packages/components/components/admin-header/index.tsx b/projects/js-packages/components/components/admin-header/index.tsx index a6a763e5eac7..516729064504 100644 --- a/projects/js-packages/components/components/admin-header/index.tsx +++ b/projects/js-packages/components/components/admin-header/index.tsx @@ -1,4 +1,5 @@ import { Page } from '@wordpress/admin-ui'; +import './admin-ui-styles.css'; import { __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis diff --git a/projects/js-packages/components/tools/copy-scss-to-build.mjs b/projects/js-packages/components/tools/copy-scss-to-build.mjs index f2622ba37f5b..505e73b64612 100644 --- a/projects/js-packages/components/tools/copy-scss-to-build.mjs +++ b/projects/js-packages/components/tools/copy-scss-to-build.mjs @@ -50,7 +50,7 @@ async function main() { return; } - for await ( const filePath of fs.glob( '**/*.scss', { + for await ( const filePath of fs.glob( '**/*.{scss,css}', { cwd: packageRoot, exclude: Array.from( IGNORED_DIRS, dir => `**/${ dir }/**` ), } ) ) { From a2759a14a3ec44f36fd7ce672ae8420ee61af5c2 Mon Sep 17 00:00:00 2001 From: William Viana Date: Thu, 26 Feb 2026 17:31:10 +0100 Subject: [PATCH 14/42] Centralize admin-ui CSS bundling in jetpack-webpack-config Replace the proxy CSS file hack with proper webpack configuration: - Add @wordpress/admin-ui/build-style/style.css to defaultRequestMap with external: false to prevent DependencyExtractionPlugin from incorrectly externalizing the CSS subpath import (the BUNDLED_PACKAGES check is exact-match only, so subpaths fall through). - Add sideEffects: true to the shared CssRule so CSS imports are never tree-shaken by packages declaring sideEffects: false. - Delete the admin-ui-styles.css proxy file and use a direct import. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-header/admin-ui-styles.css | 8 -------- .../components/components/admin-header/index.tsx | 2 +- projects/js-packages/webpack-config/src/webpack.js | 6 ++++++ .../js-packages/webpack-config/src/webpack/css-rule.js | 3 +++ 4 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 projects/js-packages/components/components/admin-header/admin-ui-styles.css diff --git a/projects/js-packages/components/components/admin-header/admin-ui-styles.css b/projects/js-packages/components/components/admin-header/admin-ui-styles.css deleted file mode 100644 index b9b1bf26cef7..000000000000 --- a/projects/js-packages/components/components/admin-header/admin-ui-styles.css +++ /dev/null @@ -1,8 +0,0 @@ -/* Proxy file to import @wordpress/admin-ui styles. - * - * Importing the CSS via @import inside a .css file avoids the - * @wordpress/dependency-extraction-webpack-plugin externalization that - * breaks direct JS `import '@wordpress/admin-ui/build-style/style.css'`. - * css-loader resolves @import independently of the externals plugin. - */ -@import "@wordpress/admin-ui/build-style/style.css"; diff --git a/projects/js-packages/components/components/admin-header/index.tsx b/projects/js-packages/components/components/admin-header/index.tsx index 516729064504..0d8f05afa5cd 100644 --- a/projects/js-packages/components/components/admin-header/index.tsx +++ b/projects/js-packages/components/components/admin-header/index.tsx @@ -1,5 +1,5 @@ import { Page } from '@wordpress/admin-ui'; -import './admin-ui-styles.css'; +import '@wordpress/admin-ui/build-style/style.css'; import { __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis diff --git a/projects/js-packages/webpack-config/src/webpack.js b/projects/js-packages/webpack-config/src/webpack.js index 87605ef35031..28f73183a9e8 100644 --- a/projects/js-packages/webpack-config/src/webpack.js +++ b/projects/js-packages/webpack-config/src/webpack.js @@ -143,6 +143,12 @@ const defaultRequestMap = { external: 'JetpackConnection', handle: 'jetpack-connection', }, + // Bundle admin-ui CSS with our assets. The JS side is already handled by the + // DependencyExtractionPlugin's BUNDLED_PACKAGES list, but the CSS subpath import + // doesn't match that exact-match check and would be incorrectly externalized. + '@wordpress/admin-ui/build-style/style.css': { + external: false, + }, }; const DependencyExtractionPlugin = ( { requestMap, ...options } = {} ) => { diff --git a/projects/js-packages/webpack-config/src/webpack/css-rule.js b/projects/js-packages/webpack-config/src/webpack/css-rule.js index 27effd435e18..4e2f6ae4868d 100644 --- a/projects/js-packages/webpack-config/src/webpack/css-rule.js +++ b/projects/js-packages/webpack-config/src/webpack/css-rule.js @@ -27,6 +27,9 @@ const CssRule = ( options = {} ) => { '\\.(?:' + exts.map( ext => ext.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ) ).join( '|' ) + ')$', 'i' ), + // CSS imports are always side effects (they inject styles into the DOM), + // so override any package.json "sideEffects: false" declarations. + sideEffects: true, use: [ MiniCssExtractLoader( options.MiniCssExtractLoader ), CssLoader( { From e73635f26ca1a9406489f195c1ff98fca0f85137 Mon Sep 17 00:00:00 2001 From: William Viana Date: Thu, 26 Feb 2026 17:36:00 +0100 Subject: [PATCH 15/42] Add changelog entries for webpack-config and components Co-Authored-By: Claude Opus 4.6 --- .../components/changelog/centralize-admin-ui-css-bundling | 4 ++++ .../webpack-config/changelog/centralize-admin-ui-css-bundling | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 projects/js-packages/components/changelog/centralize-admin-ui-css-bundling create mode 100644 projects/js-packages/webpack-config/changelog/centralize-admin-ui-css-bundling diff --git a/projects/js-packages/components/changelog/centralize-admin-ui-css-bundling b/projects/js-packages/components/changelog/centralize-admin-ui-css-bundling new file mode 100644 index 000000000000..7ee43682017f --- /dev/null +++ b/projects/js-packages/components/changelog/centralize-admin-ui-css-bundling @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Replace admin-ui CSS proxy file with direct import, now that webpack-config handles bundling centrally. diff --git a/projects/js-packages/webpack-config/changelog/centralize-admin-ui-css-bundling b/projects/js-packages/webpack-config/changelog/centralize-admin-ui-css-bundling new file mode 100644 index 000000000000..e81f3c5ae1a8 --- /dev/null +++ b/projects/js-packages/webpack-config/changelog/centralize-admin-ui-css-bundling @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Centralize admin-ui CSS bundling: add subpath to defaultRequestMap and mark CSS imports as sideEffects to prevent incorrect externalization and tree-shaking. From 8954b90db9c8fb18f4740be9f531bb6394462006 Mon Sep 17 00:00:00 2001 From: William Viana Date: Thu, 26 Feb 2026 18:17:07 +0100 Subject: [PATCH 16/42] Remove AdminHeader, use admin-ui Page directly in AdminPage Delete the AdminHeader wrapper component and inline its logic into AdminPage. When `title` is provided, AdminPage now wraps the full page content (header, tabs, children, footer) inside admin-ui's Page component instead of delegating to a separate header-only wrapper. This addresses review feedback: - Page is used for full page contents, not just as a header wrapper - No unnecessary intermediate component wrapping an existing component - Title composition (HStack + logo) lives directly in AdminPage The inner Heading wrapper around title is retained as a workaround for a known admin-ui bug with non-string titles (gutenberg#75899). A TODO comment marks it for removal once the upstream fix lands. Co-Authored-By: Claude Opus 4.6 --- .../components/admin-header/index.tsx | 59 --------- .../components/admin-header/types.ts | 43 ------- .../components/admin-page/index.tsx | 115 +++++++++++------- .../components/components/admin-page/types.ts | 2 +- projects/js-packages/components/index.ts | 2 - 5 files changed, 75 insertions(+), 146 deletions(-) delete mode 100644 projects/js-packages/components/components/admin-header/index.tsx delete mode 100644 projects/js-packages/components/components/admin-header/types.ts diff --git a/projects/js-packages/components/components/admin-header/index.tsx b/projects/js-packages/components/components/admin-header/index.tsx deleted file mode 100644 index 0d8f05afa5cd..000000000000 --- a/projects/js-packages/components/components/admin-header/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Page } from '@wordpress/admin-ui'; -import '@wordpress/admin-ui/build-style/style.css'; -import { - __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis - __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis -} from '@wordpress/components'; -import JetpackLogo from '../jetpack-logo/index.tsx'; -import type { AdminHeaderProps } from './types.ts'; -import type { FC } from 'react'; - -/** - * Unified admin page header component. - * - * Renders a sticky header with logo, product title, optional subtitle, - * actions, and tabs. Wraps the `@wordpress/admin-ui` Page component. - * - * @param {AdminHeaderProps} props - Component properties. - * @return {ReactNode} AdminHeader component. - */ -const AdminHeader: FC< AdminHeaderProps > = ( { - logo, - title, - subTitle, - actions, - tabs = null, - className, - breadcrumbs = null, - badges = null, -} ) => { - const classes = className; - - // While admin-ui Page has a title prop, it fails to render both the logo and - // text. Internally it tries to accommodate both inside Heading. - // Composing here with Heading as it is on admin-ui Page. - const composedTitle = title ? ( - - { logo || } - - { title } - - - ) : undefined; - - return ( - - { tabs } - - ); -}; - -export default AdminHeader; diff --git a/projects/js-packages/components/components/admin-header/types.ts b/projects/js-packages/components/components/admin-header/types.ts deleted file mode 100644 index cd2940a4b5b8..000000000000 --- a/projects/js-packages/components/components/admin-header/types.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { ReactNode } from 'react'; - -export type AdminHeaderProps = { - /** - * Custom logo element. Defaults to JetpackLogo icon (bolt only). - */ - logo?: ReactNode; - - /** - * Product title displayed next to the logo. - */ - title: string; - - /** - * Optional subtitle displayed below the title row. - */ - subTitle?: string; - - /** - * Optional breadcrumb elements displayed next to the title. - */ - breadcrumbs?: ReactNode; - - /** - * Optional badge elements displayed next to the title. - */ - badges?: ReactNode; - - /** - * Optional action elements (buttons, links) displayed on the right side of the header. - */ - actions?: ReactNode; - - /** - * Optional tab navigation displayed below the title/tagline. - */ - tabs?: ReactNode; - - /** - * Additional CSS class name. - */ - className?: string; -}; diff --git a/projects/js-packages/components/components/admin-page/index.tsx b/projects/js-packages/components/components/admin-page/index.tsx index d0bad43689b2..95fad8ebb4af 100644 --- a/projects/js-packages/components/components/admin-page/index.tsx +++ b/projects/js-packages/components/components/admin-page/index.tsx @@ -1,8 +1,13 @@ import restApi from '@automattic/jetpack-api'; +import { Page } from '@wordpress/admin-ui'; +import '@wordpress/admin-ui/build-style/style.css'; +import { + __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis + __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis +} from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import clsx from 'clsx'; import { useEffect, useCallback } from 'react'; -import AdminHeader from '../admin-header/index.tsx'; import JetpackFooter from '../jetpack-footer/index.tsx'; import JetpackLogo from '../jetpack-logo/index.tsx'; import Col from '../layout/col/index.tsx'; @@ -66,53 +71,81 @@ const AdminPage: FC< AdminPageProps > = ( { } }, [] ); - return ( -
- { showHeader && title ? ( - + { logo || } + + { title } + + + ) : undefined; + + const footer = showFooter && ( + + + + + + ); + + // When title is provided, use admin-ui Page for the full page layout. + if ( showHeader && composedTitle ) { + return ( +
+ - ) : ( - showHeader && ( - - - { header ? header : } - { sandboxedDomain && ( - - API Sandboxed - - ) } - + showSidebarToggle={ false } + > + { tabs } + + { children } - ) - ) } - - { children } - - { showFooter && ( + { footer } + +
+ ); + } + + // Legacy path: no title provided, render the classic header. + return ( +
+ { showHeader && ( - - + + { header ? header : } + { sandboxedDomain && ( + + API Sandboxed + + ) } ) } + + { children } + + { footer }
); }; diff --git a/projects/js-packages/components/components/admin-page/types.ts b/projects/js-packages/components/components/admin-page/types.ts index bec390ae496d..eb354ade01dc 100644 --- a/projects/js-packages/components/components/admin-page/types.ts +++ b/projects/js-packages/components/components/admin-page/types.ts @@ -25,7 +25,7 @@ export type AdminPageProps = { /** * Product title displayed in the unified header (e.g. "Social", "Backup"). - * When provided, renders the new AdminHeader instead of the legacy header slot. + * When provided, renders the admin-ui Page header instead of the legacy header slot. */ title?: string; diff --git a/projects/js-packages/components/index.ts b/projects/js-packages/components/index.ts index 7dc51e617bbc..5b2df114305e 100644 --- a/projects/js-packages/components/index.ts +++ b/projects/js-packages/components/index.ts @@ -34,8 +34,6 @@ export { default as NumberSlider } from './components/number-slider/index.tsx'; export { default as AdminSection } from './components/admin-section/basic/index.tsx'; export { default as AdminSectionHero } from './components/admin-section/hero/index.tsx'; export { default as AdminPage } from './components/admin-page/index.tsx'; -export { default as AdminHeader } from './components/admin-header/index.tsx'; -export type { AdminHeaderProps } from './components/admin-header/types.ts'; export { default as DecorativeCard } from './components/decorative-card/index.tsx'; export { default as Col } from './components/layout/col/index.tsx'; export { default as Testimonials } from './components/testimonials/index.tsx'; From 58b48504f51d74eef7b55f2fb19390fe35ac19b7 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Fri, 27 Feb 2026 01:07:25 -0300 Subject: [PATCH 17/42] Fix Jest failing to parse @wordpress/admin-ui CSS import. The direct import of @wordpress/admin-ui/build-style/style.css in AdminPage resolves to a path inside node_modules/.pnpm/ which Jest ignores by default (transformIgnorePatterns). Without being transformed by the asset stub, Jest tries to parse raw CSS as JavaScript and fails. Expand the transformIgnorePatterns exception to also match admin-ui CSS files, using a .* prefix to handle the nested node_modules path created by pnpm hoisted structure. Co-Authored-By: Claude Opus 4.6 --- tools/js-tools/jest/config.base.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/js-tools/jest/config.base.js b/tools/js-tools/jest/config.base.js index 7f33071242cc..14e212ae15dd 100644 --- a/tools/js-tools/jest/config.base.js +++ b/tools/js-tools/jest/config.base.js @@ -28,8 +28,10 @@ module.exports = { }, ], }, - // Unignore uplot css for packages/components. Globally because the monorepo build recompiles in every consumer. - transformIgnorePatterns: [ '/node_modules/(?!.*uplot.*\\.css)' ], + // Unignore certain node_modules CSS so the asset-stub transform can handle them. + // - uplot: for packages/components + // - @wordpress/admin-ui: for the unified admin page header styles + transformIgnorePatterns: [ '/node_modules/(?!.*uplot.*\\.css|.*@wordpress/admin-ui/.*\\.css)' ], moduleNameMapper: { jetpackConfig: path.join( __dirname, 'jest-jetpack-config.js' ), }, From 271a54b745fd00446827be630c1fa90bdfb74fa9 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Fri, 27 Feb 2026 01:23:51 -0300 Subject: [PATCH 18/42] Fix Jest transformIgnorePatterns for @wordpress/admin-ui CSS in all configs. The direct CSS import in AdminPage needs to be allowed through Jest transforms in every config that overrides transformIgnorePatterns. The base config and the jetpack plugin gui config both need the admin-ui exception to handle pnpm nested node_modules paths. Co-Authored-By: Claude Opus 4.6 --- projects/plugins/jetpack/tests/jest.config.gui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/plugins/jetpack/tests/jest.config.gui.js b/projects/plugins/jetpack/tests/jest.config.gui.js index 0c4e3722accf..e53fdbf3e670 100644 --- a/projects/plugins/jetpack/tests/jest.config.gui.js +++ b/projects/plugins/jetpack/tests/jest.config.gui.js @@ -6,9 +6,9 @@ module.exports = { testMatch: [ '/_inc/client/test/main.js', '/_inc/client/**/test/component.js' ], setupFilesAfterEnv: [ ...baseConfig.setupFilesAfterEnv, '/tests/jest-globals.gui.js' ], coverageDirectory: baseConfig.coverageDirectory + '/gui', - // This is necessary to allow css from uplot to be imported. + // This is necessary to allow css from uplot and @wordpress/admin-ui to be imported. transformIgnorePatterns: [ - '/node_modules/(?!(.pnpm|@automattic)/|.*uplot.*\\.css)', + '/node_modules/(?!(.pnpm|@automattic)/|.*uplot.*\\.css|.*@wordpress/admin-ui/.*\\.css)', ...baseConfig.transformIgnorePatterns, ], collectCoverageFrom: [ From 275b400818853272579e2dbb992d49733de4bf60 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Fri, 27 Feb 2026 12:40:54 -0300 Subject: [PATCH 19/42] Migrate search upsell page to unified AdminHeader (#47332) * Migrate search upsell page header to unified AdminHeader via title prop. Co-Authored-By: Claude Opus 4.6 * Add changelog entry for search package. Co-Authored-By: Claude Opus 4.6 * Migrate search dashboard page header to AdminPage with unified AdminHeader. Co-Authored-By: Claude Opus 4.6 * Delete unused search upsell header component and styles. Co-Authored-By: Claude Opus 4.6 * update logo locator for e2e --------- Co-authored-by: Claude Opus 4.6 --- .../update-normalize-search-admin-header | 4 + .../components/pages/dashboard-page.jsx | 140 +++++++++--------- .../components/pages/dashboard-page.scss | 9 +- .../components/pages/upsell-page/header.jsx | 37 ----- .../components/pages/upsell-page/index.jsx | 59 +++++--- .../components/pages/upsell-page/styles.scss | 25 ---- .../tests/e2e/specs/search-dashboard.test.ts | 4 +- 7 files changed, 111 insertions(+), 167 deletions(-) create mode 100644 projects/packages/search/changelog/update-normalize-search-admin-header delete mode 100644 projects/packages/search/src/dashboard/components/pages/upsell-page/header.jsx diff --git a/projects/packages/search/changelog/update-normalize-search-admin-header b/projects/packages/search/changelog/update-normalize-search-admin-header new file mode 100644 index 000000000000..fe84d4cdfc84 --- /dev/null +++ b/projects/packages/search/changelog/update-normalize-search-admin-header @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Migrate upsell page header to use unified AdminHeader component. diff --git a/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx b/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx index ed37c03e7084..8c88b1591d38 100644 --- a/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx +++ b/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx @@ -1,6 +1,6 @@ import { + AdminPage, JetpackFooter, - JetpackSearchLogo, Button, Container, Col, @@ -115,60 +115,73 @@ export default function DashboardPage( { isLoading = false } ) { { isPageLoading && } { ! isPageLoading && (
-
- { hasConnectionError && ( - - - - - - ) } - - { isNewPricing && supportsInstantSearch && ( - - ) } - { ! isNewPricing && supportsInstantSearch && ( - - ) } -
- + { __( 'Upgrade Jetpack Search', 'jetpack-search-pkg' ) } + + ) + } + className="uses-new-admin-ui" + showFooter={ false } + > + { hasConnectionError && ( + + + + + + ) } + -
-
- + { isNewPricing && supportsInstantSearch && ( + + ) } + { ! isNewPricing && supportsInstantSearch && ( + + ) } +
+ +
+
+ +
) } @@ -250,24 +263,3 @@ const Footer = () => {
); }; - -const Header = ( { isUpgradable, sendPaidPlanToCart } ) => { - const buttonLinkArgs = { - children: __( 'Upgrade Jetpack Search', 'jetpack-search-pkg' ), - variant: 'link', - onClick: sendPaidPlanToCart, - }; - - return ( -
-
-
-
- - { isUpgradable &&
-
-
-
- ); -}; diff --git a/projects/packages/search/src/dashboard/components/pages/dashboard-page.scss b/projects/packages/search/src/dashboard/components/pages/dashboard-page.scss index 01db1edf0491..40c129525ed7 100644 --- a/projects/packages/search/src/dashboard/components/pages/dashboard-page.scss +++ b/projects/packages/search/src/dashboard/components/pages/dashboard-page.scss @@ -21,7 +21,7 @@ body { sans-serif; } -#wpcontent { +#wpcontent:not:has(.uses-new-admin-ui) { padding-left: 0 !important; } @@ -79,18 +79,11 @@ body { background-color: variables.$white; } - .jp-search-dashboard-header, .jp-search-dashboard-footer { padding: 2.5em 0; background-color: variables.$white; } - - .jp-search-dashboard-header__logo-container { - display: flex; - align-items: center; - justify-content: space-between; - } } .usage-meter-group { diff --git a/projects/packages/search/src/dashboard/components/pages/upsell-page/header.jsx b/projects/packages/search/src/dashboard/components/pages/upsell-page/header.jsx deleted file mode 100644 index 320d5422dc57..000000000000 --- a/projects/packages/search/src/dashboard/components/pages/upsell-page/header.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import { JetpackSearchLogo } from '@automattic/jetpack-components'; -import { useSelect } from '@wordpress/data'; -import { createInterpolateElement } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { STORE_ID } from 'store'; -import './styles.scss'; - -const Header = () => { - const activateLicenseUrl = useSelect( - select => `${ select( STORE_ID ).getSiteAdminUrl() }admin.php?page=my-jetpack#/add-license` - ); - - const isWpcom = useSelect( select => select( STORE_ID ).isWpcom(), [] ); - - return ( -
- ); -}; - -export default Header; diff --git a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx index 0f6bc9f7cf55..1946c883446b 100644 --- a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx +++ b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx @@ -27,7 +27,6 @@ import Price from 'components/price'; import SearchPromotionBlock from 'components/search-promotion'; import useProductCheckoutWorkflow from 'hooks/use-product-checkout-workflow'; import { STORE_ID } from 'store'; -import Header from './header'; import './styles.scss'; @@ -44,11 +43,14 @@ export default function UpsellPage( { isLoading = false } ) { // Introduce the gate for new pricing with URL parameter `new_pricing_202208=1` const APINonce = useSelect( select => select( STORE_ID ).getAPINonce(), [] ); const isNewPricing = useSelect( select => select( STORE_ID ).isNewPricing202208(), [] ); + const isWpcom = useSelect( select => select( STORE_ID ).isWpcom(), [] ); + const activateLicenseUrl = useSelect( + select => `${ select( STORE_ID ).getSiteAdminUrl() }admin.php?page=my-jetpack#/add-license` + ); useSelect( select => select( STORE_ID ).getSearchPricing(), [] ); const domain = useSelect( select => select( STORE_ID ).getCalypsoSlug(), [] ); const blogID = useSelect( select => select( STORE_ID ).getBlogId(), [] ); const adminUrl = useSelect( select => select( STORE_ID ).getSiteAdminUrl(), [] ); - const isWpcom = useSelect( select => select( STORE_ID ).isWpcom(), [] ); const { fetchSearchPlanInfo } = useDispatch( STORE_ID ); const checkSiteHasSearchProduct = useCallback( () => { @@ -90,29 +92,44 @@ export default function UpsellPage( { isLoading = false } ) { [ isLoading, hasCheckoutStartedPaid, hasCheckoutStartedFree ] ); + const licenseAction = ! isWpcom + ? createInterpolateElement( + __( + 'Already have an existing plan or license key? Click here to get started', + 'jetpack-search-pkg' + ), + { + a: , + } + ) + : null; + return ( <> { isPageLoading && } { ! isPageLoading && ( -
- } - moduleNameHref={ JETPACK_SEARCH__LINK } - useInternalLinks={ shouldUseInternalLinks() } - > - - { isNewPricing ? ( - - ) : ( - - ) } - - -
+ + + { isNewPricing ? ( + + ) : ( + + ) } + + ) } ); diff --git a/projects/packages/search/src/dashboard/components/pages/upsell-page/styles.scss b/projects/packages/search/src/dashboard/components/pages/upsell-page/styles.scss index f0c3f3098a45..64374892b69b 100644 --- a/projects/packages/search/src/dashboard/components/pages/upsell-page/styles.scss +++ b/projects/packages/search/src/dashboard/components/pages/upsell-page/styles.scss @@ -1,30 +1,5 @@ @use "scss/variables"; -.jp-search-dashboard-upsell-page { - line-height: 1.5; - width: 100%; - - h1 { - line-height: 1.2; - } - - // Targets AdminPage component, which uses obfuscated CSS names. - > div { - margin-left: 0; - } - - &__header { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - gap: calc(var(--horizontal-spacing) * 3); - } - - &__logo { - flex-shrink: 0; - } -} - .price-tip { display: flex; height: 20px; diff --git a/projects/plugins/search/tests/e2e/specs/search-dashboard.test.ts b/projects/plugins/search/tests/e2e/specs/search-dashboard.test.ts index 65ff8c6af916..8b017d000132 100644 --- a/projects/plugins/search/tests/e2e/specs/search-dashboard.test.ts +++ b/projects/plugins/search/tests/e2e/specs/search-dashboard.test.ts @@ -60,8 +60,8 @@ test.describe( 'Search Dashboard', () => { await expect( instantSearchToggle, 'Instant search toggle should be visible' ).toBeVisible(); await expect( - page.getByRole( 'img', { name: 'Jetpack Search Logo' } ), - 'Header logo should be visible' + page.getByRole( 'img', { name: 'Jetpack Logo' } ), + 'Jetpack header logo should be visible' ).toBeVisible(); await expect( From 3e040f43b117c7ec6b57f63c82d11f0504c911c9 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Fri, 27 Feb 2026 12:44:39 -0300 Subject: [PATCH 20/42] Migrate backup admin page header to unified AdminHeader component. (#47368) Co-authored-by: Claude Opus 4.6 --- .../update-normalize-backup-admin-header | 4 + .../backup/src/js/components/Admin/header.js | 81 ----------------- .../backup/src/js/components/Admin/index.js | 90 +++++++++++++++++-- .../backup/src/js/components/Admin/style.scss | 12 --- 4 files changed, 87 insertions(+), 100 deletions(-) create mode 100644 projects/packages/backup/changelog/update-normalize-backup-admin-header delete mode 100644 projects/packages/backup/src/js/components/Admin/header.js diff --git a/projects/packages/backup/changelog/update-normalize-backup-admin-header b/projects/packages/backup/changelog/update-normalize-backup-admin-header new file mode 100644 index 000000000000..c1e3155c2269 --- /dev/null +++ b/projects/packages/backup/changelog/update-normalize-backup-admin-header @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Migrate admin page header to use unified AdminHeader component from jetpack-components. diff --git a/projects/packages/backup/src/js/components/Admin/header.js b/projects/packages/backup/src/js/components/Admin/header.js deleted file mode 100644 index 9a4db84b3b1c..000000000000 --- a/projects/packages/backup/src/js/components/Admin/header.js +++ /dev/null @@ -1,81 +0,0 @@ -import { JetpackVaultPressBackupLogo } from '@automattic/jetpack-components'; -import { useSelect } from '@wordpress/data'; -import { createInterpolateElement } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { useMemo } from 'react'; -import useCapabilities from '../../hooks/useCapabilities'; -import useConnection from '../../hooks/useConnection'; -import { STORE_ID } from '../../store'; -import { useShowBackUpNow } from '../back-up-now/hooks'; -import { BackupNowButton } from '../back-up-now/index'; -import { useIsFullyConnected } from './hooks'; - -const Header = () => { - const showActivateLicenseLink = useShowActivateLicenseLink(); - const showBackUpNowButton = useShowBackUpNow(); - - return ( -
- - - - { showActivateLicenseLink && } - { showBackUpNowButton && ( - - { __( 'Back up now', 'jetpack-backup-pkg' ) } - - ) } -
- ); -}; - -const useShowActivateLicenseLink = () => { - const connectionStatus = useConnection(); - const isFullyConnected = useIsFullyConnected(); - const { capabilitiesLoaded, hasBackupPlan } = useCapabilities(); - - // Give people a chance to activate a license if they're not fully connected, - // OR if they have a full user connection but no Backup capabilities - return useMemo( () => { - // At least wait until we know the status of the site and user connections - const connectionLoaded = Object.keys( connectionStatus ).length > 0; - if ( ! connectionLoaded ) { - return false; - } - - if ( ! isFullyConnected ) { - return true; - } - - // Even if we're fully connected, wait until we know the site's capabilities - // before deciding to show an activation link - if ( ! capabilitiesLoaded ) { - return false; - } - - return ! hasBackupPlan; - }, [ connectionStatus, isFullyConnected, hasBackupPlan, capabilitiesLoaded ] ); -}; - -const ActivateLicenseLink = () => { - const activateLicenseUrl = useSelect( select => { - const wpAdminUrl = select( STORE_ID ).getSiteData().adminUrl; - return `${ wpAdminUrl }admin.php?page=my-jetpack#/add-license`; - }, [] ); - - return ( -

- { createInterpolateElement( - __( - 'Already have an existing plan or license key? Click here to get started', - 'jetpack-backup-pkg' - ), - { - a: , - } - ) } -

- ); -}; - -export default Header; diff --git a/projects/packages/backup/src/js/components/Admin/index.js b/projects/packages/backup/src/js/components/Admin/index.js index b0fa4a4bb923..f2061ef7c198 100644 --- a/projects/packages/backup/src/js/components/Admin/index.js +++ b/projects/packages/backup/src/js/components/Admin/index.js @@ -11,18 +11,27 @@ import { useConnectionErrorNotice, ConnectionError } from '@automattic/jetpack-c import { shouldUseInternalLinks } from '@automattic/jetpack-shared-extension-utils'; import apiFetch from '@wordpress/api-fetch'; import { ExternalLink } from '@wordpress/components'; -import { createInterpolateElement, useState, useEffect, useCallback } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; +import { + createInterpolateElement, + useState, + useEffect, + useCallback, + useMemo, +} from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import useAnalytics from '../../hooks/useAnalytics'; import useBackupsState from '../../hooks/useBackupsState'; import useCapabilities from '../../hooks/useCapabilities'; import useConnection from '../../hooks/useConnection'; +import { STORE_ID } from '../../store'; import { Backups, Loading as BackupsLoadingPlaceholder } from '../Backups'; +import { useShowBackUpNow } from '../back-up-now/hooks'; +import { BackupNowButton } from '../back-up-now/index'; import { BackupConnectionScreen } from '../backup-connection-screen'; import { BackupSecondaryAdminConnectionScreen } from '../backup-connection-screen/secondary-admin'; import BackupStorageSpace from '../backup-storage-space'; import ReviewRequest from '../review-request'; -import Header from './header'; import { useIsFullyConnected, useIsSecondaryAdminNotConnected, @@ -51,11 +60,30 @@ const Admin = () => { const { capabilities, capabilitiesError, capabilitiesLoaded, hasBackupPlan } = useCapabilities(); + const showActivateLicenseLink = useShowActivateLicenseLink(); + const showBackUpNowButton = useShowBackUpNow(); + + const headerActions = useMemo( () => { + const items = []; + if ( showActivateLicenseLink ) { + items.push( ); + } + if ( showBackUpNowButton ) { + items.push( + + { __( 'Back up now', 'jetpack-backup-pkg' ) } + + ); + } + return items.length > 0 ? items : null; + }, [ showActivateLicenseLink, showBackUpNowButton ] ); + // If the user is a secondary admin not connected and the site has a backup product, // let's show the login screen. - // @TODO: Review the use case where the site is fully connected but the backup product expires and - // a secondary admin is not connected. Currently it will display the default `Site backups are - // managed by the owner of this site's Jetpack connection.` message. if ( secondaryAdminNotConnected ) { if ( isLoadingBackupProduct ) { return ( @@ -76,10 +104,14 @@ const Admin = () => { return ( } + title={ __( 'Backup', 'jetpack-backup-pkg' ) } + subTitle={ __( + 'Save changes and restore quickly with one-click recovery.', + 'jetpack-backup-pkg' + ) } + actions={ headerActions } useInternalLinks={ shouldUseInternalLinks() } >
@@ -389,4 +421,48 @@ const SecondaryAdminConnectionLayout = ( { children } ) => ( ); +const useShowActivateLicenseLink = () => { + const connectionStatus = useConnection(); + const isFullyConnected = useIsFullyConnected(); + const { capabilitiesLoaded, hasBackupPlan } = useCapabilities(); + + return useMemo( () => { + const connectionLoaded = Object.keys( connectionStatus ).length > 0; + if ( ! connectionLoaded ) { + return false; + } + + if ( ! isFullyConnected ) { + return true; + } + + if ( ! capabilitiesLoaded ) { + return false; + } + + return ! hasBackupPlan; + }, [ connectionStatus, isFullyConnected, hasBackupPlan, capabilitiesLoaded ] ); +}; + +const ActivateLicenseLink = () => { + const activateLicenseUrl = useSelect( select => { + const wpAdminUrl = select( STORE_ID ).getSiteData().adminUrl; + return `${ wpAdminUrl }admin.php?page=my-jetpack#/add-license`; + }, [] ); + + return ( +

+ { createInterpolateElement( + __( + 'Already have an existing plan or license key? Click here to get started', + 'jetpack-backup-pkg' + ), + { + a: , + } + ) } +

+ ); +}; + export default Admin; diff --git a/projects/packages/backup/src/js/components/Admin/style.scss b/projects/packages/backup/src/js/components/Admin/style.scss index 3d802a51c266..748740c2b9c2 100644 --- a/projects/packages/backup/src/js/components/Admin/style.scss +++ b/projects/packages/backup/src/js/components/Admin/style.scss @@ -174,15 +174,3 @@ .jetpack-connection-verified-error { margin: 25px 0; } - -.jetpack-admin-page__header { - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - gap: calc(var(--horizontal-spacing) * 3); - - .jetpack-admin-page__logo { - flex-shrink: 0; - } -} From 2beca821cb425bab71939d281781786ea473d731 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Fri, 27 Feb 2026 12:45:10 -0300 Subject: [PATCH 21/42] Migrate VideoPress main admin page header to unified AdminHeader (#47370) * Migrate videopress main admin page header to unified AdminHeader. Co-Authored-By: Claude Opus 4.6 * Add changelog entry for videopress admin header migration. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- .../changelog/update-normalize-videopress-admin-header | 4 ++++ .../src/client/admin/components/admin-page/index.tsx | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 projects/packages/videopress/changelog/update-normalize-videopress-admin-header diff --git a/projects/packages/videopress/changelog/update-normalize-videopress-admin-header b/projects/packages/videopress/changelog/update-normalize-videopress-admin-header new file mode 100644 index 000000000000..285f5c40cf21 --- /dev/null +++ b/projects/packages/videopress/changelog/update-normalize-videopress-admin-header @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Migrate main admin page header to use unified AdminHeader component from jetpack-components. diff --git a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx index 790ae1b82385..f1abdba4ae11 100644 --- a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx @@ -11,7 +11,6 @@ import { Col, useBreakpointMatch, ContextualUpgradeTrigger, - JetpackVideoPressLogo, } from '@automattic/jetpack-components'; import { useProductCheckoutWorkflow, @@ -194,7 +193,8 @@ const Admin = () => { return ( } + title={ __( 'VideoPress', 'jetpack-videopress-pkg' ) } + subTitle={ __( 'Professional quality, ad-free video hosting.', 'jetpack-videopress-pkg' ) } useInternalLinks={ shouldUseInternalLinks() } >
Date: Fri, 27 Feb 2026 18:24:01 +0100 Subject: [PATCH 22/42] Protect: Migrate admin page header to unified header pattern (#47361) * Protect: Migrate admin page header to use unified header pattern Replace the JetpackProtectLogo header with the new AdminPage `title` prop on both the main admin page and the setup/interstitial route. - Main admin page: swap `header={}` for `title="Protect"` - Setup route: move the "activate license" link from the custom header into the `actions` prop; delete the now-unused styles.module.scss Co-Authored-By: Claude Opus 4.6 * Protect: Fix header/tabs overlap, add subtitle, move tabs to tabs prop - Move tabs from children into the `tabs` prop so they render between the admin-ui header and the content area (fixes overlap with sticky header) - Add subtitle: "Automated malware scanning and firewall protection." - Remove the negative margin-top hack on `.navigation` (was compensating for the old legacy header layout) - Remove unused `Container` import Co-Authored-By: Claude Opus 4.6 * Protect: Add 24px horizontal padding to tabs row Match the admin-ui header's 24px horizontal padding so tabs align with the title text rather than sitting flush against the left edge. Co-Authored-By: Claude Opus 4.6 * Remove admin-ui header border in AdminPage component The :global(.admin-ui-page__header) border-bottom: none rule was present on the My Jetpack branch but missing from the parent normalize branch. This adds it to the shared AdminPage styles so all products using the unified header pattern get the borderless look. Co-Authored-By: Claude Opus 4.6 * Protect: Add subtitle to setup/interstitial page The main admin page had the subtitle but the upsell/setup route was missing it. Add the same "Automated malware scanning and firewall protection." subtitle for consistency. Co-Authored-By: Claude Opus 4.6 * Add changelog entries. --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: Changelog Bot --- .../js-packages/components/changelog/pr-47361 | 4 +++ .../components/admin-page/style.module.scss | 7 +++++ .../changelog/pr-47361 | 4 +++ projects/plugins/backup/changelog/pr-47361 | 4 +++ projects/plugins/boost/changelog/pr-47361 | 4 +++ .../changelog/pr-47361 | 4 +++ projects/plugins/crm/changelog/pr-47361 | 4 +++ projects/plugins/inspect/changelog/pr-47361 | 4 +++ projects/plugins/jetpack/changelog/pr-47361 | 4 +++ .../mu-wpcom-plugin/changelog/pr-47361 | 4 +++ .../paypal-payment-buttons/changelog/pr-47361 | 4 +++ .../changelog/update-protect-unified-header | 4 +++ .../src/js/components/admin-page/index.jsx | 17 +++++----- .../components/admin-page/styles.module.scss | 2 +- .../protect/src/js/routes/setup/index.jsx | 31 +++++++++---------- .../src/js/routes/setup/styles.module.scss | 14 --------- projects/plugins/search/changelog/pr-47361 | 4 +++ projects/plugins/social/changelog/pr-47361 | 4 +++ .../plugins/starter-plugin/changelog/pr-47361 | 4 +++ .../plugins/videopress/changelog/pr-47361 | 4 +++ .../plugins/wpcloud-sso/changelog/pr-47361 | 4 +++ projects/plugins/wpcomsh/changelog/pr-47361 | 4 +++ 22 files changed, 97 insertions(+), 42 deletions(-) create mode 100644 projects/js-packages/components/changelog/pr-47361 create mode 100644 projects/plugins/automattic-for-agencies-client/changelog/pr-47361 create mode 100644 projects/plugins/backup/changelog/pr-47361 create mode 100644 projects/plugins/boost/changelog/pr-47361 create mode 100644 projects/plugins/classic-theme-helper-plugin/changelog/pr-47361 create mode 100644 projects/plugins/crm/changelog/pr-47361 create mode 100644 projects/plugins/inspect/changelog/pr-47361 create mode 100644 projects/plugins/jetpack/changelog/pr-47361 create mode 100644 projects/plugins/mu-wpcom-plugin/changelog/pr-47361 create mode 100644 projects/plugins/paypal-payment-buttons/changelog/pr-47361 create mode 100644 projects/plugins/protect/changelog/update-protect-unified-header delete mode 100644 projects/plugins/protect/src/js/routes/setup/styles.module.scss create mode 100644 projects/plugins/search/changelog/pr-47361 create mode 100644 projects/plugins/social/changelog/pr-47361 create mode 100644 projects/plugins/starter-plugin/changelog/pr-47361 create mode 100644 projects/plugins/videopress/changelog/pr-47361 create mode 100644 projects/plugins/wpcloud-sso/changelog/pr-47361 create mode 100644 projects/plugins/wpcomsh/changelog/pr-47361 diff --git a/projects/js-packages/components/changelog/pr-47361 b/projects/js-packages/components/changelog/pr-47361 new file mode 100644 index 000000000000..e184eac61b47 --- /dev/null +++ b/projects/js-packages/components/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +AdminPage: Remove header border-bottom for a cleaner unified header appearance. diff --git a/projects/js-packages/components/components/admin-page/style.module.scss b/projects/js-packages/components/components/admin-page/style.module.scss index d0a9e3406ac2..9ebc9c16716a 100644 --- a/projects/js-packages/components/components/admin-page/style.module.scss +++ b/projects/js-packages/components/components/admin-page/style.module.scss @@ -9,6 +9,13 @@ background-color: var(--jp-white); } + // Remove the admin-ui header border. Scoped to .admin-page so this only + // applies within our component. Ideally admin-ui would expose a prop or + // CSS custom property for this — revisit if the upstream API changes. + :global(.admin-ui-page__header) { + border-bottom: none; + } + .admin-page-header { display: flex; align-items: center; diff --git a/projects/plugins/automattic-for-agencies-client/changelog/pr-47361 b/projects/plugins/automattic-for-agencies-client/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/automattic-for-agencies-client/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/backup/changelog/pr-47361 b/projects/plugins/backup/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/backup/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/boost/changelog/pr-47361 b/projects/plugins/boost/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/boost/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/classic-theme-helper-plugin/changelog/pr-47361 b/projects/plugins/classic-theme-helper-plugin/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/classic-theme-helper-plugin/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/crm/changelog/pr-47361 b/projects/plugins/crm/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/crm/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/inspect/changelog/pr-47361 b/projects/plugins/inspect/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/inspect/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/jetpack/changelog/pr-47361 b/projects/plugins/jetpack/changelog/pr-47361 new file mode 100644 index 000000000000..0bcdc3966050 --- /dev/null +++ b/projects/plugins/jetpack/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/mu-wpcom-plugin/changelog/pr-47361 b/projects/plugins/mu-wpcom-plugin/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/mu-wpcom-plugin/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/paypal-payment-buttons/changelog/pr-47361 b/projects/plugins/paypal-payment-buttons/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/paypal-payment-buttons/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/protect/changelog/update-protect-unified-header b/projects/plugins/protect/changelog/update-protect-unified-header new file mode 100644 index 000000000000..35119dc59879 --- /dev/null +++ b/projects/plugins/protect/changelog/update-protect-unified-header @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Migrate admin page header to use unified header pattern. diff --git a/projects/plugins/protect/src/js/components/admin-page/index.jsx b/projects/plugins/protect/src/js/components/admin-page/index.jsx index 2f58e8e77cae..1a609d4f1cba 100644 --- a/projects/plugins/protect/src/js/components/admin-page/index.jsx +++ b/projects/plugins/protect/src/js/components/admin-page/index.jsx @@ -1,8 +1,4 @@ -import { - AdminPage as JetpackAdminPage, - Container, - JetpackProtectLogo, -} from '@automattic/jetpack-components'; +import { AdminPage as JetpackAdminPage } from '@automattic/jetpack-components'; import { useConnection } from '@automattic/jetpack-connection'; import { __, sprintf } from '@wordpress/i18n'; import { useEffect } from 'react'; @@ -37,10 +33,9 @@ const AdminPage = ( { children } ) => { return ( } - > - { notice && } - + title={ __( 'Protect', 'jetpack-protect' ) } + subTitle={ __( 'Automated malware scanning and firewall protection.', 'jetpack-protect' ) } + tabs={ { label={ { __( 'Settings', 'jetpack-protect' ) } } /> - + } + > + { notice && } { children } ); diff --git a/projects/plugins/protect/src/js/components/admin-page/styles.module.scss b/projects/plugins/protect/src/js/components/admin-page/styles.module.scss index e35daa7eb302..037be96b89b1 100644 --- a/projects/plugins/protect/src/js/components/admin-page/styles.module.scss +++ b/projects/plugins/protect/src/js/components/admin-page/styles.module.scss @@ -3,7 +3,7 @@ } .navigation { - margin-top: calc(var(--spacing-base) * 3 * -1); // -24px + padding-inline: 24px; } .badge { diff --git a/projects/plugins/protect/src/js/routes/setup/index.jsx b/projects/plugins/protect/src/js/routes/setup/index.jsx index cf64ede35a3b..a40de8bf1f83 100644 --- a/projects/plugins/protect/src/js/routes/setup/index.jsx +++ b/projects/plugins/protect/src/js/routes/setup/index.jsx @@ -4,13 +4,11 @@ import { Col, Container, Text, - JetpackProtectLogo, } from '@automattic/jetpack-components'; import { createInterpolateElement } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import ConnectedPricingTable from '../../components/pricing-table'; import useAnalyticsTracks from '../../hooks/use-analytics-tracks'; -import styles from './styles.module.scss'; const ACTIVATE_LICENSE_URL = 'admin.php?page=my-jetpack#/add-license'; @@ -23,21 +21,20 @@ const SetupRoute = () => { return ( - - - { createInterpolateElement( - __( - 'Already have an existing plan or license key? Click here to get started', - 'jetpack-protect' - ), - { - a: , - } - ) } - -
+ title={ __( 'Protect', 'jetpack-protect' ) } + subTitle={ __( 'Automated malware scanning and firewall protection.', 'jetpack-protect' ) } + actions={ + + { createInterpolateElement( + __( + 'Already have an existing plan or license key? Click here to get started', + 'jetpack-protect' + ), + { + a: , + } + ) } + } > diff --git a/projects/plugins/protect/src/js/routes/setup/styles.module.scss b/projects/plugins/protect/src/js/routes/setup/styles.module.scss deleted file mode 100644 index 675cfc8d8fd1..000000000000 --- a/projects/plugins/protect/src/js/routes/setup/styles.module.scss +++ /dev/null @@ -1,14 +0,0 @@ -.protect-header { - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - width: 100%; -} - -.get-started-button { - - &:focus:not(:disabled) { - box-shadow: none; - } -} diff --git a/projects/plugins/search/changelog/pr-47361 b/projects/plugins/search/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/search/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/social/changelog/pr-47361 b/projects/plugins/social/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/social/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/starter-plugin/changelog/pr-47361 b/projects/plugins/starter-plugin/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/starter-plugin/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/videopress/changelog/pr-47361 b/projects/plugins/videopress/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/videopress/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/wpcloud-sso/changelog/pr-47361 b/projects/plugins/wpcloud-sso/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/wpcloud-sso/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. diff --git a/projects/plugins/wpcomsh/changelog/pr-47361 b/projects/plugins/wpcomsh/changelog/pr-47361 new file mode 100644 index 000000000000..ab4cc817d1c0 --- /dev/null +++ b/projects/plugins/wpcomsh/changelog/pr-47361 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove header border-bottom from the admin page for a cleaner unified header appearance. From 7c92caa22ded80b94839c5c6fb7069863ed9d8cc Mon Sep 17 00:00:00 2001 From: William Viana Date: Fri, 27 Feb 2026 18:31:19 +0100 Subject: [PATCH 23/42] My Jetpack: Migrate admin page header to unified admin-ui Page layout (#47345) * My Jetpack: Migrate admin page header to use unified AdminHeader component Add title prop to AdminPage so it routes through the new AdminHeader, giving My Jetpack the standardized bolt icon + "Jetpack" text header. Co-Authored-By: Claude Opus 4.6 * Remove admin-ui header border in AdminPage Override the admin-ui Page header border-bottom within AdminPage's scoped CSS module. The :global selector is nested inside .admin-page so it only applies within our component, not globally. Co-Authored-By: Claude Opus 4.6 * Add changelog entries. * My Jetpack: Left-align tabs with header (24px padding) The tabs row was centered via max-width + margin: 0 auto from the full-width-container mixin, causing them to float in the middle instead of aligning with the header text. Replace the centered container with a simple 24px left padding to match the admin-ui header padding. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: Changelog Bot --- projects/js-packages/components/changelog/pr-47345 | 4 ++++ .../my-jetpack/_inc/components/my-jetpack-screen/index.jsx | 1 + .../_inc/components/my-jetpack-tab-panel/styles.module.scss | 5 ++--- .../my-jetpack/changelog/update-my-jetpack-unified-header-v2 | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 projects/js-packages/components/changelog/pr-47345 create mode 100644 projects/packages/my-jetpack/changelog/update-my-jetpack-unified-header-v2 diff --git a/projects/js-packages/components/changelog/pr-47345 b/projects/js-packages/components/changelog/pr-47345 new file mode 100644 index 000000000000..60cee58bb233 --- /dev/null +++ b/projects/js-packages/components/changelog/pr-47345 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +AdminPage: Remove admin-ui header border via scoped CSS to support unified admin-ui Page layout. diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx index 2ad30d7f33eb..5271f83e6fe9 100644 --- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx @@ -180,6 +180,7 @@ export default function MyJetpackScreen() { sandboxedDomain={ sandboxedDomain } apiRoot={ apiRoot } apiNonce={ apiNonce } + title={ __( 'Jetpack', 'jetpack-my-jetpack' ) } optionalMenuItems={ isDevVersion && userIsAdmin ? [ resetOptionsMenuItem ] : [] } useInternalLinks={ shouldUseInternalLinks() } className={ styles[ 'my-jetpack-screen' ] } diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-tab-panel/styles.module.scss b/projects/packages/my-jetpack/_inc/components/my-jetpack-tab-panel/styles.module.scss index f4f44ed9ea0a..e04a10c21d8f 100644 --- a/projects/packages/my-jetpack/_inc/components/my-jetpack-tab-panel/styles.module.scss +++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-tab-panel/styles.module.scss @@ -15,7 +15,7 @@ :global(.components-tab-panel__tabs) { position: relative; z-index: 1; - padding-inline-start: 2rem; + padding-inline-start: 24px; margin-block-end: -1px; @media (max-width: gb.$break-medium ) { @@ -65,8 +65,7 @@ margin: 0; :global(.components-tab-panel__tabs) { - - @include full-width-container; + padding-inline-start: 24px; } :global(.components-tab-panel__tab-content) { diff --git a/projects/packages/my-jetpack/changelog/update-my-jetpack-unified-header-v2 b/projects/packages/my-jetpack/changelog/update-my-jetpack-unified-header-v2 new file mode 100644 index 000000000000..179dd8abc914 --- /dev/null +++ b/projects/packages/my-jetpack/changelog/update-my-jetpack-unified-header-v2 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Migrate admin page header to use unified AdminHeader component. From beaa23469031dbad8c35369dcebc3566008e950b Mon Sep 17 00:00:00 2001 From: William Viana Date: Fri, 27 Feb 2026 21:52:16 +0100 Subject: [PATCH 24/42] Forms: Remove admin-ui header border Forms uses @wordpress/admin-ui Page directly (not the shared AdminPage wrapper), so the border-bottom: none override from AdminPage styles doesn't apply. Add the override with higher specificity in Forms' own page styles, and remove the dead .has-tabs block which was never triggered since Forms renders tabs via DataViews, not admin-ui tabs. Co-Authored-By: Claude Opus 4.6 --- .../forms/src/dashboard/components/page/style.scss | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/projects/packages/forms/src/dashboard/components/page/style.scss b/projects/packages/forms/src/dashboard/components/page/style.scss index 4f3e8246a638..1c3f33588458 100644 --- a/projects/packages/forms/src/dashboard/components/page/style.scss +++ b/projects/packages/forms/src/dashboard/components/page/style.scss @@ -26,7 +26,7 @@ flex-direction: column; } -.admin-ui-page__header { +.admin-ui-page .admin-ui-page__header { padding: variables.$grid-unit-10 variables.$grid-unit * 2.5; position: sticky; top: 0; @@ -34,11 +34,7 @@ transition: padding ease-out 0.1s; flex-shrink: 0; z-index: 10; - - &.has-tabs { - padding-block-end: 0; - border-bottom: 1px solid var(--wpds-color-stroke-surface-neutral-weak); - } + border-bottom: none; @container (max-width: 430px) { padding: variables.$grid-unit-15 variables.$grid-unit-30; From 768a77f3907073fd050fe1779c3b17c3f368b736 Mon Sep 17 00:00:00 2001 From: William Viana Date: Sat, 28 Feb 2026 05:30:34 +0100 Subject: [PATCH 25/42] Newsletter: Migrate admin page header to use unified header pattern (#47359) Replace the custom Header component with the new AdminPage `title` and `subTitle` props from the unified header system. This renders the standard admin-ui Page header with the Jetpack bolt logo, "Newsletter Settings" title, and the existing tagline. Delete the now-unused Header component and its stylesheet. Co-authored-by: Claude Opus 4.6 --- .../update-newsletter-unified-header | 4 +++ .../src/settings/components/header.scss | 16 --------- .../src/settings/components/header.tsx | 34 ------------------- .../newsletter/src/settings/index.tsx | 28 ++++++++++++--- 4 files changed, 28 insertions(+), 54 deletions(-) create mode 100644 projects/packages/newsletter/changelog/update-newsletter-unified-header delete mode 100644 projects/packages/newsletter/src/settings/components/header.scss delete mode 100644 projects/packages/newsletter/src/settings/components/header.tsx diff --git a/projects/packages/newsletter/changelog/update-newsletter-unified-header b/projects/packages/newsletter/changelog/update-newsletter-unified-header new file mode 100644 index 000000000000..35119dc59879 --- /dev/null +++ b/projects/packages/newsletter/changelog/update-newsletter-unified-header @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Migrate admin page header to use unified header pattern. diff --git a/projects/packages/newsletter/src/settings/components/header.scss b/projects/packages/newsletter/src/settings/components/header.scss deleted file mode 100644 index c543a99b178c..000000000000 --- a/projects/packages/newsletter/src/settings/components/header.scss +++ /dev/null @@ -1,16 +0,0 @@ -.newsletter-settings__header { - - &-top { - display: flex; - align-items: center; - gap: 1em; - } -} - -.newsletter-settings__title { - margin: 0; -} - -.newsletter-settings__tagline { - margin: 8px 0 0; -} diff --git a/projects/packages/newsletter/src/settings/components/header.tsx b/projects/packages/newsletter/src/settings/components/header.tsx deleted file mode 100644 index ca4587f272e0..000000000000 --- a/projects/packages/newsletter/src/settings/components/header.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/** - * External dependencies - */ -import { JetpackLogo } from '@automattic/jetpack-components'; -import { __ } from '@wordpress/i18n'; - -/** - * Internal dependencies - */ -import './header.scss'; - -/** - * Newsletter Settings Header Component - * - * @return {JSX.Element} The header component. - */ -export function Header(): JSX.Element { - return ( -
-
- -

- { __( 'Newsletter Settings', 'jetpack-newsletter' ) } -

-
-

- { __( - 'Transform your blog posts into newsletters to easily reach your subscribers.', - 'jetpack-newsletter' - ) } -

-
- ); -} diff --git a/projects/packages/newsletter/src/settings/index.tsx b/projects/packages/newsletter/src/settings/index.tsx index 8509b7b84ef9..12caba553419 100644 --- a/projects/packages/newsletter/src/settings/index.tsx +++ b/projects/packages/newsletter/src/settings/index.tsx @@ -17,7 +17,6 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { fetchSettings, updateSettings } from './api'; -import { Header } from './components/header'; import { getNewsletterScriptData } from './script-data'; import { EmailContentSection, @@ -333,7 +332,14 @@ function NewsletterSettingsApp(): JSX.Element | null { if ( isLoading ) { return ( - }> +
@@ -347,7 +353,14 @@ function NewsletterSettingsApp(): JSX.Element | null { if ( error ) { return ( - }> +
@@ -371,7 +384,14 @@ function NewsletterSettingsApp(): JSX.Element | null { const hasWelcomeEmailChanges = Object.keys( welcomeEmailChanges ).length > 0; return ( - }> +
From b746b0f661cb0288c1da4f844faedfa423f0fb57 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Sat, 28 Feb 2026 02:13:25 -0300 Subject: [PATCH 26/42] Update/admin header normalization css override (#47397) * changelog * use global selector to change admin-ui-page__header position to relative --- .../changelog/update-admin-header-normalization-css-override | 4 ++++ .../components/components/admin-page/style.module.scss | 1 + 2 files changed, 5 insertions(+) create mode 100644 projects/js-packages/components/changelog/update-admin-header-normalization-css-override diff --git a/projects/js-packages/components/changelog/update-admin-header-normalization-css-override b/projects/js-packages/components/changelog/update-admin-header-normalization-css-override new file mode 100644 index 000000000000..8fd6ff878335 --- /dev/null +++ b/projects/js-packages/components/changelog/update-admin-header-normalization-css-override @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +AdminPage: override admin-ui header position so it's not sticky diff --git a/projects/js-packages/components/components/admin-page/style.module.scss b/projects/js-packages/components/components/admin-page/style.module.scss index 9ebc9c16716a..4d163e97c2e2 100644 --- a/projects/js-packages/components/components/admin-page/style.module.scss +++ b/projects/js-packages/components/components/admin-page/style.module.scss @@ -14,6 +14,7 @@ // CSS custom property for this — revisit if the upstream API changes. :global(.admin-ui-page__header) { border-bottom: none; + position: relative; } .admin-page-header { From 77abffb46febad6c82104b1a720d824d5a1e7606 Mon Sep 17 00:00:00 2001 From: William Viana Date: Sat, 28 Feb 2026 06:46:40 +0100 Subject: [PATCH 27/42] Boost: Migrate header to lightweight unified pattern (#47392) * Boost: Migrate header to lightweight unified pattern Replace the large custom Jetpack Boost SVG logo with the compact unified header: small Jetpack icon + "Boost" title + subtitle. This matches the pattern used across Protect, My Jetpack, and Settings for consistent product identity. - Swap Logo SVG for JetpackLogo from @automattic/jetpack-components - Add "Boost" title heading and descriptive subtitle - Update styles: compact padding (16px 24px), flex gap, proper focus state - Remove jb-container centering from masthead for left-aligned layout - Hide subtitle on subpages where breadcrumb provides context Co-Authored-By: Claude Opus 4.6 * Add changelog entry for Boost header migration Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- .../src/js/layout/header/header.module.scss | 37 ++++++++++++++----- .../assets/src/js/layout/header/header.tsx | 14 +++++-- .../changelog/update-boost-unified-header | 4 ++ 3 files changed, 43 insertions(+), 12 deletions(-) create mode 100644 projects/plugins/boost/changelog/update-boost-unified-header diff --git a/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss b/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss index 802f98cac3f6..ba9c9162608a 100644 --- a/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss +++ b/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss @@ -1,36 +1,55 @@ .header { background-color: var(--primary-white); - overflow: auto; + padding: 16px 24px 0; + + // Nested under .header for specificity over .jb-dashboard h2 global reset. + .title { + font-family: -apple-system, system-ui, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 1.4; + margin: 0; + color: #1e1e1e; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .subtitle { + font-size: 13px; + color: #757575; + margin: 4px 0 0; + } } .masthead { display: flex; justify-content: space-between; - margin-top: 40px; - margin-bottom: 20px; align-items: center; flex-wrap: wrap; - gap: 24px; + gap: 8px; } .nav-area { display: flex; align-items: center; flex-direction: row; + gap: 8px; } .logo { cursor: pointer; + display: inline-flex; + line-height: 0; - :global(svg) { - height: 42px; - width: 100%; + &:focus { + box-shadow: 0 0 0 2px var(--jp-blue, #3858e9); + border-radius: 2px; + outline: none; } } .chevron { - margin-left: 16px; - margin-right: 16px; width: 24px; height: 24px; padding-top: 2px; diff --git a/projects/plugins/boost/app/assets/src/js/layout/header/header.tsx b/projects/plugins/boost/app/assets/src/js/layout/header/header.tsx index 9be2d54ca1ed..0404112a4cad 100644 --- a/projects/plugins/boost/app/assets/src/js/layout/header/header.tsx +++ b/projects/plugins/boost/app/assets/src/js/layout/header/header.tsx @@ -1,9 +1,10 @@ +import { JetpackLogo } from '@automattic/jetpack-components'; +import { __ } from '@wordpress/i18n'; import clsx from 'clsx'; import type { ReactNode } from 'react'; import styles from './header.module.scss'; import { BackButton } from '$features/ui'; import ChevronRight from '$svg/chevron-right'; -import Logo from '$svg/logo'; import { useNavigate } from 'react-router'; type HeaderProps = { @@ -15,7 +16,7 @@ const Header = ( { subPageTitle = '', children }: HeaderProps ) => { const navigate = useNavigate(); return (
-
+
{ role="button" tabIndex={ 0 } > - +
+

{ __( 'Boost', 'jetpack-boost' ) }

{ subPageTitle !== '' && ( <> @@ -44,6 +46,12 @@ const Header = ( { subPageTitle = '', children }: HeaderProps ) => { { children }
+ { ! subPageTitle && ( +

+ { __( 'Optimize your site performance and loading speed.', 'jetpack-boost' ) } +

+ ) } + { subPageTitle !== '' && (
diff --git a/projects/plugins/boost/changelog/update-boost-unified-header b/projects/plugins/boost/changelog/update-boost-unified-header new file mode 100644 index 000000000000..9585bc38fc36 --- /dev/null +++ b/projects/plugins/boost/changelog/update-boost-unified-header @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Replaced the large Jetpack Boost logo header with a compact unified header pattern (Jetpack icon + title + subtitle) for consistent product identity. From 9b6940a5fa7c9b5120a0fcda8f2b0a0e921557a5 Mon Sep 17 00:00:00 2001 From: Christian Gastrell Date: Sat, 28 Feb 2026 03:20:24 -0300 Subject: [PATCH 28/42] Modules page: Migrate PHP-rendered header to unified pattern (#47398) Replace the large inline Jetpack wordmark SVG with the bolt icon + dynamic title text ("Modules" on the modules page, "Jetpack" elsewhere). Uses the same jp-masthead markup and classes as the React Masthead component. Co-authored-by: Claude Opus 4.6 --- .../admin-pages/class.jetpack-admin-page.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php b/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php index 287e5bc86f88..bc8a27d2e509 100644 --- a/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php +++ b/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php @@ -273,12 +273,22 @@ public static function wrap_ui( $callback, $args = array() ) { ?> "> - +
Date: Mon, 2 Mar 2026 10:37:59 +0000 Subject: [PATCH 29/42] Add changelog entries. --- projects/packages/forms/changelog/pr-47313 | 4 ++++ projects/plugins/jetpack/changelog/pr-47313 | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 projects/packages/forms/changelog/pr-47313 create mode 100644 projects/plugins/jetpack/changelog/pr-47313 diff --git a/projects/packages/forms/changelog/pr-47313 b/projects/packages/forms/changelog/pr-47313 new file mode 100644 index 000000000000..58b595875f98 --- /dev/null +++ b/projects/packages/forms/changelog/pr-47313 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Dashboard: Fix admin page header CSS specificity to prevent style conflicts. diff --git a/projects/plugins/jetpack/changelog/pr-47313 b/projects/plugins/jetpack/changelog/pr-47313 new file mode 100644 index 000000000000..3cdfd982808a --- /dev/null +++ b/projects/plugins/jetpack/changelog/pr-47313 @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Forms: Fix admin page header CSS specificity to prevent style conflicts. From 499846b021c13103ffb821599ddefbe3cdb528cf Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 13:56:02 +0100 Subject: [PATCH 30/42] Apply suggestion from @simison Jetpack product name doesn't need to be translated. Co-authored-by: Mikael Korpela --- .../my-jetpack/_inc/components/my-jetpack-screen/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx index 5271f83e6fe9..e0b43f730184 100644 --- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx @@ -180,7 +180,7 @@ export default function MyJetpackScreen() { sandboxedDomain={ sandboxedDomain } apiRoot={ apiRoot } apiNonce={ apiNonce } - title={ __( 'Jetpack', 'jetpack-my-jetpack' ) } + title="Jetpack" optionalMenuItems={ isDevVersion && userIsAdmin ? [ resetOptionsMenuItem ] : [] } useInternalLinks={ shouldUseInternalLinks() } className={ styles[ 'my-jetpack-screen' ] } From fdc21a8fb3e1a30cd1a7a973f804a200293e6d61 Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 13:56:20 +0100 Subject: [PATCH 31/42] Apply suggestion from @simison Product name doesn't need to be translated. Co-authored-by: Mikael Korpela --- projects/plugins/protect/src/js/routes/setup/index.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/plugins/protect/src/js/routes/setup/index.jsx b/projects/plugins/protect/src/js/routes/setup/index.jsx index a40de8bf1f83..4a1549561f75 100644 --- a/projects/plugins/protect/src/js/routes/setup/index.jsx +++ b/projects/plugins/protect/src/js/routes/setup/index.jsx @@ -22,6 +22,7 @@ const SetupRoute = () => { From ec7b5f673ecaf28a9dec1aa77d4b9a2078b8a63f Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 13:58:25 +0100 Subject: [PATCH 32/42] Apply suggestion from @simison Co-authored-by: Mikael Korpela --- projects/packages/newsletter/src/settings/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/packages/newsletter/src/settings/index.tsx b/projects/packages/newsletter/src/settings/index.tsx index 12caba553419..ea8b3f2829ba 100644 --- a/projects/packages/newsletter/src/settings/index.tsx +++ b/projects/packages/newsletter/src/settings/index.tsx @@ -386,7 +386,7 @@ function NewsletterSettingsApp(): JSX.Element | null { return ( Date: Mon, 2 Mar 2026 14:02:10 +0100 Subject: [PATCH 33/42] Properly fix product names being translated --- projects/packages/newsletter/src/settings/index.tsx | 4 ++-- projects/plugins/protect/src/js/routes/setup/index.jsx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/projects/packages/newsletter/src/settings/index.tsx b/projects/packages/newsletter/src/settings/index.tsx index ea8b3f2829ba..0579dc773231 100644 --- a/projects/packages/newsletter/src/settings/index.tsx +++ b/projects/packages/newsletter/src/settings/index.tsx @@ -334,7 +334,7 @@ function NewsletterSettingsApp(): JSX.Element | null { return ( { return ( Date: Mon, 2 Mar 2026 14:41:28 +0100 Subject: [PATCH 34/42] Apply suggestion from @Copilot Fix grammatical error. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../search/src/dashboard/components/pages/upsell-page/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx index 1946c883446b..a5917f74cae8 100644 --- a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx +++ b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx @@ -112,7 +112,7 @@ export default function UpsellPage( { isLoading = false } ) { moduleName={ __( 'Jetpack Search', 'jetpack-search-pkg' ) } title={ __( 'Search', 'jetpack-search-pkg' ) } subTitle={ __( - 'Help you visitors find exactly what they are looking for.', + 'Help your visitors find exactly what they are looking for.', 'jetpack-search-pkg' ) } actions={ licenseAction } From 87755a0c96ee28efd2544ae975da53099edc7c08 Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 15:23:48 +0100 Subject: [PATCH 35/42] Jetpack Settings: Migrate header to unified pattern and left-align tabs (#47388) * Lightweight header for Jetpack Settings page Replace the full JetpackLogo masthead with a compact bolt icon + route-aware title, matching the admin-ui Page header style. Move the Masthead outside .jp-top-inside so its background spans full width while the inner content uses left-aligned padding. Update SCSS to use sticky positioning and clean typography consistent with admin-ui. Co-Authored-By: Claude Opus 4.6 * Jetpack Settings: Left-align navigation tabs with header The navigation tabs were centered via max-width + margin: 0 auto on .jp-top-inside, while the Masthead header uses full-width 24px padding. Replace the centered container with padding-inline: 24px to align tabs with the header text. Co-Authored-By: Claude Opus 4.6 * Add changelog entry for Jetpack Settings header migration Co-Authored-By: Claude Opus 4.6 * add about page title * rollback some css changes * Hello Dolly compatibility fixes for Jetpack admin pages Clear floated #dolly element so it doesn't overlap admin-ui headers, and set its background to white so it blends with the page. - AdminPage: clear: both on .admin-ui-page, white background on #dolly - My Jetpack: z-index: 2 on #dolly so it stays above the header - Boost: clear: both on .jb-dashboard, white background on #dolly Co-Authored-By: Claude Opus 4.6 * Search: Remove unnecessary global style resets and move JITM notices Remove global *, body, and #wpcontent resets from dashboard-page.scss that were not adding value. Move JITM notices div inside AdminPage content area alongside the connection error container. Co-Authored-By: Claude Opus 4.6 * Newsletter: Add scoped box-sizing and #dolly positioning Scope box-sizing: border-box to #newsletter-settings-root and position #dolly to align with the newsletter settings page layout. Co-Authored-By: Claude Opus 4.6 * Add changelog entries. --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: Christian Gastrell Co-authored-by: github-actions[bot] --- .../js-packages/components/changelog/pr-47388 | 4 + .../components/admin-page/style.module.scss | 11 +++ .../my-jetpack/_inc/style.module.scss | 1 + .../packages/my-jetpack/changelog/pr-47388 | 4 + .../packages/newsletter/changelog/pr-47388 | 4 + .../newsletter/src/settings/style.scss | 9 +++ projects/packages/search/changelog/pr-47388 | 4 + .../components/pages/dashboard-page.jsx | 16 ++-- .../components/pages/dashboard-page.scss | 24 ------ .../app/assets/src/css/main/wp-admin.scss | 5 ++ projects/plugins/boost/changelog/pr-47388 | 4 + .../_inc/client/components/masthead/index.jsx | 34 ++++++++- .../client/components/masthead/style.scss | 73 ++++++------------- projects/plugins/jetpack/_inc/client/main.jsx | 2 +- .../_inc/client/scss/shared/_main.scss | 7 +- .../admin-pages/class.jetpack-admin-page.php | 5 +- ...update-jetpack-settings-lightweight-header | 4 + 17 files changed, 114 insertions(+), 97 deletions(-) create mode 100644 projects/js-packages/components/changelog/pr-47388 create mode 100644 projects/packages/my-jetpack/changelog/pr-47388 create mode 100644 projects/packages/newsletter/changelog/pr-47388 create mode 100644 projects/packages/search/changelog/pr-47388 create mode 100644 projects/plugins/boost/changelog/pr-47388 create mode 100644 projects/plugins/jetpack/changelog/update-jetpack-settings-lightweight-header diff --git a/projects/js-packages/components/changelog/pr-47388 b/projects/js-packages/components/changelog/pr-47388 new file mode 100644 index 000000000000..4e3d1119c995 --- /dev/null +++ b/projects/js-packages/components/changelog/pr-47388 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Admin page: Fix Hello Dolly banner display and clear floats on Jetpack admin pages. diff --git a/projects/js-packages/components/components/admin-page/style.module.scss b/projects/js-packages/components/components/admin-page/style.module.scss index 4d163e97c2e2..c4d13fa6566b 100644 --- a/projects/js-packages/components/components/admin-page/style.module.scss +++ b/projects/js-packages/components/components/admin-page/style.module.scss @@ -17,6 +17,12 @@ position: relative; } + // Normalize admin headers: implementation of admin-ui needs to + // comprehend old wp-admin floating containers, such as Hello Dolly. + :global(.admin-ui-page) { + clear: both; + } + .admin-page-header { display: flex; align-items: center; @@ -34,3 +40,8 @@ color: #fff; } } + +// Make Hello Dolly background white for Jetpack admin pages. +:global(.jetpack-admin-page #dolly) { + background-color: #fff; +} diff --git a/projects/packages/my-jetpack/_inc/style.module.scss b/projects/packages/my-jetpack/_inc/style.module.scss index 784bd30ec7b4..0fbddec17126 100644 --- a/projects/packages/my-jetpack/_inc/style.module.scss +++ b/projects/packages/my-jetpack/_inc/style.module.scss @@ -4,6 +4,7 @@ body.jetpack_page_my-jetpack p#dolly { position: absolute; inset-inline-end: 0; + z-index: 2; @media (max-width: 782px) { padding-inline-end: 10px; diff --git a/projects/packages/my-jetpack/changelog/pr-47388 b/projects/packages/my-jetpack/changelog/pr-47388 new file mode 100644 index 000000000000..807eb64699e9 --- /dev/null +++ b/projects/packages/my-jetpack/changelog/pr-47388 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Fix Hello Dolly banner z-index to prevent overlap on the My Jetpack page. diff --git a/projects/packages/newsletter/changelog/pr-47388 b/projects/packages/newsletter/changelog/pr-47388 new file mode 100644 index 000000000000..6f932d2bc80a --- /dev/null +++ b/projects/packages/newsletter/changelog/pr-47388 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Settings: Fix Hello Dolly banner display and box-sizing on the newsletter settings page. diff --git a/projects/packages/newsletter/src/settings/style.scss b/projects/packages/newsletter/src/settings/style.scss index 7a71ab63674a..bf7d7de243b3 100644 --- a/projects/packages/newsletter/src/settings/style.scss +++ b/projects/packages/newsletter/src/settings/style.scss @@ -1,6 +1,15 @@ // Import dataviews styles for DataForm component @import "@wordpress/dataviews/build-style/style.css"; +#newsletter-settings-root * { + box-sizing: border-box; +} + +.jetpack_page_jetpack-newsletter #dolly { + width: 100%; + text-align: right; +} + .newsletter-settings { max-width: 1200px; margin-inline: auto; diff --git a/projects/packages/search/changelog/pr-47388 b/projects/packages/search/changelog/pr-47388 new file mode 100644 index 000000000000..3051754a9592 --- /dev/null +++ b/projects/packages/search/changelog/pr-47388 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Dashboard: Remove global CSS overrides and move admin notices inside the main container. diff --git a/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx b/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx index 8c88b1591d38..a24582ca5c4a 100644 --- a/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx +++ b/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx @@ -107,11 +107,6 @@ export default function DashboardPage( { isLoading = false } ) { return ( <> - - -
- - { isPageLoading && } { ! isPageLoading && (
@@ -131,13 +126,16 @@ export default function DashboardPage( { isLoading = false } ) { className="uses-new-admin-ui" showFooter={ false } > - { hasConnectionError && ( - + + { hasConnectionError && ( - - ) } + ) } + +
+ + +
-
+
- + +

{ this.getTitle() }

{ offlineNotice } { sandboxedBadge }
{ isWoASite() && }
-
+
); } } diff --git a/projects/plugins/jetpack/_inc/client/components/masthead/style.scss b/projects/plugins/jetpack/_inc/client/components/masthead/style.scss index c151b2ab873d..fad81946af41 100644 --- a/projects/plugins/jetpack/_inc/client/components/masthead/style.scss +++ b/projects/plugins/jetpack/_inc/client/components/masthead/style.scss @@ -1,78 +1,51 @@ -@use "../../scss/functions/rem"; -@use "../../scss/calypso-colors"; -@use "../../scss/mixins/breakpoints"; @use "../../scss/variables/colors"; .jp-masthead { background-color: colors.$white; - text-align: center; - - @media (max-width: rem.convert( 782px ) ) { - padding: 0 rem.convert(24px); - - .jetpack-masterbar & { - padding-left: rem.convert(64px); - } - } + padding: 16px 24px; } .jp-masthead__inside-container { display: flex; - flex-wrap: wrap; - width: 100%; - padding-bottom: rem.convert(6px); + align-items: center; + justify-content: space-between; + gap: 8px; } -.jp-masthead-middle .jp-masthead__inside-container { - margin: 0 auto; - max-width: rem.convert(1040px); - - @media (max-width: 1360px) { - max-width: 95%; - } -} - -.jp-masthead__logo-container { - flex-grow: 0; - flex-shrink: 0; - padding: rem.convert(40px) 0 rem.convert(20px) 0; - - @include breakpoints.breakpoint( "<480px" ) { - padding: rem.convert(11px) 0 0; - margin-right: rem.convert(16px); - } +.jp-masthead__title-container { + display: flex; + align-items: center; + gap: 8px; } .jp-masthead__logo-link { - display: inline-block; + display: inline-flex; outline: none; - vertical-align: middle; &:focus { - line-height: 0; // fixes rectangle gap box-shadow: 0 0 0 2px colors.$blue-light; - } - - + code { - margin: 0 10px; - padding: 5px 9px; border-radius: 2px; - background: #e6ecf1; - color: #647a88; } } +.jp-masthead__title { + font-family: -apple-system, system-ui, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 1.4; + margin: 0; + color: #1e1e1e; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .jp-masthead__nav { display: flex; flex-wrap: nowrap; - flex-grow: 1; flex-shrink: 0; - text-align: right; - margin-top: rem.convert(6px); - padding: rem.convert(4px) 0; .dops-button-group { - flex-grow: 1; align-self: center; /* This fixes an unwanted space between the buttons in the @@ -83,10 +56,6 @@ font-size: 0; } - @include breakpoints.breakpoint( "<480px" ) { - text-align: left; - } - .dops-button { background: colors.$white; color: colors.$black; diff --git a/projects/plugins/jetpack/_inc/client/main.jsx b/projects/plugins/jetpack/_inc/client/main.jsx index b78168ca052c..c13c4138b0e8 100644 --- a/projects/plugins/jetpack/_inc/client/main.jsx +++ b/projects/plugins/jetpack/_inc/client/main.jsx @@ -845,8 +845,8 @@ class Main extends Component { { showHeader && (
+ { this.shouldShowMasthead() && }
- { this.shouldShowMasthead() && } { this.shouldShowRewindStatus() && } { mainNav }
diff --git a/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss b/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss index a13ac7d4448b..c894953a28fa 100644 --- a/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss +++ b/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss @@ -76,12 +76,7 @@ width: 100%; .jp-top-inside { - max-width: rem.convert(1040px); - margin: 0 auto; - - @media (max-width: 1360px) { - max-width: 95%; - } + padding-inline: 24px; .jitm-banner.jitm-card { margin: 0 0 24px; diff --git a/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php b/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php index bc8a27d2e509..4e5453f6c28e 100644 --- a/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php +++ b/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php @@ -282,8 +282,11 @@ public static function wrap_ui( $callback, $args = array() ) {
-

{ __( 'Boost', 'jetpack-boost' ) }

+

+ { 'Boost' /** "Boost" is a product name, do not translate. */ } +

{ subPageTitle !== '' && ( <> From 3965be60db7c9c03945a701df9d62f20f760bc84 Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 16:30:10 +0100 Subject: [PATCH 37/42] Boost: Match header spacing with admin-ui Page layout Add flex column layout with 8px gap to match admin-ui Page header's spacing between title and subtitle. Also add padding-block-end: 8px on subtitle to match the admin-ui-page__header-subtitle style. This brings the total header height to 96px, matching Social, Backup, etc. Co-Authored-By: Claude Opus 4.6 --- .../app/assets/src/js/layout/header/header.module.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss b/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss index 697b17f3ed81..522d17070389 100644 --- a/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss +++ b/projects/plugins/boost/app/assets/src/js/layout/header/header.module.scss @@ -1,6 +1,9 @@ .header { background-color: var(--primary-white); padding: 16px 24px; + display: flex; + flex-direction: column; + gap: 8px; // Nested under .header for specificity over .jb-dashboard h2 global reset. .title { @@ -18,7 +21,8 @@ .subtitle { font-size: 13px; color: #757575; - margin: 4px 0 0; + margin: 0; + padding-block-end: 8px; } } From 7ce445a9fac4058eb2f285927aada753ace9f42a Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 16:40:05 +0100 Subject: [PATCH 38/42] Boost: Add white background to mount point for Hello Dolly compatibility The #jb-admin-settings React mount point had a transparent background, so the area behind the floated #dolly element showed the gray wp-admin background instead of white. Give the mount point a white background to match how AdminPage-based products handle this. Co-Authored-By: Claude Opus 4.6 --- projects/plugins/boost/app/assets/src/css/main/wp-admin.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/plugins/boost/app/assets/src/css/main/wp-admin.scss b/projects/plugins/boost/app/assets/src/css/main/wp-admin.scss index 6238c592fdcc..6698fbb92f9b 100644 --- a/projects/plugins/boost/app/assets/src/css/main/wp-admin.scss +++ b/projects/plugins/boost/app/assets/src/css/main/wp-admin.scss @@ -112,6 +112,10 @@ p { min-height: 100vh; } +.jetpack_page_jetpack-boost #jb-admin-settings { + background: #fff; +} + .jetpack_page_jetpack-boost #dolly { background: #fff; } From f7e1852d6c468b605b5e3abf223145caa4236dec Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 16:40:23 +0100 Subject: [PATCH 39/42] Settings: Remove Hello Dolly border-bottom to match unified header The existing #dolly style had a border-bottom that created a visible horizontal line between the Hello Dolly text and the Jetpack header. Remove it so the dolly area blends seamlessly with the header below. Co-Authored-By: Claude Opus 4.6 --- projects/plugins/jetpack/_inc/client/scss/shared/_main.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss b/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss index c894953a28fa..aea1038af59d 100644 --- a/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss +++ b/projects/plugins/jetpack/_inc/client/scss/shared/_main.scss @@ -55,7 +55,7 @@ font-size: rem.convert(12px); font-style: italic; color: colors.$gray; - border-bottom: 1px color.adjust(colors.$gray, $lightness: 30%) solid; + border-bottom: none; @include breakpoints.breakpoint( "<660px" ) { display: none; From e86c0444dcc4285dcbeda9a7621562e394384510 Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 16:46:35 +0100 Subject: [PATCH 40/42] Settings: Also fix Hello Dolly border in admin-static.scss The previous commit fixed border-bottom in _main.scss (.jetpack-pagestyles #dolly), but admin-static.scss has a duplicate .wp-admin #dolly rule that loads later in the CSS bundle, overriding the fix via cascade order. Co-Authored-By: Claude Opus 4.6 --- .../plugins/jetpack/_inc/client/scss/shared/admin-static.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/_inc/client/scss/shared/admin-static.scss b/projects/plugins/jetpack/_inc/client/scss/shared/admin-static.scss index a7beefc57edf..2038583c97f6 100644 --- a/projects/plugins/jetpack/_inc/client/scss/shared/admin-static.scss +++ b/projects/plugins/jetpack/_inc/client/scss/shared/admin-static.scss @@ -213,5 +213,5 @@ font-size: 0.75rem; font-style: italic; color: #87a6bc; - border-bottom: 1px #e9eff3 solid; + border-bottom: none; } From 913f7d1d2e83eb0d1241a27e8fc159499d9c9ad8 Mon Sep 17 00:00:00 2001 From: William Viana Date: Mon, 2 Mar 2026 17:07:34 +0100 Subject: [PATCH 41/42] Stop translating product names across all admin pages Product names (Boost, Protect, Search, Social, Backup, VideoPress, Jetpack, etc.) are brand names and should not be wrapped in translation functions. - Remove moduleName props from AdminPage/JetpackFooter callers so the default "Jetpack" kicks in for footers - Change translated title props to plain strings with do-not-translate comments - Fix default moduleName in AdminPage and JetpackFooter components to use plain strings instead of __() - Fix translated product names in Boost image-guide PHP and Jetpack Stats banner Co-Authored-By: Claude Opus 4.6 --- .../js-packages/components/components/admin-page/index.tsx | 2 +- .../components/components/jetpack-footer/index.tsx | 2 +- projects/packages/backup/src/js/components/Admin/index.js | 5 ++--- .../packages/publicize/_inc/components/admin-page/index.tsx | 4 ++-- .../src/dashboard/components/pages/dashboard-page.jsx | 3 +-- .../src/dashboard/components/pages/upsell-page/index.jsx | 3 +-- .../src/client/admin/components/admin-page/index.tsx | 3 +-- .../client/admin/components/edit-video-details/index.tsx | 1 - .../boost/app/modules/image-guide/class-image-guide.php | 2 +- .../plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx | 6 +++++- .../protect/changelog/update-normalize-admin-page-headers | 4 ++++ .../plugins/protect/src/js/components/admin-page/index.jsx | 3 +-- projects/plugins/protect/src/js/routes/setup/index.jsx | 1 - 13 files changed, 20 insertions(+), 19 deletions(-) create mode 100644 projects/plugins/protect/changelog/update-normalize-admin-page-headers diff --git a/projects/js-packages/components/components/admin-page/index.tsx b/projects/js-packages/components/components/admin-page/index.tsx index 95fad8ebb4af..08a2ca553117 100644 --- a/projects/js-packages/components/components/admin-page/index.tsx +++ b/projects/js-packages/components/components/admin-page/index.tsx @@ -27,7 +27,7 @@ import type { FC, ReactNode } from 'react'; const AdminPage: FC< AdminPageProps > = ( { children, className, - moduleName = __( 'Jetpack', 'jetpack-components' ), + moduleName = 'Jetpack' /** "Jetpack" is a product name, do not translate. */, moduleNameHref, showHeader = true, showFooter = true, diff --git a/projects/js-packages/components/components/jetpack-footer/index.tsx b/projects/js-packages/components/components/jetpack-footer/index.tsx index 4cfc24e15c3d..eb58a8d81652 100644 --- a/projects/js-packages/components/components/jetpack-footer/index.tsx +++ b/projects/js-packages/components/components/jetpack-footer/index.tsx @@ -33,7 +33,7 @@ const ExternalIcon: FC = () => ( * @return {ReactNode} JetpackFooter component. */ const JetpackFooter: FC< JetpackFooterProps > = ( { - moduleName = __( 'Jetpack', 'jetpack-components' ), + moduleName = 'Jetpack' /** "Jetpack" is a product name, do not translate. */, className, moduleNameHref = 'https://jetpack.com', menu, diff --git a/projects/packages/backup/src/js/components/Admin/index.js b/projects/packages/backup/src/js/components/Admin/index.js index f2061ef7c198..087bd4dec007 100644 --- a/projects/packages/backup/src/js/components/Admin/index.js +++ b/projects/packages/backup/src/js/components/Admin/index.js @@ -105,8 +105,7 @@ const Admin = () => { return ( ( - + { children } diff --git a/projects/packages/publicize/_inc/components/admin-page/index.tsx b/projects/packages/publicize/_inc/components/admin-page/index.tsx index b0ef6e2d3ca1..9da61e83825d 100644 --- a/projects/packages/publicize/_inc/components/admin-page/index.tsx +++ b/projects/packages/publicize/_inc/components/admin-page/index.tsx @@ -66,7 +66,7 @@ export const SocialAdminPage = () => { return ( { return ( {
diff --git a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx index a5917f74cae8..60f61ba04c62 100644 --- a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx +++ b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx @@ -109,8 +109,7 @@ export default function UpsellPage( { isLoading = false } ) { { isPageLoading && } { ! isPageLoading && ( { return ( diff --git a/projects/packages/videopress/src/client/admin/components/edit-video-details/index.tsx b/projects/packages/videopress/src/client/admin/components/edit-video-details/index.tsx index 5f43b70f81b6..94f5b742ab8d 100644 --- a/projects/packages/videopress/src/client/admin/components/edit-video-details/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/edit-video-details/index.tsx @@ -278,7 +278,6 @@ const EditVideoDetails = () => { ) }
diff --git a/projects/plugins/boost/app/modules/image-guide/class-image-guide.php b/projects/plugins/boost/app/modules/image-guide/class-image-guide.php index bbcbb9a63a60..e2600d41154d 100644 --- a/projects/plugins/boost/app/modules/image-guide/class-image-guide.php +++ b/projects/plugins/boost/app/modules/image-guide/class-image-guide.php @@ -68,7 +68,7 @@ public function add_to_adminbar( $bar ) { 'id' => 'jetpack-boost-guide', 'parent' => null, 'group' => null, - 'title' => __( 'Jetpack Boost', 'jetpack-boost' ), + 'title' => 'Jetpack Boost', // "Jetpack Boost" is a product name, do not translate. 'href' => admin_url( 'admin.php?page=' . Admin::MENU_SLUG ), 'meta' => array( 'target' => '_self', diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx b/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx index f499310d65cd..600a0ef0d0f5 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx @@ -358,7 +358,11 @@ export class DashStats extends Component { if ( 'inactive' === this.props.getModuleOverride( 'stats' ) ) { return (
- +
); } diff --git a/projects/plugins/protect/changelog/update-normalize-admin-page-headers b/projects/plugins/protect/changelog/update-normalize-admin-page-headers new file mode 100644 index 000000000000..be99a905f44d --- /dev/null +++ b/projects/plugins/protect/changelog/update-normalize-admin-page-headers @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Remove translated product names from admin page headers and footers. diff --git a/projects/plugins/protect/src/js/components/admin-page/index.jsx b/projects/plugins/protect/src/js/components/admin-page/index.jsx index 1a609d4f1cba..d5cf4a2913a9 100644 --- a/projects/plugins/protect/src/js/components/admin-page/index.jsx +++ b/projects/plugins/protect/src/js/components/admin-page/index.jsx @@ -32,8 +32,7 @@ const AdminPage = ( { children } ) => { return ( diff --git a/projects/plugins/protect/src/js/routes/setup/index.jsx b/projects/plugins/protect/src/js/routes/setup/index.jsx index d0549ac38ec0..2935599923ff 100644 --- a/projects/plugins/protect/src/js/routes/setup/index.jsx +++ b/projects/plugins/protect/src/js/routes/setup/index.jsx @@ -20,7 +20,6 @@ const SetupRoute = () => { return ( Date: Mon, 2 Mar 2026 17:10:44 +0100 Subject: [PATCH 42/42] Fix remaining translated product names flagged in review - Newsletter: remove moduleName prop and MODULE_NAME constant so the default "Jetpack" footer kicks in - Jetpack admin page PHP: use plain echo for "Jetpack" product name instead of esc_html_e() Co-Authored-By: Claude Opus 4.6 --- projects/packages/newsletter/src/settings/index.tsx | 5 ----- .../_inc/lib/admin-pages/class.jetpack-admin-page.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/projects/packages/newsletter/src/settings/index.tsx b/projects/packages/newsletter/src/settings/index.tsx index 0579dc773231..02b82d8e84b7 100644 --- a/projects/packages/newsletter/src/settings/index.tsx +++ b/projects/packages/newsletter/src/settings/index.tsx @@ -32,8 +32,6 @@ import { import type { NewsletterSettings } from './types'; import './style.scss'; -const MODULE_NAME = __( 'Jetpack Newsletter', 'jetpack-newsletter' ); - /** * Normalize settings from API response * @@ -333,7 +331,6 @@ function NewsletterSettingsApp(): JSX.Element | null { if ( isLoading ) { return (