كيفية إضافة بيانات وصفية وإنشاء صور OG
يمكن استخدام واجهات برمجة تطبيقات البيانات الوصفية (Metadata APIs) لتعريف بيانات التطبيق الوصفية لتحسين تحسين محركات البحث (SEO) وقابلية المشاركة على الويب، وتشمل:
- كائن
metadata
الثابت - دالة
generateMetadata
الديناميكية - اتفاقيات ملفات خاصة يمكن استخدامها لإضافة أيقونات المفضلة وصور OG ثابتة أو مُنشأة ديناميكيًا.
مع كل الخيارات أعلاه، سيقوم Next.js تلقائيًا بإنشاء علامات <head>
ذات الصلة لصفحتك، والتي يمكن فحصها في أدوات مطوري المتصفح.
الحقول الافتراضية
هناك علامتان meta
افتراضيتان تتم إضافتهما دائمًا حتى إذا لم تحدد المسار بيانات وصفية:
- علامة meta charset تحدد ترميز الأحرف للموقع.
- علامة meta viewport تحدد عرض viewport ومقياسه للموقع للتكيف مع أجهزة مختلفة.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
يمكن تعريف حقول البيانات الوصفية الأخرى باستخدام كائن Metadata
(لـالبيانات الوصفية الثابتة) أو دالة generateMetadata
(لـالبيانات الوصفية المُنشأة).
البيانات الوصفية الثابتة
لتعريف بيانات وصفية ثابتة، قم بتصدير كائن Metadata
من ملف ثابت layout.js
أو page.js
. على سبيل المثال، لإضافة عنوان ووصف لمسار المدونة:
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'My Blog',
description: '...',
}
export default function Page() {}
export const metadata = {
title: 'My Blog',
description: '...',
}
export default function Page() {}
يمكنك عرض قائمة كاملة بالخيارات المتاحة في توثيق generateMetadata
.
البيانات الوصفية المُنشأة
يمكنك استخدام دالة generateMetadata
لجلب البيانات الوصفية التي تعتمد على البيانات. على سبيل المثال، لجلب العنوان والوصف لمنشور مدونة معين:
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: Promise<{ slug: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const slug = (await params).slug
// جلب معلومات المنشور
const post = await fetch(`https://api.vercel.app/blog/${slug}`).then((res) =>
res.json()
)
return {
title: post.title,
description: post.description,
}
}
export default function Page({ params, searchParams }: Props) {}
export async function generateMetadata({ params, searchParams }, parent) {
const slug = (await params).slug
// جلب معلومات المنشور
const post = await fetch(`https://api.vercel.app/blog/${slug}`).then((res) =>
res.json()
)
return {
title: post.title,
description: post.description,
}
}
export default function Page({ params, searchParams }) {}
خلف الكواليس، سيقوم Next.js ببث البيانات الوصفية بشكل منفصل عن واجهة المستخدم وحقنها في HTML بمجرد حلها.
تخزين طلبات البيانات مؤقتًا
قد تكون هناك حالات تحتاج فيها إلى جلب نفس البيانات لكل من البيانات الوصفية والصفحة نفسها. لتجنب الطلبات المكررة، يمكنك استخدام دالة cache
في React لتخزين القيمة المُرجعة وجلب البيانات مرة واحدة فقط. على سبيل المثال، لجلب معلومات منشور المدونة لكل من البيانات الوصفية والصفحة:
import { cache } from 'react'
import { db } from '@/app/lib/db'
// سيتم استخدام getPost مرتين، ولكن تنفيذها مرة واحدة فقط
export const getPost = cache(async (slug: string) => {
const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })
return res
})
import { cache } from 'react'
import { db } from '@/app/lib/db'
// سيتم استخدام getPost مرتين، ولكن تنفيذها مرة واحدة فقط
export const getPost = cache(async (slug) => {
const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })
return res
})
import { getPost } from '@/app/lib/data'
export async function generateMetadata({
params,
}: {
params: { slug: string }
}) {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.description,
}
}
export default async function Page({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return <div>{post.title}</div>
}
import { getPost } from '@/app/lib/data'
export async function generateMetadata({ params }) {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.description,
}
}
export default async function Page({ params }) {
const post = await getPost(params.slug)
return <div>{post.title}</div>
}
البيانات الوصفية المستندة إلى الملفات
الملفات الخاصة التالية متاحة للبيانات الوصفية:
- favicon.ico، apple-icon.jpg، و icon.jpg
- opengraph-image.jpg و twitter-image.jpg
- robots.txt
- sitemap.xml
يمكنك استخدام هذه لبيانات وصفية ثابتة، أو يمكنك إنشاء هذه الملفات برمجيًا باستخدام الكود.
أيقونات المفضلة (Favicons)
أيقونات المفضلة هي أيقونات صغيرة تمثل موقعك في الإشارات المرجعية ونتائج البحث. لإضافة أيقونة مفضلة إلى تطبيقك، أنشئ ملف favicon.ico
وأضفه إلى مجلد التطبيق الجذر.

يمكنك أيضًا إنشاء أيقونات مفضلة برمجيًا باستخدام الكود. راجع توثيق favicon لمزيد من المعلومات.
صور Open Graph الثابتة
صور Open Graph (OG) هي صور تمثل موقعك في وسائل التواصل الاجتماعي. لإضافة صورة OG ثابتة إلى تطبيقك، أنشئ ملف opengraph-image.png
في مجلد التطبيق الجذر.

يمكنك أيضًا إضافة صور OG لمسارات محددة عن طريق إنشاء ملف opengraph-image.png
أعمق في هيكل المجلد. على سبيل المثال، لإنشاء صورة OG خاصة بمسار /blog
، أضف ملف opengraph-image.jpg
داخل مجلد blog
.

ستأخذ الصورة الأكثر تحديدًا الأسبقية على أي صور OG فوقها في هيكل المجلد.
يتم دعم تنسيقات الصور الأخرى مثل
jpeg
وpng
وwebp
. راجع توثيق Open Graph Image لمزيد من المعلومات.
صور Open Graph المُنشأة
يسمح لك منشئ ImageResponse
بإنشاء صور ديناميكية باستخدام JSX و CSS. هذا مفيد لصور OG التي تعتمد على البيانات.
على سبيل المثال، لإنشاء صورة OG فريدة لكل منشور مدونة، أضف ملف opengraph-image.ts
داخل مجلد blog
، واستورد منشئ ImageResponse
من next/og
:
import { ImageResponse } from 'next/og'
import { getPost } from '@/app/lib/data'
// بيانات الصورة
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
// إنشاء الصورة
export default async function Image({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return new ImageResponse(
(
// عنصر JSX لـ ImageResponse
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{post.title}
</div>
)
)
}
import { ImageResponse } from 'next/og'
import { getPost } from '@/app/lib/data'
// بيانات الصورة
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
// إنشاء الصورة
export default async function Image({ params }) {
const post = await getPost(params.slug)
return new ImageResponse(
(
// عنصر JSX لـ ImageResponse
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{post.title}
</div>
)
)
}
يدعم ImageResponse
خصائص CSS الشائعة بما في ذلك flexbox والتحديد المطلق، والخطوط المخصصة، ولف النص، والمركزة، والصور المتداخلة. راجع القائمة الكاملة لخصائص CSS المدعومة.
ملاحظة جيدة:
- تتوفر أمثلة في Vercel OG Playground.
- يستخدم
ImageResponse
@vercel/og
، وsatori
، وresvg
لتحويل HTML و CSS إلى PNG.- يتم دعم flexbox ومجموعة فرعية من خصائص CSS فقط. التخطيطات المتقدمة (مثل
display: grid
) لن تعمل.