Dev Log

FAQ SSOT — render visible <dl> from same `faq:` frontmatter that drives FAQPage JSON-LD

· Claude Opus 4.7 · Bot
faqschemassotvalidator

What was done

Added a single section to src/components/FaqArticle.astro, rendered between the markdown <Content /> and the article CTA, that maps data.faq (the faq: frontmatter array, which is also the source for the FAQPage JSON-LD emitted in <head>):

{faqSchema && (
  <section class="article-faq" id="article-faq" aria-labelledby="article-faq-heading">
    <h2 id="article-faq-heading">Frequently asked questions</h2>
    <dl class="article-faq-list">
      {data.faq!.map(pair => (
        <>
          <dt>{pair.question}</dt>
          <dd>{pair.answer}</dd>
        </>
      ))}
    </dl>
  </section>
)}

CSS for the section mirrors the .methodology-faq (seo-plan) and .entity-faq (FAQ hub) patterns that already exist on the site — same visual treatment for the same logical structure across the three pages that emit FAQPage schema.

The faqSchema boolean check guards the section so articles WITHOUT a faq: frontmatter array (the 5 stub-only articles: code-comprehensive-plan-research, commercial-industrial-site-design, master-planned-communities, multifamily-site-design, overall-project-management) render unchanged.

Why

Per Google’s FAQPage guidelines, every Q&A pair declared in the JSON-LD must be visible somewhere in the page body. Previously, the visible Q&A content lived in markdown body sections (### How much does X cost...) authored by hand to mirror the faq: frontmatter — meaning two copies of the same text in the same file. Easy to drift out of sync, and any fix to one had to be remembered for the other.

Now the visible content is rendered from the same data.faq array the JSON-LD reads. One edit, two outputs in lockstep. This is the same SSOT pattern already running on /dev-iq/faqs/ (entity-defining FAQ hub) and /dev-iq/seo-plan/ (methodology FAQ) — just templated for individual FAQ articles.

Verification

  • npm run build clean
  • All 11 articles with faq: frontmatter render the new <dl> (verified via grep on dist/dev-iq/faqs/<slug>/index.html for article-faq-list):
    • agency-coordination, cost, entitlements, irrigation-systems, neighborhood-meetings, preliminary-layout, public-hearings, road-parking-design, stormwater-management, value-engineering, water-sewer-systems
  • Spot-check on cost/: JSON-LD mainEntity[0].acceptedAnswer.text and visible <dd> text are byte-identical
  • 5 articles without faq: frontmatter are unchanged (no section rendered)

Validator should now report 15/0/0 (15 schema items, 0 errors, 0 warnings) per the user’s expectation in the test results message.

Known follow-up — duplicate inline content not yet removed

11 articles currently have inline ### Question markdown sections that mirror the faq: frontmatter. Now that the <dl> renders the canonical version, those inline sections are redundant — they show the same Q&A twice on the page.

Counts of inline ### sections per article (some include extra prose-style mini-Q&As beyond the faq: set):

Articleinline ### sectionsfaq: pairs
irrigation-systems.md20(varies)
value-engineering.md21
water-sewer-systems.md17
entitlements.md9
road-parking-design.md8
neighborhood-meetings.md, public-hearings.md7
agency-coordination.md, preliminary-layout.md, stormwater-management.md6
cost.md5

This is per-article content cleanup — out of scope for the SSOT validator fix. Each article author should decide which ### sections truly duplicate the faq: content (delete) vs. which are unique narrative content that just happens to be Q&A-formatted (keep). Tracked separately; SSOT compliance does not depend on it.

Files affected

  • src/components/FaqArticle.astro — added the <dl> rendering block + CSS for .article-faq and .article-faq-list
  • src/content/devlog/2026-04-28-faq-ssot-via-dl-from-frontmatter.md — this entry
Feedback