کش وردپرس؛ معماری، تنظیم امن و رفع نسخه قدیمی

اگر یک مشتری سبد یا نام کاربر دیگری را ببیند، مسئله دیگر «کش قدیمی» نیست؛ یک رخداد امنیتی است. اگر فقط مدیر سایت نسخه تازه را ببیند اما مهمان هنوز HTML قبلی را بگیرد، احتمالاً دو نسخه با Cache key یا لایه متفاوت دارید. و اگر بعد از پاک‌سازی کامل، سرور زیر بار کند شود، Purge خودِ درمان نبوده؛ فقط منشأ را ناگهان با همه درخواست‌ها روبه‌رو کرده است.

کش وردپرس یک دکمه یا افزونه نیست. زنجیره‌ای از Browser، CDN/Edge، Reverse proxy، Page cache، Object cache، Transient، PHP OPcache و Cache در APIهای وابسته است. راه‌حل پایدار با پنج سؤال ساخته می‌شود: چه چیزی قابل‌ذخیره است، چه درخواست‌هایی باید یک پاسخ مشترک بگیرند، تازگی مجاز چقدر است، چه رویدادی نسخه را باطل می‌کند و از کجا می‌فهمیم پاسخ درست تحویل شده است؟

این راهنما برای مدیر WordPress، توسعه‌دهنده، تیم محتوا و فروشگاه ایرانی است. برای مبانی عمومی TTL، Fresh/Stale، Cache-Control و ETag ابتدا راهنمای «کش چیست و معماری Cache چگونه طراحی می‌شود» را ببینید؛ این مقاله مالک تنظیم، ایمنی و عیب‌یابی Cache در WordPress است.

پاسخ کوتاه: کش وردپرس چیست؟

WordPress برای تولید یک صفحه می‌تواند PHP اجرا کند، از Database بخواند، Hookهای قالب و افزونه را فراخوانی کند و HTML بسازد. Cache یک کپی قابل‌بازسازی از پاسخ یا نتیجه میانی را نگه می‌دارد تا درخواست بعدی کار کمتری انجام دهد. Cache نباید تنها نسخه Order، Payment، User profile یا Inventory باشد؛ Source of truth جای دیگری است.

پرسشپاسخ درستبرداشت پرریسک
هدف چیست؟کاهش Latency/Origin load در محدوده تازگی و صحتبالاتر بردن Hit ratio به هر قیمت
Cache چه نگه می‌دارد؟نسخه قابل حذف و بازتولیدتنها کپی داده تجاری
چه کسی پاسخ را می‌گیرد؟فقط درخواست‌های هم‌ارز طبق Cache keyهرکس همان URL را باز کرد
Purge چه می‌کند؟نسخه مشخص را Invalid یا حذف می‌کندعلت ریشه‌ای را خودکار رفع می‌کند
موفقیت چیست؟پاسخ درست و تازه با هزینه کمترصرفاً نمره Performance یا HIT بیشتر

مدل ذهنی کش: Request تا Regeneration

هر لایه Cache را با این جریان بخوانید:

  1. Eligibility: آیا Method، Status، مسیر و ماهیت پاسخ اجازه ذخیره می‌دهند؟
  2. Identity: Cache key از کدام بخش‌های Scheme، Host، Path، Query، Header، Cookie، Language یا Device ساخته می‌شود؟
  3. Lookup: نسخه‌ای برای این Key هست و هنوز Fresh است؟
  4. Serve/Revalidate: پاسخ مستقیم استفاده می‌شود، با Origin اعتبارسنجی می‌شود یا دوباره تولید می‌شود؟
  5. Invalidate: TTL، انتشار محتوا، تغییر وابستگی، Purge دستی یا Eviction چه زمانی آن را کنار می‌زند؟
  6. Observe: Hit/Miss/Age/Version و زمان Origin چگونه ثبت و بررسی می‌شوند؟

وقتی نسخه قدیمی می‌بینید، پاسخ یکی از این شش مرحله غلط است. این مدل از آزمون تصادفی تنظیم‌ها مفیدتر است.

نقشه لایه‌های Cache در WordPress

لایهدارایی یا نتیجهKey رایجنشانه خرابیمالک محتمل
BrowserCSS، JS، Font، Image و گاهی HTMLURL + Headerفقط یک Browser قدیمی استFrontend/HTTP
Service WorkerAsset یا Response طبق کد برنامهمنطق Cache APIIncognito یا دستگاه دیگر متفاوت استPWA/Frontend
CDN/EdgeAsset و در Cache-everything گاهی HTMLHost/Path/Query + Ruleکشور، اپراتور یا PoP متفاوت استInfrastructure
Reverse proxy/HostHTML یا پاسخ PHP در Nginx/Varnish/LiteSpeedURL/Cookie/HeaderPurge افزونه اثری نداردHost/DevOps
Page Cache pluginHTML آماده برای VisitorURL + Mobile/User/Cookie ruleمهمان قدیمی، مدیر تازهWordPress admin
Object CacheObject، Option و Query resultKey + Group + BlogHTML تازه اما داده درونی قدیمیBackend/Host
Transientنتیجه موقت API/محاسبه/MarkupTransient nameWidget یا نرخ/Feed دیر تازه می‌شودPlugin/Theme owner
PHP OPcacheBytecode کامپایل‌شده PHPFile path/versionپس از Deploy رفتار کد قبلی می‌ماندHost/Release
Upstream APIپاسخ سرویس قیمت، ارسال یا Searchقرارداد Providerهمه لایه‌های WordPress تازه‌اند، داده نهIntegration owner

دکمه «پاک‌کردن کش» یک افزونه معمولاً همه این لایه‌ها را کنترل نمی‌کند. همچنین فعال بودن چند Page cache مستقل لزوماً Performance را دو برابر نمی‌کند؛ ممکن است Ruleها و Purgeهای ناسازگار بسازد.

Cache، Session، Queue و Source of truth را قاطی نکنید

جزءاگر حذف شود چه باید شود؟نمونه WordPress/فروشگاهریسک اشتباه
Cacheبا هزینه بیشتر بازسازی شودHTML مقاله یا Query resultکندی موقت
Sessionرفتار کاربر مختل می‌شودشناسه سبد/وروداختلاط یا از دست رفتن Journey
Queueکارهای در انتظار گم نشوندایمیل سفارش یا Preload jobکار انجام‌نشده/تکراری
Source of truthنباید به Cache وابسته باشدOrder، Transaction، Stockاز دست رفتن یا تناقض تجاری

Redis می‌تواند برای Cache، Session یا Queue به کار رود، اما این کاربردها سیاست Persistence، Eviction، Isolation و Recovery یکسانی ندارند. فرمان سراسری مانند FLUSHALL روی Instance مشترک ممکن است چیزی بیش از Cache وردپرس را حذف کند؛ Scope و مالکیت را پیش از هر Flush ثابت کنید.

قبل از نصب یا تنظیم افزونه، Baseline بگیرید

بدون Baseline نمی‌دانید Cache چه مشکلی را حل کرده یا چه خطایی ساخته است. «سایت حس می‌شود سریع‌تر است» شاهد کافی نیست. اثر را در کنار چارچوب سرعت سایت، UX و Outcome بسنجید.

حوزهشاهد پایهتقسیم لازمGuardrail
LatencyTTFB و زمان پاسخ OriginURL type، HIT/MISS، Mobile/Desktopp95/p99 بدتر نشود
LoadPHP worker، CPU، DB query/timeWarm/Cold و ساعت ترافیکQueue و Error بالا نرود
FreshnessPublish→visible latencyHTML/Asset/Data/Regionاز بودجه تازگی عبور نکند
Correctnessتست Persona/Cart/Price/RoleGuest/User/Admin و دو Sessionهیچ پاسخ شخصی Share نشود
ResilienceOrigin unavailable/cold testNormal/Peak/Failure5xx و Recovery کنترل شود
BusinessView→Cart→Payment→Keptقبل/بعد و Release cohortخطای پرداخت/موجودی رشد نکند

Inventory: دقیقاً چه Cacheهایی فعال‌اند؟

یک جدول مالکیت بسازید؛ نام Plugin به‌تنهایی کافی نیست.

لایه/محصولScopeRule sourcePurge pathEvidenceOwner
Browser/CDNAsset یا HTMLHeader/Edge ruleURL/Tag/PrefixAge و Provider status
Host cachePublic HTMLPanel/Nginx/VarnishPanel/APIResponse header/Log
WP RocketPage/optimizationPlugin + compatibilityPost/DomainFile/Plugin header
Object CacheKey/groupobject-cache.phpKey/Group/AllHit/Miss/Eviction
Transient/APIFeature-specificPlugin codeEvent/TTLVersion/last refresh

برای هر افزونه، مسئول نگهداری، Changelog، Compatibility، Rollback و هزینه عملیاتی را هم ثبت کنید. «رایگان» یا «محبوب» بودن جای این ارزیابی را نمی‌گیرد؛ راهنمای TCO و ریسک افزونه/قالب WordPress چارچوب انتخاب را تکمیل می‌کند.

قرارداد Cache برای هر نوع پاسخ

پیش از انتخاب TTL، برای هر Page/API type یک Cache contract بنویسید:

فیلد قراردادپرسشمثال مقالهمثال Checkout
Eligibilityکدام Method/Status قابل ذخیره است؟GET/HEAD عمومی ۲۰۰پیش‌فرض Bypass
Cache keyچه Requestهایی هم‌ارزند؟Host + Canonical pathUser/session-dependent
Freshness budgetحداکثر نسخه قدیمی قابل‌قبول؟بر پایه سیاست تحریریهقیمت/موجودی بسیار محدود
Invalidationچه Eventهایی کدام Keyها را پاک کنند؟Update post→post/home/archiveCart/stock/payment event
Failure modeدر خطای Origin نسخه stale مجاز است؟شاید، طبق Ruleبرای پاسخ شخصی/تراکنش خیر
Evidenceدرستی چگونه دیده می‌شود؟Version marker + headerSession isolation + backend
Ownerچه کسی تغییر/Incident را پاسخ می‌دهد؟Content/PlatformCommerce/Payment

Cache key: مرز میان سرعت و نشت داده

Cache key تعیین می‌کند کدام Requestها «یکسان» فرض شوند. Key بیش‌ازحد جزئی، Entryهای فراوان و Hit کم می‌سازد؛ Key بیش‌ازحد کلی، پاسخ اشتباه یا شخصی را میان کاربران Share می‌کند.

بُعدچه زمانی در Key باشد؟خطر حذفخطر افزودن بی‌دلیل
Scheme/Hostاگر پاسخ واقعاً فرق داردHost contamination/Redirect اشتباهFragmentation
Pathتقریباً همیشهصفحه اشتباه
QueryParameter محتوایی لازمVariant/Search اشتباهUTM و Noise، Hit کم
Languageپاسخ Server-side متفاوتزبان/جهت اشتباهVariation زیاد Header
DeviceHTML سرور واقعاً متفاوتMarkup ناسازگارتقسیم Mobile/Desktop بی‌دلیل
Cookie/Userترجیحاً Bypass پاسخ شخصی؛ در طراحی خاص Key جدانشت Cart/Profile/NonceCache per-user کم‌ارزش

مستند Cache key در Cloudflare نشان می‌دهد Query، Header، Cookie، Host و ویژگی کاربر می‌توانند رفتار Key را عوض کنند و دسترسی گزینه‌ها به Plan وابسته است. این تنظیم محصول خاص است؛ Rule واقعی CDN خودتان را بخوانید و از روی نام گزینه حدس نزنید.

پارامترهای رهگیری را با پارامترهای محتوایی یکی نگیرید

utm_source معمولاً نباید نسخه HTML جدا بسازد؛ اما Parameter انتخاب Currency، Language یا Variant ممکن است محتوا را تغییر دهد. حذف همه Queryها از Key بدون Contract می‌تواند پاسخ یک Search، Filter یا Preview را به Request دیگر بدهد. ابتدا Parameter registry با Purpose، Output effect، Cache policy و Owner بسازید.

Responsive بودن معمولاً Cache موبایل جدا نمی‌خواهد

اگر Browser با CSS همان HTML را Responsive می‌کند، Device key فقط Hit ratio را تقسیم می‌کند. Cache موبایل جدا زمانی توجیه دارد که Origin واقعاً Markup متفاوت تولید کند؛ آن‌گاه Tablet، Bot، Header variation و QA دو نسخه نیز به هزینه سیستم اضافه می‌شوند.

پاسخ شخصی را به Shared cache نسپارید

وجود Cookie به‌تنهایی پاسخ را Private نمی‌کند. راهنمای HTTP caching در MDN میان Private browser cache و Shared cache فرق می‌گذارد و برای محتوای شخصی private را توضیح می‌دهد. در WordPress علاوه بر Header، Rule واقعی CDN/Host/Plugin و آزمون دو Session مستقل لازم است.

هدرهای HTTP را به‌عنوان قرارداد بخوانید

Directive/Headerمعنای عملیخطای رایج
Cache-Control: no-storeپاسخ ذخیره نشوداستفاده سراسری و از دست‌دادن Cache مفید
privateShared cache استفاده نکند؛ Private cache ممکن استفرض اینکه Cookie خودکار همین کار را می‌کند
no-cacheذخیره ممکن است؛ پیش از reuse باید Validate شودترجمه به «اصلاً ذخیره نکن»
max-ageFreshness برای Cache هدف طبق قرارداد HTTPیک عدد برای HTML و Asset
s-maxageFreshness ویژه Shared cacheنادیده‌گرفتن رفتار CDN خاص
ETag/Last-ModifiedValidator برای Conditional requestتصور اینکه به‌تنهایی Purge می‌کنند
Ageسن تقریبی پاسخ در Shared cacheتفسیر بدون شناخت لایه/Provider
Varyانتخاب پاسخ بر اساس Header مشخصVary: User-Agent و Fragmentation شدید

RFC 9111 مرجع هنجاری Cache در HTTP است. Headerهای «آشپزخانه‌ای» و متناقض را کورکورانه روی همه Routeها نگذارید؛ Contract باید با نوع Response و رفتار Managed cache هماهنگ باشد.

نسخه‌گذاری Asset از Purge مرورگر قابل‌اعتمادتر است

برای CSS/JS/Image تغییرپذیر، Filename یا Content hash جدید منتشر کنید و Assetهای Fingerprinted را با عمر بلند نگه دارید. URL جدید باعث می‌شود Browser و CDN نسخه تازه را مستقل از Cache قبلی بخواهند. Minify، Delay JS و Remove Unused CSS موضوع دیگری‌اند؛ آن‌ها را با Page caching یکی نگیرید و مطابق راهنمای بهینه‌سازی CSS و JavaScript جدا تست کنید.

Page Cache در WordPress: HTML عمومی، نه همه Routeها

Page cache بیشترین منفعت را جایی دارد که کاربران ناشناس پاسخ یکسان می‌گیرند: مقاله، صفحه خدمات، Landing عمومی و Archive پایدار. پاسخ‌های زیر نیازمند Bypass یا Contract جدا هستند:

  • Admin، Login، Preview، Draft و مسیرهای دارای Permission؛
  • Account، Cart، Checkout و صفحه حاوی داده Session؛
  • Callback/Webhook و عملیات تغییر‌دهنده State؛
  • REST/AJAX شخصی، Nonce و پاسخ وابسته به Role؛
  • Search/Facet/Queryهایی که Key آن‌ها تعریف نشده است؛
  • Error و Redirectهایی که نباید طولانی‌مدت ذخیره شوند.

قانون «GET همیشه امن برای Cache است» کافی نیست؛ یک GET می‌تواند Profile شخصی یا Token داخل HTML داشته باشد. Eligibility را از Response semantics، Authentication و Data classification بسازید.

Object Cache و Redis: Query کمتر، مسئولیت بیشتر

طبق مستند WP_Object_Cache، Object Cache پیش‌فرض WordPress فقط در طول Request در حافظه می‌ماند؛ Persistence به Drop-in/Backend جدا نیاز دارد. تعریف WP_CACHE به‌تنهایی Persistent Object Cache را فعال نمی‌کند. افزونه‌ها نیز باید از توابع wp_cache_* استفاده کنند، نه اینکه مستقیماً به کلاس داخلی متکی باشند.

کنترل Redis/Object Cacheسؤال Acceptanceنشانه خطر
Namespace/Databaseسایت و Environment جدا هستند؟Key collision میان Production/Staging
Memory limitmaxmemory و Headroom تعریف شده؟رشد بدون سقف یا OOM
Eviction policyبا الگوی Cache سازگار است؟Eviction زیاد/Write error
ObservabilityHit/Miss، Evicted/Expired، Latency دیده می‌شوند؟فقط وضعیت Connected
Failureقطع Redis Graceful degradation دارد؟کل سایت Down می‌شود
Flush scopeKey/Group/Site قابل هدف‌گیری است؟FLUSHALL به‌عنوان Runbook عادی

مستند رسمی Redis درباره Eviction تفاوت Policyها و شاخص‌هایی مانند keyspace_hits، keyspace_misses و evicted_keys را توضیح می‌دهد. Hit ratio بالا بدون Correctness ارزش ندارد؛ اما Hit پایین همراه Eviction زیاد می‌تواند نشانه Memory/Policy نامتناسب باشد.

Transient: زمان انقضا سقف است، نه قول ماندگاری

Transients API وردپرس تصریح می‌کند که Transient ممکن است پیش از زمان Expiration ناپدید شود و پس از آن نباید برگردد. با Persistent Object Cache نیز محل نگهداری می‌تواند از Database به Backend Cache منتقل شود. بنابراین:

  • کد باید Cache miss و بازتولید را همیشه مدیریت کند؛
  • برای داده حساس به تازگی، Event invalidation را کنار TTL داشته باشد؛
  • Falsey value را از «وجود ندارد» درست تفکیک کند؛
  • External API failure را با Timeout، Backoff و Last-known-good policy روشن مدیریت کند؛
  • Transient را جای Order، Payment state یا Durable queue نگذارد.

PHP OPcache با HTML Cache فرق دارد

OPcache در PHP Bytecode کامپایل‌شده Script را نگه می‌دارد؛ Page cache نسخه HTML یک Response را. اگر پس از Deploy کد رفتار قبلی مانده اما HTML/CDN پاک شده‌اند، Release process، Symlink/File timestamp، OPcache invalidation و PHP-FPM processها را بررسی کنید. Restart کور در ساعت اوج جای Runbook استقرار نیست.

WP Rocket: Cache، Purge و Preload سه وضعیت متفاوت‌اند

رفتار زیر مربوط به مستندات جاری WP Rocket در مرداد ۱۴۰۵ است و جای بررسی Version، Host compatibility و تنظیم واقعی سایت شما را نمی‌گیرد. مستند پاک‌سازی WP Rocket می‌گوید هنگام انتشار یا ویرایش محتوا، Cache همان محتوا و وابستگی‌هایی مانند Home و Taxonomy مرتبط می‌تواند پاک شود. پس هر Update لزوماً Full purge نیست.

عملیاتچه می‌کند؟هزینه/ریسکشاهد اتمام
Cache HITنسخه ساخته‌شده را تحویل می‌دهداگر Key/Rule غلط باشد پاسخ غلط سریع‌تر می‌رسدHeader/File + Version marker
Purge/ClearEntry هدف را Invalid/حذف می‌کنددرخواست بعدی Cold استMISS/فقدان File و سپس نسخه تازه
Preload/WarmURL را برای بازسازی پیشاپیش Request می‌کندCPU/DB/Queue مصرف می‌کندEntry جدید + HIT بعدی
File optimizationCSS/JS را Transform یا زمان اجرا را عوض می‌کندشکست ظاهر/InteractionAsset و Task regression

طبق مستند Preload WP Rocket، Preload با پاک‌سازی پیوند دارد، از Sitemap/URLهای شناخته‌شده Queue می‌سازد و در رفتار جاری تا ۴۵ URL در ۶۰ ثانیه پردازش می‌کند و هنگام فشار سرعت را کاهش می‌دهد. این سقف مشخصه محصول در زمان نگارش است، نه عدد جهانی برای همه Hostها. Cron، دسترسی عمومی Sitemap و Cache مدیریتی Host نیز بر نتیجه اثر دارند.

چرا پوشه Cache خالی است؟

ممکن است Host خودش Page caching را مدیریت کند و WP Rocket در آن محیط فایل HTML نسازد؛ ممکن است Request با Login، Query، Cookie یا Route مستثنا باشد؛ یا Preload/Cron هنوز کار نکرده باشد. ابتدا Contract Hosting و Header را بخوانید، سپس سراغ File system بروید.

استثنا را فقط در یک لایه ثبت نکنید

راهنمای Exclusion در WP Rocket نشان می‌دهد Hostهای مدیریت‌شده‌ای وجود دارند که استثنای Page cache باید در لایه Host اعمال شود. اگر Checkout را در Plugin مستثنا اما CDN آن را Cache کنید، سیاست انتهایی هنوز ناامن است. Ruleها را Edge→Host→Plugin→Application هم‌راستا کنید.

TTL را از Freshness budget بسازید، نه از عدد پیشنهادی Blogها

نوع محتوارویداد تغییربودجه تازگی نمونهمکانیزم اصلیFallback
مقاله پایدارPublish/Updateطبق SLA تحریریهEvent purge + TTL محافظRevalidate
صفحه اصلی/Archiveتغییر عضو وابستهکوتاه‌تر از مقالهDependency purgeTTL
قیمت/موجودیERP/Order/Manual updateبر پایه ریسک OversellEvent + API contractکوتاه/Bypass
CSS/JS fingerprintedURL جدید در Deployعمر بلندContent hashRollback manifest
Account/Checkoutهر Request/Sessionشخصی و جاریShared-cache bypassprivate/no-store طبق پاسخ

TTL بلند با Invalidation دقیق می‌تواند هم سریع و هم تازه باشد؛ TTL کوتاه بدون Dependency map فقط Miss بیشتری می‌سازد. برعکس، Event purge ممکن است Fail شود، بنابراین TTL محافظ و مانیتور Publish→visible هنوز ارزش دارند.

Invalidation را به‌صورت Graph وابستگی طراحی کنید

ویرایش یک نوشته فقط URL نوشته را تغییر نمی‌دهد. کارت همان نوشته ممکن است در Home، Category، Tag، Author archive، Related content، Sitemap یا Feed دیده شود. «Purge همه» Dependency را پنهان می‌کند؛ «Purge فقط نوشته» نسخه‌های قدیمی پراکنده می‌سازد.

EventTargetهای محتملروش کم‌ریسکAcceptance
Update postPost + Home + Archiveهای عضو + RelatedTag/URL dependency purgeVersion تازه در همه Surfaceها
تغییر Menuتمام Templateهای دارای HeaderTemplate/tag purge یا Controlled full purgeNav تازه Guest/Mobile
تغییر Price/StockPDP + Category + Search + APIProduct/SKU event fan-outPage/API/Cart parity
Deploy CSS/JSHTML manifest/referenceVersioned asset + HTML purgeهیچ ۴۰۴/Mixed version نیست
Plugin/config changeScope نامعلوم/Template-wideStaging، سپس Scope مستندSmoke + rollback

Version marker، بحث «برای من تازه است» را پایان می‌دهد

برای Release یا محتوای حساس یک Marker غیرشخصی در Header یا HTML بگذارید: Build ID، Content version یا Updated timestamp. سپس همان Marker را از چند Persona و Region بخوانید. Timestamp روی Screen که با JavaScript محلی ساخته شده، شاهد نسخه HTML Origin نیست.

Purge باید Idempotent، قابل تکرار و قابل مشاهده باشد

Event انتشار ممکن است Retry شود. Handler پاک‌سازی نباید با اجرای دوباره داده خراب کند. Event ID، Target count، زمان Queue، نتیجه Provider و خطا را ثبت کنید؛ اگر Purge API شکست خورد، Retry با Backoff و Alarm داشته باشید.

از Cache stampede پس از Purge جلوگیری کنید

وقتی Entry پرتقاضا هم‌زمان برای هزار Request منقضی شود، همه می‌توانند برای بازسازی به PHP/Database حمله کنند. Full purge پیش از کمپین نیز همین اثر را در مقیاس سایت می‌سازد.

کنترلاثرمحدودیت
Request collapsing/Lockیک Worker بازسازی؛ بقیه منتظرپشتیبانی لایه و Timeout درست لازم است
TTL jitterانقضای Entryها پخش می‌شودبرای Freshness سخت مناسب هر داده نیست
Stale-while-revalidateنسخه stale هنگام بازسازی سرو می‌شودفقط در بودجه تازگی و محصول پشتیبان
Stale-if-errorدر خطای Origin محتوای قبلی می‌ماندبرای Account/Transaction نامناسب
Priority preloadRouteهای حیاتی زودتر Warm می‌شوندQueue و Origin capacity لازم است
Rate-limited rolloutموج Cold کنترل می‌شودRunbook و Monitoring می‌خواهد

قابلیت دقیق هر کنترل به CDN، Reverse proxy و Plugin بستگی دارد. نام Directive را مساوی اجرای واقعی ندانید؛ Failover را با Load کنترل‌شده و طرح مانیتورینگ Uptime و Performance آزمایش کنید.

کش فروشگاه WooCommerce: سرعت زیر Guardrail صحت

مستند جاری WooCommerce برای Cache، Cart، My Account و Checkout را Dynamic می‌داند و Cookieهایی مانند woocommerce_cart_hash، woocommerce_items_in_cart و wp_woocommerce_session_ را در سیاست Cache مطرح می‌کند. بسیاری از Pluginها استثناهای پیش‌فرض دارند؛ پیش‌فرض را با مسیر، زبان، افزونه درگاه و دو Session واقعی تأیید کنید.

Surfaceپیش‌فرض تصمیموابستگیتست حیاتی
Category عمومیقابل Cache با Purge دقیقPrice/Stock/Sort/Facetلیست با PDP و Cart برابر است
PDP عمومیقابل Cache مشروطVariant/Price/Stock/Promotionدو Browser و آخرین موجودی
CartShared bypassSession/Coupon/Shippingسبد A هرگز در B نیست
CheckoutShared bypassUser/Address/Nonce/PaymentGuest/User و Retry
My AccountShared bypassIdentity/Order/ProfileLogout/Login و Back button
Callback/WebhookBypass؛ عملیات IdempotentTransaction/order stateSuccess/Fail/Cancel/Duplicate

برای فروشگاه ایرانی، تست فقط «صفحه پرداخت باز شد» نیست. Journey افزودن کالا، Coupon، انتخاب شهر و روش ارسال، ورود/خروج، انتقال به درگاه، بازگشت موفق/ناموفق/لغوشده، Callback تکراری، تأخیر Webhook، تغییر موجودی و Refund را پوشش دهید. راهنمای UX فروشگاه Taskهای خرید را تکمیل می‌کند.

بازگشت Browser از درگاه، حقیقت نهایی پرداخت نیست

Route بازگشت را Cache نکنید و State پرداخت را صرفاً از Query کاربر نپذیرید. Verify server-to-server، Idempotency، Correlation با Order و Reconciliation لازم‌اند. طراحی قرارداد Callback/Webhook در راهنمای API، امنیت و قابلیت اطمینان عمیق‌تر آمده است.

نمایش پاسخ شخصی به کاربر دیگر Incident است

فوراً لایه Shared cache را برای Surface متاثر Bypass/Purge، Evidence شامل Header/Request ID/زمان/Persona را حفظ، دامنه کاربران و داده افشاشده را بررسی و Incident process را فعال کنید. فقط Clear cache و بستن Ticket کافی نیست. اعتماد، اطلاع‌رسانی و جبران باید با سیستم شواهد و Remedy فروشگاه هماهنگ باشد.

Web Cache Deception و Cache poisoning را در Threat model بگذارید

Ruleهای «Cache everything» یا اعتماد به پسوند URL می‌توانند Response پویا را قابل‌ذخیره کنند. مستند Cache Deception Armor نمونه‌ای را توضیح می‌دهد که Route شخصی با پسوند ظاهراً استاتیک مانند .jpg پاسخ HTML می‌دهد و ممکن است اشتباه Cache شود. کنترل محصول خاص مفید است اما جای این موارد را نمی‌گیرد:

  • Route شخصی با پسوند یا Path اضافه نباید همان Response موفق را برگرداند؛
  • Content-Type، Status و Extension باید سازگار باشند؛
  • Host، Query و Header کنترل‌نشده نباید Key یا Response را مسموم کنند؛
  • Admin/Login/API/Preview و پاسخ‌های دارای Token از Shared cache خارج باشند؛
  • آزمون Cache باید با دو Identity و Request دستکاری‌شده انجام شود.

فرآیند عیب‌یابی نسخه قدیمی در وردپرس

۱. Symptom را به Artifact تبدیل کنید

URL نهایی، زمان تغییر، Expected value، Actual value، Persona، Login state، Browser، Device، Network/Region و Screenshot را ثبت کنید. مشخص کنید قدیمی چیست: HTML، CSS، JS، Image، Price، Menu، API JSON یا داده Dashboard.

۲. URL نهایی و Redirect chain را ثابت کنید

گاهی تیم URL قدیمی را Purge می‌کند اما کاربر پس از ۳۰۱ به Canonical دیگری می‌رسد. HTTP/HTTPS، www/non-www، Slash، Query و زبان را ثبت کنید. خطا را روی Destination واقعی بازتولید کنید، نه فقط آدرس تایپ‌شده.

۳. Browser را از Shared cache جدا کنید

Incognito فقط Cookie/Storage معمول آن Profile را تا حدی جدا می‌کند؛ اثبات نمی‌کند CDN یا Host تازه است. یک Device/Network دیگر و یک Request بدون Session بگیرید. اگر فقط یک Browser مشکل دارد، Asset cache، Service Worker و Local storage را بررسی کنید.

۴. Source، DOM و Data را جدا مقایسه کنید

مشاهدهلایه محتملبررسی بعدی
Source قدیمی استHTML در Edge/Host/PluginAge/HIT، Version marker، Origin bypass
Source تازه، DOM قدیمیJS/Service Worker/HydrationNetwork/Console/Runtime state
HTML تازه، CSS قدیمیBrowser/CDN assetAsset URL/hash/header
Shell تازه، Data قدیمیObject/Transient/APIAPI response، Key و last refresh
Guest قدیمی، Admin تازهPublic Page cacheCookie bypass و دو Request
فقط یک Region قدیمیCDN PoP/Regional originProvider status/purge propagation

۵. Header و Body را با هم بگیرید

یک HEAD لزوماً دقیقاً همان مسیر Cache یا تولید GET را طی نمی‌کند. برای Headerهای پاسخ GET بدون ذخیره Body می‌توانید از الگوی زیر استفاده کنید:

curl -sS -D - -o /dev/null 'https://example.com/final-url/'
curl -sS -D - -o /dev/null 'https://example.com/final-url/'

دو درخواست پیاپی را برای Cache-Control، Age، ETag، Vary، Set-Cookie و Headerهای Provider مانند HIT/MISS/BYPASS مقایسه کنید. نام Header و معنای Status به محصول بستگی دارد. Header را همراه یک Marker داخل Body و Log Origin تفسیر کنید.

۶. کوچک‌ترین لایه اثبات‌شده را Purge کنید

اگر یک Asset قدیمی است، URL همان Asset؛ اگر HTML یک Post قدیمی است، Post و وابستگی‌های تعریف‌شده؛ اگر Object مشخص است، Key/Group پشتیبانی‌شده. Full purge، Redis flush و Restart آخرین Escalationهای کنترل‌شده‌اند، نه قدم اول.

۷. بعد از Purge، علت و پیشگیری را ثابت کنید

حل شدن پس از Clear فقط می‌گوید نسخه‌ای Cached بوده؛ نمی‌گوید چرا Invalidation شکست خورد. Event log، Purge target، Queue، Provider response، Dependency map و زمان Visible شدن را ثبت کنید. سپس همان سناریو را یک بار دیگر بدون مداخله دستی تکرار کنید.

ماتریس نشانه، فرضیه و آزمون ردکننده

نشانهفرضیه اولآزمون ردکنندهاقدام پس از اثبات
فقط یک کاربر قدیمیBrowser/Service WorkerDevice و Profile دیگرAsset version/update SW
Guest قدیمی، Login تازهPage cache عمومیOrigin/Cache bypass مجازTarget purge و Rule fix
Purge افزونه بی‌اثرHost/CDN بالادستProvider header و Origin comparisonPurge همان لایه/هماهنگی Hook
قیمت قدیمی، متن تازهObject/Transient/APIData source مستقیمEvent invalidation/TTL fix
بعد Purge موج 5xxStampede/Origin capacityCold vs Warm loadLock/Warm/rate limit/capacity
سبد فرد دیگرShared personalized cacheدو Session با Marker مستقلIncident، Bypass، Scope review
Deploy دیده نمی‌شودOPcache/Old pod/Asset manifestBuild ID در NodeهاAtomic deploy/invalidation

تست ایمنی Cache: دو Session از یک Browser مهم‌ترند

تست «صفحه برای من باز شد» فقط Happy path یک Identity است. ماتریس باید پاسخ مشترک و پاسخ شخصی را در حالت Warm و Cold تفکیک کند.

محورحالت‌هاAssertion
IdentityGuest A، Guest B، User A، User B، Adminهیچ Marker شخصی بین Identityها جابه‌جا نمی‌شود
Sessionدو Browser/Profile مستقلCart، Nonce و Account جدا می‌مانند
Cache stateCold، MISS، HIT، پس از PurgeBody و Header با Contract سازگارند
DeviceMobile/Desktop/Tabletنسخه اشتباه یا Fragmentation بی‌دلیل نیست
Localeفارسی/زبان دوم، RTL/LTRLanguage/Direction درست است
Queryبدون Query، UTM، Search، Facet، VariantParameter policy اجرا می‌شود
Region/NetworkPoP/اپراتورهای منتخبPurge propagation در SLA است
FailureOrigin slow/down، Redis down، Queue delayedFailure mode و Alarm مطابق قرارداد است

تست منفی از تست مثبت مهم‌تر است

  • پاسخ Account با Cookie کاربر A را بگیرید؛ همان URL را با B و بدون Cookie Request کنید و عدم وجود Marker A را Assert کنید.
  • URL پویا را با پسوند ساختگی، Slash اضافه، Host و Query دستکاری‌شده آزمون کنید؛ Response شخصی نباید Cacheable ۲۰۰ شود.
  • پس از Logout، Back/Reload و URL مستقیم را تست کنید؛ داده حساس نباید از Shared cache برگردد.
  • برای Errorها، ۴۰۴/۴۲۹/۵۰۰ و Redirect موقت را بررسی کنید؛ TTL ناخواسته Incident را طولانی نکند.
  • در دو Request پیاپی، Header و Version marker را با هم Assert کنید؛ فقط Status ۲۰۰ کافی نیست.

آزمون Warm و Cold را جدا گزارش کنید

سناریوچه چیزی می‌سنجد؟خطای تفسیر
Warm HITهزینه Delivery از Cacheتعمیم به کاربر اول/پس از Purge
Cold MISSظرفیت PHP/DB و زمان Regenerationمقایسه مستقیم با HIT
Mixed trafficنسبت واقعی URLهای Cacheable/DynamicLoad test فقط Homepage
Purge burstStampede، Queue و Recoveryتست بدون Rate واقعی
Dependency updateتازگی همه Surfaceهای وابستهبررسی فقط URL ویرایش‌شده
Origin failureStale/fail-closed و Alarmفرض خودکار CDN

Load test را روی Production بدون هماهنگی و سقف اجرا نکنید. Dataset، نرخ، مدت، IP، زمان و Abort threshold باید از پیش معلوم باشند. هدف شکستن سایت نیست؛ پیدا کردن نقطه‌ای است که Latency/Error/Queue از Guardrail می‌گذرند.

انتشار تغییرات Cache بدون شوک

  1. Change brief: Route/Layer/Expected effect/Risk/Owner/Rollback را ثبت کنید.
  2. Staging parity: CDN/Host/Object cache و Cookie rule تا حد ممکن شبیه Production باشند.
  3. Baseline: Warm/Cold، Header، Task و Business guardrail را ذخیره کنید.
  4. Canary: Rule یا Release را روی Scope کوچک/URL نمونه اجرا کنید.
  5. Targeted invalidation: Dependencyهای متاثر را Purge کنید.
  6. Controlled warmup: URLهای حیاتی را با Priority و Rate متناسب Warm کنید.
  7. Verification: Guest/User/Admin، دو Session، Mobile و Region را تست کنید.
  8. Observe: Origin load، Error، Purge latency، Freshness و Transaction را تا تثبیت ببینید.
  9. Rollback: Rule/Plugin/Build را برگردانید و دوباره Cache state را همگرا کنید.

Deploy اتمیک، Mixed asset را کم می‌کند

ابتدا Assetهای Versioned و Backward-compatible را منتشر کنید، سپس HTML را به URLهای جدید اشاره دهید. پاک‌کردن Asset قبلی پیش از پایان عمر HTML قبلی می‌تواند ۴۰۴ بسازد. Rollback نیز باید Manifest نسخه قبلی را در دسترس داشته باشد.

پیش از کمپین فروش Full purge نکنید

Cache cold، Preload queue و بازدید کمپین می‌توانند هم‌زمان به Origin برسند. تغییر بزرگ را پیش‌تر Rollout، مسیرهای حیاتی را Warm، و Capacity را با Headroom تأیید کنید. Freeze window برای تنظیم Cache/Plugin در ساعات حساس تعریف کنید.

Observability: از HIT تا Outcome

Hit ratio فقط یک Diagnostic است. یک سیستم می‌تواند HIT بالا و قیمت غلط داشته باشد یا HIT پایین اما Journey سالم. داشبورد تصمیم باید چهار لایه را وصل کند:

لایهشاخص‌هاتقسیمتصمیم
DeliveryHIT/MISS/BYPASS، Age، bytesURL type/PoP/DeviceKey/Rule/TTL
OriginRPS، PHP workers، DB time، TTFB p95Cold/Warm/EndpointCapacity/Query/Preload
Cache storeMemory، Hit/Miss، Eviction، LatencyGroup/Instance/SitePolicy/Namespace/Limit
CorrectnessPublish→visible، parity، leakage testSurface/Persona/RegionInvalidation/Incident
JourneySearch→PDP→Cart→Pay→KeptRelease/Cohort/DeviceRollback/UX fix

برای هر Purge یا Deploy یک Correlation ID میان Event، Queue، CDN response و Test evidence نگه دارید. Alert بدون Runbook فقط Noise است؛ هر Alert باید Owner، Severity، اولین بررسی و Escalation داشته باشد.

SLO پیشنهادی: تازگی و صحت را کنار سرعت بگذارید

SLO/Guardrailتعریف نمونهمنبع شاهد
Freshnessدرصد Updateهای قابل مشاهده زیر بودجه هر Page typeCMS event + Probe
Correctnessصفر Leakage در Synthetic cross-session testsTest suite/Incident
AvailabilitySuccessful response برای Journey حیاتیProbe + Backend
Latencyp75/p95 Warm و Cold جداRUM/APM/Edge
PurgePropagation کامل Targetها در SLAProvider log + Marker
Recoveryزمان همگرایی پس از Rollback/Cold eventIncident timeline

عددها باید از ریسک کسب‌وکار و Baseline خود سایت تعیین شوند. مقاله پزشکی، موجودی لحظه‌ای و Landing ثابت Freshness یکسان ندارند. از Benchmark عمومی به‌عنوان Context استفاده کنید، نه SLA آماده.

سه مثال برای سایت‌های ایرانی

مجله محتوایی با WP Rocket و CDN

مقاله‌ها عمومی و Cacheable هستند؛ Update هر مقاله Post، Home و Categoryهای عضو را Purge می‌کند. Assetها Fingerprinted و طولانی‌عمرند. Preload ابتدا Home و مقاله‌های پرترافیک را Warm می‌کند. Probe از دو شبکه Marker نسخه را می‌خواند. Full purge فقط در تغییر Template سراسری و با Warmup کنترل‌شده انجام می‌شود.

فروشگاه WooCommerce در کمپین

Category/PDP عمومی Cache می‌شوند، اما Cart/Checkout/Account/Callback Shared bypass هستند. تغییر Stock بر اساس SKU، PDP و Listing وابسته را Invalid می‌کند؛ Cart و Backend دوباره قیمت/موجودی را تأیید می‌کنند. پیش از کمپین، دو Session مستقل، Coupon، ارسال شهرهای منتخب، درگاه موفق/ناموفق، Callback تکراری و Cache cold تست می‌شوند.

سامانه عضویت یا رزرو

Landing عمومی Cacheable است؛ Dashboard، ظرفیت شخصی، Profile و Routeهای دارای Nonce خارج از Shared cache هستند. API ظرفیت می‌تواند Contract کوتاه‌عمر داشته باشد، اما تأیید رزرو با Transaction/Lock در Source of truth انجام می‌شود. نمایش ظرفیت Cached هرگز جای کنترل نهایی هنگام ثبت را نمی‌گیرد.

اشتباه‌های رایج در تنظیم کش وردپرس

اشتباهچرا شکست می‌خورد؟جایگزین
نصب دو Page cache بدون مالکRule و Purge ناسازگاریک مسئول Delivery و Inventory لایه‌ها
Full purge پس از هر ویرایشCold load/StampedeDependency-based purge
TTL یکسان برای همهریسک و تغییر متفاوت‌اندFreshness budget هر نوع پاسخ
Cache کاربران واردشده برای HITFragmentation یا LeakageBypass؛ فقط Design مستند و تست‌شده
نادیده گرفتن CDN/HostPurge Plugin کافی نیستEnd-to-end rule alignment
Redis برای حل Query بدعلت را پنهان و عملیات را پیچیده می‌کندProfile Query + Cache بر اساس شاهد
FLUSHALL در Runbook عادیScope بزرگ/سرویس مشترکKey/Group/Site flush پشتیبانی‌شده
Hard refresh به‌عنوان Verificationفقط بخشی از Browser را Bypass می‌کندHeader+Marker+Origin/Edge evidence
بهینه‌سازی JS هم‌زمان با Cacheعلت شکست مبهم می‌شودیک متغیر، Acceptance و Rollback
تعقیب Hit ratio بدون صحتپاسخ غلط را سریع‌تر می‌کندCorrectness/Freshness guardrails

برنامه ۳۰/۶۰/۹۰ روزه Cache وردپرس

روز ۱ تا ۳۰: کشف و مهار ریسک

  • Inventory کامل Browser/CDN/Host/Plugin/Object/Transient/OPcache و Owner؛
  • فهرست Routeهای عمومی، شخصی، تراکنشی و API؛
  • تأیید فوری Bypass برای Login/Account/Cart/Checkout/Callback؛
  • Baseline Warm/Cold، Header، Origin load و Publish→visible؛
  • Cross-session test و Incident path برای Leakage.

روز ۳۱ تا ۶۰: قرارداد و اتوماسیون

  • Cache contract برای Page/API type و Parameter registry؛
  • Dependency map و Targeted purge با Event log؛
  • Versioned asset و Atomic deployment؛
  • Redis namespace/memory/eviction/alert و Failure test؛
  • Automated assertions برای Header، Marker، Persona و Transaction.

روز ۶۱ تا ۹۰: تاب‌آوری و یادگیری

  • Controlled cache-cold و Origin-failure exercise؛
  • Priority warmup، Rate limit و Stampede controls؛
  • SLO تازگی/صحت/Latency/Purge/Recovery؛
  • Canary و Rollback rehearsal پیش از کمپین؛
  • بازبینی Incident، حذف Cache بی‌ارزش و اصلاح Runbook.

چک‌لیست کیفیت تنظیم Cache وردپرس

  • Cache را کپی قابل‌بازسازی می‌دانیم، نه Source of truth.
  • همه لایه‌ها، Rule source، Purge path، Evidence و Owner ثبت شده‌اند.
  • برای هر Page/API type، Eligibility و Cache key روشن است.
  • Query/Cookie/Language/Device فقط در صورت اثر واقعی وارد Key می‌شوند.
  • Account، Cart، Checkout، Preview، Callback و پاسخ شخصی Shared bypass هستند.
  • no-store، private و no-cache درست تفکیک شده‌اند.
  • TTL از Freshness budget می‌آید و Event invalidation دارد.
  • Dependency map Post/Product/Template ساخته شده است.
  • Purge هدفمند، Idempotent، Logged و Retryable است.
  • Preload Priority/Rate و ظرفیت Origin هماهنگ‌اند.
  • Assetهای تغییرپذیر Versioned/Fingerprinted هستند.
  • Redis Memory/Eviction/Latency/Failure/Flush scope مانیتور می‌شود.
  • Transient miss و External API failure قابل مدیریت‌اند.
  • Deploy و OPcache invalidation Runbook و Rollback دارند.
  • دو Session و چند Persona/Device/Region تست می‌شوند.
  • Warm، Cold، Purge burst و Origin failure جدا سنجیده می‌شوند.
  • Version marker، Header و Log به یک Correlation ID متصل‌اند.
  • Correctness/Freshness/Business guardrail بر Hit ratio مقدم‌اند.

پرسش‌های متداول کش وردپرس

چرا بعد از ویرایش هنوز نسخه قدیمی WordPress را می‌بینم؟

ابتدا Artifact را مشخص کنید: HTML، CSS/JS، تصویر یا داده. سپس URL نهایی، Persona و Region را ثبت، Source/DOM/API را جدا و Headerهایی مانند Age/HIT را همراه Version marker بررسی کنید. فقط لایه اثبات‌شده و Dependencyهایش را Purge کنید؛ حل شدن با Full clear علت شکست Invalidation را مشخص نمی‌کند.

آیا بعد از هر تغییر باید کل کش را پاک کنیم؟

خیر. Update نوشته معمولاً همان URL و Surfaceهای وابسته مانند Home/Category را نیاز دارد. Full purge همه Entryها را Cold می‌کند و می‌تواند موج PHP/DB بسازد. تغییر Template سراسری شاید Scope بزرگ بخواهد، اما باید با Warmup، Monitoring و Rollback انجام شود.

آیا Redis برای هر سایت WordPress لازم است؟

نه. Persistent Object Cache وقتی ارزش دارد که Profiling نشان دهد Query/Option تکراری گلوگاه است و تیم بتواند Memory، Eviction، Isolation و Failure را اداره کند. سایت کوچک با Page cache سالم ممکن است سود محدودی بگیرد. Redis افزونه یا Query معیوب را اصلاح نمی‌کند.

آیا WP Rocket خودکار Cart و Checkout را مستثنا می‌کند؟

مستند جاری WP Rocket برای Ecommerce استثناهای خودکار برای Pluginهای پشتیبانی‌شده را توضیح می‌دهد؛ اما مسیرهای ترجمه‌شده، افزونه درگاه، Host cache و CDN لایه‌های جدا هستند. Cart، Checkout، Account، Cookie و Callback را با دو Session و خرید آزمایشی تأیید کنید.

Clear Cache و Preload چه تفاوتی دارند؟

Clear/Purge نسخه ذخیره‌شده را Invalid یا حذف می‌کند؛ Preload سپس URL را پیشاپیش Request می‌کند تا Entry دوباره ساخته شود. Preload مصرف CPU/DB/Queue دارد و باید با Priority، Rate و ظرفیت Origin هماهنگ شود. پاک‌سازی موفق به‌تنهایی به معنی Warm شدن یا رفع علت نیست.

جمع‌بندی: پاسخ درست، تازه و قابل‌اثبات

کش وردپرس خوب صرفاً TTFB را پایین نمی‌آورد؛ درخواست‌های واقعاً هم‌ارز را به پاسخ درست، در بودجه تازگی و با هزینه کمتر وصل می‌کند. Cache key غلط می‌تواند داده شخصی را Share کند، Invalidation ناقص نسخه‌های پراکنده بسازد و Full purge بی‌برنامه Origin را زیر بار ببرد.

از یک Route مهم شروع کنید: Contract آن را بنویسید، Header و Marker بگیرید، دو Session را تست کنید، Dependency purge را اجرا و Warm/Cold را جدا بسنجید. سپس همین الگو را به Page typeهای دیگر گسترش دهید. وقتی Owner، Evidence، Guardrail و Rollback دارید، Clear cache از واکنش حدسی به یک عملیات کنترل‌شده تبدیل می‌شود.

منابع رسمی و مرجع

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *