I have extended WooCommerce to create a custom endpoint. This endpoint, points to a template that has a form to save user meta data. When the form is submitted I want it to redirect to another URL. Until I added add_action( 'init', array($this, 'ob_function')); this was giving me a "headers already sent" error message. (ob_function simply contains ob_start).

My question is, should I be doing it this way? I've taken a look at some examples, have read up on it, etc but am unsure if this is bad practice (even though it works) as I guess that this is declaring ob_start every time init is loaded. I tried using conditional logic for the endpoint URL to restrict ob_start being declared when this destination was the URL but kept receiving the aforementioned 'headers already sent' error message.

  • No it's not, and it's not clear to me from your description why you'd even want to use ob_start() for what you're trying to do. I don't see how it's relevant? Are you just doing it because it made the error go away? That's not what it's for. Jul 2, 2019 at 5:43
  • 2
    The "headers already sent" error means that your code is generating some sort of output too early. ob_start() is for capturing output, so as a side effect you're preventing any output from happening too early, but you haven't actually solved the cause of why you were getting output. I suggest forgetting about ob_start() and updating your question with relevant code for this initial problem, so you can get help with that. Jul 2, 2019 at 5:45
  • @JacobPeattie I'm using ob_start() as WordPress already generates the output that I think you're referring to i.e. It generates its own headers which is why I'm getting headers already sent. The WooCommerce plugin does itself use something similar and I haven't included it for the sake of it.
    – NickC
    Jul 2, 2019 at 7:26
  • Why do you need to redirect after WordPress sends headers? Jul 2, 2019 at 7:36
  • @JacobPeattie It doesn't really matter to me if the headers are sent or not but that's the error I get in any case. Tom Macfarlin - Resolving wp_redirect is essentially what I'm trying to solve.
    – NickC
    Jul 2, 2019 at 10:35

2 Answers 2


My question is, should I be doing it this way?

Yes, but only if the other possible/better fixes do not work for you.

You can also read this article about troubleshooting common WordPress errors such as the "headers already sent" error.

And when developing a plugin/theme, I suggest you to turn on WordPress debugging because normally, you would be able to identify the source of an error by (simply) checking the error_log or wp-content/debug.log file for entries/lines relevant to the error. :)

And here's a working example as a reference when adding custom WooCommerce endpoint:

Here's the code which adds a /company-profile endpoint to the WooCommerce "My Account" endpoint; so you'd have example.com/my-account/company-profile, which simply displays a form with a field to set/update the user's company ID (registration number..), and upon successful update, the user is sent back to the "My Account" page.

And if you look at that code and try it with a default WordPress installation — with just WooCommerce as the only active plugin, you should see that there's no output being generated prior to performing the redirection.


From what I can tell opinion is divided on how to handle this (although Tom Macfarlin - a reputable and well respected WordPress contributor more or less suggests to do what I've used to solve this.

For good measure, I added ob_flush(); after ob_start(); as I couldn't sensibly see that I should start an output buffer and leave it in that state.

A concern I mentioned was that add_action( 'init', array($this, 'ob_function')); would call this every time init was loaded. In the end I added this to ob_function() so that it was only called when this endpoint was the URI and a $_POST variable was set:

public function ob_function(){

    // Start output buffer to solve headers already sent issue for company profile redirect when saved.

    if( 'https://' . $_SERVER['HTTP_HOST']. $_SERVER['REQUEST_URI']  == trailingslashit(get_site_url()) . 'recruiters/my-account/company-profile/' ){




  • Actually, after I re-read the question, I wondered how are you creating the endpoint? Because if you look at this (and try it out), you'd see that I'm not getting the "headers already sent" error.
    – Sally CJ
    Jul 3, 2019 at 2:09
  • Thank you @SallyCJ I've left it until now to reply as I'm yet to try this but I will do and come back to you. Looks good
    – NickC
    Jul 3, 2019 at 21:44
  • Thanks for trying the code and I'm glad it helped you! I've also posted an answer, and hopefully you don't mind the extra paragraphs at the top.. =)
    – Sally CJ
    Jul 5, 2019 at 0:49

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.