Skip to content

Honor WooCommerce currency decimals in conversion events.#13141

Open
faisalahammad wants to merge 1 commit into
google:developfrom
faisalahammad:fix/12986-wc-decimal-currency-minor-unit
Open

Honor WooCommerce currency decimals in conversion events.#13141
faisalahammad wants to merge 1 commit into
google:developfrom
faisalahammad:fix/12986-wc-decimal-currency-minor-unit

Conversation

@faisalahammad

Copy link
Copy Markdown

Summary

WooCommerce add_to_cart and purchase events sent to GA4 now reflect the store's configured currency precision. Previously the JS helper that converted the integer minor-unit price back into a decimal value was hard-coded to divide by 100, so any store that set WooCommerce → Settings → General → Currency options → Number of decimals to anything other than 2 (e.g. 4 for BHD, 0 for JPY, 3 for KWD/OMR/TND) saw the wrong value arrive in GA4.

Fixes #12986

Changes

includes/Core/Conversion_Tracking/Conversion_Event_Providers/WooCommerce.php

Before: the wp_footer and maybe_add_purchase_inline_script inline scripts emitted the wcdata global with currency, products, add_to_cart, purchase, and eventsToTrack fields only. The decimal conversion happened downstream in JS, which had no way to read the store's minor-unit count.

After: both inline scripts also emit window._googlesitekit.wcdata.currency_minor_unit = <absint wc_get_price_decimals()>; so JS can recover the correct decimal precision.

sprintf( 'window._googlesitekit.wcdata.currency_minor_unit = %d;', absint( wc_get_price_decimals() ) ),

assets/js/event-providers/woocommerce.js

Before: formatPrice defaulted to currencyMinorUnit = 2 and the value was hard-coded at every call site.

After: formatPrice keeps = 2 as a defensive fallback but is now always called with the value read from the wcdata global. The new globalCurrencyMinorUnit is destructured alongside globalCurrency and passed into formatEventData / formatProductData, which in turn pass it to formatPrice for both the top-level value and each items[].price.

const {
    currency: globalCurrency,
    currency_minor_unit: globalCurrencyMinorUnit = 2,
    ...
} = global._googlesitekit?.wcdata || {};

Testing

Test 1: PHP price formatter honors the decimals option

  1. composer test -- --filter WooCommerceTest::test_get_formatted_price_returns_correct_minor_units
  2. Test sets woocommerce_price_decimals to 0, 2, and 4 and verifies get_formatted_price() produces the expected integer minor-unit count (e.g. 1.2345 with decimals=4 yields 12345, 500 with decimals=0 yields 500).

Result: 6 dataset cases pass.

Test 2: inline script exposes the decimals value to JS

  1. composer test -- --filter WooCommerceTest::test_inline_script_emits_currency_minor_unit
  2. Test registers the provider script, fires wp_footer, and asserts the rendered output contains wcdata.currency_minor_unit = 4; after setting woocommerce_price_decimals = 4.

Result: passes.

Test 3: JS event provider formats values per currency decimals

  1. BABEL_ENV=test NODE_ENV=test node_modules/.bin/jest --config tests/js/jest.config.js --rootDir . --passWithNoTests assets/js/event-providers/woocommerce.test.js
  2. Covers 0/2/3/4 decimals on both add_to_cart and purchase events, plus the fallback when currency_minor_unit is missing from wcdata.

Result: 8 tests pass.

Test 4: lint clean

  1. composer lint -- includes/Core/Conversion_Tracking/Conversion_Event_Providers/WooCommerce.php tests/phpunit/integration/Core/Conversion_Tracking/Conversion_Event_Providers/WooCommerceTest.php tests/phpunit/includes/wc-functions-stub.php
  2. node_modules/.bin/eslint --no-eslintrc --config .eslintrc.json --ignore-path .eslintignore assets/js/event-providers/woocommerce.js assets/js/event-providers/woocommerce.test.js

Result: clean.

Manual reproduction (before this fix)

  1. Set Number of decimals to 4 under WooCommerce → Settings → General → Currency options.
  2. Add a product priced at 1.2345.
  3. Open Google Tag Assistant; click Add to cart.
  4. Before the fix: dataLayer shows value: 123.45 and items[0].price: 123.45. After the fix: both show 1.2345.

The JS helper that converts the integer minor-unit price back into a
decimal string was hard-coded to divide by 100. When a store set the
WooCommerce 'Number of decimals' option to 4 (or 0, or 3), the value
pushed to GA4 for add_to_cart and purchase events was off by 100x
(or 10x, etc).

Read wc_get_price_decimals() on the PHP side and expose it on the
window._googlesitekit.wcdata global. Thread the value through the
formatPrice helper on the JS side so both the top-level value and
per-item price use the correct minor-unit count.

Fixes google#12986
@google-cla

google-cla Bot commented Jul 19, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Format WooCommerce Conversion Event Values to Be Decimal Value as Opposed to Whole Cents Only

1 participant