Book Now
Advanced Technical SEO

PHP BUFFER. MODIFYING HTML OUTPUT BEFORE SENDING

Introduction to PHP buffer and HTML output modification

PHP BUFFER. MODIFYING HTML OUTPUT BEFORE SENDING
Author:
Carlos Sánchez
Topics:
Metatags
,
Technologies
,
WPO
Publication Date:
2025-10-28

Last Review:
2025-10-28

PHP's output buffer is a technique that allows you to intercept and manipulate the HTML generated by the server before sending it to the browser. Normally PHP sends the HTML output to the client as it's being generated, but with the buffer we can tell PHP to temporarily store that output in memory instead of sending it immediately.
This way, the complete HTML is stored in an internal buffer and we can modify it however we want (for example, remove or alter parts of the code) before finally sending it to the user.

web 2.0
The change would be made on the server, before the HTML file that is sent to the user is generated.

In other words, the buffer captures, stores, and even allows us to modify all outputs (the echo statements and generated HTML) before they are sent to the browser. Something similar to the article where I show how to modify the DOM with JS, but more advanced.

This ability to post-process the HTML on the server (preprocess it before reaching the user) has very powerful and useful applications in technical SEO and WPO (web performance optimization).

Por ejemplo, podemos eliminar referencias a archivos CSS o JS innecesarios, reestructurar el marcado HTML, añadir etiquetas de precarga de recursos, o incluso insertar contenido pre-renderizado para los buscadores, independientemente de cómo se haya construido la página (ya sea código personalizado o constructores visuales como Elementor, Divi, etc.).

For example, we can remove references to unnecessary CSS or JS files, restructure the HTML markup, add resource preload tags, or even insert pre-rendered content for search engines, regardless of how the page was built (whether it's custom code or visual builders like Elementor, Divi, etc.).

Reduction of unnecessary CSS/JS/IMG/Video files

By removing superfluous files that aren't used on a page, we reduce the number of HTTP requests (which is less relevant anyway if we use HTTP/2 or higher) and the amount of data the browser has to download. This speeds up page load time and improves user experience.

Preloading and prioritization of critical resources

By inserting preload tags, deferred loads, or priority tags in the final HTML, we can tell the browser which resources it should load with higher priority.

This is difficult to achieve with JavaScript alone once the page has loaded, because although we can modify the DOM with JS, since the page has already loaded, even if we modify the priorities, this will no longer have any effect.
With the buffer, we can modify the section to include preloading of the main image, web fonts, or critical CSS.

Greater control of the website

With this it doesn't matter how the page is built, because using this technique we have absolute control over the resulting HTML for the user. With this we can fix the imperfections we find on a website or even those generated by certain plugins that don't allow us to achieve exactly what we need (anyone who has had to handle a navigation bar in PrestaShop knows what I'm talking about).

We can, for example, set conditionals by URL (a conditional with $_SERVER['REQUEST_URI'] and make certain resources load or not load on specific URLs (if we combine it with regex, the website is yours).
Below we'll see practical examples of how to use PHP's buffer in different environments (WordPress, "pure" PHP, and PrestaShop) to modify the HTML output.
Then we'll analyze the key benefits in SEO and performance, and compare this approach with the typical DOM manipulation using JavaScript on the client side.

How the code works in "Vanilla" PHP

I'm attaching the code and will now explain it (although I've left comments):

<?php
ob_start(); // Iniciar el buffer de salida
// (Generación normal de la página HTML)
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mi Sitio</title>
<!-- Hoja de estilos principal -->
<link rel="stylesheet" href="/css/estilos.css">
<script src="/js/galeria.js" defer></script>
</head>
<body>
<h1>Bienvenido a mi sitio</h1>
<!-- Contenido de la página -->
<p>Este es un ejemplo de página.</p>
</body>
</html>
<?php
// Obtener el contenido generado en el buffer
$html = ob_get_clean();
// Modificaciones en el HTML antes de enviarlo:
// Quitamos cualquier script a galeria.js que haya quedado en el HTML
$html = str_replace('<script src="/js/galeria.js" defer></script>', '', $html);
// 2. Agregar un comentario al pie del body con el tiempo de generación
$generado_en = '<!-- Página generada en '.date('Y-m-d H:i:s').' -->';
$html = str_replace('</body>', "$generado_en\n</body>", $html);
// Enviar el HTML final modificado al cliente
echo $html;
?>

We start the buffer at the beginning with the ob_start() function. All the HTML that is being created/generated (whether inside or outside PHP, like pure HTML sections) is retained in the buffer instead of being sent directly. At the end we use ob_get_clean() to get that HTML and simultaneously clean the buffer (meaning nothing is sent yet). Then we can manipulate the $html string as we wish.

In this basic example:

Finally, we do echo $html to send the already processed version to the browser. If we hadn't used the buffer, any echo or HTML text would have been sent immediately to the browser as it's generated. Thanks to the buffer, we have the complete page in the $html variable and we apply changes before delivering it.

This pattern can be expanded to do massive replacements, add or remove chunks of HTML, or even pass $html through some minification function before sending it (removing spaces, comments, etc. to reduce size). PHP even allows us to pass a callback function to ob_start() (as we saw in the WordPress example) to automate the filtering without needing to manually call ob_get_clean(); in the pure example, we opted for the "manual" way for greater clarity.

Not understanding this?
If you need help with the more technical aspects, book a consultancy session with me: Get real SEO help!

Modifying the final HTML in WordPress

In WordPress there is no native hook that gives us the final HTML of the entire page before sending it (beyond filtering parts like the_content).
However, we can achieve this by starting a buffer at the beginning of the load and applying changes before WordPress finishes rendering. A simple way is to activate the buffer when initializing the theme and release it at the end of execution.
For example, we could add in the functions.php file of our theme (or in a custom plugin as with the Asdrubal SEO methodology) something like the following:

// Iniciar el buffer de salida al arrancar el tema
function iniciar_buffer() {
ob_start(function ($buffer) {
// Ejemplo: eliminar un CSS innecesario agregado por un plugin (ej. Elementor)
$buffer = preg_replace('/<link[^>]*id=["\']elementor-frontend-css["\'][^>]*>.*?>/is', '', $buffer);
// Ejemplo: agregar precarga de una imagen destacada para mejorar LCP
$buffer = str_replace(
'</head>',
'<link rel="preload" href="/wp-content/uploads/2025/03/hero.jpg" as="image" />'."\n".'</head>',
$buffer
);
return $buffer; // devolver el HTML modificado
});
}
add_action('after_setup_theme', 'iniciar_buffer');
// Liberar el buffer al terminar la carga (envía el HTML modificado al cliente)
function finalizar_buffer() {
if (ob_get_level()) { // si hay un buffer activo
ob_end_flush(); // volcar el contenido del buffer y enviarlo
}
}
add_action('shutdown', 'finalizar_buffer');

There are many ways to do it, I'm just showing one of them.
You can always ask your favorite LLM for code based on this according to your needs.

In this code, we use ob_start() with a callback function that receives the $buffer (all the HTML of the page) and returns the modified version. We've included two examples within the callback:

The iniciar_buffer() function hooks into after_setup_theme (right after loading the theme, before printing headers) to ensure we capture all the HTML, including the page header. In fact, using this hook allows us to even include modifications in <head> and not just in the body. Then, with add_action('shutdown', 'finalizar_buffer'), we ensure that at the end of execution (WordPress's shutdown hook) the buffer is closed and the modified HTML is sent to the browser.

This way we can modify any part of the HTML generated by WordPress after it has been built, but before the user receives it. It doesn't matter if the page was built with Gutenberg, Elementor, a complex theme, etc. – we have the ability to post-process the HTML to our liking on the server.

Modifying anything in PrestaShop without dying in the attempt

If you give up on a CMS, the buffer is your friend, you just need to make a module (like a plugin in WordPress) and change it as you wish.
Important: if you make changes to the code, unlike with WordPress, you have to deactivate the module and activate it again.
Putting the hate aside, we'll use a specific hook for these cases: actionOutputHTMLBefore. This hook executes just before rendering the complete page in the Front Office, passing the complete HTML code so that modules can modify it. We can take advantage of it by creating a custom module that hooks into actionOutputHTMLBefore and alters the HTML.
Let's imagine a simple module called mimodulo, whose goal is to optimize the HTML output. The hook function structure would be like this:

// Archivo principal del módulo: mimodulo.php
class MiModulo extends Module {
public function __construct() {
$this->name = 'mimodulo';
// ... (otros datos del módulo, constructor estándar) ...
parent::__construct();
$this->displayName = 'Mi Módulo de Optimización';
$this->description = 'Optimiza la salida HTML eliminando recursos innecesarios.';
}D
public function install() {
return parent::install()
&& $this->registerHook('actionOutputHTMLBefore');
}D
// Hook que se ejecuta antes de la salida de HTML
public function hookActionOutputHTMLBefore($params) {
if (!isset($params['html'])) return;
// Referencia al HTML completo de la página
$html = &$params['html']; // se pasa por referencia
// 1. Eliminar un CSS innecesario (ejemplo: módulo de comentarios en páginas sin comentarios)
$html = str_replace(
'<link rel="stylesheet" href="/modules/comentarios/views/css/comentarios.css" type="text/css" media="all">',
'',
$html
);
// 2. Mover un bloque de script al final del <body> para no bloquear la carga inicial
$html = str_replace(
'<script src="/themes/mi-tema/js/mi-script.js"></script>',
'',
$html
);
$html = str_replace(
'</body>',
'<script src="/themes/mi-tema/js/mi-script.js" defer></script>'."\n".'</body>',
$html
);
// No sólo le he añadido el defer, sino que lo he desplazado a una de las partes más bajas de la web
// 3. Agregar precarga de fuente web crucial
$html = str_replace(
'<head>',
'<head><link rel="preload" href="/themes/mi-tema/fonts/mi-font.woff2" as="font" type="font/woff2" crossorigin>',
$html
);
// Y puedes seguir así hasta el infinito
}
}

Although it's very effective, I always recommend testing all implementations in A TEST ENVIRONMENT.

In this module, when installing it we register the actionOutputHTMLBefore hook. PrestaShop will call hookActionOutputHTMLBefore passing the complete HTML of the page in $params['html'], by reference (this means that if we modify it, those changes persist). Inside the function we see some example optimizations:

At the end of the function, PrestaShop will continue with its flow and send the already modified $html content to the browser. Thanks to this hook, we achieve a similar effect to PHP's buffer but taking advantage of PrestaShop's hooks system so we don't have to manually wrap the output. This approach is safe in PrestaShop because it's officially supported: PrestaShop's core executes Hook::exec('actionOutputHTMLBefore', ['html' => &$html]) in the FrontController just before printing the response.

Note: We can always resort to manually starting an ob_start() in a FrontController override if it doesn't work for us. In fact we'll have to do that in older versions of Presta.

PS: If you're interested in seeing how it's done in other specific systems like Laravel with Middleware, you can always contact me and I can write an article about that particular type of implementation.

If you like this article, you would help me a lot by sharing my content:
Interested in Advanced SEO Training?

I currently offer advanced SEO training in Spanish. Would you like me to create an English version? Let me know!

Tell me you're interested
You might be interested in other articles:
SEO Articles
Usamos cookies para asegurar que te damos la mejor experiencia en nuestra web. Aquí tienes nuestra política de Cookies.