DuracellTomi's Google Tag Manager for WordPress - Version 1.15

Version Description

  • Added: pagePostType data layer variable will now return 404-error on 404 pages and search-results on search result pages
  • Added: Google Tag Manager container code can be disabled for specific WordPress user roles under Advanced plugin options. A browser console warning will be shown in such cases to prevent confusion
  • Added: support for all Contact Form 7 events for more granual tracking: gtm4wp.contactForm7MailSent, gtm4wp.contactForm7MailFailed, gtm4wp.contactForm7SpamDetected, gtm4wp.contactForm7InvalidInput
  • Added: additional data layer variables for date attributes: pagePostDateDayName, pagePostDateHour, pagePostDateMinute, pagePostDateIso, pagePostDateUnix - by ajtatum
  • Fixed: unclickable products in WooCommerce product lists in Firefox when visiting site in Strict privacy mode or using private browsing
  • Fixed: tracking step 2 on WooCommerce checkout page was broken
  • Updated: removed CDATA blocks as they are not required in simple HTML and they break some cases where code optimizer is being used
  • Updated: products per impression in WooCommerce integration now defaults to 10 instead of 0. This allows view_item_list event to fire on new sites as well
  • Updated: code placement options. Separated container on/off option and replaced code placement with the new terminology: compatibility mode
  • Updated: removed optional chaining operator usage (?.) in JavaScript codes for better compatibility with outdated browsers
  • Updated: changed 'Do not flag orders as being tracked' description to be more precise about what happens if turned on or left off
  • Updated: if you enter your custom domain name for server side tagging with the https:// prefix, it will be removed before domain name validation
  • Updated: all script blocks to be ignored by Cookiebot if this integration is enabled
  • Updated: do not track WooCommerce order where payment failed
Download this release

Release Info

Developer duracelltomi
Plugin Icon 128x128 DuracellTomi's Google Tag Manager for WordPress
Version 1.15
Comparing to
See all releases

Code changes from version 1.14.2 to 1.15

admin/admin.php CHANGED
@@ -4,7 +4,8 @@ define( 'GTM4WP_ADMIN_GROUP', 'gtm4wp-admin-group' );
4
 
5
  define( 'GTM4WP_ADMIN_GROUP_GENERAL', 'gtm4wp-admin-group-general' );
6
  define( 'GTM4WP_ADMIN_GROUP_GTMID', 'gtm4wp-admin-group-gtm-id' );
7
- define( 'GTM4WP_ADMIN_GROUP_PLACEMENT', 'gtm4wp-admin-code-placement' );
 
8
  define( 'GTM4WP_ADMIN_GROUP_INFO', 'gtm4wp-admin-group-datalayer-info' );
9
 
10
  define( 'GTM4WP_ADMIN_GROUP_INCLUDES', 'gtm4wp-admin-group-includes' );
@@ -267,7 +268,7 @@ $GLOBALS['gtm4wp_scrollerfieldtexts'] = array(
267
  $GLOBALS['gtm4wp_integratefieldtexts'] = array(
268
  GTM4WP_OPTION_INTEGRATE_WPCF7 => array(
269
  'label' => __( 'Contact Form 7', 'duracelltomi-google-tag-manager' ),
270
- 'description' => __( 'Check this to include a dataLayer event after a successfull form submission.', 'duracelltomi-google-tag-manager' ),
271
  'phase' => GTM4WP_PHASE_STABLE,
272
  'plugintocheck' => 'contact-form-7/wp-contact-form-7.php',
273
  ),
@@ -376,8 +377,10 @@ $GLOBALS['gtm4wp_integratefieldtexts'] = array(
376
  GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG => array(
377
  'label' => __( 'Do not flag orders as being tracked', 'duracelltomi-google-tag-manager' ),
378
  'description' => __(
379
- 'Check this to prevent the plugin to flag orders as being already tracked.<br /><br />This ensures that no order data will be tracked ' .
380
- 'multiple times in any ad or measurement system so please only enable this feature if you really need it (with iDeal you might need this)!',
 
 
381
  'duracelltomi-google-tag-manager'
382
  ),
383
  'phase' => GTM4WP_PHASE_STABLE
@@ -445,7 +448,12 @@ $GLOBALS['gtm4wp_advancedfieldtexts'] = array(
445
  ),
446
  GTM4WP_OPTION_GTMDOMAIN => array(
447
  'label' => __( 'Container domain name', 'duracelltomi-google-tag-manager' ),
448
- 'description' => __( "Enter your custom domain name if you are using a server side GTM container for tracking. Leave this blank to use www.googletagmanager.com", 'duracelltomi-google-tag-manager' ),
 
 
 
 
 
449
  'phase' => GTM4WP_PHASE_STABLE,
450
  )
451
  );
@@ -536,11 +544,19 @@ function gtm4wp_admin_output_field( $args ) {
536
  break;
537
  }
538
 
539
- case GTM4WP_ADMIN_GROUP_PLACEMENT: {
540
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_FOOTER . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_FOOTER . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_FOOTER ? 'checked="checked"' : '' ) . '/> ' . __( 'Footer of the page (not recommended by Google, no tweak in your template required)', 'duracelltomi-google-tag-manager' ) . '<br />';
541
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_BODYOPEN . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_BODYOPEN . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN ? 'checked="checked"' : '' ) . '/> ' . __( 'Custom (needs tweak in your template)', 'duracelltomi-google-tag-manager' ) . '<br />';
542
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN_AUTO ? 'checked="checked"' : '' ) . '/> ' . __( 'Codeless injection (no tweak, right placement but experimental, could break your frontend)', 'duracelltomi-google-tag-manager' ) . '<br />';
543
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_OFF . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_OFF . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_OFF ? 'checked="checked"' : '' ) . '/> ' . __( 'Off (only add data layer to the page source)', 'duracelltomi-google-tag-manager' ) . '<br /><br />' . $args['description'];
 
 
 
 
 
 
 
 
544
 
545
  break;
546
  }
@@ -642,6 +658,21 @@ function gtm4wp_admin_output_field( $args ) {
642
  break;
643
  }
644
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
645
  default: {
646
  if ( preg_match( '/' . GTM4WP_OPTIONS . "\\[blacklist\\-[^\\]]+\\]/i", $args['label_for'] ) ) {
647
  if ( 'blacklist-sandboxed' == $args['entityid'] ) {
@@ -796,6 +827,9 @@ function gtm4wp_sanitize_options( $options ) {
796
  define( "FILTER_FLAG_HOSTNAME", 0 );
797
  }
798
 
 
 
 
799
  $newoptionvalue = filter_var( $newoptionvalue, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME );
800
  if ( $newoptionvalue === false ) {
801
  $newoptionvalue = '';
@@ -856,17 +890,33 @@ function gtm4wp_sanitize_options( $options ) {
856
  $output[ $optionname ] = $newoptionvalue;
857
  }
858
 
859
- // GTM container code placement
860
  } elseif ( $optionname == GTM4WP_OPTION_GTM_PLACEMENT ) {
861
- $output[ $optionname ] = (int) $newoptionvalue;
862
- if ( ( $output[ $optionname ] < 0 ) || ( $output[ $optionname ] > 3 ) ) {
863
- $output[ $optionname ] = 0;
 
 
 
 
 
 
 
 
864
  }
865
 
866
  // scroll tracking content ID
867
  } elseif ( $optionname == GTM4WP_OPTION_SCROLLER_CONTENTID ) {
868
  $output[ $optionname ] = trim( str_replace( '#', '', $newoptionvalue ) );
869
 
 
 
 
 
 
 
 
 
870
  // anything else
871
  } else {
872
  switch ( gettype( $optionvalue ) ) {
@@ -918,14 +968,34 @@ function gtm4wp_admin_init() {
918
  );
919
 
920
  add_settings_field(
921
- GTM4WP_ADMIN_GROUP_PLACEMENT,
922
- __( 'Container code <code>&lt;noscript&gt;</code> part placement', 'duracelltomi-google-tag-manager' ),
 
 
 
 
 
 
 
 
 
 
 
 
923
  'gtm4wp_admin_output_field',
924
  GTM4WP_ADMINSLUG,
925
  GTM4WP_ADMIN_GROUP_GENERAL,
926
  array(
927
- 'label_for' => GTM4WP_ADMIN_GROUP_PLACEMENT,
928
- 'description' => __( "Code placement decides where to put the second, so called noscript part of the GTM container code.<br />This code is usually only executed if your visitor has for some reason disabled JavaScript.<br/>The main GTM container code will be placed into the <code>&lt;head&gt;</code> section of your webpages anyway (where it belongs to).<br />If you select 'Custom' you need to edit your template file and add the following line just after the opening <code>&lt;body&gt;</code> tag:<br /><code>&lt;?php if ( function_exists( 'gtm4wp_the_gtm_tag' ) ) { gtm4wp_the_gtm_tag(); } ?&gt;</code>", 'duracelltomi-google-tag-manager' ),
 
 
 
 
 
 
 
 
929
  )
930
  );
931
 
4
 
5
  define( 'GTM4WP_ADMIN_GROUP_GENERAL', 'gtm4wp-admin-group-general' );
6
  define( 'GTM4WP_ADMIN_GROUP_GTMID', 'gtm4wp-admin-group-gtm-id' );
7
+ define( 'GTM4WP_ADMIN_GROUP_CONTAINERON', 'gtm4wp-admin-container-on' );
8
+ define( 'GTM4WP_ADMIN_GROUP_COMPATMODE', 'gtm4wp-admin-compat-mode' );
9
  define( 'GTM4WP_ADMIN_GROUP_INFO', 'gtm4wp-admin-group-datalayer-info' );
10
 
11
  define( 'GTM4WP_ADMIN_GROUP_INCLUDES', 'gtm4wp-admin-group-includes' );
268
  $GLOBALS['gtm4wp_integratefieldtexts'] = array(
269
  GTM4WP_OPTION_INTEGRATE_WPCF7 => array(
270
  'label' => __( 'Contact Form 7', 'duracelltomi-google-tag-manager' ),
271
+ 'description' => __( 'Check this to fire dataLayer events after Contact Form 7 submissions (supported events: invalid input, spam detected, form submitted, form submitted and mail sent, form submitted and mail send failed).', 'duracelltomi-google-tag-manager' ),
272
  'phase' => GTM4WP_PHASE_STABLE,
273
  'plugintocheck' => 'contact-form-7/wp-contact-form-7.php',
274
  ),
377
  GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG => array(
378
  'label' => __( 'Do not flag orders as being tracked', 'duracelltomi-google-tag-manager' ),
379
  'description' => __(
380
+ 'Turn this on to prevent the plugin to flag orders as being already tracked.<br /><br />'.
381
+ 'Leaving this unchecked ensures that no order data will be tracked multiple times '.
382
+ 'in any ad or measurement system.<br />'.
383
+ 'Please only turn this feature on if you really need it!',
384
  'duracelltomi-google-tag-manager'
385
  ),
386
  'phase' => GTM4WP_PHASE_STABLE
448
  ),
449
  GTM4WP_OPTION_GTMDOMAIN => array(
450
  'label' => __( 'Container domain name', 'duracelltomi-google-tag-manager' ),
451
+ 'description' => __( "Enter your custom domain name if you are using a server side GTM container for tracking. Do not include https:// prefix. Leave this blank to use www.googletagmanager.com", 'duracelltomi-google-tag-manager' ),
452
+ 'phase' => GTM4WP_PHASE_STABLE,
453
+ ),
454
+ GTM4WP_OPTION_NOGTMFORLOGGEDIN => array(
455
+ 'label' => __( 'User roles to exclude', 'duracelltomi-google-tag-manager' ),
456
+ 'description' => __( "Do not load GTM container on the frontend if role of the logged in user is any of this", 'duracelltomi-google-tag-manager' ),
457
  'phase' => GTM4WP_PHASE_STABLE,
458
  )
459
  );
544
  break;
545
  }
546
 
547
+ case GTM4WP_ADMIN_GROUP_CONTAINERON: {
548
+ echo $args['description'].'<br/><br/>';
549
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[container-on]_1" name="' . GTM4WP_OPTIONS . '[container-on]" value="1" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] != GTM4WP_PLACEMENT_OFF ? 'checked="checked"' : '' ) . '/> ' . __( 'On', 'duracelltomi-google-tag-manager' ) . '<br />';
550
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[container-on]_0" name="' . GTM4WP_OPTIONS . '[container-on]" value="0" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_OFF ? 'checked="checked"' : '' ) . '/> ' . __( 'Off', 'duracelltomi-google-tag-manager' ) . '<br />';
551
+
552
+ break;
553
+ }
554
+
555
+ case GTM4WP_ADMIN_GROUP_COMPATMODE: {
556
+ echo $args['description'].'<br/><br/>';
557
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[compat-mode]_' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" name="' . GTM4WP_OPTIONS . '[compat-mode]" value="' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN_AUTO || $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_OFF ? 'checked="checked"' : '' ) . '/> ' . __( 'Off (no tweak, right placement)', 'duracelltomi-google-tag-manager' ) . '<br />';
558
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[compat-mode]_' . GTM4WP_PLACEMENT_FOOTER . '" name="' . GTM4WP_OPTIONS . '[compat-mode]" value="' . GTM4WP_PLACEMENT_FOOTER . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_FOOTER ? 'checked="checked"' : '' ) . '/> ' . __( 'Footer of the page (not recommended by Google, Search Console verification will not work)', 'duracelltomi-google-tag-manager' ) . '<br />';
559
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[compat-mode]_' . GTM4WP_PLACEMENT_BODYOPEN . '" name="' . GTM4WP_OPTIONS . '[compat-mode]" value="' . GTM4WP_PLACEMENT_BODYOPEN . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN ? 'checked="checked"' : '' ) . '/> ' . __( 'Manually coded (needs tweak in your template)', 'duracelltomi-google-tag-manager' ) . '<br />';
560
 
561
  break;
562
  }
658
  break;
659
  }
660
 
661
+ case GTM4WP_OPTIONS . "[" . GTM4WP_OPTION_NOGTMFORLOGGEDIN . "]": {
662
+ $roles = get_editable_roles();
663
+
664
+ echo $args['description'].'<br/><br/>';
665
+
666
+ $saved_roles = explode(",", $gtm4wp_options[GTM4WP_OPTION_NOGTMFORLOGGEDIN]);
667
+
668
+ foreach($roles as $role_id => $role_info) {
669
+ $role_name = translate_user_role( $role_info['name'] );
670
+ echo '<input type="checkbox" id="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']_' . $role_id . '" name="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . '][]" value="' . $role_id . '"' . ( in_array( $role_id, $saved_roles ) ? ' checked="checked"' : '' ) . '><label for="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']_' . $role_id . '">' . $role_name . '</label><br/>';
671
+ }
672
+
673
+ break;
674
+ }
675
+
676
  default: {
677
  if ( preg_match( '/' . GTM4WP_OPTIONS . "\\[blacklist\\-[^\\]]+\\]/i", $args['label_for'] ) ) {
678
  if ( 'blacklist-sandboxed' == $args['entityid'] ) {
827
  define( "FILTER_FLAG_HOSTNAME", 0 );
828
  }
829
 
830
+ // remove https:// prefix if used
831
+ $newoptionvalue = str_replace( 'https://', '', $newoptionvalue );
832
+
833
  $newoptionvalue = filter_var( $newoptionvalue, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME );
834
  if ( $newoptionvalue === false ) {
835
  $newoptionvalue = '';
890
  $output[ $optionname ] = $newoptionvalue;
891
  }
892
 
893
+ // GTM container ON/OFF + compat mode
894
  } elseif ( $optionname == GTM4WP_OPTION_GTM_PLACEMENT ) {
895
+ $container_on_off = (bool) $options['container-on'];
896
+ $container_compat = (int) $options['compat-mode'];
897
+
898
+ if ( !$container_on_off ) {
899
+ $output[ $optionname ] = GTM4WP_PLACEMENT_OFF;
900
+ } else {
901
+ if ( ( $container_compat < 0 ) || ( $container_compat > 2 ) ) {
902
+ $container_compat = 2;
903
+ }
904
+
905
+ $output[ $optionname ] = $container_compat;
906
  }
907
 
908
  // scroll tracking content ID
909
  } elseif ( $optionname == GTM4WP_OPTION_SCROLLER_CONTENTID ) {
910
  $output[ $optionname ] = trim( str_replace( '#', '', $newoptionvalue ) );
911
 
912
+ // do not output GTM container code for specific user roles
913
+ } elseif ( $optionname == GTM4WP_OPTION_NOGTMFORLOGGEDIN ) {
914
+ if ( is_array( $newoptionvalue ) ) {
915
+ $output[ $optionname ] = implode(",", $newoptionvalue );
916
+ } else {
917
+ $output[ $optionname ] = '';
918
+ }
919
+
920
  // anything else
921
  } else {
922
  switch ( gettype( $optionvalue ) ) {
968
  );
969
 
970
  add_settings_field(
971
+ GTM4WP_ADMIN_GROUP_CONTAINERON,
972
+ __( 'Container code ON/OFF', 'duracelltomi-google-tag-manager' ),
973
+ 'gtm4wp_admin_output_field',
974
+ GTM4WP_ADMINSLUG,
975
+ GTM4WP_ADMIN_GROUP_GENERAL,
976
+ array(
977
+ 'label_for' => GTM4WP_ADMIN_GROUP_CONTAINERON,
978
+ 'description' => __( "Turning OFF the Google Tag Manager container itself will remove both the head and the body part of the container code but leave data layer codes working.<br/>This should be only used in specific cases where you need to place the container code manually or using another tool.", 'duracelltomi-google-tag-manager' ),
979
+ )
980
+ );
981
+
982
+ add_settings_field(
983
+ GTM4WP_ADMIN_GROUP_COMPATMODE,
984
+ __( 'Container code compatibility mode', 'duracelltomi-google-tag-manager' ),
985
  'gtm4wp_admin_output_field',
986
  GTM4WP_ADMINSLUG,
987
  GTM4WP_ADMIN_GROUP_GENERAL,
988
  array(
989
+ 'label_for' => GTM4WP_ADMIN_GROUP_COMPATMODE,
990
+ 'description' => __(
991
+ 'Compatibility mode decides where to put the second, so called <code>&lt;noscript&gt;</code> or <code>&lt;iframe&gt;</code> part of the GTM container code.<br />'.
992
+ 'This code is usually only executed if your visitor has disabled JavaScript for some reason.<br/>'.
993
+ 'It is also mandatory in order to verify your site in Google Search Console using the GTM method.<br/>'.
994
+ 'The main GTM container code will be placed into the <code>&lt;head&gt;</code> section of your webpages anyway (where it belongs to).<br/><br/>'.
995
+ 'If you select "Manually coded", you need to edit your template files and add the following line just after the opening <code>&lt;body&gt;</code> tag:<br />'.
996
+ "<code>&lt;?php if ( function_exists( 'gtm4wp_the_gtm_tag' ) ) { gtm4wp_the_gtm_tag(); } ?&gt;</code>",
997
+ 'duracelltomi-google-tag-manager'
998
+ ),
999
  )
1000
  );
1001
 
common/readoptions.php CHANGED
@@ -8,6 +8,7 @@ define( 'GTM4WP_OPTION_ENV_GTM_PREVIEW', 'gtm-env-gtm-preview' );
8
  define( 'GTM4WP_OPTION_DONOTTRACK', 'gtm-browser-do-not-track' );
9
  define( 'GTM4WP_OPTION_LOADEARLY', 'gtm-load-gtm-early' );
10
  define( 'GTM4WP_OPTION_GTMDOMAIN', 'gtm-domain-name' );
 
11
 
12
  define( 'GTM4WP_OPTION_INCLUDE_REMARKETING', 'include-remarketing' );
13
  define( 'GTM4WP_OPTION_INCLUDE_LOGGEDIN', 'include-loggedin' );
@@ -141,6 +142,7 @@ $gtm4wp_defaultoptions = array(
141
  GTM4WP_OPTION_DONOTTRACK => false,
142
  GTM4WP_OPTION_LOADEARLY => false,
143
  GTM4WP_OPTION_GTMDOMAIN => '',
 
144
 
145
  GTM4WP_OPTION_INCLUDE_REMARKETING => false,
146
  GTM4WP_OPTION_INCLUDE_LOGGEDIN => false,
@@ -197,7 +199,7 @@ $gtm4wp_defaultoptions = array(
197
 
198
  GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC => false,
199
  GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC => false,
200
- GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION => 0,
201
  GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP => false,
202
  GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL => false,
203
  GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY => '',
8
  define( 'GTM4WP_OPTION_DONOTTRACK', 'gtm-browser-do-not-track' );
9
  define( 'GTM4WP_OPTION_LOADEARLY', 'gtm-load-gtm-early' );
10
  define( 'GTM4WP_OPTION_GTMDOMAIN', 'gtm-domain-name' );
11
+ define( 'GTM4WP_OPTION_NOGTMFORLOGGEDIN', 'gtm-no-gtm-for-logged-in' );
12
 
13
  define( 'GTM4WP_OPTION_INCLUDE_REMARKETING', 'include-remarketing' );
14
  define( 'GTM4WP_OPTION_INCLUDE_LOGGEDIN', 'include-loggedin' );
142
  GTM4WP_OPTION_DONOTTRACK => false,
143
  GTM4WP_OPTION_LOADEARLY => false,
144
  GTM4WP_OPTION_GTMDOMAIN => '',
145
+ GTM4WP_OPTION_NOGTMFORLOGGEDIN => '',
146
 
147
  GTM4WP_OPTION_INCLUDE_REMARKETING => false,
148
  GTM4WP_OPTION_INCLUDE_LOGGEDIN => false,
199
 
200
  GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC => false,
201
  GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC => false,
202
+ GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION => 10,
203
  GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP => false,
204
  GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL => false,
205
  GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY => '',
duracelltomi-google-tag-manager-for-wordpress.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  Plugin Name: Google Tag Manager for Wordpress
4
- Version: 1.14.2
5
  Plugin URI: https://gtm4wp.com/
6
  Description: The first Google Tag Manager plugin for WordPress with business goals in mind
7
  Author: Thomas Geiger
@@ -10,10 +10,10 @@ Text Domain: duracelltomi-google-tag-manager
10
  Domain Path: /languages
11
 
12
  WC requires at least: 3.2
13
- WC tested up to: 5.9.0
14
  */
15
 
16
- define( 'GTM4WP_VERSION', '1.14.2' );
17
  define( 'GTM4WP_PATH', plugin_dir_path( __FILE__ ) );
18
 
19
  global $gtp4wp_plugin_url, $gtp4wp_plugin_basename;
1
  <?php
2
  /*
3
  Plugin Name: Google Tag Manager for Wordpress
4
+ Version: 1.15
5
  Plugin URI: https://gtm4wp.com/
6
  Description: The first Google Tag Manager plugin for WordPress with business goals in mind
7
  Author: Thomas Geiger
10
  Domain Path: /languages
11
 
12
  WC requires at least: 3.2
13
+ WC tested up to: 6.3.1
14
  */
15
 
16
+ define( 'GTM4WP_VERSION', '1.15' );
17
  define( 'GTM4WP_PATH', plugin_dir_path( __FILE__ ) );
18
 
19
  global $gtp4wp_plugin_url, $gtp4wp_plugin_basename;
integration/woocommerce.php CHANGED
@@ -688,6 +688,11 @@ function gtm4wp_woocommerce_datalayer_filter_items( $dataLayer ) {
688
  }
689
  }
690
 
 
 
 
 
 
691
  if ( isset( $order ) ) {
692
  $dataLayer = array_merge( $dataLayer, gtm4wp_get_purchase_datalayer( $order, $order_items ) );
693
 
@@ -835,16 +840,22 @@ function gtm4wp_woocommerce_thankyou( $order_id ) {
835
  }
836
  }
837
 
 
 
 
 
 
838
  if ( isset( $order ) ) {
839
  $dataLayer = gtm4wp_get_purchase_datalayer( $order, NULL );
840
 
841
  $has_html5_support = current_theme_supports( 'html5' );
 
842
 
843
  echo '
844
- <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . '>//<![CDATA[
845
  window.' . $gtm4wp_datalayer_name . ' = window.' . $gtm4wp_datalayer_name . ' || [];
846
  window.' . $gtm4wp_datalayer_name . '.push(' . json_encode( $dataLayer ) . ');
847
- //]]></script>';
848
 
849
  if ( ! $do_not_flag_tracked_order ) {
850
  update_post_meta( $order_id, '_ga_tracked', 1 );
@@ -1236,9 +1247,12 @@ function gtm4wp_add_productdata_to_wc_block($content, $data, $product) {
1236
  }
1237
 
1238
  function gtm4wp_woocommerce_header_top() {
 
 
1239
  $has_html5_support = current_theme_supports( 'html5' );
 
1240
 
1241
- echo "<script" . ( $has_html5_support ? ' type="text/javascript"' : '' ) . ">
1242
  const gtm4wp_is_safari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
1243
  if ( gtm4wp_is_safari ) {
1244
  window.addEventListener('pageshow', function(event) {
688
  }
689
  }
690
 
691
+ if ( isset( $order ) && ( "failed" == $order->get_status() ) ) {
692
+ // do not track order where payment failed
693
+ unset( $order );
694
+ }
695
+
696
  if ( isset( $order ) ) {
697
  $dataLayer = array_merge( $dataLayer, gtm4wp_get_purchase_datalayer( $order, $order_items ) );
698
 
840
  }
841
  }
842
 
843
+ if ( isset( $order ) && ( "failed" == $order->get_status() ) ) {
844
+ // do not track order where payment failed
845
+ unset( $order );
846
+ }
847
+
848
  if ( isset( $order ) ) {
849
  $dataLayer = gtm4wp_get_purchase_datalayer( $order, NULL );
850
 
851
  $has_html5_support = current_theme_supports( 'html5' );
852
+ $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
853
 
854
  echo '
855
+ <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>
856
  window.' . $gtm4wp_datalayer_name . ' = window.' . $gtm4wp_datalayer_name . ' || [];
857
  window.' . $gtm4wp_datalayer_name . '.push(' . json_encode( $dataLayer ) . ');
858
+ </script>';
859
 
860
  if ( ! $do_not_flag_tracked_order ) {
861
  update_post_meta( $order_id, '_ga_tracked', 1 );
1247
  }
1248
 
1249
  function gtm4wp_woocommerce_header_top() {
1250
+ global $gtm4wp_options;
1251
+
1252
  $has_html5_support = current_theme_supports( 'html5' );
1253
+ $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
1254
 
1255
+ echo "<script" . ( $has_html5_support ? ' type="text/javascript"' : '' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . ">
1256
  const gtm4wp_is_safari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
1257
  if ( gtm4wp_is_safari ) {
1258
  window.addEventListener('pageshow', function(event) {
js/gtm4wp-contact-form-7-tracker.js CHANGED
@@ -1,17 +1,51 @@
1
- document.addEventListener('wpcf7submit', function(event) {
2
- let gtm4wp_cf7formid = '(not set)';
3
- if ( event && event.detail && event.detail.contactFormId ) {
4
- gtm4wp_cf7formid = event.detail.contactFormId;
 
 
 
 
5
  }
6
 
7
- let gtm4wp_cf7forminputs = [];
8
  if ( event && event.detail && event.detail.inputs ) {
9
- gtm4wp_cf7forminputs = event.detail.inputs;
10
  }
11
 
12
- window[ gtm4wp_datalayer_name ].push({
13
- 'event': 'gtm4wp.contactForm7Submitted',
14
- 'gtm4wp.cf7formid': gtm4wp_cf7formid,
15
- 'gtm4wp.cf7inputs': gtm4wp_cf7forminputs
16
- });
17
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function gtm4wp_prepare_cf7_data( eventdata ) {
2
+ let cf7data = {
3
+ formid: '(not set)',
4
+ inputs: []
5
+ }
6
+
7
+ if ( eventdata && eventdata.detail && eventdata.detail.contactFormId ) {
8
+ cf7data.formid = eventdata.detail.contactFormId;
9
  }
10
 
 
11
  if ( event && event.detail && event.detail.inputs ) {
12
+ cf7data.inputs = event.detail.inputs;
13
  }
14
 
15
+ return cf7data;
16
+ }
17
+
18
+ /**
19
+ * Contact Form 7 DOM and Google Tag Manager for WordPress data layer event pairs
20
+ * @see https://contactform7.com/dom-events/
21
+ * @const
22
+ * @type {Object}
23
+ */
24
+ const gtm4wp_ctf7_event_pairs = {
25
+ wpcf7invalid: 'gtm4wp.contactForm7InvalidInput',
26
+ wpcf7spam: 'gtm4wp.contactForm7SpamDetected',
27
+ wpcf7mailsent: 'gtm4wp.contactForm7MailSent',
28
+ wpcf7mailfailed: 'gtm4wp.contactForm7MailFailed',
29
+ wpcf7submit: 'gtm4wp.contactForm7Submitted',
30
+ };
31
+
32
+ /**
33
+ * Handle Contact Form 7 DOM events
34
+ * If CTF7 event fired push a data layer event with form data(id, inputs)
35
+ * @param {Object} w Window
36
+ * @param {Object} d Document
37
+ * @param {Object} p CTF7 - GTM4WP event pairs
38
+ * @return void
39
+ */
40
+ (function ( w, d, p ) {
41
+ for ( let ctf7event in p ) {
42
+ d.addEventListener( ctf7event, function( event ) {
43
+ const cf7data = gtm4wp_prepare_cf7_data( event );
44
+ w[ gtm4wp_datalayer_name ].push({
45
+ 'event': p[ ctf7event ],
46
+ 'formid': cf7data.formid,
47
+ 'inputs': cf7data.inputs
48
+ });
49
+ });
50
+ }
51
+ }( window, document, gtm4wp_ctf7_event_pairs ));
js/gtm4wp-form-move-tracker.js CHANGED
@@ -1,5 +1,5 @@
1
  document.addEventListener("focusin", function(event) {
2
- const elem = event.target?.closest("input,select,textarea,button,meter,progress");
3
  if ( elem ) {
4
  window[ gtm4wp_datalayer_name ].push({
5
  'event' : 'gtm4wp.formElementEnter',
@@ -8,15 +8,15 @@ document.addEventListener("focusin", function(event) {
8
  'inputName' : elem.getAttribute("name") || "(no input name)",
9
  'inputClass': elem.getAttribute("class") || "(no input class)",
10
 
11
- 'formID' : elem.form?.getAttribute("id") || "(no form ID)",
12
- 'formName' : elem.form?.getAttribute("name") || "(no form name)",
13
- 'formClass': elem.form?.getAttribute("class") || "(no form class)"
14
  });
15
  }
16
  }, false);
17
 
18
  document.addEventListener("focusout", function(event) {
19
- const elem = event.target.closest("input,select,textarea,button,meter,progress");
20
  if ( elem ) {
21
  window[ gtm4wp_datalayer_name ].push({
22
  'event' : 'gtm4wp.formElementLeave',
@@ -25,9 +25,9 @@ document.addEventListener("focusout", function(event) {
25
  'inputName' : elem.getAttribute("name") || "(no input name)",
26
  'inputClass': elem.getAttribute("class") || "(no input class)",
27
 
28
- 'formID' : elem.form?.getAttribute("id") || "(no form ID)",
29
- 'formName' : elem.form?.getAttribute("name") || "(no form name)",
30
- 'formClass': elem.form?.getAttribute("class") || "(no form class)"
31
  });
32
  };
33
  }, false);
1
  document.addEventListener("focusin", function(event) {
2
+ const elem = event && event.target && event.target.closest("input,select,textarea,button,meter,progress");
3
  if ( elem ) {
4
  window[ gtm4wp_datalayer_name ].push({
5
  'event' : 'gtm4wp.formElementEnter',
8
  'inputName' : elem.getAttribute("name") || "(no input name)",
9
  'inputClass': elem.getAttribute("class") || "(no input class)",
10
 
11
+ 'formID' : (elem.form && elem.form.getAttribute("id")) || "(no form ID)",
12
+ 'formName' : (elem.form && elem.form.getAttribute("name")) || "(no form name)",
13
+ 'formClass': (elem.form && elem.form.getAttribute("class")) || "(no form class)"
14
  });
15
  }
16
  }, false);
17
 
18
  document.addEventListener("focusout", function(event) {
19
+ const elem = event && event.target && event.target.closest("input,select,textarea,button,meter,progress");
20
  if ( elem ) {
21
  window[ gtm4wp_datalayer_name ].push({
22
  'event' : 'gtm4wp.formElementLeave',
25
  'inputName' : elem.getAttribute("name") || "(no input name)",
26
  'inputClass': elem.getAttribute("class") || "(no input class)",
27
 
28
+ 'formID' : (elem.form && elem.form.getAttribute("id")) || "(no form ID)",
29
+ 'formName' : (elem.form && elem.form.getAttribute("name")) || "(no form name)",
30
+ 'formClass': (elem.form && elem.form.getAttribute("class")) || "(no form class)"
31
  });
32
  };
33
  }, false);
js/gtm4wp-woocommerce-enhanced.js CHANGED
@@ -4,7 +4,7 @@ window.gtm4wp_changedetail_fired_during_pageload=false;
4
  window.gtm4wp_is_cart = false;
5
  window.gtm4wp_is_checkout = false;
6
  window.gtm4wp_checkout_step_fired = []; // step 1 will be the billing section which is reported during pageload, no need to handle here
7
- window.gtm4wp_shipping_payment_method_step_offset = window.gtm4wp_needs_shipping_address ? 0 : -1;
8
 
9
  window.gtm4wp_first_container_id = "";
10
 
@@ -68,7 +68,8 @@ function gtm4wp_handle_cart_qty_change() {
68
 
69
  // is quantity changed changed?
70
  if ( original_value != current_value ) {
71
- const productdata = qty_el.closest( '.cart_item' )?.querySelector( '.remove' );
 
72
  if ( !productdata ) {
73
  return;
74
  }
@@ -253,8 +254,14 @@ function gtm4wp_handle_shipping_method_change() {
253
  }
254
 
255
  function gtm4wp_process_woocommerce_pages() {
256
- window.gtm4wp_is_cart = document.querySelector( 'body' )?.classList?.contains( 'woocommerce-cart' );
257
- window.gtm4wp_is_checkout = document.querySelector( 'body' )?.classList?.contains( 'woocommerce-checkout' );
 
 
 
 
 
 
258
 
259
  // loop through WC blocks to set proper listname and position parameters
260
  const gtm4wp_product_block_names = {
@@ -419,7 +426,8 @@ function gtm4wp_process_woocommerce_pages() {
419
  return true;
420
  }
421
 
422
- const productdata = event_target_element.closest( '.product,.wc-block-grid__product' )?.querySelector( '.gtm4wp_productdata' );
 
423
  if ( !productdata ) {
424
  return true;
425
  }
@@ -492,11 +500,12 @@ function gtm4wp_process_woocommerce_pages() {
492
  }
493
 
494
  let product_variant_id = product_form.querySelectorAll( '[name=variation_id]' );
495
- let product_is_grouped = product_form.classList?.contains( 'grouped_form' );
496
 
497
  if ( product_variant_id.length > 0 ) {
498
  if ( gtm4wp_last_selected_product_variation ) {
499
- gtm4wp_last_selected_product_variation.quantity = product_form.querySelector( '[name=quantity]' )?.value || 1;
 
500
 
501
  // fire ga3 version
502
  window[ gtm4wp_datalayer_name ].push({
@@ -528,7 +537,7 @@ function gtm4wp_process_woocommerce_pages() {
528
  products_in_group.forEach( function( dom_productdata ) {
529
  const product_qty_input = document.querySelectorAll( 'input[name=quantity\\[' + dom_productdata.getAttribute( 'data-gtm4wp_product_id' ) + '\\]]' );
530
  if ( product_qty_input.length > 0 ) {
531
- product_qty = product_qty_input[0]?.value || 1;
532
  } else {
533
  return true;
534
  }
@@ -577,14 +586,15 @@ function gtm4wp_process_woocommerce_pages() {
577
  }
578
  });
579
  } else {
 
580
  const product_data = {
581
- 'id': gtm4wp_use_sku_instead ? product_form.querySelector( '[name=gtm4wp_sku]' )?.value : product_form.querySelector( '[name=gtm4wp_id]' )?.value,
582
- 'name': product_form.querySelector( '[name=gtm4wp_name]' )?.value,
583
- 'price': product_form.querySelector( '[name=gtm4wp_price]' )?.value,
584
- 'category': product_form.querySelector( '[name=gtm4wp_category]' )?.value,
585
- 'quantity': product_form.querySelector( '[name=quantity]' )?.value,
586
- 'stocklevel': product_form.querySelector( '[name=gtm4wp_stocklevel]' )?.value,
587
- 'brand': product_form.querySelector( '[name=gtm4wp_brand]' )?.value
588
  };
589
 
590
  // fire ga3 version
@@ -614,14 +624,16 @@ function gtm4wp_process_woocommerce_pages() {
614
  document.addEventListener( 'click', function( e ) {
615
  const dom_productdata = e.target;
616
 
617
- if ( !dom_productdata.closest( '.mini_cart_item a.remove,.product-remove a.remove' ) ) {
618
  return true;
619
  }
620
 
621
  let qty = 0;
622
- let qty_element = dom_productdata.closest( '.cart_item' )?.querySelectorAll( '.product-quantity input.qty' );
 
623
  if ( !qty_element || ( qty_element.length === 0 ) ) {
624
- qty_element = dom_productdata.closest( '.mini_cart_item' )?.querySelectorAll( '.quantity' );
 
625
  if ( qty_element && ( qty_element.length > 0 ) ) {
626
  qty = parseInt( qty_element[0].textContent );
627
 
@@ -745,6 +757,11 @@ function gtm4wp_process_woocommerce_pages() {
745
  }
746
  }
747
 
 
 
 
 
 
748
  const ctrl_key_pressed = e.ctrlKey || e.metaKey;
749
 
750
  e.preventDefault();
@@ -764,7 +781,7 @@ function gtm4wp_process_woocommerce_pages() {
764
  }
765
  },
766
  'eventCallback': function( container_id ) {
767
- if (window.gtm4wp_first_container_id != container_id) {
768
  // only call this for the first loaded container
769
  return true;
770
  }
@@ -806,14 +823,14 @@ function gtm4wp_process_woocommerce_pages() {
806
  }
807
 
808
  const product_form = event.target;
809
- const product_variant_id = product_form.querySelector( '[name=variation_id]' )?.value;
810
- const product_id = product_form.querySelector( '[name=gtm4wp_id]' )?.value;
811
- const product_name = product_form.querySelector( '[name=gtm4wp_name]' )?.value;
812
- const product_sku = product_form.querySelector( '[name=gtm4wp_sku]' )?.value;
813
- const product_category = product_form.querySelector( '[name=gtm4wp_category]' )?.value;
814
- const product_price = product_form.querySelector( '[name=gtm4wp_price]' )?.value;
815
- const product_stocklevel = product_form.querySelector( '[name=gtm4wp_stocklevel]' )?.value;
816
- const product_brand = product_form.querySelector( '[name=gtm4wp_brand]' )?.value;
817
 
818
  let current_product_detail_data = {
819
  name: product_name,
@@ -934,7 +951,7 @@ function gtm4wp_process_woocommerce_pages() {
934
  window.gtm4wp_checkout_products_ga4 = window.gtm4wp_checkout_products_ga4 || [];
935
 
936
  // this checkout step is not reported to GA4 as currently there is no option to report in-between custom steps
937
- document.addEventListener( 'blur', function( e ) {
938
  let event_target_element = e.target;
939
 
940
  if ( !event_target_element ) {
4
  window.gtm4wp_is_cart = false;
5
  window.gtm4wp_is_checkout = false;
6
  window.gtm4wp_checkout_step_fired = []; // step 1 will be the billing section which is reported during pageload, no need to handle here
7
+ window.gtm4wp_shipping_payment_method_step_offset = gtm4wp_needs_shipping_address ? 0 : -1;
8
 
9
  window.gtm4wp_first_container_id = "";
10
 
68
 
69
  // is quantity changed changed?
70
  if ( original_value != current_value ) {
71
+ const cart_item_temp = qty_el.closest( '.cart_item' );
72
+ const productdata = cart_item_temp && cart_item_temp.querySelector( '.remove' );
73
  if ( !productdata ) {
74
  return;
75
  }
254
  }
255
 
256
  function gtm4wp_process_woocommerce_pages() {
257
+ window.gtm4wp_is_cart = false;
258
+ window.gtm4wp_is_checkout = false;
259
+
260
+ const doc_body = document.querySelector( 'body' );
261
+ if ( doc_body ) {
262
+ window.gtm4wp_is_cart = doc_body.classList && doc_body.classList.contains( 'woocommerce-cart' );
263
+ window.gtm4wp_is_checkout = doc_body.classList && doc_body.classList.contains( 'woocommerce-checkout' );
264
+ }
265
 
266
  // loop through WC blocks to set proper listname and position parameters
267
  const gtm4wp_product_block_names = {
426
  return true;
427
  }
428
 
429
+ const product_el = event_target_element.closest( '.product,.wc-block-grid__product' );
430
+ const productdata = product_el && product_el.querySelector( '.gtm4wp_productdata' );
431
  if ( !productdata ) {
432
  return true;
433
  }
500
  }
501
 
502
  let product_variant_id = product_form.querySelectorAll( '[name=variation_id]' );
503
+ let product_is_grouped = product_form.classList && product_form.classList.contains( 'grouped_form' );
504
 
505
  if ( product_variant_id.length > 0 ) {
506
  if ( gtm4wp_last_selected_product_variation ) {
507
+ const qty_el = product_form.querySelector( '[name=quantity]' );
508
+ gtm4wp_last_selected_product_variation.quantity = (qty_el && qty_el.value) || 1;
509
 
510
  // fire ga3 version
511
  window[ gtm4wp_datalayer_name ].push({
537
  products_in_group.forEach( function( dom_productdata ) {
538
  const product_qty_input = document.querySelectorAll( 'input[name=quantity\\[' + dom_productdata.getAttribute( 'data-gtm4wp_product_id' ) + '\\]]' );
539
  if ( product_qty_input.length > 0 ) {
540
+ product_qty = (product_qty_input[0] && product_qty_input[0].value) || 1;
541
  } else {
542
  return true;
543
  }
586
  }
587
  });
588
  } else {
589
+ const product_id_el = gtm4wp_use_sku_instead ? product_form.querySelector( '[name=gtm4wp_sku]' ) : product_form.querySelector( '[name=gtm4wp_id]' );
590
  const product_data = {
591
+ 'id': product_id_el && product_id_el.value,
592
+ 'name': product_form.querySelector( '[name=gtm4wp_name]' ) && product_form.querySelector( '[name=gtm4wp_name]' ).value,
593
+ 'price': product_form.querySelector( '[name=gtm4wp_price]' ) && product_form.querySelector( '[name=gtm4wp_price]' ).value,
594
+ 'category': product_form.querySelector( '[name=gtm4wp_category]' ) && product_form.querySelector( '[name=gtm4wp_category]' ).value,
595
+ 'quantity': product_form.querySelector( '[name=quantity]' ) && product_form.querySelector( '[name=quantity]' ).value,
596
+ 'stocklevel': product_form.querySelector( '[name=gtm4wp_stocklevel]' ) && product_form.querySelector( '[name=gtm4wp_stocklevel]' ).value,
597
+ 'brand': product_form.querySelector( '[name=gtm4wp_brand]' ) && product_form.querySelector( '[name=gtm4wp_brand]' ).value
598
  };
599
 
600
  // fire ga3 version
624
  document.addEventListener( 'click', function( e ) {
625
  const dom_productdata = e.target;
626
 
627
+ if ( !dom_productdata || !dom_productdata.closest( '.mini_cart_item a.remove,.product-remove a.remove' ) ) {
628
  return true;
629
  }
630
 
631
  let qty = 0;
632
+ const cart_item_el = dom_productdata.closest( '.cart_item' );
633
+ let qty_element = cart_item_el && cart_item_el.querySelectorAll( '.product-quantity input.qty' );
634
  if ( !qty_element || ( qty_element.length === 0 ) ) {
635
+ const mini_cart_item_el = dom_productdata.closest( '.mini_cart_item' );
636
+ qty_element = mini_cart_item_el && mini_cart_item_el.querySelectorAll( '.quantity' );
637
  if ( qty_element && ( qty_element.length > 0 ) ) {
638
  qty = parseInt( qty_element[0].textContent );
639
 
757
  }
758
  }
759
 
760
+ // do not do anything if GTM was not loaded for any reason
761
+ if ( "" === window.gtm4wp_first_container_id ) {
762
+ return true;
763
+ }
764
+
765
  const ctrl_key_pressed = e.ctrlKey || e.metaKey;
766
 
767
  e.preventDefault();
781
  }
782
  },
783
  'eventCallback': function( container_id ) {
784
+ if ( "undefined" !== typeof container_id && window.gtm4wp_first_container_id != container_id) {
785
  // only call this for the first loaded container
786
  return true;
787
  }
823
  }
824
 
825
  const product_form = event.target;
826
+ const product_variant_id = product_form.querySelector( '[name=variation_id]' ) && product_form.querySelector( '[name=variation_id]' ).value;
827
+ const product_id = product_form.querySelector( '[name=gtm4wp_id]' ) && product_form.querySelector( '[name=gtm4wp_id]' ).value;
828
+ const product_name = product_form.querySelector( '[name=gtm4wp_name]' ) && product_form.querySelector( '[name=gtm4wp_name]' ).value;
829
+ const product_sku = product_form.querySelector( '[name=gtm4wp_sku]' ) && product_form.querySelector( '[name=gtm4wp_sku]' ).value;
830
+ const product_category = product_form.querySelector( '[name=gtm4wp_category]' ) && product_form.querySelector( '[name=gtm4wp_category]' ).value;
831
+ const product_price = product_form.querySelector( '[name=gtm4wp_price]' ) && product_form.querySelector( '[name=gtm4wp_price]' ).value;
832
+ const product_stocklevel = product_form.querySelector( '[name=gtm4wp_stocklevel]' ) && product_form.querySelector( '[name=gtm4wp_stocklevel]' ).value;
833
+ const product_brand = product_form.querySelector( '[name=gtm4wp_brand]' ) && product_form.querySelector( '[name=gtm4wp_brand]' ).value;
834
 
835
  let current_product_detail_data = {
836
  name: product_name,
951
  window.gtm4wp_checkout_products_ga4 = window.gtm4wp_checkout_products_ga4 || [];
952
 
953
  // this checkout step is not reported to GA4 as currently there is no option to report in-between custom steps
954
+ document.addEventListener( 'focusout', function( e ) {
955
  let event_target_element = e.target;
956
 
957
  if ( !event_target_element ) {
public/frontend.php CHANGED
@@ -204,6 +204,11 @@ function gtm4wp_add_basic_datalayer_data( $dataLayer ) {
204
  $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
205
  $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
206
  $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
 
 
 
 
 
207
  }
208
 
209
  if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTERMLIST ] ) {
@@ -288,6 +293,8 @@ function gtm4wp_add_basic_datalayer_data( $dataLayer ) {
288
  }
289
 
290
  if ( is_search() ) {
 
 
291
  $dataLayer['siteSearchTerm'] = get_search_query();
292
  $dataLayer['siteSearchFrom'] = '';
293
  if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
@@ -309,6 +316,10 @@ function gtm4wp_add_basic_datalayer_data( $dataLayer ) {
309
  $dataLayer['pagePostType'] = 'bloghome';
310
  }
311
 
 
 
 
 
312
  if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_BROWSERDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_OSDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_DEVICEDATA ] ) {
313
  spl_autoload_register(
314
  function( $class ) {
@@ -512,14 +523,37 @@ function gtm4wp_wp_loaded() {
512
  }
513
  }
514
 
 
 
 
 
 
 
 
 
 
 
 
 
515
  function gtm4wp_get_the_gtm_tag() {
516
  global $gtm4wp_options, $gtm4wp_datalayer_name, $gtm4wp_container_code_written;
517
 
 
 
 
518
  $_gtm_tag = '
 
519
  <!-- Google Tag Manager (noscript) -->';
520
 
521
  if ( GTM4WP_PLACEMENT_OFF == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) {
522
  $gtm4wp_container_code_written = true;
 
 
 
 
 
 
 
523
  }
524
 
525
  if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && ( ! $gtm4wp_container_code_written ) ) {
@@ -595,6 +629,7 @@ function gtm4wp_wp_footer() {
595
  }
596
 
597
  $has_html5_support = current_theme_supports( 'html5' );
 
598
 
599
  if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_NEWUSERREG ] ) {
600
  $user_logged_in = array_key_exists( "gtm4wp_user_logged_in", $_COOKIE ) ?
@@ -603,7 +638,7 @@ function gtm4wp_wp_footer() {
603
 
604
  if ( $user_logged_in ) {
605
  echo "
606
- <script" . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ">
607
  if ( window." . $gtm4wp_datalayer_name . " ) {
608
  window." . $gtm4wp_datalayer_name . ".push({
609
  'event': 'gtm4wp.userLoggedIn'
@@ -622,7 +657,7 @@ function gtm4wp_wp_footer() {
622
 
623
  if ( $user_registered ) {
624
  echo "
625
- <script" . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ">
626
  if ( window." . $gtm4wp_datalayer_name . " ) {
627
  window." . $gtm4wp_datalayer_name . ".push({
628
  'event': 'gtm4wp.userRegistered'
@@ -674,10 +709,11 @@ function gtm4wp_wp_header_top( $echo = true ) {
674
  global $gtm4wp_options, $gtm4wp_datalayer_name;
675
 
676
  $has_html5_support = current_theme_supports( 'html5' );
 
677
 
678
  $_gtm_top_content = '
679
  <!-- Google Tag Manager for WordPress by gtm4wp.com -->
680
- <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . '>//<![CDATA[
681
  var gtm4wp_datalayer_name = "' . $gtm4wp_datalayer_name . '";
682
  var ' . $gtm4wp_datalayer_name . ' = ' . $gtm4wp_datalayer_name . ' || [];';
683
 
@@ -695,7 +731,6 @@ function gtm4wp_wp_header_top( $echo = true ) {
695
  }
696
 
697
  $_gtm_top_content .= '
698
- //]]>
699
  </script>
700
  <!-- End Google Tag Manager for WordPress by gtm4wp.com -->';
701
 
@@ -712,10 +747,13 @@ function gtm4wp_wp_header_begin( $echo = true ) {
712
  global $gtm4wp_datalayer_name, $gtm4wp_datalayer_json, $gtm4wp_options, $woocommerce;
713
 
714
  $has_html5_support = current_theme_supports( 'html5' );
 
715
 
716
  $_gtm_header_content = '
717
  <!-- Google Tag Manager for WordPress by gtm4wp.com -->
718
- <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . '>//<![CDATA[';
 
 
719
 
720
  if ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) {
721
  $gtm4wp_datalayer_data = array();
@@ -831,12 +869,42 @@ function gtm4wp_wp_header_begin( $echo = true ) {
831
  ' . $gtm4wp_datalayer_name . '.push( dataLayer_content );';
832
  }
833
 
834
- $_gtm_header_content .= '//]]>
835
  </script>';
836
 
837
  $_gtm_header_content .= apply_filters( GTM4WP_WPFILTER_AFTER_DATALAYER, '' );
838
 
839
- if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && ( GTM4WP_PLACEMENT_OFF != $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
840
  $_gtm_codes = explode( ',', str_replace( array( ';', ' ' ), array( ',', '' ), $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) );
841
  $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
842
 
@@ -854,12 +922,12 @@ function gtm4wp_wp_header_begin( $echo = true ) {
854
  }
855
 
856
  $_gtm_tag .= '
857
- <script data-cfasync="false"' . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>//<![CDATA[
858
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({\'gtm.start\':
859
  new Date().getTime(),event:\'gtm.js\'});var f=d.getElementsByTagName(s)[0],
860
  j=d.createElement(s),dl=l!=\'dataLayer\'?\'&l=\'+l:\'\';j.async=true;j.src=
861
  \'//' . $_gtm_domain_name . '/gtm.\'' . '+\'js?id=\'+i+dl' . $_gtm_env . ';f.parentNode.insertBefore(j,f);
862
- })(window,document,\'script\',\'' . $gtm4wp_datalayer_name . '\',\'' . $one_gtm_code . '\');//]]>
863
  </script>';
864
  }
865
 
204
  $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
205
  $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
206
  $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
207
+ $dataLayer['pagePostDateDayName'] = get_the_date( 'l' );
208
+ $dataLayer['pagePostDateHour'] = get_the_date( 'H' );
209
+ $dataLayer['pagePostDateMinute'] = get_the_date( 'i' );
210
+ $dataLayer['pagePostDateIso'] = get_the_date( 'c' );
211
+ $dataLayer['pagePostDateUnix'] = get_the_date( 'U' );
212
  }
213
 
214
  if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTERMLIST ] ) {
293
  }
294
 
295
  if ( is_search() ) {
296
+ $dataLayer['pagePostType'] = 'search-results';
297
+
298
  $dataLayer['siteSearchTerm'] = get_search_query();
299
  $dataLayer['siteSearchFrom'] = '';
300
  if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
316
  $dataLayer['pagePostType'] = 'bloghome';
317
  }
318
 
319
+ if ( is_404() ) {
320
+ $dataLayer['pagePostType'] = '404-error';
321
+ }
322
+
323
  if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_BROWSERDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_OSDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_DEVICEDATA ] ) {
324
  spl_autoload_register(
325
  function( $class ) {
523
  }
524
  }
525
 
526
+ function gtm4wp_get_container_placement_string() {
527
+ global $gtm4wp_options;
528
+
529
+ switch($gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ]) {
530
+ case GTM4WP_PLACEMENT_FOOTER: return "footer";
531
+ case GTM4WP_PLACEMENT_BODYOPEN: return "manual";
532
+ case GTM4WP_PLACEMENT_BODYOPEN_AUTO: return "automatic";
533
+ case GTM4WP_PLACEMENT_OFF: return "off";
534
+ default: return "unknown (" . $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] . ")";
535
+ }
536
+ }
537
+
538
  function gtm4wp_get_the_gtm_tag() {
539
  global $gtm4wp_options, $gtm4wp_datalayer_name, $gtm4wp_container_code_written;
540
 
541
+ $has_html5_support = current_theme_supports( 'html5' );
542
+ $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
543
+
544
  $_gtm_tag = '
545
+ <!-- GTM Container placement set to ' . gtm4wp_get_container_placement_string() . ' -->
546
  <!-- Google Tag Manager (noscript) -->';
547
 
548
  if ( GTM4WP_PLACEMENT_OFF == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) {
549
  $gtm4wp_container_code_written = true;
550
+
551
+ $_gtm_tag .= '
552
+ <script' . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>
553
+ const console_cmd = console.warn || console.log;
554
+ console_cmd && console_cmd("[GTM4WP] Google Tag Manager container code placement set to OFF !!!");
555
+ console_cmd && console_cmd("[GTM4WP] Data layer codes are active but GTM container must be loaded using custom coding !!!");
556
+ </script>';
557
  }
558
 
559
  if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && ( ! $gtm4wp_container_code_written ) ) {
629
  }
630
 
631
  $has_html5_support = current_theme_supports( 'html5' );
632
+ $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
633
 
634
  if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_NEWUSERREG ] ) {
635
  $user_logged_in = array_key_exists( "gtm4wp_user_logged_in", $_COOKIE ) ?
638
 
639
  if ( $user_logged_in ) {
640
  echo "
641
+ <script" . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . ">
642
  if ( window." . $gtm4wp_datalayer_name . " ) {
643
  window." . $gtm4wp_datalayer_name . ".push({
644
  'event': 'gtm4wp.userLoggedIn'
657
 
658
  if ( $user_registered ) {
659
  echo "
660
+ <script" . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . ">
661
  if ( window." . $gtm4wp_datalayer_name . " ) {
662
  window." . $gtm4wp_datalayer_name . ".push({
663
  'event': 'gtm4wp.userRegistered'
709
  global $gtm4wp_options, $gtm4wp_datalayer_name;
710
 
711
  $has_html5_support = current_theme_supports( 'html5' );
712
+ $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
713
 
714
  $_gtm_top_content = '
715
  <!-- Google Tag Manager for WordPress by gtm4wp.com -->
716
+ <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>
717
  var gtm4wp_datalayer_name = "' . $gtm4wp_datalayer_name . '";
718
  var ' . $gtm4wp_datalayer_name . ' = ' . $gtm4wp_datalayer_name . ' || [];';
719
 
731
  }
732
 
733
  $_gtm_top_content .= '
 
734
  </script>
735
  <!-- End Google Tag Manager for WordPress by gtm4wp.com -->';
736
 
747
  global $gtm4wp_datalayer_name, $gtm4wp_datalayer_json, $gtm4wp_options, $woocommerce;
748
 
749
  $has_html5_support = current_theme_supports( 'html5' );
750
+ $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
751
 
752
  $_gtm_header_content = '
753
  <!-- Google Tag Manager for WordPress by gtm4wp.com -->
754
+ <!-- GTM Container placement set to ' . gtm4wp_get_container_placement_string() . ' -->
755
+ <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>
756
+ const console_cmd = console.warn || console.log;';
757
 
758
  if ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) {
759
  $gtm4wp_datalayer_data = array();
869
  ' . $gtm4wp_datalayer_name . '.push( dataLayer_content );';
870
  }
871
 
872
+ $_gtm_header_content .= '
873
  </script>';
874
 
875
  $_gtm_header_content .= apply_filters( GTM4WP_WPFILTER_AFTER_DATALAYER, '' );
876
 
877
+ $output_container_code = true;
878
+ if ( GTM4WP_PLACEMENT_OFF == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) {
879
+ $output_container_code = false;
880
+
881
+ $_gtm_header_content .= '
882
+ <script' . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>
883
+ console_cmd && console_cmd("[GTM4WP] Google Tag Manager container code placement set to OFF !!!");
884
+ console_cmd && console_cmd("[GTM4WP] Data layer codes are active but GTM container must be loaded using custom coding !!!");
885
+ </script>';
886
+ }
887
+
888
+ $disabled_roles = explode( ',', $gtm4wp_options[ GTM4WP_OPTION_NOGTMFORLOGGEDIN ] );
889
+ if (count($disabled_roles) > 0 ) {
890
+ $current_user = wp_get_current_user();
891
+ foreach( $current_user->roles as $user_role ) {
892
+ if ( in_array( $user_role, $disabled_roles ) ) {
893
+ $output_container_code = false;
894
+
895
+ $_gtm_header_content .= '
896
+ <script' . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>
897
+ console_cmd && console_cmd("[GTM4WP] Google Tag Manager container code was disabled for this user role: ' . $user_role . ' !!!");
898
+ console_cmd && console_cmd("[GTM4WP] Logout or login with a user having a different user role!");
899
+ console_cmd && console_cmd("[GTM4WP] Data layer codes are active but GTM container code is omitted !!!");
900
+ </script>';
901
+
902
+ break;
903
+ }
904
+ }
905
+ }
906
+
907
+ if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && $output_container_code ) {
908
  $_gtm_codes = explode( ',', str_replace( array( ';', ' ' ), array( ',', '' ), $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) );
909
  $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
910
 
922
  }
923
 
924
  $_gtm_tag .= '
925
+ <script data-cfasync="false"' . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>
926
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({\'gtm.start\':
927
  new Date().getTime(),event:\'gtm.js\'});var f=d.getElementsByTagName(s)[0],
928
  j=d.createElement(s),dl=l!=\'dataLayer\'?\'&l=\'+l:\'\';j.async=true;j.src=
929
  \'//' . $_gtm_domain_name . '/gtm.\'' . '+\'js?id=\'+i+dl' . $_gtm_env . ';f.parentNode.insertBefore(j,f);
930
+ })(window,document,\'script\',\'' . $gtm4wp_datalayer_name . '\',\'' . $one_gtm_code . '\');
931
  </script>';
932
  }
933
 
readme.txt CHANGED
@@ -4,8 +4,8 @@ Donate link: https://gtm4wp.com/
4
  Tags: google tag manager, tag manager, gtm, google, adwords, google adwords, google ads, adwords remarketing, google ads remarketing, remarketing, google analytics, analytics, facebook ads, facebook remarketing, facebook pixel, google optimize, personalisation
5
  Requires at least: 3.4.0
6
  Requires PHP: 5.6
7
- Tested up to: 5.8.2
8
- Stable tag: 1.14.2
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl.html
11
 
@@ -152,7 +152,7 @@ and/or custom JavaScript variables you can secure the Tag Manager container.
152
 
153
  Google Tag Manager for WordPress integrates with several popular plugins. More integration to come!
154
 
155
- * Contact Form 7: fire an event upon successful form submission
156
  * WooCommerce:
157
  * Classic e-commerce (deprecated):
158
  * fire an event when visitors add products to their cart
@@ -163,6 +163,8 @@ Google Tag Manager for WordPress integrates with several popular plugins. More i
163
  * implementation of [Enhanced E-commerce GA4](https://developers.google.com/tag-manager/ecommerce-ga4)
164
  * Does not support promotions since WooCommerce does not have such a feature (yet)
165
  * Does not support refunds
 
 
166
 
167
  = Server side containers =
168
 
@@ -233,6 +235,23 @@ https://gtm4wp.com/how-to-articles/how-to-exclude-admin-users-from-being-tracked
233
 
234
  == Changelog ==
235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  = 1.14.2 =
237
 
238
  * Fixed: undefined google_business_vertical
@@ -749,6 +768,10 @@ Please report all bugs found in my plugin using the [contact form on my website]
749
 
750
  == Upgrade Notice ==
751
 
 
 
 
 
752
  = 1.14.2 =
753
 
754
  Bugfix release
4
  Tags: google tag manager, tag manager, gtm, google, adwords, google adwords, google ads, adwords remarketing, google ads remarketing, remarketing, google analytics, analytics, facebook ads, facebook remarketing, facebook pixel, google optimize, personalisation
5
  Requires at least: 3.4.0
6
  Requires PHP: 5.6
7
+ Tested up to: 5.9.0
8
+ Stable tag: 1.15
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl.html
11
 
152
 
153
  Google Tag Manager for WordPress integrates with several popular plugins. More integration to come!
154
 
155
+ * Contact Form 7: fire an event when a Contact Form 7 form was submitted with any result (mail sent, mail failed, spam detected, invalid input)
156
  * WooCommerce:
157
  * Classic e-commerce (deprecated):
158
  * fire an event when visitors add products to their cart
163
  * implementation of [Enhanced E-commerce GA4](https://developers.google.com/tag-manager/ecommerce-ga4)
164
  * Does not support promotions since WooCommerce does not have such a feature (yet)
165
  * Does not support refunds
166
+ * Google Optimize: load your Google Optimize container directly from your website with the ability to use the data layer variables provided during page load
167
+ * AMP: load your AMP container on the AMP version of your pages
168
 
169
  = Server side containers =
170
 
235
 
236
  == Changelog ==
237
 
238
+ = 1.15 =
239
+
240
+ * Added: pagePostType data layer variable will now return 404-error on 404 pages and search-results on search result pages
241
+ * Added: Google Tag Manager container code can be disabled for specific WordPress user roles under Advanced plugin options. A browser console warning will be shown in such cases to prevent confusion
242
+ * Added: support for all Contact Form 7 events for more granual tracking: gtm4wp.contactForm7MailSent, gtm4wp.contactForm7MailFailed, gtm4wp.contactForm7SpamDetected, gtm4wp.contactForm7InvalidInput
243
+ * Added: additional data layer variables for date attributes: pagePostDateDayName, pagePostDateHour, pagePostDateMinute, pagePostDateIso, pagePostDateUnix - by [ajtatum](https://github.com/ajtatum)
244
+ * Fixed: unclickable products in WooCommerce product lists in Firefox when visiting site in Strict privacy mode or using private browsing
245
+ * Fixed: tracking step 2 on WooCommerce checkout page was broken
246
+ * Updated: removed CDATA blocks as they are not required in simple HTML and they break some cases where code optimizer is being used
247
+ * Updated: products per impression in WooCommerce integration now defaults to 10 instead of 0. This allows view_item_list event to fire on new sites as well
248
+ * Updated: code placement options. Separated container on/off option and replaced code placement with the new terminology: compatibility mode
249
+ * Updated: removed optional chaining operator usage (?.) in JavaScript codes for better compatibility with outdated browsers
250
+ * Updated: changed 'Do not flag orders as being tracked' description to be more precise about what happens if turned on or left off
251
+ * Updated: if you enter your custom domain name for server side tagging with the https:// prefix, it will be removed before domain name validation
252
+ * Updated: all script blocks to be ignored by Cookiebot if this integration is enabled
253
+ * Updated: do not track WooCommerce order where payment failed
254
+
255
  = 1.14.2 =
256
 
257
  * Fixed: undefined google_business_vertical
768
 
769
  == Upgrade Notice ==
770
 
771
+ = 1.15 =
772
+
773
+ Various updates, fixes and improvements
774
+
775
  = 1.14.2 =
776
 
777
  Bugfix release