Skip to content

Jetpack SEO: Content tab, per-post schema, and Content coverage card#49351

Open
angelablake wants to merge 11 commits into
trunkfrom
add/jetpack-seo-content-tab
Open

Jetpack SEO: Content tab, per-post schema, and Content coverage card#49351
angelablake wants to merge 11 commits into
trunkfrom
add/jetpack-seo-content-tab

Conversation

@angelablake
Copy link
Copy Markdown
Contributor

@angelablake angelablake commented Jun 2, 2026

Part 4 of the 8-PR Jetpack SEO product split (originally by @keoshi; driven here by @angelablake). Linear: JETPACK-1680. Targets trunk (PRs #2 and #3 are merged).

Adds per-post SEO + a Content tab to the SEO admin page. Re-implemented on the wp-build + script-data foundation from #2/#3 — no package REST controller, reuses core endpoints + post meta + script-data.

Proposed changes

  • Content tab (?tab=content): a DataViews list of published posts and pages backed by core /wp/v2/posts + /wp/v2/pages and registered SEO post meta. Factual columns — schema type, meta-description set, search visibility — with client-side filters; no SEO "score". An Edit SEO modal edits the post's SEO meta (custom title, description, schema type, noindex) via core post meta (no write endpoint) with a live SERP preview.
  • Content SEO coverage card on the Overview: factual per-metric rings + literal counts (custom description set, schema type set). Backed by a content_coverage aggregate in script-data (get_content_coverage() in Initializer). No composite grade.
  • Per-post schema type (jetpack_seo_schema_type meta, enum-validated): a Schema type control (Default / Article / FAQ) in the block-editor SEO panel, reusing the existing withSeoHelper HOC.
  • Front-end JSON-LD (Schema_Builder): Article + FAQ structured data on wp_head for published posts with the matching schema type set.
  • Factual edit.php columns (Schema / Meta description / Search) on public post-list tables, via one shared Jetpack_SEO_Posts::get_post_seo_coverage() helper.

Product decisions

  • No good/fair/poor scoring. SEO needs depend on the site's goals, so we report factual state, not a grade.
  • Schema scoped to Article + FAQ for per-post overrides. HowTo / Organization / LocalBusiness need structured input or backing config → deferred (JETPACK-1701).
  • Published posts only in the Content tab. Drafts and scheduled posts have no SEO impact until published and are excluded to keep the list consistent with the Overview coverage card counts.

Must-fixes from the #48154 review

#12 (enum-validated schema type), #8 (no JSON_UNESCAPED_SLASHES), #9 (wp_trim_words on Article description), and removing the dead LocalBusiness/Organization writers are all addressed. #13/#14 are voided by dropping the score.

Related product discussion/links

Screenshots

SEO.Content.tab.walkthrough.mp4

Testing instructions

Requires the seo-tools Jetpack module active and — until the feature flag is removed in JETPACK-1702 — the filter rsm_jetpack_seo returning true (add a mu-plugin: add_filter( 'rsm_jetpack_seo', '__return_true' );).

Content tab (wp-admin/admin.php?page=jetpack-seo&tab=content):

  1. Confirm published posts and pages appear merged in the list; drafts do not appear.
  2. Use the Type filter chip to narrow to Posts or Pages.
  3. Use Add filter to filter by Schema type, Meta description, or Search visibility.
  4. Click the pencil icon on any row to open the Edit SEO modal. Edit the custom title, description, schema type, and noindex toggle; save and confirm the row updates without a page reload.
  5. Confirm the title link on each row opens the Gutenberg editor for that post.

Overview (wp-admin/admin.php?page=jetpack-seo):
6. Confirm the Content SEO card shows correct counts for posts with a custom description set and schema type set.
7. Edit a post's description via the modal and confirm the ring/count updates immediately.

Block editor:
8. Open any post in Gutenberg; expand the SEO panel in the sidebar. Confirm the Schema type selector (Default / Article / FAQ) appears and saves.

Post list tables (wp-admin/edit.php, wp-admin/edit.php?post_type=page):
9. Confirm Schema, Meta description, and Search columns appear and reflect each post's current SEO state.

Front-end JSON-LD:
10. Set a published post's schema type to Article or FAQ; view-source on the front end and confirm the corresponding JSON-LD block appears in <head>.

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

No. This PR adds no Tracks events and reads no new user data beyond what the existing seo-tools module already accesses (post meta, core options).

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 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-content-tab branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack add/jetpack-seo-content-tab
bin/jetpack-downloader test jetpack-mu-wpcom-plugin add/jetpack-seo-content-tab

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 [Extension] SEO [Feature] SEO Tools Tools for improving a site's search engine optimization. [Package] Seo [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] In Progress labels Jun 2, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 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 🤖


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.

@github-actions github-actions Bot added the [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. label Jun 2, 2026
@jp-launch-control
Copy link
Copy Markdown

jp-launch-control Bot commented Jun 2, 2026

Code Coverage Summary

Coverage changed in 2 files.

File Coverage Δ% Δ Uncovered
projects/plugins/jetpack/modules/seo-tools/class-jetpack-seo-posts.php 0/101 (0.00%) 0.00% 35 💔
projects/plugins/jetpack/modules/seo-tools.php 0/25 (0.00%) 0.00% 2 ❤️‍🩹

2 files are newly checked for coverage.

File Coverage
projects/plugins/jetpack/extensions/plugins/seo/schema-panel.js 0/3 (0.00%) 💔
projects/plugins/jetpack/modules/seo-tools/class-jetpack-seo-admin-columns.php 0/54 (0.00%) 💔

Full summary · PHP report · JS report

If appropriate, add one of these labels to override the failing coverage check: Covered by non-unit tests Use to ignore the Code coverage requirement check when E2Es or other non-unit tests cover the code Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR I don't care about code coverage for this PR Use this label to ignore the check for insufficient code coveage.

@dhasilva dhasilva force-pushed the add/jetpack-seo-settings-tab branch from c9d4d60 to a482cb0 Compare June 2, 2026 21:22
@angelablake angelablake force-pushed the add/jetpack-seo-content-tab branch from 805cb9a to 4fe2052 Compare June 2, 2026 22:04
Base automatically changed from add/jetpack-seo-settings-tab to trunk June 2, 2026 22:09
Angela Blake and others added 7 commits June 2, 2026 17:24
- Jetpack_SEO_Posts: register jetpack_seo_schema_type meta (show_in_rest with
  an enum schema so core REST rejects unknown types — must-fix #12), plus
  get_post_schema_type() and a single factual get_post_seo_coverage() helper
  (presence/state only, no scoring) shared by the columns + Overview card.
  Per-post types scoped to none/Article/FAQ (LocalBusiness/Organization/HowTo
  deferred to the Expanded Schema project, JETPACK-1701).
- Schema_Builder (package): front-end JSON-LD on wp_head for Article + FAQ
  (FAQ parsed from core/details; emits nothing if absent). Must-fix #8 (drop
  JSON_UNESCAPED_SLASHES) and #9 (cap Article description with wp_trim_words).
- Initializer: wire Schema_Builder::init() in (front-end emission).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Admin columns (class-jetpack-seo-admin-columns.php, wired in seo-tools.php):
  factual Schema / Meta description / Search columns on public post lists, via
  the shared Jetpack_SEO_Posts::get_post_seo_coverage() helper. No traffic-light
  scoring and no React-island preview (display-only).
- Block editor: new schema-panel.js (Default/Article/FAQ SelectControl) reusing
  the existing withSeoHelper HOC; wired SeoSchemaPanel into the existing SEO
  panel's three placements (sidebar, document settings, pre-publish).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Content tab (?tab=content): DataViews list of posts/pages backed by core
  /wp/v2/posts + registered SEO meta (no package REST controller). Factual
  columns (schema type, meta-description set, search visibility) + an Edit SEO
  modal that writes core post meta, with a live SERP preview. Adds
  @wordpress/dataviews, @wordpress/core-data, @wordpress/html-entities.
- Content SEO coverage card on the Overview: factual per-metric DonutMeter
  rings (custom description, schema type) + literal counts, noindex as a plain
  count. No composite score / grading. Backed by a content_coverage aggregate
  in get_overview_data() via script-data (count helpers in the Initializer).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…SEO_Posts

get_content_coverage() referenced Jetpack_SEO_Posts:: constants, but the
package Initializer has no `use Jetpack_SEO_Posts;` import (only
Jetpack_SEO_Utils), so in this namespace it resolved to a non-existent
Automattic\\Jetpack\\SEO\\Jetpack_SEO_Posts and fataled on every SEO-page
load. php -l/phpcs can't see it; phan would have (the guarded Utils calls carry
@phan-suppress; mine didn't).

Fix: mirror the three meta keys as local package constants (they're stable
strings) so coverage counting doesn't depend on the plugin class at all. Also
hardened Schema_Builder::emit() to guard on Jetpack_SEO_Posts + added the
matching @phan-suppress annotations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Same namespace-resolution fatal as the previous fix, one line further down the
same call chain: `new WP_Query` in this namespaced file (no use import, no
leading backslash) resolved to Automattic\\Jetpack\\SEO\\WP_Query and fataled
the SEO page. Qualified to \WP_Query. Audited every class reference in the
package's namespaced files — all others are use-imported or same-namespace.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1. Overview layout: move the Content SEO card out of the 2-up grid into a
   full-width row beneath Site visibility + Site verification.
2. Content edits reflect on the Overview card without a reload: coverage counts
   lifted to the app root, nudged optimistically (per-metric delta) when a
   post's SEO is saved on the Content tab.
3. Edit SEO row action now has a pencil icon (more discoverable than a label-
   only hover action).
4. Drop the 'hidden from search' count from the coverage card; add a Search
   visibility filter (Visible/Hidden) to the Content tab instead — most content
   is visible by default, so it's a filter, not a headline stat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@angelablake angelablake force-pushed the add/jetpack-seo-content-tab branch from 4fe2052 to c385898 Compare June 2, 2026 22:26
Angela Blake and others added 3 commits June 2, 2026 18:36
- changelog: Type 'added' → 'enhancement' (Changelogger validity)
- class-schema-builder.php: cast post_author to int for get_the_author_meta() (Phan PhanTypeMismatchArgument)
- use-seo-posts.ts: fetch merged posts+pages client-side (up to 100 each); expose draft/pending/private statuses; drop pagination args
- content/index.tsx: use filterSortAndPaginate for client-side filter/sort/paginate; fix ButtonTrigger icon (wrap pencil in <Icon>); restore getValue for type/schema/description/visibility filter fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Restrict Content tab to published posts only (drop draft/pending/future/private).
  Unpublished content has no SEO impact, and showing it created a count mismatch
  with the Overview coverage card.
- Replace the hover-only DataViews primary action with a rendered 'editAction'
  column: an EditButton component (useCallback-stable onClick) that is always
  visible, so users don't need to hover to discover the edit affordance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Content tab (PR #4) is now in place; remove the "lands in follow-up PR"
note and document the tab, its data access pattern (core REST + registered
post meta), and the JSON-LD emission.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@angelablake angelablake added [Status] Needs Review This PR is ready for review. and removed [Status] In Progress labels Jun 3, 2026
…lary

The seo package uses keep-a-changelog types (added/changed/fixed/…) and the
jetpack plugin uses the Jetpack set (enhancement/bugfix/compat/…). The two
Type values were swapped, failing the Changelogger validity check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@angelablake angelablake marked this pull request as ready for review June 4, 2026 18:56
@angelablake angelablake removed [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. [Status] In Progress labels Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs [Extension] SEO [Feature] SEO Tools Tools for improving a site's search engine optimization. [Package] Seo [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] Needs Review This PR is ready for review. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant