WebGee Docsمركز المساعدة
ووردبريس

توجيه الروابط ذات الأحرف الكبيرة إلى صيغتها الصغيرة

الرابط بحرف كبير يأخذ مدخلًا خاصًا به في ذاكرة LiteSpeed ولا يصيبها في أي زيارة. قاعدة توجيه واحدة في Cloudflare تجمع كل الطلبات على رابط واحد بأحرف صغيرة.

اجعل كل طلب لموقعك ينتهي إلى رابط واحد بأحرف صغيرة، فيقدّم LiteSpeed نسخة مخزَّنة واحدة لكل صفحة بدل نسخة لكل صيغة من صيغ الأحرف.

تنطبق على أي موقع في الاستضافة المشتركة أو الموزِّعة أو المميّزة يقع خلف Cloudflare، وعلى أي خطة من خطط Cloudflare بما فيها المجانية. وتحتاج وصولًا إلى حساب Cloudflare الذي يستخدمه النطاق — انظر وضع موقعك خلف Cloudflare.

لماذا تُجزِّئ الأحرف الكبيرة ذاكرة التخزين

يبني LiteSpeed Cache مفتاح كل مدخل على مسار الطلب كنصٍّ حرفي، فهذان مدخلان منفصلان:

https://example.com/Blog/My-Great-Article
https://example.com/blog/my-great-article

الصفحة نفسها والمحتوى نفسه ووسم canonical نفسه — ومدخلان اثنان، يُسخَّن كلٌّ منهما على حدة.

وتصل الطلبات ذات الأحرف الكبيرة بلا انقطاع، من:

  • مسارات التصنيفات والوسوم وأنواع المحتوى المخصّصة التي أُنشئت بحرف كبير ولم تُوحَّد بعدها،
  • روابط داخلية قديمة كُتبت قبل ترتيب هذه المسارات،
  • روابط خارجية ونسخ منقولة حفظت الصيغة كما وردت في وسم og:url أو في رابط منسوخ،
  • فهرس Google، الذي يظلّ يطلب النصّ نفسه الذي زحف إليه. فوسم canonical يوحّد الفهرسة، لكنه لا يمنع وصول الطلب إلى الرابط المفهرَس.

والأخير هو الأغلى ثمنًا. فزيارات البحث التي تهبط على صيغة نادرة الطلب تخطئ الذاكرة، فتعيد PHP وMySQL بناء الصفحة في كل زيارة، بينما تجلس النسخة ذات الأحرف الصغيرة مخزَّنة وسريعة لا تخدم أحدًا تقريبًا. وبيانات Core Web Vitals الميدانية (CrUX) تُجمع من زيارات حقيقية، فتصير التجربة المقيسة لتلك الصفحة هي المسار البطيء غير المخزَّن.

ويسهل إغفال ذلك، لأن:

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

ولا يحوّل Apache ولا LiteSpeed الروابط إلى أحرف صغيرة من تلقاء نفسه، وذلك عن قصد: فالمسارات في لينكس حسّاسة لحالة الأحرف، والملفات الحقيقية تعتمد على ذلك.

تحقّق هل تعنيك المشكلة

نزّل سجلّ وصول خامًا واعرض الطلبات الناجحة لمسارات تحوي حرفًا كبيرًا وليست ملفات:

awk '$9 == 200 && $7 ~ /[A-Z]/ && $7 !~ /\./ {print $7}' example.com-ssl_log | sort | uniq -c | sort -rn | head -20

وكل مسار له عدد يُعتدّ به هو صفحة قُدِّمت من PHP لا من الذاكرة في كل تلك الزيارات.

وفي Google Search Console تظهر المشكلة نفسها في Performance → Pages: صفحة واحدة مذكورة مرتين بصيغتي أحرف مختلفتين.

أضف قاعدة التوجيه في Cloudflare

  1. في Cloudflare، اختر النطاق ثم افتح Rules → Overview.

    صفحة Rules Overview في Cloudflare مصفّاة على Redirect Rules، وزر Create rule في أعلى اليمين

  2. اختر Create rule ثم Redirect Rules.

  3. في Rule name اكتب اسمًا تعرفه لاحقًا، مثل UnifiedURLs.

  4. تحت If incoming requests match… اختر Custom filter expression.

  5. الصق هذا في صندوق التعبير. وإن ظهر لك البنّاء المرئي بدل صندوق النصّ، فاختر Edit expression في الزاوية للتحويل إلى النصّ.

    (http.request.uri.path contains "A" or http.request.uri.path contains "B" or http.request.uri.path contains "C" or http.request.uri.path contains "D" or http.request.uri.path contains "E" or http.request.uri.path contains "F" or http.request.uri.path contains "G" or http.request.uri.path contains "H" or http.request.uri.path contains "I" or http.request.uri.path contains "J" or http.request.uri.path contains "K" or http.request.uri.path contains "L" or http.request.uri.path contains "M" or http.request.uri.path contains "N" or http.request.uri.path contains "O" or http.request.uri.path contains "P" or http.request.uri.path contains "Q" or http.request.uri.path contains "R" or http.request.uri.path contains "S" or http.request.uri.path contains "T" or http.request.uri.path contains "U" or http.request.uri.path contains "V" or http.request.uri.path contains "W" or http.request.uri.path contains "X" or http.request.uri.path contains "Y" or http.request.uri.path contains "Z") and http.request.uri.path.extension eq ""

    والصيغة البديهية لهذا هي http.request.uri.path matches "[A-Z]"، غير أن المعامل matches يحتاج خطة Business أو Enterprise. وسلسلة contains تؤدّي العمل نفسه على كل الخطط.

  6. تحت Then… اضبط Type على Dynamic، والصق هذا في Expression:

    concat("https://", http.host, lower(http.request.uri.path))
  7. اضبط Status code على 301 - Permanent Redirect، وفعّل Preserve query string.

  8. تحت Place at اختر First. فالتوجيه ينبغي أن يقع قبل أن تشتغل أي قاعدة أخرى على رابط على وشك التغيّر.

  9. اختر Save.

نموذج Edit Single Redirect، وفيه تعبير التصفية المخصّص وتعبير التوجيه الديناميكي ورمز الحالة 301 وترتيب القاعدة

http.request.uri.path.extension eq "" هو شطر التعبير الذي يُبقي الملفات الحقيقية خارج التوجيه، وهو مهم. فمجلد الرفع مليء بأسماء مثل IMG_2024.jpg وBanner-Photo.png، ونظام الملفات حسّاس لحالة الأحرف — وتصغير تلك المسارات يحوّل صورًا عاملة إلى صفحات 404. فأبقِه. ويُستثنى موقع تنتهي روابطه بـ .html: فتلك الصفحات تُستبعد مع الملفات.

لماذا 301 لا 302

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

تأكّد أنه نجح

ينبغي أن يردّ الرابط ذو الأحرف الكبيرة الآن بتوجيه:

curl -sI https://example.com/Blog/My-Great-Article | head -n 3

ابحث عن HTTP/2 301 وعن location: https://example.com/blog/my-great-article.

ثم اطلب الرابط ذا الأحرف الصغيرة مرتين وتحقّق أنه مخزَّن:

curl -sI https://example.com/blog/my-great-article | grep -i litespeed

وينبغي أن يعيد الطلب الثاني x-litespeed-cache: hit — انظر التأكد من عمل LiteSpeed Cache.

ثم تأكّد أن ملفًا في اسمه أحرف كبيرة ما زال يُفتح. وينبغي أن يعيد هذا 200:

curl -so /dev/null -w '%{http_code}\n' https://example.com/wp-content/uploads/2026/01/IMG_2024.jpg

إن لم ينجح

  • الرابط ذو الأحرف الكبيرة ما زال يعيد 200. فالمضيف لا يمرّ عبر Cloudflare — إذ يحتاج سجلّ DNS إلى السحابة البرتقالية، وإلا لم تر القواعد هذه الزيارات. وتأكّد كذلك أن القاعدة تظهر Active.
  • صارت الصور 404. فاختبار الامتداد ناقص، أو سقطت الأقواس حول سلسلة or عند اللصق. فـ and أقوى ارتباطًا من or، ومن دون الأقواس ينطبق الاستثناء على contains "Z" الأخيرة وحدها. صحّح التعبير ثم امسح ذاكرة Cloudflare: فالتوجيه الخاطئ قد خُزِّن.
  • الموقع في حلقة توجيه. فثمّة ما يعيد الرابط ذا الأحرف الصغيرة إلى آخر بحرف كبير — إضافة، أو قاعدة في .htaccess، أو Site Address محفوظ في ووردبريس بحرف كبير. عالجه هناك لا بإزالة هذه القاعدة.
  • رابط ما زال يتصرّف بالطريقة القديمة بعد تعديل القاعدة. فالمتصفحات تحفظ 301 بشدّة. اختبر بـ curl أو في نافذة خاصة، لا في التبويب الذي كنت تستعمله.

لماذا لا يصلح هذا في .htaccess

المقطع المتداوَل لهذه المشكلة يستعمل خريطة إعادة كتابة:

RewriteMap lc int:tolower

وRewriteMap لا يصحّ إلا في سياق إعدادات الخادم أو المضيف الافتراضي، في Apache وLiteSpeed على السواء. وفي ملف .htaccess يعيد Apache خطأ 500، وفي الاستضافة المشتركة لا وصول لك إلى المستوى الذي يُسمح فيه بالتوجيه. ولا بديل يعمل من .htaccess وحده — فـ mod_rewrite لا يستطيع تغيير حالة أحرف نصٍّ بغير خريطة.

وإن لم يكن الموقع خلف Cloudflare، فافعلها في PHP. أنشئ wp-content/mu-plugins/ إن لم يكن موجودًا، واحفظ هذا في wp-content/mu-plugins/lowercase-urls.php. فالإضافات الواجبة تُحمَّل تلقائيًا ولا تحتاج تفعيلًا:

<?php
/**
 * Plugin Name: Lowercase URL redirect
 */
add_action( 'init', function () {
	if ( is_admin() || wp_doing_ajax() || 'GET' !== ( $_SERVER['REQUEST_METHOD'] ?? '' ) ) {
		return;
	}

	$parts = explode( '?', $_SERVER['REQUEST_URI'] ?? '', 2 );
	$path  = $parts[0];

	if ( $path === strtolower( $path ) || strpos( $path, '/wp-json/' ) === 0 ) {
		return;
	}

	wp_safe_redirect( strtolower( $path ) . ( isset( $parts[1] ) ? '?' . $parts[1] : '' ), 301 );
	exit;
} );

وهذا لا يعمل إلا مع الطلبات التي يتولّاها ووردبريس، فلا يمسّ الملفات في wp-content/uploads. وهو بديل احتياطي لا عوض: إذ يظلّ الطلب يصل إلى PHP، وهو العمل الذي تتجنّبه قاعدة Cloudflare من أصله.

مواضيع ذات صلة

في هذه الصفحة