Sto provando a sviluppare un plugin di cache per WordPress per approfondire meglio le mie conoscenze in merito alla cache e alla cache su WordPress.
È una bella sfida.
Ci sono un sacco di cose che potrebbero andare storto e che potrebbero rompere il corretto funzionamento di un sito WP, per cui devo andare più a fondo e studiare di più.
Nel frattempo, mi segno i miei appunti personali sull’argomento.
Indice
Cosa è la cache
La cache è una memoria temporanea usata per salvare i dati che vengono richiesti spesso, così da poterli recuperare più velocemente.
Nel mio caso, è una memoria temporanea usata per salvare queries al database di WordPress, o intere pagine così da velocizzarne il caricamento.
La cache solitamente ha una durata, un tempo di validità per il quale è considerata valida e può essere usata.
Oltre tale data di validità, la cache scade, non può essere più usata e si deve generare nuovamente la pagina.
Questo è utile per invalidare la cache in una pagina dopo che è stato aggiornato un contenuto, ad esempio per un articolo. Così verrà rigenerata la pagina con il contenuto aggiornato anziché mostrare il vecchio contenuto.
Tipi di cache
Nel mio caso ho analizzato:
- Page cache: salva l’HTML completo delle pagine.
- Browser cache: aggiunge header HTTP.
- Object cache: salva risultati di query o elaborazioni.
Page cache
La prima volta che una pagina viene generata, viene salvato tutto l’HTML generato in un file o nel database.
Dalla volta successiva, viene caricato direttamente l’HTML salvato in precedenza, senza bisogno di rigenerarlo in maniera dinamica come la prima volta, quindi risparmiando tempo e risorse.
Soprattutto, si riducono notevolmente il numero di richieste fatte a WordPress e al database, alleggerendo tutto il sistema.
Dove viene salvato l’HTML?
- File su disco: si salva l’HTML in un file.
- Database: si salva l’HTML direttamente nel database, normalmente tramite i
transients.
Nel mio caso per la page cache su disco salvo i file in wp-content/cache/riaco-cache/ usando hashing per il nome e aggiungendo altre informazioni utili come expires, il termine della validità della cache.
Salvo i file in formato .json per poter memorizzare anche informazioni aggiuntive come expires, save_at, url, e altro.
Ha però lo svantaggio di dover fare un passaggio in più per servire il codice html della pagina, ovvero devo recuperare il file .json, recuperare l’html e ritornarlo.
Salvando il codice HTML direttamente in un file .html, si serve direttamente il file, ma, avrei comunque un passaggio in più da fare che è quello di mappare le informazioni aggiuntive, probabilmente usando un altro file di mapping.
La page cache va molto bene per:
- pagine statiche
- utenti non loggati
- articoli di WordPress
Invece può causare problemi per pagine dinamiche o che si basano sulle sessioni o cookie per funzionare. In questo caso, bisogna disabilitarla.
Browser cache
La browser cache è la cache salvata direttamente dal browser (es. Chrome), che bypassa la page cache e mostra direttamente lui quello che ha salvato nella sua memoria.
Per usarla si deve aggiungere agli headers della richiesta HTTP qualcosa di simile a:
header('Cache-Control: public, max-age=3600');
header('Expires: ' . gmdate(
'D, d M Y H:i:s',
time() + 3600
) . ' GMT');
Anche in questo caso è meglio non mettere in cache pagine che usano sessioni o cookies, ed evitare la cache per utenti loggati.
Per controllare che funzioni ispeziona tramite la dev console:
Chrome → F12 → Network → Headers → Response Headers.
Dovresti vedere qualcosa come:
Cache-Control: public, max-age=3600
Attenzione però che così non riuscirai ad invalidare la cache del browser e può essere un problema.
Immagina:
12:00 → Mario visita Homepage
12:05 → Tu pubblichi un nuovo articolo
La page cache sul server viene svuotata.
Ma il browser di Mario ha:
Cache-Control: max-age=3600
Fino alle 13:00 potrebbe continuare a usare la copia locale senza nemmeno contattare il server.
Per questo motivo in produzione bisognerebbe usare:
Cache-Control: public, max-age=0, must-revalidate
ETag: "..."
Last-Modified: "..."
Questo è uno dei meccanismi più eleganti della cache HTTP, perché non dice al browser di usare sempre la cache, ma gli permette di verificare se la copia locale è ancora valida senza riscaricare tutta la pagina.
Oppure un max-age= più stretto, tipo 5 minuti (max-age=300).
Object cache
L’object cache salva il risultato di queries e dati interni di WordPress.
Ad esempio:
WP_Queryget_post()get_option()
Si gestisce con la classe WP_Object_Cache usando le funzioni wp_cache_*.
wp_cache_get()wp_cache_set()wp_cache_delete()
Di default l’object cache di WordPress non è persistente, ovvero viene salvata in memoria solamente durante quella specifica richiesta.
Quindi se durante una richiesta (richiesta A) eseguo una query più di una volta, dalla seconda volta in poi viene usata la cache in memoria.
Ma, quando arriva una nuova richiesta (richiesta B), la query non è più in cache, quindi deve rigenerare la query, la salva in cache per questa richiesta B e se viene usata un’altra volta durante la richiesta B allora sì che la può leggere dalla cache.
Si ha un vantaggio ma si può fare di meglio.
Per questo tornano utili sistemi di memoria persistente, che memorizzano direttamente in RAM il risultato della query.
Prendendo l’esempio di prima, arriva una richiesta (richiesta A, esegue una query e la salva in cache. Questa viene salvata direttamente in RAM e rimane lì.
Poi arriva una richiesta B, e questa volta, anzichè dover eseguire la query, legge il risultato della query dall’object cache persistente dalla memoria RAM.
Molto più veloce e con un netto risparmio di risorse.
I sistemi di object cache persistente più usati sono Redis (Redis è stato sviluppato da Salvatore Sanfilippo) e Memcached.
Questi sistemi però devono essere installati sul server (chiedi al servizio assistenza del tuo hosting) per poter essere utilizzati.
Per prestazioni ancora migliori
I plugin più veloci intercettano la richiesta prima che WordPress venga caricato, utilizzando file come advanced-cache.php e l’impostazione WP_CACHE nel file wp-config.php.
In questo modo, se la pagina è già in cache, l’HTML viene restituito senza avviare l’intero bootstrap di WordPress, riducendo notevolmente il tempo di risposta.
Ho notato un netto miglioramento della velocità di caricamento.
Ottimizzazioni avanzate
Un plugin di cache completo aggiunge spesso funzionalità come:
- Cache mobile e desktop separate.
- Cache distinta per lingua (es. siti multilingua).
- Preload della cache tramite crawler.
- Cache separata per dispositivo o cookie.
- Minificazione di HTML, CSS e JavaScript.
- Compressione Gzip.
- Integrazione con CDN.
- Esclusioni configurabili per URL, cookie o ruoli utente.
- Purge selettivo (solo la pagina modificata e gli archivi correlati).
- Supporto per cache persistente con Redis o Memcached.
- Interfaccia di amministrazione per gestire le impostazioni.
Domande
Perchè non basta solo la Page Cache?
Perchè non tutte le richieste sono soggette a page cache. Ad esempio:
- utenti loggati
- pagine WooCommerce come carrello e checkout
- chiamate admin-ajax.php
- chiamate REST API
Per le pagine con cache scaduta, bisogno rigenerare la cache, e anche in questo caso usare object cache può essere utile per farci risparmiare tempo e risorse.
Sistemi come Redis riducono la pressione sul Database.
Posso salvare l’object cache in file .json per renderli persistenti?
Visto che non ho Redis disponibile sul mio server condiviso, ho pensato: perchè non salvare l’object cache in file .json persistenti?
La risposta è che probabilmente non è una buona idea, perchè nella generazione di una pagina, andrei a richiedere 50+ file salvati come object cache, il che lo renderebbe probabilmente più lento rispetto alla richiesta delle queries da database.


