2

So, wp_localize_script() are awesome to add custom data to a script. And these data gets added to the HTML like:

<script id='woocommerce_some-js-extra' type="text/javascript">
var wc_some_params = {"key":"sdfsfsdfs","use_iframes":"1","images_dir":"https:\/\/dadadasdad.com\/wp-content\/plugins\/woocommerce-some-gateway\/assets\/images"};
</script>

This is all good. But the problem is that if I want to add an extra attribute to the script tag and instead of showing it like this:

<script id='woocommerce_some-js-extra' type="text/javascript">

if I want to show it like this:

<script id='woocommerce_some-js-extra' data-cfasync="false" type="text/javascript">

This is where I am facing the problem. I really see no way to add the extra data-cfasync="false" attribute to that inline script tag. Initially, I tried to use script_loader_tag filter but the problem is that when I am doing the following:

add_filter( 'script_loader_tag', function( $tag, $handle ) {
    if( $handle === 'woocommerce_somesubmit' ) {
    return str_replace( ' type', ' data-cfasync="false" type', $tag );
  } else {
    return $tag;
  }
}, 10, 2 );

It is pointing to the script added via wp_enqueue_script() and not pointing to the inline script added via wp_localize_script(). So, instead of adding that attribute to the inline script, it is adding the attribute to the script tag with src in it.

I was wondering if anyone knows any hooks or filter to add/modify the script tag added via wp_localize_script(). I searched a lot and even checked the WordPress core codes but still couldn't figure out a way for this. Also, there is no similar questions I have found for this issue. Any help will be highly appreciated.

Edit/Explanation: The answer mentioned here: How do I add custom attributes to javascript tags in Wordpress? does not apply to this question as that answer is showing how to add an extra attribute to script tags that are loading external scripts with src. But wp_localize_script() adds internal javascript and not points to any external javascript. The clean_url approach shown in the answer can also be done using script_loader_tag if you know the handle of the script.

But please note here we are looking for a way to add an extra attribute to internal scripts added via wp_localize_script() which doesn't have any src attribute to it.

2
  • Does this answer your question? How do I add custom attributes to javascript tags in Wordpress?
    – DevelJoe
    Sep 2, 2020 at 8:39
  • @DevelJoe unfortunately No. Cause in the clean_url hook it is looking for any script tag with certain src in it and then add a custom attribute it to. But the script tag added via localize script doesn't have any src in it. It is an internal script, not pointing to ay external script. The approach you have shown can be done using script_loader_tag as well but here we are looking at the internal scripts with no src in it.
    – iSaumya
    Sep 2, 2020 at 9:14

1 Answer 1

2

I also found that Cloudflare Rocket Loader would cause javascript errors in this situation. When the .js file was marked to be ignored, but the inline js was unable to be so marked, undefined errors would occur when the script tried to access the async-loaded inline data.

The approach detailed in How to intercept already localized scripts only allows you to change the data in the localized script tags. I.e:

var wc_some_params = {...}

It does not give you access to the outer <script></script> tags. To add the data-cfasync="false" attribute to the script tag I extended WP_Script and overloaded the print_extra_script() function in order to filter the full tag.

1. Create child class of WP_Script with the new filter

/**
* Extends WP_Scripts class to filter inline script tags added via wp_localize_script().
*/
class WP_Filterable_Scripts extends WP_Scripts {

    private $type_attr;

    /**
    * Executes the parent class constructor and initialization, then copies in the 
    * pre-existing $wp_scripts contents
    */
    public function __construct() {
        parent::__construct();

        if (
            function_exists( 'is_admin' ) && ! is_admin()
            &&
            function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'script' )
        ) {
            $this->type_attr = " type='text/javascript'";
        }

        /**
        * Copy the contents of existing $wp_scripts into the new one.
        * This is needed for numerous plug-ins that do not play nice.
        *
        * https://wordpress.stackexchange.com/a/284495/198117
        */
        if ( $GLOBALS['wp_scripts'] instanceof WP_Scripts ) {
            $missing_scripts = array_diff_key( $GLOBALS['wp_scripts']->registered, $this->registered );
            foreach ( $missing_scripts as $mscript ) {
                $this->registered[ $mscript->handle ] = $mscript;
            }
        }
    }

    /**
     * Adapted from wp-includes/class.wp-scripts.php and added the
     * filter `wp_filterable_script_extra_tag`
     *
     * @param string $handle
     * @param bool $echo
     *
     * @return bool|mixed|string|void
     */
    public function print_extra_script( $handle, $echo = true ) {
        $output = $this->get_data( $handle, 'data' );
        if ( ! $output ) {
            return;
        }

        if ( ! $echo ) {
            return $output;
        }

        $tag = sprintf( "<script%s id='%s-js-extra'>\n", $this->type_attr, esc_attr( $handle ) );

        /**
        * Filters the entire inline script tag.
        *
        * @param string $tag    <script type="text/javascript" id="plug-js-extra">...</script>
        * @param string $handle Script handle.
        */
        $tag = apply_filters( 'wp_filterable_script_extra_tag', $tag, $handle );

        // CDATA is not needed for HTML 5.
        if ( $this->type_attr ) {
            $tag .= "/* <![CDATA[ */\n";
        }

        $tag .= "$output\n";

        if ( $this->type_attr ) {
            $tag .= "/* ]]> */\n";
        }

        $tag .= "</script>\n";

        echo $tag;

        return true;
    }
}

2. Create new, filterable $wp_scripts object

The new WP_Filterable_Scripts class can be instantiated:

add_action( 'init', function () {
    $fscripts              = new WP_Filterable_Scripts;
    $GLOBALS['wp_scripts'] = $fscripts;
}, 100 );

3. Filter the tags to add data-cfasync attribute when needed

I wanted to keep a blacklist of handles to tag, so here's the use of an array of regexes. Any handle that matches will get the data-cfasync="false" tag inserted on the enqueued js file as well as the inline script.

function add_cfasync( $tag, $handle ) {
    $attr    = "data-cfasync='false' ";
    $filters = array(
        '/^hoverintent.*$/',
        '/^admin-bar$/',
        '/^jquery.*$/',
        '/.*event.*$/',
        '/^query-monitor$/',
        '/^wpmenucart-ajax-assist$/',
    );

    if ( ! is_admin() ) {
        foreach ( $filters as $exclude_regex ) {
            if ( preg_match( $exclude_regex, $handle ) != false ) {
                $tag = str_replace( '<script ', '<script ' . $attr, $tag );
            }
        }
    }

    return $tag;
}
add_filter( 'wp_filterable_script_extra_tag', 'add_cfasync', 0, 2 );
add_filter( 'script_loader_tag', 'add_cfasync', 0, 2 );

If you only wish to modify the wp_localize_script() inlines, remove the second add_filter line.

Blacklisting the necessary handles has resolved all my Rocket Loader errors in Wordpress.

Edit

I have subsequently found that filtering solely the wp_localize_script() inline scripts is sufficient to eliminate all Rocket Loader javascript errors on my Wordpress site.

add_filter( 'wp_filterable_script_extra_tag', 'add_cfasync', 0, 2 );

In my case Rocket Loader can handle all external js without error, as long as certain localized scripts have cfasync="false". YMMV.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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