post_content); } finally { $echoed = self::drain($level); $GLOBALS['post'] = $previousPost; foreach ($previousGlobals as $name => $value) { $GLOBALS[$name] = $value; } } return $echoed . $html; } /** * Pops every output buffer opened while rendering, including one a rogue shortcode/filter * left open (drained here instead of leaking into the caller) – but never one it already * closed for us: the loop only pops down to the level recorded before our own ob_start(), * so a filter that closes one buffer too many simply loses whatever was already echoed * (nothing left to drain) rather than us popping a buffer that belongs to the caller. * Buffers are combined in the order their content was written (innermost popped first, * then prepended) so a leaked nested buffer's output stays after what came before it. */ private static function drain(int $level): string { $output = ''; while (ob_get_level() > $level) { $output = (string) ob_get_clean() . $output; } return $output; } }