Next.js: تحسين محركات البحث (SEO) وواجهة Metadata

آخر تحديث: 2026-08-26

تحسين محركات البحث (SEO) هو محرك زيارات مجاني للمواقع الإلكترونية — البيانات الوصفية الصحيحة يمكنها أن تجعل Google يفهرس موقعك أسرع بثلاث مرات.

1. ما ستتعلمه



2. قصة حقيقية لمدير عمليات المحتوى

(1) نقطة الألم: بعد ثلاثة أشهر من الإطلاق، Google فهرس 5 صفحات فقط

بوب مسؤول عن عمليات المحتوى في TaskFlow. بعد ثلاثة أشهر من إطلاق المدونة، كان قد كتب 50 مقالاً:

"Google Search Console يظهر أن 5 صفحات فقط تم فهرستها. عند التدقيق، اكتشفت أن جميع الصفحات تحمل <title> بعنوان 'TaskFlow'، ولا يوجد وصف meta، ولا صورة Open Graph — لذلك عند المشاركة على وسائل التواصل الاجتماعي، تظهر كروابط عادية."

المشكلة التأثير القياس الكمي
عنوان مكرر محركات البحث لا تستطيع التمييز بين الصفحات 5 فقط من أصل 50 مفهرسة
لا توجد صورة OG لا توجد صورة معاينة للمشاركة الاجتماعية نسبة النقر على المشاركة: 0.3%
لا يوجد JSON-LD لا يوجد ملخص وسائط غنية لا توجد معلومات إضافية في نتائج البحث
لا يوجد Sitemap Google لا يستطيع الزحف إلى الصفحات العميقة تأخير الفهرسة 30 يوماً

(2) حل Next.js Metadata API

استخدم generateMetadata() لتوليد وسوم SEO فريدة وبيانات JSON-LD منظمة لكل صفحة.

TS
// app/blog/[slug]/page.tsx — SEO للمقالات الإخبارية
import type { Metadata } from 'next'

export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
  const { slug } = await params
  const post = await getPost(slug)

  return {
    title: `${post.title} - TaskFlow Blog`,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [{ url: post.ogImage, width: 1200, height: 630 }]
    }
  }
}

(3) النتائج

المؤشر قبل التحسين بعد التحسين التحسن
معدل فهرسة Google 10% 98% 9.8x
نسبة النقر على المشاركة الاجتماعية 0.3% 2.8% 9.3x
نتائج البحث الغنية بالوسائط ❌ لا يوجد ✅ مسار التنقل + بطاقات المقالات
سرعة اكتشاف الصفحات 30 يوماً < 24 ساعة 30x


3. البيانات الوصفية الثابتة والديناميكية

(1) التصدير الثابت

TS
// app/about/page.tsx — بيانات وصفية للصفحة الثابتة
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'حول TaskFlow - منصة التعاون الجماعي',
  description: 'TaskFlow تساعد أكثر من 10,000 فريق على العمل بكفاءة عالية، وتوفر إدارة المشاريع والتعاون الفوري والتحليلات الذكية.',
  keywords: ['تعاون جماعي', 'إدارة مشاريع', 'TaskFlow', 'SaaS'],
  authors: [{ name: 'فريق TaskFlow', url: 'https://taskflow.io' }]
}

(2) التوليد الديناميكي

TS
// app/products/[id]/page.tsx — بيانات وصفية للمنتج
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://api.taskflow.io/products/${id}`).then(r => r.json())

  return {
    title: `${product.name} - منتجات TaskFlow`,
    description: product.description,
    openGraph: {
      title: product.name,
      description: product.description,
      url: `https://taskflow.io/products/${id}`,
      siteName: 'TaskFlow',
      images: [
        {
          url: product.ogImage,
          width: 1200,
          height: 630,
          alt: product.name
        }
      ],
      locale: 'zh_CN',
      type: 'website'
    },
    twitter: {
      card: 'summary_large_image',
      title: product.name,
      description: product.description,
      images: [product.ogImage]
    },
    alternates: {
      canonical: `https://taskflow.io/products/${id}`,
      languages: {
        'en': `https://taskflow.io/en/products/${id}`,
        'ja': `https://taskflow.io/ja/products/${id}`,
        'ar': `https://taskflow.io/ar/products/${id}`
      }
    }
  }
}

(3) جدول مرجعي سريع لحقول Metadata

الحقل الغرض مثال
title عنوان الصفحة / <title> 'تفاصيل المنتج - TaskFlow'
description ملخص محرك البحث 'أداة إدارة المشاريع TaskFlow...'
openGraph مشاركة Facebook / LinkedIn { title, description, images }
twitter بطاقة X (Twitter) { card: 'summary_large_image' }
alternates.canonical الرابط المرجعي لمنع المحتوى المكرر https://taskflow.io/page
alternates.languages hreflang متعدد اللغات { 'en': '...' }
robots تعليمات الزواحف { index: true, follow: true }

▶ مثال: SEO كامل لمقالة مدونة

المخرجات:

TEXT 📖 للعرض فقط
تنفذ الدالة غير المتزامنة وتعيد البيانات التي تم جلبها.
TS
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next'

interface Post {
  title: string
  excerpt: string
  ogImage: string
  publishedAt: string
  author: string
  tags: string[]
}

async function getPost(slug: string): Promise<Post> {
  const res = await fetch(`https://api.taskflow.io/blog/${slug}`, { next: { revalidate: 3600 } })
  return res.json()
}

export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
  const { slug } = await params
  const post = await getPost(slug)

  return {
    title: `${post.title} | TaskFlow Blog`,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt,
      authors: [post.author],
      images: [{ url: post.ogImage, width: 1200, height: 630 }]
    },
    twitter: {
      card: 'summary_large_image',
      title: post.title,
      description: post.excerpt,
      images: [post.ogImage]
    },
    keywords: [...post.tags, 'TaskFlow', 'Project Management'],
    alternates: { canonical: `https://taskflow.io/blog/${slug}` },
    robots: { index: true, follow: true }
  }
}

المخرجات:

TEXT 📖 للعرض فقط
يُعرّف أنواع TypeScript: Post.

▶ مثال: استخدام وسم robots meta للتحكم في زواحف الويب

المخرجات:

TEXT 📖 للعرض فقط
يُعرّف أنواع TypeScript: Post.
TS
// app/private/dashboard/page.tsx — منع محركات البحث من الفهرسة
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'لوحة التحكم - TaskFlow',
  robots: {
    index: false,        // لا تقم بالفهرسة
    follow: false,       // لا تتبع الروابط
    noarchive: true,     // لا تقم بالتخزين المؤقت
    nosnippet: true,     // لا تعرض الملخص
    nocache: true        // لا تقم بالتخزين المؤقت
  }
}

export default function DashboardPage() {
  return <h1>لوحة تحكم خاصة</h1>
}
💻 المخرجات (HTML head):

HTML
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet" />

المخرجات:

TEXT 📖 للعرض فقط
يعرض المتصفح: عنوان "لوحة تحكم خاصة". محركات البحث لن تفهرس هذه الصفحة — وسم <meta name="robots" content="noindex, nofollow, noarchive, nosnippet"> يمنع الزحف.


4. بيانات JSON-LD المنظمة

(1) ثلاثة مخططات شائعة

100%
graph TB
    A[بيانات JSON-LD المنظمة] --> B[BreadcrumbList<br/>مسار التنقل]
    A --> C[Article<br/>تفاصيل المقالة]
    A --> D[FAQPage<br/>الأسئلة الشائعة]

    B --> E[عرض مسار نتائج البحث]
    C --> F[لوحة المعرفة + صورة الغلاف]
    D --> G[عرض الأسئلة والأجوبة مباشرة في نتائج البحث]

    style A fill:#cce5ff
    style B fill:#d4edda
    style C fill:#d4edda
    style D fill:#d4edda
المخطط حالة الاستخدام العرض في نتائج البحث
BreadcrumbList جميع الصفحات عرض مسار التنقل (الرئيسية > المنتجات > التفاصيل)
Article مقالة المدونة بطاقة المقالة (العنوان + الملخص + صورة الغلاف + تاريخ النشر)
FAQPage مركز المساعدة / الأسئلة الشائعة عرض قائمة الأسئلة والأجوبة (قابلة للطي)
Product صفحة المنتج السعر + المخزون + التقييم بالنجوم

(2) دالة حقن JSON-LD

TS
// lib/jsonld.ts — أدوات توليد JSON-LD
export function breadcrumbJsonld(items: { name: string; url: string }[]) {
  return {
    '@context': 'https://schema.org',
    '@type': 'BreadcrumbList',
    itemListElement: items.map((item, index) => ({
      '@type': 'ListItem',
      position: index + 1,
      name: item.name,
      item: item.url
    }))
  }
}

export function articleJsonld(post: {
  title: string
  excerpt: string
  url: string
  ogImage: string
  publishedAt: string
  author: string
}) {
  return {
    '@context': 'https://schema.org',
    '@type': 'Article',
    headline: post.title,
    description: post.excerpt,
    image: post.ogImage,
    datePublished: post.publishedAt,
    author: { '@type': 'Person', name: post.author },
    publisher: { '@type': 'Organization', name: 'TaskFlow', logo: 'https://taskflow.io/logo.png' },
    mainEntityOfPage: { '@type': 'WebPage', '@id': post.url }
  }
}

▶ مثال: صفحة مقالة JSON-LD + مسار التنقل

المخرجات:

TEXT 📖 للعرض فقط
تنفذ وحدة TypeScript بنجاح.
TSX
// app/blog/[slug]/page.tsx — SEO كامل + JSON-LD
import { breadcrumbJsonld, articleJsonld } from '@/lib/jsonld'

export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  const post = await getPost(slug)
  const url = `https://taskflow.io/blog/${slug}`

  const breadcrumb = breadcrumbJsonld([
    { name: 'الرئيسية', url: 'https://taskflow.io' },
    { name: 'المدونة', url: 'https://taskflow.io/blog' },
    { name: post.title, url }
  ])

  const article = articleJsonld({
    title: post.title,
    excerpt: post.excerpt,
    url,
    ogImage: post.ogImage,
    publishedAt: post.publishedAt,
    author: post.author
  })

  return (
    <>
      {/* حقن JSON-LD */}
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }}
      />
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(article) }}
      />

      <article>
        <h1>{post.title}</h1>
        <p>{post.excerpt}</p>
        <div>{post.content}</div>
      </article>
    </>
  )
}

المخرجات:

TEXT 📖 للعرض فقط
يعرض واجهة مكون ▶ مثال: صفحة مقالة JSON-LD + مسار التنقل كما هو موضح في القسم.
💡 نصيحة: Google Search Console يوفر أداة "اختبار النتائج الغنية" التي يمكنها التحقق مما إذا كان JSON-LD قد تم تحليله بشكل صحيح.



5. Sitemap و robots.txt

(1) توليد Sitemap ديناميكي

TS
// app/sitemap.ts — Sitemap ديناميكي (يشمل جميع الصفحات تلقائياً)
import type { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = 'https://taskflow.io'

  // الصفحات الثابتة
  const staticPages = [
    { url: baseUrl, lastModified: new Date(), changeFrequency: 'monthly' as const, priority: 1.0 },
    { url: `${baseUrl}/about`, lastModified: new Date(), changeFrequency: 'monthly' as const, priority: 0.8 },
    { url: `${baseUrl}/blog`, lastModified: new Date(), changeFrequency: 'weekly' as const, priority: 0.9 },
    { url: `${baseUrl}/pricing`, lastModified: new Date(), changeFrequency: 'monthly' as const, priority: 0.8 },
    { url: `${baseUrl}/contact`, lastModified: new Date(), changeFrequency: 'yearly' as const, priority: 0.5 }
  ]

  // مقالات المدونة الديناميكية (من API)
  const posts = await fetch('https://api.taskflow.io/blog/posts').then(r => r.json())

  const blogPages = posts.map((post: { slug: string; updatedAt: string }) => ({
    url: `${baseUrl}/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt),
    changeFrequency: 'weekly' as const,
    priority: 0.7
  }))

  // الصفحات متعددة اللغات
  const locales = ['en', 'ja', 'ar']
  const localizedPages = locales.flatMap((locale) =>
    staticPages.map((page) => ({
      url: `${baseUrl}/${locale}${page.url.replace(baseUrl, '')}`,
      lastModified: page.lastModified,
      changeFrequency: page.changeFrequency,
      priority: page.priority * 0.9,
      alternates: {
        languages: Object.fromEntries(
          locales.map((l) => [l, `${baseUrl}/${l}${page.url.replace(baseUrl, '')}`])
        )
      }
    }))
  )

  return [...staticPages, ...blogPages, ...localizedPages]
}

(2) robots.txt

TS
// app/robots.ts
import type { MetadataRoute } from 'next'

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      {
        userAgent: '*',
        allow: '/',
        disallow: ['/api/', '/admin/', '/_next/', '/dashboard']
      },
      {
        userAgent: 'GPTBot',
        disallow: '/'
      }
    ],
    sitemap: 'https://taskflow.io/sitemap.xml'
  }
}

▶ مثال: التحقق من Sitemap متعدد اللغات

TEXT 📖 للعرض فقط
# مقتطف من sitemap.xml المُنشأ
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://taskflow.io/about</loc>
    <lastmod>2026-07-06</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
    <xhtml:link rel="alternate" hreflang="en" href="https://taskflow.io/en/about"/>
    <xhtml:link rel="alternate" hreflang="ja" href="https://taskflow.io/ja/about"/>
    <xhtml:link rel="alternate" hreflang="ar" href="https://taskflow.io/ar/about"/>
  </url>
</urlset>


6. توليد صور OG ديناميكية

(1) بنية @vercel/og

100%
graph LR
    A[مشاركة الرابط على وسائل التواصل] --> B[زاحف الويب يطلب صورة OG]
    B --> C[@vercel/og دالة Edge]
    C --> D[Satori + React]
    D --> E[تحويل JSX إلى PNG]
    E --> F[صورة OG بحجم 1200×630]
    F --> G[Facebook / X / LinkedIn تعرض]

    style C fill:#cce5ff
    style D fill:#d4edda
    style E fill:#fff3cd
المكتبة الوظيفة الوصف
@vercel/og توليد صورة OG عبر دالة Edge صفر حمل على الخادم
Satori تحويل JSX → SVG أقل من 1 مللي ثانية
resvg-wasm عرض SVG → PNG ~5 مللي ثانية

(2) التثبيت والأمثلة الأساسية

BASH
npm install @vercel/og
TSX
// app/og/route.tsx — API توليد صورة OG
import { ImageResponse } from '@vercel/og'

export const runtime = 'edge'

export async function GET() {
  return new ImageResponse(
    (
      <div style={{
        width: '100%',
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        background: 'linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%)',
        color: 'white',
        fontSize: 60,
        fontWeight: 700,
        padding: 40
      }}>
        <h1>TaskFlow</h1>
        <p style={{ fontSize: 32, opacity: 0.9 }}>منصة التعاون الجماعي</p>
      </div>
    ),
    { width: 1200, height: 630 }
  )
}

▶ مثال: صورة OG ديناميكية للمقالة

المخرجات:

TEXT 📖 للعرض فقط
يعرض واجهة مكون GET.
TSX
// app/blog/[slug]/og/route.tsx — صورة OG للمقالات المميزة
import { ImageResponse } from '@vercel/og'

export const runtime = 'edge'

export async function GET(req: Request, { params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params

  // جلب معلومات المقالة
  const post = await fetch(`https://api.taskflow.io/blog/${slug}`).then(r => r.json())

  return new ImageResponse(
    (
      <div style={{
        width: 1200,
        height: 630,
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        padding: 60,
        background: 'linear-gradient(135deg, #1e1b4b 0%, #4f46e5 100%)',
        color: 'white'
      }}>
        {/* الوسوم */}
        <div style={{ display: 'flex', gap: 8 }}>
          {post.tags?.slice(0, 3).map((tag: string) => (
            <span key={tag} style={{
              padding: '4px 12px',
              borderRadius: 20,
              background: 'rgba(255,255,255,0.2)',
              fontSize: 18
            }}>{tag}</span>
          ))}
        </div>

        {/* العنوان */}
        <h1 style={{ fontSize: 52, margin: '20px 0', lineHeight: 1.2 }}>
          {post.title}
        </h1>

        {/* المؤلف + التاريخ */}
        <div style={{ display: 'flex', gap: 16, fontSize: 22, opacity: 0.8 }}>
          <span>{post.author}</span>
          <span>{new Date(post.publishedAt).toLocaleDateString('zh-CN')}</span>
        </div>

        {/* الشعار */}
        <div style={{ position: 'absolute', bottom: 40, right: 60, fontSize: 28, fontWeight: 'bold' }}>
          TaskFlow Blog
        </div>
      </div>
    ),
    { width: 1200, height: 630 }
  )
}

المخرجات:

TEXT 📖 للعرض فقط
يجلب البيانات من جانب الخادم ويعرض قائمة من العناصر من post.
المحتوى المرئي: ))} | TaskFlow Blog
💡 نصيحة: معالج مسار صورة OG موجود في /blog/[slug]/og/route.tsx، والرابط النهائي هو https://taskflow.io/blog/nextjs-seo-guide/og. ببساطة قم بالإشارة إلى هذا العنوان في generateMetadata.



7. مثال كامل: تنفيذ شامل لـ SEO متعدد اللغات + صور OG

TSX
// app/layout.tsx — التخطيط الجذري (الافتراضي) SEO + متعدد اللغات
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: { template: '%s | TaskFlow', default: 'TaskFlow - منصة التعاون الجماعي' },
  description: 'TaskFlow تساعد أكثر من 10,000 فريق حول العالم على العمل بكفاءة عالية. توفر إدارة المشاريع والتعاون الفوري والتحليل الذكي بالذكاء الاصطناعي.',
  openGraph: {
    siteName: 'TaskFlow',
    type: 'website',
    locale: 'zh_CN',
    images: [{ url: 'https://taskflow.io/og-default.png', width: 1200, height: 630 }]
  },
  twitter: { card: 'summary_large_image', site: '@taskflow' },
  robots: { index: true, follow: true },
  alternates: {
    canonical: 'https://taskflow.io',
    languages: {
      'en': 'https://taskflow.io/en',
      'ja': 'https://taskflow.io/ja',
      'ar': 'https://taskflow.io/ar'
    }
  }
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh">
      <body>{children}</body>
    </html>
  )
}
TS
// app/sitemap.ts — Sitemap كامل
import type { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const baseUrl = 'https://taskflow.io'
  const locales = ['zh', 'en', 'ja', 'ar'] as const
  
  const pages = ['', '/about', '/blog', '/pricing', '/contact']
  
  return pages.flatMap((page) =>
    locales.map((locale) => ({
      url: `${baseUrl}/${locale}${page}`,
      lastModified: new Date(),
      changeFrequency: 'monthly' as const,
      priority: page === '' ? 1.0 : 0.8,
      alternates: {
        languages: Object.fromEntries(locales.map((l) => [l, `${baseUrl}/${l}${page}`]))
      }
    }))
  )
}
TS
// app/robots.ts
import type { MetadataRoute } from 'next'

export default function robots(): MetadataRoute.Robots {
  return {
    rules: { userAgent: '*', allow: '/', disallow: ['/api/', '/admin/', '/dashboard'] },
    sitemap: 'https://taskflow.io/sitemap.xml'
  }
}
TSX
// app/blog/[slug]/page.tsx — صفحة المقالة تجمع كل SEO
import type { Metadata } from 'next'

type Props = { params: Promise<{ slug: string }> }

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params
  const post = await fetch(`https://api.taskflow.io/blog/${slug}`).then(r => r.json())

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt,
      authors: [post.author],
      images: [{ url: `https://taskflow.io/blog/${slug}/og`, width: 1200, height: 630 }]
    },
    twitter: {
      card: 'summary_large_image',
      title: post.title,
      description: post.excerpt,
      images: [`https://taskflow.io/blog/${slug}/og`]
    },
    alternates: {
      canonical: `https://taskflow.io/blog/${slug}`,
      languages: {
        en: `https://taskflow.io/en/blog/${slug}`,
        ja: `https://taskflow.io/ja/blog/${slug}`,
        ar: `https://taskflow.io/ar/blog/${slug}`
      }
    }
  }
}

export default async function BlogPostPage({ params }: Props) {
  const { slug } = await params

  return (
    <article>
      {/* بيانات JSON-LD المنظمة */}
      <script type="application/ld+json" dangerouslySetInnerHTML={{
        __html: JSON.stringify({
          '@context': 'https://schema.org',
          '@type': 'BreadcrumbList',
          itemListElement: [
            { '@type': 'ListItem', position: 1, name: 'الرئيسية', item: 'https://taskflow.io' },
            { '@type': 'ListItem', position: 2, name: 'المدونة', item: 'https://taskflow.io/blog' },
            { '@type': 'ListItem', position: 3, name: slug }
          ]
        })
      }} />

      <h1>عنوان المقالة</h1>
      <div>محتوى المقالة...</div>
    </article>
  )
}

❓ أسئلة شائعة

س ما الفرق بين التصدير من generateMetadata() و metadata؟
ج metadata هو تصدير ثابت يُستخدم للتوجيه الثابت (مثل /about). أما generateMetadata() فهي دالة غير متزامنة تولد البيانات الوصفية ديناميكياً بناءً على params / searchParams وتُستخدم للتوجيه الديناميكي (مثل /blog/[slug]). لا يمكن استخدام الاثنين معاً في وقت واحد.
س ما العلاقة بين JSON-LD ووسوم meta؟
ج وسوم meta (<title> / <meta name="description">) هي وسوم SEO أساسية. أما JSON-LD (<script type="application/ld+json">) فهي بيانات منظمة تمكن Google من عرض المقتطفات الغنية (مسارات التنقل، التقييمات بالنجوم، الأسئلة الشائعة القابلة للطي). الاثنان متكاملان ويجب تنفيذهما معاً.
س هل توليد صور OG الديناميكية يزيد من حمل الخادم؟
ج @vercel/og يعمل على Edge Runtime (الحوسبة الطرفية)، وتستغرق كل صورة حوالي 5 مللي ثانية فقط للتوليد، مما يؤدي إلى حمل شبه معدوم. في بيئة الإنتاج، نوصي بتمكين التخزين المؤقت عبر CDN (Cache-Control: public, max-age=31536000, immutable).
س أين يجب إعداد وسم hreflang؟
ج قم بإعداده في generateMetadata() عند alternates.languages. Next.js يقوم تلقائياً بحقن <link rel="alternate" hreflang="en" href="..."> في <head> الصفحة. تحتاج أيضاً إلى تضمين وسم xhtml:link المقابل في Sitemap.
س هل حقلا changeFrequency و priority في Sitemap يؤثران على ترتيب Google؟
ج Google صرّح رسمياً بأنه يتجاهل هذين الحقلين. لكنهما لا يزالان ذا قيمة مرجعية لمحركات البحث الأخرى مثل Bing و Yandex. نوصي بأن يتضمن Sitemap جميع الصفحات وأن يكون حقل lastModified دقيقاً — فهذا مهم للزواحف لتحديد ما إذا كانت ستعيد الزحف إلى الصفحات.

📖 ملخص


📝 تمارين

  1. سؤال أساسي (⭐): قم بإعداد تصدير metadata في المسار الثابت /about، متضمناً العنوان والوصف وOpen Graph وبطاقة Twitter.

  2. تمرين متقدم (⭐⭐): قم بتنفيذ SEO كامل لصفحة تفاصيل خبر: generateMetadata() تولد العنوان والوصف ووسوم OG وبطاقة Twitter ديناميكياً، وحقن بيانات Article JSON-LD المنظمة، وإدراج جميع روابط المقالات في Sitemap.

  3. تحدٍ (⭐⭐⭐): قم ببناء نظام كامل لتوليد صور OG: @vercel/og يولّد صورة مشاركة بحجم 1200×630 لكل مقالة مدونة، متضمنة العنوان والمؤلف والوسوم؛ وقم بالإشارة إلى رابط الصورة في generateMetadata()؛ وأخيراً، استخدم أداة Google Rich Results Test للتحقق من صحة JSON-LD ووسوم OG.

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%