Ha egy WordPress-oldal lassú, a legtöbben először a tárhelyre gyanakszanak. Pedig gyakran a háttérben futó admin-ajax.php hívások okozzák a gondot: egy kosár-számláló, egy élő szűrő, egy chat-widget vagy egy látogatószámláló. Mindegyik a saját kérését küldi a szervernek, oldalbetöltésenként akár többször is. Ebben a cikkben lépésről lépésre megnézzük, hogyan találod meg a terhelés forrását, és mit kezdj vele utána.

Miért terheli meg a szervert az admin-ajax.php?
Röviden: mert minden egyes hívás betölti a teljes WordPresst (a magot, a témát és az összes aktív bővítményt), a válasz pedig alapesetben nem gyorsítótárazható. Tíz AJAX-hívás tehát nagyjából tíz külön PHP-feldolgozást jelent, nem tíz apró adatcsomagot.
Hivatalosan igazolt: a WordPress kódbázisában az admin-ajax.php betölti a wp-load.php fájlt, lefuttatja az admin_init horgot, és a nocache_headers() függvénnyel olyan fejléceket küld, amelyek tiltják a gyorsítótárazást. A bővítmények a wp_ajax_{action} (bejelentkezett felhasználó) és a wp_ajax_nopriv_{action} (látogató) horgokra kötik a saját feldolgozójukat. Ebből két gyakorlati következmény adódik:
- minden bővítmény, amely az
admin_inithorogra akaszt valamit (licencellenőrzést, frissítésfigyelést, értesítéseket), minden AJAX-kérésnél újra lefut, akkor is, ha semmi köze a híváshoz; - az oldalgyorsítótár a HTML-t PHP nélkül is kiszolgálhatja, a mellette induló AJAX-kéréseket viszont nem, így a gyorsítótár mellett is ugyanúgy dolgozik a PHP.
Melyik bővítménytípusok küldik a legtöbb AJAX-kérést?
Röviden: azok, amelyek az oldal betöltése után friss, személyre szabott vagy „élő” adatot mutatnak.
Kosár-számláló és mini kosár
A WooCommerce a kosár tartalmát a ?wc-ajax=get_refreshed_fragments végponton frissíti. Ez nem az admin-ajax.php, de ugyanúgy betölti a WordPresst. Hivatalosan igazolt: a WooCommerce 7.8-as verziójától ez a szkript alapból csak ott töltődik be, ahol mini kosár blokk vagy widget van. Egy régebbi téma vagy kiegészítő bővítmény azonban visszakapcsolhatja minden oldalra.
Élő szűrő és élő keresés
A termékszűrők és keresőmezők minden kattintásnál vagy billentyűleütésnél kérést küldhetnek. Késleltetés (debounce) nélkül egy nyolcbetűs keresőszó nyolc kérést jelenthet, mindegyik adatbázis-lekérdezéssel.
Chat-widget
Ha a chat a saját szervereden fut, nem külső szolgáltatónál, akkor jellemzően néhány másodpercenként lekérdezi, jött-e új üzenet. Ez akkor is fut, ha a látogató hozzá sem nyúl a chathez, egészen addig, amíg a fül nyitva van.
Látogatószámláló és statisztika-bővítmény
Ezek minden oldalmegtekintésnél írnak az adatbázisba. Az írás drágább az olvasásnál, és sok egyidejű látogatónál a zárolások miatt más lekérdezéseket is lassíthat.
Heartbeat API
Hivatalosan igazolt: a WordPress Heartbeat API az adminban rendszeres időközönként (a dokumentáció szerint 15 és 120 másodperc között) hívja az admin-ajax.php végpontot, szerkesztés közben sűrűbben. Az automatikus mentés és a szerkesztési zárolás is ezen fut. Egy szerkesztő, aki öt admin fület hagy nyitva, folyamatos háttérforgalmat generál.
Tényleg a tárhely a hibás, ha lassú a WordPress?
Röviden: sokszor nem. Saját tapasztalat: a „lassú a WordPress” panaszok nagy része mögött nem gyenge tárhely áll, hanem oldalanként 3-4 párhuzamos AJAX-hívás, amelyek egymástól függetlenül, egyszerre foglalnak PHP-folyamatot.
A számolás egyszerű. Ha egy oldal betöltése egy HTML-kérés plusz négy AJAX-kérés, akkor 20 egyidejű látogató nem 20, hanem 100 PHP-kérést jelent. Ha a HTML a gyorsítótárból jön, a PHP-terhelés nagy része már csak az AJAX-ból származik.
Szakmai feltételezés: osztott tárhelyen vagy kisebb VPS-en ilyenkor ritkán a processzor fogy el először. Sokkal inkább a PHP-FPM egyidejű folyamatkorlátja (pm.max_children) telik be, és a további kérések sorban állnak. Ezt látod „véletlenszerű” lassulásnak: az oldal hol gyors, hol több másodpercig tölt. Egy erősebb csomag elfedheti a gondot, de a hívások száma a forgalommal együtt tovább nő.
Milyen sorrendben keresd meg, melyik bővítmény terheli a szervert?
Röviden: a szervertől haladj a böngésző felé, és csak a végén kapcsolgass bővítményeket. Így az éles oldalt csak olvasod, kísérletezni pedig stagingen fogsz.
- Access log szűrése: mennyi kérés jön, mikor és melyik oldalról.
- Az
actionparaméter naplózása: melyik feldolgozó fut, és mennyi ideig. - DevTools Network nézet: melyik JavaScript-fájl indítja a kérést.
- Query Monitor: hány lekérdezést futtat, és melyik komponens.
- Egyenkénti kikapcsolás stagingen, mérés előtte és utána.
1. lépés: Szűrd az access logot
A webszerver hozzáférési naplója (Apache vagy Nginx access log) megmutatja, hány kérés érkezik a gyanús végpontokra. Általában a tárhelypanelen vagy SSH-n éred el. Hasznos parancsok:
grep -cE 'admin-ajax.php|wc-ajax=|/wp-json/' access.log: összesen hány AJAX- és REST-kérés jött;awk '/admin-ajax.php/ {print substr($4,2,17)}' access.log | sort | uniq -c | sort -rn | head: melyik percben volt a legtöbb;awk '/admin-ajax.php/ {print $11}' access.log | sort | uniq -c | sort -rn | head: melyik oldalról (referer) indulnak;awk '/admin-ajax.php/ {print $1}' access.log | sort | uniq -c | sort -rn | head: melyik IP-címekről érkeznek.
A mezők sorszáma a szokásos „combined” naplóformátumra érvényes, egyedi formátumnál eltérhet. Ha a kérések nagy része néhány IP-ről, referer nélkül érkezik, az inkább bot vagy támadás, nem bővítmény. A böngészőben futó AJAX-hívások jellemzően valós látogatókhoz és konkrét oldalakhoz köthetők. Ha például csak a termékoldalakról jön sok hívás, a gyanúsítottak köre máris szűkül.
2. lépés: Naplózd, melyik action fut
Az access log a POST-kérések törzsét nem rögzíti, így azt sem, melyik action futott. Ezt egy rövid, ideiglenes must-use bővítménnyel pótolhatod. A wp-content/mu-plugins/ mappába tett PHP-fájl automatikusan betöltődik:
<?php
if ( defined( 'DOING_AJAX' ) ) {
add_action( 'shutdown', function () {
$a = isset( $_REQUEST['action'] ) ? preg_replace( '/[^a-z0-9_-]/i', '', $_REQUEST['action'] ) : '-';
$ms = round( ( microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'] ) * 1000 );
error_log( date( 'c' ) . ' ' . $a . ' ' . $ms . 'ms' . PHP_EOL, 3, WP_CONTENT_DIR . '/ajax-naplo.log' );
} );
}
Egy-két óra forgalom után a naplóból kiderül, melyik action a leggyakoribb és melyik a leglassabb. A bővítmények többnyire saját előtagot adnak az action nevének, így ráismerhetsz a gazdára. Ha nem, a bővítménymappákban keress rá a wp_ajax_ kifejezésre. A naplófájl nyilvánosan elérhető mappában keletkezik, ezért a mérés végén töröld a fájlt és a bővítményt is. A wc-ajax kérésekre ez a kód nem fut le, azoknál viszont a végpont neve eleve látszik az access logban.
3. lépés: Nézd meg a DevTools Network nézetét
Nyisd meg a gyanús oldalt Chrome-ban, nyomd meg az F12-t, a Network fülön válaszd a Fetch/XHR szűrőt, és kapcsold be a Preserve log opciót. Töltsd újra az oldalt, és várj egy percet görgetés és kattintás nélkül.
- A Payload fülön látod az
actionértékét. - Az Initiator oszlop megmutatja, melyik JavaScript-fájl indította a kérést. Ha az útvonal
/wp-content/plugins/bovitmeny-neve/, megvan a gazda. - A Timing fülön a „Waiting for server response” érték a szerveroldali feldolgozás idejét mutatja.
- Ha egy perc tétlenség alatt is ismétlődő kérések jelennek meg, az időzített lekérdezés (polling).
Saját tapasztalat: ez a lépés gyakran néhány perc alatt megadja a választ, mert a kérés és a bővítmény kapcsolata közvetlenül látszik. Nézd meg bejelentkezve és inkognitó ablakban is, mert sok bővítmény mást tölt be az adminnak, mint a látogatónak.
4. lépés: Telepítsd a Query Monitort
A Query Monitor ingyenes fejlesztői bővítmény, amely komponensenként (mag, téma, bővítmény) csoportosítva mutatja az adatbázis-lekérdezéseket, a PHP-hibákat és a futásidőt. Hivatalosan igazolt: a dokumentációja szerint a jQuery-vel indított AJAX-kérések hibakeresési adatait a válasz fejlécébe írja. REST-kéréseknél hitelesített kérés esetén szintén fejlécben adja vissza, az _envelope paraméterrel pedig a válasz törzsében. A Queries by Component panelen gyorsan kiderül, melyik bővítmény futtat aránytalanul sok lekérdezést. Az éles oldalon csak rövid ideig tartsd bekapcsolva, mert maga is terhel.
5. lépés: Kapcsold ki a bővítményeket egyenként stagingen
A gyanúsítottakat staging (teszt) környezetben ellenőrizd, ne az élő oldalon. A menet:
- Készíts friss másolatot az élő oldalról a tárhely staging funkciójával vagy mentésből.
- Mérj alapértéket: számold meg a DevTools-ban az XHR-kéréseket egy oldalbetöltésnél, és jegyezd fel a válaszidőket. Egy hívást parancssorból is mérhetsz:
curl -s -o /dev/null -w '%{time_starttransfer}' -d 'action=AKCIO_NEVE' https://staging.example.hu/wp-admin/admin-ajax.php - Kapcsolj ki egyszerre egy bővítményt (WP-CLI-vel:
wp plugin deactivate bovitmeny-neve), és mérj újra ugyanazon az oldalon. - Ha a kérésszám vagy a válaszidő érdemben csökken, jegyezd fel, kapcsold vissza a bővítményt, és jöhet a következő.
- A végén nézd meg, mit törne el a kikapcsolás (kosár, szűrő, űrlap), mert ettől függ a döntés.
Ha nincs staging, a Health Check & Troubleshooting bővítmény hibaelhárító módja csak a saját munkamenetedben kapcsolja ki a bővítményeket, a látogatók a teljes oldalt látják. Ez vészmegoldás: funkcionális hibák keresésére jó, terhelésmérésre kevésbé, mert a látogatói forgalom közben változatlanul fut.
Mit lehet gyorsítótárazni az AJAX-válaszok közül?
Röviden: mindent, ami nem függ a látogatótól, és nem változik másodpercenként. A személyes adatnál (kosár, bejelentkezett állapot) nem a teljes választ, hanem a mögötte lévő drága számítást érdemes gyorsítótárazni.
- Jól gyorsítótárazható: szűrőtalálatok azonos paraméterekre, összesített látogatószám, legutóbbi bejegyzések listája, készletinformáció, ha nem kell percre pontosnak lennie.
- Részben gyorsítótárazható: kosár-számláló (a termékadatok igen, a kosár tartalma nem), ajánlott termékek (a lista igen, a személyes szűrés nem).
- Nem gyorsítótárazható: chatüzenetek, űrlapküldés, fizetés, és minden, ami az adatbázisba ír.
Rövid lejáratú tárolásra a WordPress Transients API való, a gyakran ismétlődő lekérdezésekhez perzisztens objektum-gyorsítótár (Redis vagy Memcached). Az élő szűrőnél a legolcsóbb javítás a késleltetés: a kérés csak akkor induljon, ha a látogató pár száz ezredmásodpercig nem gépel tovább. Szakmai feltételezés: egy látogatószámlálónál már az is sokat segíthet, ha az írás nem minden megtekintésnél, hanem összegyűjtve, időzítve történik, vagy ha a funkciót egy meglévő analitikai eszköz váltja ki.
Mikor érdemes a hívást REST API-ra költöztetni?
Röviden: amikor a hívás nyilvános, csak olvas, és GET-kéréssel kiszolgálható. Egy ilyen REST-válasz HTTP-szinten gyorsítótárazható, az admin-ajax.php POST-kérése nem.
Hivatalosan igazolt: a REST API kérései nem futtatják az admin_init horgot, a végpontokhoz pedig saját jogosultság-ellenőrzést (permission_callback) kell megadni. A GET-válaszra beállított Cache-Control fejléc alapján a CDN vagy a szerveroldali gyorsítótár PHP nélkül is kiszolgálhatja a kérést, ha a beállítása ezt engedi. Bejelentkezett felhasználónál a WordPress alapból tiltó fejléceket küld, így ez főleg a látogatói forgalomnál segít.
Akkor éri meg a költöztetés, ha:
- a hívás minden látogatónak ugyanazt adja vissza (szűrő, számláló, lista);
- a kérés sok oldalon, nagy forgalommal fut;
- a kód saját fejlesztés, vagy a bővítmény fejlesztője támogatja az átállást.
Harmadik féltől származó bővítmény kódját ne írd át, mert a következő frissítés felülírja. És ne feledkezz meg róla: a REST API önmagában nem gyorsabb, a WordPresst ugyanúgy betölti. A nyereség a gyorsítótárazhatóságból és a kimaradó admin-inicializálásból jön.
Mikor kell a bővítményt lecserélni?
Röviden: ha a terhelés a bővítmény működésének része, és beállításból nem kapcsolható ki. Ilyenkor a finomhangolás csak tüneti kezelés.
Érdemes cserét keresni, ha az alábbiak közül legalább egy igaz:
- rövid időközönként kérdez le, és az időköz nem állítható;
- minden oldalon betölti a szkriptjét, azokon is, ahol a funkció meg sem jelenik;
- látogatói hívásban minden megtekintésnél ír az adatbázisba;
- a Query Monitor szerint egy hívása aránytalanul sok lekérdezést futtat, és a fejlesztő nem reagál a jelzésre;
- hosszú ideje nem kapott frissítést.
A chat-widget a legtisztább eset: egy külső szolgáltató chatje a saját szerverét terheli, nem a tiédet, és jó eséllyel beállítható, hogy csak kattintásra töltődjön be. Saját tapasztalat: sokszor csere helyett elég a bővítményt csak azokon az oldalakon betölteni, ahol valóban kell, például a termékszűrőt csak a kategóriaoldalakon.
A Heartbeat nem cserélhető, de szabályozható: a heartbeat_settings szűrővel ritkítható az időköz, a látogatói oldalon pedig kikapcsolható, ha semmi nem használja. A szerkesztőképernyőn ne tiltsd le teljesen, mert az automatikus mentés is rajta múlik.
Mit ellenőrizz, mielőtt tárhelyet váltasz?
Röviden: azt, hogy a terhelés a kérések számából vagy a szerver kapacitásából fakad. Az alábbi lista segít eldönteni.
- Hány AJAX- és REST-kérés indul egy oldalbetöltéskor kijelentkezett látogatóként?
- Van-e ismétlődő kérés egy perc tétlenség alatt?
- Melyik action a leggyakoribb és melyik a leglassabb a naplóban?
- Melyik bővítmény fájlja szerepel Initiatorként a DevTools-ban?
- Ír-e az adatbázisba bármilyen látogatói hívás?
- Generálnak-e Heartbeat-forgalmat a nyitva hagyott admin fülek?
- Betelik-e a PHP-FPM folyamatkorlát csúcsidőben? Ezt a tárhely-szolgáltató meg tudja mondani.
- Mennyit csökkent a kérésszám és a válaszidő a kikapcsolási teszt után?
Ha mindenre megvan a válasz, és a terhelés még mindig magas, akkor jó eséllyel valóban kevés a szerver erőforrása. Ez sem biztos: a lassú adatbázis-lekérdezések és a botforgalom hasonló tüneteket okozhat, ezeket érdemes külön megvizsgálni.
Források és további olvasnivalók
- WordPress Developer Resources: Plugin Handbook, AJAX
- WordPress Developer Resources: Heartbeat API
- WordPress REST API Handbook
- WordPress kódbázis: wp-admin/admin-ajax.php
- Query Monitor dokumentáció
- WooCommerce Developer Blog: a cart fragments működésének változása a 7.8-as verzióban
- Chrome DevTools dokumentáció: Network panel
- WP-CLI Handbook
- PHP kézikönyv: FastCGI Process Manager (FPM) konfiguráció
- MDN Web Docs: HTTP caching
- Minden admin-ajax.php hívás betölti a teljes WordPresst, lefuttatja az admin_init horgot, és a válasza alapesetben nem gyorsítótárazható.
- Az access log megmutatja a hívások mennyiségét és forrásoldalát, a POST-kérésekben küldött action értékét viszont csak külön naplózással vagy a DevTools-ban látod.
- A DevTools Initiator oszlopa gyakran közvetlenül megmutatja, melyik bővítmény JavaScript-fájlja indítja a kérést.
- A nyilvános, csak olvasó hívásokat érdemes GET-alapú REST-végpontra költöztetni, mert azok válasza HTTP-szinten gyorsítótárazható.
- Cseréld le a bővítményt, ha a rövid időközű lekérdezés vagy a látogatói adatbázis-írás a működése része, és beállításból nem kapcsolható ki.
Gyakori kérdések
Honnan tudom, hogy az admin-ajax.php okozza a lassulást?
Szűrd az access logot az admin-ajax.php, wc-ajax és wp-json kérésekre, és nézd meg a DevTools Network fülén az XHR szűrővel, hány kérés indul egy oldalbetöltéskor. Ha egy perc tétlenség alatt is ismétlődnek a kérések, vagy csúcsidőben ezekből jön a PHP-kérések nagy része, jó eséllyel itt van a gond.
Miért nem segít ezen a gyorsítótár-bővítmény?
Az oldalgyorsítótár a HTML-t szolgálja ki PHP nélkül, de az admin-ajax.php alapból gyorsítótárazást tiltó fejléceket küld, a POST-kérések pedig egyébként sem kerülnek a page cache-be. Az AJAX-hívások így a gyorsítótár mellett is betöltik a teljes WordPresst.
Kikapcsolhatom teljesen a Heartbeat API-t?
A látogatói oldalon igen, ha semmi nem használja. Az adminban inkább csak ritkítsd a heartbeat_settings szűrővel, mert az automatikus mentés és a szerkesztési zárolás is rá épül.
Gyorsabb a REST API, mint az admin-ajax.php?
Önmagában nem sokkal, mert a REST-kérés is betölti a WordPresst. Az előnye, hogy nem futtatja az admin_init horgot, és a nyilvános GET-válaszai HTTP-szinten gyorsítótárazhatók, így egy CDN vagy szerveroldali gyorsítótár PHP nélkül is kiszolgálhatja őket.
Kikapcsolhatom a bővítményeket az élő oldalon a teszteléshez?
Nem ajánlott, mert a látogatóknál eltörhet a kosár vagy az űrlap. Használj staging környezetet, vagy végszükség esetén a Health Check & Troubleshooting bővítmény hibaelhárító módját, amely csak a saját munkamenetedben kapcsolja ki a bővítményeket.
Források és további olvasnivalók
Ezen az oldalon a hivatalosan igazolt információt elsődleges forrásokból építjük fel; a saját tapasztalatot és a szakmai becslést mindig külön jelöljük a szövegben.