WordPress plugin conflict: how to find which plugin broke your site

Your site is broken, you suspect a plugin, and you do not know which one. This article walks the structured diagnosis: safe-mode for one user, folder-rename bisection when wp-admin is gone, and the debug log read that names the offender.

Something on your WordPress site stopped working: a white screen, a fatal error, a checkout button that does nothing, an admin area that refuses to load. You changed something recently, probably activated or updated a plugin, and now the site is misbehaving. You suspect a plugin conflict but you do not know which plugin and you do not want to nuke every plugin at once and lose your shopping carts, login sessions, and form drafts in the process.

The diagnosis is a sequence, not a single button. This article walks it in order.

What a plugin conflict actually is

A plugin conflict is what happens when two pieces of code that each work on their own stop working when they run in the same WordPress request. It is rarely a case of one plugin being "broken". The usual story is two plugins that both touch the same WordPress hook, the same global variable, the same JavaScript handler, or the same database row. Each is correct in isolation. Together, they collide.

WordPress runs every active plugin's PHP in the same process and the same global namespace. Plugins communicate by registering callbacks on shared hooks (filters and actions). When two callbacks run on the same hook, the order they run in is controlled by a priority number passed to add_filter and add_action. The default priority is 10. Lower numbers run first. Ties are broken by registration order, which is determined by alphabetical plugin folder order on disk.

That last detail is why a conflict can suddenly appear after you rename a plugin folder, change which plugin is "active", or even update one plugin to a new version that registers its callbacks slightly differently.

Signs you are looking at a plugin conflict

A few symptoms reliably point to plugin code rather than core, theme, or hosting issues:

  • The site started misbehaving immediately after you activated, updated, or deactivated a plugin.
  • A specific feature breaks (checkout, contact form, admin save button, image upload) while the rest of the site still works.
  • The browser console shows a JavaScript error referencing a file under wp-content/plugins/.
  • The PHP error log has a fatal whose file path lives under wp-content/plugins/.
  • Visitors and admins see different things: the admin loads, but the front end is broken, or vice versa.
  • The same page works when you switch to the default theme, fails when you switch back. (That points at a theme/plugin conflict, but the diagnosis path is identical.)

If the site shows the WordPress critical error screen, the canonical entry point is there has been a critical error on this website, which covers the recovery email flow that lets WordPress itself tell you which plugin caused the fatal. If the page is fully blank with no error message, start with white screen of death in WordPress. Both articles eventually send you back here once you have stabilized the site enough to investigate the underlying conflict.

Common causes, ordered by likelihood

After enough of these tickets, the order is consistent.

  1. Hook priority collision. Two plugins register callbacks on the same hook (commonly the_content, template_redirect, wp_enqueue_scripts, woocommerce_payment_complete). Each expects the data in a specific shape. The priority order, often set implicitly by the default 10, decides which one wins. Both plugins are individually correct.
  2. JavaScript conflict in the browser. Two plugins enqueue different versions of the same library (jQuery UI, Select2, Swiper), or two scripts attach handlers to the same DOM element and one stops the other from firing. Symptom: the page loads but a button or modal does nothing. The browser console has a TypeError, an Uncaught ReferenceError, or a is not a function error.
  3. PHP fatal from a missing dependency. Plugin A calls a function defined in plugin B (get_field() from Advanced Custom Fields, WC() from WooCommerce, acf_register_block_type()). When plugin B is deactivated, updated to a version that renamed the function, or just loads later, plugin A throws Call to undefined function.
  4. Name collision at the PHP level. Two plugins define a class, function, or constant with the same name. PHP throws Cannot redeclare class. This is rare on actively maintained plugins because most modern plugins prefix their names, but it still happens with old or hand-rolled code.
  5. remove_action mismatch. Plugin A tries to unhook a callback that plugin B added, but A and B disagree about the priority. The unhook silently fails (because remove_action and remove_filter only unhook a callback registered on the exact same priority), and the original callback keeps firing. Symptom: a feature you thought you disabled is still active.
  6. Asset dequeue conflict. Plugin A calls wp_dequeue_script on a handle that plugin B depends on. The script load chain breaks and plugin B's frontend stops working.

The first three account for the large majority of plugin-conflict tickets I see. The rest are the long tail.

Step 1: use Health Check & Troubleshooting safe-mode (no downtime for visitors)

When wp-admin still loads, the cleanest first move is the Health Check & Troubleshooting plugin maintained by WordPress.org. It has 300,000+ active installations and ships a feature called Troubleshooting Mode that disables plugins and switches to a default theme for your logged-in user only. Visitors continue to see the live site as it is.

The plugin's last release on the WordPress.org repository is 1.7.1 from 2024-07-25, which is older than I would normally tolerate for a tool I rely on, but the safe-mode functionality has not changed and the plugin still works on current WordPress. If you are uncomfortable using a plugin that has not seen a release in over 18 months, the manual folder-rename path in step 2 produces the same diagnostic result.

How to use it:

  1. Install Health Check & Troubleshooting from Plugins > Add New in wp-admin. Activate it.
  2. Open Tools > Site Health > Troubleshooting.
  3. Click Enable Troubleshooting Mode. Your session now sees a stripped-down WordPress: every plugin is paused for you and the active theme is replaced by a default theme. According to the WordPress.org support handbook, this is "only the case for your user, it does not affect any other site visitors, or users of your site."
  4. Reproduce the broken behavior. If it is gone, the cause is in your plugins or theme. If it is still there, the cause is somewhere else (core, hosting, server config) and you can stop here and look further upstream.
  5. Use the admin bar's Troubleshooting Mode menu to re-enable plugins one by one. After each plugin you re-enable, reproduce the broken behavior. The first plugin that brings the symptom back is the one involved in the conflict.
  6. When you find the culprit, click Disable Troubleshooting Mode in the admin bar. Your normal session returns and every plugin's actual activation state is restored.

You will know it worked when the symptom reappears on a specific plugin re-enable and disappears when you disable troubleshooting mode again. Note that the plugin name you found is one half of the conflict pair, not necessarily the broken one. Step 4 covers how to figure out which plugin is the actual fix target.

A useful detail the plugin's reviews surface: troubleshooting mode is per-cookie. If the cookie gets cleared or you switch browsers mid-session, you may exit safe-mode without intending to. Stay in the same browser window for the whole diagnosis.

Step 2: bisect via folder rename when wp-admin is unreachable

When wp-admin itself is broken, safe-mode is unavailable and you fall back to a more direct technique: rename plugin folders on disk to deactivate them in chunks, then narrow down with binary search.

This is the path the official WordPress recovery mode docs describe under "What to do if the recovery email notification doesn't arrive". It works whenever you have file access (SFTP, hosting panel file manager) and is the single most reliable diagnostic technique because it requires nothing inside WordPress to be working.

The crucial discipline: rename folders, never delete them. Renaming preserves the plugin's database options, transients, sessions, shopping carts, and form drafts. Deleting can fire the plugin's uninstall.php hook (depending on host and how the deletion is triggered) which on many plugins wipes their data. Bulk-deactivating "the safe way" via wp-admin's bulk action also flushes some transients on certain plugins. Folder rename is the only zero-side-effect option.

The procedure:

  1. Connect via SFTP, your hosting panel's file manager, or whatever file access your host gives you.
  2. Open wp-content/plugins/.
  3. Pick the half of your plugin list that is more likely to contain the suspect (most-recently-installed first, or the one you just updated). Rename each of those folders by appending .off, for example bad-plugin becomes bad-plugin.off. WordPress treats a renamed folder as a deactivated plugin. The database row in wp_options.active_plugins still references the old name, which is what lets you "reactivate" by renaming the folder back.
  4. Reload the broken page.
  5. If the symptom is gone, the conflict is somewhere in the half you just disabled. Re-enable that half by removing the .off suffix from each folder, then disable a smaller subset (a quarter, then an eighth) the same way. Each round halves the suspect pool.
  6. If the symptom is still there, the conflict is in the half you did not touch. Restore the renamed half (drop .off) and disable the other half.
  7. Continue until you are down to one plugin folder. That is the plugin involved in the conflict.

For a site with 30 plugins, you reach a single suspect in about five rounds. For 100 plugins it is seven. Faster than reactivating one by one, and you never lose transient data.

WP-CLI users with SSH access have a faster equivalent: wp plugin deactivate <plugin-slug> deactivates without touching uninstall.php. The same bisection logic applies. The full reference is documented at WP-CLI plugin deactivate.

A separate tool worth knowing about is Plugin Detective (current version 1.2.29, last updated 2025-12-09). It is a server-side PHP plugin that automates exactly this binary-search bisection from inside wp-admin, with a guided "yes it is fixed / no it is still broken" interface. Two limitations to keep in mind: it only finds which plugin is involved, not why (it does not detect hook-priority collisions or read the debug log for you), and it explicitly does not support multisite installs. For single-site WordPress installs where wp-admin still loads, it is faster than manual folder renames. For multisite or when wp-admin is gone, you are back to the SFTP path above.

Step 3: read the debug log to pinpoint the hook or function

Knowing which plugin is involved is half the answer. The other half is which line of code, which function, and which hook. The debug log tells you all three.

If you have not enabled WP_DEBUG_LOG yet, follow how to enable and read the WordPress debug log to set the four constants safely. The short version, in wp-config.php before the "stop editing" line:

// Enable debug mode
define( 'WP_DEBUG', true );
// Write errors to wp-content/debug.log
define( 'WP_DEBUG_LOG', true );
// Hide errors from visitors
define( 'WP_DEBUG_DISPLAY', false );
// Belt-and-braces: also tell PHP not to display
@ini_set( 'display_errors', 0 );

With debugging on, reactivate just the suspect plugin (rename bad-plugin.off back to bad-plugin), reload the page that triggers the symptom once, then deactivate the plugin again. Open wp-content/debug.log. The last block of entries describes what happened. A typical fatal looks like:

[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

Three things to extract:

  • The folder under wp-content/plugins/ is the plugin that crashed. In the example, some-theme-addon.
  • The function name in the message is the missing or conflicting symbol. get_field() is from Advanced Custom Fields, so the conflict is some-theme-addon calling ACF without ACF being loaded or with an incompatible ACF version.
  • The file and line is where to point a developer if the plugin needs a real fix.

If the symptom is a JavaScript error in the browser console rather than a PHP fatal, the debug log will not catch it. Open the browser's DevTools Console tab, reproduce the symptom, and look for the first red error. The file URL points at the offending plugin's JS handle. From there, Query Monitor can show you which scripts and styles are enqueued and in what order, which is the JS-side equivalent of the hook-priority debugging that PHP fatals make obvious.

For hook priority issues specifically, debug logging alone is not enough. You need to see which callbacks are registered on a hook and in what order. Query Monitor has a Hooks panel that lists this for the current request, including the priority and the callback function for every hook fired. That panel is what tells you whether your fix is "change the priority of plugin A's callback" or "remove plugin B's callback entirely".

Set WP_DEBUG back to false once you have your answer. A live site should never run with debug logging on for longer than the incident itself.

Step 4: permanent fixes per cause type

Once you know which plugin is involved and which hook, function, or asset is the collision point, the permanent fix splits into a few branches.

Hook priority collision

If two plugins both hook into, say, the_content at default priority 10 and the wrong one wins, the fix is to change the priority of the one you want to lose, in a tiny custom plugin or a mu-plugin. Example:

// In a mu-plugin: run plugin-a's callback after plugin-b's,
// instead of the default order
remove_filter( 'the_content', 'plugin_a_callback', 10 );
add_filter( 'the_content', 'plugin_a_callback', 20 );

You need the exact function name plugin A registered. Query Monitor's Hooks panel shows it. The priority you pick (20 here) just needs to be higher than the priority plugin B is using, so plugin A's callback runs after plugin B's and gets the final word on the output.

Be aware of the remove_filter priority requirement: the priority you pass to remove_filter must match the priority the original add_filter used. If plugin A registered at priority 10 and you call remove_filter(... , 'plugin_a_callback', 20), the unhook silently fails. This is the same trap as the remove_action mismatch from the common-causes list.

JavaScript conflict

When the conflict is in the browser, the fix is usually to dequeue one of the scripts on the pages where the conflict happens. In a small custom plugin or mu-plugin:

add_action( 'wp_enqueue_scripts', function () {
    if ( is_singular( 'product' ) ) {
        // The slow-but-broken slider is not needed on product pages
        wp_dequeue_script( 'plugin-b-slider' );
    }
}, 100 );

The 100 priority is intentionally late, so it runs after both plugins have enqueued their scripts. The script handle (plugin-b-slider here) is visible in Query Monitor's Scripts panel. Watch out: dequeuing a script that has dependents will break those too. The full chain is what wp_dequeue_script actually unhooks.

PHP fatal from missing dependency

The fix is one of:

  • Reinstall the plugin that defines the missing function (most common: re-enable Advanced Custom Fields or WooCommerce after they were accidentally deactivated).
  • Pin the dependency plugin to a version that still defines the function the addon expects (often the case after a major update renamed an internal API).
  • Replace the addon with a maintained alternative if the dependency relationship is permanently broken.

Permanently disabling the addon is also a valid choice if the function it depends on is not coming back.

Name collision at PHP level

There is no clean fix from a site-owner's seat. One of the two plugins has to rename its colliding symbol, which means either contacting the plugin author or replacing the plugin. In the meantime, deactivate the less essential of the two.

remove_action or remove_filter mismatch

Look at the source code of the plugin trying to unhook. Find the priority it is using. Compare with the priority of the original add_action. They have to match exactly. If the original was added at priority 5 and the unhook is using default 10, the fix is to change the unhook to priority 5 (in a custom plugin override, since you cannot edit the plugin code without it being overwritten on the next update).

Asset dequeue conflict

Same as the JavaScript conflict above, but the offender is another plugin's wp_dequeue_script call. The fix is either to re-enqueue the script on a later priority, or to disable the over-eager dequeue plugin. The second option is usually more honest: a plugin that dequeues another plugin's assets without an opt-out is overstepping.

What plugin-conflict diagnosis is NOT

A few claims pop up in WordPress troubleshooting guides that do more harm than good.

  • "Deactivate all plugins at once and reactivate one by one." This is the WordPress.org Learn lesson's recommended path on the official troubleshooting plugin and theme conflicts page. It works diagnostically, but on a live site with active visitors it destroys transient data and can break checkouts in flight. The Health Check safe-mode in step 1 and the folder-rename bisection in step 2 are the per-user and per-folder equivalents that do not nuke session state.
  • "If two plugins conflict, one of them is broken." Almost never true. Most conflicts are the consequence of two pieces of correct code making different assumptions about hook priority or about which plugin runs first. Naming one as "broken" sets you up to demand a fix from a plugin author who will (correctly) say their plugin works fine on its own.
  • "Plugin Detective will find every conflict." Plugin Detective finds which plugin is involved by binary-search bisection. It does not detect hook-priority collisions, JavaScript errors, or which function is colliding. For those you need the debug log and Query Monitor.
  • "Switch the theme to fix the conflict." Switching to a default theme is a useful diagnostic step (it tells you whether the active theme is involved) but it is rarely the fix. If the symptom disappears on the default theme, the conflict is between a plugin and the theme's plugin-handling code, and the right fix is in the theme, not in switching to one you do not actually want to use.
  • "Increase memory and the conflict goes away." A higher PHP memory limit hides some symptoms (specifically the Allowed memory size exhausted flavor) without fixing the conflict. The full per-cause fix for memory exhaustion lives in allowed memory size exhausted in WordPress. For an actual hook or JS conflict, more memory does nothing.

When to escalate

If the diagnosis stalls, or the conflict is between two plugins you cannot replace and cannot patch, the bundle to hand to a developer or your host is:

  • The exact name and version of every plugin involved. For Health Check users, the safe-mode log of which plugin re-enable triggered the symptom.
  • The active theme name and version.
  • The PHP version on the server (visible in your hosting panel).
  • The WordPress version (from wp-includes/version.php or any working dashboard view).
  • The full last 30 lines of wp-content/debug.log after triggering the symptom once.
  • For a JavaScript conflict, the full text of the first red error in the browser console, including the file URL.
  • The exact reproduction steps. "Open the cart, add a product, click checkout" beats "checkout is broken".
  • Whether you have reproduced the issue on a staging copy. A conflict that appears on production but not staging is a hint that something on staging (the URL, a feature flag, a missing third-party connection) is changing the code path.
  • For a hook-priority collision, the relevant Query Monitor Hooks panel screenshot showing both callbacks and their priorities.

A specialist with that bundle in hand can usually identify the conflict pair and write the fix override in under an hour. Without it, the same investigation is most of an afternoon.

How to prevent the next conflict

You cannot eliminate plugin conflicts on an open ecosystem with tens of thousands of plugins, but a few habits keep them rare and survivable.

  • Run as few plugins as you actually use. Every plugin is a hook registration, an asset enqueue, and a potential collision partner. Audit the list once a quarter and remove anything you do not actively rely on.
  • Test plugin updates on a staging copy before production. The full setup path is in setting up a WordPress staging environment. Staging does not catch every conflict (production load and third-party connections matter), but it catches most of them.
  • Update one plugin at a time. Bulk-updating ten plugins in a click saves 30 seconds and costs you the ability to know which one started the conflict if anything breaks.
  • Pin critical dependencies to known-good versions. For sites where plugin A depends on a specific function in plugin B, do not auto-update plugin B without testing first. The mechanism for controlling which plugins auto-update is in WordPress automatic updates: control what updates and when.
  • Keep WP_DEBUG_LOG ready to enable. The four constants from step 3 should be one search-and-replace away in wp-config.php. When the next conflict happens, you want to flip them on, capture one reproduction, and flip them off.
  • Subscribe to the changelogs of plugins that have hurt you before. Reading the release notes for a major plugin update before clicking takes less time than recovering from a bad one.

When a plugin conflict does happen, the cost is not the conflict itself. It is the panic of a broken site without a diagnosis path. Run through this article on a staging copy you can break on purpose. The next real conflict becomes a fifteen-minute job rather than a panicked afternoon, which is the entire reason the path is worth practising once before you need it.

Want this to stop being your problem?

If outages or errors keep repeating, the fix is often consistency: updates, backups and monitoring that don't get skipped.

See WordPress maintenance

Search this site

Start typing to search, or browse the knowledge base and blog.