Sebuah situs klien yang saya pegang tiba-tiba dilaporkan "rusak semua" oleh pemiliknya. Language switcher tidak berpindah, preloader hilang, tombol login error, currency switcher diam, dan sebagian ikon tidak muncul. Yang bikin saya bingung: saya sudah patch semua file terkait dan upload satu per satu ke server produksi. Di lokal semuanya benar, saya cek berkali-kali. Tapi di browser klien, tidak ada satu pun perubahan yang kelihatan. File di server sudah versi baru, tampilan tetap versi lama.
Reaksi pertama saya seperti kebanyakan orang: pasti ada yang salah di kode saya. Jadi saya mulai menambal berdasarkan teori, dan di sinilah saya kehilangan beberapa jam.
Tiga ronde tambalan yang tidak mengubah apa pun
Ronde pertama, saya curiga masalahnya di sisi browser. Klien pakai Brave, dan Brave Shields memang suka memblokir script tertentu. Saya minta dia matikan Shields untuk domain itu. Tidak ada bedanya.
Ronde kedua, saya rombak logika redirect di language switcher. Saya pikir mungkin ada race condition antara redirect ?lang= dan pembacaan cookie bahasa. Saya rapikan urutannya, upload ulang, minta hard refresh. Tetap nol perubahan.
Ronde ketiga, saya utak-atik seluruh cookie handling: cara setcookie() dipanggil, path-nya, kapan preloader membaca state. Semua saya perbaiki, semua saya upload. Hasilnya sama persis dengan dua ronde sebelumnya, yaitu tidak ada apa-apa yang berubah di layar klien.
Tiga teori berbeda, tiga tambalan berbeda, dan tidak satu pun berpengaruh, padahal saya bisa membuka file di server via SSH dan melihat kode baru saya ada di sana. Ketika file di disk sudah benar tapi yang tampil tetap salah, dan tidak peduli seberapa banyak kamu menambal, masalahnya hampir pasti bukan di kode. Sesuatu di antara PHP dan browser sedang menyajikan versi lama.
curl membongkar penyebabnya
Saya berhenti menebak dan langsung memeriksa apa yang sebenarnya dikirim server, bukan apa yang saya kira dikirim server:
curl -I https://situs-klien.example/ | grep -i x-litespeed-cacheJawabannya bikin semuanya masuk akal:
X-LiteSpeed-Cache: hitHeader itu muncul di setiap halaman. Managed host situs ini menjalankan LSCache, full-page cache bawaan LiteSpeed. Status hit artinya HTML yang dikirim ke pengunjung bukan hasil render PHP saat itu, melainkan salinan yang sudah tersimpan di cache. Dan salinan itu lebih tua dari upload saya. Waktu saya lihat sumber halaman, buktinya jelas: markup homepage masih versi lama tanpa elemen preloader, dan main.min.js masih dimuat di ?ver=1.6.0, versi sebelum semua patch saya.
Jadi kode redirect dan setcookie() saya benar sejak awal. Masalahnya, kode itu tidak pernah dieksekusi. LSCache mencegat request lebih dulu dan langsung mengembalikan HTML basi dari cache, sebelum PHP sempat jalan sama sekali.
Kenapa file di server bukan yang dilihat user
Ini bagian yang bikin banyak orang tersesat. Full-page cache menyimpan seluruh HTML hasil render sebuah halaman, lalu menyajikannya apa adanya untuk request berikutnya tanpa menyentuh PHP lagi. Jadi lapisan yang sebenarnya kamu hadapi itu berurutan begini:
browser → LSCache full-page cache → PHP/WordPress → file di disk
Saya mengubah lapisan paling dalam, yaitu file di disk. Tapi selama LSCache masih memegang salinan HTML lama dan status-nya hit, request pengunjung berhenti di lapisan kedua dan tidak pernah turun ke PHP. Upload file sebanyak apa pun tidak akan terasa selama full-page cache belum tahu bahwa isinya sudah usang. Bump versi tema, hard refresh, ganti cookie, semua sia-sia karena semuanya beroperasi di lapisan yang salah.
Perbaikannya
Perbaikannya empat langkah, dan intinya adalah membuat LSCache sadar bahwa konten berubah dan tidak boleh disajikan seragam untuk semua orang.
Pertama, saya bump konstanta PCP_VERSION yang dipakai untuk mem-versioning semua aset. Dengan versi baru, setiap URL aset dapat ?ver= yang segar, jadi browser terpaksa mengambil ulang JS dan CSS alih-alih memakai yang lama dari cache-nya sendiri.
Kedua, dan ini kunci untuk switcher, saya daftarkan cookie bahasa dan currency sebagai bagian dari cache key lewat filter litespeed_vary_cookies. Tanpa ini, LSCache menyajikan satu HTML yang sama untuk semua nilai bahasa dan currency, sehingga perpindahan tidak pernah terlihat.
add_filter('litespeed_vary_cookies', fn($c) => array_merge($c, ['pcp_language','pcp_currency']));
if ( isset($_GET['lang']) ) {
nocache_headers();
do_action('litespeed_control_set_nocache');
}Ketiga, khusus request yang membawa ?lang=, saya panggil nocache_headers() plus do_action('litespeed_control_set_nocache') supaya LSCache tidak meng-cache request itu dan redirect bahasa benar-benar dijalankan PHP, bukan dipotong cache.
Keempat, sebagai jaring pengaman, saya kirim header Vary: Cookie supaya lapisan cache mana pun di atasnya juga memperlakukan cookie sebagai pembeda.
Checklist
- Kalau klien bilang "masih rusak setelah upload", tindakan pertama adalah
curl -Iproduksi dan cek headerX-LiteSpeed-Cache. Kalauhit, kamu sedang melihat HTML basi. - Ingat: file di disk tidak sama dengan yang dilihat user selama ada full-page cache di depannya.
- Berhenti menambal kode kalau tiga teori berbeda sama-sama tidak berpengaruh. Itu sinyal masalah cache, bukan bug logika.
- Bump versi aset supaya
?ver=segar dan browser mengambil ulang JS dan CSS. - Daftarkan cookie yang mengubah tampilan (bahasa, currency) ke
litespeed_vary_cookiesbiar jadi bagian cache key. - Matikan cache untuk request yang harus menjalankan logika PHP, misalnya
?lang=, dengannocache_headers()danlitespeed_control_set_nocache.
