Wpis zaplanowany na 9:00 o 9:30 dalej ma status „Zaplanowany”. Wtyczka kopii zapasowych od rana nic nie zrobiła. Czy to wina hostingu? Zwykle nie: WordPress czeka, aż ktoś wejdzie na stronę. Zmierzyliśmy to czekanie na testowej instalacji i pokazujemy log przed i po przejściu na prawdziwy harmonogram.
Dlaczego WP-Cron czeka na odwiedzającego
WP-Cron to harmonogram zaszyty w WordPressie, a nie cron systemu. Według dokumentacji WordPressa sprawdza przy każdym załadowaniu strony listę zaplanowanych zadań i wykonuje te, którym minął termin. Nie działa w tle, tylko przy wizycie. Dokumentacja ostrzega, że zadanie zaplanowane na 14:00 spóźni się, jeśli pierwsza wizyta przyjdzie dopiero o 17:00.
Z WP-Crona korzysta rdzeń WordPressa (sprawdzanie aktualizacji, publikowanie zaplanowanych wpisów) i wiele wtyczek. Zaległe zadania nie przepadają, tylko czekają w kolejce na najbliższą wizytę. Dokumentacja ujmuje to tak, że zadanie na pewno się wykona, ale nie wiadomo kiedy. Na stronie firmowej, którą w nocy nikt nie odwiedza, to „kiedyś” potrafi trwać wiele godzin.
Log przed: 25 minut bez odwiedzin
Postawiliśmy czystego WordPressa 7.1.4 kreatorem na serwerze testowym, w osobnym kontenerze, z WP-Cronem w ustawieniu domyślnym. Wszystkie czasy poniżej są w UTC, bo serwer chodzi w UTC.
Zaplanowaliśmy dwie rzeczy. Wpis miał wyjść o 20:34:40. Zdarzenie testowe miało się wykonywać co 5 minut od 20:29:40 i dopisywać do pliku chwilę swojego uruchomienia. Potem przez 25 minut nikt nie wszedł na stronę, a dziennik dostępu Apache zostawał pusty. Stan po tym czasie:
20:49:44 UTC
$ wp cron event list --fields=hook,next_run_gmt
hook next_run_gmt
t774_zdarzenie 2026-11-05 20:29:40
publish_future_post 2026-11-05 20:34:40
$ wp post get 5 --fields=ID,post_status,post_date_gmt
ID 5
post_date_gmt 2026-11-05 20:34:40
post_status future
plik z logiem zdarzenia: nie istnieje, zdarzenie nie wykonało się ani razu
żądania w dzienniku dostępu Apache od początku pomiaru: 0
Oba terminy minęły: zdarzenia o 20 minut, wpisu o 15. Potem weszliśmy na stronę jednym zwykłym GET /:
20:49:46 UTC GET / -> 200
dziennik dostępu Apache:
127.0.0.1 - - [05/Nov/2026:20:49:46 +0000] "POST /wp-cron.php?doing_wp_cron=1793911786.40… HTTP/1.1" 200 315 "-" "WordPress/7.1.4; http://t774.isbre.pl"
127.0.0.1 - - [05/Nov/2026:20:49:46 +0000] "GET / HTTP/1.1" 200 69609 "-" "curl/8.14.1"
20:49:54 UTC
post_status publish
t774_zdarzenie następny termin 2026-11-05 20:54:40
plik z logiem zdarzenia:
2026-11-05 20:49:46 UTC t774_zdarzenie wykonane
Ta jedna wizyta wystarczyła. WordPress sam zawołał wp-cron.php (to POST z agentem „WordPress/7.1.4” w tej samej sekundzie),
opublikował wpis z 15-minutowym spóźnieniem i wykonał zdarzenie. Pięć terminów tego zdarzenia (20:29:40, 20:34:40, 20:39:40, 20:44:40
i 20:49:40) skończyło się jednym wykonaniem, a następny termin ustawił na 20:54:40. Gdyby wizyta przyszła rano, spóźnienie
wyniosłoby godziny, nie minuty.
Krok 1: wyłącz uruchamianie z ruchu
W wp-config.php dopisz nad wierszem „That’s all, stop editing!” jedną linię:
define( 'DISABLE_WP_CRON', true );
Możesz też zrobić to z WP-CLI przez SSH: wp config set DISABLE_WP_CRON true --raw --type=constant. Polecenie wstawia stałą
we właściwym miejscu pliku, nad wierszem „stop editing”. Dokumentacja WordPressa mówi, że ta stała wyłącza cron w całości,
więc zrób krok 2 od razu. Bez niego nic się nie wykona, nawet przy odwiedzinach.
Krok 2: dodaj zadanie w panelu
W panelu otwórz usługę, wejdź w „Zadania cykliczne (cron)”, kliknij „Dodaj zadanie” i wypełnij dwa pola.
Harmonogram: */5 * * * *, czyli co 5 minut. Gotowy przycisk „Co 15 minut” też się nada, jeśli kwadrans opóźnienia nie przeszkadza.
Komenda (jedna linia, w miejsce twojadomena.pl wpisz swoją domenę). Taką komendę podpowiada też panel w polu „Komenda”:
cd ~/domains/twojadomena.pl/public_html && wp cron event run --due-now >> ~/logs/wp-cron.log 2>&1
Każdy kawałek ma swoją robotę:
cd ~/domains/twojadomena.pl/public_htmlwchodzi do katalogu, w którym leży WordPress.wp cron event run --due-nowto polecenie WP-CLI, które wykonuje zdarzenia z minionym terminem. Według dokumentacji WP-CLI pilnuje przy tym blokadydoing_cron, więc dwa przebiegi nie nałożą się na siebie. Programywp,composeriphpdziałają w zadaniu bez pełnej ścieżki, tak jak w SSH.>> ~/logs/wp-cron.log 2>&1dopisuje wynik do pliku w katalogulogs, w którym leży też dziennik błędów PHP. To jedyne miejsce, w którym zobaczysz wynik zadania: crontab ma ustawioneMAILTO="", więc nic nie przychodzi pocztą.
Chcesz mieć w logu godzinę każdego przebiegu? Owiń polecenie w nawias z date:
cd ~/domains/twojadomena.pl/public_html && (date '+\%F \%T'; wp cron event run --due-now) >> ~/logs/wp-cron.log 2>&1
Znak % ma w crontabie znaczenie specjalne, dlatego w date stoi przed nim ukośnik. W takiej postaci zadanie działało w pomiarze niżej.
Dokumentacja WordPressa proponuje prostszy wariant: cron wywołujący wget --delete-after adres-twojej-strony/wp-cron.php. Działa, ale idzie
przez serwer WWW, a więc podlega limitowi czasu żądania. WP-CLI uruchamia PHP z konsoli, które nie ma limitu czasu wykonania (zmierzyliśmy
max_execution_time równe 0), więc długie zadanie wtyczki nie zostanie ucięte w połowie.
Polecenie php w konsoli nie musi być wersją, na której chodzi strona. Jeśli zadanie ma użyć tej samej, wpisz ją wprost:
php8.4 /usr/local/bin/wp cron event run --due-now.
Log po: 17 minut bez odwiedzin
Ten sam układ, ten sam WordPress, tym razem z krokami 1 i 2: stała DISABLE_WP_CRON w wp-config.php (WP-CLI wstawiło ją nad wierszem „stop editing”)
i zadanie */5 * * * * z komendą z kroku 2, w wariancie z date, założone tym samym poleceniem serwera, które woła panel. Zdarzenie testowe z poprzedniego pomiaru zostało. Nowy
wpis zaplanowaliśmy na 20:58:06. Przez kolejne 17 minut nikt nie wszedł na stronę, a dziennik dostępu Apache dalej miał zero żądań. Tak wyglądał ~/logs/wp-cron.log:
2026-11-05 20:55:01
Executed the cron event 'do_pings' in 0.439s.
Executed the cron event 't774_zdarzenie' in 0.008s.
Success: Executed a total of 2 cron events.
2026-11-05 21:00:01
Executed the cron event 'publish_future_post' in 0.076s.
Executed the cron event 't774_zdarzenie' in 0.011s.
Success: Executed a total of 2 cron events.
2026-11-05 21:05:01
Executed the cron event 'do_pings' in 0.444s.
Executed the cron event 't774_zdarzenie' in 0.019s.
Success: Executed a total of 2 cron events.
A tak plik zdarzenia testowego, do którego dopisuje się jego własny kod:
2026-11-05 20:49:46 UTC t774_zdarzenie wykonane
2026-11-05 20:55:03 UTC t774_zdarzenie wykonane
2026-11-05 21:00:02 UTC t774_zdarzenie wykonane
2026-11-05 21:05:02 UTC t774_zdarzenie wykonane
Pierwsza linia tego pliku pochodzi jeszcze z pomiaru „przed”. Przebiegi zadania ruszają o równych porach, co 5 minut: 20:55:01, 21:00:01 i 21:05:01. Wpis z terminem 20:58:06 wyszedł w przebiegu z 21:00:01, 1 minutę i 55 sekund po czasie, a dziennik dostępu Apache dalej
nie miał ani jednego żądania. Zdarzenie testowe, które w pomiarze „przed” stało 20 minut nieruszone, wykonywało się teraz w pierwszym przebiegu po terminie (20:54:40, 20:59:40, 21:04:40),
od 22 do 23 sekund po nim. Spóźnienie zależy więc od tego, jak termin trafia w przebieg: raz było to 22 sekundy, raz prawie 2 minuty, a górną granicą jest odstęp zadania. Nazwa do_pings w logu to zdarzenie rdzenia, które WordPress dokłada po opublikowaniu
wpisu: po publikacji z 20:49 poszło w przebiegu z 20:55, po publikacji z 21:00 w przebiegu z 21:05.
Pozostaje pytanie, czy wizyta nadal cokolwiek uruchamia. O 21:07:10 dołożyliśmy zdarzenie jednorazowe z terminem „teraz” i od razu weszliśmy na stronę:
21:07:12 UTC GET / -> 200
dziennik dostępu Apache od początku pomiaru:
127.0.0.1 - - [05/Nov/2026:21:07:12 +0000] "GET / HTTP/1.1" 200 71438 "-" "curl/8.14.1"
21:07:22 UTC
hook next_run_gmt
t774_jednorazowe 2026-11-05 21:07:11
21:10:01 UTC, wp-cron.log:
Executed the cron event 't774_jednorazowe' in 0.006s.
W dzienniku nie ma żadnego POST /wp-cron.php. Zdarzenie czekało zaległe, aż ruszył przebieg zadania o 21:10:01. Po kroku 1 wizyty niczego już nie uruchamiają, robi to wyłącznie zadanie z panelu.
Na co uważać
- Spóźnienie ma górną granicę. Granicą jest odstęp zadania: przy
*/5zdarzenie rusza najpóźniej 5 minut po terminie, przy przycisku „Co 15 minut” kwadrans po nim. Wpis zaplanowany na 8:00 wyjdzie w pierwszym przebiegu po 8:00. - Jedna instalacja, jedno zadanie. WP-CLI działa na katalogu, do którego wejdzie
cd, więc drugi WordPress (inna domena albo podkatalog) potrzebuje własnego zadania. Limit zadań zależy od pakietu: od 3 w Start do 50 w Max. - Godziny w panelu to UTC. Panel pisze to przy polu „Harmonogram” i przy gotowych przyciskach („Codziennie o 6:00 UTC”). Zadanie na
0 6 * * *ruszy o 7:00 zimą i o 8:00 latem, a „następnie” na liście zadań też jest w UTC. Przy*/5nie ma to znaczenia, przy zadaniu dziennym ma. - Log nie obraca się sam. Dziennik błędów PHP w katalogu
logsplatforma obraca, alewp-cron.logjuż nie. Przebieg bez zdarzeń dopisuje do niego około 64 bajtów, a przebieg z dwoma zdarzeniami około 160. Przy 288 przebiegach na dobę to od 18 do 46 KB. Od czasu do czasu skasuj plik.
Strona z izolacją ma własny harmonogram. Wybierz ją w polu „Gdzie uruchomić”, bo zadanie konta głównego nie ma dostępu do jej plików. Zadanie wykona się jako użytkownik tej strony, bez katalogu domowego, więc wszystkie ścieżki podaj w całości. Katalog logs konta jest dla takiej strony zamknięty do zapisu, dlatego log trafia do katalogu tmp strony. Panel podpowiada to po wybraniu strony, a login zamień na login konta:
cd /home/login/domains/twojadomena.pl/public_html && wp cron event run --due-now >> /home/login/domains/twojadomena.pl/tmp/wp-cron.log 2>&1
Co sprawdzić dziś
- Zajrzyj do
wp-config.phpi do panelu. StałaDISABLE_WP_CRONbez zadania w panelu znaczy, że żadne zdarzenie się nie wykona. Zadanie bez stałej znaczy, że WordPress dalej uruchamia cron także przy wizytach. - Zaplanuj wpis na najbliższe 10 minut i sprawdź w kokpicie po kwadransie. Przy włączonym kroku 1 wizyta w kokpicie niczego nie uruchamia, więc jeśli wpis wyszedł, zrobiło to zadanie.
- Po godzinie otwórz
~/logs/wp-cron.log, przez SFTP albo SSH. Powinien mieć wpis co 5 minut, a w nim „Success: Executed a total of N cron events.”. - Jeśli po kwadransie nie ma pliku
wp-cron.log,cdnie trafił w katalog WordPressa. Błądcdnie trafia do logu, więc sprawdź ścieżkę z zadania na liście i w SFTP.
Źródła
Strony odczytane 5 listopada 2026 (mogą się zmienić):
- WordPress, Cron:
developer.wordpress.org/plugins/cron/ - WordPress, Hooking WP-Cron Into the System Task Scheduler:
developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/ - WordPress, Editing wp-config.php:
developer.wordpress.org/advanced-administration/wordpress/wp-config/ - WP-CLI, wp cron event run:
developer.wordpress.org/cli/commands/cron/event/run/