Iets op je WordPress-site is stukgegaan: een wit scherm, een fatal error, een afrekenknop die niks doet, een admin die niet meer laadt. Je hebt onlangs iets veranderd, waarschijnlijk een plugin geactiveerd of geüpdatet, en nu doet de site raar. Je vermoedt een plugin-conflict, maar je weet niet welke plugin en je hebt geen zin om alle plugins tegelijk uit te zetten en daarbij elke winkelwagen, login-sessie en concept-formulier in één keer kwijt te raken.
De diagnose is een volgorde, geen knop. Dit artikel loopt hem stap voor stap af.
Wat een plugin-conflict eigenlijk is
Een plugin-conflict ontstaat als twee stukken code die los van elkaar prima werken, samen niet meer werken in dezelfde WordPress-request. Het is zelden zo dat één van de plugins "stuk" is. Het normale verhaal: twee plugins haken op dezelfde WordPress-hook, gebruiken dezelfde global, claimen dezelfde JavaScript-handler of schrijven naar dezelfde database-rij. Op zichzelf werkt elke plugin gewoon. Samen botsen ze.
WordPress draait elke actieve plugin in hetzelfde PHP-proces en dezelfde global namespace. Plugins praten met elkaar via callbacks op gedeelde hooks (filters en actions). Als twee callbacks op dezelfde hook draaien, wordt de volgorde bepaald door een prioriteitsnummer dat je meegeeft aan add_filter en add_action. De default priority is 10. Lagere getallen draaien eerder. Bij gelijkspel wint de volgorde van registratie, die weer wordt bepaald door de alfabetische volgorde van plugin-mappen op schijf.
Dat laatste detail is precies waarom een conflict ineens opduikt nadat je een plugin-folder hernoemt, een plugin activeert of deactiveert, of zelfs een plugin update naar een versie die zijn callbacks net iets anders registreert.
Signalen dat je naar een plugin-conflict kijkt
Een paar symptomen wijzen betrouwbaar op plugin-code in plaats van core, theme of hosting:
- De site begon raar te doen direct nadat je een plugin activeerde, updatete of deactiveerde.
- Eén specifieke functie is stuk (afrekenen, contactformulier, opslaan in admin, media uploaden), terwijl de rest van de site nog gewoon werkt.
- De browser-console toont een JavaScript-error die verwijst naar een bestand onder
wp-content/plugins/. - De PHP error log heeft een fatal waarvan het bestandspad onder
wp-content/plugins/ligt. - Bezoekers en admins zien iets anders: de admin laadt wel, maar de voorkant is stuk, of andersom.
- Dezelfde pagina werkt als je naar het standaard theme schakelt en is stuk als je terug schakelt. (Dat wijst op een theme/plugin-conflict, maar het diagnose-pad is hetzelfde.)
Toont je site het kritieke-foutscherm, begin dan bij er heeft zich een kritieke fout voorgedaan op deze site. Dat artikel behandelt de recovery-mail waarmee WordPress je zelf vertelt welke plugin de fatal veroorzaakte. Bij een volledig leeg scherm zonder foutmelding begin je bij white screen of death in WordPress. Beide artikelen sturen je uiteindelijk weer naar dit artikel terug zodra de site stabiel genoeg is om het echte conflict te onderzoeken.
Veelvoorkomende oorzaken, op volgorde van waarschijnlijkheid
Na genoeg van dit soort tickets is de volgorde consistent.
- Hook-priority botsing. Twee plugins registreren callbacks op dezelfde hook (vaak
the_content,template_redirect,wp_enqueue_scripts,woocommerce_payment_complete). Beide verwachten de data in een specifieke vorm. De volgorde, meestal impliciet door de default priority10, bepaalt wie wint. Beide plugins zijn los van elkaar correct. - JavaScript-conflict in de browser. Twee plugins enqueueren verschillende versies van dezelfde library (jQuery UI, Select2, Swiper), of twee scripts hangen handlers aan hetzelfde DOM-element en de één blokkeert de ander. Symptoom: de pagina laadt, maar een knop of modal doet niks. De browser-console toont een
TypeError, eenUncaught ReferenceError, of eenis not a function. - PHP fatal door een ontbrekende dependency. Plugin A roept een functie aan die door plugin B wordt gedefinieerd (
get_field()van Advanced Custom Fields,WC()van WooCommerce,acf_register_block_type()). Wordt plugin B gedeactiveerd, geüpdatet naar een versie waarin de functie hernoemd is, of laadt B gewoon later, dan crasht plugin A opCall to undefined function. - Naamcollisie op PHP-niveau. Twee plugins definiëren een class, functie of constante met dezelfde naam. PHP gooit
Cannot redeclare class. Komt zelden voor bij actief onderhouden plugins (die prefixen meestal alles), maar gebeurt nog wel met oude of zelfgeschreven code. remove_actionmismatch. Plugin A probeert een callback van plugin B uit te haken, maar A en B zijn het oneens over de priority. Het uithaken faalt stilletjes (omdatremove_actionenremove_filteralleen iets uithaken op exact dezelfde priority), en de oorspronkelijke callback blijft draaien. Symptoom: een functie waarvan jij dacht dat hij uitstond, is nog steeds actief.- Asset-dequeue conflict. Plugin A roept
wp_dequeue_scriptaan op een handle waar plugin B van afhangt. De script-keten breekt en de frontend van plugin B doet niks meer.
De eerste drie zijn samen het overgrote deel van de plugin-conflict-tickets die ik zie. De rest is de long tail.
Stap 1: gebruik Health Check & Troubleshooting safe-mode (geen impact voor bezoekers)
Als wp-admin nog laadt, is de schoonste eerste zet de Health Check & Troubleshooting plugin van WordPress.org zelf. Hij heeft 300.000+ actieve installaties en bevat een feature genaamd Troubleshooting Mode die alle plugins uitzet en het thema vervangt door een default theme alleen voor jouw ingelogde gebruiker. Bezoekers zien gewoon de live site zoals hij is.
De laatste release op de WordPress.org repository is 1.7.1 van 2024-07-25. Dat is ouder dan ik normaal accepteer voor een tool waar ik op leun, maar de safe-mode-functionaliteit is niet veranderd en de plugin werkt nog gewoon op recente WordPress-versies. Voel je je niet prettig bij een plugin die in 18+ maanden geen release heeft gehad, dan geeft het handmatige folder-rename-pad in stap 2 hetzelfde diagnostische resultaat.
Hoe je hem gebruikt:
- Installeer Health Check & Troubleshooting via Plugins > Nieuwe plugin in
wp-admin. Activeer hem. - Open Gereedschap > Site Health > Troubleshooting.
- Klik op Enable Troubleshooting Mode. Je sessie krijgt nu een afgekleed WordPress te zien: alle plugins zijn voor jou gepauzeerd en het actieve theme is vervangen door een default theme. Volgens het WordPress.org support handbook is dit "only the case for your user, it does not affect any other site visitors, or users of your site."
- Reproduceer het kapotte gedrag. Is het weg, dan zit de oorzaak in je plugins of theme. Is het er nog steeds, dan zit de oorzaak ergens anders (core, hosting, server-config) en kun je hier stoppen en stroomopwaarts kijken.
- Gebruik het Troubleshooting Mode-menu in de admin bar om plugins één voor één weer aan te zetten. Reproduceer na elke plugin het kapotte gedrag. De eerste plugin waarbij het symptoom terugkomt, is de plugin die in het conflict betrokken is.
- Heb je de boosdoener gevonden, klik dan op Disable Troubleshooting Mode in de admin bar. Je normale sessie keert terug en alle plugins gaan terug naar hun echte activatie-status.
Je weet dat het werkt als het symptoom terugkomt op een specifieke plugin-reactivatie en weer verdwijnt zodra je troubleshooting mode uitzet. Belangrijk: de plugin die je vond is één helft van het conflict-paar, niet per se de stukke. Stap 4 gaat over hoe je bepaalt welke plugin de echte fix-target is.
Een nuance die uit de reviews van de plugin naar boven komt: troubleshooting mode is per cookie. Als die cookie verloren gaat of je wisselt midden in de sessie van browser, dan val je per ongeluk uit safe-mode. Blijf voor de hele diagnose in hetzelfde browservenster.
Stap 2: bisecteer met folder-rename als wp-admin niet bereikbaar is
Is wp-admin zelf stuk, dan is safe-mode geen optie en val je terug op een directere techniek: plugin-mappen op schijf hernoemen om ze in chunks te deactiveren, en met binary search de boosdoener vinden.
Dit is het pad dat de officiële WordPress recovery mode docs beschrijven onder "What to do if the recovery email notification doesn't arrive". Het werkt zolang je file-toegang hebt (SFTP, file manager in je hostingpaneel) en is verreweg de meest betrouwbare diagnostische techniek, omdat er niks binnen WordPress voor hoeft te werken.
De cruciale discipline: hernoem mappen, verwijder ze nooit. Hernoemen behoudt de plugin's database-options, transients, sessies, winkelwagens en concept-formulieren. Verwijderen kan de uninstall.php van de plugin afvuren (afhankelijk van host en hoe de verwijdering verloopt), die bij veel plugins hun data wist. De "veilige" bulk-deactivatie via wp-admin's bulk action gooit ook bij sommige plugins transients weg. Folder-rename is de enige optie zonder bijwerkingen.
De procedure:
- Verbind via SFTP, de file manager van je hostingpaneel of welke file-toegang je host je geeft.
- Open
wp-content/plugins/. - Pak de helft van je pluginlijst die het meest waarschijnlijk de boosdoener bevat (meest recent geïnstalleerd, of degene die je net updatete). Hernoem die mappen door
.offaan de naam te plakken, dusbad-pluginwordtbad-plugin.off. WordPress behandelt een hernoemde map als een gedeactiveerde plugin. De rij inwp_options.active_pluginsverwijst nog naar de oude naam, en daardoor kun je "reactiveren" door de map terug te hernoemen. - Herlaad de stukke pagina.
- Is het symptoom weg, dan zit het conflict ergens in de helft die je net uitzette. Zet die helft weer aan (haal
.offweg) en deactiveer een kleinere subset (een kwart, daarna een achtste) op dezelfde manier. Elke ronde halveert de verdachte pool. - Is het symptoom er nog steeds, dan zit het conflict in de helft die je niet hebt aangeraakt. Herstel de hernoemde helft (haal
.offweg) en deactiveer de andere helft. - Ga door tot je nog één plugin-map over hebt. Dat is de plugin die in het conflict zit.
Voor een site met 30 plugins kom je in ongeveer vijf rondes bij één verdachte uit. Voor 100 plugins is het zeven. Sneller dan één voor één reactiveren, en je verliest geen transient data.
WP-CLI-gebruikers met SSH-toegang hebben een snellere variant: wp plugin deactivate <plugin-slug> deactiveert zonder uninstall.php aan te raken. Dezelfde bisectie-logica is van toepassing. De volledige reference staat in WP-CLI plugin deactivate.
Een aparte tool die het kennen waard is: Plugin Detective (huidige versie 1.2.29, laatst bijgewerkt 2025-12-09). Het is een server-side PHP plugin die exact deze binary-search bisectie automatiseert vanuit wp-admin, met een geleide "ja, het is gefixt / nee, het is nog steeds stuk"-interface. Twee beperkingen om in je achterhoofd te houden: hij vindt alleen welke plugin betrokken is, niet waarom (hij detecteert geen hook-priority botsingen en leest geen debug log voor je), en hij ondersteunt expliciet geen multisite. Voor enkelvoudige WordPress-installs waar wp-admin nog laadt, is hij sneller dan handmatig folders hernoemen. Voor multisite of als wp-admin weg is, zit je weer op het SFTP-pad hierboven.
Stap 3: lees de debug log om de hook of functie aan te wijzen
Weten welke plugin betrokken is, is de helft van het antwoord. De andere helft is welke regel code, welke functie en welke hook. De debug log vertelt je alle drie.
Heb je WP_DEBUG_LOG nog niet aanstaan, volg dan de WordPress debug log inschakelen en lezen voor de vier constants op een veilige manier. De korte versie, in wp-config.php boven de "stop editing"-regel:
// Debug-modus aan
define( 'WP_DEBUG', true );
// Errors naar wp-content/debug.log schrijven
define( 'WP_DEBUG_LOG', true );
// Errors verbergen voor bezoekers
define( 'WP_DEBUG_DISPLAY', false );
// Voor de zekerheid: vertel PHP ook niet te tonen
@ini_set( 'display_errors', 0 );
Met debug aan reactiveer je alleen de verdachte plugin (hernoem bad-plugin.off terug naar bad-plugin), herlaad de pagina die het symptoom triggert één keer, en deactiveer de plugin daarna meteen weer. Open wp-content/debug.log. Het laatste blok aan entries beschrijft wat er gebeurde. Een typische fatal ziet er zo uit:
[24-Apr-2026 10:14:22 UTC] PHP Fatal error: Uncaught Error: Call to undefined
function get_field() in /var/www/html/wp-content/plugins/some-theme-addon/render.php
on line 87
Drie dingen om eruit te halen:
- De map onder
wp-content/plugins/is de plugin die crashte. In het voorbeeld:some-theme-addon. - De functienaam in de melding is het ontbrekende of botsende symbol.
get_field()komt uit Advanced Custom Fields, dus het conflict issome-theme-addondie ACF aanroept zonder dat ACF geladen is, of met een incompatibele ACF-versie. - Het bestand en de regel zijn waar je een ontwikkelaar naartoe stuurt als de plugin écht gerepareerd moet worden.
Is het symptoom een JavaScript-error in de browser-console in plaats van een PHP fatal, dan vangt de debug log dat niet. Open de Console-tab in de DevTools van de browser, reproduceer het symptoom en zoek de eerste rode error. De bestand-URL wijst naar de JS-handle van de boosdoener-plugin. Vandaaruit kan Query Monitor je laten zien welke scripts en styles enqueued zijn en in welke volgorde, wat het JS-equivalent is van de hook-priority debugging die PHP fatals zo zichtbaar maakt.
Voor hook-priority issues specifiek is alleen debug logging niet genoeg. Je moet zien welke callbacks op een hook zijn geregistreerd en in welke volgorde. Query Monitor heeft een Hooks-paneel dat dit voor de huidige request toont, inclusief priority en callback-functie voor elke hook die afgevuurd is. Dat paneel vertelt je of de fix is "verander de priority van plugin A's callback" of "verwijder plugin B's callback helemaal".
Zet WP_DEBUG weer op false zodra je je antwoord hebt. Een live site zou nooit langer met debug logging aan moeten draaien dan het incident zelf duurt.
Stap 4: permanente fixes per type oorzaak
Heb je eenmaal de plugin én de hook, functie of asset waar het botst, dan splitst de permanente fix in een paar takken.
Hook-priority botsing
Haken twee plugins beide op bijvoorbeeld the_content op default priority 10 en wint de verkeerde, dan is de fix om de priority van degene die je wil laten verliezen aan te passen, in een klein custom plugin of een mu-plugin. Voorbeeld:
// In een mu-plugin: laat plugin-a's callback ná plugin-b's draaien,
// in plaats van de default volgorde
remove_filter( 'the_content', 'plugin_a_callback', 10 );
add_filter( 'the_content', 'plugin_a_callback', 20 );
Je hebt de exacte functienaam nodig die plugin A heeft geregistreerd. Het Hooks-paneel van Query Monitor toont dat. De priority die je kiest (20 hier) hoeft alleen hoger te zijn dan die van plugin B, zodat plugin A's callback ná die van B draait en het laatste woord heeft over de output.
Let op de remove_filter priority-eis: de priority die je aan remove_filter meegeeft moet exact gelijk zijn aan de priority waarmee oorspronkelijk geregistreerd is. Heeft plugin A op priority 10 geregistreerd en roep jij remove_filter(... , 'plugin_a_callback', 20) aan, dan faalt het uithaken stilletjes. Dezelfde valkuil als de remove_action mismatch uit de oorzakenlijst.
JavaScript-conflict
Zit het conflict in de browser, dan is de fix meestal om één van de scripts te dequeueeren op de pagina's waar het botst. In een klein custom plugin of mu-plugin:
add_action( 'wp_enqueue_scripts', function () {
if ( is_singular( 'product' ) ) {
// De trage-maar-stukke slider is op productpagina's niet nodig
wp_dequeue_script( 'plugin-b-slider' );
}
}, 100 );
De 100 als priority is bewust laat, zodat dit draait nadat beide plugins hun scripts geënqueued hebben. De script-handle (plugin-b-slider hier) zie je in het Scripts-paneel van Query Monitor. Pas op: een script dequeueeren waar andere scripts van afhangen breekt die ook. Wat wp_dequeue_script echt uithaakt is de hele keten.
PHP fatal door ontbrekende dependency
De fix is een van deze:
- Reinstalleer de plugin die de ontbrekende functie definieert (meest voorkomend: Advanced Custom Fields of WooCommerce die per ongeluk gedeactiveerd zijn).
- Pin de dependency-plugin op een versie die de functie nog wel heeft die de addon verwacht (vaak het geval na een major update die een interne API hernoemde).
- Vervang de addon door een onderhouden alternatief als de afhankelijkheid permanent gebroken is.
De addon definitief uitzetten is ook een prima keuze, als de functie waar hij van afhangt niet meer terugkomt.
Naamcollisie op PHP-niveau
Vanuit een site-eigenaar-stoel bestaat hier geen schone fix. Een van de twee plugins moet zijn botsende symbol hernoemen, wat betekent: contact opnemen met de plugin-auteur of de plugin vervangen. Tot het zover is, deactiveer de minst belangrijke van de twee.
remove_action of remove_filter mismatch
Kijk in de broncode van de plugin die probeert uit te haken. Zoek de priority die hij gebruikt. Vergelijk met de priority van de oorspronkelijke add_action. Die moeten exact gelijk zijn. Was de oorspronkelijke op priority 5 toegevoegd en gebruikt het uithaken default 10, dan is de fix om het uithaken op priority 5 te zetten (in een custom plugin override, want de plugin-code zelf bewerken wordt bij de volgende update overschreven).
Asset-dequeue conflict
Hetzelfde als het JavaScript-conflict hierboven, maar de boosdoener is een andere plugin die wp_dequeue_script aanroept. De fix is óf het script opnieuw enqueueeren op een latere priority, óf de te-ijverige dequeue-plugin uitzetten. Die tweede optie is meestal eerlijker: een plugin die zomaar de assets van een andere plugin dequeuet zonder een opt-out, gaat over de schreef.
Wat plugin-conflict-diagnose níet is
Een paar claims duiken op in WordPress-troubleshooting-gidsen die meer kwaad dan goed doen.
- "Zet alle plugins tegelijk uit en activeer ze één voor één weer." Dit is het pad dat het officiële troubleshooting plugin and theme conflicts artikel op WordPress.org Learn aanraadt. Diagnostisch werkt het, maar op een live site met actieve bezoekers verwoest het transient data en kan het checkouts halverwege breken. De Health Check safe-mode in stap 1 en de folder-rename bisectie in stap 2 zijn de per-gebruiker- en per-folder-equivalenten die de sessie-state intact laten.
- "Als twee plugins botsen, is er één stuk." Bijna nooit waar. De meeste conflicten zijn het gevolg van twee stukken correcte code die verschillende aannames doen over hook-priority of welke plugin eerst draait. Een van de twee als "stuk" bestempelen zet je op het verkeerde been: je gaat dan een fix eisen van een plugin-auteur die (terecht) zegt dat zijn plugin op zichzelf prima werkt.
- "Plugin Detective vindt elk conflict." Plugin Detective vindt welke plugin betrokken is via binary-search bisectie. Hij detecteert geen hook-priority botsingen, geen JavaScript-errors en geen botsende functienamen. Voor die dingen heb je de debug log en Query Monitor nodig.
- "Schakel naar een ander theme om het conflict op te lossen." Schakelen naar een default theme is een nuttige diagnostische stap (het vertelt je of het actieve theme erbij betrokken is), maar het is zelden de fix. Verdwijnt het symptoom op het default theme, dan zit het conflict tussen een plugin en de plugin-handling van het theme, en de juiste fix zit in het theme, niet in een theme dat je eigenlijk niet wil.
- "Meer geheugen en het conflict is weg." Een hogere PHP memory limit verbergt sommige symptomen (specifiek de
Allowed memory size exhausted-variant), maar lost het conflict niet op. De volledige fix per oorzaak voor geheugen vind je in allowed memory size exhausted in WordPress. Bij een echte hook- of JS-botsing helpt meer geheugen niks.
Wanneer het escaleren tijd is
Loopt de diagnose vast, of zit je met een conflict tussen twee plugins die je niet kunt vervangen en niet kunt patchen, dan is het bundeltje voor een ontwikkelaar of je host:
- De exacte naam en versie van elke betrokken plugin. Voor Health Check-gebruikers: het log van bij welke plugin-reactivatie het symptoom terugkwam.
- De naam en versie van het actieve theme.
- De PHP-versie op de server (zichtbaar in je hostingpaneel).
- De WordPress-versie (uit
wp-includes/version.phpof een werkend dashboard). - De laatste 30 regels van
wp-content/debug.logna het symptoom één keer reproduceren. - Bij een JavaScript-conflict: de volledige tekst van de eerste rode error in de browser-console, inclusief de bestand-URL.
- De exacte reproductie-stappen. "Open de winkelwagen, voeg een product toe, klik afrekenen" wint het van "afrekenen is stuk".
- Of je het issue gereproduceerd hebt op een staging-kopie. Een conflict dat op productie wel optreedt en op staging niet, is een hint dat iets op staging (de URL, een feature flag, een ontbrekende third-party connectie) het code-pad anders maakt.
- Bij een hook-priority botsing: een screenshot van het Hooks-paneel van Query Monitor met beide callbacks en hun priorities.
Een specialist met dat bundeltje in de hand kan meestal binnen een uur het conflict-paar identificeren en de fix-override schrijven. Zonder dat is dezelfde investigation een groot deel van een middag.
Hoe je het volgende conflict voorkomt
Plugin-conflicten kun je in een open ecosysteem met tienduizenden plugins niet wegnemen, maar een paar gewoonten houden ze zeldzaam en behapbaar.
- Draai zo min mogelijk plugins die je daadwerkelijk gebruikt. Elke plugin is een hook-registratie, een asset-enqueue en een potentiële conflict-partner. Audit de lijst eens per kwartaal en haal alles eruit waar je niet actief op leunt.
- Test plugin-updates eerst op een staging-kopie. Het volledige opzetpad staat in een WordPress staging-omgeving inrichten. Staging vangt niet elk conflict (productiebelasting en third-party connecties tellen mee), maar wel de meeste.
- Update plugins één voor één. Tien plugins in één klik bulk-updaten scheelt je 30 seconden en kost je het vermogen om te weten welke plugin het conflict startte als er iets stuk gaat.
- Pin kritische dependencies op bekende-werkende versies. Hangt plugin A op een specifieke functie in plugin B, doe dan plugin B niet zomaar via auto-update. Het mechanisme om te bepalen welke plugins auto-updaten staat in WordPress automatic updates: control what updates and when.
- Houd
WP_DEBUG_LOGklaar om aan te zetten. De vier constants uit stap 3 zouden één search-and-replace verwijderd moeten zijn inwp-config.php. Als het volgende conflict toeslaat, wil je ze aanzetten, één reproductie vastleggen, en weer uitzetten. - Abonneer je op de changelogs van plugins die je eerder pijn hebben gedaan. De release notes lezen van een major update voordat je klikt, kost minder tijd dan herstellen na een slechte.
Doet zich een plugin-conflict voor, dan zit de echte kostenpost niet in het conflict zelf. Hij zit in de paniek van een stukke site zonder diagnose-pad. Loop dit artikel een keer door op een staging-kopie die je expres mag slopen. Het volgende echte conflict wordt een klusje van een kwartier in plaats van een paniekerige middag, en dat is precies waarom het de moeite waard is om dit pad eens te oefenen voor je het echt nodig hebt.