3

I'm currently writing a plugin in which users can select whether they want to insert a google analytics tag or a GTM tag (Google tag manager). I've already figured out how to insert the code after the tag.

At the moment the code gets inserted through a custom function in my theme's function.php and calling the function in the themes header.php

Header.php

<?php wp_after_body();?>

Functions.php

function wp_after_body() {
do_action('wp_after_body');
}

But I was wondering if there is a solution in which I can just use my plugin file to insert the code after the tag (So I don't have to change the theme files everytime I use the plugin).

I've already tried this:

https://stackoverflow.com/a/27309880/7634982

3 Answers 3

2

Since you want your plugin to be theme independent you will have to rely on hooks that you may assume are there in any decently made theme. At the moment you can only rely on wp_head and wp_footer. A hook right after the <body> tag is under discussion, but even if it would be declared standard today, there would still be thousands of existing themes not implementing it. So that's no use for you.

The option you tried just buffers most of the page, letting you change the buffer's content before it is printed. It should work, though it is far from elegant and could easily interfere with other plugins using some kind of buffering.

So, no, there is no direct WordPressy way to do this in a reliable way. What you could do in a plugin, however, is solve it with json. The idea is fairly simple, though it will require some work (and probably a learning curve).

Hooking into wp_head add a jquery script file that adds a DOM-element right after the <body> tag and use the rest api to call the function that you would normally generate the code that you want in that place.

2
  • I'd like to know more about this approach. Do you have any idea where i would start looking? Commented Oct 30, 2018 at 11:15
  • The jquery part is fairly standard. For the other part I'd ask google for a "custom endpoints tutorial"
    – cjbj
    Commented Oct 30, 2018 at 12:23
4

As of WordPress 5.2 (May 2019) this is officially supported

Compatibility: WordPress 5.2+ usage as of Jan 2021 is at 76% according to WordPress Stats.

How to use: Comprehensive WordPress blog post explaining wp_body_open functionality at https://make.wordpress.org/core/2019/04/24/miscellaneous-developer-updates-in-5-2/

TL;DR

Snippet Usage

<?php add_action( 'wp_body_open', function () { ?>

<!-- Your HTML code here -->

<?php } ); ?>

Theme Usage

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

Theme Usage with Backwards-Compatibility

<body <?php body_class(); ?>>
<?php 
if ( function_exists( 'wp_body_open' ) ) {
    wp_body_open();
} else {
    do_action( 'wp_body_open' );
}
1

I am afraid this is not possible at the moment. This is completely on the Theme territory, and you would always depend on the Theme code.

BUT!! There is a simple hack you can use, for a not complicated code insertion. I say it is a hack, and you will see why.

The only thing you can count on that will exist in 99.99% of the Themes is <body <?php body_class(); ?>>. So we can use a filter hook to add another 'class' to the body tag, except... it won't be a class. Look at this code:

add_filter( 'body_class', function ( $classes ) {
    return array_merge( 
        $classes, 
        array( '">
            <iframe src="//www.googletagmanager.com/ns.html?id=XXX-XXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe>
            <input type="hidden' // Important to handle the closing of the body element
        ) 
    );
} );

What have we done here? We have first added "> to close the body element. Then you can insert whatever HTML you want. The last part is also mandatory, to handle the actual closing of the body element, we need to create something that won't break our template, so a hidden input field should work well. We add <input type="hidden, but without closing with "> because the body_class() function will do it for us.

Note that there is a possibility this would collide with some other filters on body_class, depending on the priority. To handle this, you could wrap this into another action hook that will fire after the theme is loaded, for instance get_header. In that case, the full code would be:

add_action( 'get_header', function() {
    add_filter( 'body_class', function ( $classes ) {
        return array_merge(
            $classes,
            array( '">
            <iframe src="//www.googletagmanager.com/ns.html?id=XXX-XXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe>
            <input type="hidden' // Important to handle the closing of the body element
            ) );
    } );
});

Even though this possibly does what you want, I can't really recommend this.

2
  • 2
    If there's anything else on the body-tag after the filter call, like a style or aria-label, this solution may break the site.
    – cjbj
    Commented Oct 30, 2018 at 9:47
  • 1
    This worked for me, Cheers mate. Commented Oct 30, 2018 at 14:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.