تخطَّ إلى المحتوى

البيانات المهيكلة في Next.js، مُولَّدة من رسم بياني واحد

معظم JSON-LD يُنشَر ككتل أربع منفصلة تُعيد كل واحدة إعلان المؤسسة. رسمٌ بياني واحد متّصل بمراجع @id ثابتة شيفرةٌ أقل، وهو ما يستطيع الزاحف تحليله.

5 دقيقة قراءة

البيانات المهيكلة هي الجزء من السيو التقني الذي تتّسع فيه المسافة أكثر ما تتّسع بين ما تطلقه الفرق وما تكافئ عليه المواصفة. التنفيذ المعتاد مكوّن لكل نوع صفحة، يبثّ كلٌّ منه <script type="application/ld+json"> خاصًّا به، ويُعيد كلٌّ منه إعلان المؤسسة والموقع والشعار.

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

رسمٌ واحد، لا أربع كتل

المفتاح @graph موجود لهذا. يحوي قائمة عُقد، لكلٍّ منها @id ثابت، وتشير العُقد بعضها إلى بعض بذلك الـ@id بدل أن تكرّر محتوى بعضها.

{
  "@context": "https://schema.org",
  "@graph": [
    { "@type": "Organization", "@id": "https://example.com/#org", "name": "Example" },
    { "@type": "WebSite", "@id": "https://example.com/#site", "publisher": { "@id": "https://example.com/#org" } },
    { "@type": "WebPage", "@id": "https://example.com/blog/post#page", "isPartOf": { "@id": "https://example.com/#site" } },
    { "@type": "Article", "@id": "https://example.com/blog/post#article", "mainEntityOfPage": { "@id": "https://example.com/blog/post#page" } }
  ]
}

أربع عُقد، ومؤسسة واحدة، وكل علاقة مذكورة مرّة واحدة. قيم الـ@id هي الآلية كلّها: هي ما يتيح للزاحف أن يدمج العقدة التي يراها هنا مع العقدة نفسها في كل صفحة أخرى.

قاعدتان تجعلانها تعمل:

  • روابط مطلقة دائمًا. #org وحده ليس معرّفًا، بل جزء رابط يعني شيئًا مختلفًا في كل صفحة.
  • ثابتة إلى الأبد. الـ@id الذي يتغيّر بين عمليات النشر - لأنه بُني من slug عُدِّل، أو من معرّف صفّ في قاعدة بيانات - يُهدر كل ما راكمه الزاحف مقابله.

وَلِّدها بدل أن تكتبها

سبب انحراف الـJSON-LD المكتوب يدويًا أن لا شيء يجبره على موافقة الصفحة. فيتغيّر العنوان في تصدير metadata ويحتفظ headline في البيانات المهيكلة بالقديم، لأنهما نصّان في ملفّين.

العلاج مساعد واحد محدَّد الأنواع، يُستدعى من الموضع الذي يعرف الجواب أصلًا:

// lib/jsonld.ts
export function articleNode({ url, title, description, published, modified }: ArticleInput) {
  return {
    '@type': 'Article',
    '@id': `${url}#article`,
    headline: title,
    description,
    datePublished: published,
    dateModified: modified ?? published,
    mainEntityOfPage: { '@id': `${url}#page` },
    publisher: { '@id': `${SITE}#org` },
  };
}
// app/blog/[slug]/page.tsx
<JsonLd data={graph(
  webPageNode({ url, title: doc.title, description: doc.description }),
  articleNode({ url, title: doc.title, description: doc.description,
                published: doc.date, modified: doc.updated }),
  breadcrumbNode(trail),
)} />

الآن لا تستطيع البيانات المهيكلة أن تخالف الصفحة، لأنها تقرأ المتغيّرات نفسها التي تعرضها الصفحة. وهذا هو مبدأ الروابط المعيارية وخرائط الموقع التي لا يمكن أن تنحرف: مصدر واحد للحقيقة، يُولَّد عند الطرفين.

أين تنتمي داخل الاستجابة

في الـHTML المعروض على الخادم. أي <script> يحقنه مكوّن عميل بعد الترطيب هو ترميز قد ينفّذه الزاحف وقد لا ينفّذه، ولا داعي للمراهنة - فالبيانات معروفة على الخادم.

export function JsonLd({ data }: { data: object }) {
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
    />
  );
}

dangerouslySetInnerHTML هنا صحيحة وليست اختصارًا: فReact يهرّب الأبناء النصّيين، وهو ما يُفسد الـJSON. ما يجب ألّا تفعله هو إدراج نصّ يتحكّم به المستخدم دون تهريب < - فتعليقٌ يحوي </script> سيغلق الوسم وينفّذ ما بعده.

الأنواع التي تستحقّ، والأنواع التي مجرّد استعراض

تستحقّ البيانات المهيكلة مكانها حين تقابل نتيجة غنيّة أو تحدّد كِيانًا. وما عدا ذلك ترميزٌ لا يقرأه أحد.

تستحقّ:

  • Organization وWebSite، مرّة واحدة، ويُشار إليهما من كل مكان.
  • BreadcrumbList، فهو يظهر مباشرة في النتائج.
  • Article على المقالات، وProduct ببيانات Offer حقيقية على المنتجات.
  • FAQPage، لكن فقط حيث تكون الأسئلة ظاهرة على الصفحة. وسْم أسئلة غير معروضة مخالفة للإرشادات، لا حيلة ذكية.
  • LocalBusiness أو أحد أنواعها الفرعية حيث يوجد عنوان حقيقي. انتبه: الأنواع الفرعية تشترط address - فـProfessionalService بلا عنوان غير صالح، وهذه طريقة شائعة لإطلاق رسمٍ معطوب مع الاعتقاد أنه أغنى.

لا تستحقّ كثيرًا:

  • Review كتبتها عن نفسك. فترميز المراجعات الذاتية غير مؤهّل للنتائج الغنيّة منذ سنوات.
  • HowTo وRecipe على صفحات ليست هذه ولا تلك.
  • speakable وSiteNavigationElement وبقيّة الذيل الطويل الذي لا تستهلكه أي واجهة.

كيف تتحقّق

أداتان، وتجيبان عن سؤالين مختلفين. اختبار النتائج الغنيّة يخبرك إن كانت الصفحة مؤهّلة لنوع نتيجة بعينه. ومدقّق ترميز Schema يخبرك إن كان رسمك سليم البنية - وهو الذي يلتقط مرجع @id معلَّقًا في الفراغ، وهو ما تتجاهله الأداة الأولى بلا اكتراث.

شغّل الاثنتين على الـHTML المعروض للصفحة المنشورة، لا على مقتطف ملصوق. المقتطف هو ما كتبتَه، والـHTML المعروض هو ما أطلقتَه - وفي المواقع التي أمامها طبقة تخزين مؤقّت ليسا الشيء نفسه بالضرورة.

العودة إلى كل المقالات