Skip to content

Jetpack SEO: introduce package foundation and Site visibility Overview#49203

Merged
dhasilva merged 21 commits into
trunkfrom
add/jetpack-seo-foundation
Jun 2, 2026
Merged

Jetpack SEO: introduce package foundation and Site visibility Overview#49203
dhasilva merged 21 commits into
trunkfrom
add/jetpack-seo-foundation

Conversation

@angelablake
Copy link
Copy Markdown
Contributor

@angelablake angelablake commented May 27, 2026

Part 2 of a stacked PR series extracted from #48154 (Jetpack SEO: introduce new SEO product). Originally authored by @keoshi; driven here by @angelablake. See #48154 for the split plan covering all 8 PRs.

Adds a new automattic/jetpack-seo package that mounts a React admin at wp-admin/admin.php?page=jetpack-seo. The entire surface is gated behind the rsm_jetpack_seo feature flag (off by default during roll-out); when the flag is on, the menu item additionally requires the seo-tools module to be active.

This PR is intentionally the smallest viable foundation: the package scaffold, the Initializer, and the Overview screen's single Site visibility card. Follow-up PRs add the Settings tab, Per-post SEO (Content) tab, AI tab, module absorption + migration, and the remaining Overview cards as each lands with the feature that owns its data.

Proposed changes

New package: automattic/jetpack-seo

  • Feature flag: the whole package is gated behind the rsm_jetpack_seo filter (Initializer::FEATURE_FILTER), defaulting to false. When the flag is off, Initializer::init() returns early and registers nothing — no admin menu, no assets, no script data — so the package is inert on production until the flag is flipped.
  • PHP: Initializer registers the admin menu (gated behind the rsm_jetpack_seo flag, then on the seo-tools module), loads wp-build's generated bundle (build/build.php + WP_Build_Polyfills::register()), and bootstraps the app's read-only initial state. Because the user-facing slug (jetpack-seo) differs from wp-build's page slug (jetpack-seo-dashboard), the screen id is aliased on current_screen so wp-build's auto-generated enqueue callback fires. No REST controller.
  • React: a @wordpress/build (wp-build) dashboard. Routing via @wordpress/route (routes/index/{route,stage}.tsx); _inc/app.tsx wraps the routes in AdminPage chrome from @automattic/jetpack-components. UI uses @wordpress/components, @wordpress/ui, @wordpress/icons. One screen: Overview, rendering a single Site visibility card (search engines allowed, sitemap active, SEO tools active).
  • Data: read-only initial state is bootstrapped server-side onto window.JetpackScriptData.seo via the jetpack_admin_js_script_data filter (Initializer::inject_script_data()) and read synchronously on the client through @automattic/jetpack-script-data (_inc/data/get-overview.ts). wp-build pages load as ES modules, so wp_localize_script can't bootstrap them — the script-data layer is the supported channel (mirrors Podcast/Newsletter).
  • Layout chrome: opts the SEO admin page into the shared jetpack-admin-page-layout-wp-build mixin from @automattic/jetpack-base-styles, scoped to body.jetpack_page_jetpack-seo / body.toplevel_page_jetpack-seo, via _inc/admin-page-layout.scss.
  • Packaging: .gitattributes with /build/** production-include so the wp-build-compiled JS/CSS is included when the package is vendored into the Jetpack plugin distribution (without this, the SEO admin page renders blank on Jetpack Beta — the PHP files vendor through but the built bundle doesn't).
  • Tests: PHPUnit configs for major versions 8/9/11/12 plus a tests/jest.config.js and test script, so the CI test matrix has a config to select across PHP 7.4–8.5.

Jetpack plugin wiring

  • class.jetpack.php: load the new package in late_initialization().
  • composer.json: require automattic/jetpack-seo.

Related product discussion/links

Screenshots

SEO Overview

SEO menu item under Jetpack and the Overview screen with its Site visibility card. The three status rows reflect live data bootstrapped via the script-data layer. (Visually unchanged by the wp-build rebuild.)

Testing instructions

Prerequisites

  • A Jetpack-connected site with the seo-tools module active (e.g. a JN site running this PR's Jetpack Beta artifact).
  • Sign in as an admin (manage_options).
  • Enable the feature flag — it's off by default. Add a filter that returns true for rsm_jetpack_seo (e.g. drop add_filter( 'rsm_jetpack_seo', '__return_true' ); in a mu-plugin or snippet). With the flag off, the package registers nothing and the steps below show no SEO menu.

Feature flag gating

  • With the flag off (default), confirm there is no Jetpack → SEO menu item and wp-admin/admin.php?page=jetpack-seo is not reachable.
  • Turn the flag on, then continue below.

Menu visibility

  • In wp-admin, confirm Jetpack → SEO appears in the admin menu.
  • Deactivate the module (wp jetpack module deactivate seo-tools). The SEO menu item should disappear — nothing registers when the module is off.
  • Reactivate (wp jetpack module activate seo-tools). The menu item should reappear.

Overview screen

  • Click Jetpack → SEO. The page should load at wp-admin/admin.php?page=jetpack-seo with the title "SEO" and a Site visibility card.
  • The card shows three rows, driven by live data bootstrapped via the script-data layer (no REST request):
    • Search engines allowed/blocked (Settings → Reading → "Discourage search engines" / blog_public)
    • Sitemap active/disabled (jetpack_seo_sitemap_enabled; defaults off — the toggle lands in PR Edit and rename the readme for GitHub #3)
    • SEO tools active/inactive (the seo-tools module state)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack or WordPress.com Site Helper), and enable the add/jetpack-seo-foundation branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack add/jetpack-seo-foundation
bin/jetpack-downloader test jetpack-mu-wpcom-plugin add/jetpack-seo-foundation

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions github-actions Bot added [JS Package] Components [Package] Seo [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Tests] Includes Tests Docs RNA labels May 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • 🔴 Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • 🔴 Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

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 🤖


🔴 Action required: We would recommend that you add a section to the PR description to specify whether this PR includes any changes to data or privacy, like so:

## Does this pull request change what data or activity we track or use?

My PR adds *x* and *y*.

Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

No scheduled milestone found for this plugin.

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

@jp-launch-control
Copy link
Copy Markdown

jp-launch-control Bot commented May 27, 2026

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/plugins/jetpack/class.jetpack.php 758/2291 (33.09%) -0.01% 1 ❤️‍🩹

Full summary · PHP report · JS report

Comment on lines +42 to +48
return createElement(
tagName,
{
className: clsx( styles.bounds, styles[ width ], className ),
},
children
);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rather use JSX which is much more readable.

Comment on lines +50 to +60
.statusOk {
background: #4ab866;
}

.statusWarn {
background: #dba617;
}

.statusErr {
background: #cc1818;
}
Copy link
Copy Markdown
Member

@simison simison May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use design system tokens for colours --wpds-*) from @wordpress/theme for ok/warn/err.

Comment on lines +66 to +68
display: flex;
justify-content: flex-end;
gap: 8px;
Copy link
Copy Markdown
Member

@simison simison May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use the Stack component from @wordpress/ui for flex layouts to avoid lots of CSS.


.loading {
padding: 16px 0;
color: #757575;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use style token colors from @wordpress/theme.

}

.loading {
padding: 16px 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use spacing tokens from @wordpress/theme.

Comment on lines +1 to +5
.placeholder {
padding: 48px;
text-align: center;
color: #757575;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use Stack and style tokens.

Comment on lines +7 to +19
// Override AdminPage's default `--jp-white` background with the admin-ui
// neutral-surface token (#fcfcfc). Targets the stable `.jp-admin-page__page`
// hook (passed via `className` from `<AdminPage>`) rather than admin-ui's
// internal `.admin-ui-page*` classes, which are hashed in the standalone
// admin-ui build and only literal in some WP core bundles. Double-class on
// `.neutralBg` for specificity over AdminPage's own `.background` rule.
.neutralBg.neutralBg {

&:global(.background),
:global(.jp-admin-page__page) {
background-color: var(--wpds-color-bg-surface-neutral, #fcfcfc);
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now an SEO page overriding a Jetpack override over the core colour, flipping back to the core. :-) Doesn't make sense. Let's instead have the design consolidate designs across pages so we don't need to do exceptions, or otherwise avoid this messy way of stacking overrides.

Comment on lines +21 to +28
// Padding around the routed content on Overview and Settings. The admin-ui
// Page renders children unwrapped (no `.admin-ui-page__content` exists unless
// `hasPadding` is passed, which jetpack-components' AdminPage doesn't do), so
// Shell wraps the Outlet in this container and we pad it here.
.paddedContent {
padding: var(--wpds-dimension-padding-2xl, 24px);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't make sense 😅

Like note says there's hasPadding prop in Page component, which we should use instead of CSS overrides, which are using CSS selectors which can't be relied upo as stable API.

Comment on lines +29 to +33
// Content tab hosts a full-height DataViews. No extra padding so it can fill
// the region edge-to-edge.
.fullBleed {
padding: 0;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

When hasPadding is falsy, there's no padding already.

Comment on lines +35 to +48
// The admin-ui `Page` component renders the tabs prop between the header and
// the content container (not inside the header like Forms' own Page does).
// Wrap them so they visually continue the header: same white background, same
// horizontal padding (matching admin-ui's `--wpds-dimension-padding-2xl` = 24px
// on `.admin-ui-page__header`), and a soft divider at the bottom. This keeps
// the tabs visually anchored to the header and makes their starting edge line
// up with the page title.
.tabsBar {
background: var(--wpds-color-bg-surface-neutral-strong, #fff);
padding-inline: var(--wpds-dimension-padding-2xl, 24px);
border-bottom:
var(--wpds-border-width-xs, 1px) solid
var(--wpds-color-stroke-surface-neutral-weak, #e4e4e4);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep Tabs behaviour centralized at AdminPage and not do local modifications; it gets very difficult to maintain otherwise and whole point of centralizing it in first place.

Tabs as a more integrated part of Header is coming up in next versions of Admin UI component so it'll be better.

@@ -0,0 +1,48 @@
.placeholder {
padding: 48px;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use sapcing tokens from @wordpress/theme.

Comment thread projects/packages/seo/_inc/shell.tsx Outdated
* The chrome inside the HeaderActionsProvider. Split so the AdminPage
* render can read header actions from context.
*/
const ShellChrome: FC = () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all seems very complicated; is it worth having as "shell" which override background and padding in AdminPage, which like I noted elsewhere should just be features of AdminPage?

It's a lot of code for very minimal gain.

Comment on lines +83 to +84
__( 'SEO', 'jetpack-seo' ),
__( 'SEO', 'jetpack-seo' ),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been avoiding translating product names ("Jetpack SEO"), internal ref for context p1HpG7-wSr-p2

* @return void
*/
public static function add_menu_item() {
if ( ! self::is_seo_tools_module_active() ) {
Copy link
Copy Markdown
Member

@simison simison May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module check might make sense somewhere higher up, before we even let the class initialise and run its functions.

For example, we're happily registering routes and other functionality even when the module is disabled.

}
/>
{ data.sitemap_active && (
<ExternalLink href={ data.sitemap_url }>{ __( 'View', 'jetpack-seo' ) }</ExternalLink>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use newer Link component from @wordpress/ui instead.

@@ -0,0 +1,45 @@
import { Notice, Spinner } from '@wordpress/components';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use more modern Notice from @wordpress/ui instead.

@github-actions github-actions Bot added [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. and removed [Status] Needs Review This PR is ready for review. labels Jun 2, 2026
keoshi and others added 19 commits June 2, 2026 15:51
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
…ange

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>
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>
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>
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>
- 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>
…age 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>
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>
@dhasilva dhasilva force-pushed the add/jetpack-seo-foundation branch from 497c55d to 2bdd70c Compare June 2, 2026 18:52
dhasilva and others added 2 commits June 2, 2026 16:18
…ard 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>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dhasilva
Copy link
Copy Markdown
Contributor

dhasilva commented Jun 2, 2026

Added a very important fix: a feature flag. The module is not enough, people would see an unfinished page in their sidebar without it.

@dhasilva dhasilva merged commit 8ee5aa3 into trunk Jun 2, 2026
93 checks passed
@dhasilva dhasilva deleted the add/jetpack-seo-foundation branch June 2, 2026 20:22
@github-actions github-actions Bot added [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. and removed [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. labels Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs [JS Package] Components [Package] Seo [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ RNA [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants