Common causes
- HTML or an included header template is output before session_start()
- Whitespace or a UTF-8 BOM before <?php in the file or an included file
- A PHP warning printed to the page before session_start() runs
- session_start() called inside a template partway through the page
- In WordPress, a plugin calling session_start() too late, such as inside a shortcode or template
How to fix it
- Move session_start() to the very top. Call it on the first lines of the entry script, before any include that outputs HTML. A shared bootstrap file is the best place.
- Find the output that came first. Use headers_sent($file, $line) just before session_start() and log $file:$line, or read 'output started at' in the related warning.
- Remove whitespace and BOM. Ensure nothing precedes <?php, drop closing ?> tags in PHP-only files, and save files as UTF-8 without BOM.
- Start the session only once and only if needed. Guard with if (session_status() === PHP_SESSION_NONE) so multiple includes do not try again.
- Use the right WordPress hook. Start sessions early on the init hook, not inside templates or shortcodes, and close them with session_write_close() to avoid blocking REST and loopback requests.
- Keep warnings out of output. Set display_errors = Off in production so a stray notice cannot become the output that blocks the session.
bootstrap.php
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start([
'cookie_httponly' => true,
'cookie_secure' => true,
'cookie_samesite' => 'Lax',
]);
} How to stop it happening again
- Start sessions in one bootstrap file included first
- Omit closing ?> tags and save files without BOM
- Never call session_start() from templates