الطريقة الأكثر موثوقية لإدراج JSON-LD في App Router هي إخراج `<script type="application/ld+json">` مباشرةً داخل Server Component. عندها تظهر البيانات المنظَّمة في HTML الأولي الذي يعيده الخادم، ويستطيع زاحف الذكاء الاصطناعي قراءتها من دون تشغيل JavaScript. أما JSON-LD التي تُضاف لاحقًا عبر useEffect أو Google Tag Manager، فهي شبه غائبة عن محركات الإجابة؛ فمعظم الزواحف تنهي عملها وتغادر قبل اكتمال hydration للصفحة.
لماذا يجب إخراجها من جانب الخادم؟
الفارق الأساسي هو التوقيت. يكتب Server Component بيانات JSON-LD داخل سلسلة HTML لحظة وصول الطلب، ولذلك يحتوي أول ملف تلتقطه زواحف مثل GPTBot وClaudeBot وPerplexityBot وGoogle-Extended على المخطط كاملًا. أما الإدراج من جانب العميل، فيتطلب انتظار المتصفح حتى ينزّل الحزمة البرمجية وينفذها، وهي خطوة لا تجريها معظم زواحف الذكاء الاصطناعي أصلًا. وهنا يقع التباس شائع: تختبر أداة Google's Rich Results Test كود JavaScript بعد تصييره، فتبدو البيانات المدرجة من جانب العميل سليمة وتظن أنها اجتازت الاختبار. لكن محرك الإجابة يحصل فعليًا على HTML الأصلي قبل التصيير، فلا يجد فيه أي مخطط. وفي عمليات التدقيق التقني التي نجريها للعملاء، تُعد هذه من أكثر المشكلات شيوعًا وأسهلها مرورًا من دون ملاحظة، رغم أثرها السلبي.
أبسط تنفيذ عملي: صفحة واحدة في page.tsx
التنفيذ نفسه قصير جدًا. لا تحتاج إلى حزم إضافية أو مسارات API؛ يكفي إنجازه داخل Server Component المسؤول عن تصيير المقالة. ويرتكز على ثلاث مهام أساسية: جلب البيانات، وتجميع الكائنات، وإخراج السكربت.
- في `app/blog/[slug]/page.tsx`، وهو Server Component افتراضيًا، استخدم `await` أولًا لجلب بيانات المقالة.
- أنشئ كائن JavaScript خالصًا باسم `jsonLd`، وضع في بدايته `"@context": "https://schema.org"` و`"@type": "Article"`، ثم املأ بقية الحقول، مثل headline وdatePublished وauthor وimage، ديناميكيًا من بيانات المقالة.
- ضع في بداية JSX المُعاد: `<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c") }} />`.
- لا تستورد أي مكتبات خاصة بالعميل، ولا تضف "use client" في أعلى الملف؛ فبمجرد إضافتها يتحول الملف إلى Client Component وتضيع فائدة التنفيذ السابق بالكامل.
ربط عدة كيانات باستخدام @graph
تحتاج الصفحة الواحدة عادةً إلى أكثر من مخطط: فالعلامة التجارية تمثل Organization، والمقالة تمثل Article، ومسار التنقل يمثل BreadcrumbList، وقسم الأسئلة والأجوبة يمثل FAQPage. وبدلًا من إخراج أربعة وسوم script مستقلة، يمكنك اتباع نهج أنظف عبر جمعها في مصفوفة `@graph` داخل كائن JSON-LD واحد، ثم استخدام `@id` لربطها ببعضها. على سبيل المثال، اجعل `publisher` في Article يشير إلى `@id` الخاص بـOrganization، واجعل العنصر الأخير في BreadcrumbList يشير إلى `@id` الخاص بالصفحة الحالية. وبهذا يستطيع محرك الإجابة استيعاب خريطة علاقات الكيانات كاملةً في عملية تحليل واحدة، مع تقليل احتمال التقاط عقد متكررة أو متناقضة.
- Organization وWebSite: ضعهما في `app/layout.tsx` لمشاركتهما مرة واحدة على مستوى الموقع كله، ولا تعِد تعريفهما في كل صفحة.
- Article أو BlogPosting: ضعه في ملف `page.tsx` الخاص بالمقالة، واملأ حقوله ديناميكيًا من بيانات الصفحة الحالية.
- BreadcrumbList: نظّمه وفق التسلسل الهرمي للمسارات، فهو مفيد خصوصًا في مساعدة الذكاء الاصطناعي على فهم بنية الموقع.
- FAQPage: لا تضفه إلا إذا كانت الصفحة تعرض فعلًا قسمًا للأسئلة والأجوبة، ويجب أن يطابق نص `acceptedAnswer` المحتوى الظاهر فيها. لا تنشئ أسئلة صورية لمجرد استكمال المخطط.

كيف تحافظ على سهولة صيانة JSON-LD؟
إذا وزّعت كائنات المخططات على صفحات متفرقة، فلن يجرؤ أحد على تعديلها بعد ثلاثة أشهر. منهجنا هو إنشاء ملف `lib/schema.ts` واستخدام أنواع `schema-dts`، مثل (`import type { Article, WithContext } from "schema-dts"`)، لضبط القيمة التي تعيدها كل دالة توليد. فإذا كان اسم الحقل أو نوعه غير صحيح، يعرض TypeScript خطأ أثناء مرحلة التجميع. عندها لا تفعل الصفحة سوى استدعاء `buildArticleSchema(post)`، والحصول على كائن آمن من ناحية الأنواع، ثم إخراجه. ويُطبّق أي تعديل لاحق على الموقع كله. كذلك نستخدم دائمًا عناوين URL مطلقة، ونجمعها تحت ثابت `SITE_URL` لمنع عدم تطابق `@id` بين الموقع الرسمي ونطاق المعاينة.
أخطاء شائعة وخطوات التحقق قبل الإطلاق
- عدم تطابق `url` أو `image` أو `datePublished` في JSON-LD مع المحتوى الفعلي الظاهر في الصفحة؛ فهذا التباين يرصده محرك الإجابة ويقلل ثقته في الصفحة بأكملها.
- استخدام مسارات نسبية في `@id` أو `url` قد يوجّهها إلى موقع خاطئ عند الانتقال إلى نطاق المعاينة.
- نسيان إفلات `<`، أو إضافة `"use client"` من دون قصد في أعلى الصفحة، ما يحول السكربت إلى مخرجات من جانب العميل.
- قبل الإطلاق، استخدم Google Rich Results Test للتحقق من صحة البنية، ثم استخدم `curl` لجلب HTML الأصلي للصفحة مباشرةً والتأكد من وجود السكربت فعلًا في الاستجابة الأولية، لا في متصفح DevTools وحده. وهذه هي الخطوة الأهم لأنها تحاكي بدقة ما يراه زاحف الذكاء الاصطناعي.
في المواقع التي دققناها، لا تكمن معظم مشكلات JSON-LD في كتابة المخطط بصورة خاطئة، بل في اقتصاره على جانب العميل. فإذا لم يظهر في HTML الذي يعيده الخادم، سيتعامل معه الذكاء الاصطناعي كما لو أنه غير موجود.— Tenten GEO Technical Audit
من التنفيذ إلى الاستشهاد بالمحتوى
نقل JSON-LD إلى Server Component هو الحد الأدنى لجعل المحتوى «قابلًا للقراءة آليًا». بعد ذلك، عليك توحيد أسماء الكيانات والروابط الداخلية والاتساق بين الصفحات، كي يستطيع الذكاء الاصطناعي الاستشهاد بمحتواك بثبات بوصفه مصدرًا موثوقًا. وإذا لم تكن متأكدًا من وصول البيانات المنظَّمة في موقعك إلى HTML الذي يراه الزاحف، يمكنك حجز جلسة تشخيص GEO لمدة 30 دقيقة. سنراجع شفرة المصدر التي جرى التقاطها فعليًا لتحديد الفجوات، بدلًا من الاكتفاء بالنظر إلى الصفحة بعد تصييرها.



