Learn how to run hooks after the body tag in WordPress using output buffering and shortcodes. This guide provides a simple solution for inserting custom content after the body tag.
Sometimes you need to run a bit of code the moment the page’s body opens: a tracking pixel, a skip-to-content link, an announcement bar, a consent banner. The catch is that the opening body tag lives in the theme, so a plugin can’t just print there.
Since WordPress 5.2 (2019), there’s a hook built for exactly this: wp_body_open. If your theme is reasonably current, reach for it first.
<?php
// Since WordPress 5.2, hook right after the opening body tag.
add_action( 'wp_body_open', function () {
echo do_shortcode( '[myshortcode text="WordPress"]' );
} );That’s the whole trick when the theme supports it. Themes opt in by calling wp_body_open() right after their <body> tag, and the function simply fires the wp_body_open action. Below are two older patterns worth knowing for the cases where that hook isn’t available.
The manual hook
Before wp_body_open existed, theme authors rolled their own action right after the body tag:
<?php
<body <?php body_class(); ?>>
<?php do_action('after_body'); ?>
</body>Anything hooked to after_body then runs in that spot. It works, but only if the theme actually prints that line, and every theme names its hook differently. wp_body_open is the standardized version of the same idea, which is why it’s the better default.
Automating it with output buffering
If you’re shipping a plugin and can’t count on the theme calling any hook, you can capture the whole page and splice your content in after the body tag with output buffering and a regular expression:
<?php
// Start output buffering at wp_head
function process_buffer_start() {
ob_start();
}
add_action( 'wp_head', 'process_buffer_start' );
// End output buffering at wp_footer and inject content after body
function process_buffer_end() {
// Retrieve the entire output buffer contents
$get_clean_buffer = ob_get_clean();
// Restart the output buffer
ob_start();
// Process the shortcode (in this case, a custom [myshortcode])
$process_shortcode = do_shortcode( '[myshortcode text="WordPress"]' );
// Use a regular expression to insert the shortcode content after the body tag
echo preg_replace( '<body.*>', '$0' . $process_shortcode, $get_clean_buffer );
// Flush the output buffer and send the output to the browser
ob_flush();
}
add_action( 'wp_footer', 'process_buffer_end' );
// Define a shortcode for demo purposes
function myshortcode_fallback( $atts ) {
// Set default attributes for the shortcode
$a = shortcode_atts( array(
'text' => ''
), $atts );
// Return the formatted content for the shortcode
return sprintf( '<div>I love %1$s</div>', esc_html( $a['text'] ) );
}
add_shortcode( 'myshortcode', 'myshortcode_fallback' );Honest caveat: this runs on every request, buffers the entire page, and rewrites it with a regex. That’s heavier and more fragile than a real hook. A minified or unusual body tag can slip past the pattern, and other buffering plugins can collide with it. Treat it as a last resort, for themes that don’t support wp_body_open and don’t expose a hook of their own.


