AdminPage: stick JetpackFooter to the bottom of the viewport#49201
AdminPage: stick JetpackFooter to the bottom of the viewport#49201angelablake wants to merge 1 commit into
Conversation
Make `.admin-page` a flex column with `min-height: calc(100vh - --wp-admin--admin-bar--height)` and give `.jetpack-footer` `margin-top: auto`, so every product using the shared `AdminPage` gets a consistent sticky-footer layout instead of having the footer float up against short content. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! |
Code Coverage SummaryThis PR did not change code coverage! That could be good or bad, depending on the situation. Everything covered before, and still is? Great! Nothing was covered before? Not so great. 🤷 |
|
Pretty sure there's a way to do this already without adding all these styles in the admin page component. 🤔 @CGastrell likely knows more. 👋 |
| // comprehend old wp-admin floating containers, such as Hello Dolly | ||
| // (`clear: both`). Also make the Page a flex column that fills the | ||
| // wp-admin content area so `JetpackFooter` can stick to the bottom. | ||
| :global(.admin-ui-page) { |
There was a problem hiding this comment.
Using the internal CSS selector from admin-ui will break in future and cannot be used as a stable API.
| // root, and the footer claims any leftover space via `margin-top: auto`. | ||
| display: flex; | ||
| flex-direction: column; | ||
| min-height: calc(100vh - var(--wp-admin--admin-bar--height, 32px)); |
There was a problem hiding this comment.
Likely works with variable, but noting that the default will be 48px when on mobile.
|
Thanks for splitting this out, @angelablake ! Before this lands I want to flag two things: it overlaps with layout infrastructure we already have, and it couples the shared The
|
|
Thanks @CGastrell ! I'll take your suggestion. |
Drops the SEO admin page's reliance on admin-ui's internal `.admin-ui-page*` classes — which are hashed in the standalone `@wordpress/admin-ui` build and only literal in some WP core bundles — in favor of the stable `.jp-admin-page__page` hook that `<AdminPage>` forwards onto admin-ui's `<Page>` and the shared `jetpack-admin-page-layout-wp-build` mixin from `@automattic/jetpack-base-styles`. This also delivers the sticky `JetpackFooter` behavior previously proposed as a one-off in `<AdminPage>`'s own SCSS — the shared mixin already pins the footer to the bottom of the viewport via the stable selector chain, which is the same path Newsletter / Protect / Backup / Search / VideoPress take. See CGastrell's review on #49201. Per-page opt-in lives in a new non-module `_inc/admin-page-layout.scss` (matching the Newsletter pattern), so the mixin's body-class scope stays out of the CSS-modules file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
One more thing while I'm here — also addressed CGastrell's "one more heads-up" paragraph in the same commit: migrated the Closing this PR — the work moves into #49203. (Posted via Claude on Angela's behalf.) |
Drops the SEO admin page's reliance on admin-ui's internal `.admin-ui-page*` classes — which are hashed in the standalone `@wordpress/admin-ui` build and only literal in some WP core bundles — in favor of the stable `.jp-admin-page__page` hook that `<AdminPage>` forwards onto admin-ui's `<Page>` and the shared `jetpack-admin-page-layout-wp-build` mixin from `@automattic/jetpack-base-styles`. This also delivers the sticky `JetpackFooter` behavior previously proposed as a one-off in `<AdminPage>`'s own SCSS — the shared mixin already pins the footer to the bottom of the viewport via the stable selector chain, which is the same path Newsletter / Protect / Backup / Search / VideoPress take. See CGastrell's review on #49201. Per-page opt-in lives in a new non-module `_inc/admin-page-layout.scss` (matching the Newsletter pattern), so the mixin's body-class scope stays out of the CSS-modules file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#49203) * Components: add BoundedLayout layout primitive Add a shared `BoundedLayout` wrapper to `@automattic/jetpack-components` with two MSD-aligned presets — `compact` (660px) and `wide` (1344px) — so products can keep visual alignment across Overview / Settings / Dashboard screens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Jetpack SEO: introduce package foundation and Site visibility Overview Adds a new `automattic/jetpack-seo` package that mounts a React admin at `wp-admin/admin.php?page=jetpack-seo`. Menu item gates on the `seo-tools` module being active. This PR is the first of a staged series introducing the Jetpack SEO product; it ships only the package scaffold and the Overview screen's Site visibility card. Follow-up PRs add the Settings, Per-post SEO (Content), and AI tabs, along with their REST writers and respective Overview cards. New package - PHP: `Initializer` (admin menu registration + asset enqueue, gated on `seo-tools`), `REST_Controller` exposing `/jetpack-seo/v1/overview` only. - React SPA: `createHashRouter` + `RouterProvider`, `AdminPage` from `@automattic/jetpack-components`, TanStack Query for server state. - Single screen: Overview with a Site visibility card (search-engines allowed, sitemap active/inactive, SEO tools active/inactive). All other Overview cards land with the PRs that own their underlying features. Jetpack plugin wiring - `class.jetpack.php`: load the new package in `late_initialization()`. - `composer.json`: require `automattic/jetpack-seo`. Co-Authored-By: Angela Blake <angela.blake@a8c.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * SEO foundation: fix typecheck, project structure, and changelog format CI feedback from the initial push surfaced four classes of issues: - Typecheck failures from the partial scope: - Remove the unused "Manage settings" button from SiteVisibilityCard (referenced the trimmed JetpackSeoRoutes.Settings constant). The button returns in PR #3 when the Settings tab lands as its deep-link target. - Update useSimpleMutation onSuccess to TanStack Query v5's 4-arg form (data, variables, onMutateResult, context) — v5 added onMutateResult between variables and context. - Project-structure expectations for a new package: - Add .phan/config.php so static analysis recognises the package's PHP. - Add changelog/.gitkeep so the changelog directory survives release. - Changelog format: - Reset CHANGELOG.md to the keep-a-changelog header only (no pre-release `[0.1.0-alpha] - unreleased` block — pending entries live in changelog/). - Change the Jetpack-plugin changelog Type from `added` to `enhancement` (plugin/jetpack uses major|enhancement|compat|bugfix|other, not the keep-a-changelog vocabulary the packages use). Co-Authored-By: Filipe Varela <filipe@automattic.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * SEO foundation: address Phan + scope-leftover issues CI surfaced two more issues on the foundation PR: - Initializer still called `LLMS_Txt::init()`, `AI_Crawlers::init()`, and `Schema_Builder::init()` — those classes live in later PRs (#4 and #6). Remove the calls; they return when their classes land. - Initializer registered `maybe_redirect_legacy_surfaces` on `admin_init`, which would have 301-redirected `?page=jetpack&tab=seo|traffic` to the new admin page. But the legacy Traffic page is still live on trunk in this PR's window, so redirecting now strands users mid-task. Remove the hook + the method entirely; the redirect lands in PR #5b alongside the discoverability banner and the actual deletion of the legacy surfaces. - Phan can't see `Jetpack_SEO_Utils` (lives in plugins/jetpack, not this package). The runtime-safety `class_exists` checks already guard the calls; add `@phan-suppress-next-line PhanUndeclaredClassMethod` so static analysis stops flagging them. Co-Authored-By: Filipe Varela <filipe@automattic.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * SEO foundation: opt into shared admin-page-layout mixin Drops the SEO admin page's reliance on admin-ui's internal `.admin-ui-page*` classes — which are hashed in the standalone `@wordpress/admin-ui` build and only literal in some WP core bundles — in favor of the stable `.jp-admin-page__page` hook that `<AdminPage>` forwards onto admin-ui's `<Page>` and the shared `jetpack-admin-page-layout-wp-build` mixin from `@automattic/jetpack-base-styles`. This also delivers the sticky `JetpackFooter` behavior previously proposed as a one-off in `<AdminPage>`'s own SCSS — the shared mixin already pins the footer to the bottom of the viewport via the stable selector chain, which is the same path Newsletter / Protect / Backup / Search / VideoPress take. See CGastrell's review on #49201. Per-page opt-in lives in a new non-module `_inc/admin-page-layout.scss` (matching the Newsletter pattern), so the mixin's body-class scope stays out of the CSS-modules file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * SEO foundation: ship PHPUnit + jest configs across the CI matrix The first PR push only included `phpunit.11.xml.dist`, so CI's PHP test matrix (PHP 7.4–8.5) failed at config-read because PHPUnit 8/9/12 had no config to select. Adds `phpunit.8.xml.dist`, `phpunit.9.xml.dist`, and `phpunit.12.xml.dist`, mirrored verbatim from `packages/ip`'s set. Adds a `test` script + a `tests/jest.config.js` so the JS-tests CI job doesn't error with `Missing script: test` either. Uses `--passWithNoTests` so the package can ship before it grows JS tests, and inherits the shared `jetpack-js-tools/jest/config.base.js` for when it does (asset stub for `.scss` imports, ts/jsx transform, JSDOM environment). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * SEO foundation: add .gitattributes so build/ ships with the package Without `.gitattributes`, the production-publish pipeline that vendors `automattic/jetpack-seo` into the Jetpack plugin's `jetpack_vendor/` respects `.gitignore` and drops the webpack-built `build/` directory. The PHP source files come along (they're not gitignored), so the SEO admin menu item appears and the mount `<div id="jetpack-seo-root">` renders — but the enqueued `build/index.js` URL 404s, leaving the admin page visually blank. Mirrors Newsletter's `.gitattributes` (the canonical wp-build package): - `/build/** production-include` overrides gitignore for build output - `*.tsx`/`*.ts`/`*.scss` under `_inc/` and `src/` are `production-exclude` since webpack has already compiled them into `build/`. Confirmed against the 404 on `wp-content/plugins/jetpack-dev/jetpack_vendor/automattic/jetpack-seo/build/index.js` in JetpackBeta on `sweetly-partial-gazelle.jurassic.ninja`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Jetpack SEO: migrate Overview to the shared data-sync layer Address review feedback on #49203 — replace hand-rolled data plumbing with Jetpack's established patterns. Data layer: - Register a read-only `overview` data-sync entry (namespace `jetpack_seo`) via Data_Sync_Readonly + Schema, bootstrapped onto the page with attach_to_plugin() so the app hydrates from window.jetpack_seo without a round-trip. - use-overview -> useDataSync; overview-types -> Zod OverviewSchema; providers -> DataSyncProvider. - Delete class-rest-controller.php, use-simple-query.ts and the unused use-simple-mutation.ts; drop the dead jetpackSeoRest bootstrap and the now-unused @wordpress/api-fetch and @tanstack/react-query deps. Module gating: - Move the seo-tools module check up into Initializer::init() so no routes, menu, or assets register when the module is off (matches how other Jetpack modules gate), removing the redundant per-method check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: adopt shared components and design tokens on the Overview Address review feedback on #49203 — replace hand-rolled UI with the platform's primitives. - Collapse shell.tsx onto AdminPage (drop the header-actions slot/fill context and the background/padding CSS overrides); delete header-actions-context.tsx and _inc/style.module.scss. - Use @wordpress/ui Notice (compound), Stack, and Link in place of @wordpress/components Notice/ExternalLink and flexbox CSS. - Give StatusDot its own style module using @wordpress/theme color tokens; tokenize remaining colors and spacing. - Extract ternary __() labels to module scope so i18n extraction survives the production minifier. - Remove the unused BoundedLayout from @automattic/jetpack-components. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: rebuild the admin page on wp-build + script-data Migrate the SEO foundation page off the custom webpack/React-Router setup onto @wordpress/build (wp-build), matching the live pattern the other recently-modernized Jetpack admin pages use (modeled on the Podcast package). - Build: add the wpPlugin block + wp-build scripts, the routes/index entry (stage/route/package.json), and drop webpack.config.js, babel.config.js, react-router, and zod. - Data layer: replace the data-sync Overview wiring with the shared script-data layer. wp-build pages load as ES modules, so wp_localize_script can't bootstrap them; the server now injects state onto window.JetpackScriptData.seo via the jetpack_admin_js_script_data filter (Podcast/Newsletter pattern), read synchronously in get-overview.ts. - PHP: keep the seo-tools module gate and the Admin_Menu top-level menu; load build/build.php + register WP_Build_Polyfills and alias the screen id on current_screen so wp-build's self-hooked enqueue fires for our slug. - Styles: convert CSS-module SCSS to plain prefixed SCSS (no wp-build package uses CSS modules). - composer: drop wp-js-data-sync + schema, add wp-build-polyfills. Verified: dev + production build, tsgo typecheck, php -l, phpcs, eslint, and i18n string extraction all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: align wp-build to trunk cohort (@wordpress/build 0.14.0) Sync the branch with trunk and bump @wordpress/build 0.13.0 -> 0.14.0 to match the current wp-build cohort. The branch had fallen ~99 commits behind trunk, which had since bumped @wordpress/build; the stale 0.13.0 pin left the PR-merge lockfile referencing build variants trunk no longer defines, failing CI's frozen install. Regenerated pnpm-lock.yaml on the merged tree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: refresh plugins/jetpack composer.lock for the SEO dep change The SEO package's composer.json changed (dropped wp-js-data-sync + schema, added wp-build-polyfills), so the consuming plugin's lock was stale and failed CI's "Lock files are up to date" check. Regenerated via tools/composer-update-monorepo.sh. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: fix Overview page padding and status-dot colors Two CSS regressions from the wp-build rebuild, caught in JN testing: - Page had no content padding: the layout SCSS included the `jetpack-admin-page-layout-wp-build` mixin, which only carries breadcrumb / anchor resets — not the content layout. Switch to the plain `jetpack-admin-page-layout` mixin (as Scan/Podcast do) and target both the top-level and Jetpack-submenu body classes. - Status dots rendered near-black: the plain `--wpds-color-fg-content-*` tokens are the darkest text shades (#2900 / #470000). Use the `-weak` variants (#007f30 / #cc1818 / amber), the vivid indicator colors the shared StatusIndicator pattern uses. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: add content padding to the Overview page The card sat flush against the header and page sides. `<AdminPage>` renders its content with `horizontalSpacing={0}` and no `hasPadding`, so only the header is padded — content padding is the consumer's responsibility (as in Scan/Podcast). The earlier frontend cleanup removed the old `.paddedContent` override without replacing it. Wrap the screen in `.jetpack-seo-page-content` padded at `--wpds-dimension-padding-2xl` (24px) to align with the header. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: remove the broken sitemap "View" link from the Overview The link pointed at home_url('/sitemap.xml'), which 404s: the "active" signal comes from a placeholder option (jetpack_seo_sitemap_enabled, which exists nowhere else in Jetpack) rather than the real `sitemaps` module, and even when the module is active Jetpack generates the sitemap via cron so the URL isn't live immediately. Drop the link to avoid shipping a dead link; correct sitemap detection + URL is tracked as a follow-up. The status row itself is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: address #49203 review feedback (docs + cleanup) - README: rewrite to match the shipped wp-build + script-data architecture (drop HashRouter/react-query/useSimpleQuery, REST API, pnpm run build/watch). - composer.json: drop unused requires (jetpack-connection/constants/assets); keep admin-ui/status/wp-build-polyfills, which the Initializer actually uses. - admin-page-layout.scss: use the -wp-build layout mixin variant so the code matches the changelog claim; it's a no-op superset until a tab adds breadcrumbs. - Initializer: guard init() with a private static $initialized flag (Podcast pattern) so the body can't re-run when seo-tools is off; document the pre-wired sitemap_url / front_page_description Overview fields. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: regenerate jetpack composer.lock after trimming seo package deps Follow-up to 8bc377e, which dropped the unused jetpack-connection/ constants/assets requires from the jetpack-seo package. The Jetpack plugin's composer.lock still recorded the old require set for the package, so the 'Lock files are up to date' check failed. Regenerated with `composer update automattic/jetpack-seo`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: gate the package behind the rsm_jetpack_seo feature flag Gate the entire SEO surface (admin menu, wp-build bundle, script data) behind the rsm_jetpack_seo filter, default false during roll-out, mirroring how the Scan package gates itself. Consolidate the package changelog into a single entry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * remove product name translations * Jetpack SEO: address review — drop wpds token fallbacks and fragile card CSS - Remove hex fallbacks on --wpds-* design tokens to match @wordpress/theme's no-token-fallback-values convention (tokens are guaranteed under ThemeProvider). - Remove the equal-height grid CSS that targeted @wordpress/ui's non-stable hashed Card internals; defer until a second Overview card exists. - Use title="SEO" instead of title={ 'SEO' }. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Jetpack SEO: use logical margin-inline-end on the status dot for RTL Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Filipe Varela <filipe@automattic.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Angela Blake <angela.blake@a8c.com> Co-authored-by: Angela Blake <angelablake@Angelas-MacBook-Pro.local> Co-authored-by: Douglas <douglas.henri@automattic.com>
Part 1 of a stacked PR series extracted from #48154 (Jetpack SEO: introduce new SEO product).
This is the smallest, foundational piece: make the shared
AdminPagecomponent a flex column withmin-height: calc(100vh - --wp-admin--admin-bar--height), and give.jetpack-footermargin-top: auto. Every product using the shared admin shell gets a consistent sticky-footer layout instead of the footer floating up against short content.Originally authored by @keoshi in #48154; extracted here so it can land independently and unblock the rest of the SEO product split.
Proposed changes
.admin-pagebecomes a flex column with a viewport-basedmin-height, fitting wp-admin's content area.:global(.admin-ui-page)flex-grows inside that column.:global(.jetpack-footer)claims any leftover vertical space viamargin-top: auto.Related product discussion/links
Screenshots
Before/after screenshots showing the footer position on a short Jetpack admin page (e.g. My Jetpack landing) — to be added.
Testing instructions
The change affects every Jetpack admin page that uses the shared
AdminPageshell (My Jetpack, the main Jetpack settings page, Boost, Protect, Search, Backup, Stats, etc.).Verify the footer sticks to the bottom on short pages:
wp-admin/admin.php?page=my-jetpack. With short content, theJetpackFootershould sit at the bottom of the viewport, not float up against the content with empty space underneath.Verify the footer appears normally on long pages:
wp-admin/admin.php?page=jetpack#/settingsand expand all the cards. The footer should appear at the end of the content with normal scrolling — no clipping, no overlap with content above.Verify no visual regression on:
AdminPagethat already rendered correctly (Boost, Protect, Search, Backup, Stats dashboards)Does this pull request change what data or activity we track or use?
No.