🎞️
Next.jsでOGPを設定する方法
Next.js で OGP を設定する方法
Next.js で OGP(Open Graph Protocol)を設定することで、SNS でシェアされた際に適切なプレビュー画像とメタ情報を表示できます。本記事では、Next.js の App Router を使用した OGP 設定の実装方法を紹介します。
はじめに
OGP を設定することで、以下のようなメリットがあります:
- SNS でシェアされた際に、魅力的なプレビュー画像と情報が表示される
- SEO の向上
- クリック率の向上
Next.js では、opengraph-image.tsxというファイルコンベンションを使用することで、動的に OGP 画像を生成できます。
1. OGP 画像の生成
opengraph-image.tsx の作成
Next.js では、opengraph-image.tsxというファイルを作成することで、そのルート用の OGP 画像を自動生成できます。
まず、トップページ用の OGP 画像を作成します:
src/app/opengraph-image.tsx
import { generateOGPImage } from '@/utils/ogp/generate-image'
export default async function Image() {
return generateOGPImage({
title: 'サイト名',
subtitle: 'サイトの説明',
})
}
動的なルート(例:/posts/[id])の場合も、同様にopengraph-image.tsxを作成できます:
src/app/posts/[id]/opengraph-image.tsx
import { generateOGPImage } from '@/utils/ogp/generate-image'
import { getPost } from '@/lib/posts'
export default async function Image({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const post = await getPost(id)
if (!post) {
// エラー時のフォールバック画像を返す
return generateOGPImage({
title: '記事が見つかりません',
})
}
return generateOGPImage({
title: post.title,
subtitle: post.description,
})
}
OGP 画像生成ユーティリティ
OGP 画像を生成するためのユーティリティ関数を作成します。Next.js の ImageResponse を使用して、React コンポーネントから画像を生成できます。
このユーティリティでは、以下の要素で構成されています:
-
OGP_SIZE: OGP 画像の推奨サイズ(1200×630px)を定義 -
CardContent: 画像内に表示するコンテンツ(タイトルとサブタイトル)を表示するコンポーネント -
Container: 背景グラデーションとレイアウトを管理するコンポーネント -
generateOGPImage: これらのコンポーネントを組み合わせて、ImageResponseで画像を生成する関数
src/utils/ogp/generate-image.tsx
import { ImageResponse } from 'next/og'
export const OGP_SIZE = {
width: 1200,
height: 630,
}
interface CardContent {
title: string
subtitle?: string
}
function CardContent({ title, subtitle }: CardContent) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '80px',
backgroundColor: 'white',
borderRadius: '24px',
boxShadow:
'0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
maxWidth: '1000px',
}}
>
<h1
style={{
fontSize: '64px',
fontWeight: 'bold',
color: '#1f2937',
marginBottom: subtitle ? '40px' : '20px',
textAlign: 'center',
maxWidth: '900px',
}}
>
{title}
</h1>
{subtitle && (
<p
style={{
fontSize: '28px',
color: '#6b7280',
textAlign: 'center',
}}
>
{subtitle}
</p>
)}
</div>
)
}
function Container({ children }: { children: React.ReactNode }) {
return (
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
background: 'linear-gradient(to bottom, #3b82f6, #2563eb)',
}}
>
{children}
</div>
)
}
export function generateOGPImage(content: CardContent) {
return new ImageResponse(
(
<Container>
<CardContent {...content} />
</Container>
),
{
width: OGP_SIZE.width,
height: OGP_SIZE.height,
},
)
}
2. メタデータの設定
layout.tsx でのメタデータ設定
layout.tsxで OGP 画像を参照するように設定します:
src/app/layout.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'サイト名 - サイトの説明',
description: 'サイトの説明文',
openGraph: {
title: 'サイト名 - サイトの説明',
description: 'サイトの説明文',
url: 'https://example.com',
siteName: 'サイト名',
type: 'website',
locale: 'ja_JP',
images: [
{
url: '/opengraph-image',
width: 1200,
height: 630,
alt: 'サイト名 - サイトの説明',
},
],
},
twitter: {
card: 'summary_large_image',
title: 'サイト名 - サイトの説明',
description: 'サイトの説明文',
images: ['/opengraph-image'],
},
}
動的ルートでのメタデータ生成
動的なルートでは、generateMetadata関数を使用してメタデータを生成します:
src/app/posts/[id]/page.tsx
import type { Metadata } from 'next'
import { getPost } from '@/lib/posts'
export async function generateMetadata({
params,
}: {
params: Promise<{ id: string }>
}): Promise<Metadata> {
const { id } = await params
const post = await getPost(id)
if (!post) {
return {
title: '記事が見つかりません',
description: '指定された記事は存在しません。',
}
}
return {
title: `${post.title} | サイト名`,
description: post.description,
openGraph: {
title: post.title,
description: post.description,
type: 'article',
url: `https://example.com/posts/${id}`,
siteName: 'サイト名',
images: [`https://example.com/posts/${id}/opengraph-image`],
},
twitter: {
card: 'summary_large_image',
title: post.title,
description: post.description,
images: [`https://example.com/posts/${id}/opengraph-image`],
},
}
}
3. 共通メタデータの管理
コードの重複を避けるため、共通のメタデータを管理する関数を作成します:
src/lib/metadata.ts
import type { Metadata } from 'next'
export function createBaseMetadata(): Metadata {
return {
metadataBase: new URL('https://example.com'),
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
openGraph: {
siteName: 'サイト名',
type: 'website',
locale: 'ja_JP',
},
twitter: {
card: 'summary_large_image',
},
}
}
各ページのメタデータ生成関数で、この共通メタデータを使用します:
src/app/posts/[id]/page.tsx
import { createBaseMetadata } from '@/lib/metadata'
import type { Metadata } from 'next'
import { getPost } from '@/lib/posts'
export async function generateMetadata({
params,
}: {
params: Promise<{ id: string }>
}): Promise<Metadata> {
const { id } = await params
const baseMetadata = createBaseMetadata()
const post = await getPost(id)
if (!post) {
return {
...baseMetadata,
title: '記事が見つかりません',
description: '指定された記事は存在しません。',
}
}
return {
...baseMetadata,
title: `${post.title} | サイト名`,
description: post.description,
openGraph: {
...baseMetadata.openGraph,
title: post.title,
description: post.description,
url: `https://example.com/posts/${id}`,
images: [`https://example.com/posts/${id}/opengraph-image`],
},
twitter: {
...baseMetadata.twitter,
title: post.title,
description: post.description,
images: [`https://example.com/posts/${id}/opengraph-image`],
},
}
}
まとめ
Next.js で OGP を設定する方法を紹介しました。主なポイントは以下の通りです:
-
opengraph-image.tsxを使用した動的 OGP 画像生成: Next.js のファイルコンベンションを活用することで、簡単に OGP 画像を生成できます -
メタデータの適切な設定:
openGraphとtwitterのメタデータを設定することで、SNS での表示を最適化できます - 共通メタデータの管理: コードの重複を避け、保守性を向上させるため、共通メタデータを管理する関数を作成します
これらの実装により、SNS でシェアされた際に適切なプレビュー画像と情報が表示され、SEO の向上にもつながります。
Discussion