Wydajność

Cache w WordPress — jak działa i które wtyczki wybrać?

Dowiedz się jak działa cache w WordPress, jakie są jego rodzaje i która wtyczka cache będzie najlepsza dla Twojej strony. Praktyczny poradnik.

DDawid Penkala
Zaktualizowano: 8 min czytania
Serwery i infrastruktura IT — wizualizacja systemu cache

„Zainstaluj WP Rocket i będzie szybko” — najczęstsza porada w polskim internecie dotycząca cache w WordPressie. Czasem działa. Najczęściej pomija 60% problemu.

Cache w WordPressie to nie jedna rzecz, to pięć. Każda rozwiązuje inne wąskie gardło. Poniżej — warstwy, co robią, i kiedy która ma sens.

Dlaczego jedna wtyczka nie wystarczy

Zrozumienie jak WP generuje stronę to fundament. Przy każdym requeście dzieje się:

  1. nginx/Apache odbiera żądanie i odpala PHP-FPM,
  2. PHP parsuje rdzeń WordPressa (setki plików, kilkadziesiąt MB kodu),
  3. WP łączy się z MySQL/MariaDB i wykonuje 50–300 zapytań,
  4. motyw renderuje template’y i shortcody,
  5. serwer zwraca HTML.

Etapy 2–4 to ~200–600 ms nawet na dobrym hostingu. Bez cache’u każdy user płaci ten koszt za siebie.

Cache skraca jeden z tych etapów — inne warstwy inne etapy. Dlatego mówimy o pięciu warstwach.

Warstwa 1: OPcache (PHP)

Nie ruszasz, ale warto wiedzieć, że istnieje. OPcache to wbudowany w PHP mechanizm, który zapisuje skompilowane pliki PHP w pamięci. Zamiast parsować wp-blog-header.php przy każdym requeście, PHP używa już skompilowanej wersji.

Działa out-of-the-box od PHP 5.5. Upewnij się tylko, że jest włączony (php -m | grep OPcache). Na dobrym hostingu zawsze jest.

Efekt: −30–50 ms na jedno żądanie. Niewielki, ale darmowy.

Warstwa 2: Object Cache (Redis/Memcached)

Ta warstwa jest niedoceniana. WordPress w standardzie ma in-process object cache — trzyma wyniki zapytań bazy tylko w pamięci jednego requestu PHP. Następny request = od zera.

Object Cache (Redis albo Memcached) to trwała pamięć między requestami. Pierwsze zapytanie do get_option('siteurl') trafia do bazy, wynik ląduje w Redis. Kolejne 10 000 requestów bierze z Redis (0.1 ms) zamiast z MySQL (1–5 ms).

Aktywacja (zakładając że hosting ma Redis):

wp plugin install redis-cache --activate

W wp-config.php:

define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_CACHE_KEY_SALT', 'moja-domena.pl:');

Potem wp redis enable z WP-CLI albo przycisk w ustawieniach wtyczki.

Efekt u nas mierzony: na sklepie WooCommerce z 8000 produktów — liczba zapytań MySQL per home request z 180 do 18. TTFB 900 ms → 340 ms.

Kiedy ma sens: zawsze na sklepach WooCommerce i stronach membership. Rzadziej na prostych blogach (tam różnica jest mniej odczuwalna).

Warstwa 3: Page Cache (full-page HTML)

To jest to, co ludzie mają na myśli mówiąc „cache w WordPressie”. Gotowy HTML strony zapisany na dysku (albo w Redis), serwowany bez uruchamiania PHP.

Popularne opcje:

  • WP Rocket ($59/rok) — pay-to-win. Działa bez konfiguracji, robi też preload, defer JS, minifikację. Kupujemy u większości klientów.
  • LiteSpeed Cache (darmowy) — jeśli hosting używa LiteSpeed HTTP Server. Działa wtedy na poziomie serwera (szybciej niż WP Rocket), ale nie pomoże na nginx/Apache.
  • W3 Total Cache (darmowy) — zaawansowane opcje, stroma krzywa uczenia. Używamy rzadko, głównie gdy klient chce pełną kontrolę bez kosztu.
  • Cache Enabler (darmowy, od KeyCDN) — minimalistyczna, nie ma opcji nawet na dzień dobry, ale robi swoją pracę.

Kiedy NIE używać Page Cache:

  • Strony zbyt personalized (sklep z zalogowanym userem — cache może wyświetlić koszyk innego).
  • Sklepy na WooCommerce bez exclude reguł dla /cart/, /checkout/, /my-account/ — krytyczne, inaczej wycieka prywatny cart innego klienta.

Każda wtyczka page cache ma ustawienia „exclude from cache” dla tych ścieżek. Włącz je przed aktywacją cache na produkcji.

Warstwa 4: Browser Cache

Klient (przeglądarka) przechowuje statyki lokalnie. Drugi request na tę samą stronę = obrazy, CSS, JS pobrane z dysku użytkownika, nie z serwera.

Ustawiamy w .htaccess (Apache) albo konfiguracji nginx:

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
</IfModule>

Statyki dostają max-age=31536000, immutable — browser nie zapyta serwera przez rok. Klucz: pliki muszą mieć wersjonowanie (style.css?v=2.1.3 albo style.abc123.css). W WordPressie domyślnie ?ver= się pojawia, ale niektóre wtyczki to rozbijają.

Warstwa 5: Edge Cache (CDN / Cloudflare Worker)

Warstwa, o której mało kto w WordPressie mówi, a daje największe różnice dla użytkowników z dalszych lokalizacji.

Opcje:

  • Cloudflare APO (Automatic Platform Optimization, $5/mies.) — cache’uje HTML stron WP na edge’u CF. Działa tylko gdy domena jest na CF w tryb pełnego proxy mode.
  • BunnyCDN / KeyCDN z custom cache rules dla HTML.
  • Własny Cloudflare Worker — najwięcej kontroli. U nas na devance.agency Worker cache’uje strony na edge’u z 10-minutowym TTL i bypass dla ścieżek dynamicznych (/konto/, /zamowienie/). Pierwszy user z Warszawy dostaje HTML w ~40 ms, koleje w 20 ms.

Kiedy ma sens: przy ruchu > 1000 unique/day. Przy 50 users/day różnica niewielka (cache ciągle wygasa przed kolejnym userem).

Typowa kombinacja u klientów

Zwykły sklep WooCommerce, ~500 zamówień/mies:

  1. OPcache — hosting (zawsze).
  2. Redis Object Cache — redis-cache plugin.
  3. WP Rocket — page cache + defer JS + lazy loading.
  4. Browser cache — .htaccess rules.
  5. Cloudflare free plan — browser cache + basic DDoS.

Koszt: 59 $/rok WP Rocket + ~20 zł/mies dodatkowo za Redis (jeśli hosting go nie ma w pakiecie).

Debugging cache issues

Najczęstsze problemy, z którymi trafiają do nas klienci po wdrożeniu cache:

  • „Zmieniłem tekst, ale się nie pojawia” — cache page trzyma starą wersję. Rozwiązanie: ręczne Clear Cache w wtyczce, lub wp cache flush + flush w wtyczce.
  • „Koszyk pokazuje produkty innego klienta” — brak wykluczenia /cart/ z cache. Krytyczny bug, natychmiast wyłączyć cache na tych ścieżkach.
  • „Login do WP-Admin nie działa” — cache serwuje zalogowanemu userowi stronę guest. Wykluczyć /wp-admin/, /wp-login.php i ciasteczko wordpress_logged_in_*.
  • „Strona wygląda połamana po aktywacji” — minifikacja CSS/JS psuje reguły. Wyłącz concatenation, zostaw tylko minify.

Każdy z tych problemów widzieliśmy co najmniej 3 razy. Przyczyna zwykle: domyślne ustawienia WP Rocket/LiteSpeed nie pasują do niestandardowej konfiguracji. Przed aktywacją na produkcji — zawsze test na stagingu.

Jak zmierzyć efekt cache

Przed cache: PageSpeed mobile → zapamiętaj LCP, TTFB, Total Blocking Time.

Po: ten sam test, ale koniecznie 2 razy pod rząd z tym samym URL. Drugi wynik pokazuje cold cache vs warm cache. Różnica to właściwy efekt.

Dodatkowo w CLI:

curl -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" -o /dev/null -s https://twoja-domena.pl/

U naszych klientów typowe wyniki po aktywacji pełnego stacku cache: LCP mobile z 3.5–4.5 s do 1.2–1.8 s, TTFB z 400–800 ms do 80–150 ms.


Cache działa — ale źle skonfigurowany potrafi wysłać prywatne dane klientów do innych. Jeśli prowadzisz sklep na WooCommerce i nie wiesz, jakie wykluczenia masz ustawione, umów audyt — sprawdzenie zajmuje 15 minut, a wyciek takich danych kosztuje znacznie więcej.

Tagi:WordPresscachewydajnośćoptymalizacjawtyczkiszybkość
Dawid Penkala
Dawid Penkala

Doświadczony WordPress Developer z ponad 14-letnim stażem w tworzeniu zaawansowanych stron i sklepów internetowych. Specjalizuje się w WordPressie, dedykowanych wtyczkach i motywach.

Więcej o autorze