تحسين محركات البحث والبيانات الوصفية في Next.js
فهم تحسين محركات البحث في Next.js
تحسين محركات البحث (SEO) أمر بالغ الأهمية لجعل موقعك قابلاً للاكتشاف. توفر Next.js ميزات شاملة مدمجة لإدارة البيانات الوصفية وإنشاء خرائط الموقع والتحكم في فهرسة محرك البحث. يمكن أن يؤدي التنفيذ السليم لتحسين محركات البحث إلى تحسين رؤية موقعك وترتيبه في نتائج البحث بشكل كبير.
واجهة برمجة التطبيقات للبيانات الوصفية
تقدم Next.js 13+ واجهة برمجة التطبيقات للبيانات الوصفية لإدارة البيانات الوصفية للصفحة في مكونات الخادم:
// app/page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'الرئيسية - موقعي الرائع',
description: 'مرحباً بك في موقعي الرائع مع منتجات وخدمات رائعة',
keywords: ['منتجات', 'خدمات', 'تجارة إلكترونية'],
};
export default function HomePage() {
return <h1>مرحباً</h1>;
}
البيانات الوصفية الديناميكية مع generateMetadata
للصفحات الديناميكية، استخدم دالة generateMetadata لإنشاء بيانات وصفية بناءً على معلمات المسار أو البيانات:
// app/products/[id]/page.tsx
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
interface Product {
id: string;
name: string;
description: string;
price: number;
image: string;
category: string;
}
async function getProduct(id: string): Promise<Product | null> {
const res = await fetch(`https://api.example.com/products/${id}`);
if (!res.ok) return null;
return res.json();
}
export async function generateMetadata({
params,
}: {
params: { id: string };
}): Promise<Metadata> {
const product = await getProduct(params.id);
if (!product) {
return {
title: 'المنتج غير موجود',
};
}
return {
title: `${product.name} - اشتري الآن',
description: product.description,
keywords: [product.name, product.category, 'شراء عبر الإنترنت'],
openGraph: {
title: product.name,
description: product.description,
images: [
{
url: product.image,
width: 1200,
height: 630,
alt: product.name,
},
],
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: product.name,
description: product.description,
images: [product.image],
},
};
}
export default async function ProductPage({ params }: { params: { id: string } }) {
const product = await getProduct(params.id);
if (!product) {
notFound();
}
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<p>{product.price} دولار</p>
</div>
);
}
علامات Open Graph ووسائل التواصل الاجتماعي
قم بتكوين علامات Open Graph لمشاركة أفضل على وسائل التواصل الاجتماعي:
// app/blog/[slug]/page.tsx
import { Metadata } from 'next';
export async function generateMetadata({
params,
}: {
params: { slug: string };
}): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
authors: [{ name: post.author }],
openGraph: {
title: post.title,
description: post.excerpt,
url: `https://example.com/blog/${params.slug}`,
siteName: 'مدونتي',
images: [
{
url: post.coverImage,
width: 1200,
height: 630,
alt: post.title,
},
],
locale: 'ar_SA',
type: 'article',
publishedTime: post.publishedAt,
modifiedTime: post.updatedAt,
authors: [post.author],
tags: post.tags,
},
twitter: {
card: 'summary_large_image',
title: post.title,
description: post.excerpt,
creator: '@myhandle',
images: [post.coverImage],
},
};
}
عناوين URL الأساسية واللغات البديلة
قم بتكوين عناوين URL الأساسية والبدائل اللغوية لتحسين محركات البحث:
// app/[locale]/products/[id]/page.tsx
import { Metadata } from 'next';
export async function generateMetadata({
params,
}: {
params: { locale: string; id: string };
}): Promise<Metadata> {
const baseUrl = 'https://example.com';
const productPath = `/products/${params.id}`;
return {
title: 'اسم المنتج',
description: 'وصف المنتج',
alternates: {
canonical: `${baseUrl}/${params.locale}${productPath}`,
languages: {
'en-US': `${baseUrl}/en${productPath}`,
'ar-SA': `${baseUrl}/ar${productPath}`,
'fr-FR': `${baseUrl}/fr${productPath}`,
'x-default': `${baseUrl}/en${productPath}`,
},
},
};
}
علامات Robots الوصفية
التحكم في الزحف والفهرسة لمحرك البحث:
// app/admin/page.tsx - عدم فهرسة صفحات المسؤول
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'لوحة تحكم المسؤول',
robots: {
index: false,
follow: false,
nocache: true,
},
};
// app/products/page.tsx - السماح بالفهرسة
export const metadata: Metadata = {
title: 'المنتجات',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
};
إنشاء robots.txt
قم بإنشاء ملف robots.txt للتحكم في وصول الزاحف:
// app/robots.ts
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/admin', '/api', '/_next'],
},
{
userAgent: 'Googlebot',
allow: '/',
disallow: ['/admin'],
},
],
sitemap: 'https://example.com/sitemap.xml',
};
}
// هذا ينتج:
// User-agent: *
// Allow: /
// Disallow: /admin
// Disallow: /api
// Disallow: /_next
//
// User-agent: Googlebot
// Allow: /
// Disallow: /admin
//
// Sitemap: https://example.com/sitemap.xml
إنشاء Sitemap.xml
قم بإنشاء خريطة موقع ديناميكية لمحركات البحث:
// app/sitemap.ts
import { MetadataRoute } from 'next';
async function getProducts() {
const res = await fetch('https://api.example.com/products');
return res.json();
}
async function getBlogPosts() {
const res = await fetch('https://api.example.com/posts');
return res.json();
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://example.com';
// الصفحات الثابتة
const staticPages = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily' as const,
priority: 1,
},
{
url: `${baseUrl}/about`,
lastModified: new Date(),
changeFrequency: 'monthly' as const,
priority: 0.8,
},
{
url: `${baseUrl}/contact`,
lastModified: new Date(),
changeFrequency: 'yearly' as const,
priority: 0.5,
},
];
// صفحات المنتجات الديناميكية
const products = await getProducts();
const productPages = products.map((product: any) => ({
url: `${baseUrl}/products/${product.id}`,
lastModified: new Date(product.updatedAt),
changeFrequency: 'weekly' as const,
priority: 0.7,
}));
// منشورات المدونة الديناميكية
const posts = await getBlogPosts();
const blogPages = posts.map((post: any) => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: new Date(post.updatedAt),
changeFrequency: 'monthly' as const,
priority: 0.6,
}));
return [...staticPages, ...productPages, ...blogPages];
}
فهرس خريطة الموقع للمواقع الكبيرة
للمواقع التي تحتوي على العديد من الصفحات، قم بإنشاء فهرس خريطة الموقع:
// app/sitemap-index.ts
import { MetadataRoute } from 'next';
export default function sitemapIndex(): MetadataRoute.Sitemap {
return [
{
url: 'https://example.com/sitemap-products.xml',
lastModified: new Date(),
},
{
url: 'https://example.com/sitemap-blog.xml',
lastModified: new Date(),
},
{
url: 'https://example.com/sitemap-pages.xml',
lastModified: new Date(),
},
];
}
// app/sitemap-products.xml.ts
export default async function productsSitemap(): Promise<MetadataRoute.Sitemap> {
const products = await getProducts();
return products.map((product: any) => ({
url: `https://example.com/products/${product.id}`,
lastModified: new Date(product.updatedAt),
}));
}
البيانات المنظمة JSON-LD
أضف بيانات منظمة للحصول على نتائج بحث غنية:
// components/StructuredData.tsx
export default function StructuredData({ data }: { data: any }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
);
}
// app/products/[id]/page.tsx
import StructuredData from '@/components/StructuredData';
export default async function ProductPage({ params }: { params: { id: string } }) {
const product = await getProduct(params.id);
const structuredData = {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.name,
description: product.description,
image: product.image,
offers: {
'@type': 'Offer',
price: product.price,
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
url: `https://example.com/products/${params.id}`,
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: product.rating,
reviewCount: product.reviewCount,
},
};
return (
<>
<StructuredData data={structuredData} />
<div>
<h1>{product.name}</h1>
{/* ... */}
</div>
</>
);
}
البيانات المنظمة للمقالات
أضف بيانات منظمة لمنشورات المدونة والمقالات:
// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
const structuredData = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
image: post.coverImage,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
'@type': 'Person',
name: post.author,
url: `https://example.com/authors/${post.authorSlug}`,
},
publisher: {
'@type': 'Organization',
name: 'مدونتي',
logo: {
'@type': 'ImageObject',
url: 'https://example.com/logo.png',
},
},
description: post.excerpt,
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `https://example.com/blog/${params.slug}`,
},
};
return (
<>
<StructuredData data={structuredData} />
{/* محتوى المقالة */}
</>
);
}
البيانات المنظمة لمسار التنقل
عزز التنقل باستخدام بيانات منظمة لمسار التنقل:
// components/Breadcrumbs.tsx
interface BreadcrumbItem {
label: string;
href: string;
}
export default function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
const structuredData = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.label,
item: `https://example.com${item.href}`,
})),
};
return (
<>
<StructuredData data={structuredData} />
<nav aria-label="مسار التنقل">
<ol>
{items.map((item, index) => (
<li key={index}>
<Link href={item.href}>{item.label}</Link>
</li>
))}
</ol>
</nav>
</>
);
}
// الاستخدام
<Breadcrumbs
items={[
{ label: 'الرئيسية', href: '/' },
{ label: 'المنتجات', href: '/products' },
{ label: 'حاسوب محمول', href: '/products/laptop-123' },
]}
/>
علامات التحقق
أضف علامات التحقق لمحركات البحث ومنصات التواصل الاجتماعي:
// app/layout.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
verification: {
google: 'your-google-verification-code',
yandex: 'your-yandex-verification-code',
bing: 'your-bing-verification-code',
},
other: {
'facebook-domain-verification': 'your-facebook-verification-code',
},
};
قالب البيانات الوصفية
قم بإنشاء بيانات وصفية متسقة عبر الصفحات باستخدام القوالب:
// app/layout.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: {
template: '%s | موقعي الرائع',
default: 'موقعي الرائع - أفضل المنتجات عبر الإنترنت',
},
description: 'الوصف الافتراضي للموقع',
};
// app/products/page.tsx
export const metadata: Metadata = {
title: 'المنتجات', // يصبح "المنتجات | موقعي الرائع"
};
// app/about/page.tsx
export const metadata: Metadata = {
title: 'من نحن', // يصبح "من نحن | موقعي الرائع"
};
تحسين الأداء لتحسين محركات البحث
يتأثر تصنيف تحسين محركات البحث بالأداء. قم بتحسين Core Web Vitals:
// تحسين الصور
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="صورة البطل"
width={1200}
height={600}
priority // تحميل الصور فوق الجزء المرئي أولاً
placeholder="blur"
/>
// تحسين الخطوط
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // منع النص غير المرئي أثناء تحميل الخط
});
// تحسين النصوص البرمجية
import Script from 'next/script';
<Script
src="https://analytics.example.com/script.js"
strategy="lazyOnload" // التحميل بعد أن تصبح الصفحة تفاعلية
/>
وراثة ودمج البيانات الوصفية
ترث المسارات الفرعية البيانات الوصفية الأصلية ويمكنها تجاوزها:
// app/layout.tsx (الجذر)
export const metadata = {
title: {
template: '%s | الموقع',
default: 'الموقع',
},
openGraph: {
siteName: 'موقعي',
},
};
// app/blog/layout.tsx (تخطيط المدونة)
export const metadata = {
openGraph: {
type: 'article', // يتجاوز لجميع صفحات المدونة
},
};
// app/blog/[slug]/page.tsx (منشور فردي)
export async function generateMetadata({ params }) {
return {
title: 'منشور مدونتي', // يرث القالب من الجذر
// يرث siteName وtype من الآباء
};
}
تمرين تطبيقي
المهمة: بناء مدونة محسنة بالكامل لتحسين محركات البحث:
- إنشاء بيانات وصفية ديناميكية لمنشورات المدونة باستخدام generateMetadata
- إضافة علامات Open Graph وTwitter Card مع صور مناسبة
- تنفيذ بيانات منظمة للمقالة مع معلومات المؤلف والناشر
- إنشاء sitemap.xml مع جميع منشورات المدونة والفئات
- إنشاء robots.txt يسمح لجميع الزواحف
- إضافة التنقل بمسار التنقل مع بيانات منظمة
- تنفيذ علامات hreflang للنسخ الإنجليزية والعربية
- إضافة علامات التحقق لـ Google Search Console
إضافي: استخدم Rich Results Test من Google للتحقق من صحة تنفيذ البيانات المنظمة.
الملخص
النقاط الرئيسية حول تحسين محركات البحث في Next.js:
- استخدم واجهة برمجة التطبيقات للبيانات الوصفية للبيانات الوصفية الثابتة وgenerateMetadata للبيانات الوصفية الديناميكية
- قم دائماً بتضمين علامات Open Graph وTwitter Card للمشاركة على وسائل التواصل الاجتماعي
- تنفيذ بيانات منظمة JSON-LD للحصول على نتائج بحث غنية
- إنشاء خرائط مواقع ديناميكياً باستخدام مسار sitemap.ts
- التحكم في وصول الزاحف باستخدام robots.txt وعلامات robots الوصفية
- إضافة عناوين URL أساسية وعلامات hreflang للمواقع متعددة اللغات
- تحسين الصور والخطوط والنصوص البرمجية لتحسين Core Web Vitals
- استخدام علامات التحقق للتكامل مع أدوات محرك البحث