الانتقال إلى المحتوى
الخادم و .htaccess

المحتوى المختلط في WordPress بعد الانتقال إلى https

أزل تحذيرات المحتوى المختلط في WordPress بعد الانتقال إلى https: اعثر على روابط http المتبقية في قاعدة البيانات، واستبدلها بأمان، وافرض https في htaccess.

نُشر

شهادتك مثبّتة، والموقع يُحمَّل عبر https، والقفل ما زال يرفض الظهور. هذا هو المحتوى المختلط: الصفحة نفسها وصلت عبر https، لكن شيئًا بداخلها — صورة، أو ورقة أنماط، أو سكربت — ما زال يُطلب عبر http:// عاديًا. هذا الدليل يمرّ بك على إيجاد تلك الروابط، واستبدالها دون إفساد البيانات المتسلسلة، وتصحيح siteurl و home، وفرض https على مستوى الخادم حتى لا تعود المشكلة.

ما هو المحتوى المختلط فعلًا

تثبيت الشهادة يغيّر طريقة تشفير الاتصال. ولا يغيّر ما تطلبه صفحاتك. فكل http://yoursite.com/wp-content/uploads/logo.png كُتب في مقال أو مربع جانبي أو إعداد قالب قبل الانتقال ما زال جالسًا في قاعدة البيانات، والمتصفح يطلبه بكل طاعة عبر اتصال غير آمن.

المتصفحات تعامل فئتين معاملة مختلفة، والتفرقة تهمّ حين تقرّر مدى إلحاح المشكلة:

  • المحتوى المختلط النشط — السكربتات وأوراق الأنماط والإطارات المضمّنة و XHR. يُحجب تمامًا. ولهذا قد يبدو موقع مكسورًا بعد الانتقال إلى https دون أي رسالة خطأ في أي مكان: ورقة أنماط رُفضت في صمت.
  • المحتوى المختلط السلبي — الصور والصوت والفيديو. يُحمَّل عادةً، لكن القفل يُخفَّض وبعض المتصفحات تعرض مؤشر «غير آمن».

كلاهما يستحق الإصلاح. الأول وحده هو الذي يكسر الأشياء.

الخطوة 1: اكتشف ما زال غير آمن

ابدأ من المتصفح. افتح الصفحة، وافتح أدوات المطوّر، واقرأ وحدة التحكم. فكل طلب محجوب أو مخفَّض يُذكر هناك برابطه الكامل. هذا يخبرك ماذا هو غير آمن؛ ولا يخبرك أين هو مخزّن.

ولذلك انظر في قاعدة البيانات مباشرة. صدّرها وابحث في الملف المصدَّر:

wp db export dump.sql
grep -o "http://example\.com[^\"']*" dump.sql | sort -u | head -50

وإن لم يكن WP-CLI متاحًا، فـ mysqldump ينتج الملف نفسه:

mysqldump -u USER -p DBNAME > dump.sql

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

الخطوة 2: أصلح siteurl و home أولًا

siteurl و home هما الخياران اللذان يستخدمهما WordPress لبناء كل رابط داخلي يولّده تقريبًا. فإن كان أيّهما ما زال يقول http://، سيظل WordPress يُصدر روابط غير آمنة مهما كانت بقية قاعدة البيانات نظيفة.

افحصهما:

wp option get siteurl
wp option get home

أو عبر sql:

SELECT option_name, option_value
FROM wp_options
WHERE option_name IN ('siteurl', 'home');

هذان الاثنان نصان بسيطان لا مصفوفتان متسلسلتان، فالتحديث المباشر عبر sql آمن هنا فعلًا:

UPDATE wp_options
SET option_value = REPLACE(option_value, 'http://example.com', 'https://example.com')
WHERE option_name IN ('siteurl', 'home');

فخ واحد قبل أن تضيّع وقتك في هذا. إن كان wp-config.php يعرّف WP_HOME أو WP_SITEURL، فهذان الثابتان يتجاوزان قاعدة البيانات تمامًا وسيبدو تحديثك بلا أثر:

define( 'WP_HOME', 'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );

حدّثهما هناك، أو احذفهما ودع قاعدة البيانات تقود. افحص هذا أولًا — فهو يفسّر كثيرًا من حالات «غيّرته ولم يحدث شيء».

الخطوة 3: يجب أن يكون الاستبدال آمنًا على التسلسل

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

فـ WordPress يخزّن المصفوفات والكائنات كنصوص متسلسلة بصيغة php، وتلك الصيغة تسجّل طول كل نص تحتويه بالبايت:

a:1:{s:4:"logo";s:38:"http://example.com/img/logo.png";}

غيّر http:// إلى https:// باستبدال sql خام فيصير النص أطول ببايت واحد بينما يبقى الطول المعلن على قيمته القديمة. يقرأ php الطول، ويمشي ذلك العدد من البايتات، فلا يجد المُنهي حيث يتوقعه، فيرفض فكّ تسلسل المصفوفة كلها. عندها يسلّم WordPress القالب أو الإضافة قيمة تتصرف كأن الإعداد لم يُحفظ قط.

والعَرَض ليس رسالة خطأ. بل مربعات جانبية تختفي، وإعدادات مخصّص تعود إلى أصلها، وتخطيطات منشئ الصفحات تُعرض فارغة — دون أي شيء في لوحة الإدارة يشير إلى أن خطأً وقع. والتعافي من ذلك دون نسخة احتياطية مؤلم فعلًا، فخذ واحدة:

wp db export backup-before-https-replace.sql

ثم استخدم أداة تفكّ التسلسل، وتستبدل داخل البنية المفكوكة، وتعيد التسلسل بأطوال مصحّحة. جرّب على الجاف أولًا:

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

و --skip-columns=guid مهم: فـ guid معرّف دائم لقارئات الخلاصات، لا رابط حيّ، وإعادة كتابته قد تجعل المشتركين يرون أرشيفك كله كمقالات جديدة. وإن احتجت إلى معرفة أي الأعمدة آمن لـ sql البسيط وأيها يتطلب معالجة واعية بالتسلسل قبل أن تشغّل أي شيء، فابنِ الجمل بـ أداة البحث والاستبدال sql لـ WordPress.

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

الخطوة 4: افرض https على مستوى الخادم

تنظيف قاعدة البيانات يمنع صفحاتك من طلب موارد غير آمنة. لكنه لا يمنع زائرًا من الوصول عبر http:// من الأساس. وهذا إعادة توجيه على مستوى الخادم، وموضعها في Apache هو .htaccess:

# BEGIN Force HTTPS
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
# END Force HTTPS

أمران عن الموضع. ضع هذا فوق علامات # BEGIN WordPress — فكل ما بداخلها يُتخلص منه كلما حفظ أحدهم الروابط الدائمة. وهذا لا يعمل إلا إذا كان mod_rewrite مفعّلًا وكان المضيف الافتراضي يسمح بالتجاوزات (AllowOverride All، أو FileInfo على الأقل). وعلى nginx يُتجاهل .htaccess كليًا وهذا يحتاج إلى الوضع في كتلة الخادم بدلًا منه.

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

حلقة إعادة التوجيه، ولماذا تحدث

إن بدأ الموقع يعيد التوجيه إلى ما لا نهاية لحظة إضافتك تلك القاعدة، فإن TLS لديك ينتهي في مكان أعلى السلسلة — موزّع أحمال، أو وسيط عكسي، أو شبكة توزيع محتوى — ثم يمرّر http عاديًا إلى Apache. فيرى Apache طلبًا غير آمن، ويوجّه إلى https، فيمرّر الوسيط http مجددًا، وهكذا تدور.

اختبر الترويسة الممرَّرة بدلًا من ذلك:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

و WordPress نفسه لديه النقطة العمياء ذاتها في ذلك الإعداد — فـ is_ssl() يقرأ $_SERVER['HTTPS']، والوسيط لا يضبطه أبدًا، فتخرج روابط الإدارة بصيغة http://. أضف هذا إلى wp-config.php، فوق سطر «توقّف عن التحرير»:

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
	$_SERVER['HTTPS'] = 'on';
}

ويجدر الوضوح بشأن الخطر: X-Forwarded-Proto ترويسة يرسلها العميل. والثقة بها صحيحة فقط حين يكون هناك وسيط تتحكم فيه يعيد كتابتها دائمًا. أما على خادم يمكن الوصول إليه مباشرة من الإنترنت، فيمكن تزويرها.

ما لن يصلحه استبدال قاعدة البيانات

  • روابط مكتوبة يدويًا في الملفات. أي شيء كُتب في functions.php، أو في قالب طفل، أو كمسار أصل مضمّن ليس في قاعدة البيانات. فتّش مجلد القالب على حدة.
  • JSON مهروب. بعض المنشئين يخزّنون الروابط بصيغة https:\/\/example.com. والبحث عن الصيغة العادية يفوتها تمامًا، فقد تحتاج إلى مرور ثانٍ على النص المهروب.
  • الموارد الخارجية. سكربت أو تضمين من طرف ثالث متاح عبر http فقط لا يمكن إصلاحه من جهتك. ابحث عن نسخة عبر https أو تخلّ عنه.
  • ذواكر التخزين المؤقت. ذاكرة الصفحات، وذاكرة الكائنات، ونسخ شبكة التوزيع تستمر في تقديم الترميز القديم بعد استبدال صحيح. أفرغ الثلاثة قبل أن تستنتج أن الاستبدال فشل.

وشيء واحد يستحق التخطي: ترويسة سياسة أمان المحتوى upgrade-insecure-requests ستُسكت التحذيرات بإعادة كتابة الطلبات غير الآمنة في المتصفح. لكنها تعالج العَرَض وتترك الروابط الخاطئة في قاعدة بياناتك، حيث سيحملها التصدير أو الترحيل أو الخلاصة التالية معها. أصلح البيانات، ثم استخدمها كشبكة أمان إن أردت.

ما زلت عالقًا؟

أعد فحص siteurl و home بعد كل خطوة — فالإضافات وأدوات الترحيل تعيد كتابتهما أحيانًا من خلفك. وإن ظلت وحدة التحكم تسمّي رابطًا غير آمن لا تجده في الملف المصدَّر، فاعرض مصدر الصفحة وابحث عنه هناك: فإن ظهر في الترميز المولَّد ولم يظهر في قاعدة البيانات، فهو يُبنى في php، والقالب أو الإضافة التي تنتجه هي ما يجب إصلاحه.

FAQ

أسئلة

لماذا ما زال موقعي على WordPress يعرض تحذيرات محتوى مختلط بعد تثبيت شهادة SSL؟

الشهادة تغيّر طريقة تشفير الاتصال فقط، لا ما تطلبه صفحاتك. فروابط http القديمة تبقى مخزّنة في قاعدة البيانات، داخل محتوى المقالات وخيارات المربعات الجانبية وإعدادات القالب. يحمّل المتصفح الصفحة عبر https، فيرى صورة أو سكربتًا يُطلب عبر http عادي، فيبلّغ عن محتوى مختلط في صفحة آمنة من كل وجه آخر.

كيف أعثر على روابط http التي ما زالت في قاعدة بيانات WordPress؟

افتح صفحة في المتصفح واقرأ وحدة تحكم المطوّر، فهي تسمّي كل طلب غير آمن برابطه. ثم صدّر قاعدة البيانات وابحث في الملف المصدَّر عن نطاقك مع بادئة http. وعدّ النتائج في كل جدول يخبرك إن كانت المشكلة في محتوى المقالات، أم في wp_options، أم في جداول إضافات لم تكن تتوقعها.

هل أستطيع إصلاح المحتوى المختلط ببحث واستبدال sql بسيط؟

فقط للقيم البسيطة مثل siteurl و home. أما أي شيء يخزّنه WordPress كمصفوفة متسلسلة، وهو ما يشمل معظم قيم الخيارات والبيانات الوصفية، فيسجّل طول كل نص بداخله بالبايت. الاستبدال الخام يغيّر النص ويترك الطول القديم، فتفشل القيمة في فك التسلسل، ويعود الإعداد صامتًا إلى قيمته الافتراضية.

ما قاعدة htaccess التي تفرض https في WordPress؟

قاعدة RewriteRule محروسة بشرط على متغير https، توضع فوق علامات BEGIN WordPress حتى لا يمحوها حفظ الروابط الدائمة. وخلف وسيط أو شبكة توزيع محتوى يُقرأ متغير https على أنه معطّل حتى في الطلبات الآمنة، فاختبر ترويسة X-Forwarded-Proto بدلًا من ذلك وإلا أعادت القاعدة التوجيه إلى ما لا نهاية.

لماذا دخل موقعي في حلقة إعادة توجيه بعد فرض https؟

تشفير TLS لديك ينتهي شبه أكيد عند وسيط أو شبكة توزيع محتوى، ثم يمرّر ذلك الوسيط طلب http عاديًا إلى Apache. فترى قاعدة إعادة الكتابة طلبًا غير آمن، وتوجّه إلى https، فيمرّر الوسيط http مجددًا، وتتكرر الحلقة. بدّل الشرط إلى ترويسة X-Forwarded-Proto واضبط متغير الخادم https في wp-config.

هل يعطّل المحتوى المختلط الصفحة كلها أم القفل فقط؟

يعتمد على المورد. فالمتصفحات تحجب المحتوى المختلط النشط مثل السكربتات وأوراق الأنماط والإطارات المضمّنة حجبًا تامًا، وهذا قد يكسر التخطيط أو الوظائف دون تفسير ظاهر. أما المحتوى المختلط السلبي مثل الصور والفيديو فيُحمَّل عادةً، لكن القفل يُخفَّض وقد يرى الزوار مؤشر «غير آمن». وكلاهما يستحق الإصلاح.