Your site worked ten minutes ago. Now it is a blank screen and a line of PHP you never wrote.

The WordPress fatal error: cannot redeclare fires when a function, class, or constant gets declared a second time inside one request. PHP stops execution on the spot.

Usual suspects: a snippet pasted twice into functions.php, two copies of the same plugin, or a theme shipping its own build of a shared library.

What this guide covers:

  • Reading the error message and locating both file paths
  • Getting back into wp-admin when the dashboard is gone
  • Fixing each cause, from duplicate snippets to Composer library conflicts
  • Guards, prefixes, and staging habits that keep it from returning

What Is the WordPress “Cannot Redeclare” Fatal Error

Cannot redeclare is a PHP fatal error that fires when a function, class, constant, or method name gets declared a second time inside the same request. PHP stops execution on the spot. WordPress then serves a blank page or the critical error screen.

Variables in PHP overwrite silently. Functions and classes do not.

Once a name enters the declared function table, that slot stays locked for the rest of the page load. A second function myhelper() anywhere in the load order kills the request.

Error level: EERROR, the most severe class PHP throws. No partial render, no fallback template, no graceful degradation.

Message variantWhat got duplicatedTypical origin
Cannot redeclare function_name()Global functionfunctions.php or a plugin file
Cannot redeclare class ClassNameClass definitionBundled library or autoloader
Cannot declare class X, name already in useImported class nameDuplicate use statement
Constant CONSTANT_NAME already definedConstantdefine() call without a guard

PHP 8.x wraps most of these in an uncaught Error object and prints a stack trace. PHP 7.4 prints the bare message with no trace, which is worth knowing because 42.91% of WordPress sites still run PHP 7.4 according to WordPress.org statistics.

Have you seen the latest WordPress statistics?

Discover the latest WordPress statistics: market share, security trends, performance data, and revenue insights that shape the web.

Check Them Out →

The symptom on the front end depends on your WordPress version. On 5.2 and later you get the critical error page, and on older installs you get a true white screen of death.

Every redeclaration crash belongs to the broader family of WordPress fatal error events, but this one has a narrower fix path than memory or permission failures.

How to Read the Cannot Redeclare Error Message

The message names 4 things: the duplicated symbol, the file holding the original declaration, that file’s line number, and the file where the duplicate appears. The second path is where PHP stopped. The first path is where the name was claimed.

Fatal error: Cannot redeclare wpsitesgooglefonts() (previously declared in /wp-content/plugins/theme-customisations/custom/functions.php:21) in /wp-content/plugins/theme-customisations/custom/functions.php on line 27 `

That exact error appeared in a Treehouse community thread after a user pasted a second Google Fonts snippet into the same custom functions file.

Symbol: wpsitesgooglefonts()

First declaration: line 21

Duplicate: line 27, same file

When both paths match, the duplicate sits inside one file. When they differ, two separate codebases are fighting over the same name.

Recovery Mode emails arrive with the subject “Your Site is Experiencing a Technical Issue” (SolidWP) and name the paused plugin without printing the raw message. You still want the raw message.

Enabling WPDEBUG and WPDEBUGLOG to See the Full Message

Open wp-config.php above the “stop editing” comment and set three constants.

  • define(‘WPDEBUG’, true);
  • define(‘WPDEBUGLOG’, true);
  • define(‘WPDEBUGDISPLAY’, false);

Output lands in wp-content/debug.log. Keeping display off means visitors never see file paths while you work.

Site Health caveat: WordPress disables its own fatal error handler when WPDEBUG is true, so the critical error page gets replaced by the raw output. That trade is usually worth it. If you want the display route instead of the log route, the constants that show PHP errors in WordPress work the same way.

Finding the Error in Server Logs When Debug Output Is Suppressed

Hosts write PHP fatals to their own errorlog regardless of your WordPress settings.

Common locations, in the order worth checking:

  • cPanel > Metrics > Errors
  • /home/user/logs/errorlog or publichtml/errorlog
  • Host dashboard log viewers (Kinsta, SiteGround, WP Engine all expose one)

Query Monitor surfaces PHP errors in the admin bar once you regain access, which shortens the loop on repeat crashes. Grepping the WordPress error log for the word “redeclare” pulls every instance at once.

What Causes the Cannot Redeclare Error in WordPress

Six causes account for nearly every case: duplicated snippets in functions.php, two copies of one plugin, shared third-party libraries, parent and child theme overlap, require instead of requireonce, and generic function names colliding across packages.

The collision surface grew with the ecosystem. US WordPress sites average 21 plugins each and the official directory lists over 60,300 free plugins (SQ Magazine, 2025), so name overlap between independent codebases stopped being rare years ago.

CauseTell in the error messageFix difficulty
Duplicate snippetBoth file paths are identicalLow
Two plugin copiesFile paths differ by folder suffixLow
Bundled libraryClass name or vendor folder appears in the pathHigh
Parent and child themeOne file path appears in each theme folderMedium

Duplicate Snippets in functions.php

Someone pastes a snippet, forgets, and pastes it again three weeks later. That accounts for more of these crashes than any plugin bug.

The truepluginsactivate() duplicate is a documented example: two copies of that function land at the end of wp-includes/functions.php and take the site down instantly.

Both file paths in the message will be identical, with two different line numbers. That signature means the fix lives in one file.

Two Copies of the Same Plugin

How it happens: a manual upload creates plugin-name-2 alongside plugin-name.

Where it comes from: failed updates, migrations, restored backups, and FTP uploads that did not overwrite cleanly.

What breaks: WordPress loads every folder in wp-content/plugins that has an active entry, so both copies declare the same functions.

Botched updates are a frequent trigger here, and the same root cause produces most errors when updating plugins.

Bundled Library Conflicts Between Plugin and Theme

ACF powers over 2 million sites (WordPress.org), and a good share of premium themes ship ACF PRO inside the theme folder.

Install standalone ACF next to one of those themes and both try to declare the same classes.

  • TGM Plugin Activation, bundled by hundreds of themes
  • Freemius SDK, shared across freemium plugins
  • Composer vendor folders with unprefixed packages

A theme shipping its own copy of a library produces a WordPress theme error that looks identical to a plugin conflict in the log.

require vs requireonce Include Mistakes

require: loads the file every single time the statement runs. Loop it, call it from two hooks, or include it from two bootstrap files, and the declarations inside run twice.

requireonce: tracks the resolved absolute path and skips repeat loads.

Same split applies to include and includeonce. Use the once variants for anything containing declarations.

How to Regain Admin Access After the Fatal Error

Five methods restore wp-admin without touching any code: the Recovery Mode email link, renaming the plugin folder over FTP, renaming the whole plugins directory, renaming the active theme folder, and clearing activeplugins in the database.

WordPress 5.2 (May 2019) added fatal error recovery mode specifically so administrators could fix crashes that previously required a developer, per Make WordPress Core.

Recovery Mode link: sent to the admin address, valid for 24 hours, pauses the offending plugin or theme and drops you into a working dashboard.

Rename one plugin folder: in File Manager or FileZilla, change plugin-name to plugin-name-off. WordPress deactivates it on the next load.

Rename wp-content/plugins: nukes every plugin at once. Use it when the message does not name a folder.

Rename the active theme folder: WordPress falls back to Twenty Twenty-Five or whichever default is installed.

phpMyAdmin route: open wpoptions, find the activeplugins row, and replace the serialized value with a:0:{}. Back up the table first.

Once you are back in, the “there has been a critical error” screen has its own full critical error recovery walkthrough covering the cases where the email never arrives.

How to Fix Cannot Redeclare Caused by Duplicate Code in functions.php

Search the file for the function name printed in the error, delete the second declaration, and reload. Renaming the duplicate instead of deleting it leaves dead code that fires unwanted hooks.

Steps that actually resolve it:

  1. Copy the symbol name from the error, minus the parentheses
  2. Open functions.php over SFTP and search for it
  3. Go to the line number listed second in the message
  4. Delete that block, including its addaction or addfilter call
  5. Save and reload the front end

Load order matters. Child theme functions.php loads before the parent theme’s, which is why a snippet copied into both files crashes with the child theme path listed as the original declaration.

Wrapping the block in if (!functionexists(‘name’)) also clears the crash. It works, though it hides the duplication rather than removing it.

Editing this file over FTP beats the built-in theme editor every time, since a bad save through the browser can lock you out again. The mechanics of editing functions.php in WordPress are worth getting right before you touch a live site.

Better long-term move: keep snippets in WPCode or Code Snippets, which store each block separately and deactivate a broken one instead of taking the site down.

How to Fix Duplicate Plugin and Bundled Library Conflicts

Two separate codebases declaring the same name require removing one copy, not guarding it. Identify both folders from the file paths, decide which one the site actually needs, and delete the other.

Guards do not help here. Wrapping a class in classexists() means the second version never loads, and any code expecting that version’s methods breaks quietly instead of loudly.

Removing the Duplicate Plugin Folder

Compare the two paths in the error message. One will carry a suffix like -2, -old, -backup, or a version number.

Order of operations: deactivate through Recovery Mode first, then delete the folder over SFTP, then reactivate the survivor.

Check the plugin’s readme.txt version line in both folders before choosing. Deleting the newer copy by accident wastes an hour.

Resolving Shared Third-Party Library Versions

Two plugins loading different versions of one Composer package is the hardest variant of this error.

Why it breaks: Composer’s autoloader registers the first class it finds. The second plugin then calls methods that version does not have, or triggers a redeclaration if the package loads outside the autoloader.

Real-world fix: plugin developers run PHP Scoper or Mozart to prefix their dependencies at build time, which isolates each copy under its own namespace.

You cannot patch that from the outside without breaking updates. Report the collision to both developers and disable one plugin until it ships.

How classexists, functionexists, and requireonce Prevent Redeclaration

Three native PHP guards stop redeclaration before it happens: functionexists() checks the declared function table, classexists() checks the class table, and requireonce tracks resolved file paths. defined() covers constants.

GuardProtectsGotcha
function_exists()Global functionsFunction names are matched case-insensitively
class_exists()ClassesTriggers the autoloader unless false is passed as the second argument
require_onceEntire filesCompares resolved paths; symlinks can bypass duplicate detection
defined()ConstantsWithout it, constants may be silently overwritten

classexists() detail: the second parameter controls autoloading. Pass false inside a bootstrap file so the check does not pull in the very class you are about to define.

Pluggable functions are the one place where a guard is the correct permanent answer. WordPress core wraps wpmail(), wpnewusernotification(), and roughly 25 others in functionexists() inside pluggable.php precisely so a plugin can replace them.

Core ticket #9915 documents the failure mode: a plugin declaring wpnewusernotification() in the global scope crashes with “previously declared in wp-includes/pluggable.php”. Only one piece of code gets to claim each pluggable name.

Where guards stop being a fix: two full copies of one plugin. A functionexists() wrapper silences the crash and leaves you running half of one codebase and half of another.

Patching pluggable.php directly is never the answer, and the reasoning behind editing core WordPress files applies here more than anywhere else in the stack.

How Namespaces and Unique Prefixes Stop Function Name Collisions

Namespaces isolate class, function, and constant names inside a package so two codebases can use the same name without colliding. Prefixes achieve the same result in the global scope. Both remove the collision instead of guarding against it.

The WordPress Plugin Handbook sets the floor: prefixes should run at least 4 letters, with 5 recommended, and should avoid common English words.

Every global function, class, constant, and hook name needs that prefix. Namespacing does not cover constants declared with define() or hook strings, so those still get prefixed individually per the WordPress PHP Coding Standards.

ApproachCoversLimitation
Prefix (wporg)Functions, classes, constants, and hooksCreates longer names; no automatic enforcement
NamespaceClasses, functions, and constants inside the packageHooks and define() constants still require prefixes
Class wrapperMethods and propertiesThe class name itself can still conflict

Names that collide most: plugininit, getsettings, sendemail, wplog, render, Logger, Cache.

A DEV Community walkthrough by Marcus Kober shows the failure in three lines: two plugins each declaring plugininit() produce "Cannot redeclare plugininit() (previously declared in /plugin-01/plugin-01.php)".

The WordPress Coding Standards enforce this through the PrefixAllGlobalsSniff rule in PHPCS, which flags any unprefixed global on every commit.

Dependencies get the same treatment. PHP Scoper and Mozart rewrite Composer packages under a private namespace at build time so two plugins carrying the same library never meet in the global scope.

How to Identify the Conflicting Plugin or Theme by Testing

Deactivate everything, then reactivate one plugin at a time and reload after each. The plugin that brings the error back is the culprit. Switch to a default theme separately to rule the theme in or out.

Run the sequence in this order:

  1. Deactivate all plugins from the Plugins screen
  2. Confirm the site loads
  3. Reactivate one plugin, reload the front end and wp-admin
  4. Repeat until the crash returns
  5. Switch to Twenty Twenty-Five and repeat if plugins come back clean

The Health Check & Troubleshooting plugin (300K+ active installs, WordPress.org) does this without taking the live site down. It sets a browser cookie, so only your session runs with plugins disabled while visitors see the site unchanged.

Do the whole thing on a clone, not on production. WP Staging, LocalWP, Kinsta’s one-click staging, and WP Engine’s three-environment setup all give you a copy to break.

Write down what you activated and in what order. Redeclaration crashes depend on load order, so an unrecorded sequence is not reproducible.

Which WordPress Fatal Errors Look Like Cannot Redeclare But Are Not

Four errors produce the same blank page or critical error screen: call to undefined function, allowed memory size exhausted, cannot declare class because the name is already in use, and parse errors in functions.php. Each has a different fix path.

ErrorRoot problemFirst move
Cannot redeclareA name is declared twiceRemove one of the duplicate declarations
Call to undefined functionThe function was never loaded or declaredCheck the file load order
Allowed memory size exhaustedPHP memory limit has been reachedIncrease WP_MEMORY_LIMIT
Parse error, unexpectedInvalid or broken PHP syntaxRevert the most recent code edit

The inverse case: a call to undefined function means the opposite problem, a function called before its file loaded or after a plugin was removed.

Memory, not names: when the log reads allowed memory size exhausted, no duplicate exists at all. A single heavy import or image process ate the limit.

Import collisions: “Cannot declare class X because the name is already in use” comes from two use statements pulling different classes under one alias, not from two declarations.

Pluggable functions sit in their own category. Declaring wpmail() or wpnewusernotification() outside pluggable.php throws a redeclaration message, but the fix is a filter, not a deletion.

A missing semicolon in functions.php also kills the site with a fatal message on a line you never touched, which is why a WordPress syntax error gets mistaken for a conflict. The parse error walkthrough covers the “unexpected” variants in detail.

How PHP Version Changes Affect Redeclaration Errors

A PHP version change alters which files load, which fallback declarations run, and which conditions PHP treats as fatal. The same plugin set can run clean on 7.4 and crash on 8.2 without a single line of code changing.

WordPress.org statistics for 2026 put PHP 8.2 at 25.804% of reporting sites and PHP 7.4 at 19.288%, which is why plugin authors still ship version-conditional code paths that can double-declare.

PHP versionRedeclaration-relevant change
PHP 8.0Signature mismatches became fatal instead of warnings; @ no longer suppresses E_ERROR
PHP 8.1More deprecations appeared, pushing plugins toward polyfill fallbacks
PHP 8.2Dynamic properties were deprecated, leading to class rewrites in shared libraries

The polyfill trap: a plugin defines strcontains() for older PHP, PHP 8.0 already provides it, and the unguarded fallback throws a redeclaration error on the function it was meant to protect.

Case does not save you. PHP function names are case-insensitive, so MyFunction() and myfunction() occupy the same slot and still collide.

Check your current version in Tools > Site Health > Info > Server before changing anything. Host control panels expose the switcher, and knowing where php.ini sits in a WordPress install helps when the panel setting and the runtime disagree.

Roots reported in December 2025 that only about 48% of WordPress sites run a PHP version still receiving security patches. Rolling back to an older version buys you an afternoon, not a fix.

How to Prevent Cannot Redeclare Errors on a Production Site

Five practices keep redeclaration crashes off live sites: staging-first deployment, version control on the theme, plugin folder audits after every migration, permanent debug logging with display off, and uptime monitoring that catches the fatal before a customer does.

Staging first: every snippet, plugin activation, and theme update goes to a clone before production. Kinsta ships one-click staging in MyKinsta and WP Engine gives three environments per install.

Version control the theme: a Git repo on wp-content/themes turns a broken functions.php into a one-command revert instead of an FTP archaeology session.

Audit after migrations: clone operations and restored backups are where plugin-name-2 folders appear. List wp-content/plugins and look for suffixed duplicates before declaring a migration finished.

Log permanently: keep WPDEBUGLOG on and WPDEBUGDISPLAY off in production so the message exists before you need it.

One plugin update at a time. Batch updates hide which package introduced the collision.

Monitoring closes the loop, since a fatal error returns a 500 and most uptime services flag it within a minute. Agencies running dozens of installs get more out of this than anyone, and the tooling for managing multiple WordPress sites usually bundles both update staging and error alerts.

The cheapest prevention costs nothing: wrap every custom function in a guard and prefix it with something no other developer would pick.

FAQ on WordPress Fatal Error: Cannot Redeclare

What does cannot redeclare actually mean?

PHP found a function, class, or constant name that was already declared earlier in the same request. Names cannot be claimed twice. PHP throws an EERROR and stops the page immediately.

Why does the message show two file paths?

The first path holds the original declaration. The second path is where PHP hit the duplicate and stopped. Identical paths mean one file contains both copies, and different paths mean two codebases collided.

Can I fix this without FTP access?

Yes, in most cases. The Recovery Mode email link gets you into wp-admin, and cPanel File Manager handles folder renames. phpMyAdmin clears activeplugins when nothing else works.

Should I rename the duplicate function instead of deleting it?

Delete it. Renaming leaves dead code that still fires its addaction or addfilter call, which produces duplicate output, doubled emails, or hooks running twice with no error to warn you.

Does a functionexists wrapper fix two copies of the same plugin?

No. The guard silences the crash while leaving half of one codebase and half of another running. Delete the duplicate plugin folder instead of wrapping the declaration.

Why did the error appear right after a PHP upgrade?

Plugins ship polyfills for older PHP. When the newer version already provides that function, an unguarded fallback declares it a second time and crashes the exact code it was meant to protect.

Is this error a sign my site was hacked?

Usually not. Duplicated snippets and plugin folders explain nearly every case. Injected copies of truepluginsactivate() inside wp-includes/functions.php are the one documented exception worth scanning for.

Which file should I open first?

The one listed second in the error message, at the line number given. That is where PHP stopped. The first path only tells you which name was already taken.

Will deactivating all plugins delete my content?

No. Deactivation leaves posts, pages, media, and plugin settings in the database untouched. Renaming the plugins folder over SFTP does the same thing without a working dashboard.

How do I stop it happening again?

Prefix every custom function with 4 to 5 unique characters, wrap declarations in functionexists(), use requireonce for includes, and test snippets on a staging copy before production.

Conclusion

The WordPress fatal error: cannot redeclare tells you more than almost any other crash. Two file paths, two line numbers, one symbol name.

Read the message before touching a single file. WPDEBUGLOG writes it to debug.log, and your host keeps a copy in the server error log when debug display stays off.

Then work in order: Recovery Mode for access, delete the second declaration, confirm with a default theme active.

What separates a five-minute fix from a lost afternoon is process, not skill.

Prefix every global. Use requireonce for includes. Guard classes with class_exists and constants with defined.

Test on a clone, keep a Git history on the theme directory, and the next naming collision never reaches a visitor.