أهلاً بيك يا صديقي المطور في المحطة الفاصلة والأخيرة من دورة حياة إضافات ووردبريس (Plugin Lifecycle). بعد ما اتعلمنا إزاي الإضافة بتتحمل في الذاكرة مع كل ريكوست، وإزاي بتمر بمرحلة التفعيل (Activation) ومرحلة التعطيل (Deactivation)، جه الوقت نتكلم عن اللحظة الحاسمة اللي ما فيش بعدها رجوع: مرحلة **الحذف النهائي (Plugin Uninstall)**.
كتير من المطورين بيخلطوا خلط كارثي بين التعطيل والحذف؛ تلاقي مطور فاكر إن المستخدم لما يدوس Deactivate لازم نروح نمسح الجداول من قاعدة البيانات ونحذف الإعدادات، وده غلط قاتل بيخرب بيوت العملاء وأصحاب المتاجر لو حصل أي تحديث أو تعطيل مؤقت لاختبار تعارض الإضافات! ومطور تاني يروح يكتب كود الإضافة ويسيبها تماماً بدون أي آلية تنظيف، فالعميل لما يحذف الإضافة، يفضل في قاعدة بياناته ميجابايتات من الجداول الوهمية (Orphaned Tables) ومئات السطور في جدول wp_options بتشتغل Autoload وتخنق السيرفر لسنين طويلة بعد ما الإضافة اتنسيت أصلاً.
في المقال ده، هنشرح بالعامية المصرية التقنية المعايير الهندسية الصارمة لكتابة ملف uninstall.php احترافي، وهنعرف الفرق الجوهري بينه وبين دالة register_uninstall_hook()، وإزاي نامن الملف ده ضد الاختراق والوصول المباشر، وإزاي نصمم سياسة تنظيف ذكية تحترم رغبة المستخدم (Data Retention Policy) وتدعم شبكات ووردبريس المتعددة (Multisite Network)، مع كود إنتاجي متكامل ودراسة حالة حقيقية و20 سؤال وجواب بيغطوا كل تفصيلة ممكن تقابلك في مقابلات العمل وسوق العمل الحر.
الفرق الجوهري بين التعطيل (Deactivation) والحذف (Uninstall)
عشان نفهم الفلسفة التصميمية لووردبريس، لازم نرسخ القاعدة الذهبية اللي بنكررها دايماً: **التعطيل هو مجرد إيقاف مؤقت للوظائف الحركية (Pause)، بينما الحذف هو استئصال كامل مع محو الآثار (Purge).**
تعال نشوف المقارنة دي عشان ترسخ في ذهنك:
| وجه المقارنة | مرحلة التعطيل (Deactivation) | مرحلة الحذف (Uninstall) |
|---|---|---|
| الغرض الأساسي | إيقاف تنفيذ كود الإضافة مؤقتاً لتحديثها أو لاختبار تعارض برمجي. | إزالة الإضافة نهائياً من النظام لعدم حاجة العميل إليها. |
| جداول قاعدة البيانات المخصصة | ممنوع لمسها نهائياً؛ تظل محتفظة بكافة سجلات العملاء والعمليات. | يتم حذفها بالكامل (DROP TABLE) إذا لم يطلب العميل الاحتفاظ بها. |
| خيارات النظام (wp_options) | تبقى كما هي لضمان عودة الإعدادات فور إعادة التفعيل. | تُحذف جميع المفاتيح والسجلات التابعة للإضافة بالكامل. |
| الكاش والمؤقتات (Transients) | يُفضل مسحها لمنع البيانات البايتة. | تُمسح جذرياً من قاعدة البيانات ومخدمات الكاش كـ Redis. |
| المهام المجدولة (WP-Cron) | يتم إلغاء جدولتها فوراً لمنع الأخطاء في الخلفية. | يتم إلغاؤها والتأكد من تفريغ طوابير المهام التابعة لها. |
| ملفات الرفع واللوجات | تظل محفوظة في مجلد wp-content/uploads. | تُحذف مجلدات الكاش واللوجات وتُترك ملفات الوسائط بحسب سياسة الإضافة. |
طرق برمجة الحذف: uninstall.php أم register_uninstall_hook()؟
ووردبريس بيوفر طريقتين عشان تنفذ كود الحذف لما المستخدم يدوس على رابط Delete في لوحة التحكم:
- ملف
uninstall.phpفي المجلد الرئيسي للإضافة: وده هو الأسلوب القياسي والمفضل رقم 1 عالمياً والموصى به رسمياً في دليل تطوير ووردبريس. - دالة
register_uninstall_hook(): دالة بيتم استدعاؤها داخل ملف الإضافة الرئيسي وبتحدد كولباك (Callback) للتنفيذ وقت الحذف.
ليه مجتمع ووردبريس بيفضل uninstall.php دائماً؟
السبب هندسي بحت بيتعلق بإدارة موارد الذاكرة وموثوقية التشغيل:
- عدم تحميل ملفات الإضافة في الذاكرة: لما بتستخدم
register_uninstall_hook()، ووردبريس بيضطر يحمل ملف الإضافة الرئيسي بكل كلاساته وتبعيّاته عشان يقدر يشوف الهوك المسجل والكولباك. لو في ملف الإضافة أي كود قديم أو كلاس ناقص أو تعارض مع إصدار PHP، عملية الحذف هتفشل بـ Fatal Error والمستخدم مش هيعرف يحذف الإضافة! - العزل التام والنظافة: ملف
uninstall.phpبيشتغل كملف معزول تماماً ومستقل؛ ووردبريس بيكتشف وجوده تلقائياً لما المستخدم يطلب الحذف، ويشغله في بيئة نظيفة بدون ما يحمل أي ملف تاني من ملفات الإضافة. ده بيضمن إن الحذف ينجح حتى لو بقية ملفات الإضافة معطوبة أو فيها أخطاء برمجية قاتلة.
صمام الأمان الحرج: ثابت WP_UNINSTALL_PLUGIN
بما إن ملف uninstall.php موجود مباشرة في مجلد الإضافة تحت مسار الويب العام (Public Web Root)، أي شخص في العالم يقدر يفتح المتصفح ويكتب الرابط المباشر للملف:
https://example.com/wp-content/plugins/my-plugin/uninstall.php
لو أنت مش حامي الملف ده، تخيل معايا السيناريو المرعب: أي زائر أو بوت على الإنترنت يزور الرابط ده، الملف هيتنفذ ويمسح كل جداول الإضافة وبيانات العملاء وقاعدة البيانات في ثانية واحدة!
عشان كده ووردبريس بيوفر ثابت أمان خاص اسمه WP_UNINSTALL_PLUGIN. لما مدير الموقع يضغط على زرار الحذف من لوحة التحكم، ووردبريس هو اللي بيعرف الثابت ده قبل ما يستدعي الملف. أول سطر إجباري في ملف uninstall.php لازم يكون فحص هذا الثابت:
اخرج فوراً!
if (!defined('WP_UNINSTALL_PLUGIN')) {
exit;
}
زيادة في التأمين والاحترافية، كمان بنفحص صلاحيات المستخدم الحالي عشان نضمن إن اللي بينفذ العملية مدير معتمد عنده صلاحية إدارة الإضافات وحذفها:
<?php
if (!current_user_can('delete_plugins')) {
exit;
}
تصميم سياسة الاحتفاظ بالبيانات (Keep Data Policy)
من أرقى الممارسات اللي بتميز المطور المحترف عن الهاوي هي احترام رغبة مدير الموقع. مش كل مدير موقع بيحذف الإضافة بيكون عايز يدمر بياناته التاريخية للأبد؛ ساعات المدير بيكون بيحذف الإضافة عشان يثبت نسخة تانية يدوي، أو عشان ينقل السيرفر، أو بيجرب حاجة وعايز يرجع يركبها بعدين بنفس سجلات الطلبات والفواتير والإعدادات.
عشان كده، المعيار المعتمد في كبرى الإضافات العالمية (زي WooCommerce و Yoast SEO) هو توفير خيار واضح في صفحة إعدادات الإضافة في لوحة التحكم، زي:
“مسح كافة البيانات والجداول نهائياً عند حذف الإضافة (Delete all data upon plugin deletion)”.
لو المستخدم سايب الخيار ده غير مفعل (Unchecked)، ملف uninstall.php يكتفي بتنظيف الكاش المؤقت والمهام المجدولة، ويسيب الجداول وسجلات البيانات سليمة تماماً عشان لو أعاد تثبيت الإضافة يلاقي بياناته زي ما سابها. أما لو المستخدم فعل الخيار ده بإرادته الواعية، يبقى الملف ينفذ التنظيف الجذري الشامل.
قائمة مهام التنظيف الشامل (Systematic Cleanup Checklist)
عملية التنظيف الاحترافية لازم تشمل كل مكان الإضافة سابت فيه أثر داخل بيئة ووردبريس:
1. تنظيف جدول الخيارات (wp_options) والمؤقتات
احذف كل المفاتيح الفردية والمصفوفات اللي حفظتها في خيارات ووردبريس باستخدام دالة delete_option(). ولو عندك مفاتيح متغيرة أو ديناميكية كتيرة، تقدر تنفذ استعلام SQL مباشر بمسح كل المفاتيح اللي بتبدأ بالبادئة (Prefix) الخاصة بإضافتك:
query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
$wpdb->esc_like('my_enterprise_') . '%'
)
);
2. حذف الجداول المخصصة (Custom Database Tables)
لو إضافتك كانت بتبني جداول خاصة بيها لتخزين سجلات ضخمة (زي جدول الطلبات وسجل الحركات واللوجات)، احذفها باستخدام أمر DROP TABLE IF EXISTS:
prefix . 'enterprise_orders',
$wpdb->prefix . 'enterprise_logs',
$wpdb->prefix . 'enterprise_customers'
];
foreach ($tables_to_drop as $table) {
$wpdb->query("DROP TABLE IF EXISTS {$table}");
}
3. تنظيف المقالات المخصصة والبيانات الوصفية (Post Meta)
لو إضافتك كانت بتسجل Custom Post Type وملايين السجلات الوصفية التابعة ليه في جدول wp_postmeta، لازم تمسح السجلات دي كلها عشان قاعدة البيانات ترجع رشيقة، وتمسح أي Term Relationships ارتبطت بالتصنيفات الخاصة بالإضافة.
4. تنظيف بيانات المستخدمين الوصفية (User Meta)
لو كنت بتخزن تفضيلات أو توكنات خاصة بالمستخدمين في جدول wp_usermeta:
query(
$wpdb->prepare(
"DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s",
$wpdb->esc_like('my_enterprise_user_') . '%'
)
);
5. حذف مجلدات الرفع المؤقتة والملفات المخزنة
لو الإضافة كانت بتنشئ مجلد مخصص داخل wp-content/uploads لتخزين ملفات PDF للفواتير المصدرة أو ملفات الكاش أو ملفات التصدير CSV المؤقتة، لازم تحذف المجلد ده بالكامل باستخدام كلاس WP_Filesystem بعد التأكد من عدم احتوائه على ملفات حساسة خاصة بالنظام.
التعامل مع شبكات ووردبريس المتعددة (Multisite Network)
في بيئة Multisite، ووردبريس بيكون عنده شبكة فيها عشرات أو مئات المواقع الفرعية (Sub-sites). كل موقع فرعي له بادئة جداول خاصة بيه (زي wp_2_options, wp_3_options).
لو الإضافة تم حذفها من لوحة إدارة الشبكة (Network Admin)، ووردبريس بينفذ ملف uninstall.php مرة واحدة فقط على مستوى الشبكة! لو كتبت كود الحذف العادي، هيتم مسح بيانات الموقع الرئيسي فقط، وهتفضل بيانات باقي المواقع الفرعية موجودة في قواعد بياناتها كأنك ما عملتش حاجة!
عشان كده، كود الحذف الاحترافي لازم يفحص: هل إحنا في بيئة Multisite؟ لو أيوة، نلف على كل المواقع باستخدام دالة get_sites() ونستخدم switch_to_blog() لتنظيف كل موقع فرعي على حدة، وفي النهاية نحذف خيارات الشبكة العامة (Site Options):
0]); // جلب جميع مواقع الشبكة
foreach ($sites as $site) {
switch_to_blog($site->blog_id);
enterprise_clean_site_data(); // دالة تنظيف الموقع الحالي
restore_current_blog();
}
// مسح خيارات الشبكة الموحدة
delete_site_option('my_enterprise_network_settings');
} else {
enterprise_clean_site_data();
}
الكود البرمجي الكامل لملف uninstall.php الإنتاجي
تعال نشوف كود إنتاجي متكامل ومكتوب بأعلى معايير الأمان والأداء وموثق بالكامل:
prefix . 'enterprise_transactions',
$wpdb->prefix . 'enterprise_audit_log',
$wpdb->prefix . 'enterprise_webhooks'
];
foreach ($custom_tables as $table_name) {
// نستخدم DROP TABLE IF EXISTS بأمان
$wpdb->query("DROP TABLE IF EXISTS `{$table_name}`");
}
// --- المرحلة الثالثة: حذف الخيارات التابعة للإضافة من wp_options ---
delete_option('my_enterprise_settings');
delete_option('my_enterprise_license_key');
delete_option('my_enterprise_db_version');
// مسح أي إعدادات ديناميكية أخرى تبدأ ببادئة الإضافة
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
$wpdb->esc_like('my_enterprise_') . '%'
)
);
// --- المرحلة الرابعة: حذف التدوينات المخصصة وبياناتها الوصفية ---
$post_ids = $wpdb->get_col(
$wpdb->prepare(
"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s",
'enterprise_invoice'
)
);
if (!empty($post_ids)) {
foreach ($post_ids as $pid) {
// حذف التدوينة نهائياً وتخطي سلة المهملات
wp_delete_post((int) $pid, true);
}
}
// --- المرحلة الخامسة: تنظيف بيانات المستخدمين الوصفية ---
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s",
$wpdb->esc_like('enterprise_user_') . '%'
)
);
// --- المرحلة السادسة: مسح الكاش الكائني (Object Cache) ---
wp_cache_flush();
}
/**
* دالة مسؤولة عن حذف الملفات والمجلدات المؤقتة في wp-content/uploads
*/
function enterprise_purge_upload_directories() {
$upload_dir = wp_upload_dir();
$plugin_upload_path = trailingslashit($upload_dir['basedir']) . 'enterprise-invoices-cache';
if (is_dir($plugin_upload_path)) {
require_once ABSPATH . 'wp-admin/includes/file.php';
WP_Filesystem();
global $wp_filesystem;
if ($wp_filesystem) {
$wp_filesystem->delete($plugin_upload_path, true);
}
}
}
// =========================================================================
// التنفيذ الفعلي مع دعم شبكات Multisite والمواقع الفردية
// =========================================================================
if (is_multisite()) {
// شبكة متعددة: نلف على جميع المواقع المسجلة في الشبكة
$site_ids = get_sites(['fields' => 'ids', 'number' => 0]);
if (!empty($site_ids)) {
foreach ($site_ids as $site_id) {
switch_to_blog((int) $site_id);
enterprise_purge_single_site_data();
restore_current_blog();
}
}
// مسح خيارات الشبكة الموحدة
delete_site_option('my_enterprise_network_license');
delete_site_option('my_enterprise_network_master_config');
} else {
// موقع فردي عادي
enterprise_purge_single_site_data();
}
// تنظيف مجلدات التخزين المؤقتة
enterprise_purge_upload_directories();
دراسة حالة حقيقية: كارثة حذف إضافة الفواتير في متجر مصري شهير بوسط البلد
عشان تعيش أهمية الكلام ده في أرض الواقع، هحكي لك قصة حصلت مع متجر إلكتروني مصري متخصص في بيع الأجهزة المنزلية مقره في وسط البلد بالقاهرة:
المتجر كان متعاقد مع مبرمج حر بنى لهم إضافة خاصة لطباعة الفواتير الإلكترونية المعتمدة وربطها بالضرائب المصرية. المبرمج استسهل وكتب كود حذف الجداول داخل هوك register_deactivation_hook()! ولما سألوه ليه عملت كده، قال: “عشان لما الإضافة تقف تنظف نفسها أول بأول!”.
في يوم جمعة، وكان موسم تخفيضات البلاك فرايدي (Black Friday)، فريق الدعم الفني للمتجر واجه مشكلة تعارض بسيطة بين إضافة شحن جديدة وإضافة الفواتير. موظف الدعم حب يجرب يعطل إضافة الفواتير لمدة دقيقتين بس عشان يتأكد من مصدر التعارض، وضغط على زرار Deactivate.
في نفس الثانية، كود التعطيل اتنفذ، ونفذ أمر:
DROP TABLE wp_electronic_invoices;
واتمسحت أكتر من 95,000 فاتورة ضريبية رسمية وحركات دفع بقيمة تتجاوز 18 مليون جنيه مصري!
النتيجة كانت صدمة عارمة، وتوقف المتجر، واضطروا يسترجعوا نسخة احتياطية (Backup) قديمة تسببت في فقدان آلاف الطلبات الحديثة وغرامات مالية كبيرة.
لما استلمت المشروع وعملت تدقيق معماري للكود (Architecture Audit)، قمت بالإجراءات التالية:
- فصل التعطيل عن الحذف نهائياً: تم إفراغ هوك التعطيل تماماً من أي استعلامات حذف، وقصر دوره على إلغاء جدولة WP-Cron وحفظ حالة الإضافة.
- إنشاء ملف
uninstall.phpمخصص: تم نقل عمليات مسح الجداول بالكامل لملف الحذف فقط، مع صمام أمانWP_UNINSTALL_PLUGIN. - إضافة خيار “حماية البيانات”: تم وضع خيار افتراضي محمي بكلمة سر للمدير العام: “لا تقم بحذف الجداول حتى لو تم حذف الإضافة إلا بموافقة صريحة”، مع تنبيه أحمر عريض يحذر من الحذف غير المقصود.
- بناء آلية التصدير التلقائي: في حال قرر المدير مسح الجداول، الكود يقوم أولاً بإنشاء نسخة احتياطية مضغوطة من جدول الفواتير بصيغة SQL وتنزيلها تلقائياً قبل تنفيذ أمر
DROP TABLE.
الوصايا العشر لمطوري ووردبريس عند تصميم كود الحذف (Uninstall)
- إياك ولمس البيانات في التعطيل: احفر في عقلك أن كود مسح الجداول مكانه الوحيد هو الحذف وليس التعطيل.
- اعتمد ملف uninstall.php دائماً: هو الخيار الأسرع، والأنظف، والأكثر أماناً وموثوقية في كل إصدارات ووردبريس.
- اقفل الباب بصمام الأمان: تأكد دائماً أن أول سطر يفحص
defined('WP_UNINSTALL_PLUGIN')لمنع الوصول المباشر عبر المتصفح. - تحقق من صلاحية المستخدم: لا تنفذ عمليات المسح إلا إذا كان المستخدم يملك صلاحية
current_user_can('delete_plugins'). - وفر خيار الاحتفاظ بالبيانات: امنح عميلك القدرة على الاحتفاظ بسجلاته وإعداداته عبر خيار واضح في لوحة التحكم.
- دعم شبكات Multisite بذكاء: استخدم
get_sites()وswitch_to_blog()لتنظيف قواعد بيانات كافة المواقع التابعة للشبكة. - نظف ما تراه وما لا تراه: امسح الجداول المخصصة، وخيارات
wp_options، والمؤقتات، وبيانات الميتا، والمهام المجدولة. - نظف الملفات المؤقتة في uploads: احذف مجلدات الكاش والفواتير المولدة ولا تترك نفايات تستهلك مساحة التخزين على السيرفر.
- تفريغ الكاش الكائني (Object Cache): استدعِ دائماً
wp_cache_flush()بعد عمليات الحذف لضمان عدم بقاء بيانات شبحية في Redis أو Memcached. - وثق كودك بالكامل: اكتب تعليقات توضيحية تشرح ما يفعله كل استعلام حذف لضمان سلامة مراجعة الكود وفهمه من المطورين الآخرين.
تنظيف الرتب والصلاحيات المخصصة (Roles & Capabilities Cleanup)
فاكر في مقال سابق لما اتكلمنا عن صلاحيات ووردبريس (Roles & Capabilities) وقلنا إن الصلاحيات بتتخزن في جدول wp_options تحت مفتاح wp_user_roles وبتفضل محفوظة ومستمرة في قاعدة البيانات؟
لو إضافتك كانت بتسجل رتبة جديدة خاصة بنظامها (زي رتبة store_auditor أو invoice_manager)، وسيبت الموقع وحذفت الإضافة، الرتبة دي هتفضل متعلقة في جدول الخيارات إلى ما لا نهاية!
عشان كده، من أبجديات التنظيف المعماري الصارم داخل ملف uninstall.php، إنك تستدعي دالة remove_role() لإزالة أي رتب مخصصة أضافتها الإضافة، بالإضافة إلى إزالة أي صلاحيات مخصصة (Custom Capabilities) كنت منحتها للمدير أو المحررين:
remove_cap('manage_enterprise_invoices');
$admin_role->remove_cap('export_enterprise_reports');
$admin_role->remove_cap('view_enterprise_audit_log');
}
تنفيذ الحذف الآلي والتحكم الكامل عبر WP-CLI
في بيئات السيرفرات السحابية وإدارة العشرات من مواقع العملاء عبر أنظمة DevOps، الحذف مش بيتم بالماوس من لوحة التحكم، بل بيتم عبر سطر الأوامر بواسطة أداة WP-CLI.
الأمر الأساسي لحذف أي إضافة هو:
# حذف الإضافة مع تشغيل إجراءات التنظيف في uninstall.php
wp plugin uninstall my-enterprise-plugin
# حذف الإضافة على مستوى شبكة Multisite بالكامل دفعة واحدة
wp plugin uninstall my-enterprise-plugin --network
# حذف ملفات الإضافة بدون تشغيل ملف uninstall.php (في حالات الطوارئ القصوى)
wp plugin uninstall my-enterprise-plugin --skip-delete
لما بتنفذ أمر wp plugin uninstall، بيقوم WP-CLI بنفسه بتعريف ثابت WP_UNINSTALL_PLUGIN واستدعاء ملف uninstall.php الخاص بك بنفس الترتيب القياسي. فلو كودك مصمم صح وبيحترم المعايير اللي شرحناها، عملية الحذف هتتم في جزء من الثانية والسطر البرمجي هيطبع لك رسالة نجاح خضراء تفتح النفس، مع ضمان خلو قاعدة البيانات من أي نفايات مهملة.
الأسئلة الشائعة حول حذف إضافات ووردبريس (FAQ)
1. ما هو الفرق الأساسي بين التعطيل (Deactivation) والحذف (Uninstall) في ووردبريس؟
التعطيل هو مجرد إيقاف مؤقت لعمل الإضافة لا يؤثر على أي بيانات في قاعدة البيانات، بينما الحذف هو إزالة ملفات الإضافة بالكامل وتنظيف آثارها وجداولها نهائياً من الموقع.
2. لماذا يُفضل استخدام uninstall.php بدلاً من register_uninstall_hook()؟
لأن uninstall.php يعمل كملف معزول ومستقل تماماً دون تحميل بقية ملفات الإضافة في الذاكرة، مما يضمن نجاح الحذف حتى لو كانت ملفات الإضافة تالفة أو تحتوي على أخطاء برمجية قاتلة (Fatal Errors).
3. ماذا يحدث إذا نسيت إضافة فحص WP_UNINSTALL_PLUGIN في بداية ملف uninstall.php؟
يصبح الملف ثغرة أمنية مدمرة، حيث يمكن لأي شخص زيارة رابط الملف مباشرة عبر المتصفح وتشغيل استعلامات حذف الجداول ومسح قاعدة البيانات بالكامل.
4. كيف أحذف جدول مخصص بأمان أثناء عملية الحذف؟
باستخدام كائن قاعدة البيانات العام $wpdb وتنفيذ استعلام صريح مثل: $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}my_table");.
5. هل يجب أن أقوم بحذف جداول الإضافة فوراً بمجرد الضغط على Delete؟
الأفضل والأكثر احترافية هو فحص إعدادات الإضافة أولاً؛ فإذا اختار المستخدم خيار “الاحتفاظ بالبيانات”، يجب الحفاظ على الجداول ومسح المؤقتات والكاش فقط.
6. كيف أتعامل مع حذف الإضافة في بيئة شبكات ووردبريس المتعددة (Multisite)؟
يجب فحص ما إذا كانت البيئة Multisite باستخدام is_multisite()، ثم الدوران على كافة المواقع باستخدام get_sites() وتنفيذ switch_to_blog() لتنظيف جداول كل موقع فرعي، ثم حذف الخيارات العامة عبر delete_site_option().
7. كيف أحذف الخيارات (Options) التي تحتوي على بادئة موحدة دفعة واحدة؟
عبر تنفيذ استعلام SQL مباشر على جدول {$wpdb->options} باستخدام WHERE option_name LIKE 'prefix_%' مع استخدام $wpdb->prepare() و $wpdb->esc_like() لضمان الحماية.
8. هل يتم استدعاء ملف uninstall.php عند ترقية الإضافة (Plugin Update)؟
لا، أثناء ترقية الإضافة يتم استدعاء التعطيل المؤقت والتفعيل الجديد فقط، ولا يتم استدعاء ملف uninstall.php نهائياً.
9. ما هي الطريقة الصحيحة لحذف المنشورات المخصصة (Custom Posts) التابعة للإضافة؟
يتم جلب معرفات المنشورات (IDs) التابعة لـ Post Type الإضافة، ثم التكرار عليها وحذفها نهائياً باستخدام wp_delete_post($post_id, true); مع تمرير true لتخطي سلة المهملات ومسح الميتا تلقائياً.
10. كيف أقوم بتنظيف بيانات المستخدمين الوصفية (User Meta) المسجلة بواسطة الإضافة؟
باستخدام استعلام حذف مباشر على جدول {$wpdb->usermeta} يمسح المفاتيح التي تطابق بادئة الإضافة المحددة.
11. هل يجب إلغاء مهام WP-Cron في ملف uninstall.php؟
نعم، للتأكد التام من عدم بقاء أي مهام مجدولة شاردة في قاعدة البيانات باستخدام دالة wp_clear_scheduled_hook().
12. كيف أقوم بحذف مجلدات التخزين المؤقتة التابعة للإضافة في uploads؟
باستخدام واجهة WP_Filesystem القياسية، وتحديد مسار المجلد داخل wp_upload_dir()['basedir'] وحذفه بالكامل باستخدام $wp_filesystem->delete($dir, true);.
13. لماذا يجب استدعاء wp_cache_flush() في نهاية ملف uninstall.php؟
لتفريغ الكاش الكائني (Object Cache) والتأكد من إزالة أي بيانات قديمة مخزنة في الذاكرة السريعة (Redis أو Memcached)، حتى لا تعرض لوحة التحكم بيانات غير موجودة.
14. هل يمكن استخدام الكلاسات الخاصة بالإضافة داخل ملف uninstall.php؟
لا يُنصح بذلك إطلاقاً؛ لأن ملفات الإضافة قد تكون محذوفة جزئياً أو معدلة، والأفضل كتابة الكود داخل uninstall.php بدوال مباشرة ومستقلة تماماً.
15. ماذا لو قام المستخدم بحذف مجلد الإضافة يدوياً عبر FTP بدلاً من لوحة التحكم؟
في هذه الحالة لن يتم تشغيل ملف uninstall.php، وستظل البيانات في قاعدة البيانات؛ لذا يُنصح دائماً مديري المواقع بحذف الإضافات من لوحة التحكم لتشغيل إجراءات التنظيف الرسمية.
16. كيف أمنع حذف البيانات المهمة عن طريق الخطأ من قبل المديرين المبتدئين؟
بجعل خيار “حذف البيانات عند إلغاء التثبيت” غير مفعل افتراضياً، وإظهار رسالة تحذيرية حمراء واضحة تتطلب تأكيداً إضافياً قبل حفظ الخيار.
17. هل تؤثر الجداول المهملة (Orphaned Tables) المتروكة بدون حذف على أداء الموقع؟
نعم، تستهلك مساحة التخزين في السيرفر، وتزيد من حجم النسخ الاحتياطية ووقت استعادتها، وتتسبب في بطء فهارس قاعدة البيانات عند تشغيل عمليات التحسين الشاملة.
18. ما الفرق بين delete_transient() وحذفها عبر SQL المباشر؟
دالة delete_transient() تتعامل مع الموقع الحالي فقط وتدعم الكاش الكائني، بينما استعلام SQL المباشر على _transient_% يضمن مسح المؤقتات القديمة المنتهية الصلاحية من جدول wp_options دفعة واحدة.
19. كيف أتأكد من نجاح عملية الحذف واختبار ملف uninstall.php محلياً؟
عن طريق تثبيت الإضافة محلياً، وإنشاء بيانات تجريبية وفحص الجداول عبر phpMyAdmin، ثم حذف الإضافة من لوحة التحكم والتحقق من اختفاء الجداول والخيارات بالكامل.
20. ما هي القاعدة الذهبية التي يجب أن يتذكرها كل مبرمج ووردبريس؟
“اترك الموقع كما وجدته أو أفضل؛ الإضافة الممتازة هي التي تفيد الموقع أثناء عملها، وتختفي بسلام ونظافة تامة دون ترك أي ذرة غبار خلفها عند حذفها!”
التعامل مع القيود والمفاتيح الأجنبية (Foreign Keys) في جداول InnoDB
لو أنت بتبني أنظمة تخطيط موارد المؤسسات (ERP) أو منصات محاسبية متقدمة على ووردبريس، وبتستخدم محرك التخزين InnoDB مع علاقات المفاتيح الأجنبية (Foreign Key Constraints) بين الجداول المخصصة التابعة لإضافتك، ممكن تلاحظ إن تنفيذ أمر DROP TABLE يفشل أو يرمي خطأ:
Cannot drop table 'enterprise_orders' referenced by a foreign key constraint.
عشان تتفادى المشكلة دي أثناء تشغيل ملف uninstall.php، لازم تعطل فحص المفاتيح الأجنبية مؤقتاً قبل مسح الجداول وترجع تفعلها فوراً بعد الانتهاء، بالشكل المعماري ده:
query("SET FOREIGN_KEY_CHECKS = 0;");
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}enterprise_order_items;");
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}enterprise_orders;");
// إعادة تفعيل فحص القيود فوراً لضمان سلامة باقي جداول الموقع
$wpdb->query("SET FOREIGN_KEY_CHECKS = 1;");
التقنية دي بتضمن حذف سلس وخالي من أي استثناءات، وبتحافظ في نفس الوقت على سلامة قواعد البيانات دون التأثير على أي جداول تابعة لووردبريس نفسه أو لإضافات أخرى.


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