⏱️ جاري الحساب…

تشريح بلوك Gutenberg: العلاقة التكاملية بين block.json و edit و save

رسم مفاهيمي يوضح مكونات بلوك Gutenberg ضمن سلسلة تطوير ووردبريس
📋 فهرس محتويات المقال (اضغط للتنقل السريع) ▾

يا أهلاً بيك يا هندسة في ورشة العمل الحقيقية لصناع ووردبريس المعاصر! لما تبدأ تدخل عالم تطوير بلوكات جوتنبرج (Custom Gutenberg Blocks)، أول حاجة هتصطدم بيها هو “المثلث المعماري” اللي بيقوم عليه أي بلوك في الدنيا: ملف البيانات الوصفية block.json، ومكون التحرير في لوحة التحكم edit.js، ودالة الحفظ والتصيير save.js. لو فهمت التناغم والهارموني اللي بين التلاتة دول، هتقدر تبني أي واجهة مستخدم مهما كانت درجة تعقيدها في دقائق معدودة وبكود برودكشن فائق السرعة والأمان. لكن لو واحد منهم اختلف مع التاني، المحرر هيرمي لك شاشة الرعب الشهيرة: “This block contains unexpected or invalid content”! في الدليل التشريحي العملي ده، هنمسك البلوك حتة حتة، نفهم تدفق البيانات و setAttributes، ونبني بلوك بطاقة تسعير مؤسسي عالي الاحترافية.

المثلث المقدس: كيف تتكامل أضلاع البلوك الثلاثة؟

عشان تبني بلوك ناجح ومستقر، لازم تفهم دور كل ضلع من أضلاع المثلث:

  1. الملف الوصفي (block.json): ده بطاقة هوية البلوك وجواز سفره؛ بيحدد اسمه، أيقونته، تصنيفه، والأهم: الخصائص (Attributes) اللي البلوك هيخزنها، وملفات الـ CSS والـ JS اللي النواة محتاجة تحملها في المحرر والفرونت إند.
  2. مكون التحرير (edit.js): ده كود React التفاعلي اللي بيشتغل حصرياً داخل لوحة تحكم ووردبريس. وظيفته يدي المحرر تجربة كتابة وتعديل بصرية وسلسة (WYSIWYG)، ويحتوي على أزرار التنسيق وشريط الأدوات (Toolbar) ولوحة الإعدادات الجانبية (Inspector Controls).
  3. دالة الحفظ (save.js): دي دالة نقية (Pure Function) بتشتغل في لحظة ضغط زرار “حفظ” أو “نشر”. وظيفتها تاخد الـ Attributes المخزنة وتحولها لكود HTML ثابت ونقي يتم كتابته داخل عمود post_content في قاعدة البيانات، وهو نفس الكود اللي الزائر هيشوفه في الموقع.

التشريح التفصيلي لملف block.json (المواصفة القياسية v3)

ملف block.json هو المعيار الرسمي المعتمد من ووردبريس لتوحيد تعريف البلوكات بين PHP و JavaScript. تعال نفكك محتوياته الأساسية:

1. الهوية والتصنيف (Identity & Categorization)

  • apiVersion => 3: أحدث إصدار للمعيار (يدعم الـ Iframe داخل المحرر وعزل الـ Styles).
  • name => 'my-plugin/pricing-card': الاسم البرمجي الفريد للبلوك (يتكون من فضاء اسم واسم المورد).
  • title و description: النصوص الظاهرة للمحرر في قائمة إدراج البلوكات.
  • category => 'widgets': التصنيف الذي يظهر تحته البلوك في المحرر.
  • icon => 'money-alt': أيقونة Dashicon أو كود SVG مخصص للبلوك.

2. تعريف الخصائص (Attributes Schema)

الـ Attributes هي “المتغيرات” بتاعة البلوك. بتحدد نوع كل خاصية، قيمتها الافتراضية، ومصدر استخراجها:

"attributes": {
  "planTitle": {
    "type": "string",
    "default": "الباقة الاحترافية"
  },
  "price": {
    "type": "number",
    "default": 499.00
  },
  "isFeatured": {
    "type": "boolean",
    "default": false
  }
}

3. سحر خصائص الدعم التلقائي (Block Supports)

بدل ما تكتب كود CSS لاختيار الألوان والمسافات، ووردبريس بيوفر خاصية supports اللي بتضيف الخيارات دي تلقائياً في شريط إعدادات البلوك:

"supports": {
  "color": {
    "background": true,
    "text": true
  },
  "spacing": {
    "padding": true,
    "margin": true
  },
  "align": ["wide", "full"]
}

مكون التحرير: كواليس edit.js وإدارة الحالة التفاعلية

مكون الـ Edit بيستلم مجموعة من الـ Props الرسمية من محرر جوتنبرج:

  • attributes: كائن يحتوي على كافة القيم الحالية المخزنة للبلوك.
  • setAttributes: الدالة السحرية لتعديل الحالة (State Dispatcher). بتشتغل زي setState في React؛ أول ما تناديها، جوتنبرج بيحدث الذاكرة ويعلم المقال كمسودة غير محفوظة (Dirty State).
  • isSelected: قيمة منطقية (Boolean) بتعرفك هل المحرر ضاغط على البلوك ده حالياً ولا لأ (مفيدة لإظهار عناصر تحكم إضافية فقط عند التحديد).

تنظيم الواجهة: InspectorControls و BlockControls

في تجربة المستخدم، بنقسم عناصر التحكم لمكانين: 1. شريط الأدوات العائم (<BlockControls>): بنحط فيه العمليات السريعة اللي المستخدم بيحتاجها باستمرار (زي محاذاة النص، أو تحويل النص لـ Bold). 2. الشريط الجانبي (<InspectorControls>): بنحط فيه الإعدادات المتقدمة والتفصيلية (زي تغيير السعر، تفعيل الباقة المميزة، وضبط هوامش العنصر) باستخدام مكونات جاهزة زي <PanelBody> و <ToggleControl>.

دالة الحفظ: كواليس save.js والـ Serialization النظيف

القاعدة الذهبية رقم 1 في جوتنبرج: دالة save يجب أن تكون Pure Function بنسبة 100%! يعني إيه دالة نقية؟ يعني لنفس قيم الـ attributes الممررة، دالة save لازم ترجع نفس كود الـ HTML بالحرف والمسافة في كل مرة! لو كتبت جوة دالة save كود بيعتمد على الوقت الحالي new Date()، أو استدعاء شبكة عشوائي، كود الـ HTML المولد هيتغير في كل مرة تفتح فيها المقال، ومحرر جوتنبرج هيكتشف عدم التطابق ويرمي خطأ Block Invalidation الشهير!

الخطاف المعماري الإلزامي: useBlockProps

في إصدارات جوتنبرج الحديثة، لازم تغلف العنصر الجذري للبلوك بـ useBlockProps:

  • في edit.js: بنكتب <div { ...useBlockProps() }> لحقن معالجات الأحداث، وفئات التحديد، والـ CSS المطبق من supports داخل المحرر.
  • في save.js: بنكتب <div { ...useBlockProps.save() }> لحقن فئات الـ HTML النهائية وفئات الألوان والهوامش التي حددها المحرر في الكود النهائي.

مقارنة معمارية: البلوكات الثابتة (Static) مقابل البلوكات الديناميكية (Dynamic)

المعيار المعماريالبلوكات الثابتة (Static Blocks – save.js)البلوكات الديناميكية (Dynamic Blocks – PHP Render)
مكان تصيير الـ HTMLفي المتصفح وقت الحفظ ويخزن HTML صريح في الداتابيزعلى السيرفر بواسطة PHP في كل ريكوست للزائر
دالة save في JavaScriptترجع كود JSX / HTML كامل ودلاليترجع null دائماً؛ لأن السيرفر هو من يتولى العرض
الحاجة لـ render_callback في PHPلا تحتاج (ووردبريس يطبع المحتوى المخزن مباشرة)إلزامية ومطلوبة لكتابة كود الـ HTML في PHP
التعرض لأخطاء Block Invalidationمعرضة للخطأ عند تغيير كود الـ HTML بدون دالة Deprecationمحصنة تماماً ومستحيل تواجه خطأ Invalidation!
السرعة والأداء في الواجهة الأماميةفائقة السرعة؛ جاهزة في الداتابيز ولا تستهلك معالج الخادمتستهلك معالج خادم الـ PHP في كل زيارة (تحتاج لكاش)
سيناريو الاستخدام المثاليالعناصر الثابتة: بطاقات الأسعار، التنبيهات، الاقتباساتالعناصر المتغيرة: أحدث المقالات، خلاصات الأخبار، الطقس

تطبيق برودكشن متكامل: بناء بلوك بطاقة تسعير احترافية (Enterprise Pricing Card)

تعال نبني كود برودكشن حقيقي لبلوك بطاقة أسعار. الكود متقسم للملفات المعمارية الثلاثة:

1. ملف البيانات الوصفية (block.json)

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "enterprise/pricing-card",
  "version": "1.0.0",
  "title": "بطاقة باقة تسعير",
  "category": "widgets",
  "icon": "money-alt",
  "description": "بلوك مؤسسي لعرض خطط الأسعار والاشتراكات الشهرية والسنوية.",
  "supports": {
    "color": {
      "background": true,
      "text": true
    },
    "spacing": {
      "padding": true,
      "margin": true
    }
  },
  "attributes": {
    "planName": {
      "type": "string",
      "default": "الباقة الذهبية"
    },
    "price": {
      "type": "number",
      "default": 1499.00
    },
    "currency": {
      "type": "string",
      "default": "ج.م"
    },
    "features": {
      "type": "string",
      "default": "دعم فني 24/7nتحديثات مستمرةnاستضافة مجانية"
    },
    "isFeatured": {
      "type": "boolean",
      "default": false
    }
  },
  "editorScript": "file:./index.js",
  "editorStyle": "file:./index.css",
  "style": "file:./style-index.css"
}

2. ملف مكون التحرير (edit.js)

import { __ } from '@wordpress/i18n';
import { 
    useBlockProps, 
    RichText, 
    InspectorControls 
} from '@wordpress/block-editor';
import { 
    PanelBody, 
    TextControl, 
    ToggleControl 
} from '@wordpress/components';

export default function Edit({ attributes, setAttributes }) {
    const { planName, price, currency, features, isFeatured } = attributes;

    const blockProps = useBlockProps({
        className: `az-pricing-card ${isFeatured ? 'is-featured-plan' : ''}`
    });

    return (
        
            
                
                     setAttributes({ price: parseFloat(val) || 0 })}
                    />
                     setAttributes({ currency: val })}
                    />
                     setAttributes({ isFeatured: val })}
                    />
                
            

            
{isFeatured && ( {__('الأكثر شعبية في مصر', 'text-domain')} )} setAttributes({ planName: val })} placeholder={__('اسم الباقة...', 'text-domain')} />
{price.toLocaleString()} {currency} / شهرياً
setAttributes({ features: val })} placeholder={__('أدخل مميزات الباقة كل ميزة في سطر...', 'text-domain')} />

3. ملف دالة الحفظ (save.js)

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function save({ attributes }) {
    const { planName, price, currency, features, isFeatured } = attributes;

    const blockProps = useBlockProps.save({
        className: `az-pricing-card ${isFeatured ? 'is-featured-plan' : ''}`
    });

    return (
        
{isFeatured && ( الأكثر شعبية في مصر )}
{price.toLocaleString()} {currency} / شهرياً
اشترك الآن
); }

تفكيك الكود وشرح فلسفته المعمارية بالعامية المصرية

تعال نتأمل مع بعض الدقة الهندسية في بناء البلوك ده:

  • التوافق الحرفي بين edit و save: لو قارنت كود الـ JSX في edit.js والـ JSX في save.js، هتلاقي هيكل الـ DOM مطابق تماماً: نفس الوسوم، نفس الكلاسات، ونفس الترتيب. الفرق الوحيد إن في edit.js بنستخدم RichText القابل للكتابة وتعديل الـ State بـ onChange، وفي save.js بنستخدم RichText.Content المجرد اللي بيطبع كود HTML نقي وثابت. التطابق ده هو الضمان الوحيد إن البلوك عمره ما هيضرب Invalid Content!
  • استخدام useBlockProps و useBlockProps.save(): الخطاف ده بيحقن فئات الـ CSS المسؤولة عن الألوان والهوامش اللي المحرر اختارها في شريط الخصائص تلقائياً في الوسم الجذري <div>، بدون ما تضطر تقرأ كلاسات الألوان بإيدك أو تطبقها مانيوال!
  • استغلال الـ InspectorControls للمدخلات المعقدة: خلينا السعر وتفعيل الباقة المميزة في الشريط الجانبي (Sidebar)، وخلينا النصوص والعناوين قابلة للتحرير المباشر داخل الصفحة (In-place Editing)، وده بيقدم أعلى تجربة مستخدم (UX) لفريق التحرير في الشركة.

دراسة حالة واقعية من السوق المصري: كارثة الـ Invalid Blocks في 400 صفحة هبوط

تعال أحكيلك كواليس واقعة تقنية صعبة حصلت مع وكالة تسويق رقمي وبرمجة شهيرة في المعادي بالقاهرة:

الخطأ المعماري الفادح

الوكالة بنت حزمة بلوكات مخصصة لعميل عندهم بيدير منصة عقارات وتأجير شاليهات في الساحل الشمالي والعين السخنة. الموقع كان فيه أكثر من 400 صفحة هبوط للمشاريع العقارية كلها مبنية بالبلوك ده. المطور في أول تحديث للبلوك قرر إنه يغير كود الـ HTML في دالة save.js: غير الوسم من <div class="price"> إلى <span class="price-tag">! ورفع الكود المحدث بالـ Git على سيرفر الإنتاج فوراً!

لحظة الذعر في صالة التحرير

تاني يوم الصبح، دخل 30 كاتب ومسؤول مبيعات يعدلوا أسعار الشاليهات وتفاصيل الحجز. أول ما فتحوا أي صفحة من الـ 400 صفحة في لوحة التحكم، اتفاجأوا بالصدمة: كل البلوكات اتحولت لشاشات خطأ صفراء وحمراء بتقول: "This block contains unexpected or invalid content - Attempt Block Recovery"! ولما الموظف كان بيدوس على "Attempt Block Recovery"، جوتنبرج كان بيحول البلوك لكود HTML كلاسيكي ميت مش عارفين يعدلوا فيه ولا يغيروا الصور ولا الأسعار! حملات إعلانات بآلاف الدولارات كانت شغالة على الفيسبوك وجوجل، وتوقف فريق المبيعات تماماً عن العمل لمدة يومين!

خطة الإنقاذ بتطبيق مصفوفة الـ Deprecation

  1. إعادة صياغة كود البلوك عبر مصفوفة deprecated: فهمنا الفريق إنك لما تغير كود الـ HTML في دالة save لبلوك مستخدم بالفعل في مقالات منشورة، ممنوع تمسح الكود القديم! لازم توثقه كنسخة قديمة (Deprecated Version) داخل مصفوفة deprecated في ملف index.js:
    deprecated: [
        {
            attributes: oldAttributes,
            save({ attributes }) {
                // كود الـ HTML القديم بالـ div
                return 
    {attributes.price}
    ; } } ]
  2. الهجرة التلقائية السلسة: أول ما ووردبريس لقى مصفوفة الـ Deprecation، محرك جوتنبرج قارن الـ HTML بالنسخة القديمة وتعرف عليه، وقام بترقية البلوك تلقائياً للـ <span> الجديد في صمت وبدون ما يظهر أي خطأ أو تحذير للمحررين!
  3. اعتماد الاختبارات المؤتمتة للبلوكات (Block Snapshot Testing): أدخلنا نظام اختبارات Jest و Playwright للتأكد من عدم حدوث أي تغيير في كود دالة save مستقبلاً بدون مصفوفة ترقية معتمدة.

جدول مؤشرات التعافي الهندسي

المؤشر الفني والتشغيليلحظة وقوع الكارثةبعد تطبيق مصفوفة Deprecationالنتيجة المعمارية
نسبة صفحات الهبوط المصابة بالخطأ100% (400 صفحة هبوط معطلة)0.00% (صفر أخطاء)استعادة كاملة لكافة صفحات الموقع
إنتاجية فريق المبيعات والتحريرتوقف تام وارتباك إداريتحرير فوري وسلس دون انقطاعاستقرار بيئة العمل بنسبة 100%
فقدان البيانات والتنسيقات البصريةتحول البلوكات لـ Classic HTML ميتاحتفاظ كامل بكافة الـ Attributes والخياراتسلامة بيانات المحتوى
المرونة المعمارية للتحديثات المستقبليةرعب وخوف من لمس أي كود قديمتحديثات آمنة مدعومة بـ Versioning دقيقثقة مطلقة لفريق التطوير

الوصايا العشر لتطوير بلوكات Gutenberg احترافية

  1. اعتمد على block.json دائماً: هو المعيار الحديث والوحيد المعتمد؛ لا تسجل البلوكات بالطرق القديمة في JavaScript فقط.
  2. اجعل دالة save نقية تماماً (Keep Save Pure): إياك واستدعاء تواريخ حية أو أرقام عشوائية أو طلبات شبكة داخل دالة save لتفادي كابوس الـ Invalidation.
  3. استخدم مصفوفة deprecated عند تغيير الـ HTML: إذا قمت بتعديل مخرجات وسم في دالة save لبلوك مستخدم، وثق النسخة السابقة دائماً.
  4. استخدم useBlockProps في كل مكان: لا تكتب وسوم الحاويات مجردة؛ احقن useBlockProps() في التحرير و useBlockProps.save() في الحفظ.
  5. استثمر في مكونات النواة الجاهزة: استخدم مكونات حزمة @wordpress/components مثل TextControl و ToggleControl لضمان اتساق الواجهة مع لوحة تحكم ووردبريس.
  6. حدد أنواع الـ Attributes بدقة: لا تترك نوع الخاصية مجهولاً؛ حدد هل هي string أو number أو boolean أو array.
  7. فعل ميزات supports بدلاً من إعادة كتابتها: دع ووردبريس يدير الألوان والهوامش والمحاذاة نيابة عنك عبر ملف block.json.
  8. اجعل مخرجات الـ HTML دلالية (Semantic HTML): استخدم الوسوم الصحيحة مثل <figure>، <blockquote>، و <article> لتحسين الـ SEO وإمكانية الوصول (A11y).
  9. عطل دالة save للبلوكات الديناميكية: إذا كان البلوك يعتمد على PHP في التصيير اللحظي، اجعل دالة save ترجع null صريحة.
  10. احرص على دعم الترجمة والتدويل (i18n): غلف كافة النصوص الظاهرة للمحرر بدوال الترجمة الرسمية __('النص', 'text-domain').

التعمق المعماري: خوارزمية مصادر الخصائص (Attribute Sources) وتوفير حجم الداتابيز

يا صديقي المطور، من أذكى الأفكار المعمارية في ووردبريس هي إنك مش بالضرورة تخزن كل قيمة في الـ JSON بتاع تعليق البلوك! لو عندك بلوك فيه عنوان <h3>الباقة الذهبية</h3>، ليه تخزن كلمة "الباقة الذهبية" مرتين: مرة في كود الـ HTML ومرة تانية كـ JSON جوة <!-- wp:custom/block {"planTitle":"الباقة الذهبية"} -->؟ ده بيضاعف حجم قاعدة البيانات على الفاضي! عشان كده جوتنبرج بيدعم خاصية عبقرية اسمها Attribute Sources في ملف block.json:

"attributes": {
  "planTitle": {
    "type": "string",
    "source": "text",
    "selector": "h3.plan-title"
  },
  "buttonUrl": {
    "type": "string",
    "source": "attribute",
    "selector": "a.cta-button",
    "attribute": "href"
  }
}

إيه اللي بيحصل هنا؟ وقت الحفظ، تعليق البلوك بيتخزن فاضي تماماً: <!-- wp:enterprise/pricing-card /-->! ولما المحرر يفتح المقال تاني، محرك جوتنبرج بيشغل DOM Parser داخلي، يروح يقرا النص اللي جوة وسم <h3 class="plan-title"> ويحطه في attributes.planTitle، ويقرا خاصية href من وسم <a> ويحطها في attributes.buttonUrl! التقنية دي بتوفر أكثر من 50% من حجم جدول wp_posts في المواقع الكبيرة اللي فيها آلاف المقالات.

معمارية التحويل التلقائي (Block Transforms API)

عمرك سألت نفسك إزاي لما بتحدد فقرة نصية في جوتنبرج وتقدر تحولها بضغطة زرار واحدة لاقتباس (Quote) أو قائمة نقطية (List)؟ ده بيتم عبر Block Transforms API المسجل في كود البلوك: تقدر تعرف تحويلات قادمة (from) وتحويلات صادرة (to). مثلاً، تقدر تسمح للمحرر إنه يحول بلوك بطاقة التسعير القديم إلى بلوك جدول مقارنة بضغطة زر واحدة: المحرك بياخد الـ Attributes الحالية (الاسم، السعر، المميزات) وينقلها تلقائياً للبلوك الجديد دون أن يفقد المحرر أي حرف كتبه! ده النضج الحقيقي اللي بيميز البلوكات المؤسسية عن التجارب البرمجية العشوائية.

التعمق المعماري: كتل الحاويات المتداخلة (InnerBlocks) والتحكم في قفل القوالب (Template Locking)

يا صديقي المطور، لما تبني بلوك مركب زي "قسم الخدمات" أو "أكوردين الأسئلة الشائعة" أو "جدول الأسعار المتعدد"، هتحتاج إن البلوك يحتوي على بلوكات تانية حرة يقدر المحرر يضيفها ويحركها جواه. هنا بيجي دور المكون النواتي العبقري <InnerBlocks /> من حزمة @wordpress/block-editor. المكون ده بيسمحلك تحول البلوك بتاعك لحاوية (Container Block). والأجمل من كده، إنك تقدر تتحكم بصرامة هندسية في إيه اللي مسموح للمحرر يضيفه جواه عبر مصفوفة ALLOWED_BLOCKS وقوالب البداية TEMPLATE:

// تحديد قفل صارم للبلوكات المسموح بها داخل الحاوية
const ALLOWED_BLOCKS = ['core/heading', 'core/paragraph', 'core/button'];
const TEMPLATE = [
    ['core/heading', { placeholder: 'عنوان القسم الرئيسي...', level: 2 }],
    ['core/paragraph', { placeholder: 'اكتب وصفاً جذاباً للخدمة هنا...' }],
    ['core/button', { text: 'تواصل معنا الآن' }]
];

export default function Edit() {
    return (
        
); }

خاصية templateLock="all" أو templateLock="insert" دي بتعتبر صمام أمان لا غنى عنه في المواقع المؤسسية الكبيرة؛ لأنها بتسمح للمحرر إنه يعدل النصوص والصور بحرية كاملة، لكن بتمنعه تماماً من إنه يبوظ شبكة التصميم (Layout Grid) أو يمسح أزرار الـ CTA الأساسية، وده اللي بيحافظ على الهوية البصرية للعلامة التجارية في كل صفحات الموقع.

الأسئلة الشائعة حول تشريح بلوك Gutenberg (20 سؤالاً تقنياً)

1. ما هو الدور الأساسي لملف block.json في بنية البلوك؟

هو المركز الموحد لتعريف هوية البلوك، خصائصه (Attributes)، ميزات الدعم (Supports)، وربط ملفات الـ CSS والـ JS بين بيئة PHP وبيئة JavaScript.

2. ما الفرق الجوهري بين مكون edit.js ودالة save.js؟

المكون edit.js يعمل داخل لوحة التحكم فقط لتوفير تجربة تحرير تفاعلية بصرية، بينما save.js دالة نقية تحدد كود الـ HTML النهائي الذي يخزن في قاعدة البيانات ويعرض للزوار.

3. لماذا يرمي المحرر خطأ "This block contains unexpected or invalid content"؟

بسبب اختلاف كود الـ HTML المولد من دالة save.js الحالية عن كود الـ HTML المخزن مسبقاً في قاعدة البيانات لنفس البلوك بنفس الـ Attributes.

4. كيف تعمل مصفوفة deprecated على حل مشكلة الـ Invalidation؟

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

5. ما هي وظيفة دالة setAttributes() في مكون التحرير؟

تقوم بتحديث قيم خصائص البلوك في متجر بيانات المحرر وحفظها كمسودة جديدة، وتشبه دالة setState في بيئة React.

6. ما هو الخطاف useBlockProps ولماذا يعتبر استخدامه إلزامياً؟

يقوم بحقن الفئات والسمات ومعالجات الأحداث وخصائص الـ Block Supports تلقائياً في الوسم الجذري للبلوك في المحرر وفي دالة الحفظ.

7. متى يجب أن ترجع دالة save القيمة null؟

عند بناء بلوك ديناميكي (Dynamic Block) يعتمد على السيرفر في توليد الـ HTML عبر دالة render_callback في PHP (مثل بلوك أحدث المقالات).

8. ما هو الفرق بين editorScript و viewScript في ملف block.json؟

الـ editorScript يتم تحميله فقط داخل لوحة التحكم لتشغيل المحرر، بينما viewScript يتم تحميله في الواجهة الأمامية للموقع لإضافة تفاعلية للزوار.

9. ما هي وظيفة المكون <InspectorControls>؟

يسمح بحقن حقول الإعدادات والخيارات المتقدمة في الشريط الجانبي الأيمن للمحرر (Sidebar) بدلاً من ملء مساحة التحرير الرئيسية.

10. ما هي وظيفة المكون <BlockControls>؟

يسمح بإضافة أزرار وخيارات في شريط الأدوات العائم (Toolbar) الذي يظهر مباشرة فوق البلوك عند تحديده.

11. كيف يمكنني إتاحة تحرير النصوص المتعددة الأسطر داخل البلوك؟

باستخدام المكون <RichText multiline="p" /> الذي يسمح بإنشاء فقرات متعددة وتنسيق الخطوط داخل البلوك بسلاسة.

12. ما فائدة خاصية apiVersion: 3 في block.json؟

تتيح عزل تصميم البلوك داخل Iframe في المحرر، وتمنع تداخل ملفات CSS الخاصة بالثيم مع واجهة لوحة تحكم ووردبريس.

13. كيف أمنع المحرر من استخدام وسم معين في ميزة التحرير الغني؟

بتحديد مصفوفة الـ allowedFormats في مكون RichText (مثل حصر التنسيق في Bold و Italic فقط ومنع الروابط).

14. هل يمكن لبلوك أن يحتوي على بلوكات أخرى بداخله (Nested Blocks)؟

نعم، باستخدام المكون النواتي <InnerBlocks /> الذي يسمح للمحرر بإدراج أي بلوكات أخرى داخل البلوك الأب مع إمكانية قفل القالب المسموح.

15. كيف أضيف فئة CSS مخصصة للبلوك بناءً على خاصية معينة؟

بتمرير الفئة في وسيط className داخل useBlockProps({ className: 'my-custom-class' }) في ملف التحرير والحفظ.

16. ما الفرق بين تخزين الخاصية كـ Comment Attribute وتخزينها كـ Source Attribute؟

الـ Comment Attribute يخزن الخاصية كـ JSON في تعليق البلوك، بينما الـ Source Attribute يستخرج القيمة مباشرة من وسم الـ HTML نفسه (مثل قراءة النص من داخل <h3>).

17. كيف أمنع تكرار إدراج نفس البلوك أكثر من مرة في المقال الواحد؟

بإضافة خاصية "supports": { "multiple": false } في ملف block.json، مما يمنع إضافة أكثر من نسخة واحدة منه في الصفحة.

18. ما هي أفضل أداة لبناء وتهيئة مشروع بلوك جوتنبرج جديد؟

الأداة الرسمية المدعومة من فريق ووردبريس @wordpress/create-block التي تنشئ هيكل المشروع بالكامل مع إعدادات Webpack و ESLint.

19. كيف يؤثر استخدام Block Supports على حجم ملفات الـ CSS؟

يقلل حجم الـ CSS بشكل ملحوظ؛ لأن ووردبريس يقوم بتوليد فئات CSS ونظام Inline Utility Styles للميزات المفعلة فقط دون كتابة أكواد زائدة.

20. ما هي القاعدة الذهبية لتصميم بلوك جوتنبرج يدوم لسنوات؟

"احترم العقد وافصل المسؤوليات": اجعل block.json مصدر الحقيقة للبيانات، واجعل edit سهلاً وممتعاً، واجعل save نقياً ودلالياً ولا تلمس الـ HTML بدون توثيق الـ Deprecation.

الصورة الرمزية لـ Mohamed Abozaid

م. محمد أبو زيد

WordPress Architect & Enterprise Consultant

مهندس برمجيات متخصص في تطوير حلول ووردبريس المتقدمة، معمارية Block Themes، ومحرر Gutenberg، وتحسين الأداء لمواقع الشركات الكبرى في مصر والخليج العربي.


اترك تعليقاً