Title: Cannot modify header information warning
Last modified: April 20, 2025

---

# Cannot modify header information warning

 *  [adarkerforest](https://wordpress.org/support/users/jgdraper328/)
 * (@jgdraper328)
 * [1 year, 1 month ago](https://wordpress.org/support/topic/cannot-modify-header-information-warning-5/)
 * Hello!
 * I am a total amateur trying to learn PHP and WordPress to develop a plugin to
   search and edit user information from custom database tables. The way it works
   is a basic search field that sends a post request using the submitted email. 
   This email is searched and an ID is found and is supposed to be appended to the
   URL and go to a results page.
 * I had everything working great and then I started getting the following error
   when I try to redirect to the results page:
 * [20-Apr-2025 21:58:17 UTC] PHP Warning: Cannot modify header information – headers
   already sent by (output started at …public/wp-includes/fonts/class-wp-font-face.
   php:121) in …/public/wp-includes/pluggable.php on line 1450
   [20-Apr-2025 21:58:
   17 UTC] PHP Warning: Cannot modify header information – headers already sent 
   by (output started at …/public/wp-includes/fonts/class-wp-font-face.php:121) 
   in …./public/wp-includes/pluggable.php on line 1453
 * I did not touch wordpress core and even did a fresh install. Can someone let 
   me know if this code contains any of the errors that would cause this:
 *     ```wp-block-code
       function search_processing() {if( $_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['email'] )) {      $this->email = sanitize_email( $_POST['email'] );      $this->model = new Example_Class( $this->email );      $this->some_id = $this->model->get_some_id();      if (!empty( $this->some_id )) {            $results = add_query_arg(array(            'some_id' => $this->some_id             ));            wp_redirect( $results );            exit;        } else {                $this->error_email = sanitize_email( $_POST['email'] );                $this->error_message = 'No ID found for ' . $this->error_email .        '.';                 return;}}// If we have a some_id in GET parameters show resultsif ( !empty( $_GET['some_id'] ) ) {include __DIR__ . '/../views/results.php';exit;}}
       ```
   
    -  This topic was modified 1 year, 1 month ago by [adarkerforest](https://wordpress.org/support/users/jgdraper328/).

Viewing 2 replies - 1 through 2 (of 2 total)

 *  [Ahir Hemant](https://wordpress.org/support/users/hemant-ahir/)
 * (@hemant-ahir)
 * [1 year, 1 month ago](https://wordpress.org/support/topic/cannot-modify-header-information-warning-5/#post-18428101)
 * This means your script tried to send HTTP headers **after something was already
   output to the browser** — usually whitespace, HTML, or even a BOM character (
   Byte Order Mark).
 * Possible Triggers in Your Case:
 * Even if you didn’t touch WordPress core, this can happen if:
    - There’s **any whitespace or echo before the `wp_redirect()` call**.
    - An included file like `results.php` or your main plugin file has whitespace
      outside `<?php ... ?>`.
    - PHP files use **UTF-8 with BOM**, which sends output before headers.
 * **Use `ob_start()` at the beginning of your file** if needed to buffer output:
 *  [Aditya Singh](https://wordpress.org/support/users/iamadisingh/)
 * (@iamadisingh)
 * [1 year, 1 month ago](https://wordpress.org/support/topic/cannot-modify-header-information-warning-5/#post-18428754)
 * Hello [@jgdraper328](https://wordpress.org/support/users/jgdraper328/)
 * That “headers already sent” warning is a very common issue when working with 
   redirects in PHP and WordPress. Let’s break down what’s happening and how to 
   fix it.
 * **1. What the Error Means**
 * The error message: `PHP Warning: Cannot modify header information – headers already
   sent by (output started at …public/wp-includes/fonts/class-wp-font-face.php:121)
   in pluggable.php on line 1450`
    - **“Cannot modify header information”**: PHP needs to send HTTP headers (like
      the `Location:` header for a redirect) _before_ any actual content (HTML, 
      whitespace, etc.) is sent to the browser.
    - **“headers already sent by (output started at …)”**: This tells you exactly
      where the output began _before_ your redirect attempt. In your case, it’s 
      class-wp-font-face.php on line 121.
    - **“…in pluggable.php on line 1450”**: This is the line inside WordPress’s `
      wp_redirect` function where it tries (and fails) to send the `Location:` header
      because output already started.
 * **2. What’s Causing the Output?**
 * The file class-wp-font-face.php is part of WordPress core, specifically the Font
   Face API introduced in WP 6.4. Line 121 in that file is:
 *     ```wp-block-code
       // ...existing code...printf( $this->get_style_element(), $css );// ...existing code...
       ```
   
 * This line prints the `<style>` block containing `@font-face` rules into the HTML`
   <head>` of your page. This is normal WordPress behavior – it’s setting up fonts
   for your theme. You didn’t do anything wrong here, and you definitely shouldn’t
   modify this core file.
 * **3. Why is it a Problem for Your Code?**
 * Your `search_processing()` function attempts to call `wp_redirect()` _after_ 
   WordPress has already started building the HTML page and printed those font styles.
   Because output has already started, PHP cannot send the necessary `Location:`
   header for the redirect to work.
 * **4. How to Resolve This**
 * The key is to ensure your form processing and potential redirect happen _before_
   WordPress starts outputting any HTML. The standard WordPress way to handle this
   is by using an appropriate action hook.
    - **Hook Earlier:** Instead of running your `search_processing()` logic directly
      in a template file or a shortcode handler (which often run _after_ the headers
      have started), hook it into an action that fires earlier in the WordPress 
      request lifecycle.
       * **`template_redirect`**: This hook is specifically designed for actions
         like intercepting page requests, handling form submissions, and performing
         redirects _before_ the theme’s template file is loaded. This is usually
         the best hook for your scenario.
       * **`init`**: This hook runs even earlier, but `template_redirect` is generally
         preferred for this type of task as conditional tags (like `is_page()`) 
         are available.
    - **Separate Processing and Display:** Your `search_processing` function currently
      tries to do two things: process the POST request (and potentially redirect)
      _and_ display the results if a GET parameter is present. You should separate
      these:
       1. **Processing Function (hooked to `template_redirect`):** This function should
          _only_ check for the POST request (`$_SERVER['REQUEST_METHOD'] === 'POST'`).
          If it’s a POST request, it performs the lookup, and if an ID is found, it
          calls `wp_redirect()` and `exit;`. It does nothing if it’s not a POST request
          or if no ID is found.
       2. **Display Logic:** Let WordPress handle the display. After the redirect, 
          the browser will load the new URL (e.g., `your-page/?some_id=123`). You can
          then display the results on that page. How you display depends on your setup:
       3.  * If it’s a specific WordPress page, you can modify that page’s template
             to check for `$_GET['some_id']` and include your `results.php` view.
           * If you’re using a shortcode, the shortcode function can check for `$_GET['
             some_id']` and display the results.
 * **Example Implementation:**
 *     ```wp-block-code
       <?php// Assuming this code is in your plugin's main file or a class// Hook the processing function to template_redirectadd_action( 'template_redirect', 'my_plugin_handle_search_submission' );function my_plugin_handle_search_submission() {    // Only process if it's a POST request for your specific form    // (You might add a hidden field to your form to check here too)    if ( 'POST' === $_SERVER['REQUEST_METHOD'] && ! empty( $_POST['email'] ) ) {        // Use local variables instead of class properties if this is a standalone function        $email = sanitize_email( $_POST['email'] );        // Assuming Example_Class is available or loaded        $model = new Example_Class( $email );        $some_id = $model->get_some_id();        if ( ! empty( $some_id ) ) {            // Build the URL to redirect to.            // Replace 'your-results-page-slug' with the actual slug of your results page            $results_page_url = home_url( '/your-results-page-slug/' );            $redirect_url = add_query_arg( array( 'some_id' => $some_id ), $results_page_url );            // Perform the redirect and stop execution            wp_redirect( $redirect_url );            exit;        } else {            // Handle the "ID not found" case. You might want to redirect back            // to the search form with an error message query parameter.            $search_page_url = home_url( '/your-search-page-slug/' ); // Replace with your search page slug            $redirect_url = add_query_arg( array(                'search_error' => 'not_found',                'searched_email' => rawurlencode( $email ) // Pass the email back if needed            ), $search_page_url );            wp_redirect( $redirect_url );            exit;        }    }    // If it's not a POST request for this form, do nothing and let WordPress continue.}// --- In your results page template OR your shortcode function ---// Check if the ID is present in the URLif ( ! empty( $_GET['some_id'] ) ) {    $retrieved_id = absint( $_GET['some_id'] ); // Sanitize the ID    // Now you have $retrieved_id, you can fetch the data and display it    // Example:    // $data_to_display = get_data_by_some_id( $retrieved_id );    include __DIR__ . '/../views/results.php'; // Make sure $retrieved_id is available in this view} elseif ( ! empty( $_GET['search_error'] ) && 'not_found' === $_GET['search_error'] ) {    // Optionally display the error message on the search page itself    $error_email = ! empty( $_GET['searched_email'] ) ? sanitize_email( rawurldecode( $_GET['searched_email'] ) ) : '';    echo '<p class="error-message">No ID found for ' . esc_html( $error_email ) . '.</p>';}// Your regular search form HTML would go here or be part of the template/shortcode output?>
       ```
   
 * By hooking into `template_redirect`, you ensure your redirect logic runs before
   any HTML output, resolving the “headers already sent” error.

Viewing 2 replies - 1 through 2 (of 2 total)

The topic ‘Cannot modify header information warning’ is closed to new replies.

 * In: [Fixing WordPress](https://wordpress.org/support/forum/how-to-and-troubleshooting/)
 * 3 replies
 * 3 participants
 * Last reply from: [Aditya Singh](https://wordpress.org/support/users/iamadisingh/)
 * Last activity: [1 year, 1 month ago](https://wordpress.org/support/topic/cannot-modify-header-information-warning-5/#post-18428754)
 * Status: not resolved

## Topics

### Topics with no replies

### Non-support topics

### Resolved topics

### Unresolved topics

### All topics
