تخطّى إلى المحتوى الرئيسي
sitemap.ts و robots.ts في Next.js 16: كيف نتحكم في زواحف Google وزواحف البحث بالذكاء الاصطناعي

sitemap.ts و robots.ts في Next.js 16: كيف نتحكم في زواحف Google وزواحف البحث بالذكاء الاصطناعي

November 3, 2026
هندسة الواجهات
7 دقيقة قراءة

أهم النقاط

ملفا app/robots.ts و app/sitemap.ts في Next.js App Router هما Route Handlers خاصة يخزّنها Next.js مؤقتًا افتراضيًا، لذلك تبقى خريطة الموقع المبنية من بيانات CMS قديمة حتى البناء التالي أو حتى إعادة التحقق منها صراحةً.

وفقًا لمعيار RFC 9309 يلتزم الزاحف بمجموعة user-agent الأكثر تحديدًا التي تطابقه فقط، لذلك فإن مجموعة مخصصة لـ OAI-SearchBot تحل محل مجموعة * بدل أن تكمّلها، ويجب أن تكرر كل مسار Disallow.

تشغّل شركات الذكاء الاصطناعي زواحف منفصلة للبحث وللتدريب: تستخدم OpenAI الزاحف OAI-SearchBot لبحث ChatGPT والزاحف GPTBot للتدريب، وتستخدم Anthropic الزاحفين Claude-SearchBot و ClaudeBot. حظر زاحف التدريب لا يحظر زاحف البحث.

تتجاهل Google الحقلين changefreq و priority في خرائط المواقع، وتستخدم lastmod فقط عندما تكون قيمته دقيقة باستمرار، لذلك فإن ضبط lastModified على وقت البناء لكل رابط يُهدر الحقل الوحيد المهم.

قاعدة Disallow في robots.txt توقف الزحف وليس الفهرسة. لإبقاء صفحة خارج نتائج البحث نرسل noindex ونترك الرابط متاحًا للزحف.

لماذا نولّد robots.txt و sitemap.xml من الكود؟

في Devya نولّد robots.txt و sitemap.xml من TypeScript في كل مشروع Next.js بدل نسخ ملفات ثابتة بين المستودعات. الملفات الثابتة تفشل بصمت: تُفهرس بيئة الاختبار (staging)، ويطابق زاحفٌ قاعدةً لم يكتبها أحد له، وتتعلم محركات البحث تجاهل تواريخ تتغير مع كل عملية بناء. توليد الملفين من ثوابت المسارات ودوال البيانات نفسها التي تستخدمها الصفحات يبقيهما صادقين، ويسمح لنا بالتعامل مع زواحف الذكاء الاصطناعي التي تحدد ما إذا كان ChatGPT أو Claude أو Perplexity يستطيع الاستشهاد بالصفحة.

ماذا يولّد robots.ts و sitemap.ts في Next.js 16؟

يعيد app/robots.ts كائنًا من نوع MetadataRoute.Robots يقدّمه Next.js على المسار /robots.txt، ويعيد app/sitemap.ts مصفوفة من نوع MetadataRoute.Sitemap يقدّمها Next.js على المسار /sitemap.xml. يجب أن يكون robots.ts في جذر مجلد app، بينما يمكن وضع sitemap.ts داخل مقطع مسار مثل app/blog/sitemap.ts الذي يقدّم /blog/sitemap.xml.

تصف وثائق Next.js الملفين بأنهما Route Handlers خاصة مخزّنة مؤقتًا افتراضيًا، إلا إذا استدعيا واجهة وقت الطلب مثل cookies() أو headers()، أو استخدما إعداد مسار ديناميكيًا. عمليًا يُحسب الناتج وقت البناء. عندما تكون المقالات داخل المستودع يعيد كل نشر بناء خريطة الموقع. وعندما تأتي المقالات من CMS أو API، يحفظ معالج النشر لدينا المقالة ثم يستدعي revalidatePath('/sitemap.xml') بجانب إعادة التحقق من صفحة المقالة، فتظهر المقالة الجديدة في خريطة الموقع دون انتظار إعادة البناء.

أي زواحف الذكاء الاصطناعي نسمح بها، وأيها يخص التدريب فقط؟

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

OpenAI: الزاحف OAI-SearchBot لبحث ChatGPT، والزاحف GPTBot للتدريب، و ChatGPT-User لعمليات الجلب التي يطلقها المستخدم.

Anthropic: الزاحف Claude-SearchBot للبحث، والزاحف ClaudeBot للتدريب، و Claude-User لعمليات الجلب التي يطلقها المستخدم.

Perplexity: الزاحف PerplexityBot للبحث، و Perplexity-User لعمليات الجلب التي يطلقها المستخدم.

Google: الزاحف Googlebot لبحث Google بما في ذلك AI Overviews، ورمز المنتج Google-Extended لاستخدام المحتوى في نماذج Gemini.

Apple: الزاحف Applebot للبحث، ورمز المنتج Applebot-Extended لتدريب النماذج. Common Crawl: الزاحف CCBot الذي تُستخدم مجموعة بياناته العامة على نطاق واسع في التدريب.

إن Google-Extended و Applebot-Extended رموز منتجات في robots.txt وليست زواحف منفصلة. تؤكد Google أن Google-Extended لا يؤثر على الظهور أو الترتيب في بحث Google، لذلك تتبع AI Overviews قواعد Googlebot.

القاعدة الافتراضية لدينا أن الموقع العام الموجود ليُقرأ يسمح بها جميعًا. أما المحتوى المرخّص أو المدفوع فنحظر عنه زواحف التدريب ونبقي زواحف البحث، لأن OpenAI تذكر أن المواقع التي تحظر OAI-SearchBot لا تظهر في إجابات بحث ChatGPT إلا كروابط تنقّل. وتوثّق Perplexity أن Perplexity-User يتجاهل robots.txt عمومًا لأن شخصًا طلب الصفحة، لذلك نعامل أدوات الجلب التي يطلقها المستخدم كمتصفحات. وكل ما يجب ألا يُجلب أبدًا يوضع خلف المصادقة، لأن robots.txt طلبٌ وليس تحكمًا في الوصول.

لماذا يتجاهل زاحفٌ مُسمّى قواعد * لدينا؟

يلتزم الزاحف بمجموعة user-agent واحدة فقط هي الأكثر تحديدًا من بين ما يطابقه، ولا تنطبق مجموعة * إلا عندما لا تطابقه أي مجموعة مُسمّاة. يحدد هذا السلوكَ معيار RFC 9309 الخاص ببروتوكول استبعاد الروبوتات، ولا تُدمج قواعد * مع قواعد المجموعة المُسمّاة أبدًا.

يبدو الفخ بريئًا: يضيف أحدهم User-agent: OAI-SearchBot مع Allow: / للتأكد من أن ChatGPT يرى الموقع، فيتجاهل هذا الزاحف بعدها سطري Disallow: /api/ و Disallow: /admin/ الموجودين في مجموعة *. في ملف robots.ts لدينا توجد المسارات الخاصة في ثابت واحد يُنشر داخل كل مجموعة غير محظورة بالكامل، ويوضح تعليق فوق كل مجموعة مُسمّاة أنها تحل محل *.

تعيد عمليات البناء غير الإنتاجية Disallow: / لكل وكلاء المستخدم. تضيف Vercel ترويسة X-Robots-Tag: noindex إلى عمليات النشر التجريبية (preview) افتراضيًا، لكن بيئة staging المستضافة ذاتيًا لا تحصل على هذه الحماية. الاعتماد على VERCEL_ENV وحده خطأ في الاستضافة الذاتية، لأن هذا المتغير غير موجود هناك فيحظر موقع الإنتاج كل الزواحف، لذلك يقبل فحصنا أيضًا متغيرنا الخاص DEPLOY_ENV. قاعدة Disallow تُبعد الزواحف الملتزمة فقط عن بيئة staging، أما الحماية الحقيقية فهي المصادقة، لأن الرابط المحظور قد يُفهرس رغم ذلك عبر روابط خارجية.

كيف نضبط lastModified و changeFrequency و priority؟

نضبط lastModified على تاريخ التغيير الفعلي للمحتوى، ونحذف changeFrequency و priority. توثّق Google أنها تتجاهل changefreq و priority، وأنها تستخدم lastmod فقط عندما تكون القيمة دقيقة باستمرار ويمكن التحقق منها. ونشرت Bing أيضًا إرشادات بأن قيم lastmod الدقيقة تساعد زاحفها. ختم كل رابط بـ new Date() في كل بناء يخبر الزواحف أن كل شيء تغيّر، فتتعلم تجاهل الحقل.

المقصود بالتغيير هو تغيّر النص أو العنوان أو البيانات المنظمة، لا رابط في التذييل يمس كل الصفحات، لذلك يخزّن نموذج المقالات لدينا updatedAt منفصلًا عن publishedAt ولا يحدّثه إلا عند التعديل.

في المواقع ثنائية اللغة يولّد الحقل alternates.languages في عنصر خريطة الموقع روابط hreflang، وتتوقع Google إدراج كل نسخة لغوية مع المجموعة الكاملة من البدائل، لذلك يُخرج sitemap.ts لدينا عنصرًا لكل لغة مع كائن alternates نفسه. لا يعمل hreflang إلا عندما يكون لكل لغة رابط مستقل قابل للزحف. الموقع الذي يبدّل اللغة عبر ملف تعريف ارتباط (cookie) على رابط واحد يُظهر للزواحف لغة واحدة فقط، ولا تستطيع أي خريطة موقع إصلاح ذلك.

كيف نقسّم خريطة موقع تتجاوز 50,000 رابط؟

يحدّ بروتوكول sitemaps.org ملف خريطة الموقع الواحد بـ 50,000 رابط أو 50 ميجابايت غير مضغوطة. يتعامل Next.js مع المواقع الأكبر عبر generateSitemaps التي تعيد قائمة كائنات تحمل id، ويقدّم Next.js كل جزء على مسار مثل /blog/sitemap/0.xml. منذ Next.js 16 أصبحت الخاصية id الممررة إلى دالة sitemap وعدًا (Promise) يُحل إلى نص، لذلك ننتظرها بـ await ونحوّلها إلى رقم قبل حساب إزاحة الصفحة.

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

كيف نتحقق من أن الزواحف ترى ما قصدناه؟

نختبر الكائنات المولّدة في CI، ثم نفحص الناتج المنشور وتقارير محركات البحث نفسها. ولأن robots() دالة عادية، يضبط اختبار Vitest البيئة عبر vi.stubEnv ويستدعي robots() ويتحقق من أن كل مجموعة غير محظورة بالكامل لا تزال تحظر /api/ و /admin/. ويتحقق اختبار ثانٍ من أن بيئة preview تعيد Disallow: / لكل وكلاء المستخدم.

بعد النشر نجلب /robots.txt و /sitemap.xml من نطاق الإنتاج ونقرؤهما كما يقرؤهما الزاحف.

يعرض Google Search Console آخر ملف robots.txt جلبته Google مع أخطاء تحليله، وعدد روابط خريطة الموقع التي اكتشفتها.

توفر Bing Webmaster Tools الفحوصات نفسها، وتدعم Bing بروتوكول IndexNow لإبلاغها بتغيّر الروابط عند النشر، بينما لا تستخدمه Google.

يمكن لقواعد الجدار الناري وشبكات CDN الخاصة بالروبوتات أن تحظر الزاحف قبل أن يقرأ robots.txt أصلًا، لذلك نفحص سجلات الجدار الناري بحثًا عن وكيل المستخدم الخاص بالزاحف عندما يبدو أنه يتجاهل قاعدة Allow.

الأسئلة الشائعة

س: هل يؤدي حظر GPTBot إلى إزالة الموقع من إجابات ChatGPT؟

ج: ليس وحده. يجمع GPTBot بيانات التدريب، بينما يجلب بحث ChatGPT الصفحات عبر OAI-SearchBot. حظر GPTBot مع السماح لـ OAI-SearchBot يلغي الاشتراك في التدريب ويبقي الصفحات مؤهلة للظهور كمصادر في إجابات بحث ChatGPT.

س: هل تُبقي قاعدة Disallow في robots.txt الصفحة خارج Google؟

ج: لا. توقف Disallow الزحف، لكن Google قد تفهرس رابطًا محظورًا تكتشفه عبر روابط أخرى دون محتواه. لإبقاء الصفحة خارج النتائج أرسل وسم robots meta بقيمة noindex أو ترويسة X-Robots-Tag، واترك الرابط قابلًا للزحف ليراها Googlebot.

س: لماذا لا تظهر مقالة جديدة في sitemap.xml في Next.js؟

ج: ملف sitemap.ts مخزّن مؤقتًا افتراضيًا، فتبقى البيانات المقروءة وقت البناء حتى البناء التالي أو إعادة التحقق. استدعِ revalidatePath('/sitemap.xml') عند النشر، أو أعد بناء الموقع.

س: هل نثق في وكيل المستخدم الخاص بالزاحف في سجلات الخادم؟

ج: لا. أي عميل يستطيع إرسال User-Agent: GPTBot. توثّق Google التحقق عبر DNS العكسي لـ Googlebot، وتنشر OpenAI نطاقات عناوين IP لزواحفها، لذلك تحقّق من المصدر قبل اعتبار الحركة زاحفًا حقيقيًا.