1

I've run into a headers already send problem while adding functionality to one of my plugins. I wish to send my 301 redirect header after some checks to deteremine if the contents of the page is obsolete. I have a wordpress page that contains just the shortcode [shortcode]. Then in my plugin I hook into init to register my shortcode using the following snippet of code

function __construct()
{
    //register an activation hook for the plugin
    register_activation_hook(__FILE__, array(
        &$this,
        'install_bnw'
    ));
    //Hook up to the init action
    add_action('init', array(
        &$this,
        'start_session'
    ), 1);
    add_action('init', array(
        &$this,
        'class_loader'
    ));
    add_action('init', array(
        &$this,
        'init_bnw'
    ));
    add_filter('wpseo_canonical', array(
        &$this,
        'wpseo_canonical'
    ));
}


/**
 * Runs when the plugin is activated
 */
function install_bnw()
// TODO: Add check if the *** plugin is currently activated and if it can be reached from this plugin.
{

    // do not generate any output here
}

/**
 * Starts a session before any output is generated.
 * TODO: Might not be the most efficient way to handle sessions, needs improvement.
 */
public function start_session()
{
    if (!session_id()) {
        session_start();
    }

}

/**
 * Runs when the plugin is initialized.
 * Adds filters to wordpress functions and calls functions that need to be executed.
 */
function init_bnw()
{     // Adds all the shortcodes that need to be added.
    $this->add_shortcodes();
  // -- Some more code -- 
}

/**
 * Autoloader that uses template_autoloader to load class files from a predetermined location.
 */
function class_loader()
{
    // register an autoloader function for template classes
    spl_autoload_register(array(
        &$this,
        'template_autoloader'
    ));
}


/**
 * Used by the class_loader function to load classes from files but only if the files exist to ensure this plugin works with other plugins.
 * @param $class
 * @return bool that tells if the include worked.
 * @throws Exception
 *
 */
function template_autoloader($class)
{
    $classPath = "includes/$class.php";
    // Checks if the file exists for compatibility with other plugins using the spl_autoload functionality.
    if (file_exists(__DIR__ . '/' . $classPath)) {
        include_once $classPath;
        return true;
    } else {
        return false;
    }

}



/**
     * Contains all the shortcodes that need to be added to wordpress in order for this plugin to function.
     */
    private function add_shortcodes()
    {
       // Add all the shortcodes that need to be added here.
     // --Some shortcodes here --
    add_shortcode('shortcode', array(
            &$this,
            'shortcodeDesinationFunction'
        ));
       // -- More shortcodes --        
    }

The function shortcodeDestinationFunction loads a class, with an empty constructor and then calls the following function:

function showTraining()
{
    // -- Do some data getting and business logic here but no outputting --
    // If training is in the past
    if($startdate < $currentdate)
    {
// -- Some more data getting function that don't output anthing
        $newLocation = "/text/text/$subjectLabel/$trainingLevel";
        // Disable caching for testing
         header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
         header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // past date to encourage expiring immediately
        header ('HTTP/1.1 301 Moved Permanently');
        header ('Location:'.$newLocation); 
    }
 // Some more code

As you can see I want the page that has this shortcode to be able to send a 301 redirect when a certain condition applies.

When I run the code I get the following error's (from the blackbox wordpress plugin):

Warning Cannot modify header information - headers already sent by (output started at /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-includes/class.wp-styles.php:122) on line 183 in file /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-content/plugins/BNWPweb/includes/examenTraining.php
Warning Cannot modify header information - headers already sent by (output started at /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-includes/class.wp-styles.php:122) on line 184 in file /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-content/plugins/BNWPweb/includes/examenTraining.php
Warning Cannot modify header information - headers already sent by (output started at /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-includes/class.wp-styles.php:122) on line 186 in file /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-content/plugins/BNWPweb/includes/examenTraining.php
Warning Cannot modify header information - headers already sent by (output started at /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-includes/class.wp-styles.php:122) on line 187 in file /var/www/vhosts/bndev.int.bijlesnetwerk.nl/httpdocs/wp-content/plugins/BNWPweb/includes/examenTraining.php 

Line 183 is the first header statement, and the line referenced from the wordpress core file contains the following:

} else {
            echo $tag;
            $this->print_inline_style( $handle );
        }

Now my question is, how do I send a header via a plugin shortcode without getting the headers already send warning?

I have already googled quite a bit and I have read some stackexchange answer but none seem applicable, I don't think it's a problem with a random whitespace or one of my plugins outputting something that it isn't supposed to. I have also read Wordpress FAQ about headers already sent to no avail.

4
  • Where is showTraining () hooked? It seems before redirecting something got printed from /wp-includes/class.wp-styles.php:122 Did you try to hook the showTraining () function with 'template_redirect' hook? Commented Oct 21, 2014 at 15:27
  • @Ashok showTraining() is a function of an class that is called by the function shortcodeDesinationFunction() which in turn hooks into init. Is template_redirect called before init? Commented Oct 21, 2014 at 16:08
  • Yes, in this case it needs to be hooked with template_redirect. Also, you should use wp_redirect(): codex.wordpress.org/Function_Reference/wp_redirect Commented Oct 21, 2014 at 16:45
  • @Ashok the 'template_redirect' was indeed the answer. Would you like to submit your comment as an answer or should I answer it myself? Commented Nov 3, 2014 at 18:19

1 Answer 1

1

You can't add headers after content has already been sent to the browser. If you try, you will get those "Warning Cannot modify header information - headers already sent by... " messages.

Shortcodes execute inside the the_content filter, and that filter runs well into a page load. That means that content has long since been sent to the browser by the time you try to add headers. To make this work with a shortcode you'd need to do something like what is done here, but honestly, I'd recommend not using a shortcode. That isn't the right tool for altering early page load content.

I can't tell exactly what you are doing, but my gut feeling is that a custom meta field would be a better choice.

2
  • If header functions work in that filter there is something else going on-- maybe output buffering. It should not work in a stock install.
    – s_ha_dum
    Commented Nov 3, 2014 at 17:41
  • i'm sorry I made a mistake I meant to quote the filter that @Ashok provided in his comment. That leaves me with a problem. Your answer put me on the right track but didn't offer the solution directly, Ashok comment was the answer. Commented Nov 3, 2014 at 18:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.