개발 slecs

아티클 페이지 Open Graph 메타 분리로 SEO 파이프라인 완성

목차

Base.astro에 article 전용 메타 props를 뚫고, [slug] 페이지에서 그걸 내려보내는 작업을 했다.

작업 자체는 심플해 보이지만, SEO 파이프라인을 제대로 닫는 작업이라 짚고 넘어갈 게 꽤 있다.


왜 지금 이 작업이었나

블로그나 콘텐츠 사이트에서 Base 레이아웃은 모든 페이지가 공유하는 껍데기다. 문제는 공용 껍데기이다 보니 처음엔 최소한의 메타만 박아두는 경우가 많다 — <title>, <meta name="description"> 정도.

그런데 아티클 페이지는 요구사항이 다르다. Open Graph의 og:typearticle이어야 하고, article:published_time, article:author 같은 article 전용 프로퍼티도 있어야 소셜 카드나 검색 엔진이 콘텐츠를 제대로 읽는다. 이걸 Base에 그냥 때려박으면 블로그 홈이나 태그 페이지 같은 non-article 페이지에도 엉뚱한 메타가 딸려 나간다.

그래서 나온 패턴이 "Base는 공통 뼈대만, article 전용 props는 선택적으로 받아서 조건부 렌더링"이다. 이번 커밋이 딱 그 구조를 만든 것.


작업 내용

변경된 파일은 두 개.

파일 역할 이번 변경
src/layouts/Base.astro 전역 레이아웃, <head> 관리 article 메타 props 인터페이스 추가 + 조건부 렌더링
src/pages/t/[slug]/index.astro 개별 아티클 페이지 Base에 article 메타 데이터 전달

Base.astro 쪽에서 props 인터페이스를 열어줬을 거고, 대략 이런 패턴이다.

---
interface Props {
  title: string;
  description?: string;
  // article 전용
  articleMeta?: {
    publishedTime?: string;
    author?: string;
    tags?: string[];
  };
}

const { title, description, articleMeta } = Astro.props;
---

<head>
  <title>{title}</title>
  <meta name="description" content={description} />

  {articleMeta && (
    <>
      <meta property="og:type" content="article" />
      <meta property="article:published_time" content={articleMeta.publishedTime} />
      <meta property="article:author" content={articleMeta.author} />
    </>
  )}
</head>

articleMeta가 없으면 og:type도 기본값(보통 website)으로 내려가고, article 전용 태그는 아예 렌더 안 된다. 페이지 타입에 따라 <head>가 달라지는 구조가 이렇게 잡힌다.

[slug]/index.astro에서는 frontmatter나 content collection에서 긁어온 데이터를 articleMeta에 조립해서 Base로 던지는 식.

---
const { slug } = Astro.params;
const post = await getEntry('posts', slug);

const articleMeta = {
  publishedTime: post.data.pubDate.toISOString(),
  author: post.data.author,
  tags: post.data.tags,
};
---

<Base title={post.data.title} description={post.data.description} articleMeta={articleMeta}>
  <!-- 본문 -->
</Base>

이 구조에서 챙겨야 할 것들

Astro 기반 콘텐츠 사이트에서 이런 작업을 할 때 몇 가지 포인트가 있다.

  • props optional 처리articleMeta를 optional로 두면 기존 페이지들은 아무것도 안 바꿔도 된다. 새 props 추가했다고 Base 쓰는 모든 페이지 손댈 필요가 없음.
  • og:type 기본값 — article 메타가 없을 때 og:typewebsite로 fallback하는 거 명시적으로 처리하는 게 깔끔하다. 소셜 미리보기 디버거에서 og:type 빠진 페이지는 경고 뜨기도 함.
  • 날짜 포맷article:published_time은 ISO 8601 형식이어야 한다. pubDate.toISOString() 같이 명시적으로 변환하지 않으면 소셜 크롤러가 못 읽는 경우 생김.
  • 태그 → article:tagtags 배열이 있으면 article:tag를 여러 개 찍어야 한다. 하나로 합쳐서 넣으면 의미 없음.

회고

Base 레이아웃 처음 짤 때 article 메타까지 미리 설계해두는 팀이 많지 않다. 초반엔 페이지 뜨는 것 자체에 집중하니까. 그러다 나중에 "소셜 공유했는데 카드가 이상해요" 이슈가 들어오면 그제야 <head> 뜯게 되는데, 그 시점에 이미 페이지가 많아져 있으면 수정 범위가 커진다.

이번처럼 props 인터페이스를 잘 잡아두면 나중에 article:section이나 article:modified_time 같은 필드 추가해도 Base만 건드리면 된다. [slug] 페이지에서 데이터만 얹어주면 끝.

SEO 작업이 "나중에 하면 되지" 하고 밀리기 쉬운 작업인데, 콘텐츠가 쌓이기 전에 파이프라인 잡아두는 게 훨씬 낫다는 걸 매번 느낀다.


다음은 article:tag 여러 개 렌더 처리랑 og:image 동적 생성 쪽 볼 것 같다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.