为何在single.php中使用wp_redirect未触发header警告?
我之前使用wp_redirect()时,必须将其放在init这类动作钩子中,否则会触发「Warning: Cannot modify header information - headers already sent by.」警告。但今日遇到一个案例,直接在single.php中使用了wp_redirect(),代码如下:
<?php /** * The template for displaying all single posts * * @link https://developer.wordpress.org/themes/basics/template-hierarchy/#single-post * * @package Adele_Royce */ get_header(); ?> <?php if ( !is_user_logged_in() ) { wp_redirect( 'https://example.com/login/'); } else { ?> <section class="blog-wrap"> <div class="container"> <div class="row"> <div class="col-xl-12 col-md-12 col-sm-12"> <div id="primary" class="content-area"> <main id="primary" class="site-main"> <?php while ( have_posts() ) : the_post(); get_template_part( 'template-parts/content', get_post_type() ); endwhile; // End of the loop. ?> </main><!-- #main --> </div><!-- #primary --> </div> </div> </div> </section> <?php } ?> <?php get_footer(); ?>
为什么这种写法不会触发header警告?
原因解析
输出缓冲机制在兜底
WordPress默认开启了输出缓冲(output buffering),页面要输出的内容会先暂存在服务器缓冲区里,而非直接发送给浏览器。这段代码里的wp_redirect()虽然在get_header()之后执行,但只要get_header()调用的header.php模板没有触发缓冲区刷新,也没有直接输出任何内容(比如多余的空格、HTML标签),HTTP响应头就还没被发送,此时修改头信息不会触发警告。wp_redirect()的自检逻辑wp_redirect()内部会先检查HTTP头是否已经发送。如果头信息还未发送,就正常执行跳转;只有当头信息已经发送给浏览器后,才会抛出那个经典的警告。这个案例刚好满足“头未发送”的条件,所以没报错。这种写法是“碰运气”,存在风险
这绝非规范用法,完全依赖当前header.php的状态。如果后续修改header.php时不小心加了空格、换行,或者在PHP标签外写了HTML,缓冲区会被提前刷新,wp_redirect()立刻就会触发警告。正确的做法是把跳转逻辑挂在template_redirect这类更早的动作钩子上,确保在任何页面输出前执行跳转。
内容的提问来源于stack exchange,提问作者ARWVISIONS

