An echo line in a transition_post_status action leads to “cannot modify header information – headers already sent by”

I tried to set up an action hook with transition_post_status. Inside I wanted to set up a few conditional statements. To see if everything works I wanted to place a debug statement. Problem is as soon as I set an echo statement i get the output alongside two warning messages:

Error

Warning: Cannot modify header information - headers already sent by (output started at /Applications/MAMP/htdocs/sandbox/wp-content/plugins/media-meta-require/media-meta-require.php:193) in /Applications/MAMP/htdocs/sandbox/wp-admin/post.php on line 233

Warning: Cannot modify header information - headers already sent by (output started at /Applications/MAMP/htdocs/sandbox/wp-content/plugins/media-meta-require/media-meta-require.php:193) in /Applications/MAMP/htdocs/sandbox/wp-includes/pluggable.php on line 1178

The error turns up no matter how I call the Error string. With a plain echo string:

function mmr_attachment_check( $new_status, $old_status, $post ) {
    if( $new_status === 'publish' ) {
        echo 'Error';
    }
}
add_action( 'transition_post_status', 'mmr_attachment_check', 10, 3 );

With an echo containing html elements:

function mmr_attachment_check( $new_status, $old_status, $post ) {
    if( $new_status === 'publish' ) {
        echo '<div class="error"><p>Error</p></div>';
    }
}
add_action( 'transition_post_status', 'mmr_attachment_check', 10, 3 );

or if i call an external function:

function mmr_attachment_check( $new_status, $old_status, $post ) {
    if( $new_status === 'publish' ) {
        mmr_admin_notice();
    }
}
add_action( 'transition_post_status', 'mmr_attachment_check', 10, 3 );

function mmr_admin_notice() {
    global $pagenow;
    if( $pagenow == 'post.php') {
        echo '<div class="error"><p>Error</p></div>';
    }
}

as soon as i comment out the echo related line it passes without an error. i’ve also consulted the wp troubleshooting document regarding that problem. But i can’t find any whitespaces or alikes which might cause that behaviour in my example. :/

Solutions Collecting From Web of "An echo line in a transition_post_status action leads to “cannot modify header information – headers already sent by”"

The error message you are seeing is normal for that operation. By the time the transition_post_status hook fires, the HTTP page headers is already sent. By simply echoing an error message inside a hook like transition_post_status which was never intended to echo any output to the browser, as you did, you are actually trying to insert your error message into this page headers, causing the error message to show up.

transition_post_status should be used to fire a hooked function on success or to performs a specific task, and not to echo output to the browser. The following is untested, but you can try something like this

add_action( 'transition_post_status', function ( $new_status, $old_status, $post ) {
    if( $new_status === 'publish' ) {
        add_action( 'admin_head', function () {
            echo 'To test if we get this message without headers already sent error message';
        }, PHP_INT_MAX );
    }, 10, 3 );