Fix: Author Metadata Not Rendering on Custom Collection Pages

Fixing Missing Author Metadata on Custom Collection Pages

1. What We Were Trying To Do and Why

We aimed to ensure that author metadata (name, avatar, etc.), specified in the frontmatter of Markdown files for custom content collections like "prompts" and "specs", would render correctly on their respective article pages (e.g., /vibe-with/prompts/some-prompt-slug).
The author information was present in the Markdown files (e.g., authors: ["Michael Staton"]) but was not appearing on the rendered pages. This was impacting content attribution and user experience.

2. Incorrect Attempts and Understanding

Our initial efforts focused on the wrong parts of the rendering pipeline:
  • Misdiagnosis 1: OneArticleOnPage.astro or AuthorHandle.astro: We initially suspected the issue was within the final rendering components, OneArticleOnPage.astro or AuthorHandle.astro. We modified OneArticleOnPage.astro to flexibly handle author (string) or authors (array) in its data prop. This was a useful refinement but didn't solve the root cause because the author data wasn't reaching this component at all.
  • Misdiagnosis 2: Normalization in OneArticle.astro: We then correctly identified that the data prop being passed to OneArticleOnPage.astro was missing author information. We added author normalization logic (similar to ChangelogLayout.astro) into the OneArticle.astro layout. This ensured that if author data was present in the data prop received by OneArticle.astro, it would be correctly formatted as an authors array. However, server-side logs showed that the data prop arriving at OneArticle.astro still lacked author fields for the affected collections.
    astro
    // site/src/layouts/OneArticle.astro - Added normalization
    // ... (script section)
    const normalizeDataWithAuthors = (pageData) => {
      if (!pageData) return { authors: [] };
      let authorList = [];
      if (pageData.authors) {
        authorList = Array.isArray(pageData.authors)
          ? pageData.authors
          : [pageData.authors];
      } else if (pageData.author) {
        authorList = [pageData.author];
      }
      return {
        ...pageData,
        authors: authorList,
      };
    };
    const normalizedData = normalizeDataWithAuthors(data);
    // ...
    // (template section)
    <Component 
      content={transformedMdast}
      data={normalizedData} // Passed normalizedData
      articleHeading={title} 
    >
    This was a necessary step for robust data handling but didn't fix the upstream problem of missing data.

3. The "Aha!" Moment: Tracing Data Flow from Dynamic Routes

The breakthrough came when we realized that the "prompts" and "specs" collections were not standard Astro content collections located in src/content/ with a src/content/config.ts. Instead, they were handled by a unified dynamic route: site/src/pages/vibe-with/[collection]/[...slug].astro.
This dynamic route component was responsible for:
  1. Fetching entries using getCollection() (which worked, indicating Astro recognized them as collections somehow, likely via astro.config.mjs or implicit setup).
  2. Processing these entries in getStaticPaths and for page rendering.
  3. Passing data to the OneArticle.astro layout.
Upon inspecting site/src/pages/vibe-with/[collection]/[...slug].astro, we found that while it correctly fetched the full entry data (including all frontmatter like authors) using getCollection() and getEntry(), it was constructing a new, minimal contentData object to pass to OneArticle.astro. This new object only contained path, id, and collection, omitting all other frontmatter fields.
Original problematic code in site/src/pages/vibe-with/[collection]/[...slug].astro:
javascript
// ... inside the IIFE for rendering
  const contentData = {
    path: Astro.url.pathname,
    id: processedEntry.id,
    collection: finalCollection,
    // !!! All other frontmatter from processedEntry.data (like authors) was missing here !!!
  };

  return (
    <Layout /* ... */ >
      <OneArticle
        /* ... */
        data={contentData} // This data prop was incomplete
      />
    </Layout>
  );

4. The Final Solution

The fix was to ensure that the contentData object constructed in site/src/pages/vibe-with/[collection]/[...slug].astro included all the original frontmatter from processedEntry.data.
We modified the contentData assignment to spread processedEntry.data first, then add/override specific fields like path, id, and collection:
Corrected code in site/src/pages/vibe-with/[collection]/[...slug].astro:
javascript
// ... inside the IIFE for rendering
  const contentData = {
    ...processedEntry.data, // Spread all frontmatter from the processed entry
    path: Astro.url.pathname,    // Override/add path if necessary
    id: processedEntry.id,       // Override/add id if necessary
    collection: finalCollection, // Override/add collection if necessary
  };

  return (
    <Layout /* ... */ >
      <OneArticle
        /* ... */
        data={contentData} // Now data prop contains full frontmatter
      />
    </Layout>
  );
Summary of the Data Flow Fix:
  1. site/src/pages/vibe-with/[collection]/[...slug].astro: Now correctly passes the full frontmatter (including authors) from the Markdown file to OneArticle.astro via the contentData object.
  2. site/src/layouts/OneArticle.astro: Receives the complete frontmatter. Its normalizeDataWithAuthors function ensures authors is consistently an array.
  3. site/src/components/articles/OneArticleOnPage.astro: Receives the normalized data with an authors array and passes it to AuthorHandle.astro.
  4. site/src/components/basics/AuthorHandle.astro: Renders the author information.
This change ensured that the complete frontmatter, including author details, was propagated through the custom dynamic routing and layout hierarchy, allowing the author metadata to be rendered as intended.