استبدال رابط الموقع في قاعدة بيانات WordPress دون إتلاف البيانات المتسلسلة
غيّر رابط موقع WordPress في قاعدة البيانات دون أن تفرغ الودجات أو القوائم أو إعدادات القالب. استخدم أمر WP-CLI الذي يحافظ على البيانات المتسلسلة سليمة.
نُشر
لا تشغّل أمر UPDATE ... SET column = REPLACE(column, 'oldurl', 'newurl') عاريًا على قاعدة بيانات WordPress. سيغيّر النص بشكل صحيح ويدمّر إعداداتك في الوقت نفسه، لأن WordPress يخزّن المصفوفات والكائنات كنصوص متسلسلة بصيغة PHP، وهذه الصيغة تسجّل طول كل نص تحتويه بالبايت. الاستبدال الخام في SQL يعيد كتابة النص لكنه لا يمسّ الطول المسجَّل أبدًا، فتصبح القيمة غير قابلة للقراءة.
استخدم أداة مدركة للتسلسل بدلًا من ذلك. على سطر الأوامر هي wp search-replace. خذ نسخة احتياطية من قاعدة البيانات أولًا، وشغّلها كتجربة، ثم شغّلها فعليًا.
ما الذي يتعطّل بالضبط
النص المتسلسل بصيغة PHP يبدو هكذا:
s:18:"http://example.com"
الرقم 18 هو طول النص التالي بالبايت. عُدّها — http://example.com يساوي 18 محرفًا بالضبط.
تخيّل الآن إعداد قالب مخزّنًا:
a:1:{s:4:"logo";s:18:"http://example.com";}
شغّل استبدالًا عاديًا في SQL من http:// إلى https:// فتحصل على:
a:1:{s:4:"logo";s:19:"https://example.com";}
إلا أنك لا تحصل على ذلك. بل تحصل على هذا:
a:1:{s:4:"logo";s:18:"https://example.com";}
صار طول النص 19 بايتًا لكنه ما زال يدّعي أنه 18. يقرأ PHP الطول المعلن، ويمشي 18 بايتًا إلى الأمام، فلا يجد علامة الاقتباس والفاصلة المنقوطة حيث يتوقعهما، فيستسلم. وتفشل المصفوفة كلها في فك التسلسل.
لماذا يفشل بصمت
هنا يصبح هذا الخلل باهظ الثمن. لا يطلق WordPress خطأً ولا يتوقف. حين يقرأ خيارًا يمرّر القيمة عبر مساعد فك التسلسل لديه، فيعيد PHP القيمة false للبيانات المشوّهة، ويسلّم WordPress شيفرتك قيمةً تتصرف كأن الخيار لم يُضبط قط. فترتدّ الإضافة أو القالب إلى قيمها الافتراضية.
إذن العَرَض ليس صفحة خطأ. العَرَض هو:
- اختفاء الودجات من الأشرطة الجانبية
- ارتداد إعدادات المخصص إلى افتراضيات القالب
- عودة بيانات تخطيط منشئ الصفحات فارغة وعرض الصفحة خالية
- ظهور صفحات إعدادات الإضافات كأنها مثبتة للتو
- فقدان القوائم لمواضعها المعيّنة
لا شيء في لوحة التحكم يشير إلى خلل. الصف ما زال في قاعدة البيانات، وما زال ممتلئًا بما يبدو نصًا صحيحًا. الطول المُسبَق وحده مخطئ ببايت أو اثنين. صحيح أن PHP يصدر تنبيهًا عند فشل فك التسلسل، لكن على موقع إنتاجي مع تعطيل عرض الأخطاء لا يراه أحد. تفعيل WP_DEBUG مع WP_DEBUG_LOG وضبط WP_DEBUG_DISPLAY على false يضع تلك التنبيهات في ملف سجل يمكنك قراءته.
والضرر ليس موزّعًا بالتساوي أيضًا. القيم البسيطة المفردة — siteurl وhome ومحتوى المقالات العادي ورابط يجلس في عموده الخاص — تنجو من الاستبدال الساذج تمامًا. القيم المتسلسلة وحدها هي التي تنكسر. لهذا يبدو الاستبدال السيئ ناجحًا للوهلة الأولى.
افحص wp-config.php قبل أن تمسّ أي شيء
إذا عرّف wp-config.php الثابتين WP_HOME أو WP_SITEURL فإنهما يتغلبان على كل ما في قاعدة البيانات. وتعديل wp_options سيبدو بلا أثر إطلاقًا. ابحث عن أسطر كهذه قبل أن تستنتج أن المشكلة في قاعدة البيانات:
define( 'WP_HOME', 'http://example.com' );
define( 'WP_SITEURL', 'http://example.com' );
إما أن تحدّثهما إلى الرابط الجديد أو تحذفهما وتترك القيادة لقاعدة البيانات.
خذ نسخة احتياطية أولًا، وبجدّية
كسر التسلسل ليس دائمًا سهل التراجع. فبمجرد أن يختلف الطول المُسبَق عن المحتوى تصبح القيمة الأصلية غير قابلة للاستعادة من القيمة التالفة — لا يمكنك معرفة الطول الصحيح المفترض دون معرفة النص الأصلي. النسخة الاحتياطية هي وسيلة التراجع الحقيقية الوحيدة.
wp db export backup-before-replace.sql
أو باستخدام mysqldump إن لم يتوفر WP-CLI:
mysqldump -u USER -p DBNAME > backup-before-replace.sql
احتفظ بها خارج الخادم إن استطعت. فالنسخة الاحتياطية القابعة في جذر الويب هي نقطة استعادة ومشكلة أمنية في آن واحد.
الأمر الآمن
أمر search-replace في WP-CLI يفك تسلسل كل قيمة، ويمشي في البنية المفكوكة، ويستبدل داخلها، ثم يعيد التسلسل بأطوال صحيحة. جرّبه أولًا:
wp search-replace 'http://example.com' 'https://example.com' --dry-run --all-tables --skip-columns=guid
اقرأ التقرير. يخبرك بعدد الاستبدالات التي ستحدث في كل جدول وعمود. إذا بدت قائمة الجداول غريبة، أو ظهر جدول لا تعرفه بآلاف النتائج، توقّف وتفحّص قبل التشغيل الفعلي.
ثم شغّله:
wp search-replace 'http://example.com' 'https://example.com' --all-tables --skip-columns=guid --report-changed-only
ملاحظات صريحة على الرايات:
--all-tablesيغطي جداول لا يسجّلها WordPress بنفسه، وهي غالبًا حيث تسكن بيانات الإضافات. بدونها تُتجاوَز بعض جداول الإضافات كليًا.--skip-columns=guidمهمة. فعمودguidمعرّف دائم لقارئات الخلاصات لا رابط حيّ. إعادة كتابته قد تجعل المشتركين يرون أرشيفك كله كمقالات جديدة.- ابحث دون الشرطة المائلة الأخيرة ودون صيغ البروتوكول التي لا تريد المساس بها. فاستبدال
example.comالمجرّد سيصيب أيضًا عناوين البريد وأي ذكر لها في نص المقالات.
إن تعذّر عليك استخدام سطر الأوامر، فإضافات الترحيل المدركة للتسلسل تؤدي عمل فك التسلسل نفسه من لوحة التحكم. السلوك الذي تبحث عنه موصوف صراحةً بأنه يتعامل مع البيانات المتسلسلة؛ وإن لم تذكر الأداة ذلك فافترض أنها لا تفعله.
ما الجداول والأعمدة المعنية
| الجدول | العمود | خطر التسلسل |
|---|---|---|
| wp_options | option_value | مرتفع — الودجات وتعديلات القالب والبيانات المؤقتة ومعظم إعدادات الإضافات |
| wp_postmeta | meta_value | مرتفع — تخطيطات منشئ الصفحات ومصفوفات الحقول المخصصة |
| wp_usermeta | meta_value | مرتفع — الصلاحيات وتفضيلات الشاشة ولوحة التحكم |
| wp_termmeta | meta_value | متوسط — يعتمد على الإضافات |
| wp_posts | post_content, guid | منخفض للمحتوى، لكن معاملات الأكواد المختصرة وشيفرة الكتل تحمل روابط |
| wp_comments | comment_content, comment_author_url | منخفض |
| wp_links | link_url, link_image | منخفض، وغالبًا غير مستخدم |
في الشبكة المتعددة أضف wp_blogs وwp_site وwp_sitemeta، وجداول كل موقع مثل wp_2_options وwp_3_options وهكذا. تغيير الروابط في الشبكة المتعددة له قواعد إضافية تتجاوز البحث والاستبدال — عامله كمهمة منفصلة.
الحالات التي لا يحلّها search-replace كليًا
بصراحة عن الحدود:
بيانات JSON المخزّنة داخل قاعدة البيانات. بعض منشئي الصفحات يخزّنون بيانات التخطيط كـ JSON مع تهريب الشرطات المائلة، فيظهر رابطك بصيغة https:\/\/example.com بدل https://example.com. البحث عن الصيغة العادية سيفوّته. قد تحتاج تمريرة ثانية على النص المهرَّب. اختبر على نسخة.
القيم المشفّرة بـ Base64. إذا شفّرت إضافة إعداداتها قبل تخزينها فلن يرى أي استبدال نصي الرابط إطلاقًا. تلك الإعدادات تحتاج عادةً إلى إعادة إدخالها من شاشة الإضافة نفسها.
الروابط المكتوبة يدويًا في الملفات. أي شيء كُتب داخل functions.php أو قالب في قالب فرعي أو مسار أصل ثابت ليس في قاعدة البيانات ولن يُمسّ. افحص مجلد القالب بأداة بحث نصي على حدة.
المخرجات المخزنة مؤقتًا والمولَّدة. ذاكرة الكائنات المؤقتة وذاكرة الصفحات ونسخ شبكة التوزيع تستمر في تقديم الروابط القديمة بعد استبدال صحيح. امسحها ثم افحص مجددًا قبل أن تفترض فشل الاستبدال.
إن كنت قد شغّلت الاستعلام السيئ فعلًا
استعد النسخة الاحتياطية. هذا هو الجواب، ومن الأفضل قوله بوضوح بدل عرض إجراء إصلاح لا ينجح في أغلب الأحوال.
وإن لم تكن هناك نسخة احتياطية فالمسار القابل للاستعادة ضيّق: القيم التي لم تكن متسلسلة أصلًا بخير، أما المتسلسلة التالفة فيجب إعادة بنائها يدويًا أو تصفيرها بإعادة حفظ شاشة الإعدادات المعنية. إعادة حفظ منطقة ودجات، أو إعادة اختيار موضع قائمة، أو إعادة إدخال إعدادات إضافة، كلها تكتب قيمة جديدة متسلسلة بشكل صحيح فوق التالفة. مُرهِق، لكنه ينجح، وهو أفضل من ترك صفوف تالفة في مكانها لتربك من ينظر في الموقع لاحقًا.
ولتوليد العبارات الصحيحة قبل تشغيل أي شيء، ابنِها عبر أداة البحث والاستبدال في WordPress — فهي تبيّن أي الأعمدة آمن للمساس به بـ SQL عادي وأيها يتطلب معالجة مدركة للتسلسل، لترى الفرق قبل أن تلتزم بأمر معيّن.
FAQ
أسئلة
لماذا يُعطّل أمر REPLACE في SQL موقع WordPress؟
لأن WordPress يخزّن المصفوفات والكائنات كنص متسلسل بصيغة PHP، وهذه الصيغة تسجّل طول كل نص بالبايت داخلها. أمر REPLACE الخام يغيّر النص لكنه يترك رقم الطول القديم كما هو. عندها يرفض PHP فك التسلسل، فيلجأ WordPress إلى القيمة الافتراضية، وتظهر الإعدادات فارغة لا خاطئة.
ما أسلم طريقة لتغيير رابط موقع WordPress في قاعدة البيانات؟
خذ نسخة احتياطية كاملة من قاعدة البيانات، ثم شغّل أمر WP-CLI wp search-replace بوضع التجربة أولًا. يفك WP-CLI تسلسل كل قيمة، ويستبدل داخل البنية المفكوكة، ثم يعيد تسلسلها بأطوال مصححة. وإضافات الترحيل المدركة للتسلسل تؤدي المهمة نفسها من لوحة التحكم إن لم يتوفر لك سطر الأوامر.
ما الجداول التي تحتوي الرابط القديم؟
أساسًا wp_options و wp_posts و wp_postmeta و wp_usermeta و wp_termmeta و wp_comments. أما خطر التسلسل فيسكن في wp_options وفي أي عمود meta_value، لأن الودجات وتعديلات القالب والبيانات المؤقتة وبيانات منشئ الصفحات كلها مخزّنة كمصفوفات. وفي الشبكة المتعددة تحمل wp_blogs و wp_site و wp_sitemeta النطاق أيضًا.
هل يصلح تعديل قاعدة البيانات الرابط إذا كان wp-config.php يعرّفه؟
لا. إذا عرّف wp-config.php الثابتين WP_HOME أو WP_SITEURL فإنهما يتجاوزان أي قيمة في siteurl و home داخل wp_options. تعديل قاعدة البيانات لن يغيّر شيئًا مرئيًا حتى تُحدَّث تلك الثوابت أو تُحذف. افحص wp-config.php أولًا، فهذا السطر الواحد يفسّر كثيرًا من عمليات الترحيل الفاشلة.
هل أستبدل عمود guid أيضًا؟
لا. عمود guid معرّف دائم لقارئات الخلاصات وليس رابطًا عاملًا، وإعادة كتابته قد تجعل المشتركين يرون كل مقالاتك القديمة كأنها جديدة. مرّر skip-columns مع guid عند تشغيل WP-CLI. الاستثناء الوحيد الشائع موقع لم تكن له خلاصات عامة ولا مشتركون أصلًا.
كيف أعرف أن قيمة ما تلفت بعد استبدال خاطئ؟
القيم المتسلسلة التالفة تبدو طبيعية في قاعدة البيانات لكنها تعود فارغة داخل WordPress. تختفي الودجات، وتُصفَّر إعدادات المخصص، وترتد خيارات الإضافات إلى الافتراضي بلا أي رسالة خطأ. تفعيل WP_DEBUG و WP_DEBUG_LOG يُظهر تنبيه فشل فك التسلسل. ومقارنة الطول المعلن بعدد البايتات الحقيقي تؤكد ذلك مباشرة.