Strona rzadko traci ruch jednym spektakularnym ruchem. Częściej wygląda to mniej widowiskowo: artykuł, który przez rok dowoził wejścia z Google, zaczyna z tygodnia na tydzień oddawać pozycje. Najpierw spada CTR. Potem liczba kliknięć. Na końcu ktoś w zespole mówi: „ten temat już chyba nie działa”. Problem w tym, że wtedy zwykle jest za późno.
Content decay nie powinien być wykrywany raz na kwartał podczas ręcznego przeglądania raportów. W sensownie prowadzonym serwisie WordPress powinien sam raz w tygodniu sprawdzić dane z Google Search Console, porównać je z bazą wpisów i oznaczyć artykuły, które zaczęły tracić widoczność. Nie chodzi o magiczne SEO. Chodzi o prosty system wczesnego ostrzegania: który URL spada, jak mocno, od kiedy i czy warto go odświeżyć teraz, czy zostawić w spokoju.
Dane z GSC w bazie WordPressa: co pobierać i jak często
Najważniejsza decyzja: nie pobierać „wszystkiego, co się da”. To pierwszy błąd przy automatyzacji Search Console. System do Content Decay Tracking ma odpowiadać na jedno pytanie: które istniejące wpisy zaczynają tracić ruch organiczny. Do tego wystarczy kilka pól:
- URL strony,
- data,
- kliknięcia,
- wyświetlenia,
- CTR,
- średnia pozycja,
- opcjonalnie: zapytanie, jeżeli chcemy diagnozować spadek po frazach.
W praktyce najlepszy start to pobieranie danych z wymiarami page oraz date. Dopiero druga wersja systemu powinna schodzić do poziomu query, bo wtedy liczba rekordów rośnie szybko i łatwo zbudować narzędzie, które bardziej mieli dane, niż pomaga redakcji.
Minimalna tabela w bazie WordPressa może wyglądać tak:
CREATE TABLE wp_content_decay_gsc_daily (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
post_id BIGINT UNSIGNED NULL,
url_hash CHAR(32) NOT NULL,
url TEXT NOT NULL,
date DATE NOT NULL,
clicks INT UNSIGNED NOT NULL DEFAULT 0,
impressions INT UNSIGNED NOT NULL DEFAULT 0,
ctr DECIMAL(8,5) NOT NULL DEFAULT 0,
position DECIMAL(8,2) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY url_date (url_hash, date),
KEY post_date (post_id, date),
KEY date_clicks (date, clicks)
);
Pole url_hash to najczęściej hash MD5 wygenerowany z pełnego adresu URL. Działa jako wydajny, stałodługościowy klucz unikalny, ponieważ indeksowanie długich wartości tekstowych z kolumny url TEXT w MySQL jest niewygodne i mniej efektywne niż indeksowanie krótkiego pola CHAR(32).
Dlaczego osobna tabela, a nie postmeta? Bo postmeta dobrze nadaje się do kilku wartości przy wpisie, ale źle znosi dzienne szeregi danych dla setek albo tysięcy URL-i. Jeżeli serwis ma 800 artykułów i zapisujesz dane z 90 dni, robisz 72 tysiące rekordów. Przy zejściu do poziomu zapytań można dojść do milionów. Wpychanie tego do wp_postmeta kończy się wolnym kokpitem i zapytaniami SQL, których nikt później nie chce dotykać.
Pobieranie warto ustawić raz w tygodniu, ale dane powinny obejmować ostatnie 90 dni. Dlaczego nie tylko ostatnie 7? Bo pojedynczy tydzień potrafi kłamać. Długi weekend, sezonowość, aktualizacja Google, chwilowy brak danych albo jeden mocny pik z newslettera potrafią zaburzyć obraz. Dla większości serwisów poradnikowych sensowny zakres to:
- ostatnie 28 dni jako okres badany,
- poprzednie 28 dni jako okres porównawczy,
- minimum 30 kliknięć w okresie bazowym, żeby nie flagować przypadkowego szumu,
- minimum 100 wyświetleń, jeżeli CTR ma być traktowany poważnie.
Tygodniowy import można oprzeć na WP-Cronie, ale z jednym zastrzeżeniem: sam WP-Cron odpala się po wejściu użytkownika na stronę. Na małym blogu zadanie może uruchomić się z opóźnieniem, a na stronie z cache’em bywa jeszcze gorzej. Dlatego w produkcji lepszy układ jest prosty:
- w WordPressie rejestrujesz zadanie cykliczne,
- wyłączasz automatyczne wywoływanie WP-Cron przez
DISABLE_WP_CRON, - ustawiasz prawdziwy cron na serwerze, np. co 15 minut wywołujący
wp-cron.php, - samo zadanie importu pilnuje, czy cotygodniowy przebieg już się wykonał.
Nie ma sensu odpalać importu co godzinę. Dane z Search Console nie są narzędziem realtime, a content decay nie wymaga reakcji w ciągu 20 minut. Tygodniowy rytm jest wystarczający i zdrowszy dla zespołu: autorzy dostają jedną listę priorytetów, a nie codzienny alarm, który po miesiącu wszyscy ignorują.
Warto też od razu rozdzielić dwa procesy:
- import danych GSC — pobiera i zapisuje surowe dane,
- analiza decay — liczy trendy i zapisuje status przy wpisie.
To drobiazg architektoniczny, ale ratuje skórę. Jeżeli import się wysypie przez limit API, problem z autoryzacją albo timeout serwera, nie niszczysz wcześniejszych wyników analizy. System po prostu pokazuje datę ostatniego poprawnego importu.
Reguły wykrywania content decay: kiedy artykuł naprawdę wymaga odświeżenia
Nie każdy spadek kliknięć oznacza, że tekst umiera. To trzeba powiedzieć mocno, bo automatyzacja bez progów decyzyjnych zamienia kokpit WordPressa w choinkę z czerwonymi alertami.
Najprostsza reguła brzmi:
Artykuł trafia na listę odświeżenia, gdy:
- miał co najmniej 30 kliknięć w poprzednich 28 dniach,
- kliknięcia spadły o minimum 25%,
- wyświetlenia spadły o minimum 15% albo średnia pozycja pogorszyła się o minimum 2 miejsca,
- wpis nie był aktualizowany przez ostatnie 60 dni.
To nie jest idealny model statystyczny. I dobrze. Na start nie potrzeba doktoratu z analityki, tylko reguły, która odsieje przypadkowe wahania i pokaże redakcji realne tematy do pracy.
Lepszy algorytm powinien liczyć trzy osobne sygnały:
1. Spadek kliknięć
Najbardziej zrozumiały dla autora i właściciela serwisu. Jeżeli artykuł miał 400 kliknięć w poprzednich 28 dniach, a teraz ma 250, problem jest widoczny bez wykresu.
2. Spadek wyświetleń
Pokazuje, czy Google rzadziej pokazuje stronę. To często oznacza utratę pozycji, zmianę intencji wyników albo mocniejszą konkurencję.
3. Spadek CTR przy stabilnych wyświetleniach
To osobna kategoria. Jeżeli wyświetlenia stoją, ale CTR spada, tekst nadal jest widoczny, tylko użytkownicy rzadziej klikają. Wtedy pierwszym podejrzeniem nie jest treść artykułu, lecz title, meta description, data w tytule, snippet albo to, że konkurencja pokazuje konkretniejszą obietnicę.
W bazie można zapisać wynik analizy w drugiej tabeli:
CREATE TABLE wp_content_decay_flags (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
post_id BIGINT UNSIGNED NOT NULL,
url_hash CHAR(32) NOT NULL,
status VARCHAR(20) NOT NULL,
severity TINYINT UNSIGNED NOT NULL DEFAULT 0,
clicks_current INT UNSIGNED NOT NULL DEFAULT 0,
clicks_previous INT UNSIGNED NOT NULL DEFAULT 0,
clicks_delta_percent DECIMAL(8,2) NOT NULL DEFAULT 0,
impressions_delta_percent DECIMAL(8,2) NOT NULL DEFAULT 0,
position_delta DECIMAL(8,2) NOT NULL DEFAULT 0,
detected_at DATETIME NOT NULL,
resolved_at DATETIME NULL,
PRIMARY KEY (id),
KEY post_status (post_id, status),
KEY severity_detected (severity, detected_at)
);
Statusy powinny być proste:
- watch — lekki spadek, obserwować,
- refresh — wpis do aktualizacji,
- urgent — duży spadek na stronie, która wcześniej dowoziła ruch,
- resolved — spadek obsłużony albo trend wrócił do normy.
Największy priorytet dostają wpisy, które miały realny ruch. Artykuł, który spadł z 6 kliknięć do 2, nie powinien wyprzedzać tekstu, który spadł z 900 do 520. Prosty wzór na wagę alertu może wyglądać tak:
severity = spadek kliknięć w % + utracone kliknięcia / 10 + pogorszenie pozycji × 5
Przykład:
- wpis A: 900 → 520 kliknięć, spadek 42%, utracone 380 kliknięć, pozycja gorsza o 1,8
wynik: 42 + 38 + 9 = 89 - wpis B: 40 → 20 kliknięć, spadek 50%, utracone 20 kliknięć, pozycja gorsza o 0,5
wynik: 50 + 2 + 2,5 = 54,5
Drugi wpis procentowo wygląda gorzej. Pierwszy boli biznesowo bardziej. I właśnie dlatego system nie może opierać się wyłącznie na procentach.
Trzeba też dodać wyjątki. Bez nich alerty będą głupie.
Nie flaguj automatycznie:
- artykułów opublikowanych krócej niż 90 dni temu,
- wpisów sezonowych poza sezonem, np. „prezenty na święta” w lutym,
- stron z bardzo małą liczbą kliknięć,
- artykułów, które zostały zaktualizowane w ostatnich 14–30 dniach,
- URL-i z noindex, przekierowaniem albo błędem kanonicznym.
Dobra praktyka: w edycji wpisu dodaj pole „monitoruj content decay”. Dla evergreenów zostaje włączone. Dla newsów, landingów kampanijnych i tekstów sezonowych można je wyłączyć albo zmienić typ monitoringu. To ważne, bo jeden algorytm dla wszystkich treści szybko zacznie dawać fałszywe rekomendacje.
Najbardziej praktyczny podział wygląda tak:
- evergreen — monitoruj stale,
- seasonal — porównuj rok do roku, nie miesiąc do miesiąca,
- news — nie flaguj jako decay po naturalnym spadku,
- commercial — ustaw ostrzejsze progi, bo utrata ruchu może oznaczać utratę leadów.
Właśnie tu zaczyna się różnica między raportem a systemem redakcyjnym. Raport pokazuje spadki. System mówi, czy warto coś z nimi zrobić.
Flagi w kokpicie WP: jak zamienić dane w listę zadań dla autorów
Najgorszy sposób prezentacji danych? Tabela z 20 kolumnami i filtrem „eksportuj CSV”. Nikt poza osobą od SEO nie będzie z tego korzystał. Autor potrzebuje krótkiej informacji: który tekst odświeżyć, dlaczego i od czego zacząć.
W kokpicie WordPressa warto dodać osobny widok: Treści do odświeżenia. Kolumny powinny być ograniczone do minimum:
| Kolumna | Po co jest |
|---|---|
| Tytuł wpisu | autor od razu wie, czego dotyczy zadanie |
| Status | watch, refresh albo urgent |
| Utracone kliknięcia | pokazuje skalę problemu |
| Zmiana pozycji | pomaga ocenić utratę widoczności |
| Zmiana CTR | wskazuje problem ze snippetem |
| Ostatnia aktualizacja | chroni przed ponownym grzebaniem w świeżo poprawionym tekście |
| Rekomendacja | konkret: title, treść, sekcja FAQ, data, parametry techniczne |
Jak mogą wyglądać takie automatyczne reguły w praktyce? Oto kilka przykładów:
- spadł CTR, ale wyświetlenia są stabilne → przepisać title i meta description,
- spadły wyświetlenia i pozycja → porównać treść z aktualnymi wynikami TOP 5,
- pozycja stabilna, ale kliknięcia spadły sezonowo → oznaczyć jako seasonal albo odłożyć,
- spadły kliknięcia na wpisie z datą w tytule → sprawdzić, czy data nie obniża zaufania,
- wpis nie był aktualizowany ponad 12 miesięcy → sprawdzić aktualność danych, screenów, cen i instrukcji.
Przy każdym wpisie dobrze działa mały panel w edycji artykułu:
Content Decay
Status: refresh
Utracone kliknięcia: -143 w ostatnich 28 dniach
Zmiana CTR: -1,8 p.p.
Pozycja: 6,4 → 8,1
Ostatnia aktualizacja: 11 miesięcy temu
Sugestia:
Najpierw popraw title i lead. Potem sprawdź sekcje z danymi technicznymi.
To jest forma, którą autor rozumie bez szkolenia z Search Console.
Technicznie flagę można zapisać jako post meta, bo to już nie jest seria dziennych danych, tylko aktualny status wpisu:
register_post_meta('post', '_content_decay_status', [
'single' => true,
'type' => 'string',
'show_in_rest' => true,
'auth_callback' => function() {
return current_user_can('edit_posts');
},
]);
Ten kod tylko rejestruje pole i udostępnia je w REST API. Sama wartość powinna być aktualizowana podczas cotygodniowego procesu analizy trendów. Gdy algorytm wyliczy status refresh, urgent, watch albo resolved, system powinien zapisać wynik przy konkretnym wpisie, np.:
update_post_meta(
$post_id,
'_content_decay_status',
$calculated_status
);
Dzięki show_in_rest pole można później pokazać w edytorze blokowym albo obsłużyć przez własny panel Reactowy. Nie trzeba jednak zaczynać od rozbudowanej aplikacji w kokpicie. Pierwsza wersja może być zwykłą stroną administracyjną z tabelą, filtrem statusu i przyciskiem „oznacz jako obsłużone”.
Najważniejsze są trzy funkcje:
1. Widok priorytetów
Domyślne sortowanie po severity, nie po dacie. Redakcja ma zaczynać od wpisów, które straciły największy potencjał.
2. Historia decyzji
Po aktualizacji wpisu zapisz, kto go oznaczył jako poprawiony i kiedy. Bez tego za dwa miesiące nikt nie będzie wiedział, czy spadek został obsłużony, czy tylko zignorowany.
3. Chłodzenie alertów
Po aktualizacji wpisu nie pokazuj go ponownie przez 30 dni, chyba że spadek jest bardzo duży. Google potrzebuje czasu na ponowną ocenę treści, a autor nie powinien poprawiać tego samego artykułu co tydzień.
Dobry system nie kończy się na czerwonej fladze. Powinien prowadzić do decyzji redakcyjnej. Dla wpisu oznaczonego jako refresh autor powinien wykonać checklistę:
- sprawdzić, czy temat nadal odpowiada intencji użytkownika,
- porównać nagłówki i zakres informacji z aktualnymi wynikami TOP 5,
- usunąć nieaktualne daty, ceny, narzędzia i instrukcje,
- dopisać brakujące sekcje, których oczekuje użytkownik,
- poprawić title, jeżeli CTR spadł mocniej niż wyświetlenia,
- zweryfikować przykłady, screeny, procedury i wartości liczbowe,
- zapisać datę aktualizacji i krótki opis zmian.
Nie każdy tekst trzeba przepisywać od zera. To kolejna pułapka. Jeżeli problemem jest CTR, zaczynasz od tytułu i opisu. Jeżeli problemem jest utrata pozycji, aktualizujesz treść. Jeżeli problemem jest sezonowość, zmieniasz sposób porównywania danych. Jeżeli problemem jest kanibalizacja, automatyczny system decay tylko pokaże objaw — decyzja będzie dotyczyła połączenia, przekierowania, rozdzielenia albo przebudowy zakresu treści.
Najlepszy pierwszy krok? Zbudować wersję minimalną:
- pobieranie danych GSC raz w tygodniu,
- tabela dzienna dla URL-i,
- porównanie 28 dni do poprzednich 28 dni,
- próg minimum 30 kliknięć,
- lista wpisów
refreshiurgentw kokpicie, - ręczne oznaczanie jako obsłużone.
Dopiero po miesiącu pracy z takim systemem warto dodawać analizę zapytań, integrację z AI, automatyczne sugestie nagłówków czy powiadomienia na Slacka. Najpierw trzeba sprawdzić, czy zespół faktycznie aktualizuje treści z listy. Bez tego nawet najlepszy algorytm zostanie tylko kolejnym raportem, którego nikt nie otwiera.
FAQ: najczęstsze pytania o Content Decay Tracking w WordPressie
Czy do takiego systemu wystarczy zwykła wtyczka SEO?
Nie. Wtyczka SEO może pomóc w edycji title, meta description albo indeksacji, ale zwykle nie buduje własnej historii spadków na poziomie bazy wpisów. Do monitoringu decay potrzebujesz cyklicznego importu danych z Google Search Console i reguł porównujących okresy.
Jak często sprawdzać spadki ruchu?
Raz w tygodniu. Codzienne alerty przy content decay są zbyt nerwowe, bo dane organiczne naturalnie falują. Tygodniowy import i analiza 28 dni do poprzednich 28 dni dają lepszy obraz trendu.
Jaki próg spadku ustawić na start?
Dobry punkt wyjścia to minimum 30 kliknięć w okresie bazowym i spadek kliknięć o co najmniej 25%. Dla dużych serwisów próg kliknięć warto podnieść do 100, żeby lista nie zapychała się mało istotnymi adresami.
Czy trzeba analizować frazy, czy wystarczy URL?
Na start wystarczy URL. Analiza fraz jest przydatna przy diagnozie, ale zwiększa liczbę danych i złożoność systemu. Najpierw wykryj, które strony spadają. Dopiero potem sprawdzaj, na jakich zapytaniach.
Czy wpis oznaczony jako decay zawsze trzeba aktualizować?
Nie. Najpierw trzeba sprawdzić przyczynę. Spadek może wynikać z sezonowości, zmiany intencji w wynikach Google, kanibalizacji albo słabszego CTR. Aktualizacja treści jest właściwa wtedy, gdy artykuł jest niepełny, nieaktualny albo przegrywa zakresem informacji z konkurencją.
Czy dane najlepiej trzymać w postmeta?
Nie. Serie danych z GSC zapisuj wyłącznie w osobnej tabeli, bo postmeta szybko robi się ciężkie przy większej liczbie wpisów i dat. W postmeta trzymaj tylko aktualny status, np. refresh, urgent albo resolved.
Od czego zacząć wdrożenie?
Od małej wersji: import URL-i z GSC, porównanie dwóch okresów po 28 dni, próg minimalnych kliknięć i tabela w kokpicie z listą wpisów do odświeżenia. Nie zaczynaj od AI ani rozbudowanych dashboardów. Najpierw usuń największy błąd: brak systematycznej listy artykułów, które tracą ruch.

