أهلاً بيك يا صديقي المطور في المحطة الحاسمة اللي هتنقل فهمك لمحرر المكونات (Gutenberg) من مجرد مطور بيعمل بلوكات نصوص وصور منفصلة، لمهندس برمجيات بيبني “تخطيطات مركبة متكاملة” (Complex Composite Layouts). لو بتسأل نفسك إزاي بلوك الأعمدة (Columns) أو بلوك المجموعة (Group) في ووردبريس بيقدر يشيل جواه أي عدد من البلوكات التانية بسلاسة، ويحتفظ بنفس التنسيق والشكل في شاشة التحرير وفي الموقع الحقيقي بدون أدنى تعارض، فالإجابة بكلمة واحدة: InnerBlocks API.
الـ InnerBlocks مش مجرد كومبوننت بنحطه في كود الـ React؛ دي المعمارية التحتية اللي بتخلي ووردبريس يفهم مفهوم “الحاوية” (Container Architecture). زمان قبل ظهور الـ InnerBlocks Props الحديثة، كان المطورين بيلجأوا لحيل صعبة زي تكرار الـ Shortcodes أو تخزين كائنات JSON معقدة جوة خصائص فردية، وده كان بينتهي بكوارث في التوافق وتجربة كتابة مرعبة للمحررين. في المقال ده، هنفكك الـ InnerBlocks حتة حتة، وهنعرف الفرق الجوهري بين استخدامه في البلوكات الثابتة (Static Blocks) والبلوكات الديناميكية (Dynamic Blocks)، مع التركيز على نمط useInnerBlocksProps الحديث، وكيفية قفل القوالب وضمان التوافق التام بنسبة 100% بين شاشة التحرير وشاشة العرض في الواجهة الأمامية بالعامية المصرية التقنية الأصيلة.
| المعيار المعماري | النمط القديم: <InnerBlocks /> | النمط الحديث: useInnerBlocksProps Hook | الحاويات الديناميكية (Dynamic PHP) |
|---|---|---|---|
| هيكل الـ DOM والـ Wrapper | ينشئ عنصر <div> إضافي غير مرغوب فيه يكسر أحياناً تنسيقات Flex و Grid. | يدمج خصائص الحاوية مباشرة في الـ Wrapper الأصلي للبلوك دون أي وسوم دخيلة. | يتم رندرة الأبناء عبر طباعة المتغير $content داخل دالة الـ PHP. |
| تزامن التحرير والحفظ (Edit vs Save) | يتطلب وضع <InnerBlocks.Content /> صراحة في دالة الحفظ مع حذر شديد. | يوفر خطاف useInnerBlocksProps.save() متطابق تماماً في البنية مع خطاف التحرير. | دالة save في الجافاسكريبت ترجع <InnerBlocks.Content /> فقط لتمريرها للـ PHP. |
| التحكم في القوالب (Templates) | تمرير مصفوفة template كخاصية على الكومبوننت مع تداخل في الـ Props. | تعريف القالب والـ Lock ككائن إعدادات نظيف ومنفصل تماماً عن عناصر الـ JSX. | يتم حجز الهيكل المبدئي في التحرير فقط، بينما الـ PHP يعرض ما حفظه المحرر فعلياً. |
| أداء معالجة الـ Events | قد يعاني من تضارب أحداث النقر وتحديد البلوك الأب مع أحداث الأبناء داخل المتصفح. | توزيع ذكي ومتناغم للأحداث (Event Delegation) مدمج تلقائياً مع useBlockProps. | لا توجد معالجة أحداث في الواجهة الخلفية؛ مجرد تحويل نصوص HTML إلى مخرجات المتصفح. |
| دعم ميزات الـ Flex/Grid Layout | يحتاج حيل CSS معقدة وتعديل قواعد الـ Layout يدكياً لتجاوز الطبقات المضافة. | دعم طبيعي بالكامل لكافة خصائص CSS الحديثة ونظام تخطيط جوتنبرج الأصلي (Layout Support). | تطبيق التنسيقات يتم عبر فئات CSS المعرفة في ملف الـ Style الخاص بالحاوية. |
المعمارية العميقة للـ InnerBlocks API: إزاي جوتنبرج بيدير الحاويات؟
عشان تفهم InnerBlocks بعمق يفرقك عن المطورين الهواة، لازم تسأل نفسك: هو إيه اللي بيحصل في قاعدة بيانات ووردبريس وفي الذاكرة لما بنحط بلوك جوة بلوك؟
في الذاكرة (Client-side Memory)، محرر جوتنبرج بيتعامل مع كل مقال كشجرة كائنات برمجية (Block Tree AST). لما البلوك يعلن إنه بيستخدم InnerBlocks، المحرر بيفهم فوراً إن البلوك ده مش مجرد عقدة ورقية نهائية (Leaf Node)، بل هو عقدة فرعية (Branch Node) تقدر تشيل مصفوفة فرعية كاملة اسمها innerBlocks. كل عنصر في المصفوفة دي هو كائن بلوك كامل عنده clientId، name، attributes، وكمان ممكن يكون عنده innerBlocks خاصة بيه في تداخل غير محدود!
أما عند الحفظ في جدول wp_posts داخل عمود post_content، ووردبريس بيترجم الشجرة دي لنص تسلسلي (Serialized HTML with Block Delimiters). البلوك الأب بيفتح بالتعليق الشكلي:
<!-- wp:my-plugin/container {"layout":"grid"} -->
<div class="wp-block-my-plugin-container">
<!-- wp:paragraph -->
<p>هذا نص الابن الأول المتداخل</p>
<!-- /wp:paragraph -->
<!-- wp:image {"id":42} -->
<figure class="wp-block-image"><img src="..." alt=""/></figure>
<!-- /wp:image -->
</div>
<!-- /wp:my-plugin/container -->
لاحظ الدقة هنا يا هندسة: ووردبريس بيحفظ وسوم تعليقات الأبناء مباشرة بين وسم فتح الحاوية ووسم إغلاقها! دالة InnerBlocks.Content في دالة الحفظ ما بتعملش أي سحر معقد؛ كل وظيفتها إنها تحط “علامة حجز مكان” (Placeholder) في الـ JSX بتقول لمحرر جوتنبرج: “هنا بالضبط اطبع المحتوى المتسلسل لجميع الأبناء بالترتيب”.
ثورة useInnerBlocksProps Hook: وداعاً للطبقات الزائدة
في الإصدارات الأولى من Gutenberg، كنا مضطرين نكتب:
// ❌ الأسلوب القديم الذي كان يضيف وسم div غير مرغوب فيه
export function Edit() {
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<h2>عنوان الحاوية</h2>
<InnerBlocks />
</div>
);
}
المشكلة كانت إن كومبوننت <InnerBlocks /> كان بيولد تلقائياً وسم <div class="block-editor-block-list__layout"> إضافي داخلي، وده كان بيكسر تماماً رغبتك في استخدام CSS Grid مباشرة بين الأبناء وبين العناصر المجاورة لهم.
لذلك، فريق ووردبريس قدم الخطاف العبقري useInnerBlocksProps. الخطاف ده بياخد خصائص البلوك ويدمج معاها خصائص الحاوية في كائن واحد، فتقدر تحول أي وسم HTML عندك (سواء كان <div>، <section>، <ul>، أو حتى <main>) لحاوية أبناء فورية بدون وسوم حشو وسيطة!
تطبيق عملي كامل: بناء بلوك كروت شبكية متقدمة (Enterprise Grid Container)
تعال نبني مع بعض كود إنتاجي لبلوك حاوية اسمه (enterprise/feature-grid) بيحتوي على كروت مميزات (enterprise/feature-card). الحاوية دي فيها قفل قالب مرن، وأزرار إضافة مخصصة، وتطابق بنسبة 100% بين واجهة التحرير والواجهة الأمامية للموقع.
1. إعداد ملف التعريف: block.json
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "enterprise/feature-grid",
"version": "1.0.0",
"title": "شبكة الميزات المتقدمة",
"category": "design",
"icon": "grid-view",
"description": "حاوية احترافية مبنية بـ InnerBlocks لعرض بطاقات الخدمات والميزات بتنسيق شبكي متطور.",
"supports": {
"html": false,
"align": [ "wide", "full" ],
"color": {
"background": true,
"text": true
},
"spacing": {
"margin": true,
"padding": true
}
},
"attributes": {
"columnsCount": {
"type": "number",
"default": 3
},
"templateLocked": {
"type": "string",
"default": "none"
}
},
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css"
}تفكيك الخصائص التقنية:
apiVersion: 3: يضمن استخدام المعمارية الحديثة وعزل سياق التنسيقات في بيئة معزولة (Iframe) داخل المحرر.supports.html: false: خطوة أمنية وتنظيمية تمنع المحرر من العبث بكود الـ HTML الخاص بالحاوية يدوياً عبر خيار “Edit as HTML”، لحماية بنية الحاوية من التلف.columnsCount: خاصية تتحكم في توزيع الأعمدة الشبكية في الـ CSS في الواجهتين.
2. كود واجهة التحرير: edit.js باستخدام useInnerBlocksProps
import { useBlockProps, useInnerBlocksProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, RangeControl, SelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import './editor.scss';
// تحديد البلوكات المسموح بإدراجها فقط داخل هذه الحاوية
const ALLOWED_BLOCKS = [ 'enterprise/feature-card', 'core/heading', 'core/paragraph' ];
// تعريف القالب الافتراضي المبدئي عند إدراج البلوك لأول مرة
const TEMPLATE = [
[ 'core/heading', { level: 2, placeholder: 'اكتب عنوان قسم المميزات هنا...' } ],
[ 'enterprise/feature-card', { title: 'ميزة الأداء الفائق', icon: 'performance' } ],
[ 'enterprise/feature-card', { title: 'الأمان المتقدم', icon: 'shield' } ],
[ 'enterprise/feature-card', { title: 'دعم العملاء على مدار الساعة', icon: 'headset' } ]
];
export default function Edit( { attributes, setAttributes } ) {
const { columnsCount, templateLocked } = attributes;
// استخراج خصائص الغلاف الخارجي للبلوك
const blockProps = useBlockProps( {
className: `az-enterprise-grid az-grid-cols-${ columnsCount }`
} );
// دمج خصائص الحاوية المتداخلة مع الغلاف مباشرة
const innerBlocksProps = useInnerBlocksProps( blockProps, {
allowedBlocks: ALLOWED_BLOCKS,
template: TEMPLATE,
templateLock: templateLocked === 'none' ? false : templateLocked,
orientation: 'horizontal',
// استخدام زر إضافة مخصص يظهر في نهاية قائمة البلوكات
renderAppender: innerBlocksProps => (
)
} );
return (
setAttributes( { columnsCount: val } ) }
min={ 1 }
max={ 4 }
/>
setAttributes( { templateLocked: val } ) }
help={ __( 'يتحكم في صلاحيات المحررين في تعديل ترتيب وبنية الكروت الداخلية.', 'az-grid' ) }
/>
{ /* هنا يكمن السحر: لا يوجد أي وسوم متداخلة حشو! العنصر نفسه هو الحاوية */ }
>
);
}</code>شرح أسرار كود التحرير:
useInnerBlocksProps(blockProps, options): لاحظ هنا إننا مررناblockPropsكأول وسيط! الحركة دي معناها: "خد كلاسات الـ wrapper وهوامش ووردبريس وحطها على نفس الوسم، واجعل الوسم ده نفسه هو حاوية الأبناء". مفيش<div>داخلي زيادة!allowedBlocks: حماية معمارية حديدية؛ بتمنع المحرر إنه يحط بلوك غير متوافق (زي ويدجت قديمة أو فورم تكسر التصميم) داخل شبكة الخدمات.templateLock: بيوفر 4 أوضاع لقفل القالب:false(حر تماماً)،all(ممنوع تحذف كارت أو تضيف كارت جديد، بس تقدر تغير ترتيبهم أو تعدل نصوصهم)،insert(ممنوع تضيف بس ينفع تحذف أو ترتب)، وcontentOnlyوهو الوضع الأحدث اللي بيقفل التنسيق تماماً ويسمح بتعديل الكلمات فقط.
3. كود واجهة الحفظ: save.js المتطابق
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
export default function save( { attributes } ) {
const { columnsCount } = attributes;
const blockProps = useBlockProps.save( {
className: `az-enterprise-grid az-grid-cols-${ columnsCount }`
} );
const innerBlocksProps = useInnerBlocksProps.save( blockProps );
return (
);
}
لماذا save.js هنا هو قمة النقاء البرمجي؟
زمان كنت تضطر تعمل <div { ...blockProps }><InnerBlocks.Content /></div>. لو نسيت وسم أو غيرت ترتيب كلاس، ووردبريس يصرخ في وشك بـ Block Validation Error الشهير. مع useInnerBlocksProps.save(blockProps)، ووردبريس بيضمن رياضياً إن نفس الوسم ونفس الخصائص اللي اتعملت في دالة التحرير هيتم كتابتها في ملف الحفظ بدون أي خطأ بشري محتمل!
4. نمط الحاوية الديناميكية في PHP: متى ولماذا نستخدمه؟
لو كان البلوك الأب بيحتاج يعرض بيانات تتغير لحظياً من قاعدة البيانات (زي مثلاً إضافة كود ترويجي أعلى الكروت، أو حساب عدد العناصر التراكمي)، ساعتها بنلجأ للبلوك الديناميكي:
في ملف block.json بنحدد: "render": "file:./render.php"، وفي ملف save.js بنحتفظ فقط بحاوية الأبناء:
// save.js في البلوكات الديناميكية
import { useInnerBlocksProps } from '@wordpress/block-editor';
export default function save() {
return <useInnerBlocksProps.Content />;
}وفي ملف render.php بنستقبل الـ HTML الخاص بالأبناء بكل بساطة في المتغير $content:
<?php
/**
* ملف render.php لحاوية البلوك الديناميكية
*
* @var array $attributes خصائص البلوك
* @var string $content مخرجات الـ InnerBlocks مجهزة بالكامل كـ HTML
* @var WP_Block $block كائن البلوك الأصلي
*/
$cols = isset( $attributes['columnsCount'] ) ? absint( $attributes['columnsCount'] ) : 3;
$wrapper_attributes = get_block_wrapper_attributes([
'class' => 'az-enterprise-grid az-grid-cols-' . $cols,
]);
?>
<section <?php echo $wrapper_attributes; ?>>
<div class="az-grid-dynamic-badge">
<?php printf( esc_html__( 'عدد الأقسام المعروضة حالياً: %d', 'az-grid' ), count( $block->inner_blocks ) ); ?>
</div>
<!-- طباعة محتويات الأبناء التي تم توليدها وتجميعها تلقائياً -->
<div class="az-grid-items-container">
<?php echo $content; ?>
</div>
</section>الهندسة المعمارية لقفل القوالب (Template Locking Deep Dive)
قفل القوالب في InnerBlocks مش مجرد إخفاء لزر الإضافة؛ ده نظام تصاريح أمني في واجهة التحرير (Editor Authorization Layer). جوتنبرج بيدعم 3 قيم رئيسية لـ templateLock لازم تفهم الفروق الدقيقة بينهم:
-
الوضع الحر (templateLock={false}):
ده الوضع الافتراضي. المحرر عنده الحرية المطلقة إنه يمسح أي كارت، يغير ترتيب الكروت بالسحب والإفلات، ويضيف كروت جديدة أو حتى يضيف بلوكات مسموحة تانية من خلال زر الإدراج.
-
قفل الإدراج فقط (templateLock="insert"):
هنا المحرر يقدر يحذف كروت موجودة، ويقدر يبدل ترتيبهم فوق وتحت، لكن السيستم بيمنعه منعاً باتاً من إضافة كروت جديدة غير اللي كانت موجودة في القالب المبدئي.
-
القفل الهيكلي الصارم (templateLock="all"):
المحرر ممنوع يضيف كروت جديدة، وممنوع يحذف أي كارت من الكروت الحالية، وممنوع حتى يحرك الكروت من أماكنها بالسحب والإفلات! لكن يقدر يضغط على كل كارت ويعدل النصوص، يغير الصور، أو يعدل ألوان البلوك إذا كان البلوك يدعم ذلك.
-
قفل المحتوى الحصري (templateLock="contentOnly"):
أقوى إضافة معمارية في ووردبريس الحديث! لما تفعل
contentOnly، شريط الأدوات بالكامل (Toolbar) وشريط الخصائص الجانبي (Inspector Controls) بيختفوا تماماً، والمحرر بيتحول لشخص بيدخل داتا فقط بدون القدرة على إفساد الـ Padding أو تغيير الخطوط أو كسر التنسيقات الهندسية.
دراسة حالة واقعية: كارثة منصة عقارات التجمع وزايد مع فوضى كروت الوحدات
خلفية المشروع وأبعاد الأزمة
منصة عقارية مصرية رائدة بتعرض مشاريع سكنية في التجمع الخامس والشيخ زايد والعاصمة الإدارية. المنصة كان عندها قالب مصمم لعرض "كروت مقارنة الوحدات السكنية" في المقالات والمراجعات العقارية. التصميم كان بيتكون من كارت حاوية بيحتوي على: صورة الوحدة، اسم المطور، المساحة، السعر، وزرار تواصل عبر واتساب.
الأزمة التشخيصية (The Crisis)
فريق التحرير المكون من 15 محرر عقاري بدأوا يكتبوا المراجعات. ولأن البلوك القديم كان معمول بحاوية عادية بدون قفل قوالب أو تقييد بلوكات:
- أحد المحررين مسح زرار الواتساب بالخطأ في 70 مقال، وفقدت الشركة آلاف الاتصالات اليومية من عملاء حقيقيين.
- محرر آخر حط ويدجت "جدول أسعار" عشوائي مبني بكود خارجي جوة الكارت، مما أدى لكسر العرض في موبايلات الآيفون وخروج المحتوى خارج حدود الشاشة بنسبة 45%.
- أثناء تحديث موقع ووردبريس، ظهرت أخطاء Block Invalidation في أكثر من 1,200 مقال مراجعة عقارية، مما جعل الصفحات تظهر بمحتوى مشوه للمستخدمين في مصر والخليج.
الحل المعماري الجذري (The Architectural Solution)
قام الفريق بإعادة بناء نظام الكروت بالكامل باستخدام InnerBlocks API مع تطبيق القواعد المعمارية التالية:
- إنشاء بلوك حاوية رئيسي
realestate/property-cardيعتمد علىuseInnerBlocksPropsمع فرضtemplateLock="all"لضمان ثبات الهيكل الداخلي. - تحديد
allowedBlocksبشكل صارم جداً ليشمل فقط:realestate/property-image،realestate/property-specs، وrealestate/cta-whatsapp. - إنشاء قالب افتراضي محدد بدقة، بحيث بمجرد إدراج البلوك يظهر الهيكل المتكامل فوراً، ولا يُطلب من المحرر سوى كتابة الأرقام وتحديد صورة الوحدة.
- استخدام البلوك الديناميكي في زر الواتساب لقراءة رقم خدمة العملاء المركزي مباشرة من خيارات ووردبريس، حتى إذا تغير الرقم يتغير في كل المقالات التاريخية بلمسة واحدة.
جدول قياس مؤشرات الأداء والتحول التقني (Metrics Table)
| مؤشر الأداء البرمجي والتشغيلي | الوضع قبل تطبيق InnerBlocks المنظم | الوضع بعد هيكلة InnerBlocks الصارمة | نسبة التحسن والوفر المحقق |
|---|---|---|---|
| أخطاء التحقق وتلف الصفحات (Block Invalidation) | 34% من إجمالي مقالات المراجعات العقارية | 0% (انعدام تام للأخطاء لثبات كود الحفظ) | تحسن بنسبة 100% في سلامة البيانات |
| وقت إعداد صفحة مراجعة المشروع العقاري | 48 دقيقة للمقال الواحد بسبب ضبط المقاسات | 7 دقائق فقط (مجرد تعبئة بيانات في الهيكل) | توفير 85.4% في وقت الإنتاج التحريري |
| فقدان روابط التواصل والتحويلات (Leads Leak) | فقدان ما يقارب 120 فرصة بيع شهرياً | صفر فقدان (زر الواتساب مغلق ومبرمج مركزياً) | زيادة التحويلات بنسبة 18.2% فورياً |
| حجم كود الـ DOM في الواجهة الأمامية للمستخدم | متوسط 3,400 عقدة DOM للصفحة (DOM Clutter) | 1,120 عقدة بفضل التخلص من الـ Divs الزائدة | تقليص حجم الـ DOM بنسبة 67% وارتفاع سرعة LCP |
الأنماط المتقدمة في هندسة حاويات InnerBlocks
1. تخصيص زر إضافة البلوكات (Custom Appenders)
بشكل افتراضي، لما المحرر يوصل لآخر البلوك في واجهة التحرير، جوتنبرج بيعرض زر (+) صغير رمادي قد لا يكون واضحاً، أو قد يظهر في مكان غير مناسب للتصميم. لحسن الحظ، يوفر InnerBlocks خاصية renderAppender التي تسمح لك بتخصيص شكل ومكان وسلوك زر الإضافة:
import { InnerBlocks } from '@wordpress/block-editor';
// النمط الأول: استخدام الزر المدمج البسيط
const appenderSimple = () => ;
// النمط الثاني: استخدام الزر الافتراضي التفاعلي
const appenderDefault = () => ;
// النمط الثالث: إخفاء زر الإضافة تماماً حتى لو كان القالب مفتوحاً
const appenderHidden = () => false;2. ضبط اتجاه تخطيط الأبناء (Orientation Control)
لو أنت بتبني حاوية لقائمة تنقل (Navigation Menu) أو شريط أزرار (Button Group)، فأنت محتاج إن أسهم لوحة المفاتيح أثناء التنقل بين البلوكات تمشي يمين وشمال، مش فوق وتحت! هنا بتمرر خاصية orientation: 'horizontal' في إعدادات useInnerBlocksProps. الخاصية دي مش بس بتوجه سهولة الوصول (A11y & Keyboard Navigation)، بل بتخبر محرر جوتنبرج بتعديل خط الإدراج الأزرق (Drop Indicator) ليظهر رأسياً بين العناصر عند السحب والإفلات بدلاً من ظهوره أفقياً!
الوصايا العشر لمعمارية حاويات InnerBlocks الاحترافية
- ابدأ بـ useInnerBlocksProps دائماً: ابتعد نهائياً عن الكومبوننت القديم
<InnerBlocks />لتوفير وسوم الـ DOM ودعم CSS Grid و Flexbox بسلاسة تامة. - حدد allowedBlocks بلا تردد: لا تترك الحاوية مفتوحة لكل بلوكات ووردبريس إلا لو كنت تبني بديلاً لبلوك Group؛ الحاويات المتخصصة تحتاج حماية للمحرر والتصميم.
- احرص على تطابق save و edit: استخدامك لـ
useInnerBlocksProps.save(blockProps)يضمن أن نفس فئات التنسيق والوسوم تتطابق حرفياً بين الشاشتين وتتجنب كوابيس الـ Invalidation. - اختر templateLock المناسب لطبيعة المحتوى: استخدم
allللمكونات التسويقية الحساسة، وinsertللمحتوى المرن، وcontentOnlyإذا كان المحررون لا يملكون خبرة تصميمية. - احذر من تكرار save في الحاويات الديناميكية: في البلوكات التي تستخدم
render.php، لا تحفظ أي وسوم HTML للأبناء في الجافاسكريبت سوى<useInnerBlocksProps.Content />فقط. - لا تعتمد على الفهارس الثابتة للأبناء: الأبناء قد يتم إعادة ترتيبهم أو حذفهم؛ اجعل كل بلوك ابن يدير بياناته الخاصة دون افتراض مكانه في المصفوفة.
- استخدم orientation بحكمة: اضبط التوجيه على
horizontalللقوائم وأشرطة الأزرار لتحسين تجربة التنقل بلوحة المفاتيح والسحب والإفلات. - نظف الـ CSS من حيل الأصول القديمة: لا تكتب CSS يستهدف كلاسات جوتنبرج الداخلية مثل
.block-editor-block-list__layoutلأنها تتغير باستمرار في تحديثات النواة. - درب فريق التحرير على استخدام List View: عند التعامل مع حاويات InnerBlocks العميقة، فإن لوحة "عرض القائمة" (Document Overview / List View) في جوتنبرج هي أسهل طريقة لتحديد الحاوية الأب دون عناء النقر الدقيق.
- اختبر تحديثات النواة على بيئة تجريبية: تأكد دائماً من أن إصدارات ووردبريس الجديدة تحافظ على استقرار القوالب المحجوزة قبل الترقية على السيرفر الحي.
الأسئلة الشائعة حول InnerBlocks API (20 سؤالاً وجواباً تفصيلياً)
1. ما هو الفرق الجوهري بين <InnerBlocks /> و useInnerBlocksProps؟
الكومبوننت القديم يضيف وسم <div> إضافي داخلي يعقد تنسيقات CSS، بينما الخطاف الحديث يدمج سلوك الحاوية مع نفس عنصر الغلاف الخارجي للبلوك بدون أي وسوم وسيطة دخيلة.
2. كيف أمنع المحرر من إضافة أكثر من 3 بلوكات داخل الحاوية؟
يمكنك تعريف قالب يحتوي على 3 بلوكات مع تفعيل templateLock="insert"، مما يمنع إضافة أي عنصر رابع، أو استخدام كود جافاسكريبت يراقب عدد الأبناء ويخفي الـ Appender عند بلوغ الحد الأقصى.
3. هل يمكن استخدام InnerBlocks داخل بلوك هو نفسه ابن لـ InnerBlocks آخر؟
نعم بكل تأكيد؛ محرر جوتنبرج يدعم التداخل غير المحدود (Arbitrary Nesting Depth)، مثل وضع بلوك أكورديون متداخل داخل بلوك عمود متداخل داخل بلوك صفحة رئيسية.
4. ماذا يحدث لو تركت مصفوفة allowedBlocks فارغة أو غير محددة؟
إذا لم تحدد الخاصية، فإن الحاوية ستسمح بإدراج كافة البلوكات المسجلة في الموقع بلا أي قيود، وهو ما يماثل سلوك بلوك core/group تماماً.
5. كيف أحصل على مخرجات الـ InnerBlocks في ملف render.php؟
ووردبريس يمرر كود الـ HTML المولد لكافة الأبناء جاهزاً ومجمعاً داخل المتغير العالمي المحلي $content ليتم طباعته مباشرة في المكان المطلوب.
6. ما هو الفرق بين templateLock="all" و templateLock="contentOnly"؟
الوضع all يمنع الإضافة والحذف والترتيب لكنه يترك أشرطة أدوات البلوكات مفتوحة لتغيير التنسيقات، بينما contentOnly يقفل حتى التنسيقات والألوان ولا يسمح إلا بكتابة النصوص وتغيير الصور فقط.
7. كيف يمكنني إخفاء زر الإضافة (+) تماماً من واجهة المحرر؟
عن طريق تمرير دالة ترجع false في خاصية renderAppender: مثل renderAppender: () => false داخل خيارات useInnerBlocksProps.
8. هل يمكن تمرير خصائص مسبقة (Attributes) للبلوكات المعرفة في الـ template؟
نعم، مصفوفة الـ template تقبل كائناً ثانياً لكل بلوك، مثل: [ 'core/heading', { level: 3, content: 'العنوان الافتراضي' } ] ليتم إنشاؤه محملاً بهذه القيم مباشرة.
9. ما هو الخطأ الأكثر شيوعاً الذي يسبب كسر دالة save في InnerBlocks؟
محاولة طباعة عناصر JSX إضافية أو نصوص ثابتة داخل وسم الحاوية في دالة الحفظ دون مطابقتها حرفياً في دالة التحرير، مما ينتج عنه تضارب في وسوم الـ HTML المسجلة.
10. كيف يؤثر استخدام InnerBlocks على سرعة تحميل الموقع في الواجهة الأمامية؟
في البلوكات الثابتة، لا يوجد أي تأثير سلبي على السرعة، لأن كود الـ HTML محفوظ وجاهز في قاعدة البيانات دون الحاجة لأي معالجة PHP في وقت التشغيل.
11. هل يمكن تحديد بلوك معين ليكون هو الخيار الوحيد الذي يظهر عند الضغط على زر (+)؟
نعم، إذا وضعت اسماً واحداً فقط في مصفوفة allowedBlocks (مثل [ 'my-plugin/slide' ])، فإن الضغط على الزر سيقوم بإدراج هذا البلوك مباشرة دون فتح نافذة البحث.
12. كيف أتعامل مع مشاكل الـ CSS Grid عند استخدام InnerBlocks؟
باستخدام خطاف useInnerBlocksProps وتمرير فئات الـ Grid على نفس العنصر، مما يجعل البلوكات الأبناء هي الأبناء المباشرين لشبكة الـ Grid في الـ DOM.
13. هل يمكن استخدام Block Variations مع قوالب InnerBlocks مختلفة؟
نعم، تعتبر هذه إحدى أقوى ميزات جوتنبرج؛ حيث يمكنك تسجيل تنويعات متعددة للبلوك وكل تنويعة تملك مصفوفة innerBlocks وقالب أولي مختلف تماماً.
14. ماذا يحدث لو قام المحرر بلصق محتوى منسوخ داخل حاوية مقفولة بـ templateLock="all"؟
محرر جوتنبرج سيرفض لصق البلوكات الجديدة كأبناء وسيقوم بوضعها أسفل الحاوية بالكامل لحماية القالب من التعديل غير المصرح به.
15. كيف أتحقق برمجياً في PHP مما إذا كان البلوك يحتوي على أبناء أم لا؟
من خلال فحص المصفوفة !empty( $block->inner_blocks ) داخل ملف render.php الخاص بالحاوية.
16. هل يدعم InnerBlocks التحرير الجماعي للخصائص (Context API)؟
نعم، يمكن للبلوك الأب توفير خصائص عبر providesContext وتستقبلها كافة البلوكات المتواجدة داخل InnerBlocks عبر usesContext تلقائياً.
17. كيف أجعل اتجاه السحب والإفلات أفقياً في المحرر؟
عبر تمرير orientation: 'horizontal' في كائن إعدادات useInnerBlocksProps في ملف edit.js.
18. هل يمكن للمطور تحويل بلوك عادي قديم إلى حاوية InnerBlocks دون فقد المحتوى؟
نعم، باستخدام مصفوفة deprecated مع كتابة دالة migrate تأخذ الخصائص القديمة وتولد مصفوفة innerBlocks متوافقة مع الهيكل الجديد.
19. أين يتم تخزين البلوكات المتداخلة في بنية قاعدة بيانات ووردبريس؟
تخزن بالكامل داخل عمود post_content في جدول wp_posts محاطة بتعليقات HTML الدلالية المتداخلة، دون تخصيص جداول منفصلة للأبناء.
20. ما هي التوصية الأولى للمبرمجين عند تصميم مصفوفة template؟
اجعل القالب المبدئي يعكس أفضل الممارسات التصميمية للبلوك، وزود الحقول بنصوص توضيحية (Placeholders) ذكية لتوجيه المحرر خطوة بخطوة.
المراجع الرسمية والتوثيق المعتمد
- WordPress Developer Handbook: Nested Blocks and InnerBlocks API
- WordPress Package Reference: useInnerBlocksProps Hook Documentation
- WordPress Block API Reference: Block Templates and Locking Mechanics
- MDN Web Docs: CSS Grid Layout and DOM Tree Optimization
- Gutenberg Core Repository: InnerBlocks Component Source Code on GitHub


اترك تعليقاً
يجب أنت تكون مسجل الدخول لتضيف تعليقاً.