كاش ووكومرس والسيرفر: لماذا لا تكفي إضافة الكاش؟ تشخيص خطوة بخطوة

سيرفر من مكعبات شفافة يرسل شعاعاً سريعاً إلى سلة تسوق، رمزاً لتسريع ووكومرس عبر الكاش

متجرك على WooCommerce بيفتح ببطء، والنصيحة اللي بتسمعها دايماً «غيّر الاستضافة» أو «ركّب إضافة كاش». الحقيقة إن متجرين على نفس نوع السيرفر ممكن واحد فيهم يرد في 30 جزء من الثانية والتاني في ثانية كاملة، والفرق كله في مين اللي بيرد على الزائر: الكاش ولا PHP.

المقال ده موجّه لصاحب متجر ووكومرس أو الفريلانسر اللي بيبنيه، في أي سوق عربي، والأرقام فيه بالدولار. هنبدأ بتشخيص تعمله بنفسك في خمس دقائق، وبعدين نرتب الإصلاحات حسب أثرها، وأغلبها ببلاش.

بصراحة: الأرقام في هذا المقال من اختبار معملي أجراه كاتب المصدر الأصلي على متجر تجريبي (WooCommerce 11.1 و600 منتج على PHP 8.3)، ومن قياسه لمتجرين حقيقيين. لم نكرر الاختبار بأنفسنا، فاقرأ الأرقام كنِسَب بين الإعدادات لا كوعود لمتجرك.

لماذا يبطؤ ووكومرس من الأساس؟

حين يطلب الزائر صفحة منتج لا توجد لها نسخة جاهزة، يشغّل السيرفر ووردبريس وWooCommerce والقالب وكل إضافة مفعّلة، ثم يبني الصفحة من قاعدة البيانات. في المتجر التجريبي احتاجت صفحة منتج واحدة تحميل 1,392 ملف PHP وتنفيذ 90 استعلاماً قبل أن يخرج أول بايت.

التخزين المؤقت للصفحات (Page Cache) يتخطى هذا كله ويرسل نسخة HTML محفوظة. لذلك لا تُقاس سرعة المتجر بقوة السيرفر وحدها، بل بعدد المرات التي يُجبَر فيها على البناء.

المقياس الذي يكشف ذلك هو زمن الاستجابة الأول (TTFB): كل ما يحدث قبل وصول أول بايت، من البحث عن النطاق والاتصال والتشفير إلى عمل السيرفر نفسه. تعدّ Google الزمن جيداً عند 800 جزء من الثانية أو أقل، ولا يبدأ قياس LCP (ظهور أكبر عنصر في الصفحة) إلا بعد انتهائه.

ملاحظة: إذا كان زوار متجرك في القاهرة أو الرياض والسيرفر في أمريكا، فالمسافة وحدها قد تأكل بضع مئات من أجزاء الثانية قبل أن يبدأ السيرفر عمله. سيرفر في أوروبا (فرانكفورت مثلاً) مع CDN قريب يترك للسيرفر حصة أكبر من الـ 800.

وبحسب بيانات HTTP Archive التي ينقلها كاتب المصدر لشهر أغسطس 2026، حقق 12.7% فقط من مواقع WooCommerce زمن استجابة جيداً على الموبايل، مقابل 81.9% من متاجر Shopify. السبب أن Shopify يدير السيرفر والكاش لكل المتاجر، أما في ووكومرس فصاحب المتجر هو من يختار.

شخّص متجرك بثلاثة طلبات

قبل أي إصلاح تحتاج رقمين: ما يحصل عليه الزائر فعلاً، وما يحتاجه السيرفر حين يبني الصفحة بنفسه. الرقم الثاني قريب جداً مما تكلّفه صفحات السلة والدفع وحسابي، لأن ووكومرس لا يسمح بتخزينها أصلاً.

من الطرفية (Terminal)، ضع رابط أكثر منتج مبيعاً عندك بدل الرابط التجريبي، وشغّل الأمر الأول مرتين لأن الطلب الأول قد يملأ الكاش فقط:

# What a shopper gets: the cached page
curl -o /dev/null -s -w 'first byte: %{time_starttransfer}sn' https://shop.example.com/product/blue-mug/

# What PHP needs: an address no cache has stored yet
curl -o /dev/null -s -w 'first byte: %{time_starttransfer}sn' "https://shop.example.com/product/blue-mug/?nocache=$RANDOM"

ثم أضف طلباً ثالثاً بنفس الرابط مع ?gclid= وقيمة عشوائية، كأنه نقرة من إعلان Google. اقرأ النتائج الثلاث هكذا:

النتيجةمعناها
الرابط العادي سريع (أقل من 100ms تقريباً)الكاش يعمل للزوار العاديين
رابط nocache بطيء جداًهذا ما تدفعه السلة والدفع وكل زائر يفوته الكاش
رابط gclid بطء رابط nocache نفسهكل نقرة إعلانية مدفوعة تنتظر PHP — وهذا إعداد يُصلح

بدون طرفية: افتح الصفحة في نافذة Incognito في Chrome، واضغط F12 ثم تبويب Network وأعد التحميل. الصف الذي نوعه document هو الصفحة، وفي تبويب Timing تجد «Waiting for server response». وفي تبويب Headers تعرف من الذي ردّ: cf-cache-status: HIT يعني Cloudflare، وx-litespeed-cache: hit يعني LiteSpeed Cache.

تشخيص في 5 دقائق

ثلاثة طلبات تكشف بطء متجرك

قارن النتائج قبل أن تغيّر الاستضافة

  1. الرابط العادي

    ما يحصل عليه الزائر. سريع يعني أن كاش الصفحات يعمل.

  2. الرابط مع nocache

    PHP يبني الصفحة من الصفر، وهو قريب مما تكلفه السلة والدفع.

  3. الرابط مع gclid

    نقرة إعلان. إن ساوت nocache فالكاش لا يتجاهل معاملات الإعلانات.

  4. ترويسات الرد

    cf-cache-status أو x-litespeed-cache تخبرك أي كاش ردّ.

ابن موقعك قطعة قطعةarabcms.com

الإصلاحات المجانية أولاً: OPcache وكاش واحد فقط

تأكد من تشغيل OPcache

OPcache يحفظ كود PHP المترجم في الذاكرة بدل ترجمة كل الملفات مع كل طلب. في الاختبار نزلت صفحة المنتج على نواة واحدة من 473 إلى 100 جزء من الثانية بتشغيله وحده، وارتفع عدد الصفحات في الثانية من 1.9 إلى 9 تقريباً.

أغلب الاستضافات تشغّله، لكن بعض الباقات الرخيصة لا تفعل، ولن تجد له أثراً في لوحة ووردبريس. في cPanel افتح Select PHP Version وابحث عن opcache بين الإضافات المفعّلة، أو اسأل الدعم الفني صراحةً إن كان opcache.enable يساوي 1 لموقعك.

إصدار PHP: الأمان قبل السرعة

فرق السرعة بين PHP 7.4 و8.3 في الاختبار كان بين 2% و9% فقط. السبب الأقوى للترقية هو الأمان: PHP 8.1 خرج من الدعم الأمني، وPHP 8.2 يتلقى آخر تحديثاته الأمنية في 31 ديسمبر 2026 بحسب جدول php.net. تجد إصدارك في WooCommerce ← Status، وجرّب الترقية إلى 8.3 أو 8.4 على نسخة تجريبية (Staging) أولاً.

كاش صفحات واحد، في أقرب مكان للزائر

كلما ردّ الكاش مبكراً، وفّر عملاً أكثر. ترتيب الطبقات من الأبطأ للأسرع:

  • إضافة تشغّل PHP ثم تتخطى ووردبريس: مثل Cache Enabler، أو WP Rocket على سيرفر nginx. ردّت في الاختبار خلال 1.7 جزء من الثانية.
  • كاش يرد قبل PHP: WP Rocket على Apache عبر .htaccess، أو LiteSpeed Cache على سيرفر LiteSpeed، أو كاش الاستضافة المبني على Varnish أو nginx (1.1 جزء من الثانية في الاختبار).
  • كاش CDN مثل Cloudflare: يرد من مركز بيانات قريب من الزائر.

تنبيه: لا تشغّل كاشين للصفحات معاً. إضافتان، أو إضافة فوق كاش الاستضافة، تزيدان فرص بقاء نسخة قديمة بعد المسح. إن كانت استضافتك تخزّن الصفحات، أطفئ خيار Page Cache في WP Rocket واحتفظ بميزاته الأخرى مثل تأخير JavaScript.

نقرات الإعلانات التي تفوت الكاش

كل نقرة من Google Ads تصل برابط فيه gclid فريد، ومن Meta بـ fbclid، ومن الحملات بـ utm_source. الكاش الذي يخزن الصفحات حسب الرابط الكامل يعامل كل رابط منها كصفحة جديدة، فينتظر الزائر الذي دفعت ثمنه أطول من غيره.

  • WP Rocket: يتجاهل قائمة طويلة من هذه المعاملات افتراضياً.
  • LiteSpeed Cache: أضفها في تبويب Cache داخل خانة Drop Query String: fbclid وgclid وutm*.
  • Cloudflare: راجع ما تفعله قاعدة الكاش بالـ Query String، لأن الرابط الكامل هو مفتاح الكاش افتراضياً، وخيارات استثناء معاملات بعينها تختلف حسب الباقة.

لا تُبقِ الصفحة في الكاش أكثر من 12 ساعة إن كان فيها Nonce

بعض الإضافات، خاصة بوابات الدفع، تضع في الصفحة رمز أمان (Nonce) ترسله لاحقاً للسيرفر. ووردبريس لا تقبل الرمز بعد 24 ساعة، وتضمن صلاحيته 12 ساعة فقط. في أحد المتجرين الحقيقيين كانت النسخة المخزنة عمرها 36 ساعة، فكان طلب تجهيز أزرار الدفع يُرفض بخطأ 403 في كل زيارة.

للتأكد: افتح مصدر الصفحة بـ Ctrl+U وابحث عن nonce. إن وُجد، اجعل عمر الكاش أقل من 12 ساعة (ولهذا يضبط WP Rocket عمره الافتراضي على 10 ساعات)، أو امسح الكاش مرتين يومياً على الأقل.

الصفحات التي لن يلحقها الكاش أبداً

هنا يعيش البطء الحقيقي في أي متجر: السلة وصفحة الدفع وحسابي، والعملاء المسجلون الدخول، وأحياناً كل من في سلته منتج. في الاختبار ظلت صفحة السلة تأخذ 133 جزءاً من الثانية بينما صفحات المنتجات تخرج من الكاش في جزء واحد تقريباً. أفضل عملائك يحصلون على النسخة الأبطأ.

أوقف طلب Cart Fragments حيث لا حاجة له

أجزاء السلة (Cart Fragments) سكربت يحدّث عدد المنتجات في رأس الصفحة عبر طلب إلى ?wc-ajax=get_refreshed_fragments لا يمر بأي كاش. بحسب مدونة مطوري WooCommerce، توقف تحميله في كل الصفحات منذ الإصدار 7.8، وصار يُحمَّل فقط حيث تظهر أداة السلة الكلاسيكية (Cart Widget). المشكلة أن قوالب كثيرة، منها Storefront نفسه، تضع الأداة في رأس كل صفحة.

الطلب لا يؤخر ظهور الصفحة، لكنه يشغل عمليات PHP التي تحتاجها السلة والدفع، وغالباً في أسوأ توقيت: لحظة وصول زوار حملة إعلانية. ثلاث طرق لإيقافه، من الأنظف للأسرع:

  1. استبدل الأداة بكتلة Mini-Cart: النسخة المبنية بالكتل لا تستخدم Cart Fragments، وتجدها في محرر الموقع (Site Editor) في القوالب المبنية بالكتل.
  2. من إضافة تحسين الأداء: مثل خيار Disable Cart Fragmentation في إعدادات WooCommerce داخل Perfmatters.
  3. بكود قصير: يُبقي السكربت في الصفحة لكنه لا يشغّله إلا إذا وجد ملف تعريف الارتباط woocommerce_cart_hash، الذي يضعه ووكومرس عند إضافة منتج للسلة. أضفه بإضافة WPCode المجانية أو في functions.php للقالب الفرعي:
// Load WooCommerce cart fragments only for shoppers who have something in the cart.
// The check runs in the browser, so it also works on pages served from a page cache.
add_filter( 'script_loader_tag', function ( $tag, $handle ) {
    if ( 'wc-cart-fragments' !== $handle || is_cart() || is_checkout() ) {
        return $tag;
    }
    $loader = <<<'LOADER'
<script>
(function () {
    function load() {
        var held = document.querySelector('script[data-cart-src]');
        if (!held || !/(^|;s*)woocommerce_cart_hash=/.test(document.cookie)) return;
        var s = document.createElement('script');
        s.src = held.getAttribute('data-cart-src');
        held.removeAttribute('data-cart-src');
        document.head.appendChild(s);
    }
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', load);
    } else {
        load();
    }
    document.addEventListener('click', function () { setTimeout(load, 1000); });
})();
</script>
LOADER;
    return str_replace( ' src=', ' data-cart-src=', $tag ) . $loader;
}, 10, 2 );

تنبيه: اختبر النتيجة في نافذة Incognito جديدة، لا في تبويب أعدت تحميله. السكربت يحفظ الأجزاء في sessionStorage ويتخطى الطلب بعد أول زيارة، فقد تظن أنه متوقف وهو ليس كذلك. اكتب wc-ajax في فلتر Network، وافتح صفحة منتج وتوقع ألا ترى شيئاً، ثم أضف منتجاً وتوقع طلباً واحداً.

Redis: متى يفيد ومتى لا

كاش الكائنات (Object Cache) يحفظ نتائج الاستعلامات في الذاكرة. في المتجر التجريبي قلّصت إضافة Redis Object Cache استعلامات صفحة المنتج من 90 إلى 26، لكن الصفحة لم تتسرّع تقريباً، لأن قاعدة البيانات على نفس الجهاز كانت ترد بسرعة أصلاً. مع 15 إضافة مفعّلة صار الفرق نحو 8%.

القرار العملي: فعّل Redis فقط إن كانت استضافتك توفره، وتوقع فائدته في السلة والدفع ولوحة التحكم، وأكبرها حين تكون قاعدة البيانات على سيرفر منفصل. بعد التثبيت تأكد من ظهور Connected في Settings ← Redis.

وفي نفس الاتجاه، تخزين الطلبات عالي الأداء (HPOS) مفعّل افتراضياً في المتاجر الجديدة منذ WooCommerce 8.2، وينقل الطلبات إلى جداول خاصة فيسرّع الدفع وشاشة الطلبات والتقارير، دون أثر على صفحات المنتجات.

تسريبات صامتة: الخيارات المحمّلة تلقائياً وWP-Cron

نظّف جدول wp_options

الخيارات المحمّلة تلقائياً (Autoloaded Options) تُقرأ مع كل طلب. منذ ووردبريس 6.6 لم تعد الخيارات الأكبر من 150 كيلوبايت تُحمَّل تلقائياً ما لم تطلب الإضافة ذلك صراحة، وتنبّه أداة Site Health حين يتجاوز الإجمالي 800 كيلوبايت.

في الاختبار أضاف حجم 4.2 ميجابايت 12 جزءاً من الثانية لكل صفحة غير مخزنة، و16.6 ميجابايت أضافت 26 جزءاً، وتضاعف الأثر مع Redis لأنه ينقل الكتلة كاملة في كل طلب. لمعرفة حجمك وأكبر الخيارات، شغّل هذا في phpMyAdmin بعد استبدال wp_ ببادئة جداولك إن اختلفت:

-- Total autoloaded size in KB
SELECT ROUND(SUM(LENGTH(option_value)) / 1024) AS autoload_kb
FROM wp_options WHERE autoload IN ('yes', 'on', 'auto-on', 'auto');

-- The 20 largest autoloaded options
SELECT option_name, ROUND(LENGTH(option_value) / 1024) AS kb
FROM wp_options WHERE autoload IN ('yes', 'on', 'auto-on', 'auto')
ORDER BY LENGTH(option_value) DESC LIMIT 20;

خيار باسم إضافة حذفتها يمكن حذفه غالباً بعد نسخة احتياطية من قاعدة البيانات. أما الخيار الذي لا تعرفه فيتبع شيئاً ما زال مثبتاً، وإيقاف تحميله التلقائي أسلم من حذفه.

في ووردبريس: افتح Tools ← Site Health قبل أي شيء؛ إن ظهر تحذير «Autoloaded options could affect performance» فقد وجدت أول مهمة تنظيف.

اربط WP-Cron بجدولة السيرفر

ووردبريس ليس لها ساعة خاصة، فـ WP-Cron يعمل عند تحميل صفحة. في متجر مخزّن مؤقتاً لا يصل إلى PHP إلا القليل، فتتأخر مهام Action Scheduler: رسائل الطلبات، والـ Webhooks، ومزامنة المخزون، وتجديد الاشتراكات. والحل جدولة حقيقية تضبطها مرة واحدة:

  1. أضف define( 'DISABLE_WP_CRON', true ); إلى wp-config.php قبل سطر «stop editing».
  2. من Cron Jobs في cPanel، أضف مهمة كل 5 دقائق، أو اطلب من الاستضافة تشغيلها عبر WP-CLI:
# Every 5 minutes: run the due WP-Cron events and Action Scheduler jobs
*/5 * * * * wget -q -O /dev/null "https://shop.example.com/wp-cron.php?doing_wp_cron"
  1. راجع الطابور في WooCommerce ← Status ← Scheduled Actions. قائمة طويلة من المهام المتأخرة (Past-due) تعني أن الجدولة لا تعمل كفاية، وآلاف المهام الفاشلة من إضافة واحدة تشير إلى تلك الإضافة.

قبل أن تدفع في باقة أكبر: الإضافات وعمليات PHP

الإضافات تكلّف معاً أكثر من مجموعها

كل إضافة وحدها رخيصة نسبياً على السيرفر: أعلاها في الاختبار Wordfence بـ 19 جزءاً من الثانية، ثم Jetpack وYITH Wishlist وPayPal Payments بـ 11 إلى 12. لكن تشغيل 15 إضافة معاً رفع صفحة المنتج من 104 إلى 232 جزءاً من الثانية، أي أكثر من مجموعها منفردة. الطريقة الوحيدة لمعرفة كلفة مجموعتك هي قياسها: كلها مفعّلة، ثم أوقف واحدة واحدة.

عمليات PHP: اثنتان لكل نواة تكفي

عمليات PHP (PHP Workers) هي ما تبيعه الاستضافات المُدارة على أنه قدرة المتجر، لكن كل عملية تحتاج نواة معالج فارغة لتعمل. حين أرسل كاتب المصدر 20 زائراً متزامناً لصفحة غير مخزنة على نواة واحدة، أعطت 32 عملية صفحات أقل من عمليتين (7.1 مقابل 10.3 في الثانية)، وانتظاراً أطول.

احسبها قبل الشراء: عدد الصفحات في الثانية يساوي تقريباً عدد الأنوية مقسوماً على زمن بناء الصفحة. نواة واحدة وصفحة تُبنى في 100 جزء من الثانية تعطي نحو 10 صفحات في الثانية. باقة تبيعك عمليات كثيرة على أنوية قليلة تبيعك في الحقيقة طابوراً أطول.

خطة التسريع

إصلاحات ووكومرس حسب الأولوية

أغلبها مجاني ولا يحتاج ترقية الباقة

  • PHP

    شغّل OPcache

    نزل بناء الصفحة من 473 إلى 100ms في اختبار المصدر.

  • كاش

    كاش صفحات واحد

    أقرب ما يكون للزائر، ويتجاهل gclid وfbclid وutm.

  • أمان

    عمر الكاش أقل من 12 ساعة

    إن كانت الصفحة تحمل nonce لبوابة دفع.

  • السلة

    أوقف Cart Fragments

    كتلة Mini-Cart أو تأجيل السكربت حتى إضافة منتج.

  • قاعدة البيانات

    نظّف wp_options

    Site Health تنبّه عند تجاوز 800KB محمّلة تلقائياً.

  • مهام

    اربط WP-Cron بالسيرفر

    كل 5 دقائق حتى لا تتأخر رسائل الطلبات.

ابن موقعك قطعة قطعةarabcms.com

الأسئلة الشائعة

س: هل تغيير الاستضافة هو الحل الوحيد لبطء ووكومرس؟
ج: ليس غالباً. الاستضافة تضع السقف، لكن الكاش وعدد الإضافات يحددان مدى اقترابك منه. جرّب التشخيص بالطلبات الثلاثة أولاً؛ إن كان الرابط العادي سريعاً ورابط nocache بطيئاً، فالمشكلة في الإعدادات قبل السيرفر.

س: لماذا صفحة الدفع في ووكومرس أبطأ من صفحات المنتجات؟
ج: لأن ووكومرس يمنع تخزين صفحات السلة والدفع وحسابي، فيُبنى كل طلب فيها بـ PHP. ما يسرّعها هو OPcache، وتقليل الإضافات، وRedis حين تكون قاعدة البيانات بطيئة، وتفعيل HPOS.

س: هل أحتاج WP Rocket إذا كانت استضافتي فيها كاش؟
ج: لا تحتاج ميزة كاش الصفحات فيه، فكاشان معاً يسببان مشاكل. قد تظل ميزاته الأخرى مفيدة، مثل تأخير JavaScript وتحسين CSS والصور.

س: هل إيقاف Cart Fragments يكسر عداد السلة؟
ج: الكود المذكور لا يلغي السكربت بل يؤجله حتى يضيف الزائر منتجاً، فيظهر العدد صحيحاً بعدها. البديل الأنظف كتلة Mini-Cart التي لا تعتمد عليه أصلاً.

س: كم يجب أن يكون TTFB لمتجر ووكومرس؟
ج: تعدّ Google زمن 800 جزء من الثانية أو أقل جيداً، ويشمل ذلك المسافة والاتصال. للصفحات المخزنة تستطيع الوصول إلى أقل من 100 جزء من الثانية من السيرفر نفسه.

الخلاصة

بطء ووكومرس في أغلب الأحوال ليس قوة سيرفر ناقصة، بل صفحات تُبنى بـ PHP أكثر مما يجب. ابدأ بالطلبات الثلاثة، ثم OPcache وكاش واحد يتجاهل معاملات الإعلانات، ثم أوقف Cart Fragments ونظّف wp_options واربط WP-Cron بالسيرفر، واترك ترقية الباقة لآخر القائمة.

جرّب التشخيص النهارده وقولي في التعليقات الرابط العادي ورابط nocache طلعوا كام عندك. ولو محتاج حد يبص على متجرك معاك، احجز جلسة من هنا احجز استشارة مجانية.

مراجع إضافية: Best practices for the use of the “cart fragments” API — WooCommerce Developer Blog، Options API: Disabling autoload for large options — Make WordPress Core، PHP Supported Versions

مرجع المقال (بالإنجليزية): Why WooCommerce Is Slow: 924 ms to Build a Page, 27 ms to Serve It
المقال ده مش ترجمة حرفية: متكيّف للقارئ العربي ومضاف عليه سياق ووردبريس وElementor وJetEngine.

اترك تعليقاً