You are currently viewing Next.jsでMetatag(OGPタグ)を返却する

Next.jsでMetatag(OGPタグ)を返却する

React + Next.jsで作成したアプリ(フロントエンド)からOGPタグを返却したかったので調査したときのメモです

OGPタグはなぜ必要?

XServerさんの説明はこちら
https://www.xserver.ne.jp/bizhp/open-graph-protocol/

ざっくりな内容として「SNSなどにリンクをシェアしたときに、タイトルや画像を表示するための仕組み」です
今回、趣味開発しているWebアプリに「SNSで投稿内容をシェアするためのURLを発行する」機能を追加するにあたり、X(Twitter)などに画像やタイトルを表示させる必要があったため、OGPタグを追加することにしました。
(ちなみに、自分が作成しているサイトはライダー向けツーリングスポット共有サイトで、マップ上にスポットを投稿できるようなWebサイトです)

↓こんな感じで、Xポスト内に投稿した内容が画像付きで表示されるようになります

Next.jsでOGPタグを返却する仕組み

Next.jsで開発するアプリでOGPタグを返却する場合、以下の2通りの方法が利用できます

  • metadataオブジェクトを定義し、固定値を返却
  • generateMetaData関数を定義し、動的な値を返却

metadataオブジェクトを使用する場合

固定ページなど、動的に情報を取得する必要がない場合metadataオブジェクトをlayout.jsやpage.jsに定義してメタデータ(OGPタグなど)を返却することができます
https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadata-fields

動的な取得が必要なければ、こちらを利用するのが簡単そうですね!

generateMetada関数を使用する場合

例えば、ユーザーの投稿内容を表示するなど、内容を動的に取得する必要がある場合は「generateMetadata」ファンクションを使用する必要があります
https://nextjs.org/docs/app/api-reference/functions/generate-metadata

自分のサイトでは以下の方法で実装しています。実装先はapp/page.tsxになります

type Props = {
  params: Promise<{ id: string }>
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}

// SNSシェアリンク用のOGP生成処理
// https://www.project-ride.com/content_id=1 でアクセスされたときに実行される
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function generateMetadata({ params, searchParams }: Props, parent: ResolvingMetadata): Promise<Metadata> {
  
  const resolvedSearchParams = await searchParams
  const contentId = resolvedSearchParams.content_id
  const wwwBaseUrl = process.env.NEXT_PUBLIC_WWW_BASE_URL ?? ""
  const defaultImageUrl = `${process.env.NEXT_PUBLIC_IMAGE_BASE_URL ?? ""}${process.env.NEXT_PUBLIC_NO_IMAGE ?? ""}`  

  // もし content_id が URL にあれば...
  if (typeof contentId === 'string') {
    const content = await getContent(contentId);

    if (content) {
      const imageUrl = content.image_url
        ? (process.env.NEXT_PUBLIC_IMAGE_BASE_URL ?? "") + content.image_url
        : defaultImageUrl;

      const title = content.message.replace(/<br\s*\/?>/gi, '').substring(0, 30) + '...';
      const description = content.message;

      return {
        title: title, // タイトル用にメッセージを短縮
        description: description,
        openGraph: {
          title: title,
          description: description,
          url: `${wwwBaseUrl}?content_id=${contentId}`,
          images: [{ url: imageUrl }],
        },
        twitter: {
          card: 'summary_large_image',
          title: title,
          description: description,
          images: [imageUrl],
        }
      }
    }
  }

  // 有効なコンテンツが見つからない場合、デフォルト内容を返却
  return {
    title: 'RIDE-Mono',
    description: 'バイク乗りのためのおすすめスポット共有サイト',
    openGraph: {
      title: 'RIDE-Mono',
      description: 'バイク乗りのためのおすすめスポット共有サイト',
      url: wwwBaseUrl,
      images: [{ url: "" }], // デフォルト画像
    }
  }
}

スクリプト内のgetContent関数でユーザー投稿内容を取得し、メタデータを設定しています

export default function Home() {
  return (<TopPage />);
}

もともと記載していた内容をTopPageコンポーネントに分離しています
TopPageコンポーネントでは、’use client’を利用し、クライアントコンポーネントとして動作させています

プレビューが出ない時がある

生成したリンクをX(Twitter)に貼り付けたときにプレビューが表示されたり、されなかったりといった症状がでてデバッグに苦戦しました
実際には投稿後に正しくOGPの内容が表示されたので、投稿前のプレビューの精度は参考程度に考えていたほうが良いのかもしれません(逆に投稿したのに、想定したOGPの内容が表示されない場合は、何かを間違えている可能性が高い)

以上です

ということでNext.jsからMetadata(OGPタグ)を返却する方法でした
SPAだとどうやってMetadataを返却しているのか正直謎でしたが、調べてみるときちんと仕組みが備わっているんですね!

Metadataを生成することで、SNSシェア以外にもクローラー対応など、色々できることが増えそうです

コメントを残す