Extend FAQPage schema to docs comparison pages (Terraform, OpenTofu, AWS CDK, Crossplane)#20081
Conversation
The FAQ auto-detection in graph-builder.html only added a supplemental FAQPage entity for type: what-is pages, even though faq-entity.html already parses any page's markdown for a Frequently asked questions section generically. This silently dropped FAQPage structured data from every type: docs page with a Q&A section, including the four IaC comparison pages (Terraform, OpenTofu, AWS CDK, Crossplane), which together are Pulumi's highest citation-share comparison content and a Tier 1 SEO/AEO target (pulumi vs terraform, 720 mo. searches). This generalizes the same supplement to type: docs pages, guarded so the dedicated /docs/iac/faq/ page (which already gets FAQPage as its main entity via main-entity.html) is excluded to avoid a duplicate FAQPage entity in its @graph. faq-entity.html already returns an empty dict when no question-shaped H3s are found, so this is a no-op for the many docs pages without a FAQ section. Immediate beneficiaries with existing, well-formed FAQ sections: - /docs/iac/comparisons/terraform/ (7 Q&As) - /docs/iac/comparisons/opentofu/ - /docs/iac/comparisons/aws-cdk/ - /docs/iac/comparisons/crossplane/
Pre-merge Review — Last updated 2026-07-04T17:12:06ZTip Summary: This PR extends the JSON-LD schema generator ( Review confidence:
Investigation log
🔍 Verification trail
🚨 Outstanding in this PRNo outstanding findings in this PR.
|
|
Your site preview for commit 4bc25bf is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-20081-4bc25bf5.s3-website.us-west-2.amazonaws.com |
Lighthouse Performance ReportCommit: 4bc25bf | Metric definitions
|
What
Extends the site's existing FAQPage schema auto-detection so
type: docspages get the same supplemental FAQPage entity thattype: what-ispages already receive when they have a "Frequently asked questions" section.Why
layouts/partials/schema/graph-builder.htmlonly called the FAQ collector partial (faq-entity.html) forwhat-ispages. Butfaq-entity.htmlitself is generic — it just scans any page's raw markdown for a## Frequently asked questionsblock with### ...?sub-headings and returns an empty dict if none are found. That meant everydocs-type page with a real, already-written FAQ section was silently missing FAQPage structured data, including the four IaC comparison pages:/docs/iac/comparisons/terraform/— 7 fully-written Q&As, zero schema/docs/iac/comparisons/opentofu//docs/iac/comparisons/aws-cdk//docs/iac/comparisons/crossplane/These comparison pages are Pulumi's top citation-share content in our AI answer-engine tracking (Terraform comparison alone: 48 citations in the last 28 days, more than any other single docs page) and "pulumi vs terraform" is a Tier 1 SEO/AEO keyword (~720 searches/mo). FAQPage schema is the single highest-leverage structured-data type for both Google rich results and LLM citation probability, per our AEO guidelines — so this class of page not having it at all was the biggest gap I could find today.
How
One condition in
graph-builder.html: the FAQ supplement now fires forwhat-isORdocstype pages, guarded to skip pages whose title/URL already mark them as the dedicated FAQ page (those getFAQPageas their main entity already viamain-entity.html, so re-adding it here would duplicate the entity in the@graph). No changes to the parsing logic itself —faq-entity.html's existing, already-safe "return empty dict if no questions found" behavior means this is a no-op for the manydocspages that don't have a Q&A section.SCHEMA.mdupdated to document the new behavior.Verification
faq-entity.html's question-detection logic against the live content ofcontent/docs/iac/comparisons/terraform/_index.md: its## Frequently asked questionsheading followed by 7### ...?sub-headings satisfies the existing (unchanged) H3-ends-in-?detection rule, so all 7 will be picked up./docs/iac/faq/page, which is explicitly excluded by the new guard.hugo serverto double check before merge, or I can iterate further if CI surfaces anything.🧠 This PR was created by workprentice on behalf of @joeduffy.