generateMetadata

يمكنك استخدام كائن metadata أو دالة generateMetadata لتعريف البيانات الوصفية.

كائن metadata

لتعريف بيانات وصفية ثابتة، قم بتصدير كائن Metadata من ملف layout.js أو page.js.

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: '...',
  description: '...',
}

export default function Page() {}
export const metadata = {
  title: '...',
  description: '...',
}

export default function Page() {}

راجع حقول البيانات الوصفية للحصول على قائمة كاملة بالخيارات المدعومة.

دالة generateMetadata

يمكن تعيين البيانات الوصفية الديناميكية التي تعتمد على معلومات ديناميكية، مثل معلمات المسار الحالية أو البيانات الخارجية أو metadata في الأجزاء الأصلية، عن طريق تصدير دالة generateMetadata تُرجع كائن Metadata.

import type { Metadata, ResolvingMetadata } from 'next'

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

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  // قراءة معلمات المسار
  const { id } = await params

  // جلب البيانات
  const product = await fetch(`https://.../${id}`).then((res) => res.json())

  // الوصول الاختياري إلى البيانات الوصفية الأصلية وتوسيعها (بدلاً من استبدالها)
  const previousImages = (await parent).openGraph?.images || []

  return {
    title: product.title,
    openGraph: {
      images: ['/some-specific-page-image.jpg', ...previousImages],
    },
  }
}

export default function Page({ params, searchParams }: Props) {}
export async function generateMetadata({ params, searchParams }, parent) {
  // قراءة معلمات المسار
  const { id } = await params

  // جلب البيانات
  const product = await fetch(`https://.../${id}`).then((res) => res.json())

  // الوصول الاختياري إلى البيانات الوصفية الأصلية وتوسيعها (بدلاً من استبدالها)
  const previousImages = (await parent).openGraph?.images || []

  return {
    title: product.title,
    openGraph: {
      images: ['/some-specific-page-image.jpg', ...previousImages],
    },
  }
}

export default function Page({ params, searchParams }) {}

ملاحظة جيدة:

  • يمكن إضافة البيانات الوصفية إلى ملفات layout.js و page.js.
  • سيقوم Next.js بحل البيانات الوصفية تلقائيًا وإنشاء علامات <head> ذات الصلة للصفحة.
  • تصديرات كائن metadata ودالة generateMetadata مدعومة فقط في مكونات الخادم (Server Components).
  • لا يمكنك تصدير كل من كائن metadata ودالة generateMetadata من نفس مقطع المسار.
  • طلبات fetch داخل generateMetadata يتم تخزينها مؤقتًا تلقائيًا لنفس البيانات عبر generateMetadata و generateStaticParams والتخطيطات والصفحات ومكونات الخادم.
  • يمكن استخدام cache في React إذا كان fetch غير متاح.
  • البيانات الوصفية المستندة إلى الملفات لها الأولوية الأعلى وستتجاوز كائن metadata ودالة generateMetadata.

المرجع

المعاملات

تقبل دالة generateMetadata المعاملات التالية:

  • props - كائن يحتوي على معلمات المسار الحالي:

    • params - كائن يحتوي على معلمات المسار الديناميكي من المقطع الجذري وصولاً إلى المقطع الذي يتم استدعاء generateMetadata منه. أمثلة:

      المسارالرابطparams
      app/shop/[slug]/page.js/shop/1{ slug: '1' }
      app/shop/[tag]/[item]/page.js/shop/1/2{ tag: '1', item: '2' }
      app/shop/[...slug]/page.js/shop/1/2{ slug: ['1', '2'] }
    • searchParams - كائن يحتوي على معلمات البحث (search params) للرابط الحالي. أمثلة:

      الرابطsearchParams
      /shop?a=1{ a: '1' }
      /shop?a=1&b=2{ a: '1', b: '2' }
      /shop?a=1&a=2{ a: ['1', '2'] }
  • parent - وعد بحل البيانات الوصفية من مقاطع المسار الأصلية.

القيم المرجعة

يجب أن تُرجع generateMetadata كائن Metadata يحتوي على حقل بيانات وصفية واحد أو أكثر.

ملاحظة جيدة:

  • إذا كانت البيانات الوصفية لا تعتمد على معلومات وقت التشغيل، فيجب تعريفها باستخدام كائن metadata الثابت بدلاً من generateMetadata.
  • يتم تخزين طلبات fetch مؤقتًا تلقائيًا لنفس البيانات عبر generateMetadata و generateStaticParams والتخطيطات والصفحات ومكونات الخادم. يمكن استخدام cache في React إذا كان fetch غير متاح.
  • searchParams متاحة فقط في مقاطع page.js.
  • يمكن أيضًا استخدام طرق Next.js redirect() و notFound() داخل generateMetadata.

حقول البيانات الوصفية

الحقول التالية مدعومة:

title

يُستخدم سمة title لتعيين عنوان المستند. يمكن تعريفه كـ سلسلة نصية بسيطة أو كائن قالب اختياري.

سلسلة نصية
layout.js | page.js
export const metadata = {
  title: 'Next.js',
}
<head> output
<title>Next.js</title>
default

يمكن استخدام title.default لتوفير عنوان احتياطي لمقاطع المسار الفرعية التي لا تحدد title.

app/layout.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    default: 'Acme',
  },
}
app/about/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {}

// الناتج: <title>Acme</title>
template

يمكن استخدام title.template لإضافة بادئة أو لاحقة إلى titles المحددة في مقاطع المسار الفرعية.

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // مطلوب قيمة افتراضية عند إنشاء قالب
  },
}
export const metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // مطلوب قيمة افتراضية عند إنشاء قالب
  },
}
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'About',
}

// الناتج: <title>About | Acme</title>
export const metadata = {
  title: 'About',
}

// الناتج: <title>About | Acme</title>

ملاحظة جيدة:

  • title.template ينطبق على مقاطع المسار الفرعية وليس المقطع الذي تم تعريفه فيه. هذا يعني:

    • title.default مطلوب عند إضافة title.template.
    • لن ينطبق title.template المحدد في layout.js على title المحدد في page.js لنفس مقطع المسار.
    • title.template المحدد في page.js ليس له تأثير لأن الصفحة دائمًا ما تكون المقطع النهائي (ليس لديها أي مقاطع مسار فرعية).
  • title.template ليس له تأثير إذا لم يحدد المسار title أو title.default.

absolute

يمكن استخدام title.absolute لتوفير عنوان يتجاهل title.template المحدد في المقاطع الأصلية.

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
  },
}
export const metadata = {
  title: {
    template: '%s | Acme',
  },
}
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    absolute: 'About',
  },
}

// الناتج: <title>About</title>
export const metadata = {
  title: {
    absolute: 'About',
  },
}

// الناتج: <title>About</title>

ملاحظة جيدة:

  • layout.js

    • title (سلسلة نصية) و title.default يحددان العنوان الافتراضي للمقاطع الفرعية (التي لا تحدد title الخاصة بها). سيعزز title.template من أقرب مقطع أصل إذا كان موجودًا.
    • title.absolute يحدد العنوان الافتراضي للمقاطع الفرعية. يتجاهل title.template من المقاطع الأصلية.
    • title.template يحدد قالب عنوان جديد للمقاطع الفرعية.
  • page.js

    • إذا لم تحدد الصفحة عنوانها الخاص، سيتم استخدام العنوان المحلول لأقرب مقطع أصل.
    • title (سلسلة نصية) يحدد عنوان المسار. سيعزز title.template من أقرب مقطع أصل إذا كان موجودًا.
    • title.absolute يحدد عنوان المسار. يتجاهل title.template من المقاطع الأصلية.
    • title.template ليس له تأثير في page.js لأن الصفحة دائمًا ما تكون المقطع النهائي للمسار.

description

layout.js | page.js
export const metadata = {
  description: 'إطار عمل React للويب',
}
<head> output
<meta name="description" content="إطار عمل React للويب" />

حقول أخرى

layout.js | page.js
export const metadata = {
  generator: 'Next.js',
  applicationName: 'Next.js',
  referrer: 'origin-when-cross-origin',
  keywords: ['Next.js', 'React', 'JavaScript'],
  authors: [{ name: 'Seb' }, { name: 'Josh', url: 'https://nextjs.org' }],
  creator: 'Jiachi Liu',
  publisher: 'Sebastian Markbåge',
  formatDetection: {
    email: false,
    address: false,
    telephone: false,
  },
}
<head> output
<meta name="application-name" content="Next.js" />
<meta name="author" content="Seb" />
<link rel="author" href="https://nextjs.org" />
<meta name="author" content="Josh" />
<meta name="generator" content="Next.js" />
<meta name="keywords" content="Next.js,React,JavaScript" />
<meta name="referrer" content="origin-when-cross-origin" />
<meta name="color-scheme" content="dark" />
<meta name="creator" content="Jiachi Liu" />
<meta name="publisher" content="Sebastian Markbåge" />
<meta name="format-detection" content="telephone=no, address=no, email=no" />

metadataBase

metadataBase هو خيار ملائم لتعيين بادئة عنوان URL أساسي لحقول metadata التي تتطلب عنوان URL مؤهلًا بالكامل.

  • يسمح metadataBase لحقول metadata المستندة إلى URL المحددة في مقطع المسار الحالي وما دونه باستخدام مسار نسبي بدلاً من عنوان URL المطلق المطلوب.
  • سيتم دمج المسار النسبي للحقل مع metadataBase لتشكيل عنوان URL مؤهل بالكامل.
layout.js | page.js
export const metadata = {
  metadataBase: new URL('https://acme.com'),
  alternates: {
    canonical: '/',
    languages: {
      'en-US': '/en-US',
      'de-DE': '/de-DE',
    },
  },
  openGraph: {
    images: '/og-image.png',
  },
}
<head> output
<link rel="canonical" href="https://acme.com" />
<link rel="alternate" hreflang="en-US" href="https://acme.com/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://acme.com/de-DE" />
<meta property="og:image" content="https://acme.com/og-image.png" />

ملاحظة جيدة:

  • يتم تعيين metadataBase عادةً في app/layout.js الجذر لتطبيق حقول metadata المستندة إلى URL عبر جميع المسارات.
  • يمكن تكوين جميع حقول metadata المستندة إلى URL التي تتطلب عناوين URL مطلقة باستخدام خيار metadataBase.
  • يمكن أن يحتوي metadataBase على نطاق فرعي مثل https://app.acme.com أو مسار أساسي مثل https://acme.com/start/from/here
  • إذا قدم حقل metadata عنوان URL مطلقًا، سيتم تجاهل metadataBase.
  • سيؤدي استخدام مسار نسبي في حقل metadata مستند إلى URL بدون تكوين metadataBase إلى حدوث خطأ في البناء.
  • سيقوم Next.js بتطبيع الشرطات المكررة بين metadataBase (مثل https://acme.com/) وحقل نسبي (مثل /path) إلى شرطة واحدة (مثل https://acme.com/path)

تكوين URL

يفضل تكوين URL نية المطور على دلالات اجتياز الدليل الافتراضية.

  • يتم تطبيع الشرطات في نهاية metadataBase وحقول metadata.
  • يتم التعامل مع المسار "المطلق" في حقل metadata (الذي عادةً ما يستبدل مسار URL بالكامل) على أنه مسار "نسبي" (يبدأ من نهاية metadataBase).

على سبيل المثال، بالنظر إلى metadataBase التالي:

import type { Metadata } from 'next'

export const metadata: Metadata = {
  metadataBase: new URL('https://acme.com'),
}
export const metadata = {
  metadataBase: new URL('https://acme.com'),
}

سيتم حل أي حقول metadata التي ترث metadataBase أعلاه وتعيين قيمتها الخاصة على النحو التالي:

حقل metadataعنوان URL المحلول
/https://acme.com
./https://acme.com
paymentshttps://acme.com/payments
/paymentshttps://acme.com/payments
./paymentshttps://acme.com/payments
../paymentshttps://acme.com/payments
https://beta.acme.com/paymentshttps://beta.acme.com/payments

openGraph

layout.js | page.js
export const metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    url: 'https://nextjs.org',
    siteName: 'Next.js',
    images: [
      {
        url: 'https://nextjs.org/og.png', // يجب أن يكون عنوان URL مطلقًا
        width: 800,
        height: 600,
      },
      {
        url: 'https://nextjs.org/og-alt.png', // يجب أن يكون عنوان URL مطلقًا
        width: 1800,
        height: 1600,
        alt: 'النص البديل المخصص',
      },
    ],
    videos: [
      {
        url: 'https://nextjs.org/video.mp4', // يجب أن يكون عنوان URL مطلقًا
        width: 800,
        height: 600,
      },
    ],
    audio: [
      {
        url: 'https://nextjs.org/audio.mp3', // يجب أن يكون عنوان URL مطلقًا
      },
    ],
    locale: 'en_US',
    type: 'website',
  },
}
<head> output
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:url" content="https://nextjs.org/" />
<meta property="og:site_name" content="Next.js" />
<meta property="og:locale" content="en_US" />
<meta property="og:image" content="https://nextjs.org/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
<meta property="og:image" content="https://nextjs.org/og-alt.png" />
<meta property="og:image:width" content="1800" />
<meta property="og:image:height" content="1600" />
<meta property="og:image:alt" content="النص البديل المخصص" />
<meta property="og:video" content="https://nextjs.org/video.mp4" />
<meta property="og:video:width" content="800" />
<meta property="og:video:height" content="600" />
<meta property="og:audio" content="https://nextjs.org/audio.mp3" />
<meta property="og:type" content="website" />
layout.js | page.js
export const metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    type: 'article',
    publishedTime: '2023-01-01T00:00:00.000Z',
    authors: ['Seb', 'Josh'],
  },
}
<head> output
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2023-01-01T00:00:00.000Z" />
<meta property="article:author" content="Seb" />
<meta property="article:author" content="Josh" />

معلومة مفيدة:

  • قد يكون استخدام واجهة برمجة تطبيق Metadata المعتمدة على الملفات لصور Open Graph أكثر ملاءمة. بدلاً من الحاجة إلى مزامنة تصدير التكوين مع الملفات الفعلية، ستقوم واجهة برمجة التطبيق المعتمدة على الملفات بإنشاء بيانات التعريف الصحيحة تلقائيًا لك.

robots

layout.tsx | page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  robots: {
    index: true,
    follow: true,
    nocache: false,
    googleBot: {
      index: true,
      follow: true,
      noimageindex: false,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
}
<head> output
<meta name="robots" content="index, follow" />
<meta
  name="googlebot"
  content="index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1"
/>

icons

معلومة مفيدة: نوصي باستخدام واجهة برمجة تطبيق Metadata المعتمدة على الملفات للأيقونات حيثما أمكن ذلك. بدلاً من الحاجة إلى مزامنة تصدير التكوين مع الملفات الفعلية، ستقوم واجهة برمجة التطبيق المعتمدة على الملفات بإنشاء بيانات التعريف الصحيحة تلقائيًا لك.

layout.js | page.js
export const metadata = {
  icons: {
    icon: '/icon.png',
    shortcut: '/shortcut-icon.png',
    apple: '/apple-icon.png',
    other: {
      rel: 'apple-touch-icon-precomposed',
      url: '/apple-touch-icon-precomposed.png',
    },
  },
}
<head> output
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
  rel="apple-touch-icon-precomposed"
  href="/apple-touch-icon-precomposed.png"
/>
layout.js | page.js
export const metadata = {
  icons: {
    icon: [
      { url: '/icon.png' },
      new URL('/icon.png', 'https://example.com'),
      { url: '/icon-dark.png', media: '(prefers-color-scheme: dark)' },
    ],
    shortcut: ['/shortcut-icon.png'],
    apple: [
      { url: '/apple-icon.png' },
      { url: '/apple-icon-x3.png', sizes: '180x180', type: 'image/png' },
    ],
    other: [
      {
        rel: 'apple-touch-icon-precomposed',
        url: '/apple-touch-icon-precomposed.png',
      },
    ],
  },
}
<head> output
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="icon" href="https://example.com/icon.png" />
<link rel="icon" href="/icon-dark.png" media="(prefers-color-scheme: dark)" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
  rel="apple-touch-icon-precomposed"
  href="/apple-touch-icon-precomposed.png"
/>
<link
  rel="apple-touch-icon"
  href="/apple-icon-x3.png"
  sizes="180x180"
  type="image/png"
/>

معلومة مفيدة: لم تعد علامات meta من نوع msapplication-* مدعومة في إصدارات Chromium من Microsoft Edge، وبالتالي لم تعد هناك حاجة إليها.

themeColor

مهمل: خيار themeColor في metadata مهمل اعتبارًا من Next.js 14. يرجى استخدام تكوين viewport بدلاً من ذلك.

colorScheme

مهمل: خيار colorScheme في metadata مهمل اعتبارًا من Next.js 14. يرجى استخدام تكوين viewport بدلاً من ذلك.

manifest

بيان تطبيق ويب، كما هو محدد في مواصفات بيان تطبيق الويب.

layout.js | page.js
export const metadata = {
  manifest: 'https://nextjs.org/manifest.json',
}
<head> output
<link rel="manifest" href="https://nextjs.org/manifest.json" />

twitter

تستخدم مواصفات تويتر (بشكل مفاجئ) لأكثر من مجرد X (المعروف سابقًا باسم تويتر).

تعرف على المزيد حول مرجع ترميز بطاقة تويتر.

layout.js | page.js
export const metadata = {
  twitter: {
    card: 'summary_large_image',
    title: 'Next.js',
    description: 'The React Framework for the Web',
    siteId: '1467726470533754880',
    creator: '@nextjs',
    creatorId: '1467726470533754880',
    images: ['https://nextjs.org/og.png'], // يجب أن يكون عنوان URL مطلقًا
  },
}
<head> output
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
layout.js | page.js
export const metadata = {
  twitter: {
    card: 'app',
    title: 'Next.js',
    description: 'The React Framework for the Web',
    siteId: '1467726470533754880',
    creator: '@nextjs',
    creatorId: '1467726470533754880',
    images: {
      url: 'https://nextjs.org/og.png',
      alt: 'شعار Next.js',
    },
    app: {
      name: 'twitter_app',
      id: {
        iphone: 'twitter_app://iphone',
        ipad: 'twitter_app://ipad',
        googleplay: 'twitter_app://googleplay',
      },
      url: {
        iphone: 'https://iphone_url',
        ipad: 'https://ipad_url',
      },
    },
  },
}
<head> output
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:card" content="app" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
<meta name="twitter:image:alt" content="شعار Next.js" />
<meta name="twitter:app:name:iphone" content="twitter_app" />
<meta name="twitter:app:id:iphone" content="twitter_app://iphone" />
<meta name="twitter:app:id:ipad" content="twitter_app://ipad" />
<meta name="twitter:app:id:googleplay" content="twitter_app://googleplay" />
<meta name="twitter:app:url:iphone" content="https://iphone_url" />
<meta name="twitter:app:url:ipad" content="https://ipad_url" />
<meta name="twitter:app:name:ipad" content="twitter_app" />
<meta name="twitter:app:name:googleplay" content="twitter_app" />

viewport

مهمل: خيار viewport في metadata مهمل اعتبارًا من Next.js 14. يرجى استخدام تكوين viewport بدلاً من ذلك.

verification

layout.js | page.js
export const metadata = {
  verification: {
    google: 'google',
    yandex: 'yandex',
    yahoo: 'yahoo',
    other: {
      me: ['my-email', 'my-link'],
    },
  },
}
<head> output
<meta name="google-site-verification" content="google" />
<meta name="y_key" content="yahoo" />
<meta name="yandex-verification" content="yandex" />
<meta name="me" content="my-email" />
<meta name="me" content="my-link" />

appleWebApp

layout.js | page.js
export const metadata = {
  itunes: {
    appId: 'myAppStoreID',
    appArgument: 'myAppArgument',
  },
  appleWebApp: {
    title: 'تطبيق ويب Apple',
    statusBarStyle: 'black-translucent',
    startupImage: [
      '/assets/startup/apple-touch-startup-image-768x1004.png',
      {
        url: '/assets/startup/apple-touch-startup-image-1536x2008.png',
        media: '(device-width: 768px) and (device-height: 1024px)',
      },
    ],
  },
}
<head> output
<meta
  name="apple-itunes-app"
  content="app-id=myAppStoreID, app-argument=myAppArgument"
/>
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="تطبيق ويب Apple" />
<link
  href="/assets/startup/apple-touch-startup-image-768x1004.png"
  rel="apple-touch-startup-image"
/>
<link
  href="/assets/startup/apple-touch-startup-image-1536x2008.png"
  media="(device-width: 768px) and (device-height: 1024px)"
  rel="apple-touch-startup-image"
/>
<meta
  name="apple-mobile-web-app-status-bar-style"
  content="black-translucent"
/>

alternates

layout.js | page.js
export const metadata = {
  alternates: {
    canonical: 'https://nextjs.org',
    languages: {
      'en-US': 'https://nextjs.org/en-US',
      'de-DE': 'https://nextjs.org/de-DE',
    },
    media: {
      'only screen and (max-width: 600px)': 'https://nextjs.org/mobile',
    },
    types: {
      'application/rss+xml': 'https://nextjs.org/rss',
    },
  },
}
<head> output
<link rel="canonical" href="https://nextjs.org" />
<link rel="alternate" hreflang="en-US" href="https://nextjs.org/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://nextjs.org/de-DE" />
<link
  rel="alternate"
  media="only screen and (max-width: 600px)"
  href="https://nextjs.org/mobile"
/>
<link
  rel="alternate"
  type="application/rss+xml"
  href="https://nextjs.org/rss"
/>
layout.js | page.js
export const metadata = {
  appLinks: {
    ios: {
      url: 'https://nextjs.org/ios',
      app_store_id: 'app_store_id',
    },
    android: {
      package: 'com.example.android/package',
      app_name: 'app_name_android',
    },
    web: {
      url: 'https://nextjs.org/web',
      should_fallback: true,
    },
  },
}
<head> output
<meta property="al:ios:url" content="https://nextjs.org/ios" />
<meta property="al:ios:app_store_id" content="app_store_id" />
<meta property="al:android:package" content="com.example.android/package" />
<meta property="al:android:app_name" content="app_name_android" />
<meta property="al:web:url" content="https://nextjs.org/web" />
<meta property="al:web:should_fallback" content="true" />

archives

يصف مجموعة من السجلات أو المستندات أو المواد الأخرى ذات الأهمية التاريخية (المصدر).

layout.js | page.js
export const metadata = {
  archives: ['https://nextjs.org/13'],
}
<head> output
<link rel="archives" href="https://nextjs.org/13" />

assets

layout.js | page.js
export const metadata = {
  assets: ['https://nextjs.org/assets'],
}
<head> output
<link rel="assets" href="https://nextjs.org/assets" />

bookmarks

layout.js | page.js
export const metadata = {
  bookmarks: ['https://nextjs.org/13'],
}
<head> output
<link rel="bookmarks" href="https://nextjs.org/13" />

category

layout.js | page.js
export const metadata = {
  category: 'technology',
}
<head> output
<meta name="category" content="technology" />

facebook

يمكنك توصيل تطبيق Facebook أو حساب Facebook بصفحة الويب الخاصة بك لبعض ملحقات Facebook الاجتماعية توثيق Facebook

معلومة مفيدة: يمكنك تحديد إما appId أو admins، ولكن ليس كلاهما.

layout.js | page.js
export const metadata = {
  facebook: {
    appId: '12345678',
  },
}
<head> output
<meta property="fb:app_id" content="12345678" />
layout.js | page.js
export const metadata = {
  facebook: {
    admins: '12345678',
  },
}
<head> output
<meta property="fb:admins" content="12345678" />

إذا كنت تريد إنشاء علامات meta متعددة لـ fb:admins، يمكنك استخدام قيمة مصفوفة.

layout.js | page.js
export const metadata = {
  facebook: {
    admins: ['12345678', '87654321'],
  },
}
<head> output
<meta property="fb:admins" content="12345678" />
<meta property="fb:admins" content="87654321" />

pinterest

يمكنك تمكين أو تعطيل Pinterest Rich Pins على صفحة الويب الخاصة بك.

layout.js | page.js
export const metadata = {
  pinterest: {
    richPin: true,
  },
}
<head> output
<meta name="pinterest-rich-pin" content="true" />

other

يجب أن تغطي خيارات بيانات التعريف المدمجة جميع الاحتياجات. ومع ذلك، قد تكون هناك علامات بيانات تعريف مخصصة خاصة بموقعك، أو علامات بيانات تعريف جديدة تم إصدارها للتو. يمكنك استخدام خيار other لعرض أي علامة بيانات تعريف مخصصة.

layout.js | page.js
export const metadata = {
  other: {
    custom: 'meta',
  },
}
<head> output
<meta name="custom" content="meta" />

إذا كنت تريد إنشاء علامات meta متعددة بنفس المفتاح، يمكنك استخدام قيمة مصفوفة.

layout.js | page.js
export const metadata = {
  other: {
    custom: ['meta1', 'meta2'],
  },
}
<head> output
<meta name="custom" content="meta1" /> <meta name="custom" content="meta2" />

بيانات التعريف غير المدعومة

لا يوجد حاليًا دعم مدمج لأنواع بيانات التعريف التالية. ومع ذلك، لا يزال يمكن عرضها في التخطيط أو الصفحة نفسها.

الأنواع

يمكنك إضافة أمان النوع إلى البيانات الوصفية (metadata) باستخدام نوع Metadata. إذا كنت تستخدم ملحق TypeScript المدمج في بيئة التطوير الخاصة بك، فلن تحتاج إلى إضافة النوع يدويًا، ولكن يمكنك إضافة ذلك بشكل صريح إذا أردت.

كائن metadata

layout.tsx | page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Next.js',
}

دالة generateMetadata

دالة عادية
layout.tsx | page.tsx
import type { Metadata } from 'next'

export function generateMetadata(): Metadata {
  return {
    title: 'Next.js',
  }
}
دالة غير متزامنة (Async)
layout.tsx | page.tsx
import type { Metadata } from 'next'

export async function generateMetadata(): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}
مع خاصية القطعة (segment props)
layout.tsx | page.tsx
import type { Metadata } from 'next'

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

export function generateMetadata({ params, searchParams }: Props): Metadata {
  return {
    title: 'Next.js',
  }
}

export default function Page({ params, searchParams }: Props) {}
مع البيانات الوصفية الأصلية (parent metadata)
layout.tsx | page.tsx
import type { Metadata, ResolvingMetadata } from 'next'

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}
مشاريع JavaScript

لمشاريع JavaScript، يمكنك استخدام JSDoc لإضافة أمان النوع.

layout.js | page.js
/** @type {import("next").Metadata} */
export const metadata = {
  title: 'Next.js',
}
البيانات الوصفيةالتوصية
<meta http-equiv="...">استخدم رؤوس HTTP المناسبة عبر redirect()، البرمجية الوسيطة (Middleware)، رؤوس الأمان
<base>عرض العلامة في التنسيق (layout) أو الصفحة نفسها.
<noscript>عرض العلامة في التنسيق أو الصفحة نفسها.
<style>تعلم المزيد حول التنسيق في Next.js.
<script>تعلم المزيد حول استخدام النصوص البرمجية (scripts).
<link rel="stylesheet" />import أوراق الأنماط مباشرة في التنسيق أو الصفحة نفسها.
<link rel="preload />استخدم طريقة ReactDOM المسبقة (preload method)
<link rel="preconnect" />استخدم طريقة ReactDOM للاتصال المسبق (preconnect method)
<link rel="dns-prefetch" />استخدم طريقة ReactDOM للبحث المسبق عن DNS (prefetchDNS method)

تلميحات الموارد (Resource hints)

يحتوي عنصر <link> على عدد من الكلمات الرئيسية rel التي يمكن استخدامها للإشارة إلى المتصفح بأن موردًا خارجيًا قد يكون مطلوبًا. يستخدم المتصفح هذه المعلومات لتطبيق تحسينات التحميل المسبق اعتمادًا على الكلمة الرئيسية.

بينما لا تدعم واجهة برمجة تطبيق البيانات الوصفية هذه التلميحات مباشرة، يمكنك استخدام طرق ReactDOM الجديدة لإدراجها بأمان في <head> المستند.

'use client'

import ReactDOM from 'react-dom'

export function PreloadResources() {
  ReactDOM.preload('...', { as: '...' })
  ReactDOM.preconnect('...', { crossOrigin: '...' })
  ReactDOM.prefetchDNS('...')

  return '...'
}
'use client'

import ReactDOM from 'react-dom'

export function PreloadResources() {
  ReactDOM.preload('...', { as: '...' })
  ReactDOM.preconnect('...', { crossOrigin: '...' })
  ReactDOM.prefetchDNS('...')

  return '...'
}

ابدأ تحميل مورد في وقت مبكر من دورة حياة عرض الصفحة (في المتصفح). وثائق MDN.

ReactDOM.preload(href: string, options: { as: string })
<head> output
<link rel="preload" href="..." as="..." />

ابدأ اتصالًا مسبقًا بأصل (origin). وثائق MDN.

ReactDOM.preconnect(href: string, options?: { crossOrigin?: string })
<head> output
<link rel="preconnect" href="..." crossorigin />

حاول حل اسم نطاق قبل طلب الموارد. وثائق MDN.

ReactDOM.prefetchDNS(href: string)
<head> output
<link rel="dns-prefetch" href="..." />

معلومة جيدة:

  • هذه الطرق مدعومة حاليًا فقط في مكونات العميل (Client Components)، والتي لا تزال تُعرض من جانب الخادم عند التحميل الأولي للصفحة.
  • الميزات المدمجة في Next.js مثل next/font، next/image و next/script تتعامل تلقائيًا مع تلميحات الموارد ذات الصلة.

السلوك

الحقول الافتراضية

هناك علامتا meta افتراضيتان تُضافان دائمًا حتى إذا لم تحدد المسار بيانات وصفية:

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

معلومة جيدة: يمكنك تجاوز علامة viewport الافتراضية.

بث البيانات الوصفية (Streaming metadata)

يتم بث البيانات الوصفية التي تُرجعها generateMetadata إلى العميل. هذا يسمح لـ Next.js بحقن البيانات الوصفية في HTML بمجرد حلها.

نظرًا لأن بيانات وصفية الصفحة تستهدف بشكل أساسي برامج الروبوت والمفهرسات، سيقوم Next.js ببث البيانات الوصفية للروبوتات التي يمكنها تنفيذ JavaScript وفحص DOM الصفحة بالكامل (مثل Googlebot). ومع ذلك، ستستمر البيانات الوصفية في منع عرض الصفحة للروبوتات المحدودة بـ HTML (مثل Twitterbot) حيث لا يمكنها تنفيذ JavaScript أثناء الزحف.

يتم اكتشاف وكيل المستخدم للطلبات الواردة تلقائيًا لتحديد ما إذا كان سيتم تقديم بيانات وصفية متدفقة أو التراجع إلى البيانات الوصفية الحاجزة.

إذا كنت بحاجة إلى تخصيص هذه القائمة، يمكنك تعريفها يدويًا باستخدام خيار htmlLimitedBots في next.config.js. سيتأكد Next.js من أن وكلاء المستخدم الذين يتطابقون مع هذا التعبير المنتظم يتلقون بيانات وصفية حاجزة عند طلب صفحة الويب الخاصة بك.

import type { NextConfig } from 'next'

const config: NextConfig = {
  htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}

export default config
module.exports = {
  htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}

سيؤدي تحديد تكوين htmlLimitedBots إلى تجاوز القائمة الافتراضية لـ Next.js، مما يمنحك سيطرة كاملة على وكلاء المستخدم الذين يجب أن يختاروا هذا السلوك. هذا سلوك متقدم، ويجب أن يكون الافتراضي كافيًا لمعظم الحالات.

الترتيب

يتم تقييم البيانات الوصفية بالترتيب، بدءًا من القطعة الجذرية وصولاً إلى القطعة الأقرب إلى قطعة page.js النهائية. على سبيل المثال:

  1. app/layout.tsx (التنسيق الجذري)
  2. app/blog/layout.tsx (تنسيق المدونة المتداخل)
  3. app/blog/[slug]/page.tsx (صفحة المدونة)

الدمج

بعد ترتيب التقييم، يتم دمج كائنات البيانات الوصفية المصدرة من عدة أجزاء في نفس المسار بشكل سطحي معًا لتشكيل ناتج البيانات الوصفية النهائي للمسار. يتم استبدال المفاتيح المكررة بناءً على ترتيبها.

هذا يعني أن البيانات الوصفية ذات الحقول المتداخلة مثل openGraph و robots التي تم تعريفها في جزء سابق يتم تجاوزها بواسطة الجزء الأخير الذي يحددها.

تجاوز الحقول

app/layout.js
export const metadata = {
  title: 'Acme',
  openGraph: {
    title: 'Acme',
    description: 'Acme is a...',
  },
}
app/blog/page.js
export const metadata = {
  title: 'Blog',
  openGraph: {
    title: 'Blog',
  },
}

// الناتج:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />

في المثال أعلاه:

  • يتم استبدال title من app/layout.js بـ title في app/blog/page.js.
  • يتم استبدال جميع حقول openGraph من app/layout.js في app/blog/page.js لأن app/blog/page.js يحدد بيانات openGraph الوصفية. لاحظ غياب openGraph.description.

إذا كنت ترغب في مشاركة بعض الحقول المتداخلة بين الأجزاء أثناء تجاوز البعض الآخر، يمكنك استخراجها إلى متغير منفصل:

app/shared-metadata.js
export const openGraphImage = { images: ['http://...'] }
app/page.js
import { openGraphImage } from './shared-metadata'

export const metadata = {
  openGraph: {
    ...openGraphImage,
    title: 'Home',
  },
}
app/about/page.js
import { openGraphImage } from '../shared-metadata'

export const metadata = {
  openGraph: {
    ...openGraphImage,
    title: 'About',
  },
}

في المثال أعلاه، يتم مشاركة صورة OG بين app/layout.js و app/about/page.js بينما تختلف العناوين.

وراثة الحقول

app/layout.js
export const metadata = {
  title: 'Acme',
  openGraph: {
    title: 'Acme',
    description: 'Acme is a...',
  },
}
app/about/page.js
export const metadata = {
  title: 'About',
}

// الناتج:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />

ملاحظات

  • يتم استبدال title من app/layout.js بـ title في app/about/page.js.
  • يتم وراثة جميع حقول openGraph من app/layout.js في app/about/page.js لأن app/about/page.js لا يحدد بيانات openGraph الوصفية.

سجل الإصدارات

الإصدارالتغييرات
v15.2.0تم تقديم دعم البث لـ generateMetadata.
v13.2.0تم إهمال viewport، themeColor، و colorScheme لصالح تكوين viewport.
v13.2.0تم تقديم metadata و generateMetadata.