Build your WordPress website with Elementor.Discover Elementor Affiliate link
Français

Site appearance

Failures and errors · Beginner to intermediate

WordPress: fix “Headers already sent” at the PHP output source

Fix “Headers already sent” in WordPress: locate the first output, check the modified file or redirect and validate recovery.

Source published: · Source updated: · Editorial policy

Read the French edition

Recognize PHP output sent too early

WordPress displays “Cannot modify header information – headers already sent” after a file change, code addition or update. A redirect may stall or login may fail. This means PHP is trying to send a header after content transmission has begun. It does not prove the file named at the end of the warning is faulty.

The goal is to remove accidental output or move the action to the correct time, then check the affected workflow. The problem may be invisible whitespace, an encoding marker, debugging text or a redirect executed after rendering. These cases require different corrections.

File operations concern a self-hosted installation with authorized access. On WordPress.com or a service deploying configuration automatically, work through the component owner and permitted tools. In multisite, a shared file may affect several sites. Start with the exact message and one representative action.

Preserve the modified file and actions already performed

Keep the current file before any correction, even if it appears responsible. Also retain a known earlier version if available. Store copies privately outside the published directory; an accessible backup configuration file may expose secrets. A file copy and complete backup serve different needs.

Record the recent change, time and action triggering the warning. If it appears after saving a post, check whether text was already saved before clicking again. A failed redirect does not necessarily undo the preceding operation. The same applies to an order or sending action.

Prepare SFTP or file-manager access working independently of WordPress. Retain a still-usable authorized session. An isolated site copy allows component comparison; payments, email and external automation must be disabled before testing. Do not test several corrections simultaneously and lose the ability to attribute results.

Read both locations in the message

Record the path after “output started at” and its line number. It identifies where output began. The later path after “in,” with another line number, identifies where header sending was attempted too late. This distinction prevents modifying a core function merely affected by the problem.

In a fictional example, output reported at line one of wp-config.php prompts checking its beginning and encoding. Output later in a custom file may correspond to HTML, an echo or a displayed warning. A theme file normally producing the page may also reveal that the redirect simply runs after it.

Check the private log at the same request’s time and read preceding messages. An initial warning rendered on screen may precede the header error. Do not conclude there is an encoding marker from line one alone. Keep paths private and share only a useful sanitized excerpt without cookies or complete configuration.

Identify the file owner before acting

Associate the path with a specific component. wp-config.php contains site configuration. A file under wp-content/themes belongs to a theme; a path under wp-content/plugins generally identifies a plugin. Verify the directory actually used, especially if several installations or copies have similar names.

A core file may be the first to produce normal output because custom code then attempts a redirect too late. In that case, do not remove its output or modify core. Locate the late call and its owner. Conversely, a recently saved custom file reported before any page merits checking its first characters.

Choose the appropriate branch. An identified manual change is corrected in its original or prepared copy. A product regression is compared on a copy and addressed through an official fix. Custom code acting after rendering must change execution timing. If you do not recognize the file, record its path and neighboring messages before applying a recipe intended for another case.

Correct encoding or whitespace in a custom file

  1. Through file access, download the identified custom file and open it in a plain-text editor. For an entirely PHP file such as configuration, it should begin with <?php without text or whitespace sent before it. Also inspect encoding: a UTF-8 BOM may produce invisible output. Save as UTF-8 without BOM when the editor offers that option.
  2. If an entirely PHP file ends with ?>, subsequent characters may leave PHP mode. WordPress convention prefers omitting that final closing tag. Remove only the unnecessary final closing tag and outside whitespace in this file type. Do not blindly apply this rule to a template deliberately containing HTML between PHP blocks.
  3. Compare the corrected file with the private copy: usernames, keys, paths and other statements must remain. Then replace only the affected file on the site copy and check the action. If a syntax error or other behavior appears, restore the preserved file. Do not rebuild wp-config.php from a few tutorial lines.

Remove diagnostic output preceding headers

An echo, print_r or var_dump added to inspect a value may send content before login or a redirect. Search only additions related to your last intervention in the identified file. Preserve context and remove temporary diagnostic output when its role is confirmed. Do not delete all display statements from a theme.

A PHP warning displayed before the header message must also be addressed at its source. For example, a missing property may trigger a plugin warning. Hiding that warning from the response may change the symptom without fixing the component. Keep the message in the private log and find its fix or valid configuration.

For WordPress diagnosis, prefer existing logs. If temporary logging must be prepared on a copy, preserve initial settings and use a designated private file without showing errors to visitors. After observation, return to operational settings. Text disappearing from the screen is insufficient: login, saving and expected headers must work.

Check file syntax without confusing validations

An editor supporting PHP validation can find a missing parenthesis or quote after correction. If you already have a terminal and the correct PHP executable, its -l option checks syntax without executing the file as a script. Over SSH, run it under your usual account without privilege escalation. Adapt the path to your private copy and use a version compatible with the site.

A response saying no syntax errors were detected does not prove headers will be sent correctly. Whitespace outside code may remain valid output from the parser’s perspective. Checking the web workflow remains essential. The command therefore replaces neither file comparison nor reading the initial message.

If a syntax error is reported, correct the change on the copy or restore the preserved file before transfer. Do not deliberately upload a known-invalid file to production to see what happens. This step does not require running the file directly with PHP without the checking option.

php -l '/chemin/prive/copie/wp-config.php'

Handle a plugin or theme regression

When the error begins after an update without a known manual change, retain before-and-after versions and check official component announcements. A forum report helps recognize a symptom family; it does not prove your installation has exactly the same fault. Compare files and messages in the observed context.

On an isolated copy, open Plugins, then Installed Plugins if administration works. Record the suspected plugin’s state, deactivate only it normally and reproduce an action without external effects. Reactivate it after recording the result before examining another lead. If the action no longer exists without it, comparison cannot establish a conclusion about that action.

A compatible official fix can then be tested on the copy. Do not replace an entire plugin with a file from another version or delete a core file named in the trace. Rolling back a version also requires checking data changes. If the dashboard is inaccessible, use file access prepared with the maintainer for targeted, reversible intervention.

Move a custom redirect before rendering

This branch fits identified custom code redirecting after loading the header, displaying HTML or producing a page block. Its owner must preserve the original and remove the old late call. Adding a new redirect while keeping the previous one may create a chain or obscure diagnosis.

In WordPress, template_redirect allows deciding on a redirect before template selection with knowledge of requested content. Register code in a component loaded in time, such as the functions file of an already used child theme or an existing functionality plugin. An HTML block in the page editor is not that location.

Validate the condition and destination with the site administrator before changing code. This move concerns public navigation; it is not a universal solution for cookies, exports or administration operations. Test the affected path and an unrelated path on a copy. To undo, remove only the correction and restore original customization to its documented state.

Adapt a redirect example to one page

The example below only replaces an equivalent custom redirect running too late. It assumes fictional pages ancienne-page and nouvelle-page. Replace the slug passed to is_page and path passed to home_url with values verified on your copy. The condition must target only the abandoned page, not also the destination. For hierarchical pages with potentially repeated slugs, have the maintainer target the exact page ID.

In the already chosen customization component, insert this code inside existing PHP without adding another opening tag in the middle of the file. Keep a private copy before editing. Status 302 suits temporary verification; a permanent-redirect decision follows the project afterward without assuming every cache will immediately forget it.

wp_safe_redirect checks the local destination and does not automatically stop processing. The example therefore terminates execution after an accepted redirect. Check the old page reaches the new without looping and another page displays normally. This correction will not remove output already sent before the hook: if the same warning persists, return to its first origin.

add_action( 'template_redirect', function () {
    if ( is_page( 'ancienne-page' ) ) {
        if ( wp_safe_redirect( home_url( '/nouvelle-page/' ), 302 ) ) {
            exit;
        }
    }
} );

Compare components with Troubleshooting when access exists

Troubleshooting can help compare components in a diagnostic session when administration remains usable. Preferably on a copy, an administrator opens Plugins, Add New, searches for Troubleshooting by Marius L. J. and verifies the product. The official listing consulted on November 13, 2026 for version 1.0.2 states minimum WordPress 6.4 and PHP 7.2, with declared testing through WordPress 7.1.4. An old PHP branch is not an operational recommendation.

After installation and activation if needed, open Tools, Site Health, then the Troubleshooting tab and Enable Troubleshooting Mode. The tool returns to Dashboard, where its widget and administration bar let you reactivate useful components one at a time to compare the same workflow. Plugin labels may remain English. The mode does not provide an independent database copy: do not trigger real sending, orders or imports there.

To finish, use Disable Troubleshooting Mode in the widget or administration-bar menu, then check return to normal. Essential Must Use plugins remain loaded; some caches may also distort comparison. The tool fixes neither a BOM nor output in configuration loaded too early. If administration does not start, installing it provides no recovery route. Check a missing tab or rejected activation with the administrator without expanding file permissions to force the mode.

Avoid masking the fault with a global output buffer

An output buffer may delay content transmission and make the problem less visible. That does not turn a late redirect into correctly organized code. Adding a global ob_start call to configuration to hide the warning may also change other response processing. Do not present it as the default repair for a badly encoded file.

Likewise, disabling all error display is an operational rule separate from fixing causes. Visitors no longer seeing a message does not guarantee session or redirect functionality. Keep the corresponding private trace to verify what runs after the change.

If a component deliberately uses a buffer, managing it belongs to its maintainer. Do not randomly add buffer flushing or closing in another file. Return to the identified output and execution time. The criterion remains a correct response with an understood cause, not merely a quiet-looking page.

Verify the failing workflow and other responses

First reproduce the retained case in the test environment. For login, check your profile opens and a second page retains the session. For saving, reopen content to confirm persistence. For a redirect, open Chrome developer tools, Network, before loading the old page. Enable Preserve log to retain navigation. Select the document request and inspect Headers: status and Location must match the intended destination, followed by loop-free loading. Keep cookies and session headers private.

Check the log at the new test time: the old warning must not merely be replaced with another error. Also compare an unrelated public page and usual administration. If an identified cache retains an old response, purge only the affected scope after fixing the source, then repeat checking.

Do not replay a sensitive action to obtain a cleaner screenshot. Verify its already recorded state with the appropriate person. If testing worsens other pages, restore the preserved file or setting through independent access and record the result. Production deployment applies only the validated correction without leaving diagnostic files or backup copies exposed.

Document the cause and prevent the next incident

Keep the initial message, first-output file, retained change and check confirming its effect. Record whether the cause was encoding, whitespace outside PHP, temporary output or a call executed after rendering. This precision avoids treating the next warning as a general cookie or server problem.

For customizations, document the owning component and intended execution time. Work on a copy with a text editor preserving expected encoding. Core and parent-theme files must not become permanent locations for local corrections that disappear during updates.

If the problem persists, send the maintainer the precise workflow, versions and sanitized excerpt of messages from the same request. Clearly distinguish verified facts from remaining hypotheses. Access proof, a password or all of wp-config.php are unnecessary to explain output ordering. Preserve the last working state and restoration route before another intervention.

Check for a BOM without displaying file contents

If the message identifies the beginning of a custom PHP file, a maintainer can check its first three bytes on a private copy. With Python 3 already installed, this check neither executes PHP nor displays credentials inside configuration:

Replace the path with your copy’s path, never a public URL. A positive result confirms this encoding marker; it does not prove it is the only premature output. A negative result rules out neither whitespace before the PHP opening, a displayed warning nor a late redirect.

To correct it, open the copy in a plain-text editor, choose UTF-8 without BOM, then compare changes and check syntax with the guide’s PHP command. Do not bulk-convert installation files based only on this hypothesis.

Transfer only the identified file after validation. Then check the failing web workflow and its log: the byte test does not replace that check. For a regression, restore the preserved private file. This method is free and requires no plugin loaded in WordPress.

python3 -c 'import codecs; f=open("/chemin/prive/copie/wp-config.php","rb"); prefixe=f.read(3); f.close(); print("BOM UTF-8 present" if prefixe == codecs.BOM_UTF8 else "Pas de BOM UTF-8 initial")'

Sources and references

Use these references to check the features, requirements and limitations described. Reading documentation is not a practical test.

View 18 references

English translation of the reviewed French edition. Code examples retain their original identifiers, comments and output strings for reproducibility. Linked exercise files and original screenshots may contain French. No new practical tests or price checks are implied by translation.

Continue reading in English