Skip to content

SEO: convert schema output to an @graph and add a site-level Organization node#50080

Open
gmjuhasz wants to merge 4 commits into
trunkfrom
jetpack-1779-schema-site-level-organization-node-multi-node-graph
Open

SEO: convert schema output to an @graph and add a site-level Organization node#50080
gmjuhasz wants to merge 4 commits into
trunkfrom
jetpack-1779-schema-site-level-organization-node-multi-node-graph

Conversation

@gmjuhasz

@gmjuhasz gmjuhasz commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Part of JETPACK-1779

Back-end foundation slice for the Site Schemas milestone: converts the SEO schema output to a multi-node @graph and adds the first site-level node (Organization). This is the shared @graph foundation the other site-level schema types (WebSite, LocalBusiness, Person) build on.

Scope — this PR is the @graph foundation + Organization node only. It does not close JETPACK-1779's settings acceptance:

  • In this PR: convert output to a multi-node @graph (Article/FAQ preserved); emit a site-level Organization node from existing site identity; reference it from the Article publisher.
  • Not in this PR (follow-ups, so 1779 stays open): schema settings persistence + REST (social profiles sameAs, field overrides) → settings-server PR; the "Organization / Business info" settings UI → settings-UI PR. The Organization builder already accepts a $settings array; the graph passes it empty for now, so social profiles / overrides are intentionally not configurable yet.

Proposed changes

  • Refactor Schema_Builder::emit() from a single-node emitter into a thin @graph serializer. build_document() assembles the graph and wires cross-node references (Article → Organization publisher by @id); the individual node builders stay self-contained and unaware of each other.
  • New package-owned schema services under projects/packages/seo/src/:
    • Schema_Graph — collects nodes and renders the { @context, @graph } document (or null when empty).
    • Schema_Node_Ids — stable, site-root-anchored @ids (e.g. https://example.com/#organization) so nodes cross-reference reliably across every page.
    • Post_Schema_Node — the Article / FAQPage builder, moved out of Schema_Builder unchanged.
    • Organization_Schema_Node — site-level Organization node built from existing site identity (Site Title, home URL, Site Logo → Site Icon fallback, Tagline). sameAs / email / overrides come from an optional $settings seam.
  • Emission policy is unchanged: still gated on is_singular(). Site-level nodes ride along on the singular request's graph, so the home page, archives, 404s, drafts, and override-less pages still emit nothing.
  • Tests: SchemaBuilderTest now asserts the real emitted <script type="application/ld+json"> document (the actual regression surface); new PostSchemaNodeTest, SchemaGraphTest, OrganizationSchemaNodeTest. Adds the emitted-output regression harness for the current Article/FAQ behavior before the conversion.

Example emitted output for a published post (site with a Site Logo and Tagline):

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Acme Co",
      "url": "https://example.com/",
      "description": "We make fine widgets",
      "logo": { "@type": "ImageObject", "url": "https://example.com/logo.png", "width": 120, "height": 60 }
    },
    {
      "@type": "Article",
      "headline": "Hello world",
      "datePublished": "2026-01-01T00:00:00+00:00",
      "dateModified": "2026-01-02T00:00:00+00:00",
      "mainEntityOfPage": { "@type": "WebPage", "@id": "https://example.com/hello-world/" },
      "author": { "@type": "Person", "name": "Jane Doe" },
      "publisher": { "@id": "https://example.com/#organization" }
    }
  ]
}

Feature flag

Inherits the existing SEO gate — Schema_Builder only loads when the rsm_jetpack_seo feature flag is on (default off) and the SEO Tools module is active. Sites without the flag see no change at all; only the flagged new-SEO cohort gets the new @graph + Organization output. No new flag added.

Related product discussion/links

  • Tracking issue: JETPACK-1779 (Phase 1 - Jetpack SEO: Expanded Schema Markup → Site Schemas)

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

No.

Testing instructions

Setup

  • On a test site, turn on the new SEO experience: add_filter( 'rsm_jetpack_seo', '__return_true' ); (snippet / mu-plugin) and make sure the SEO Tools module is active.
  • Set Settings → General → Site Title and Tagline, and add a Site Logo (Customizer → Site Identity) — or a Site Icon as a fallback.

New behavior — @graph + Organization

  • Open a published post on the front end and View Source (or run its URL through Google's Rich Results Test).
  • Find the <script type="application/ld+json"> block and confirm:
    • It's now a @graph array (not a single top-level node).
    • It contains an Organization node with name (Site Title), url, logo (your Site Logo/Icon as an ImageObject), and description (Tagline).
    • The Article node has a publisher referencing the Organization's @id (e.g. https://your-site/#organization).
  • Paste the output into the Rich Results Test / schema.org validator → no errors.

No regression

  • The Article fields are unchanged (headline, datePublished, dateModified, author, mainEntityOfPage, and image when a featured image is set).
  • A post with the FAQ schema type still emits a valid FAQPage (in the graph; FAQPage has no publisher).
  • No schema is emitted on: the home page / archives (non-singular), draft / private posts, or a plain Page with no schema-type override.

Automated

  • pnpm jetpack test php packages/seo (or composer phpunit in projects/packages/seo) → 46 pass.
  • pnpm jetpack phan packages/seo → 0 issues.

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

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), and enable the jetpack-1779-schema-site-level-organization-node-multi-node-graph branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack jetpack-1779-schema-site-level-organization-node-multi-node-graph

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 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

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!

@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 30, 2026
@jp-launch-control

jp-launch-control Bot commented Jun 30, 2026

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/packages/seo/src/class-schema-builder.php 22/23 (95.65%) 18.94% -16 💚

4 files are newly checked for coverage.

File Coverage
projects/packages/seo/src/class-post-schema-node.php 56/60 (93.33%) 💚
projects/packages/seo/src/class-organization-schema-node.php 63/64 (98.44%) 💚
projects/packages/seo/src/class-schema-graph.php 10/10 (100.00%) 💚
projects/packages/seo/src/class-schema-node-ids.php 2/2 (100.00%) 💚

Full summary · PHP report · JS report

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors the SEO schema emitter to output a Schema.org JSON-LD @graph document on singular requests, introducing a site-level Organization node and wiring it as the Article publisher via stable @id values. This establishes the shared graph foundation for future site-level schema nodes.

Changes:

  • Convert Schema_Builder from single-node emission to assembling/serializing a multi-node @graph document.
  • Add schema infrastructure services: Schema_Graph (collector/serializer) and Schema_Node_Ids (stable site-anchored @ids).
  • Extract per-post schema building into Post_Schema_Node and add Organization_Schema_Node with settings seams + new PHPUnit coverage.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
projects/packages/seo/src/class-schema-builder.php Switches emission to @graph document assembly and serialization; wires Article → Organization publisher reference.
projects/packages/seo/src/class-schema-graph.php Adds a small graph collector that skips empty nodes and renders { @context, @graph } or null.
projects/packages/seo/src/class-schema-node-ids.php Provides stable site-root anchored node @id helpers (e.g., #organization).
projects/packages/seo/src/class-post-schema-node.php Moves Article/FAQPage node building into a dedicated builder used by the graph.
projects/packages/seo/src/class-organization-schema-node.php Introduces Organization node builder from site identity, with optional settings overrides/sanitization.
projects/packages/seo/tests/php/SchemaBuilderTest.php Updates tests to assert the actual emitted <script type="application/ld+json"> document shape and wiring.
projects/packages/seo/tests/php/SchemaGraphTest.php Adds unit tests for graph behavior (empty graph, skipping null/empty nodes, preserving order).
projects/packages/seo/tests/php/SchemaNodeIdsTest.php Adds unit tests for stable Organization @id generation.
projects/packages/seo/tests/php/PostSchemaNodeTest.php Adds unit tests for the extracted per-post node builder (Article + FAQPage).
projects/packages/seo/tests/php/OrganizationSchemaNodeTest.php Adds unit tests for Organization node outputs, sanitization, and logo fallbacks.
projects/packages/seo/changelog/add-seo-schema-organization-graph Adds a changelog entry describing the new Organization node and @graph output.

Comment thread projects/packages/seo/tests/php/SchemaNodeIdsTest.php
Comment thread projects/packages/seo/tests/php/SchemaNodeIdsTest.php
Comment thread projects/packages/seo/tests/php/SchemaBuilderTest.php
Comment thread projects/packages/seo/tests/php/OrganizationSchemaNodeTest.php
Comment thread projects/packages/seo/tests/php/OrganizationSchemaNodeTest.php
Comment thread projects/packages/seo/tests/php/OrganizationSchemaNodeTest.php
Comment thread projects/packages/seo/tests/php/OrganizationSchemaNodeTest.php
Comment thread projects/packages/seo/tests/php/OrganizationSchemaNodeTest.php
Comment thread projects/packages/seo/tests/php/OrganizationSchemaNodeTest.php
@gmjuhasz gmjuhasz marked this pull request as ready for review June 30, 2026 16:23
@gmjuhasz gmjuhasz requested review from a team and angelablake June 30, 2026 16:23
@gmjuhasz gmjuhasz self-assigned this Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Seo [Status] In Progress [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants