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

ترحيل البلوكات القديمة: معمارية Deprecation و migrate دون فقد المحتوى

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

أهلاً بيك يا صديقي المطور في أرقى وأهم مهارة هندسية بيحتاجها أي مطور ووردبريس بيبني مشاريع بتعيش لسنين طويلة: معمارية ترحيل البلوكات وتطويرها (Block Deprecation and Migration Architecture).

أي كود برمجي بتكتبه النهاردة مصيره يتغير بكرة: العميل هيطلب يضيف زرار جديد للبلوك، فريق الـ UI/UX هيقرر يغير كلاسات الـ CSS أو يستبدل وسم <div> بوسم دلالي <section>، أو حتى هتقرر تعيد تنظيم الخصائص (Attributes Schema) من نصوص عادية لكائنات معقدة. في البرمجة العادية، بتعدل الكود وخلاص؛ لكن في عالم ووردبريس ومحرر Gutenberg، التعديل ده لو اتعمل بشكل عشوائي ومباشر بيعني “انتحار برمجي” فوري! ليه؟ لإن آلاف المقالات اللي اتنشرت بالبنية القديمة هتضرب فوراً وتطلع رسالة الخطأ الكارثية Block Validation Error.

الحل العبقري اللي وفرته نواة ووردبريس هو مصفوفة deprecated ودالة migrate(). المنظومة دي بتمكنك من تطوير البلوك لـ 10 أجيال مختلفة (v1, v2, v3… إلخ) بدون ما تكسر مقال قديم واحد، مع ترقية المحتوى القديم للهيكل الجديد تلقائياً في صمت تام وبدون أدنى تدخل بشري. في الدليل الشامل ده، هنفكك المعمارية التحتية للـ Deprecation، إزاي تبني دوال الترحيل، إزاي تستخدم isEligible() لمنع تداخل الإصدارات، ودراسة حالة حقيقية لشبكة إخبارية مصرية عملاقة بالعامية المصرية التقنية الأصيلة.

المعيار المعماريالتعديل المباشر في الكود (In-place Mutation)معمارية Deprecation & migrateسكربتات SQL في قاعدة البياناتالتحويل لبلوك ديناميكي (Dynamic SSR)
سلامة المقالات التاريخية القديمةكارثية؛ تكسر كافة المقالات القديمة بـ Block Validation Error.آمنة بنسبة 100%؛ المقالات القديمة تفتح بسلاسة ودون أخطاء.خطيرة للغاية؛ أي خطأ في الـ Regex يتلف المقالات بالكامل.آمنة؛ تلغي المقارنة النصية وتحيل العرض للسيرفر.
تجربة المحرر وكاتب المحتوىمربكة ومخيفة؛ ظهور رايات صفراء تطلب استعادة البلوك قسراً.شفافة وغير مرئية تماماً؛ المحرر لا يشعر بأي تغيير هندسي.لا يشعر بشيء إذا نجح السكربت، أو يجد محتواه مشوهاً إذا فشل.طبيعية بالكامل؛ يرى نفس الواجهة بلا أي تحذيرات.
ترقية البيانات للخصائص الجديدةمستحيلة؛ البيانات القديمة تظل عالقة بالهيكل القديم.تلقائية؛ دالة migrate() تحول الخصائص القديمة للجديدة فوراً.تتطلب كتابة استعلامات SQL معقدة لفك وتركيب JSON التعليقات.تعتمد على كود PHP السيرفري للتحقق من القيم القديمة.
دعم الإصدارات المتعددة (v1, v2, v3)لا يدعم سوى إصدار واحد فقط هو الإصدار الحالي المكتوب.يدعم شجرة أجيال غير محدودة تترقى بالتتابع بسلاسة.مستحيل تتبع الأجيال بدقة بدون جداول إضافية لسجل التغييرات.يتم التعامل مع الفروق عبر شروط if-else داخل render.php.
الجهد الهندسي المطلوب للتطبيقصفر في البداية، ولكنه يكلف مئات الساعات في إصلاح الكوارث لاحقاً.جهد هندسي منضبط ودقيق بنسخ كود الحفظ القديم لمصفوفة الإلغاء.جهد عالي جداً واختبارات معقدة على نسخ احتياطية ضخمة.إعادة بناء البلوك وجعل دالة save ترجع null.

كيف تفكر نواة ووردبريس؟ دورة حياة ترحيل البلوكات (The Migration Cascade)

عشان تكتب كود ترحيل مظبوط، لازم تفهم الخوارزمية اللي محرر جوتنبرج بيمشي عليها لما يفتح أي مقال في لوحة التحكم:

  1. فحص الكود الحالي أولاً:

    جوتنبرج بياخد محتوى البلوك المحفوظ في قاعدة البيانات، ويقارنه بدالة save() الحالية (النسخة الأحدث وليكن v3). لو متطابق، بيفتح البلوك ومبيعملش أي حاجة تانية.

  2. تنشيط مصفوفة الترحيل (The Deprecation Array Loop):

    لو حصل عدم تطابق، المحرر مبيطلعش خطأ فوراً! بيبص على مصفوفة deprecated. المصفوفة دي بتكون مترتبة زمنياً من الأحدث للأقدم (v2 ثم v1). بيبدأ يمسك أول عنصر في المصفوفة ويجرب يطابق كود الـ HTML المحفوظ مع دالة save() القديمة الخاصة بالنسخة دي.

  3. التحقق الذكي عبر isEligible():

    لو وفرت دالة isEligible( attributes, innerBlocks )، جوتنبرج بيشغلها الأول؛ لو رجعت true بيكمل الفحص، لو رجعت false بيتجاوز النسخة دي فوراً ويروح للي بعدها، وده بيمنع أي تطابق خاطئ بين نسخ متقاربة.

  4. تنفيذ السحر: دالة migrate():

    أول ما يلاقي النسخة القديمة المطابقة (مثلاً لقى المقال ده مكتوب بنسخة v1)، بيشغل فوراً دالة migrate( attributes, innerBlocks ) المعرفة في نفس كائن الـ Deprecation. الدالة دي وظيفتها تحول الخصائص القديمة للخصائص الجديدة للنسخة الأحدث (v3).

  5. الترقية الصامتة والحفظ (Silent In-Memory Upgrade):

    البلوك بيفتح قدام الكاتب في المحرر وهو محدث للنسخة v3 بدون أي رسائل تحذير أو أزرار Recover! وأول ما الكاتب يضغط “تحديث المقال” (Update)، ووردبريس بيحفظ البلوك في قاعدة البيانات بالهيكل الجديد v3 للأبد، وبكده تمت عملية الترقية بسلام تام!

تطبيق عملي كامل: ترحيل بلوك بطاقة الخدمات عبر 3 أجيال (v1 -> v2 -> v3)

تعال نبني مثالاً إنتاجياً حقيقياً لبلوك كارت تسويقي (enterprise/service-card) مر بثلاث مراحل تطوير على مدار عامين في إحدى الشركات:

  • الجيل الأول (v1): كارت بسيط فيه عنوان ونص فقط، بدون أزرار أو ألوان.
  • الجيل الثاني (v2): تمت إضافة زر رابط (CTA Button) مع تغيير كلاس الـ Wrapper.
  • الجيل الثالث (v3 – الحالي): تم تحويل البلوك لحاوية تدعم أيقونة مخصصة وتنسيقات ألوان حديثة مع دمج الخصائص داخل كائن منظم.

1. ملف تعريف البلوك الحديث: block.json (الإصدار الحالي v3)

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "enterprise/service-card",
  "version": "3.0.0",
  "title": "بطاقة الخدمة المتقدمة",
  "category": "design",
  "icon": "star-filled",
  "attributes": {
    "title": {
      "type": "string",
      "default": ""
    },
    "description": {
      "type": "string",
      "default": ""
    },
    "buttonData": {
      "type": "object",
      "default": {
        "text": "اكتشف المزيد",
        "url": "#",
        "target": "_self"
      }
    },
    "cardTheme": {
      "type": "string",
      "default": "primary"
    }
  },
  "editorScript": "file:./index.js",
  "style": "file:./style-index.css"
}

2. كود الحفظ الحالي: save.js (الجيل الثالث v3)

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

export default function save( { attributes } ) {
    const { title, description, buttonData, cardTheme } = attributes;
    const blockProps = useBlockProps.save( {
        className: `az-service-card az-theme-${ cardTheme } az-version-3`
    } );

    return (
        
{ buttonData?.url && ( ) }
); }

3. ملف الترحيل الشامل: deprecated.js (تاريخ الأجيال السابقة)

/**
 * ملف deprecated.js: يحتوي على سجل التغييرات التاريخية للبلوك
 * يتم سرد الإصدارات القديمة من الأحدث إلى الأقدم
 */
import { useBlockProps, RichText } from '@wordpress/block-editor';

const deprecated = [
    // ==========================================
    // الجيل الثاني (v2): كان يحتوي على زر منفصل كخاصيتين buttonText و buttonUrl
    // وكان يستخدم وسم div بدلاً من section
    // ==========================================
    {
        attributes: {
            title: { type: 'string', default: '' },
            description: { type: 'string', default: '' },
            buttonText: { type: 'string', default: 'المزيد' },
            buttonUrl: { type: 'string', default: '#' },
        },
        // فحص هل البلوك ينتمي لهذا الجيل (يمتلك buttonUrl كخاصية نصية منفصلة)
        isEligible( attributes ) {
            return typeof attributes.buttonUrl === 'string' && ! attributes.buttonData;
        },
        // دالة الترحيل: تحويل buttonText و buttonUrl إلى كائن buttonData المنظم
        migrate( attributes ) {
            return {
                title: attributes.title,
                description: attributes.description,
                cardTheme: 'primary', // القيمة الافتراضية للخاصية الجديدة في v3
                buttonData: {
                    text: attributes.buttonText || 'اكتشف المزيد',
                    url: attributes.buttonUrl || '#',
                    target: '_self',
                },
            };
        },
        // كود الـ HTML كما كان يُحفظ بالضبط في إصدار v2
        save( { attributes } ) {
            const { title, description, buttonText, buttonUrl } = attributes;
            const blockProps = useBlockProps.save( {
                className: 'az-service-card az-version-2'
            } );

            return (
                
{ buttonUrl && ( ) }
); }, }, // ========================================== // الجيل الأول (v1): البلوك البدائي خالص بدون أي أزرار وبكلاسات قديمة // ========================================== { attributes: { title: { type: 'string', default: '' }, description: { type: 'string', default: '' }, }, isEligible( attributes ) { // مؤهل إذا لم يكن لديه كائن buttonData ولم يكن لديه خاصية buttonUrl return ! attributes.buttonData && typeof attributes.buttonUrl === 'undefined'; }, migrate( attributes ) { return { title: attributes.title, description: attributes.description, cardTheme: 'primary', buttonData: { text: 'اكتشف المزيد', url: '#', target: '_self', }, }; }, save( { attributes } ) { const { title, description } = attributes; return (

{ title }

{ description }

); }, }, ]; export default deprecated;

4. ملف تسجيل البلوك الرئيسي: index.js

import { registerBlockType } from '@wordpress/blocks';
import metadata from './block.json';
import edit from './edit';
import save from './save';
import deprecated from './deprecated';
import './style.scss';

registerBlockType( metadata.name, {
    edit,
    save,
    deprecated, // هنا يتم تمرير مصفوفة الترحيل التاريخية للنواة
} );

تحليل أسرار كود الترحيل:

  • isEligible(): هذه الدالة تحميك من الكوارث! لو كان عندك إصدار قديم وإصدار أقدم، جوتنبرج قد يخلط بينهم لو تشابه كود الـ HTML؛ لكن مع isEligible أنت تضع شرطاً منطقياً يفحص تركيبة الـ attributes القديمة بدقة حاسوبية.
  • migrate(): تأخذ الخصائص القديمة (مثل buttonText و buttonUrl) وتعيد كائناً جديداً تماماً متطابقاً مع مخطط الخصائص (Schema) للإصدار الحديث v3، مع توفير قيم افتراضية ذكية لأي حقول جديدة لم تكن موجودة في المقالات القديمة.

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

خلفية المشروع وأبعاد الأزمة

مؤسسة صحفية وإعلامية مصرية كبرى تمتلك بوابة إخبارية أرشيفها يمتد لأكثر من 14 عاماً (يحتوي على أكثر من 380,000 خبر ومقال صحفي). الموقع يعتمد على محرر Gutenberg منذ 2019، وكان الصحفيون يستخدمون بلوكاً مخصصاً باسم “صندوق الخبر العاجل والتنويه الصحفي” (Editorial Callout Alert) لتوثيق المصادر والبيانات الرسمية داخل آلاف المقالات.

الأزمة التشخيصية (The Crisis)

أرادت إدارة التحرير تحسين تجربة القراءة وتجديد هوية الموقع، فطلبت من فريق التطوير تغيير شكل الصندوق: تحويل لون الخلفية، إضافة أيقونة تنبيه، وتغيير وسم العنوان من <h4> إلى <strong> لضبط هرمية السيو (SEO Heading Hierarchy):

  • قام المطور المسؤول بتعديل ملف save.js مباشرة، ورفع الكود للسيرفر الحي دون كتابة أي سطر في مصفوفة deprecated!
  • في صباح اليوم التالي، دخل ديسك التحرير المكون من 60 صحفياً لتعديل أخبار قديمة وتحديث تقارير متابعة، فتفاجأوا بأن أكثر من 42,000 مقال تاريخي يظهر فيها شريط الخطأ الأصفر: “This block contains unexpected or invalid content”!
  • أحد المحررين المتدربين بدأ يضغط على زر “Attempt Block Recovery” في مقالات تحقيقات استقصائية حساسة، مما تسبب في مسح روابط التوثيق المرفقة في الصندوق وتحويلها لنصوص ميتة في 350 مقالاً خلال ساعة واحدة!
  • أصيبت صالة التحرير بحالة ذعر شامل، وتوقفت عمليات التحرير بالكامل، وتم استدعاء الفريق الهندسي في اجتماع طوارئ عاجل.

الحل المعماري الجذري (The Architectural Solution)

قام الفريق المعماري باتخاذ الإجراءات الهندسية الفورية لإنقاذ الأرشيف:

  1. سحب النسخة السابقة من كود الـ Save القديم من مستودع Git، وعزلها بالكامل في كائن مستقل داخل ملف deprecated.js.
  2. كتابة دالة isEligible() تفحص كود الـ HTML القديم الذي يحتوي على وسم <h4>.
  3. كتابة دالة migrate() تقوم بسحب نص العنوان القديم وتمريره للخاصية الجديدة مع ضبط كلاسات التصميم المحدثة تلقائياً.
  4. رفع الإصلاح الهندسي؛ وبمجرد أن يفتح أي صحفي مقالاً من الـ 42,000 مقال القديمة، يتعرف جوتنبرج على النسخة القديمة ويقوم بترقيتها إلى التصميم الجديد في صمت تام دون إظهار أي رسالة خطأ، وبمجرد حفظ التعديل يتم تخزين الهيكل الجديد في قاعدة البيانات!

جدول قياس مؤشرات الأداء وحماية الأرشيف الصحفي (Metrics Table)

مؤشر الأداء والنزاهة الأرشيفيةأثناء الأزمة (التعديل المباشر المتهور)بعد نشر معمارية Deprecation السليمةالأثر المتحقق والقيمة الهندسية
المقالات المصابة بالتلف والتعطل42,150 مقالاً صحفياً معطلاًصفر مقالات (استقرار تام بنسبة 100%)إنقاذ كامل للأرشيف التاريخي للبوابة
معدل الشكاوى وتوقف صالة التحريرشلل تام في النشر لمدة 4 ساعاتعودة النشر الفوري بطاقته الكاملةاستعادة ثقة فريق التحرير والصحفيين
فقدان المحتوى بسبب Recovery الخاطئ350 مقالاً استقصائياً فقدت روابط التوثيقصفر فقدان (استعادة النسخ بالـ Revisions)حماية حقوق الملكية والتوثيق الصحفي
وقت إنجاز الترحيل الهندسي الآمنمحاولات ترقيع عشوائية فاشلة35 دقيقة فقط لكتابة الـ Deprecation وتعميمهوفر زمني ومالي ضخم على المؤسسة

الوصايا العشر لترحيل وتحديث بلوكات جوتنبرج بدون كسر التوافق

  1. لا تعدل save() مباشرة في بلوك منشور: اعتبر أي كود تم دفعه للإنتاج عقداً مقدساً لا يجوز تغييره إلا بإنشاء نسخة ترحيل في deprecated.
  2. انسخ كود save القديم كما هو حرفياً: لا تحاول تحسين أو تنظيف كود الـ Save في ملف الإلغاء؛ انقله بمسافاته وكلاساته القديمة لضمان التطابق الحرفي.
  3. استخدم isEligible لتفادي الخلط بين الأجيال: ضع شروطاً تفحص الخصائص القديمة لضمان عدم تنفيذ ترحيل خاطئ على بلوك من إصدار مختلف.
  4. رتب مصفوفة deprecated من الأحدث للأقدم: جوتنبرج يفحص العناصر بالترتيب؛ ضع الإصدار الأحدث أولاً لتسريع خوارزمية الفحص وتجنب فحص الأجيال السحيقة أولاً.
  5. وفر قيماً افتراضية ذكية في migrate(): عند إضافة خصائص جديدة، اجعل دالة الترحيل تضع قيماً افتراضية منطقية تحاكي مظهر البلوك القديم.
  6. اختبر الترحيل على مقال حقيقي منشور قديماً: لا تعتمد على إنشاء مقال جديد لاختبار الترحيل؛ افتح مقالاً قديماً من قاعدة البيانات الحقيقية وتأكد من عدم ظهور تحذيرات.
  7. احفظ ملف deprecated كأرشيف تاريخي دائم: لا تحذف الإصدارات القديمة من ملف deprecated.js حتى لو مر عليها سنوات، طالما أن هناك مقالات قديمة لا تزال تستخدمها.
  8. ادعم ترحيل البلوكات المتداخلة (InnerBlocks): دالة migrate(attributes, innerBlocks) تستقبل الأبناء ويمكنها إعادة هيكلة أو حذف أو إضافة أبناء جدد برمجياً!
  9. احذر من تضارب الـ Supports في الإصدارات القديمة: إذا قمت بتغيير إعدادات supports (مثل إيقاف الألوان)، تأكد من نقلها لكائن الـ Deprecation القديم.
  10. اكتب اختبارات آلية لكل نسخة ترحيل: احتفظ بنماذج HTML لكل إصدار قديم في اختبارات Jest لضمان أن التحديثات المستقبلية لن تكسر أي جيل سابق.

معمارية ترحيل البلوكات المتداخلة وإعادة هيكلة الشجرة (Complex InnerBlocks Migration)

يا صديقي المطور، من أصعب التحديات المعمارية في ووردبريس هو لما تقرر تحول بلوك كان في الأصل “بلوك فردي بسيط” (Flat Single Block) إلى “حاوية متداخلة” (Container with InnerBlocks)، أو لما تقرر تعيد هيكلة الأبناء الداخليين (مثلاً تحول قائمة نصوص عادية إلى مجموعة بلوكات فرعية منفصلة). كيف تتعامل دالة migrate() مع هذه الحالة المعقدة؟

دالة migrate في مواصفات Gutenberg المتقدمة لا تقتصر على إرجاع كائن الخصائص الجديد فقط، بل يمكنها إرجاع مصفوفة ثنائية القيمة تحتوي على: [ newAttributes, newInnerBlocks ].

كود عملي متكامل: تحويل النصوص المحفوظة إلى بلوكات أطفال حقيقية

/**
 * مثال احترافي لدالة migrate تقوم بإنشاء وتوليد بلوكات InnerBlocks حقيقية
 * أثناء ترحيل المحتوى القديم للجيل الثالث
 */
import { createBlock } from '@wordpress/blocks';

const complexInnerBlocksDeprecation = {
    attributes: {
        rawItemsText: {
            type: 'string',
            default: '', // كان المحتوى القديم يُحفظ كنص مفصول بأسطر جديدة
        },
        sectionHeading: {
            type: 'string',
            default: '',
        },
    },
    isEligible( attributes ) {
        return typeof attributes.rawItemsText === 'string' && attributes.rawItemsText.length > 0;
    },
    migrate( attributes, innerBlocks ) {
        // 1. استخراج الأسطر القديمة وتحويلها لمصفوفة عناصر
        const lines = attributes.rawItemsText.split( 'n' ).filter( ( line ) => line.trim() !== '' );

        // 2. استخدام دالة createBlock الرسمية لإنشاء بلوكات أطفال جديدة في الشجرة
        const migratedChildren = lines.map( ( lineText ) => {
            return createBlock( 'enterprise/feature-item', {
                itemTitle: lineText.trim(),
                isCompleted: false,
            } );
        } );

        // 3. إرجاع مصفوفة تحتوي على: الخصائص الجديدة المصفاة، ومصفوفة البلوكات الأبناء المحدثة!
        return [
            {
                heading: attributes.sectionHeading || 'قائمة المميزات المطورة',
                // حذف الخاصية القديمة rawItemsText لعدم الحاجة إليها
            },
            migratedChildren, // سيتم حقن هؤلاء الأطفال تلقائياً داخل InnerBlocks الحاوية!
        ];
    },
    save( { attributes } ) {
        return (
            

{ attributes.sectionHeading }

{ attributes.rawItemsText }
); }, };

القوة الهندسية لهذا الأسلوب:
المحرر لما يفتح المقال، سيجد أن النص القديم الجاف قد تحول فورياً وداخلياً إلى بلوكات تفاعلية مستقلة يمكنه سحبها، إعادة ترتيبها، وتلوينها بخصائص الجيل الجديد، دون أن يضطر لنقل كلمة واحدة يدوياً!

الترحيل الشامل المباشر في قاعدة البيانات عبر WP-CLI (Bulk Database Migration)

على الرغم من أن معمارية deprecated تحمي موقعك وتجعل الترقية تتم “عند الطلب” (On-demand) عندما يفتح المحرر كل مقال، إلا أن المؤسسات الإعلامية الضخمة التي تمتلك 200,000 مقال قد ترغب في ترقية الأرشيف بالكامل في قاعدة البيانات دفعة واحدة دون انتظار فتح المقالات يدوياً على مدار سنوات.

أفضل ممارسة لتنفيذ الترحيل الجماعي:

  1. تجنب استعلامات SQL المباشرة: إياك وكتابة UPDATE wp_posts SET post_content = REPLACE(...)؛ لأنك ستتجاهل فك وتركيب كائنات الـ JSON وتدمر شجرة البلوكات.
  2. استخدام أمر مخصص في WP-CLI: قم ببناء أمر CLI يستدعي دالة النواة do_blocks() أو يقوم بقراءة المقال عبر parse_blocks()، ويمرر كل بلوك على دوال التحقق والترقية، ثم يعيد تسلسل المحتوى بـ serialize_blocks() ويحفظ المقال عبر wp_update_post().
<?php
/**
 * سكربت WP-CLI مخصص لترقية البلوكات التاريخية في صمت
 * Usage: wp az migrate-blocks --post_type=post
 */
if ( defined( 'WP_CLI' ) && WP_CLI ) {
    WP_CLI::add_command( 'az migrate-blocks', function( $args, $assoc_args ) {
        $posts = get_posts([
            'post_type'      => 'post',
            'posts_per_page' => -1,
            'post_status'    => 'publish',
        ]);

        WP_CLI::line( sprintf( 'تم العثور على %d مقال، جاري فحص وترقية البلوكات...', count( $posts ) ) );

        $updated_count = 0;
        foreach ( $posts as $post ) {
            $parsed_blocks = parse_blocks( $post->post_content );
            $modified      = false;

            // فحص ومعالجة شجرة البلوكات وترقيتها برمجياً...
            // عند اكتشاف بلوك قديم يتم تعديل خصائصه لهيكل v3
            
            if ( $modified ) {
                $new_content = serialize_blocks( $parsed_blocks );
                wp_update_post([
                    'ID'           => $post->ID,
                    'post_content' => $new_content,
                ]);
                $updated_count++;
            }
        }

        WP_CLI::success( sprintf( 'اكتمل الترحيل بنجاح! تم تحديث %d مقال في قاعدة البيانات.', $updated_count ) );
    } );
}
?>

هذا التكامل بين معمارية deprecated داخل محرر المتصفح، وسكربتات WP-CLI على مستوى السيرفر، يمنحك السيطرة الهندسية المطلقة على دورة حياة المحتوى، ويضمن أن موقعك يواكب أحدث المعايير البرمجية لعقود قادمة بثبات وسلاسة تامة.

الأسئلة الشائعة حول معمارية Deprecation والترحيل في جوتنبرج (20 سؤالاً وجواباً تفصيلياً)

1. ما هي مصفوفة deprecated في ووردبريس؟

هي مصفوفة من الكائنات البرمجية يتم تمريرها لدالة registerBlockType، يحتوي كل كائن منها على تعريف لنسخة قديمة من البلوك (خصائصها، دالة حفظها، ودالة ترحيلها) للحفاظ على التوافق مع المقالات السابقة.

2. متى أكون مضطراً لكتابة كائن Deprecation جديد؟

في كل مرة تقوم فيها بتغيير وسوم الـ HTML، أو فئات الـ CSS، أو بنية الخصائص (Attributes) داخل دالة save() لبلوك منشور بالفعل ومستخدم في مقالات حقيقية على الموقع.

3. ما هي وظيفة دالة migrate() بالتحديد؟

تأخذ الخصائص (وأحياناً الأبناء) من النسخة القديمة الملغاة، وتقوم بإعادة تشكيلها وتعيين قيم افتراضية جديدة لتتوافق مع مخطط الخصائص الحالي للبلوك الحديث.

4. هل يحتاج كاتب المحتوى للضغط على أي زر لترقية البلوك عند استخدام Deprecation؟

لا على الإطلاق؛ عملية الترقية تتم آلياً في صمت وبشكل فوري داخل الذاكرة بمجرد فتح المقال، وتُحفظ رسمياً في قاعدة البيانات عند الضغط على زر “تحديث” (Update).

5. ما الفارق بين isEligible() والمطابقة التلقائية لكود الـ HTML؟

المطابقة التلقائية تقارن كود الـ HTML فقط، بينما isEligible() تسمح لك بفحص شروط منطقية مخصصة على الخصائص (Attributes) قبل بدء عملية مقارنة الـ HTML لتفادي التضارب بين الإصدارات المتقاربة.

6. كيف أرتب الإصدارات داخل مصفوفة deprecated؟

القاعدة القياسية المعتمدة في نواة ووردبريس هي الترتيب الزمني العكسي: من الأحدث إلى الأقدم (v3 ثم v2 ثم v1).

7. هل يمكن لدالة migrate() ترحيل البلوكات المتداخلة (InnerBlocks)؟

نعم، دالة migrate(attributes, innerBlocks) تستقبل مصفوفة الأبناء، ويمكنك إعادة ترتيبهم، حذف بعضهم، أو تغيير خصائصهم برمجياً، ثم إرجاع [ newAttributes, newInnerBlocks ].

8. ماذا يحدث إذا قمت بحذف ملف deprecated.js من الكود؟

أي مقال محفوظ بالإصدارات القديمة سيصاب فوراً بخطأ Block Validation Error عند فتحه في المحرر مجدداً؛ لذا يجب الاحتفاظ بسجل الترحيل دائماً.

9. هل تؤثر مصفوفة deprecated على سرعة تحميل الموقع في الواجهة الأمامية؟

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

10. هل أحتاج لكتابة Deprecation لو كنت أستخدم بلوكاً ديناميكياً (render.php)؟

إذا كانت دالة save ترجع null وتغيرت طريقة العرض في الـ PHP فقط، فلن تحتاج لـ Deprecation. ولكن إذا قمت بتغيير أسماء الـ Attributes في block.json، فستحتاج لـ Deprecation لترحيل الخصائص القديمة.

11. كيف أختبر أن دالة migrate() تعمل بنجاح قبل رفع الكود؟

عن طريق جلب كود مقال قديم من قاعدة البيانات ووضعه في بيئة اختبار، وفتحه في المحرر للتأكد من عدم ظهور تحذيرات، وفحص أن كائن الخصائص في الكونسول أصبح مطابقاً للهيكل الجديد.

12. هل يمكن تحويل اسم البلوك بالكامل (Block Name) عبر Deprecation؟

لا، الـ Deprecation يعمل داخل نفس اسم البلوك؛ لتحويل بلوك من اسم لآخر بالكامل، تحتاج لاستخدام Block Transforms (التحويلات) أو خطافات الـ Raw Transformation.

13. ماذا يحدث لو تطابق كود مقال مع نسختين مختلفتين في deprecated؟

جوتنبرج سيختار النسخة الأولى التي يصادفها في المصفوفة؛ لهذا السبب يجب كتابة دالة isEligible() بدقة لعزل الشروط ومنع التطابقات المتداخلة.

14. هل يمكن إضافة خاصية supports مختلفة في كائن Deprecation؟

نعم، إذا كان الإصدار القديم يدعم خاصية معينة (مثل align: true) وتم إلغاؤها في الإصدار الحديث، يجب تعريف ذلك داخل كائن الـ Deprecation القديم.

15. كم عدد الإصدارات القديمة التي يمكن وضعها في مصفوفة deprecated؟

لا يوجد حد أقصى؛ يمكنك وضع عشرات الإصدارات التاريخية، فبلوكات ووردبريس الأساسية (مثل Paragraph و Columns) تحتوي على سجلات ترحيل تمتد لأكثر من 8 إصدارات سابقة.

16. لماذا يُنصح بنسخ كود save القديم كما هو دون أدنى تعديل؟

لأن ووردبريس يقارن النصوص حرفياً بمطابقة صارمة؛ أي تعديل في المسافات أو أسماء المتغيرات قد يمنع خوارزمية النواة من التعرف على النسخة القديمة.

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

يمكن لدالة migrate() قراءة كود اللون القديم وتحويله لرمز المتغير الجديد في theme.json أو الكلاس المحدث بسلاسة.

18. هل يتم تنفيذ دالة migrate() إذا كان كود المقال مطابقاً للإصدار الحالي؟

لا؛ ووردبريس يتوقف فوراً إذا تطابق المقال مع كود الـ Save الحالي، ولا يقوم باستدعاء دالة الترحيل إلا عند فشل التحقق الأولي.

19. كيف يمكنني كتابة اختبارات Jest لفحص دوال migrate()؟

باستدعاء دالة migrate مباشرة في بيئة الاختبار وتمرير خصائص قديمة وفحص أن الكائن المرتجع يحتوي على الخصائص الجديدة بالقيم المتوقعة بدقة.

20. ما هي القاعدة الذهبية لإدارة دورة حياة البلوكات للمطورين الكبار؟

“كود الأمس هو تاريخ يجب احترامه بالـ Deprecation، وكود اليوم هو الحاضر، ودالة migrate هي الجسر الآمن الذي ينقل موقعك للمستقبل دون فقدان نقطة حبر واحدة من مقالاتك”.

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

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

WordPress Architect & Enterprise Consultant

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


رد واحد على “ترحيل البلوكات القديمة: معمارية Deprecation و migrate دون فقد المحتوى”

  1. […] السابق: ترحيل البلوكات القديمة […]

اترك تعليقاً