GTM4WP 2.0.3 is out
GTM4WP 2.0.3 fixes Google Tag Manager tracking for WooCommerce: tax reported as discount, purchases after Stripe webhooks, Consent Mode defaults.
GTM4WP 2.0.3 is out on wordpress.org. It is a bugfix release for the 2.0 line with eleven fixes and one small addition, most of them for WooCommerce stores, all described below. The update reaches your dashboard a few hours after the release, because wordpress.org runs an automated security review on every plugin release before it is offered as a one-click update; if you do not want to wait, you can download it from the plugin page right away. The complete list of changes is in the GTM4WP 2.0.3 changelog.
Cart discounts on stores that display prices including tax
On a store that displays prices including tax, every cart line in view_cart, begin_checkout and the cart content carried a discount equal to the tax of that line, even with no coupon or sale involved. GA4 therefore reported a share of the revenue as a discount on every order. The per-item discount is the difference between the line subtotal and the line total, and on such a store the tax is added to both before they are compared. The total side read a key that WooCommerce never writes on a cart item, so only the subtotal gained the tax, and the difference was exactly the tax. An undiscounted line carries no discount again. Stores displaying prices excluding tax were never affected, and neither was the purchase event. Thank you to softwaredevelopercoza for the precise report on GitHub, which already named the key in question.
Purchases confirmed by a payment webhook
A purchase was never reported when the customer reached the order received page while the order was still Pending payment. This is the normal sequence with a payment provider that confirms the payment through a webhook, for example the WooCommerce Stripe Gateway with webhooks enabled: the customer is redirected back a moment before the confirmation arrives, the plugin sees a status that is not in “Order statuses that trigger the purchase event” and withholds the event, and the later change to Processing happens in the provider’s own request, which the plugin cannot connect to the customer’s browser. “Reliable purchase tracking” did not recover these orders either.
With “Reliable purchase tracking” turned on, such an order is now remembered in the customer’s session and checked again on the pages they view next. The purchase is reported once, on the first page view after the status has become one of the tracked statuses. The wait ends by itself when the order is cancelled, refunded or fails, or once the order is older than the “Maximum order age” (30 minutes by default). Pending payment itself is still not counted as a sale, and every existing duplicate guard applies unchanged. The same recovery works with the cache-safe data layer. If your store uses a payment provider like this, it is worth checking that “Reliable purchase tracking” is enabled.
Consent Mode defaults with a custom data layer name
If you changed the name of the data layer variable in the plugin settings, the Google Consent Mode default block still pushed its defaults to dataLayer instead of the configured variable. The container never received them, so the consent defaults did not apply. The block now uses the configured name. It also stays out of the combined JavaScript file when WP Rocket combines inline scripts, the same way the other GTM4WP blocks already did.
Add to cart on stores using the Interactivity API blocks
2.0.2 added tracking for WooCommerce blocks built on the WordPress Interactivity API, and two edge cases of that support are fixed now. An add to cart that the store refused on the product page, for example because the item was out of stock, could still be reported when a related product or a product grid item was added within the next ten seconds, so add_to_cart fired twice for a single item. A list add now supersedes whatever the product form still had waiting, so only the item that really reached the cart is reported. In addition, when the cart request to the WooCommerce Store API came back with something other than a cart, for instance a security or caching layer answering with a page instead of the cart data, the plugin could report every item as removed. Such an answer is now treated as no reading at all.
Smaller fixes
- On a subdomain multisite, or on any site defining COOKIE_DOMAIN, the cache-safe data layer could not clear its event cookie after a one-time event was delivered, so every later page view made an unnecessary request. The cookie is now set for the current host only.
- With the cache-safe data layer, a logged-in visitor served a cached page kept requesting their visitor data on every page view after WordPress refused the nonce of the page. The data is now requested once more anonymously, and that page stops asking.
- A login or registration event was lost when the visitor’s next request was a REST call, for example to the WooCommerce Store API or from a headless front end, rather than a page view.
- A user account created by a logged-in administrator through the REST API or an admin app fired gtm4wp.userRegistered in the administrator’s own browser. It no longer fires in that case.
- The form interaction and Contact Form 7 events reported a hidden field instead of the form’s URL when the form contained a field named action, id or target.
- The browser, OS and device data script reported all three kinds of data when a page optimization plugin removed its inline configuration, regardless of which of them were enabled. It now reports nothing in that case.
The Google tag developer ID
The data layer initialization block now sets the Google tag developer ID of GTM4WP, gtag(‘set’, ‘developer_id.dNGJiYT’, true), so that Google can tell which platform installed the tag. It identifies the plugin only and adds nothing about your site or its visitors.
This release is also tested with WooCommerce 11.1.2.
Please report problems in the support forum on wordpress.org or on GitHub.
