-
Notifications
You must be signed in to change notification settings - Fork 872
Normalize admin page headers with unified AdminHeader wrapping @wordpress/admin-ui #47313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4a1a98a
e3b4a14
422ea27
afacc5f
5a883b6
cedd3ab
3664f98
ef758cd
a7f1b2a
f47248b
fbf0627
caa6268
fcb207d
a2759a1
e73635f
8954b90
58b4850
271a54b
275b400
3e040f4
2beca82
fd86027
7c92caa
beaa234
768a77f
b746b0f
77abffb
9b6940a
25ad026
499846b
fdc21a8
ec7b5f6
748fbb2
518a7ab
87755a0
61c745f
3965be6
7ce445a
f7e1852
e86c044
913f7d1
176cef3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: patch | ||
| Type: changed | ||
|
|
||
| Replace admin-ui CSS proxy file with direct import, now that webpack-config handles bundling centrally. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: patch | ||
| Type: changed | ||
|
|
||
| AdminPage: Remove admin-ui header border via scoped CSS to support unified admin-ui Page layout. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: patch | ||
| Type: changed | ||
|
|
||
| AdminPage: Remove header border-bottom for a cleaner unified header appearance. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: patch | ||
| Type: fixed | ||
|
|
||
| Admin page: Fix Hello Dolly banner display and clear floats on Jetpack admin pages. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: patch | ||
| Type: changed | ||
|
|
||
| AdminPage: override admin-ui header position so it's not sticky |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: minor | ||
| Type: added | ||
|
|
||
| Add AdminHeader component wrapping @wordpress/admin-ui Page for unified admin page headers. | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,10 @@ | ||||||||||||||||||||||||||||||||||||||||||
| 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'; | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -21,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, | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -32,6 +38,11 @@ const AdminPage: FC< AdminPageProps > = ( { | |||||||||||||||||||||||||||||||||||||||||
| apiNonce = '', | ||||||||||||||||||||||||||||||||||||||||||
| optionalMenuItems, | ||||||||||||||||||||||||||||||||||||||||||
| header, | ||||||||||||||||||||||||||||||||||||||||||
| title, | ||||||||||||||||||||||||||||||||||||||||||
| subTitle, | ||||||||||||||||||||||||||||||||||||||||||
| logo, | ||||||||||||||||||||||||||||||||||||||||||
| actions, | ||||||||||||||||||||||||||||||||||||||||||
| tabs, | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| tabs, | |
| tabs, | |
| breadcrumbs, | |
| badges, |
Copilot
AI
Feb 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment mentions a known issue where the inner Heading causes double h2 wrapping because Page's Header also wraps the title in a Heading. While the comment references a Gutenberg PR (#75899) that should fix this, the workaround creates invalid HTML (nested h2 elements) which could cause accessibility and SEO issues. Consider adding a TODO comment with a tracking task to remove the inner Heading once the upstream fix lands, or explore alternative approaches that don't result in invalid HTML in the meantime.
| // Note: The inner Heading causes a double h2 wrapping because Page's Header | |
| // also wraps title in a Heading. This is a known issue — the inner Heading is | |
| // needed until https://github.com/WordPress/gutenberg/pull/75899 fixes | |
| // non-string title rendering in admin-ui. Once that lands, remove the Heading | |
| // here and pass the plain HStack with a string child. | |
| const composedTitle = title ? ( | |
| <HStack spacing={ 2 } justify="left"> | |
| { logo || <JetpackLogo showText={ false } height={ 20 } /> } | |
| <Heading as="h2" level={ 3 } weight={ 500 } truncate> | |
| // Note: The inner Heading previously caused a double h2 wrapping because Page's Header | |
| // also wraps title in a Heading. To avoid invalid nested headings while Gutenberg is | |
| // still fixing non-string title rendering in admin-ui, we render the inner Heading | |
| // as a non-heading element for styling only. | |
| // TODO: Once https://github.com/WordPress/gutenberg/pull/75899 lands and non-string | |
| // titles are supported, remove the inner Heading here and pass the plain HStack | |
| // with a string child instead. | |
| const composedTitle = title ? ( | |
| <HStack spacing={ 2 } justify="left"> | |
| { logo || <JetpackLogo showText={ false } height={ 20 } /> } | |
| <Heading as="span" weight={ 500 } truncate> |
Copilot
AI
Mar 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code passes a JSX element (an HStack containing an inner Heading as="h2") as the title prop to the Page component from @wordpress/admin-ui. The comment acknowledges this creates a double h2 heading (because Page's header internally also wraps the title in a Heading), which is an accessibility issue — it creates invalid nesting of h2 inside another h2. While the code comment references a Gutenberg PR for a future fix, it's worth noting this creates an accessibility violation in the current state and should be tracked as a known issue until the upstream fix lands.
Copilot
AI
Feb 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The root div doesn't have a marker class to identify when the new admin-ui Page component is being used. The related PR #47332 mentions using :not(:has(.uses-new-admin-ui)) for scoping styles. Consider adding a class like 'uses-new-admin-ui' to the root div when the new header path is taken (when title is provided) to help with CSS scoping and debugging.
| <div className={ rootClassName }> | |
| <div className={ clsx( rootClassName, 'uses-new-admin-ui' ) }> |
Copilot
AI
Feb 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tabs prop is rendered as { tabs } directly inside the Page component as children (content area) rather than being passed as the tabs prop to @wordpress/admin-ui's Page component. The @wordpress/admin-ui Page component accepts a tabs prop to render tab navigation inside the sticky header (as seen in the forms package's Page component). By passing tabs as children, the tab navigation will end up in the scrollable content area rather than in the sticky header. For the Protect plugin which passes a Tabs component with padding-inline: 24px styling, this could cause visual layout issues.
Consider passing tabs as a prop to Page directly: <Page tabs={ tabs } ...>, which would position the tabs in the header as intended.
| > | |
| { tabs } | |
| tabs={ tabs } | |
| > |
Copilot
AI
Feb 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR title and description mention introducing a unified "AdminHeader component" but no separate AdminHeader component exists. The header functionality is integrated directly into the AdminPage component. While the implementation is functionally correct, consider updating the PR title and description to reflect that AdminPage was extended to support unified headers via the @wordpress/admin-ui Page component, rather than adding a new AdminHeader component.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,20 @@ | |
| 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; | ||
| position: relative; | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same note about a follow-up todo as https://github.com/Automattic/jetpack/pull/47313/changes#r2872209339 |
||
|
|
||
| // 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; | ||
|
|
@@ -26,3 +40,8 @@ | |
| color: #fff; | ||
| } | ||
| } | ||
|
|
||
| // Make Hello Dolly background white for Jetpack admin pages. | ||
| :global(.jetpack-admin-page #dolly) { | ||
| background-color: #fff; | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,10 +18,37 @@ export type AdminPageProps = { | |||||||||||||||||||||||||
| showHeader?: boolean; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Custom header. Optional | ||||||||||||||||||||||||||
| * Custom header. Optional. | ||||||||||||||||||||||||||
| * @deprecated Use `title` and `subTitle` props instead for the unified header. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| header?: ReactNode; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Product title displayed in the unified header (e.g. "Social", "Backup"). | ||||||||||||||||||||||||||
| * When provided, renders the admin-ui Page header instead of the legacy header slot. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| title?: string; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Optional tagline displayed below the title in the unified header. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| subTitle?: 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; | ||||||||||||||||||||||||||
CGastrell marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+26
to
+50
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Comment on lines
+26
to
+51
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| /** | |
| /** | |
| * Breadcrumb navigation displayed in the unified header. | |
| */ | |
| breadcrumbs?: ReactNode; | |
| /** | |
| * Badge elements displayed alongside the title in the unified header. | |
| */ | |
| badges?: ReactNode; | |
| /** |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 }/**` ), | ||
| } ) ) { | ||
|
Comment on lines
+53
to
56
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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, | ||
| }, | ||
|
Comment on lines
+146
to
+151
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
| }; | ||
|
|
||
| const DependencyExtractionPlugin = ( { requestMap, ...options } = {} ) => { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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, | ||
|
Comment on lines
+30
to
+32
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate a bit more why we needed this change int his PR? |
||
| use: [ | ||
| MiniCssExtractLoader( options.MiniCssExtractLoader ), | ||
| CssLoader( { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: patch | ||
| Type: changed | ||
|
|
||
| Migrate admin page header to use unified AdminHeader component from jetpack-components. |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changelog mentions "Add AdminHeader component" but there is no separate AdminHeader component in the codebase. The functionality is integrated directly into the AdminPage component via the new title/subTitle/logo/actions/tabs props. The changelog should be updated to accurately reflect that AdminPage was extended rather than a new AdminHeader component being added.