De fout in z'n volle vorm:
Warning: Cannot modify header information - headers already sent
by (output started at /home/site/wp-content/themes/twentytwenty/functions.php:1)
in /home/site/wp-includes/pluggable.php on line 1450
Twee bestand-paden in één melding:
- "output started at" →
functions.php:1— hier zit de oorzaak. Iets in dit bestand stuurt output naar de browser vóórdat headers gezet kunnen worden. - "in" →
pluggable.php:1450— hier probeerde PHP later een header te sturen (bijv.setcookie()ofwp_redirect()) en faalde, omdat de output al begonnen was.
De eerste pad is wat je moet fixen. De tweede vermeldt alleen welke functie het te laat gemerkt heeft.
Wat zijn HTTP-headers en waarom is dit een probleem?
Een HTTP-response bestaat uit twee delen:
- Headers — metadata zoals status-code, content-type, cookies, redirects, cache-control. Komt eerst.
- Body — de daadwerkelijke HTML/JSON die de browser rendert. Komt daarna.
Zodra PHP één byte body verstuurt, is het te laat om nog een header te zetten — de header-sectie is al "afgesloten". Functies als header(), setcookie(), session_start(), en in WordPress wp_redirect(), wp_safe_redirect(), wp_login() falen dan met deze waarschuwing.
De foutmelding noemt het één "Warning" maar de gevolgen zijn flink: redirects werken niet meer, cookies worden niet gezet, en je site kan op rare manieren breken.
De drie hoofdoorzaken
1. BOM — Byte Order Mark (verreweg de #1)
Een BOM is één onzichtbaar 3-byte teken (0xEF 0xBB 0xBF) dat sommige editors aan het begin van een UTF-8 bestand zetten. PHP ziet die 3 bytes als output, en daarna is het te laat voor headers.
Veroorzaakt door:
- Bestand opgeslagen via Notepad (Windows) zonder "UTF-8 without BOM" optie
- Bestand bewerkt via FTP-client die BOM toevoegt bij save
- Code gekopieerd uit een Word-document of Outlook-mail
- Plugin-update waarbij de developer per ongeluk een BOM toegevoegd heeft
Detecteren via SSH:
# Check op BOM in wp-config.php
file wp-config.php
# Output: "wp-config.php: UTF-8 Unicode (with BOM) text" = BOM aanwezig!
# Of bytes inspecteren
hexdump -C -n 10 wp-config.php
# Begint met "ef bb bf" = BOM aanwezig
# Vind alle PHP-bestanden met BOM in wp-content/
find wp-content -name "*.php" -exec sh -c 'head -c 3 "$1" | grep -q $"\xef\xbb\xbf" && echo "$1"' _ {} \;
Verwijderen:
# Één bestand
sed -i '1s/^\xef\xbb\xbf//' wp-config.php
# Bulk: alle PHP-bestanden in een directory
find wp-content -name "*.php" -exec sed -i '1s/^\xef\xbb\xbf//' {} \;
Voorkomen: gebruik een editor die BOM-detectie heeft (VS Code, Sublime Text, Notepad++) en sla altijd op als UTF-8 zonder BOM. In VS Code zie je rechtsonder de encoding-status; klik om te switchen.
2. Whitespace vóór <?php of na ?>
Een spatie, tab of nieuwe regel buiten de PHP-tags wordt door PHP behandeld als output. Een bestand dat begint met:
<?php
// code...
Daar staat een lege regel vóór de <?php-tag. Resultaat: 1 byte (newline) wordt verstuurd vóór PHP überhaupt iets doet. "Headers already sent by line 1".
Hetzelfde geldt voor whitespace na de afsluitende ?>:
<?php
// code...
?>
Die laatste lege regel of spaties — ook dat is output.
Detecteren in WordPress (terminal):
# Whitespace voor <?php in wp-config.php?
head -1 wp-config.php
# Whitespace na ?> in functions.php?
tail -3 functions.php
Voorkomen: WordPress-best-practice is de afsluitende ?> in PHP-only bestanden helemaal weglaten. Zo kan er geen per ongeluk toegevoegde whitespace ontstaan. Kijk in WordPress core: wp-config-sample.php, wp-load.php, functions.php — geen ?> aan het einde.
3. Per ongeluk toegevoegde echo, print, var_dump of print_r
Vaak een achtergebleven debug-statement van een ontwikkelaar:
<?php
function my_function() {
echo "test"; // VERGETEN
return $value;
}
add_action('init', 'my_function');
Die echo wordt vroeg in de WordPress-cyclus uitgevoerd (op de init-hook), vóórdat WordPress headers stuurt. Resultaat: alle redirects en cookies daarna falen.
Andere veroorzakers:
print_r($variabele)— klassieker debug-outputvar_dump()— idemerror_reporting(E_ALL)+ini_set('display_errors', 1)waarbij PHP warnings/notices als output worden weergegeven- Een PHP-fout (E_NOTICE) die op je site getoond wordt vóórdat WordPress de pagina opbouwt
Vinden en verwijderen:
# Zoek alle echo/print buiten templates
grep -rn "echo\|print" wp-content/themes/jouw-theme/functions.php
grep -rn "var_dump\|print_r" wp-content/plugins/jouw-plugin/
# Of direct in WP-CLI
wp eval "var_dump(1);" # Test of debug-output errors veroorzaakt
Specifieke gevallen in WordPress
functions.php is meestal de boosdoener
Themes' functions.php wordt op de init-hook geladen, vóórdat WordPress redirects/cookies kan zetten. 80% van mijn "headers already sent" tickets komt door een aangepaste functions.php waar:
- Iemand een BOM heeft toegevoegd via een editor
- Een
?>aan het einde staat met een spatie erna - Per ongeluk debug-output is achtergelaten
wp-config.php als oorzaak
Tweede grote bron. Ook hier vaak BOM (toegevoegd bij het editen via FTP) of whitespace voor <?php. Symptoom: elke pagina geeft de fout, niet alleen redirects, omdat wp-config.php vóór alles wordt geladen.
Plugin-update brak de site
Plugin-developer heeft een nieuwe PHP-file toegevoegd met BOM erin, of debug-output achtergelaten. Quick fix: deactiveer de plugin via SSH (rename de plugin-folder), site werkt weer. Daarna een nieuwere versie of werkende oudere versie installeren.
# Deactiveer plugin via WP-CLI
wp plugin deactivate naam-van-plugin
# Of via FTP/SSH: rename de plugin-folder
mv wp-content/plugins/naam wp-content/plugins/naam.disabled
Stappenplan: dit doe je nu
- Lees de exacte foutmelding. Het pad in "output started at" wijst je naar het bestand. De regel-nummer wijst je naar de plek.
- Open dat bestand in een goede editor (VS Code, Sublime). Check de encoding rechts onderin: zie je "UTF-8 with BOM"? Klik en switch naar "UTF-8".
- Kijk naar regel 1. Whitespace vóór
<?php? Verwijderen. - Scroll naar het einde.
?>aanwezig? Verwijder de hele afsluitende tag (en eventuele whitespace erna). - Check op debug-statements:
echo,print,var_dump,print_rin de file. Verwijder alles dat onbedoeld output doet. - Refresh de site. Foutmelding weg? Klaar. Nog steeds foutmelding? De error wijst nu vermoedelijk een ander bestand aan — ga terug naar stap 1.
Wat als je geen toegang hebt tot SSH/FTP?
Drie opties:
- WordPress admin werkt nog: ga naar Tools > Plugin/Theme File Editor. Daar kun je
functions.phpbewerken in de browser. - Hosting-panel-bestandsbeheerder: cPanel, DirectAdmin en Plesk hebben file-managers met edit-functie. Vaak met BOM-detectie.
- WordPress admin werkt niet meer: schakel via FTP/SSH het thema uit door
wp-content/themes/jouw-themete hernoemen. WordPress valt terug op een default-theme. Geen FTP? Hoster mailen voor noodtoegang.
Veelgestelde vragen
De fout verdween, maar redirects werken nog steeds niet?
Headers worden vroeg gestuurd (rond send_headers-hook). Redirects later (template_redirect-hook). Als output geéérd is door iets vóór send_headers, kan een redirect later alsnog falen zonder dat je de waarschuwing meer ziet (browser-cache). Forceer een hard refresh (Ctrl+Shift+R) of test in incognito.
Werkt ob_start() als workaround?
Technisch ja. ob_start() bovenaan wp-config.php buffer alle output, zodat headers later nog gezet kunnen worden. Maar het is een pleister, geen fix — je verbergt de werkelijke oorzaak. Plus het kost extra geheugen omdat de hele response in buffer staat. Vind en repareer liever de oorzaak.
De error verschijnt alleen in admin, niet op de frontend?
Vaak een plugin-update die in admin-context output stuurt vóór WordPress kan redirecten. Check welke plugins recent zijn bijgewerkt. Ga in admin naar Plugins en deactiveer ze één voor één om de boosdoener te vinden.
Kan een PHP-fout (notice/warning) zelf "headers already sent" triggeren?
Ja. Als display_errors=On op je site, worden PHP-notices en warnings als HTML uitgevoerd. Als zo'n notice vóór WordPress' send_headers gebeurt (bijvoorbeeld een undefined index in een plugin), is dat al output. Schakel display_errors uit op productie en log alleen naar bestand.
Hoe vind ik welk plugin het veroorzaakt?
Quick test: deactiveer alle plugins via WP-CLI of door wp-content/plugins tijdelijk te hernoemen. Activeer ze daarna één voor één tot de fout terugkomt. De laatst-geactiveerde plugin is de boosdoener. Kijk in zijn code naar BOM, whitespace of echo-statements.