diff --git a/readme.txt b/readme.txt index 3bfb48f5..aba8f460 100644 --- a/readme.txt +++ b/readme.txt @@ -91,6 +91,7 @@ Yes! Pagespeed is one of our main focus points, and we strive to make the plugin = 1.X = Enhancements: +* Inline scripts are now registered with the wp_add_inline_script insted of wp_head. This allows easy extension GTM Kit and implementation of a CSP (Content Security Policy). Bugfixes: * The product ID Prefix was not added when a product variation was selected. diff --git a/src/Common/Util.php b/src/Common/Util.php index 20801865..17206845 100644 --- a/src/Common/Util.php +++ b/src/Common/Util.php @@ -224,7 +224,8 @@ public function enqueue_script( string $handle, string $script ): void { $dependency = $deps_file['dependencies']; $version = $deps_file['version']; } + $dependency[] = 'gtmkit'; - \wp_enqueue_script( $handle, GTMKIT_URL . 'assets/' . $script . '.js', $dependency, $version, true ); + \wp_enqueue_script( $handle, GTMKIT_URL . 'assets/' . $script . '.js', $dependency, $version, [ 'strategy' => 'defer' ] ); } } diff --git a/src/Frontend/Frontend.php b/src/Frontend/Frontend.php index f5f0f7d8..b73ba472 100644 --- a/src/Frontend/Frontend.php +++ b/src/Frontend/Frontend.php @@ -45,108 +45,85 @@ public function __construct( Options $options ) { */ public static function register( Options $options ): void { $page = new Frontend( $options ); + $container_active = Options::init()->get( 'general', 'container_active' ); + $noscript_implementation = Options::init()->get( 'general', 'noscript_implementation' ); if ( empty( $options->get( 'general', 'just_the_container' ) ) ) { - add_action( 'wp_head', [ $page, 'get_header_datalayer' ], 1, 0 ); - add_action( 'wp_head', [ $page, 'get_datalayer_content' ] ); + add_action( 'wp_enqueue_scripts', [ $page, 'enqueue_settings_and_data_script' ], 1, 0 ); + add_action( 'wp_enqueue_scripts', [ $page, 'enqueue_datalayer_content' ] ); } - $container_active = Options::init()->get( 'general', 'container_active' ); - if ( $container_active ) { - add_action( 'wp_head', [ $page, 'get_header_script' ], 10, 0 ); + add_action( 'wp_enqueue_scripts', [ $page, 'enqueue_header_script' ] ); } elseif ( Options::init()->get( 'general', 'console_log' ) ) { add_action( 'wp_head', [ $page, 'container_disabled' ] ); } - add_filter( 'wp_resource_hints', [ $page, 'dns_prefetch' ], 10, 2 ); - add_filter( 'rocket_excluded_inline_js_content', [ $page, 'wp_rocket_exclude_javascript' ] ); - - $noscript_implementation = Options::init()->get( 'general', 'noscript_implementation' ); - if ( $noscript_implementation === '0' && $container_active ) { add_action( 'wp_body_open', [ $page, 'get_body_script' ] ); } elseif ( $noscript_implementation === '1' && $container_active ) { add_action( 'body_footer', [ $page, 'get_body_script' ] ); } + + add_filter( 'wp_resource_hints', [ $page, 'dns_prefetch' ], 10, 2 ); + add_filter( 'rocket_excluded_inline_js_content', [ $page, 'wp_rocket_exclude_javascript' ] ); + add_filter( 'wp_inline_script_attributes', [ $page, 'set_inline_script_attributes' ], 10, 2 ); } /** - * The dataLayer initialization and settings + * The inline script for settings and data use by other GTM Kit scripts. */ - public function get_header_datalayer(): void { + public function enqueue_settings_and_data_script(): void { $settings = [ 'datalayer_name' => $this->datalayer_name, 'console_log' => Options::init()->get( 'general', 'console_log' ), ]; - ?> - - + ob_start(); + ?> + window.gtmkit_settings = ; + window.gtmkit_data = ; + options->get( 'general', 'gcm_default_settings' ) ) : ?> + if (typeof gtag === "undefined") { + function gtag(){datalayer_name ); ?>.push(arguments);} + gtag('consent', 'default', { + 'ad_storage': 'options->get( 'general', 'gcm_ad_storage' ) ) ? 'granted' : 'denied'; ?>', + 'analytics_storage': 'options->get( 'general', 'gcm_analytics_storage' ) ) ? 'granted' : 'denied'; ?>', + 'personalization_storage': 'options->get( 'general', 'gcm_personalization_storage' ) ) ? 'granted' : 'denied'; ?>', + 'functionality_storage': 'options->get( 'general', 'gcm_functionality_storage' ) ) ? 'granted' : 'denied'; ?>', + 'security_storage': 'options->get( 'general', 'gcm_security_storage' ) ) ? 'granted' : 'denied'; ?>', + }); + } else if ( window.gtmkit_settings.console_log === 'on' ) { + console.warn('GTM Kit: gtag is already defined') + } 'false', - 'data-nowprocket' => '', - 'data-cookieconsent' => 'ignore', - ] - ); - - foreach ( $attributes as $attribute => $value ) { - echo ' ' . esc_attr( $attribute ) . '="' . esc_attr( $value ) . '"'; - } + wp_register_script( 'gtmkit', '', [], GTMKIT_VERSION, [ 'in_footer' => false ] ); + wp_enqueue_script( 'gtmkit' ); + wp_add_inline_script( 'gtmkit', $script, 'before' ); } /** * The dataLayer content included before the GTM container script */ - public function get_datalayer_content(): void { - ?> - - \n"; + wp_register_script( 'gtmkit-datalayer', '', [], GTMKIT_VERSION, [ 'in_footer' => false ] ); + wp_enqueue_script( 'gtmkit-datalayer' ); + wp_add_inline_script( 'gtmkit-datalayer', $script, 'before' ); } /** * The Google Tag Manager container script */ - public function get_header_script(): void { + public function enqueue_header_script(): void { $gtm_id = Options::init()->get( 'general', 'gtm_id' ); @@ -155,10 +132,8 @@ public function get_header_script(): void { } $script_implementation = (int) Options::init()->get( 'general', 'script_implementation' ); - ?> - - \n\n"; + $script = ob_get_clean(); + + wp_register_script( 'gtmkit-container', '', [ 'gtmkit-datalayer' ], GTMKIT_VERSION, [ 'in_footer' => false ] ); + wp_enqueue_script( 'gtmkit-container' ); + wp_add_inline_script( 'gtmkit-container', $script ); } /** @@ -195,11 +174,40 @@ public function get_gtm_script( string $gtm_id ): void { $domain = Options::init()->get( 'general', 'sgtm_domain' ) ? Options::init()->get( 'general', 'sgtm_domain' ) : 'www.googletagmanager.com'; $loader = Options::init()->get( 'general', 'sgtm_container_identifier' ) ? Options::init()->get( 'general', 'sgtm_container_identifier' ) : 'gtm'; - echo "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': - new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], - j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= - 'https://" . esc_attr( $domain ) . '/' . esc_attr( $loader ) . ".js?id='+i+dl;f.parentNode.insertBefore(j,f); - })(window,document,'script','" . esc_js( $this->datalayer_name ) . "','" . esc_attr( $gtm_id ) . "');"; + echo "/* Google Tag Manager */\n"; + echo "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':\n"; + echo "new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],\n"; + echo "j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=\n"; + echo "'https://" . esc_attr( $domain ) . '/' . esc_attr( $loader ) . ".js?id='+i+dl;f.parentNode.insertBefore(j,f);\n"; + echo "})(window,document,'script','" . esc_js( $this->datalayer_name ) . "','" . esc_attr( $gtm_id ) . "');\n"; + echo "/* End Google Tag Manager */\n"; + } + + /** + * Set inline script attributes + * + * @param array $attributes The script attributes. + * @param string $script The script. + * + * @return array The script attributes. + */ + public function set_inline_script_attributes( array $attributes, string $script ): array { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed + if ( isset( $attributes['id'] ) && strpos( $attributes['id'], 'gtmkit-' ) === 0 ) { + $script_attributes = apply_filters( + 'gtmkit_header_script_attributes', + [ + 'data-cfasync' => 'false', + 'data-nowprocket' => '', + 'data-cookieconsent' => 'ignore', + ] + ); + + foreach ( $script_attributes as $attribute_name => $value ) { + $attributes[$attribute_name] = $value; + } + } + + return $attributes; } /** diff --git a/src/Integration/ContactForm7.php b/src/Integration/ContactForm7.php index 1c16b8d6..e4194cb1 100644 --- a/src/Integration/ContactForm7.php +++ b/src/Integration/ContactForm7.php @@ -62,7 +62,7 @@ public function enqueue_scripts(): void { wp_enqueue_script( 'gtmkit-cf7', GTMKIT_URL . 'assets/integration/contact-form-7.js', - [], + [ 'gtmkit' ], $this->util->get_plugin_version(), true ); diff --git a/src/Integration/EasyDigitalDownloads.php b/src/Integration/EasyDigitalDownloads.php index 539b3c32..1221ca5c 100644 --- a/src/Integration/EasyDigitalDownloads.php +++ b/src/Integration/EasyDigitalDownloads.php @@ -84,7 +84,7 @@ public function enqueue_scripts(): void { wp_enqueue_script( 'gtmkit-edd', GTMKIT_URL . 'assets/integration/edd.js', - [ 'jquery' ], + [ 'gtmkit', 'jquery' ], $this->util->get_plugin_version(), true ); diff --git a/src/Integration/WooCommerce.php b/src/Integration/WooCommerce.php index 61d9026c..169e9460 100644 --- a/src/Integration/WooCommerce.php +++ b/src/Integration/WooCommerce.php @@ -194,7 +194,7 @@ public function enqueue_scripts(): void { wp_enqueue_script( 'gtmkit-woocommerce', GTMKIT_URL . 'assets/integration/woocommerce.js', - [], + [ 'gtmkit' ], $this->util->get_plugin_version(), true );