最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

child theme - wp_add_inline_script not adding when script_loader_tag filtered

programmeradmin0浏览0评论

I'm trying to add the new GA4 code to an existing site, and there seems to be some conflict / ordering issue between script_loader_tag filters and wp_add_inline_script. My functions.php looks thusly:

...
// Enqueue scripts
function cwr_enqueue_scripts() {
        wp_enqueue_script('cwr-google-analytics', get_stylesheet_directory_uri()
            . '/js/ga.js', array(), '1.0.3');
        wp_add_inline_script('cwr-google-analytics', "ga('create', "
            . "'" . CWR_GAUA_ID . "', 'auto');ga('send', 'pageview');");


        wp_enqueue_script('cwr-google-gtag', ";
            . "/gtag/js?id=" . CWR_GA4_ID, array(), null);
        wp_add_inline_script('cwr-google-gtag', "window.dataLayer = "
            . "window.dataLayer || [];"
            . "function gtag(){dataLayer.push(arguments);} gtag('js',"
            . "new Date()); gtag('config', '" . CWR_GA4_ID . "');");
}
add_action('wp_enqueue_scripts', 'cwr_enqueue_scripts');

add_filter('script_loader_tag', 'cwr_gtag_async', 10, 3); // problem causer
function cwr_gtag_async($tag, $handle, $src) {
        if ($handle === 'cwr-google-gtag') {
                $tag = '<script type="text/javascript" id="cwr-google-gtag-js"'
                    . 'src="' . esc_url($src) . '" async></script>';
        }

        return $tag;
}
?>

As is, it outputs three lines, and never adds the "after" script to cwr-google-gtag:

...
<script type="text/javascript" id="cwr-google-gtag-js" src="=<my_id>" async></script>
<script type="text/javascript" src=".js?ver=1.0.3" id="cwr-google-analytics-js"></script>
<script type="text/javascript" id="cwr-google-analytics-js-after">
ga('create', '<my_id>', 'auto');ga('send', 'pageview');
</script>
...

If I comment out the script_loader_tag filter, then I get my extra code added, but obviously lose the async attribute:

...
<script type="text/javascript" src=".js?ver=1.0.3" id="cwr-google-analytics-js"></script>
<script type="text/javascript" id="cwr-google-analytics-js-after">
ga('create', '<my_id>', 'auto');ga('send', 'pageview');
</script>
<script type="text/javascript" src="; id="cwr-google-gtag-js"></script>
<script type="text/javascript" id="cwr-google-gtag-js-after">
window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);} gtag('js',new Date()); gtag('config', '<my_id>');
</script>
...

Any ideas what's wrong here? Or, is there a better canonical way to get this to work?

I'm trying to add the new GA4 code to an existing site, and there seems to be some conflict / ordering issue between script_loader_tag filters and wp_add_inline_script. My functions.php looks thusly:

...
// Enqueue scripts
function cwr_enqueue_scripts() {
        wp_enqueue_script('cwr-google-analytics', get_stylesheet_directory_uri()
            . '/js/ga.js', array(), '1.0.3');
        wp_add_inline_script('cwr-google-analytics', "ga('create', "
            . "'" . CWR_GAUA_ID . "', 'auto');ga('send', 'pageview');");


        wp_enqueue_script('cwr-google-gtag', "https://www.googletagmanager"
            . "/gtag/js?id=" . CWR_GA4_ID, array(), null);
        wp_add_inline_script('cwr-google-gtag', "window.dataLayer = "
            . "window.dataLayer || [];"
            . "function gtag(){dataLayer.push(arguments);} gtag('js',"
            . "new Date()); gtag('config', '" . CWR_GA4_ID . "');");
}
add_action('wp_enqueue_scripts', 'cwr_enqueue_scripts');

add_filter('script_loader_tag', 'cwr_gtag_async', 10, 3); // problem causer
function cwr_gtag_async($tag, $handle, $src) {
        if ($handle === 'cwr-google-gtag') {
                $tag = '<script type="text/javascript" id="cwr-google-gtag-js"'
                    . 'src="' . esc_url($src) . '" async></script>';
        }

        return $tag;
}
?>

As is, it outputs three lines, and never adds the "after" script to cwr-google-gtag:

...
<script type="text/javascript" id="cwr-google-gtag-js" src="https://www.googletagmanager/gtag/js?id=<my_id>" async></script>
<script type="text/javascript" src="https://www.example/wp-content/themes/vantage-child/js/ga.js?ver=1.0.3" id="cwr-google-analytics-js"></script>
<script type="text/javascript" id="cwr-google-analytics-js-after">
ga('create', '<my_id>', 'auto');ga('send', 'pageview');
</script>
...

If I comment out the script_loader_tag filter, then I get my extra code added, but obviously lose the async attribute:

...
<script type="text/javascript" src="https://www.example/wp-content/themes/vantage-child/js/ga.js?ver=1.0.3" id="cwr-google-analytics-js"></script>
<script type="text/javascript" id="cwr-google-analytics-js-after">
ga('create', '<my_id>', 'auto');ga('send', 'pageview');
</script>
<script type="text/javascript" src="https://www.googletagmanager/gtag/js?id=G-GCBJ73QR90" id="cwr-google-gtag-js"></script>
<script type="text/javascript" id="cwr-google-gtag-js-after">
window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);} gtag('js',new Date()); gtag('config', '<my_id>');
</script>
...

Any ideas what's wrong here? Or, is there a better canonical way to get this to work?

Share Improve this question asked Jan 6, 2021 at 8:39 philolegeinphilolegein 2832 silver badges12 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 3

The reason this is happening is because the markup that is filtered by script_loader_tag includes the inline scripts. So when you filter it and replace all the HTML tag for a particular script, your filter is removing those inline script tags. If you print out the original value of $tag from within your filter you will see this.

You can look at the source of WP_Scripts::do_item() to see how the inline scripts are prepended and appended. With your approach you would need to replicate all that logic. The better approach is to just use str_replace to replace part of the script tag with an amended part, like this:

if ( $handle === 'cwr-google-gtag' ) {
    $tag = str_replace(
        'id="cwr-google-gtag-js"',
        'id="cwr-google-gtag-js" async',
        $tag
    );

    return $tag;
}

That will add async after the correct script tag's ID attribute.

All that being said, your approach is not going to work. If ga.js is loaded asynchronously, then the subsequent inline script tag is going to run before ga.js has loaded, which will cause an error because ga() has not been defined by the time this runs:

ga('create', '<my_id>', 'auto');ga('send', 'pageview');

See this example from Google's documentation for loading Google Analytics asynchronously:

<!-- Google Analytics -->
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics/analytics.js'></script>
<!-- End Google Analytics -->

For this to work you need an inline script before the analytics script is loaded, and that script needs to include a line that defines ga() if it has not been defined yet.

Lastly, you should not be hosting Google Analytics in your theme. As advised by Google:

While it's possible to download the JavaScript file (gtag.js) to examine it, storing or serving the JavaScript file locally is not recommended.

Referencing the JavaScript file from Google's servers (i.e., https://www.googletagmanager/gtag/js) ensures that you get access to new features and product updates as they become available, giving you the most accurate data in your reports.

You should consult Google's documentation to make sure Google Tag Manager doesn't also need to be loaded a particular way, when adding it asynchronously.

发布评论

评论列表(0)

  1. 暂无评论