Skip to content

Commit d707208

Browse files
committed
fix: request handler output buffer handling
Previously, Acorn with the experimental request handler enabled broke WordPress static caching plugins like WP Rocket. This happened because the caching plugins work at a higher level than Acorn, but Acorn cleared all output buffers before the caching plugin could handle the contents. Fixes roots#406
1 parent 88096b5 commit d707208

File tree

1 file changed

+37
-19
lines changed

1 file changed

+37
-19
lines changed

src/Roots/Acorn/Application/Concerns/Bootable.php

+37-19
Original file line numberDiff line numberDiff line change
@@ -143,33 +143,37 @@ protected function enableHttpsInConsole(): void
143143
*/
144144
protected function registerWordPressRoute(): void
145145
{
146-
Route::any('{any?}', fn () => tap(response(''), function (Response $response) {
147-
foreach (headers_list() as $header) {
148-
[$header, $value] = preg_split("/:\s{0,1}/", $header, 2);
146+
Route::any('{any?}', fn (Request $request) => tap(
147+
response(''),
148+
function (Response $response) use ($request) {
149+
foreach (headers_list() as $header) {
150+
[$header, $value] = preg_split("/:\s{0,1}/", $header, 2);
149151

150-
if (! headers_sent()) {
151-
header_remove($header);
152-
}
152+
if (! headers_sent()) {
153+
header_remove($header);
154+
}
153155

154-
$response->header($header, $value, $header !== 'Set-Cookie');
155-
}
156+
$response->header($header, $value, $header !== 'Set-Cookie');
157+
}
156158

157-
if ($this->hasDebugModeEnabled()) {
158-
$response->header('X-Powered-By', $this->version());
159-
}
159+
if ($this->hasDebugModeEnabled()) {
160+
$response->header('X-Powered-By', $this->version());
161+
}
160162

161-
$response->setStatusCode(http_response_code());
163+
$response->setStatusCode(http_response_code());
162164

163-
$content = '';
165+
// Get the output buffer contents from our shutdown handler
166+
$content = $request->request->get('wp_ob_content');
164167

165-
$levels = ob_get_level();
168+
$levels = ob_get_level();
166169

167-
for ($i = 0; $i < $levels; $i++) {
168-
$content .= ob_get_clean();
169-
}
170+
for ($i = 0; $i < $levels; $i++) {
171+
$content .= ob_get_contents();
172+
}
170173

171-
$response->setContent($content);
172-
}))
174+
$response->setContent($content);
175+
})
176+
)
173177
->where('any', '.*')
174178
->name('wordpress');
175179
}
@@ -220,9 +224,23 @@ protected function registerRequestHandler(
220224

221225
$route->middleware('wordpress');
222226

227+
// We need to save our start level as there might be higher level output buffer handlers due to caching plugins.
228+
$startLevel = ob_get_level();
223229
ob_start();
224230

225231
remove_action('shutdown', 'wp_ob_end_flush_all', 1);
232+
add_action('shutdown', function () use ($request, $startLevel) {
233+
// Clean buffer only until our start level, keep possible higher level buffers to their handlers
234+
$levels = ob_get_level() - $startLevel;
235+
$content = '';
236+
237+
for ($i = 0; $i < $levels; $i++) {
238+
$content .= ob_get_clean();
239+
}
240+
241+
// Save content onto request to have it available in the Response handler
242+
$request->request->set('wp_ob_content', $content);
243+
}, 1);
226244
add_action('shutdown', fn () => $this->handleRequest($request), 100);
227245
}
228246

0 commit comments

Comments
 (0)