Een mailtje van je hoster dat zegt "je site trekt veel CPU via admin-ajax.php" wijst vaak richting de Heartbeat API. Soms klopt dat. Vaak ook niet. Heartbeat is een echt mechanisme dat echt load genereert, maar het duurste admin-ajax.php-verkeer op een doorsnee WooCommerce-shop is helemaal geen Heartbeat. Dit artikel behandelt beide kanten: wat Heartbeat daadwerkelijk doet, wanneer het problemen geeft, hoe je het onderscheidt van wat mensen ermee verwarren, en hoe je het throttlet zonder de editor kapot te maken.
Wat de Heartbeat API doet
De Heartbeat API is een polling-systeem van browser naar server dat WordPress opent vanuit elke ingelogde admin-tab. Het werd geïntroduceerd in WordPress 3.6 om vier specifieke features mogelijk te maken:
- Autosave. De block editor stuurt het huidige concept met een vast interval terug naar de server, zodat een browsercrash of netwerkstoring geen ongeshavelde tekst kost.
- Post locking. Zodra je een post openslaat om te bewerken, blijft Heartbeat de server eraan herinneren dat jij de lock nog vasthoudt. Opent een tweede redacteur diezelfde post, dan krijgt die een duidelijke "gebruiker X bewerkt deze post" waarschuwing in plaats van dat ze stilletjes over elkaars werk heen schrijven.
- Dashboard-sync. Schermen zoals het activity widget, de plugin-update teller in de toolbar en het "at a glance"-paneel verversen hun getallen via Heartbeat-ticks in plaats van via een volledige page reload.
- Plugin-notificaties. Plugins kunnen inhaken op het PHP-filter
heartbeat_receivedom notificaties vanuit de server naar de admin te pushen ("er kwam net een nieuwe bestelling binnen", "je security-scan is klaar").
Elke tick is een echt POST /wp-admin/admin-ajax.php-verzoek met action=heartbeat in de body. PHP-FPM boot WordPress, de actieve plugins laden, eventuele heartbeat_received-handlers draaien en het antwoord komt terug als JSON. Het is qua vorm hetzelfde verzoek als elke andere admin-ajax.php-action, en dat is precies waarom het in hosting-dashboards op één hoop belandt met de rest van het admin-ajax.php-verkeer.
Wanneer en waar Heartbeat draait
Waar Heartbeat geladen wordt is belangrijker dan de meesten denken, want het bepaalt of throttlen überhaupt zin heeft.
In de post-editor. Default interval: 15 seconden. Dit is de snelste tick omdat autosave en post locking responsief moeten voelen. De Heartbeat API plugin handbook documenteert het toegestane bereik van 15 tot 120 seconden, en 15 seconden is de default voor de editor.
Op andere wp-admin schermen. Default interval: 60 seconden. Het dashboard, het plugins-scherm, het users-scherm, het WooCommerce orders-scherm: allemaal tikken ze één keer per minuut, zolang het tabblad openstaat en focus heeft.
Op de publieke voorkant. Wordt by default helemaal niet geladen. WordPress core enqueued het heartbeat-script niet voor uitgelogde bezoekers. Voor ingelogde gebruikers op de voorkant (iemand die de site bekijkt terwijl hij in een ander tabblad in de admin zit) kunnen plugins of themes het alsnog enqueuen, maar core doet dat niet. De vaak rondgezongen claim dat "Heartbeat op de voorkant elke 120 seconden draait" klopt niet: 120 seconden is de bovenkant van het toegestane bereik, geen front-end default.
Zodra de browser-tab de focus verliest. Heartbeat vertraagt zichzelf automatisch. De JavaScript-methode wp.heartbeat.interval() schakelt naar een "slow" modus die de polling ongeveer elke twee minuten doet zodra het tabblad geminimaliseerd is of geen focus heeft. Een editor-tab die op de achtergrond openstaat, genereert dus ruwweg de helft van het verkeer van dezelfde tab in beeld.
Hoe Heartbeat zich manifesteert als admin-ajax.php-load
Waarom Heartbeat in hosting-dashboards opduikt is puur mechanisch, niet mysterieus. Elke tick is een niet-cachebaar POST-verzoek aan een admin-endpoint dat WordPress van kop tot staart draait:
- De browser vuurt
POST /wp-admin/admin-ajax.phpaf metaction=heartbeatin de body. - nginx of Apache geeft het verzoek door aan PHP-FPM.
- Een PHP-worker boot WordPress: autoload opties, actieve plugins,
wp-includes. - WordPress valideert de nonce, draait de
heartbeat_received-filter en verzamelt data die plugins terug willen sturen. - Het antwoord gaat terug als JSON. De worker is weer vrij.
- De browser plant de volgende tick in.
Dat is één volledig WordPress-verzoek per tick, per openstaande admin-tab, per ingelogde gebruiker. Op een one-man site met één editor-tab open is dat ongeveer 4 requests per minuut in de editor of 1 request per minuut op het dashboard, en de CPU-kosten zijn verwaarloosbaar. Op een site met vijf gelijktijdige redacteuren die elk een tab open hebben, komt het neer op ongeveer 1.200 editor-ticks per uur als iedereen aan het schrijven is, plus een achtergrondstroom dashboard-ticks. Zoals het artikel over hoog CPU-gebruik uitlegt komt de CPU-druk op een WordPress-server uit niet-gecachete PHP-verzoeken, en elke Heartbeat-tick is er zo eentje.
Cachen helpt niet. Heartbeat-verzoeken zijn POST-requests naar admin-ajax.php, en die sluit elke grote page cache (WP Rocket, LiteSpeed Cache, W3 Total Cache, Varnish, nginx fastcgi_cache) standaard uit. Er valt ook niets te cachen, want elke tick geeft user-specifieke JSON terug. De juiste oplossing is altijd minder vaak tikken, niet agressiever cachen.
Heartbeat vs. WooCommerce cart fragments: uit elkaar houden
Dit is de belangrijkste diagnose die je kunt stellen, want hij bepaalt of throttlen überhaupt iets oplevert. Op een doorsnee WooCommerce-shop met admin-ajax.php-pieken is het verkeer bijna nooit Heartbeat. Het is de WooCommerce cart fragments-feature, en de twee mechanismen staan volledig los van elkaar.
Heartbeat. Vuurt alleen vanuit ingelogde admin-tabs (post-editor, dashboard, plugin-schermen). De body van het verzoek bevat action=heartbeat. Elke tick raakt WordPress aan en levert admin-scoped JSON terug.
WooCommerce cart fragments. Vuurt vanuit de voorkant bij elke page load voor elke bezoeker met een sessie-cookie, inclusief uitgelogde shoppers met een lege winkelmand. De URL van het verzoek bevat wc-ajax=get_refreshed_fragments. Het bestaat om het mini-cart widget in de header bij te werken na een cache hit, omdat de gecachete HTML niet weet wat er in de winkelmand van de bezoeker zit. Op een drukke shop met frontpage-caching kan dit makkelijk 20.000+ requests per uur genereren, zonder één enkele Heartbeat.
Hoe je ze uit elkaar haalt. Open de server access log (of de log-weergave in je hosting-paneel) en kijk naar de admin-ajax.php-regels. Het onderscheid zit in de URL querystring of de POST body:
POST /wp-admin/admin-ajax.phpmet bodyaction=heartbeatis Heartbeat. Throttlen viaheartbeat_settingshelpt hier wel.GET /?wc-ajax=get_refreshed_fragmentsofPOST /?wc-ajax=get_refreshed_fragmentsis WooCommerce cart fragments. Heartbeat throttlen doet hier niks; de fix is cart fragments uitschakelen via het WooCommerce-filter of een cache-bypass regel.POST /wp-admin/admin-ajax.phpmet een andereaction=is weer een andere plugin (live search, productfilters, popup builders, analytics beacons). Elk vraagt om zijn eigen diagnose.
Throttle je Heartbeat op een site waar cart fragments het echte probleem zijn, dan beweegt de CPU-grafiek geen millimeter. Sneller kun je geen middag verspillen.
Eerst meten, dan draaien
Ga niet blind aan Heartbeat zitten tweaken. De logs of een profiler vertellen je precies hoeveel van het admin-ajax.php-verkeer daadwerkelijk Heartbeat is, en of dat volume throttlen rechtvaardigt.
Server access logs. Elke webserver schrijft een regel per request. Filter op admin-ajax.php en tel de regels waarvan body of URL action=heartbeat bevat. Blijft de ratio onder een paar procent van het totale admin-ajax.php-verkeer, dan is Heartbeat je probleem niet. Zit hij op 60% of meer, dan gaat throttlen zichtbaar helpen.
Query Monitor plugin. De gratis Query Monitor plugin voegt een paneel toe aan de admin toolbar met elke AJAX-action die in het huidige request is gevuurd, elke hook die draaide en hoeveel tijd elke query kostte. Op een pagina waar Heartbeat vuurt, laat het paneel het heartbeat_received-pad expliciet zien. Het is de snelste manier om te zien welke plugins handlers aan Heartbeat hebben gehangen en wat die per tick kosten.
Kinsta's diagnose-gids. Het admin-ajax diagnose-artikel van Kinsta loopt dezelfde log-methode uitgebreider door met echte GTmetrix-waterfall voorbeelden. Handig als je access logs nog onbekend terrein zijn.
Heartbeat beheersen met code
Het primaire pad voor Heartbeat-beheer is het filter heartbeat_settings. Dit is core WordPress, geen plugin nodig, en het is de aanpak die ik aanraad omdat hij zonder nadenken plugin-verwaarlozing en WordPress-upgrades overleeft.
Zet een van de snippets hieronder in een site-specifieke plugin of in functions.php van een child theme. Nooit in een parent theme of een plugin waar je niet de auteur van bent.
Overal throttlen naar 60 seconden (inclusief de editor). Autosave en post locking blijven werken, maar met een lager tempo. De meeste sites komen hier prima weg mee zonder klachten.
// Zet het Heartbeat-interval op 60 seconden voor alle admin-contexts.
add_filter( 'heartbeat_settings', function( $settings ) {
$settings['interval'] = 60;
return $settings;
} );
Alleen op de voorkant uitzetten. Veilig, want core laadt hem daar voor uitgelogde bezoekers toch al niet. Dit raakt alleen plugins of themes die hem enqueuen voor ingelogde gebruikers die de site bekijken.
// Deregistreer het heartbeat-script alleen op front-end page loads.
add_action( 'init', function() {
if ( ! is_admin() ) {
wp_deregister_script( 'heartbeat' );
}
} );
Heartbeat overal uitzetten. Dit is de "plat alles"-optie en heeft echte consequenties (zie de volgende sectie). Alleen gebruiken als je hebt vastgesteld dat Heartbeat de dominante bron is en het redactieteam kan leven zonder autosave en post locking.
// Deregistreer het heartbeat-script globaal. Sloopt autosave en post locking.
add_action( 'init', function() {
wp_deregister_script( 'heartbeat' );
}, 1 );
Context-afhankelijk throttlen. De Heartbeat-defaults verschillen tussen editor (15s) en dashboard (60s) omdat autosave het snellere tempo nodig heeft. Wil je de editor responsief houden maar de rest vertragen, gebruik dan get_current_screen() binnen het filter:
// Editor op 15s voor snelle autosave, overige admin-schermen naar 120s.
add_filter( 'heartbeat_settings', function( $settings ) {
if ( function_exists( 'get_current_screen' ) ) {
$screen = get_current_screen();
if ( $screen && in_array( $screen->base, array( 'post', 'post-new' ), true ) ) {
return $settings; // Editor laat op de default 15 seconden.
}
}
$settings['interval'] = 120;
return $settings;
} );
De interval-parameter is in WordPress 6.7 en eerder geknipt op het bereik 15-120 seconden. Trac ticket #61960 stelt voor dit bereik op te rekken, maar op het moment van schrijven geldt de 15-120 grens nog. Waarden buiten het bereik worden stilletjes genegeerd.
Heartbeat beheersen met de Heartbeat Control plugin
Er is een dedicated plugin voor: Heartbeat Control van WP Media, hetzelfde bedrijf achter WP Rocket. Het heeft een UI met sliders voor het dashboard, de voorkant en de post-editor, en laat je elk context los aan- en uitzetten of throttlen. Meer dan 80.000 sites gebruiken hem.
Er zit wel een kanttekening aan. De laatste release (versie 2.0.1) is van augustus 2023 en getest tot en met WordPress 6.3. In WordPress 6.7 staat in de WordPress.org-listing de waarschuwing "deze plugin is niet getest met de afgelopen drie major releases". Hij werkt nog op de meeste sites omdat het heartbeat_settings-filter dat hij wrapt niet veranderd is, maar behandel hem toch als een plugin aan het infuus in plaats van als een actief onderhouden afhankelijkheid.
Gebruik de plugin als je specifiek de UI nodig hebt (niet-technische beheerders die zelf willen prutsen, of bureaus die dezelfde configuratie uitrollen over veel klantsites). Voor alles daarbuiten: gebruik de code-snippets hierboven. De code-aanpak is één bestand dat jij beheert, zonder plugin-update risico en zonder admin UI om te onderhouden.
Wat er sneuvelt als je Heartbeat uitzet
Elke gids die zegt "zet Heartbeat uit om server-load te drukken", slaat deze sectie over. Het maakt uit, want de verkeerde instelling sloopt stilletjes features waar redacteuren op leunen.
- Autosave stopt. Een browsercrash, een wegvallende verbinding of een per ongeluk gesloten tab tijdens het schrijven kost je alles sinds de laatste handmatige save. Op een langere post kan dat een half uur tikken kwijt zijn.
- Post locking stopt. Twee redacteuren kunnen dezelfde post openen en elk over de ander heen opslaan. De laatste save wint, de wijzigingen van de eerste verdwijnen zonder waarschuwing, want het locking-mechanisme is weg.
- Plugin-notificaties stoppen. WooCommerce "nieuwe bestelling"-meldingen, security-scan meldingen, realtime back-up status en vergelijkbare plugin-features die updates naar de admin pushen, leunen op Heartbeat. Ze falen zonder foutmelding.
- Page builders kunnen misgaan. Elementor, Divi en nog een paar visuele builders gebruiken Heartbeat voor realtime editor-state (revisiehistorie, collaborator-indicators, autosave binnen de builder). Globaal Heartbeat uitzetten kan editor-fouten opleveren die op bugs in de builder lijken. Perfmatters documenteert dit expliciet: Heartbeat overal uitzetten breekt soms de functionaliteit van page builders.
- De block editor verliest zijn post-lock indicator. Gutenberg gebruikt Heartbeat voor post locking op precies dezelfde manier als de classic editor. Heartbeat uitzetten sloopt het in beide.
Veilige default. Throttle naar 60 seconden in de editor en laat het dashboard op zijn default. Dat snijdt het editor-verkeer met driekwart en houdt autosave en post locking overeind. Schakel pas over naar volledig uitzetten als je gemeten hebt dat Heartbeat het admin-ajax.php-verkeer domineert én het team akkoord is met het verlies van autosave.
Context-afhankelijke instellingen: dashboard vs. post-editor
De splitsing tussen editor-ticks van 15 seconden en dashboard-ticks van 60 seconden bestaat niet zomaar. Autosave is belangrijker op het scherm waar de gebruiker actief zit te typen. Dat is de editor. Het dashboard is een rustige bak die tellers ververst, en er staat niks op wat pijnlijk zou zijn om te verliezen.
Is jouw probleem dashboard-tabs die openstaan bij redacteuren die er niet meer naar kijken, dan is de juiste fix het dashboard verder throttlen (bijvoorbeeld naar 120 seconden) en de editor met rust laten. Offer editor-autosave niet op voor dashboard-achtergrondverkeer: in de editor voel je de pijn van verloren werk, en daar zijn tragere ticks het duurst.
Is jouw probleem een klein clubje power users dat editor-tabs de hele dag open heeft, dan is de juiste fix de editor throttlen naar 30 of 60 seconden. Achtergrondtabs met Heartbeat-slow-mode genereren toch al ongeveer de helft van het verkeer, en het team kan een iets minder snelle autosave-ervaring wel hebben.
Is jouw probleem veel gelijktijdige redacteuren die allemaal tegelijk actief schrijven, dan is het artikel over PHP workers een betere referentie. Je loopt dan tegen de grenzen van de worker pool aan, niet tegen Heartbeat-limieten. Heartbeat throttlen helpt marginaal, workers bijzetten of een groter pakket nemen helpt meer.
Wanneer je Heartbeat met rust moet laten
Heartbeat is niet zomaar een kapot onderdeel van WordPress. Voor de meeste sites kost het een fractie van een procent van de servercapaciteit en levert het features (autosave, post locking, realtime notificaties) die veel meer waard zijn dan wat het verbruikt. Er zijn gevallen waarin het juiste antwoord is: niks doen.
- One-person sites. Eén beheerder met één of twee editor-tabs open, genereert verwaarloosbaar Heartbeat-verkeer. De hele feature is onzichtbaar in de CPU-grafiek.
- Sites waar het echte probleem iets anders is. Laat je access log
wc-ajax=get_refreshed_fragmentszien als de dominante boosdoener, of zitten er in hetadmin-ajax.php-verkeeraction=waarden die niks met heartbeat te maken hebben, dan verandert Heartbeat throttlen helemaal niks. Los de echte bron op. - Sites met weinig gelijktijdige editors. Twee of drie redacteuren met elk één tab zijn geen Heartbeat-probleem. Dat is een normale WordPress-workload, en het budget van 4 requests per minuut per editor is precies wat WordPress verwacht.
- Sites waar de hoster over een andere metric klaagt. Een mailtje over "hoog CPU" op een site met 150 KB autoload-rommel en een nachtelijke back-up scanner, is geen Heartbeat-verhaal. Het artikel over hoog CPU-gebruik loopt door welk mechanisme daadwerkelijk het budget opslokt.
De grootste verspilde inspanning in WordPress-performance werk is Heartbeat throttlen terwijl het echte probleem ergens anders zit. Eerst meten, dan één ding tegelijk veranderen, dan opnieuw meten. Dat is de enige volgorde die de grafiek betrouwbaar de goede kant op duwt.
Waar je verder kunt kijken
Meldde je hoster admin-ajax.php-pieken en heb je Heartbeat uitgesloten, dan dekt het artikel over hoog CPU-gebruik de volledige lijst mechanismen die CPU verbruiken op een WordPress-server. Voelt de admin zelf traag, dan legt het artikel over een trage WordPress-admin uit waarom elk admin-verzoek zwaarder is dan een front-end verzoek, met Heartbeat als één van vijf structurele oorzaken. Heb je veel redacteuren tegelijk aan het schrijven, dan dekt het artikel over uitgeputte PHP workers het worker pool-model waar het Heartbeat-verkeer mee concurreert.