Hi @eavonius, sure. I didn’t want to hijack the thread with a wordy explanation.
I haven’t reviewed the Acorn v4 codebase, so can’t point you to a commit / change that introduced this. However, the ob_start()
workaround works as follows:
A HTTP response looks like this on the wire:
HTTP/1.1 200 OK\n
Content-Length: 11\n
Content-Type: text/plain; charset=UTF-8\n
Some-Header: foo\n
Some-Other-Header: bar\n
\n
Hello World
A redirect requires a Location
HTTP header to be sent, along with a 30x
response code.
With no output buffering, headers are usually just transmitted straight to the browser (as there’s no benefit in holding them back). As soon as we start to write or echo any sort of response, the headers will have ‘left the building’.
class-wp-styles.php
has already started outputting a response, so by the time your component constructor runs and attempts to redirect it’s impossible to go back and modify the headers and response code.
Starting output buffering with ob_start()
early allows headers to be set but not sent over the socket to the browser. When we ob_start()
, we’re telling PHP not to write to the socket and transmit anything over the wire, but to write into a buffer. The buffer is then ‘flushed’ or sent either upon termination, or with a variant of the ob_flush()
functions.
With output buffering active multiple attempts at setting a header, even after a response has been echoed, will simply modify the header in the buffer. Once we finish execution, PHP flushes the buffer and sends to the web server, which sends to the client browser.
I used muplugins_loaded
as the early hook to start output buffering from. That may be too early. wp_loaded
might be a better shout.
Coming full circle and relating this back to Acorn - if v4 is in fact the culprit here (not FSE or Gutenberg or WP), then I suspect this issue stems from Acorn rendering views later on in execution than it did previously.
You hit on a really valid point.
You’re attempting to use a View (Component) to drive Controller logic. And the reason why you’re doing that makes total sense - you’re building a functional Gutenberg block which could be considered a Controller in it’s own right.
Out of the almost infinite number of approaches to this problem, I can see two stand-outs:
- Implement a Controller layer with a service provider (with WordPress query_vars, checking for form submission or another mechanism)
- Enabling output buffering as described above, giving you flexibility to put controller logic in a view.