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

شرح Options API في ووردبريس: حفظ واسترجاع إعدادات الموقع ومعمارية الكاش وتأمين البيانات

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

أهلاً بيك في المقال رقم 30 من 100 في سلسلتنا المعمارية الشاملة معمارية ووردبريس من الأساسيات إلى الاحتراف الكامل، ضمن المستوى الثالث: نموذج بيانات ووردبريس (WordPress Data Modeling). النهاردة هنشرح الخزينة المركزية لإعدادات وتكوين أي موقع ووردبريس: واجهة برمجة الخيارات (WordPress Options API)، وهيكل جدول wp_options، وإدارة الكاش، وحفظ وقراءة البيانات بأعلى معايير الأمان والأداء بالعامية المصرية.

لو بتبني إضافة مخصصة (Custom Plugin) لبوابة دفع مصرية زي فوري (Fawry) أو باي موب (Paymob)، أو بتبني نظام ربط شحن مع شركات زي بوسطة (Bosta) وأرامكس، أول حاجة هتحتاجها هي مكان تخزن فيه مفاتيح الربط (API Keys)، وبيانات التاجر (Merchant Credentials)، وحالة الوضع التجريبي (Sandbox Mode)، وإعدادات العرض العامة. المكان ده في ووردبريس هو الـ Options API. استخدام الواجهة دي مش مجرد إنك تكتب get_option() و update_option()؛ فهمك لكيفية عمل الكاش في الذاكرة، وخوارزميات التسلسل (Serialization)، وإدارة خيار التحميل التلقائي (Autoload) هو الفرق الحاسم بين موقع يفتح في جزء من الثانية وموقع يعاني من استهلاك الذاكرة (Memory Spikes) وأخطاء تعطل بوابات الدفع!

المعمارية التحتية لجدول wp_options في قاعدة البيانات

جدول wp_options هو قلب النظام النابض؛ هو أول جدول يلمسه ووردبريس بمجرد وصول طلب المتصفح، وقبل حتى تحديد القالب أو معالجة الاستعلامات. الجدول ده يحتوي على 4 أعمدة رئيسية:

  • option_id: المفتاح الأساسي (bigint(20) unsigned auto_increment)؛ معرف فريد لكل خيار.
  • option_name: الاسم البرمجي الفريد للخيار (varchar(191)). هذا العمود عليه قيد فريد (Unique Key)، مما يمنع تكرار نفس اسم الإعداد أكثر من مرة في الموقع الواحد.
  • option_value: القيمة المخزنة للإعداد (longtext). يمكن أن تخزن نصوصاً بسيطة، أرقاماً، أو مصفوفات وكائنات معقدة يتم تسلسلها تلقائياً.
  • autoload: مؤشر التحميل التلقائي (varchar(20)). يحدد ما إذا كان هذا الخيار يجب تحميله تلقائياً في الذاكرة العشوائية مع بداية تشغيل ووردبريس (قيمته الافتراضية 'yes' في النواة الكلاسيكية و 'on' أو 'auto' في التحديثات الحديثة). في ووردبريس 6.6+ تمت إضافة فهرس مخصص على هذا العمود لتسريع استعلامات الإقلاع.

التشريح المعماري لدوال Options API الأساسية

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

1. دالة get_option($option, $default_value)

الدالة دي المسؤولة عن قراءة قيمة الإعداد. لما بتنادي get_option('siteurl')، إيه اللي بيحصل ورا الكواليس؟

  1. فحص فلتر الاستباق pre_option: ووردبريس بيفحص الخطاف pre_option_{$option}؛ لو أي إضافة أو كود مسجل اعتراض في الخطاف ده، القيمة بتتعاد فوراً دون لمس الكاش أو الداتابيز.
  2. فحص كاش التحميل التلقائي alloptions: إذا كان الخيار معلماً بـ Autoload، ووردبريس بيقرأه في جزء من الميكروثانية من مصفوفة الذاكرة $alloptions المحملة مسبقاً، بدون إرسال أي كويري SQL إطلاقاً!
  3. فحص كاش الكائن الفردي (Object Cache): إذا لم يكن ضمن الـ alloptions، يبحث في Redis أو Memcached في مجموعة options.
  4. الاستعلام من MySQL (Cache Miss): إذا لم يجده في الكاش، يرسل استعلام SQL لقاعدة البيانات، ويقوم بتخزين النتيجة في الكاش للطلبات التالية.
  5. إلغاء التسلسل (Unserialization): إذا كانت القيمة مصفوفة مشفرة، تمر عبر دالة maybe_unserialize() لتعود كمصفوفة PHP طبيعية.
  6. القيمة الافتراضية: إذا لم يكن الخيار موجوداً، تعيد الدالة القيمة الممررة في المعامل الثاني $default_value (افتراضياً false).

2. دالة update_option($option, $value, $autoload)

الدالة المسؤولة عن تحديث الإعداد، وتمتلك ذكاءً معمارياً فريداً:

  • فحص التطابق الصارم (Strict Equality Check): قبل كتابة أي سطر في قاعدة البيانات، ووردبريس يقارن القيمة الجديدة بالقيمة الحالية عبر $value === $old_value. لو القيمة لم تتغير، ووردبريس لا يرسل استعلام UPDATE لقاعدة البيانات إطلاقاً! ويعيد false فوراً لتوفير موارد الخادم.
  • الإنشاء التلقائي (Upsert Behavior): لو الخيار مكنش موجود في الأصل، دالة update_option بتروح تنادي داخلياً دالة add_option() وتنشئه تلقائياً دون أي خطأ.
  • تفريغ الكاش (Cache Invalidation): فور التحديث بنجاح، تقوم الدالة بمسح المفتاح من كاش الكائنات وإعادة ضبط مصفوفة alloptions لضمان أن كل السيرفرات المتصلة ترى التعديل في نفس اللحظة.

3. دالتا add_option و delete_option

  • add_option($option, $value, '', $autoload): مخصصة لإضافة خيار جديد فقط؛ فإذا كان الخيار موجوداً مسبقاً، تفشل العملية وتعيد false. المعامل الرابع $autoload يسمح لك بتحديد ما إذا كنت تريد تحميله تلقائياً أم لا (سنتحدث عن أهميته القصوى في قسم الأداء).
  • delete_option($option): تقوم بحذف الصف نهائياً من جدول wp_options وتطهير كافة مفاتيح الكاش المرتبطة به.

هندسة تسلسل البيانات (Serialization) ومخاطر استبدال الروابط المباشر

لما بتمرر مصفوفة لـ update_option()، ووردبريس بيستدعي داخلياً دالة maybe_serialize() اللي بتحول المصفوفة لنص مهيكل بلغة PHP، زي كده:

a:2:{s:8:"api_key";s:32:"d857829a9e3b4a28938472918274a91b";s:7:"sandbox";b:1;}

لاحظ التركيبة المعمارية للنص: كل متغير مسبوق بحرف يحدد نوعه وطوله بالبايت؛ فكلمة api_key طولها 8 أحرف s:8، وقيمتها طولها 32 حرفاً s:32.

فخ كسر السلاسل المتسلسلة (Broken Serialized Strings)

أكبر خطأ كارثي ممكن يعمله مطور مبتدئ عند نقل موقع من بيئة تجريبية إلى بيئة إنتاج، هو إنه يفتح ملف الـ SQL أو يدخل على phpMyAdmin وينفذ استعلام استبدال مباشر زي:

-- استعلام كارثي يدمر البيانات المتسلسلة
UPDATE wp_options 
SET option_value = REPLACE(option_value, 'http://test.local', 'https://mywebsite.com');

ليه الاستعلام ده كابوس؟
لأن الرابط القديم http://test.local طوله 17 حرفاً، والرابط الجديد https://mywebsite.com طوله 21 حرفاً! الاستبدال المباشر بيغير النص لكن مش بيعدل عداد الطول s:17 ليصبح s:21. أول ما ووردبريس يحاول يقرأ المصفوفة بـ unserialize()، الخوارزمية بتلاقي إن طول النص لا يطابق العداد المسجل، فترمى خطأ فوري وترجع false! النتيجة؟ كافة إعدادات القالب وبوابات الدفع والإضافات بتختفي في ثانية واحدة كأنها ممسوحة!

الحل الهندسي: لا تستخدم استعلامات SQL المباشرة لاستبدال النصوص في جداول ووردبريس أبداً؛ استخدم أدوات تفهم التسلسل وتعيد احتساب الأطوال بدقة، مثل أمر WP-CLI الرسمي:

wp search-replace 'http://test.local' 'https://mywebsite.com' --all-tables

معمارية التحميل التلقائي (Autoload) وحماية الذاكرة

معامل autoload هو صمام الأمان لسرعة الموقع. ووردبريس لما بيقلع، بيعمل استعلام واحد شهير:

SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes';

الاستعلام ده بيسحب كل الخيارات دي ويحطها في مصفوفة واحدة في الرام. ده تصرف عبقري للإعدادات الصغيرة المتكررة (مثل اسم الموقع، مسار الروابط، القالب النشط). لكن لما مطور يكتب إضافة لتخزين تقارير دورية أو كاش ضخم في Options API، ويسيب الـ autoload على 'yes'، حجم مصفوفة $alloptions بيكبر ويوصل لـ 10 أو 20 ميجابايت!

ماذا يحدث لخادمك عندما يتضخم حجم Autoload؟

  • كل طلب لصفحة عادية أو حتى صورة مفقودة أو استدعاء AJAX بيحمل الـ 20 ميجابايت دي في الرام لكل عملية PHP!
  • لو عندك 50 طلب متزامن، استهلاك الرام هيوصل لـ 1 جيجابايت في أجزاء من الثانية، والسيرفر هيرمي خطأ 502 Bad Gateway أو Out of Memory!
  • القاعدة الذهبية: أي إعداد حجمه يتجاوز 2 كيلوبايت، أو لا تحتاجه في كافة صفحات الموقع (مثل إعدادات لوحة التحكم المتخصصة أو التقارير المؤقتة)، يجب دائماً تعيينه بـ autoload = 'no'.

نمط التصميم المعتمد: حفظ إعدادات الإضافة في خيار مصفوفي موحد (Single Array Pattern)

المطور الهاوي لو عنده إضافة فيها 15 إعداداً، بيروح يخزن كل إعداد في خيار منفصل بجدول wp_options (مثلاً: az_paymob_api_key, az_paymob_iframe_id, az_paymob_currency, … إلخ). ده بيعمل زحام في قاعدة البيانات وتشتت في الكاش.
أما المهندس المحترف، فيخزن كافة إعدادات الإضافة داخل مصفوفة مجمعة واحدة تحت اسم واحد (مثل az_paymob_settings). هذا النمط يوفر استعلامات قاعدة البيانات، ويقلل عمليات التحديث، ويسهل أخذ نسخ احتياطية واسترجاع الإعدادات.

الكود البرمجي التالي يوضح تطبيقاً كاملاً لنمط المصفوفة الموحدة مع التطهير الصارم وإدارة الكاش لبوابة دفع إلكترونية:

<?php
/**
 * إدارة إعدادات بوابة الدفع وفق نمط المصفوفة الموحدة ومعايير الأمان الرسمية
 */

/**
 * جلب إعدادات الإضافة مع دمج القيم الافتراضية بأمان
 *
 * @return array مصفوفة الإعدادات النظيفة
 */
function abozaid_get_payment_gateway_settings(): array {
    // 1. تعريف القيم الافتراضية لضمان عدم حدوث Undefined Index
    $defaults = [
        'merchant_id'  => '',
        'api_key'      => '',
        'secret_key'   => '',
        'sandbox_mode' => 1, // تفعيل الوضع التجريبي افتراضياً للأمان
        'currency'     => 'EGP',
        'debug_log'    => 0,
    ];

    // 2. جلب الخيار الموحد من قاعدة البيانات أو كاش الذاكرة
    $saved_settings = get_option( 'abozaid_payment_settings', [] );

    // 3. دمج المحفوظ مع الافتراضي لضمان تماسك الهيكل
    return wp_parse_args( (array) $saved_settings, $defaults );
}

/**
 * تحديث وحفظ الإعدادات مع التطهير الصارم وإلغاء التحميل التلقائي
 *
 * @param array $input مدخلات المستخدم من شاشة الإعدادات
 * @return bool نجاح أو فشل التحديث
 */
function abozaid_update_payment_gateway_settings( array $input ): bool {
    // 1. التحقق من صلاحيات المدير الإدارية
    if ( ! current_user_can( 'manage_options' ) ) {
        return false;
    }

    // 2. تطهير كل حقل بحسب نوعه البياني الصارم
    $clean_settings = [
        'merchant_id'  => sanitize_text_field( $input['merchant_id'] ?? '' ),
        'api_key'      => sanitize_text_field( $input['api_key'] ?? '' ),
        'secret_key'   => sanitize_text_field( $input['secret_key'] ?? '' ),
        'sandbox_mode' => empty( $input['sandbox_mode'] ) ? 0 : 1,
        'currency'     => in_array( $input['currency'] ?? '', [ 'EGP', 'USD', 'SAR' ], true ) ? $input['currency'] : 'EGP',
        'debug_log'    => empty( $input['debug_log'] ) ? 0 : 1,
    ];

    // 3. الحفظ في جدول wp_options مع تحديد autoload = 'no' للأمان والأداء
    return update_option( 'abozaid_payment_settings', $clean_settings, 'no' );
}
?>

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

في أحد المتاجر الإلكترونية الكبرى للملابس في مصر، المتجر كان يحقق مبيعات تتجاوز 10,000 طلب شهرياً. في موسم تخفيضات “البلاك فرايداي”، قرر فريق المطورين نقل الموقع من خادم استضافة مشتركة إلى سيرفر سحابي مخصص عالي الأداء مع تركيب شهادة أمان SSL جديدة وتغيير الرابط من http إلى https. وفجأة، بعد النقل بدقائق، توقفت عمليات الدفع الإلكتروني تماماً وأصبح العملاء يتلقون رسائل “فشل في الاتصال بمزود الدفع”! وخسر المتجر في 4 ساعات مبيعات تقدر بنصف مليون جنيه مصري!

التحقيق والتشخيص المعماري

عند فحص ملف error.log وتتبع مسار قراءة الإعدادات، تم اكتشاف الآتي:

  • أحد المطورين قام بتشغيل استعلام SQL استبدال مباشر في phpMyAdmin لتغيير الروابط القديمة من http://myshop.eg إلى https://myshop.eg داخل جدول wp_options.
  • إضافة الدفع الإلكتروني كانت تخزن روابط الـ Webhook وعناوين الـ Callbacks ومفاتيح التاجر داخل خيار متسلسل في wp_options.
  • الاستبدال المباشر قام بكسر طول السلسلة (Serialized Length Mismatch)، فأصبحت دالة get_option() تفشل في فك التسلسل وتعيد false! وبالتالي أصبح المتجر يرسل طلبات دفع بدون مفتاح التاجر السري وبدون رابط إشعار Webhook صالح، فتقوم بوابة فوري برفض العمليات فوراً كعمليات احتيالية!

خطة الإصلاح والنتائج

  1. تم استدعاء النسخة الاحتياطية لجدول wp_options فوراً.
  2. تم تنفيذ الاستبدال المعماري الصحيح للروابط باستخدام أمر WP-CLI wp search-replace الذي أعاد احتساب أطوال البايتات بدقة متناهية.
  3. تم تطبيق نمط المصفوفة الموحدة لإعدادات الدفع مع ضبط autoload = 'no' لمنع تسريب المفاتيح في كاش الواجهة الأمامية.

النتيجة: عادت بوابة الدفع للعمل بكفاءة 100% خلال 15 دقيقة، واستقرت معدلات نجاح العمليات (Success Rate) عند 99.4%، وتم وضع بروتوكول صارم يمنع أي استبدال يدوي لقواعد البيانات في بيئة الإنتاج الحية.

الوصايا العشر للتعامل مع Options API في ووردبريس

  1. اضبط Autoload على no للخيارات الكبيرة: أي إعداد يتجاوز حجمه بضعة كيلوبايتات لا تدعه يتسلل إلى مصفوفة $alloptions في الذاكرة.
  2. لا تستخدم استعلامات SQL المباشرة للاستبدال: استخدم أدوات تفهم التسلسل مثل WP-CLI لتفادي كسر السلاسل المتسلسلة وضياع الإعدادات.
  3. اجمع إعدادات إضافتك في مصفوفة موحدة: تجنب زرع عشرات الصفوف المستقلة في wp_options؛ خيار واحد مصفوفي يوفر الذاكرة ويسهل الصيانة.
  4. افحص دائماً الصلاحيات قبل التحديث: تأكد من استدعاء current_user_can('manage_options') قبل كتابة أي إعداد جديد لحماية خيارات الموقع من الثغرات.
  5. طهر البيانات عند الحفظ وعقمها عند العرض: استخدم sanitize_text_field عند الإدخال و esc_attr أو esc_html عند الطباعة في لوحة التحكم.
  6. وفر قيماً افتراضية عبر wp_parse_args: لا تفترض أبداً أن الإعداد محفوظ في قاعدة البيانات؛ احمِ كودك من تحذيرات PHP بتوفير قيم افتراضية متماسكة.
  7. استخدم Settings API للشاشات المعقدة: إذا كنت تبني صفحة خيارات متعددة الأقسام، اعتمد على register_setting() للاستفادة من أنظمة الأمان والتطهير التلقائية.
  8. نظف الخيارات عند إلغاء التثبيت (Uninstall): استخدم ملف uninstall.php لمسح خيارات إضافتك من wp_options احتراماً لمساحة قاعدة بيانات العميل.
  9. لا تخزن بيانات متغيرة سريعة الزوال في Options API: لحفظ البيانات المؤقتة التي تنتهي صلاحيتها، استخدم Transients API بدلاً من الخيارات العادية.
  10. استفد من فحص التطابق في update_option: تذكر أن الدالة لا ترهق قاعدة البيانات إذا لم تتغير القيمة، فلا تتردد في استخدامها دون خوف من الـ Overwriting غير الضروري.

الأسئلة الشائعة حول Options API في ووردبريس

التكامل مع واجهة الإعدادات (Settings API): بناء صفحات تكوين احترافية خالية من الثغرات

في كثير من الأحيان، المطور الهاوي لما يحب يعمل صفحة إعدادات في لوحة التحكم، بيروح يعمل فورم HTML عادي في القالب، ويبعت البيانات لملف PHP مخصص أو يعمل تحقق يدوي في صفحة الأدمن بـ if (isset($_POST['submit'])). الطريقة دي مش بس بدائية؛ دي بتفتح ثغرات CSRF خطيرة وبتتجاهل نظام الأمان المدمج في النواة! ووردبريس وفر واجهة معمارية راقية مبنية خصيصاً فوق Options API تسمى Settings API.

كيف تعمل Settings API بالتناغم مع Options API؟

المعمارية دي بتعتمد على توجيه نموذج الإدخال (Form Action) إلى ملف النواة المركزي wp-admin/options.php. هذا الملف هو المعالج الرسمي لنواة ووردبريس، ويتولى تلقائياً الخطوات التالية دون كتابة سطر كود واحد منك:

  1. التحقق من صحة التوكن الأمني (Nonce Verification) لمنع هجمات تزوير الطلبات عبر المواقع (CSRF).
  2. التحقق من امتلاك المستخدم الحالي لصلاحية manage_options.
  3. استدعاء دوال التطهير والتحقق المسجلة مسبقاً (Sanitization Callbacks) لتنظيف المدخلات.
  4. حفظ النتيجة في جدول wp_options وتفريغ كاش الكائنات المتصل.
  5. إعادة توجيه المستخدم لصفحة الإعدادات مع إظهار رسالة النجاح الخضراء “تم حفظ الإعدادات بنجاح”.
<?php
/**
 * تسجيل وتأمين صفحة إعدادات بوابة الدفع باستخدام Settings API
 */
add_action( 'admin_init', 'abozaid_register_gateway_settings_api' );
function abozaid_register_gateway_settings_api(): void {
    // 1. تسجيل الإعداد في النواة مع ربطه بدالة التطهير الصارمة
    register_setting(
        'abozaid_payment_group',         // اسم مجموعة الخيارات
        'abozaid_payment_settings',      // اسم الخيار في جدول wp_options
        [
            'type'              => 'array',
            'sanitize_callback' => 'abozaid_sanitize_gateway_payload',
            'default'           => [],
        ]
    );

    // 2. تسجيل قسم الإعدادات
    add_settings_section(
        'az_gateway_main_section',
        __( 'إعدادات الاتصال بمزود الدفع الإلكتروني', 'abozaid' ),
        function() {
            echo '<p>' . esc_html__( 'يرجى إدخال بيانات التاجر والمفاتيح السرية بدقة لضمان استقرار عمليات الدفع.', 'abozaid' ) . '</p>';
        },
        'abozaid-payment-settings'
    );

    // 3. إضافة الحقول داخل القسم
    add_settings_field(
        'az_merchant_id_field',
        __( 'معرف التاجر (Merchant ID)', 'abozaid' ),
        'abozaid_render_merchant_id_input',
        'abozaid-payment-settings',
        'az_gateway_main_section'
    );
}

/**
 * دالة التطهير والتحقق الصارم مع إطلاق إشعارات الأخطاء الفورية
 */
function abozaid_sanitize_gateway_payload( $input ): array {
    $output = [];
    $merchant_id = sanitize_text_field( $input['merchant_id'] ?? '' );

    // التحقق من أن المعرف ليس فارغاً
    if ( empty( $merchant_id ) ) {
        add_settings_error(
            'abozaid_payment_settings',
            'empty_merchant_id',
            __( 'خطأ: لا يمكن ترك معرف التاجر فارغاً!', 'abozaid' ),
            'error'
        );
    } else {
        $output['merchant_id'] = $merchant_id;
    }

    $output['api_key']      = sanitize_text_field( $input['api_key'] ?? '' );
    $output['sandbox_mode'] = empty( $input['sandbox_mode'] ) ? 0 : 1;

    return $output;
}

/**
 * طباعة حقل الإدخال في شاشة لوحة التحكم
 */
function abozaid_render_merchant_id_input(): void {
    $options = get_option( 'abozaid_payment_settings', [] );
    $val = esc_attr( $options['merchant_id'] ?? '' );
    echo "<input type='text' name='abozaid_payment_settings[merchant_id]' value='{$val}' class='regular-text' />";
}
?>

قياس وتحليل الذاكرة عند قراءة الخيارات

في البيئات الموزعة عالية الزيارات (High-Concurrency Clusters)، قراءة الخيارات عبر get_option() تستهلك زمناً شبه معدوم إذا كانت محملة في الذاكرة عبر Autoload. ولكن يجب الحذر من ظاهرة Cache Churn التي تحدث عندما تقوم إضافة سيئة باستدعاء update_option() في كل زيارة لصفحة، مما يجبر Redis على مسح وإعادة كتابة مفتاح alloptions باستمرار، مسبباً تدهوراً في سرعة استجابة الخادم بالكامل.

س1: ما هو جدول wp_options وما هي أهميته في معمارية ووردبريس؟

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

س2: ما هي فائدة معامل Autoload في جدول الخيارات؟

معامل autoload يحدد ما إذا كان الخيار سيتم تحميله في مصفوفة الذاكرة $alloptions في استعلام واحد عند إقلاع الموقع (إذا كان yes)، أو سيتم جلبه باستعلام منفصل عند الحاجة إليه فقط (إذا كان no).

س3: متى يجب أن أضبط Autoload على ‘no’ صراحة؟

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

س4: ماذا يحدث إذا قمت باستبدال رابط الموقع مباشرة في MySQL عبر استعلام REPLACE؟

سيؤدي ذلك إلى كسر السلاسل المتسلسلة (Serialized Strings) في قاعدة البيانات؛ لأن طول الرابط الجديد لن يطابق عداد البايتات المسجل في السلسلة، مما يفشل دالة unserialize() ويؤدي لمسح إعدادات القوالب وبوابات الدفع بالكامل.

س5: ما هي الأداة الموصى بها لاستبدال الروابط أو النصوص بأمان في قاعدة البيانات؟

الأداة الرسمية الموصى بها هي أمر WP-CLI الشهير wp search-replace، أو إضافة موثوقة مثل Better Search Replace، حيث تقومان بفك تسلسل المصفوفات وتعديلها وإعادة حساب أطوال البايتات بدقة.

س6: هل ترسل دالة update_option استعلام SQL إذا لم تتغير القيمة؟

لا نهائياً؛ دالة update_option() تقوم بعمل فحص تطابق صارم $old_value === $new_value، فإذا كانت القيمة الجديدة مطابقة تماماً للقيمة السابقة، تعيد الدالة false فوراً دون إرسال أي استعلام لـ MySQL.

س7: ما هو الحد الأقصى لطول اسم الخيار في عمود option_name؟

الحد الأقصى هو 191 حرفاً، لأن عمود option_name نوعه varchar(191) وعليه قيد فريد (Unique Index) متوافق مع معايير محرف utf8mb4 في MySQL.

س8: ما الفرق بين Options API و Transients API؟

الـ Options API مخصصة للإعدادات الدائمة التي لا تنتهي صلاحيتها وتتطلب بقاءها طوال حياة الموقع، بينما Transients API مخصصة للكاش المؤقت ذي تاريخ انتهاء محدد (Expiration Time) ويمكن حذفه وإعادة بنائه في أي لحظة.

س9: كيف يتم تخزين المصفوفات والكائنات في جدول wp_options؟

يتم تحويلها تلقائياً إلى نص مشفر عبر دالة النواة maybe_serialize()، وعند قراءتها بـ get_option() يتم استدعاء maybe_unserialize() لتعود إلى شكلها الأصلي دون تدخل يدوي من المطور.

س10: ما هي مجموعة الكاش المستخدمة لجدول الخيارات في أنظمة Object Cache مثل Redis؟

تستخدم النواة مجموعة الكاش options، وتخزن كافة الخيارات التلقائية تحت مفتاح رئيسي واحد هو alloptions.

س11: كيف أقرأ إعداداً مع توفير قيمة احتياطية في حال عدم وجوده؟

عبر تمرير القيمة الاحتياطية كمعامل ثانٍ في الدالة، مثل: $items_per_page = get_option('az_posts_per_page', 10);، فإذا لم يكن الخيار مسجلاً ستعود القيمة 10.

س12: هل يمكن اعتراض قراءة خيار معين وتغيير قيمته أثناء التشغيل؟

نعم بالتأكيد، باستخدام فلتر pre_option_{$option_name} لاعتراض القراءة قبل لمس قاعدة البيانات، أو فلتر option_{$option_name} لتعديل القيمة بعد جلبها من الكاش.

س13: ما هو الخطاف الذي ينطلق فور تحديث قيمة خيار معين؟

الخطاف المعماري هو update_option_{$option_name} ويمرر القيمة القديمة والجديدة واسم الخيار، بالإضافة للخطاف العام updated_option.

س14: كيف أحذف كافة خيارات إضافتي عند قيام العميل بحذفها من لوحة التحكم؟

عبر إنشاء ملف uninstall.php في المجلد الرئيسي للإضافة واستدعاء دالة delete_option('my_plugin_settings') لضمان عدم ترك أي مخلفات في قاعدة البيانات بعد الحذف.

س15: لماذا ينصح بحفظ إعدادات الإضافة في مصفوفة مجمعة واحدة بدلاً من خيارات متعددة؟

لأن نمط المصفوفة الموحدة يوفر مساحة في جدول wp_options، ويقلل استعلامات قاعدة البيانات، ويجعل عمليات التحديث والكاش تتم دفعة واحدة بكفاءة وسرعة فائقة.

س16: كيف أتحقق مما إذا كان خيار معين مسجلاً بالفعل في قاعدة البيانات؟

عبر استدعاء get_option('option_name', 'not_found_token')؛ فإذا كانت النتيجة مطابقة لرمز عدم الوجود، فهذا يعني أن الخيار غير موجود نهائياً في الجدول.

س17: ما هو الحد الأقصى لحجم البيانات التي يمكن تخزينها في عمود option_value؟

عمود option_value نوعه longtext في MySQL، ونظرياً يتسع حتى 4 جيجابايت من النصوص، ولكن معمارياً يجب ألا يتجاوز أي خيار بضع مئات الكيلوبايتات لتفادي انهيار ذاكرة PHP.

س18: كيف يتم التعامل مع الخيارات في شبكات المواقع المتعددة (Multisite)؟

في شبكات Multisite، كل موقع فرعي يملك جدول wp_options خاص به، بينما إعدادات الشبكة العامة على مستوى السوبر أدمن تخزن في جدول مخصص اسمه wp_sitemeta وتدار عبر دوال get_site_option() و update_site_option().

س19: هل يؤثر كثرة صفوف جدول wp_options على سرعة الموقع؟

العدد بحد ذاته لا يؤثر كثيراً لأن عمود option_name مفهرس بـ Unique Index، ولكن التأثير السلبي الكبير يحدث عندما يتضخم حجم خيارات autoload = 'yes' المجمعة في الذاكرة.

س20: كيف أقوم بتعطيل كاش الخيارات مؤقتاً أثناء عمليات الاختبار؟

يمكن استخدام دالة wp_cache_delete('alloptions', 'options') لتفريغ كاش الخيارات العام، أو استخدام دوال الاستعلام المباشر عبر $wpdb في بيئات الاختبار فقط.

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

أكمل المسار

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

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

WordPress Architect & Enterprise Consultant

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


اترك تعليقاً