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

شرح خطاف تفعيل الإضافات register_activation_hook في ووردبريس: تهيئة قواعد البيانات وتحديث الروابط والأخطاء القاتلة

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

أهلاً بيك في المقال رقم 36 من 100 في سلسلتنا المعمارية الشاملة معمارية ووردبريس من الأساسيات إلى الاحتراف الكامل، ضمن المستوى الرابع: معمارية الإضافات (Plugin Architecture). النهاردة هنشرح المحطة الأولى في ولادة أي إضافة على السيرفر: خطاف تفعيل الإضافات (register_activation_hook)، وهندسة تهيئة قواعد البيانات بـ dbDelta، وتحديث الروابط الدائمة، والتعامل مع الشبكات المتعددة (Multisite)، وتجنب أخطاء الإخراج المفاجئ بالعامية المصرية.

لو سألت أي مبرمج مبتدئ: “إيه اللي بيحصل لما العميل يضغط على زرار ‘تفعيل’ (Activate) في لوحة تحكم ووردبريس؟”، هيقولك: “ووردبريس بيشغل الإضافة وخلاص!”. لكن كمهندس برمجيات ووردبريس محترف، أنت عارف إن لحظة التفعيل هي لحظة تأسيس البنية التحتية (Bootstrap Lifecycle Event). في الجزء من الثانية ده، الإضافة بتاعتك لازم تفحص بيئة الخادم، وتنشئ جداول MySQL المخصصة، وتزرع الإعدادات الافتراضية، وتضبط الأدوار والصلاحيات، وتحدث قواعد التوجيه (Rewrite Rules) في قاعدة البيانات. أي سطر كود مكتوب باستهتار أو أي مسافة فارغة تعمل Echo، هتخلي ووردبريس يرمي الخطأ الشهير: The plugin generated unexpected output during activation ويرفض التفعيل! في المقال ده، هنشرح المعمارية العميقة لخطاف التفعيل، وإزاي تبني سكريبت تفعيل مؤسسي لا ينكسر تحت أي ظرف.

المعمارية التحتية: ماذا يحدث في كواليس السيرفر عند ضغط زر “تفعيل”؟

عندما يضغط المدير على رابط التفعيل في صفحة wp-admin/plugins.php، يرسل المتصفح طلباً يحمل توكن أمان (Nonce) واسم الإضافة. عند هذه اللحظة، ينفذ ووردبريس الخطوات الهندسية التالية:

  1. تشغيل ميزة التقاط المخرجات (Output Buffering): يستدعي ووردبريس دالة ob_start(). أي كود داخل إضافتك يقوم بطباعة نص، أو مسافة فارغة (Whitespace) قبل وسم <?php، أو يرمي تحذير PHP Warning، يتم التقاطه في الذاكرة. إذا وجد ووردبريس أي بايت واحد مطبوع، يقوم بإلغاء التفعيل فوراً ويرمي خطأ Unexpected Output الشهير!
  2. إطلاق خطاف activate_{$plugin}: تستدعي النواة الدالة المسجلة عبر register_activation_hook(__FILE__, 'callback') في بيئة معزولة.
  3. إضافة الإضافة إلى مصفوفة active_plugins: بعد نجاح الدالة بدون أخطاء، يتم تحديث خيار active_plugins في جدول wp_options لإضافة مسار الإضافة.
  4. تفريغ الكاش وإعادة التوجيه: يتم تفريغ كاش الكائنات وإعادة توجيه المتصفح إلى plugins.php?activate=true مع إظهار رسالة النجاح الخضراء “تم تفعيل الإضافة بنجاح”.

المهام المعمارية الأساسية التي يجب تنفيذها أثناء التفعيل

خطاف التفعيل هو الفرصة الذهبية لتنفيذ العمليات الثقيلة لمرة واحدة فقط (Run-Once Operations) حتى لا ترهق الموقع في كل زيارة:

1. إنشاء وترقية جداول MySQL المخصصة عبر dbDelta

إذا كانت إضافتك تحتاج لجداول SQL مخصصة (مثلاً جدول سجلات مالية أو تتبع لوجستي)، لا تستخدم استعلام CREATE TABLE المباشر أبداً! النواة توفر دالة معمارية عبقرية اسمها dbDelta() في ملف wp-admin/includes/upgrade.php.
هذه الدالة تفحص هيكل الجدول الحالي في قاعدة البيانات وتقارنه بالاستعلام الممرر؛ فإذا لم يكن الجدول موجوداً تنشئه، وإذا كان موجوداً ولكنك أضفت عموداً جديداً أو عدلت فهرساً، تقوم بتعديل الجدول تلقائياً دون مسح بيانات العميل القديمة!

قواعد التنسيق الصارمة لدالة dbDelta (تجاهلها يفشل الاستعلام فوراً):

  • يجب وضع كل حقل في سطر منفصل مستقل.
  • يجب وضع كلمتي PRIMARY KEY في سطر منفصل متبوعتين بـ مسافتين كاملتين (Two Spaces) قبل القوسين، هكذا: PRIMARY KEY (id)!
  • يجب استخدام كلمة KEY بدلاً من INDEX لتعريف الفهارس الثانوية، مع مسافتين أيضاً.
  • يجب كتابة الكلمات المحجوزة في SQL بحروف كبيرة (Uppercase) وأنواع البيانات بحروف صغيرة.

2. تسجيل أنواع المحتوى وتحديث الروابط الدائمة (Rewrite Rules)

إذا كانت إضافتك تسجل CPTs أو Taxonomies، فالمستخدم سيتلقى خطأ 404 Not Found فور التفعيل إذا لم يتم تجديد قواعد التوجيه. الترتيب المعماري الإلزامي هو:

  1. استدعاء دالة تسجيل الـ CPT والـ Taxonomy أولاً في نفس دالة التفعيل ليتعرف عليها ووردبريس في الذاكرة.
  2. استدعاء دالة flush_rewrite_rules(false) مرة واحدة فقط لتحديث جدول الخيارات.

3. جدولة مهام الكرون وتسجيل الأدوار المخصصة

  • الأدوار: استدعاء add_role() لإضافة رتب النظام المخصصة (مثل “وسيط عقاري” أو “محاسب”).
  • الكرون: فحص ما إذا كان الحدث مجدولاً بـ wp_next_scheduled()، ثم جدولته بـ wp_schedule_event().

الأخطاء القاتلة أثناء التفعيل وكيفية تجنبها

هناك أربعة أخطاء تسقط كبار المطورين في فخاخ الإخراج غير المتوقع والانهيار:

  1. طباعة النصوص أو المسافات (Output Printing): كتابة echo أو var_dump أو ترك مسافة فارغة بعد إغلاق وسم ?> في أي ملف مضمن. الحل: لا تغلق وسم PHP نهائياً في نهاية ملفات الإضافة!
  2. تنفيذ مهام هجرة بيانات ضخمة بشكل متزامن: إذا كان لديك 50,000 سجل يحتاج للمعالجة، فتنفيذها داخل خطاف التفعيل سيجعل السيرفر يصل لحد max_execution_time (30 ثانية) ويسقط في منتصف الطريق تاركاً قاعدة البيانات معطوبة! الحل هو جدولة الهجرة في الخلفية عبر Action Scheduler أو WP-Cron.
  3. تحديث الروابط قبل تسجيل الكيانات: استدعاء flush_rewrite_rules() قبل register_post_type() يجعل التحديث عديم الفائدة لأن النواة لا تعلم بوجود المسار الجديد بعد.
  4. تجاهل فحص متطلبات بيئة الخادم (Environment Pre-flight Check): محاولة تفعيل إضافة تتطلب PHP 8.2 أو إضافة cURL على سيرفر قديم برامجة PHP 7.4 تؤدي لخطأ Fatal Error فوري.

معمارية التفعيل على مستوى الشبكة في Multisite

في شبكات المواقع المتعددة (WordPress Multisite)، يمكن لمدير الشبكة (Super Admin) الضغط على زر “تفعيل على مستوى الشبكة” (Network Activate). كيف يتعامل خطاف التفعيل مع هذا السيناريو؟

دالة الـ Callback المربوطة بـ register_activation_hook تستقبل معاملاً منطقياً اختيارياً اسمه $network_wide:

  • إذا كان $network_wide = false: الإضافة يتم تفعيلها لموقع فرعي واحد فقط.
  • إذا كان $network_wide = true: الإضافة تفعل للشبكة بالكامل! ولكن الصدمة المعمارية هي: ووردبريس ينفذ دالة التفعيل لموقع رئيسي واحد فقط ولا يمر تلقائياً على باقي المواقع الفرعية!

إذا كانت إضافتك تنشئ جداول MySQL مخصصة لكل موقع (مثل wp_2_custom_table و wp_3_custom_table)، فيجب عليك برمجياً الدوران على كافة معرفات المواقع عبر switch_to_blog()، بالإضافة للربط بخطاف wp_initialize_site لإنشاء الجداول لأي موقع جديد يتم إنشاؤه في المستقبل على الشبكة!

الكود البرمجي الكامل: كلاس التفعيل المؤسسي المتكامل (Production-Grade Activator)

الكود التالي يمثل النموذج المعماري الأرقى لإدارة دورة حياة التفعيل؛ حيث يقوم بفحص إصدار PHP والإضافات المطلوبة، وإنشاء جداول قاعدة البيانات بـ dbDelta وفق أدق المعايير، وتحديث الروابط، ودعم شبكات Multisite بالكامل:

<?php
/**
 * كلاس معالجة دورة حياة تفعيل الإضافة المؤسسية
 */
final class Abozaid_Plugin_Activator {

    /**
     * نقطة الدخول الرئيسية لخطاف التفعيل
     *
     * @param bool $network_wide هل تم التفعيل على مستوى الشبكة بالكامل؟
     */
    public static function activate( bool $network_wide = false ): void {
        // 1. الفحص الاستباقي لمتطلبات البيئة والخادم (Pre-flight Check)
        self::assert_environment_capabilities();

        // 2. معالجة التفعيل لشبكات Multisite أو المواقع الفردية
        if ( is_multisite() && $network_wide ) {
            // الدوران على كافة المواقع الفرعية في الشبكة
            $site_ids = get_sites( [ 'fields' => 'ids', 'number' => 0 ] );
            foreach ( $site_ids as $site_id ) {
                switch_to_blog( (int) $site_id );
                self::run_single_site_activation();
                restore_current_blog();
            }
        } else {
            self::run_single_site_activation();
        }
    }

    /**
     * فحص إصدارات السيرفر والإضافات التابعة
     */
    private static function assert_environment_capabilities(): void {
        if ( version_compare( PHP_VERSION, '8.1', '<' ) ) {
            deactivate_plugins( plugin_basename( AZ_CORE_FILE ) );
            wp_die( 
                esc_html__( 'فشل التفعيل: تتطلب هذه الإضافة إصدار PHP 8.1 أو أحدث.', 'abozaid' ),
                esc_html__( 'خطأ في متطلبات البيئة', 'abozaid' ),
                [ 'back_link' => true ]
            );
        }

        if ( ! extension_loaded( 'curl' ) || ! extension_loaded( 'mbstring' ) ) {
            deactivate_plugins( plugin_basename( AZ_CORE_FILE ) );
            wp_die( 
                esc_html__( 'فشل التفعيل: تتطلب الإضافة تفعيل ملحقات curl و mbstring على السيرفر.', 'abozaid' ),
                esc_html__( 'ملحقات مفقودة', 'abozaid' ),
                [ 'back_link' => true ]
            );
        }
    }

    /**
     * تنفيذ مهام التأسيس للموقع الواحد
     */
    private static function run_single_site_activation(): void {
        // أ. إنشاء أو ترقية جداول MySQL المخصصة
        self::create_custom_tables();

        // ب. زرع الإعدادات الافتراضية
        self::seed_default_options();

        // ج. تسجيل الكيانات وتحديث قواعد التوجيه
        if ( function_exists( 'abozaid_register_real_estate_cpt' ) ) {
            abozaid_register_real_estate_cpt();
        }
        flush_rewrite_rules( false );

        // د. جدولة مهام الكرون التلقائية
        if ( ! wp_next_scheduled( 'abozaid_daily_cleanup_cron' ) ) {
            wp_schedule_event( time(), 'daily', 'abozaid_daily_cleanup_cron' );
        }
    }

    /**
     * إنشاء الجداول المخصصة عبر dbDelta بالمعايير الدقيقة
     */
    private static function create_custom_tables(): void {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();
        $table_name      = $wpdb->prefix . 'az_audit_logs';

        // استعلام SQL منسق بدقة متناهية (مسافتان بعد PRIMARY KEY و KEY)
        $sql = "CREATE TABLE {$table_name} (
            id bigint(20) unsigned NOT NULL auto_increment,
            user_id bigint(20) unsigned NOT NULL default 0,
            action_name varchar(100) NOT NULL default '',
            payload longtext NOT NULL,
            created_at datetime NOT NULL default '0000-00-00 00:00:00',
            PRIMARY KEY  (id),
            KEY  user_action (user_id, action_name),
            KEY  created_at (created_at)
        ) {$charset_collate};";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta( $sql );

        // تسجيل إصدار قاعدة البيانات للمتابعة المستقبلية
        update_option( 'az_audit_db_version', '1.0.0', 'no' );
    }

    /**
     * زرع الإعدادات الافتراضية
     */
    private static function seed_default_options(): void {
        add_option( 'az_enterprise_settings', [
            'api_enabled'  => 1,
            'log_retention'=> 30, // الاحتفاظ بالسجلات لمدة 30 يوماً
            'environment'  => 'production',
        ], '', 'no' );
    }
}

// تسجيل الخطاف الرسمي في الملف الرئيسي للإضافة
register_activation_hook( AZ_CORE_FILE, [ 'Abozaid_Plugin_Activator', 'activate' ] );
?>

دراسة حالة واقعية من السوق المصري: نظام CRM عقاري وتجمد لوحة التحكم أثناء التفعيل

في إحدى شركات التطوير والتسويق العقاري الكبرى بالقاهرة الجديدة، تعاقدت الشركة مع مبرمج حر لبناء نظام CRM داخلي لإدارة طلبات العملاء والعمولات وتوزيع الليدز (Leads). المطور جهز الإضافة ورفعها للموقع. عندما دخل مدير تكنولوجيا المعلومات بالشركة وضغط على زر “تفعيل الإضافة”، تجمدت لوحة التحكم لمدة دقيقة كاملة، ثم رمى المتصفح خطأ 504 Gateway Timeout!

التشخيص المعماري وجذور الكارثة

عند فحص ملف debug.log وقاعدة البيانات، وجدنا التالي:

  • المطور وضع داخل دالة register_activation_hook حلقة تكرار (Loop) تقوم بقراءة 48,000 عميل من ملف CSV قديم، ومحاولة زرعهم في جدول مخصص عبر استعلامات $wpdb->insert() منفردة استغرقت أكثر من 90 ثانية!
  • خادم الويب (Nginx) قطع الاتصال بعد 30 ثانية لتجاوز مهلة الـ FastCGI Timeout.
  • النتيجة الكارثية: تم إدخال 6,000 عميل فقط وتوقف الاستيراد في المنتصف، وجدول قاعدة البيانات تم إنشاؤه بدون الفهارس الأساسية، ولم يتم تجديد مسارات الروابط الدائمة (Rewrite Rules)، وأصبحت لوحة التحكم تظهر خطأ “Cannot activate plugin because it triggered a fatal error” في كل محاولة تالية!

خطة الإنقاذ وإعادة الهيكلة المعمارية

  1. قمنا بإزالة حلقة استيراد البيانات الثقيلة تماماً من خطاف التفعيل وقصرنا الخطاف على إنشاء هيكل الجداول الفارغة وضبط الفهارس بـ dbDelta() في زمن أقل من 0.05 ثانية!
  2. قمنا بترحيل عملية استيراد الـ 48,000 عميل إلى مهمة خلفية مؤتمتة بنظام الدفعات (Batched Background Processing عبر Action Scheduler) تنطلق بهدوء بمعدل 1,000 سجل كل 30 ثانية دون التأثير على تجربة التفعيل.
  3. تم تنظيف السجلات الجزئية وإعادة ضبط أرقام الإصدارات.

النتيجة بالأرقام: انخفض زمن تفعيل الإضافة من أكثر من 90 ثانية مع الفشل إلى 0.32 ثانية فقط بنجاح 100%، واكتمل استيراد كافة بيانات العملاء في الخلفية دون أي تجميد للوحة التحكم أو انقطاع للموقع.

الوصايا العشر للتعامل مع خطاف تفعيل الإضافات

  1. لا تطبع أي مخرجات (No Echo / No Var_dump): أي مسافة فارغة أو نص مطبوع أثناء التفعيل سيؤدي لخطأ Unexpected Output وإلغاء التفعيل فوراً.
  2. لا تغلق وسم PHP في نهاية ملفات الإضافة: تجنب وضع ?> لتفادي حقن مسافات بيضاء غير مرئية في مجرى الإخراج.
  3. استخدم dbDelta لإنشاء وترقية الجداول: التزم بالمسافتين بعد PRIMARY KEY لتفادي فشل النواة في تحليل الاستعلام.
  4. سجل CPTs قبل تفريغ الروابط: استدعِ دالة تسجيل نوع المحتوى ثم استدعِ flush_rewrite_rules(false) لمنع أخطاء 404.
  5. لا تنفذ مهام ثقيلة متزامنة في التفعيل: رحّل عمليات استيراد البيانات الضخمة إلى مهام كرون خلفية أو معالجات دفعات.
  6. افحص متطلبات PHP والنواة استباقياً: عطل الإضافة واعرض رسالة wp_die() واضحة إذا كان السيرفر يفتقر لمتطلبات التشغيل.
  7. ادعم شبكات Multisite بوعي: تذكر أن التفعيل الشبكي يتطلب الدوران عبر switch_to_blog() والربط بـ wp_initialize_site.
  8. جدول مهام الكرون بأمان: تحقق أولاً بـ wp_next_scheduled() لمنع تكرار جدولة نفس الحدث عدة مرات في قاعدة البيانات.
  9. اضبط Autoload على no للخيارات الجديدة: استخدم add_option($key, $val, '', 'no') لحماية ذاكرة الإقلاع من التضخم.
  10. اختبر التفعيل على بيئة خالية: جرب دائماً تفعيل إضافتك على تثبيت ووردبريس جديد ونظيف للتأكد من عدم اعتمادها على إعدادات سابقة مسبقة الصنع.

الأسئلة الشائعة حول خطاف تفعيل الإضافات في ووردبريس

التفعيل عبر سطر الأوامر (WP-CLI) وأتمتة النشر على السيرفرات السحابية

في بيئات النشر الحديثة واستخدام حاويات Docker وسيرفرات Kubernetes، نادراً ما يدخل مهندس النظم على لوحة تحكم المتصفح للضغط على زر “تفعيل”. التفعيل يتم برمجياً بواسطة أدوات سطر الأوامر وأشهرها WP-CLI عبر الأمر الشهير:

wp plugin activate my-enterprise-plugin --path=/var/www/html

الفروق المعمارية بين التفعيل بالمتصفح والتفعيل بـ WP-CLI

هناك اختلافات جوهرية يجب على المطور إدراكها عند تشغيل التفعيل من سطر الأوامر:

  1. غياب مهلة الـ HTTP Timeout: في المتصفح، إذا استغرقت دالة التفعيل أكثر من 30 ثانية يقطع Nginx الاتصال فوراً بـ 504 Gateway Timeout. أما في سطر الأوامر، فمهلة التنفيذ تتبع max_execution_time الخاص بـ CLI (والذي يكون عادة غير محدود أو مرتفعاً جداً)، مما يجعله أكثر أماناً لتنفيذ المهام التأسيسية.
  2. اختلاف الـ Output Buffering: في سطر الأوامر، ووردبريس يظل يراقب المخرجات؛ فإذا طبع الكود نصوصاً غير متوقعة، سيظهر WP-CLI رسالة تحذير Warning: The plugin generated unexpected output لكنه قد يكمل التفعيل في بعض الحالات مع تنبيهك للخطأ.
  3. سياق المستخدم: عند تشغيل الأمر بـ WP-CLI، المتغير get_current_user_id() يعود بـ 0 ما لم تمرر معامل --user=admin، ولذلك يجب ألا تعتمد دالة التفعيل على وجود مستخدم مسجل دخوله في الجلسة.
<?php
/**
 * سكريبت تهيئة يدعم العمل السلس مع كل من WP-CLI والمتصفح
 */
function abozaid_flexible_activation_runner(): void {
    // التحقق مما إذا كان التفعيل يتم عبر سطر الأوامر
    $is_cli = defined( 'WP_CLI' ) && WP_CLI;

    if ( $is_cli ) {
        WP_CLI::line( 'بدء تشغيل معالج تأسيس الإضافة...' );
    }

    // تنفيذ مهام إنشاء الجداول
    Abozaid_Plugin_Activator::activate();

    if ( $is_cli ) {
        WP_CLI::success( 'تم إنشاء الجداول وتحديث الروابط بنجاح تام!' );
    }
}
?>

أتمتة تشغيل الإضافات في ملفات Docker Entrypoint

في بيئات السحابية التي تستخدم عزل الحاويات (Containerization)، يتم كتابة سكريبت entrypoint.sh يتولى فحص قاعدة البيانات وتفعيل الإضافات تلقائياً عند بناء الحاوية لأول مرة:

# فحص اتصال MySQL ثم تفعيل الإضافات وتحديث الروابط تلقائياً
wp core is-installed --path=/var/www/html && 
wp plugin activate abozaid-core --path=/var/www/html && 
wp rewrite flush --hard --path=/var/www/html

هذا النمط يضمن إمكانية استنساخ بيئات التطوير والاختبار (Staging & Production) في دقائق معدودة مع ضمان تفعيل كافة الإضافات والجداول بنفس المعايير الهندسية الصارمة.

إضاءة معمارية للمطورين: إذا كنت تستخدم بيئة Docker أو Vagrant محلية، تأكد دائماً من أن مستخدم الويب www-data يمتلك صلاحيات الكتابة الكاملة على مجلد wp-content/ حتى لا تفشل عمليات إنشاء الجداول أو ملفات التخزين المؤقت أثناء تشغيل خطاف التفعيل لأول مرة.

كما ننصح دائماً بحفظ نسخة احتياطية من قاعدة البيانات بـ wp db export قبل تفعيل أي إضافة جديدة لأول مرة في بيئات الإنتاج الحية لتفادي أي مفاجآت غير محسوبة.

س1: ما هو دور دالة register_activation_hook في ووردبريس؟

هي الدالة الرسمية لتسجيل كود يتم تنفيذه لمرة واحدة فقط عند قيام مدير الموقع بالضغط على زر “تفعيل” للإضافة، وتستخدم عادة لإنشاء جداول قاعدة البيانات وزرع الإعدادات وتحديث الروابط الدائمة.

س2: ما هو سبب ظهور خطأ “The plugin generated unexpected output during activation”؟

يحدث لأن ووردبريس يستخدم نظام Output Buffering أثناء التفعيل؛ فإذا قامت الإضافة بطباعة أي نص أو إشعار خطأ PHP أو كان هناك مسافة فارغة قبل أو بعد وسوم PHP، ترفض النواة التفعيل وتعتبره مخرجات غير متوقعة.

س3: لماذا لا تعمل دالة register_activation_hook داخل مجلد mu-plugins؟

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

س4: ما هي دالة dbDelta وما هي أهم شروط صياغة استعلاماتها؟

هي دالة النواة المسؤولة عن إنشاء وتحديث جداول MySQL بأمان. أهم شروطها: وضع كل حقل في سطر منفصل، واستخدام مسافتين كاملتين بعد كلمة PRIMARY KEY (id) وكلمة KEY index_name.

س5: لماذا يجب تمرير المعامل false لدالة flush_rewrite_rules أثناء التفعيل؟

تمرير false (وهي القيمة الافتراضية) يوجه ووردبريس لتحديث خيارات التوجيه في قاعدة البيانات فقط دون محاولة إعادة كتابة ملف .htaccess على القرص الصلب ما لم تكن هناك ضرورة قصوى.

س6: كيف يتعامل خطاف التفعيل مع شبكات المواقع المتعددة (Multisite Network Activate)؟

يمرر ووردبريس معاملاً يوضح ما إذا كان التفعيل على مستوى الشبكة $network_wide، ويجب على المطور الدوران برمجياً على كافة المواقع عبر switch_to_blog() لإنشاء الجداول في كل موقع فرعي.

س7: كيف أمنع تفعيل الإضافة إذا كان إصدار PHP على السيرفر غير متوافق؟

بفحص version_compare() داخل دالة التفعيل؛ فإذا كان الإصدار قديماً نستدعي deactivate_plugins() ثم نوقف التنفيذ بـ wp_die() مع عرض رسالة خطأ واضحة للمدير.

س8: هل يمكن توجيه المستخدم لصفحة ترحيبية أو صفحة إعدادات فور تفعيل الإضافة؟

نعم، ولكن ليس داخل خطاف التفعيل مباشرة بل بتسجيل خيار مؤقت في قاعدة البيانات (Transient)، ثم التحقق منه في خطاف admin_init وعمل إعادة توجيه عبر wp_safe_redirect() لمرة واحدة فقط.

س9: ماذا يحدث إذا احتوت دالة التفعيل على خطأ Fatal Error؟

يلتقط ووردبريس الخطأ ويلغي عملية التفعيل فوراً ويعرض رسالة الخطأ للمدير، وتبقى الإضافة في حالة “معطلة” لحماية الموقع من التوقف.

س10: أين يجب استدعاء دالة register_activation_hook في ملفات الإضافة؟

يجب استدعاؤها حصراً داخل الملف الرئيسي للإضافة (Main Plugin File) في النطاق العام، وتمرير الثابت __FILE__ كمعامل أول.

س11: كيف أضمن عدم تكرار إضافة نفس الأدوار أو الخيارات إذا أعاد المستخدم تفعيل الإضافة؟

باستخدام دالة add_option() بدلاً من update_option() لأنها لا تستبدل الإعدادات إذا كانت موجودة مسبقاً، وفحص وجود الدور بـ get_role() قبل إنشائه.

س12: هل تنطلق دالة التفعيل عند تحديث الإضافة لإصدار جديد من لوحة التحكم؟

لا، دالة التفعيل تنطلق فقط عند الضغط على زر تفعيل. عند التحديث التلقائي للإضافة لا ينطلق خطاف التفعيل، ولذلك يجب فحص ترقيات قاعدة البيانات عبر فحص أرقام الإصدارات في plugins_loaded.

س13: ما هو ملف upgrade.php وما هي أهميته في خطاف التفعيل؟

هو ملف مدمج في لوحة تحكم ووردبريس wp-admin/includes/upgrade.php يحتوي على دالة dbDelta() ودوال ترقية قواعد البيانات، ويجب تضمينه يدوياً عبر require_once قبل استدعاء الدالة.

س14: كيف يتم جدولة حدث كرون يومي بأمان أثناء التفعيل؟

بفحص ما إذا كان الحدث مسجلاً مسبقاً عبر wp_next_scheduled('my_cron_hook')، فإذا لم يكن موجوداً نستدعي wp_schedule_event(time(), 'daily', 'my_cron_hook').

س15: هل يمكن استخدام دالة wp_redirect داخل خطاف التفعيل مباشرة؟

لا ينصح بذلك؛ لأن ووردبريس يحتاج لإكمال مسار التفعيل وإعادة التوجيه إلى رابط plugins.php?activate=true، واستدعاء إعادة توجيه مبكرة قد يقطع دورة التفعيل قبل اكتمالها.

س16: كيف أتعامل مع المواقع الجديدة التي تنشأ على شبكة Multisite بعد تفعيل الإضافة شبكياً؟

بربط دالة بخطاف النواة wp_initialize_site؛ حيث ينطلق هذا الخطاف فور إنشاء أي موقع فرعي جديد في الشبكة لإنشاء الجداول المخصصة له تلقائياً.

س17: ما هو الخطأ الشائع عند تسمية جداول MySQL المخصصة أثناء التفعيل؟

إهمال استخدام بادئة الجداول الديناميكية $wpdb->prefix، مما يؤدي لفشل الاستعلامات على المواقع التي تستخدم بادئات مخصصة وتضارب الجداول في شبكات Multisite.

س18: هل يمكن كتابة ملفات ثابتة على السيرفر أثناء التفعيل (مثل إنشاء مجلد رفع مخصص)؟

نعم، باستخدام دالة wp_mkdir_p() لإنشاء مجلدات مخصصة داخل wp-content/uploads/ مع حمايتها بملف index.php فارغ أو ملف .htaccess لمنع استعراض المجلدات.

س19: كيف أختبر كود التفعيل وأتأكد من خلوه من أخطاء المخرجات أثناء التطوير؟

عبر تفعيل WP_DEBUG ومراجعة ملف debug.log، أو تجربة تعطيل وإعادة تفعيل الإضافة عدة مرات من لوحة التحكم ومراقبة شريط الاستجابة في المتصفح.

س20: لماذا يحذر من مسح بيانات الجداول القديمة أثناء التفعيل؟

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

المصادر والمراجع الرسمية

أكمل المسار

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

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

WordPress Architect & Enterprise Consultant

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


رد واحد على “شرح خطاف تفعيل الإضافات register_activation_hook في ووردبريس: تهيئة قواعد البيانات وتحديث الروابط والأخطاء القاتلة”

  1. […] السابق: تفعيل إضافة ووردبريس: Activation Hook وإعداد البيانات […]

اترك تعليقاً