fix(ga4): stabilize checkout funnel events

This commit is contained in:
2026-05-11 15:54:42 +02:00
parent 80a3cb3814
commit a9fce98b01
8 changed files with 597 additions and 106 deletions

View File

@@ -0,0 +1,184 @@
---
phase: 03-ga4-checkout-events
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- modules/pdgoogleanalytycs4pro/views/templates/hook/displayFooter.tpl
- modules/pdgoogleanalytycs4pro/views/js/scripts_17.js
- modules/pdgoogleanalytycs4pro/controllers/front/ajax.php
- modules/pdgoogleanalytycs4pro/views/templates/hook/addDeliveryInfo.tpl
- modules/pdgoogleanalytycs4pro/views/templates/hook/addPaymentInfo.tpl
autonomous: false
delegation: off
---
<objective>
## Goal
Fix GA4 checkout tracking in `modules/pdgoogleanalytycs4pro` so checkout emits the intended event sequence:
`begin_checkout` once from the cart CTA, `add_shipping_info` after address confirmation / shipping step entry, `add_payment_info` when payment is selected, and `purchase` on order confirmation.
## Purpose
The client currently sees repeated `begin_checkout` events in Tag Assistant across checkout steps and does not reliably see the later ecommerce events. The plan restores useful funnel reporting without touching PrestaShop core.
## Output
Scoped changes to the GA4 module JavaScript/templates/controller logic, plus a completion summary at `.paul/phases/03-ga4-checkout-events/03-01-SUMMARY.md`.
</objective>
<context>
<clarifications>
- No clarifications needed - the client message defines the target sequence and trigger moments.
- Assumption: the primary checkout is the standard PrestaShop 1.7 step checkout rendered by `body#checkout` and `themes/leo_gstore/templates/checkout/_partials/steps/*.tpl`; existing module fallbacks for known OPC modules should not be removed unless they directly cause duplicate events.
- Assumption: `purchase` remains controlled by the module's existing order confirmation logic; this plan verifies and preserves it rather than moving purchase to a checkout-step click.
</clarifications>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@.paul/codebase/architecture.md
@.paul/codebase/db_schema.md
## Source Files
@modules/pdgoogleanalytycs4pro/pdgoogleanalytycs4pro.php
@modules/pdgoogleanalytycs4pro/views/templates/hook/displayFooter.tpl
@modules/pdgoogleanalytycs4pro/views/js/scripts_17.js
@modules/pdgoogleanalytycs4pro/controllers/front/ajax.php
@modules/pdgoogleanalytycs4pro/views/templates/hook/addDeliveryInfo.tpl
@modules/pdgoogleanalytycs4pro/views/templates/hook/addPaymentInfo.tpl
@modules/pdgoogleanalytycs4pro/views/templates/hook/displayOrderConfirmation.tpl
@themes/leo_gstore/templates/checkout/_partials/steps/addresses.tpl
@themes/leo_gstore/templates/checkout/_partials/steps/shipping.tpl
@themes/leo_gstore/templates/checkout/_partials/steps/payment.tpl
</context>
<acceptance_criteria>
## AC-1: Begin Checkout Fires Once From Cart CTA
```gherkin
Given a customer has products in the cart
When the customer clicks "przejdz do realizacji zamowienia" / checkout CTA from the cart
Then GA4 receives one `begin_checkout` event for that cart transition
And navigating between checkout steps does not emit additional `begin_checkout` events
```
## AC-2: Shipping Event Fires At Shipping Stage
```gherkin
Given a customer is in checkout with address data accepted
When the checkout advances from address/customer data into delivery selection or confirms the delivery option
Then GA4 receives `add_shipping_info` with cart items, value, currency, and `shipping_tier`
And the event is not emitted repeatedly from unrelated checkout step refreshes
```
## AC-3: Payment Event Fires On Payment Selection
```gherkin
Given a customer is on the payment step
When the customer selects a payment option
Then GA4 receives `add_payment_info` with cart items, value, currency, and `payment_type`
And accepting terms or refreshing the step does not cause duplicate payment events for the same selected option
```
## AC-4: Purchase Remains Available On Confirmation
```gherkin
Given an order is successfully placed
When the order confirmation page renders
Then GA4 receives `purchase` with transaction id, value, shipping, tax, currency, and item data
And the fix for earlier checkout steps does not disable the existing purchase path
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Move begin_checkout to the cart checkout CTA</name>
<files>modules/pdgoogleanalytycs4pro/views/templates/hook/displayFooter.tpl, modules/pdgoogleanalytycs4pro/views/js/scripts_17.js</files>
<action>
Stop automatic footer-rendered `begin_checkout` on `tagType === 'order'` / `order-opc`, because that fires on each checkout page/step render.
Preserve the existing ecommerce payload generation by either reusing the rendered data in a JS-accessible helper or moving the trigger into a click handler for the cart's checkout CTA.
Add a client-side once guard keyed by cart/session so double clicks or repeated binding do not send duplicate `begin_checkout`.
Preserve existing lulandia.pl Ads conversion behavior only when `begin_checkout` actually fires.
</action>
<verify>Inspect rendered cart HTML/JS and use browser console/Tag Assistant to confirm one `begin_checkout` after clicking the cart checkout CTA and none from checkout step navigation.</verify>
<done>AC-1 satisfied.</done>
</task>
<task type="auto">
<name>Task 2: Trigger shipping and payment events from real checkout transitions</name>
<files>modules/pdgoogleanalytycs4pro/views/js/scripts_17.js, modules/pdgoogleanalytycs4pro/controllers/front/ajax.php, modules/pdgoogleanalytycs4pro/views/templates/hook/addDeliveryInfo.tpl, modules/pdgoogleanalytycs4pro/views/templates/hook/addPaymentInfo.tpl</files>
<action>
Replace or augment the current radio-click-only handlers with handlers aligned to the PrestaShop 1.7 checkout flow:
- `add_shipping_info`: fire when address confirmation moves the customer into the delivery step and/or when `confirmDeliveryOption` is submitted, using the currently selected carrier.
- `add_payment_info`: fire when `input[name="payment-option"]` is selected on the payment step.
Add de-duplication guards keyed by selected carrier/payment module and cart so repeated DOM updates do not emit duplicate events.
Ensure AJAX responses containing script snippets are inserted into an existing stable container or executed safely even when `#hook-display-before-carrier` is absent.
Fix unsafe coupon checks in `ajax.php` such as `($cart_rules & is_array($cart_rules))` if touched, using `is_array($cart_rules) && sizeof($cart_rules)`.
</action>
<verify>Use Tag Assistant and browser console on checkout: address continue -> `add_shipping_info`; payment radio selection -> `add_payment_info`; repeat step refreshes do not duplicate the same selected values.</verify>
<done>AC-2 and AC-3 satisfied.</done>
</task>
<task type="auto">
<name>Task 3: Preserve purchase and validate syntax</name>
<files>modules/pdgoogleanalytycs4pro/controllers/front/ajax.php, modules/pdgoogleanalytycs4pro/views/templates/hook/displayOrderConfirmation.tpl</files>
<action>
Confirm the existing `purchase` path still renders on order confirmation when `PD_GA4P_TRANSACTION_SEND_TYPE` is frontend-confirmation mode.
Do not move `purchase` onto payment or final-summary clicks.
Only adjust escaping or event wrapper code if required by the previous tasks; otherwise leave purchase template behavior intact.
</action>
<verify>Run `php -l modules\pdgoogleanalytycs4pro\controllers\front\ajax.php` and confirm an order confirmation page still includes a single `gtag('event', 'purchase', ...)` block or Tag Assistant sees `purchase` after order placement.</verify>
<done>AC-4 satisfied and PHP syntax passes.</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>GA4 checkout funnel event sequencing for begin_checkout, add_shipping_info, add_payment_info, and purchase.</what-built>
<how-to-verify>
1. Open Tag Assistant for the test domain.
2. Add a product to cart and click the cart checkout CTA.
3. Confirm exactly one `begin_checkout`.
4. Continue through personal/address data into delivery and confirm `add_shipping_info`.
5. Select payment and confirm `add_payment_info`.
6. Place a test order and confirm `purchase`.
</how-to-verify>
<resume-signal>Type "approved" if the sequence is correct, or describe the missing/duplicated event.</resume-signal>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- PrestaShop core files in `classes/`, `controllers/`, `vendor/`, or root checkout controllers.
- Theme checkout templates unless implementation proves the module cannot hook into the existing DOM safely.
- GA4 Measurement Protocol server-side purchase logic in `hookActionOrderStatusPostUpdate`, except for read-only verification.
- Unrelated analytics modules such as `fbpixel`.
## SCOPE LIMITS
- This plan fixes GA4 event timing only; it does not redesign the checkout UI.
- No new third-party dependencies.
- No database schema changes.
- Preserve existing item payload fields as much as possible.
</boundaries>
<verification>
Before declaring plan complete:
- [ ] `php -l modules\pdgoogleanalytycs4pro\controllers\front\ajax.php`
- [ ] Browser console has no JavaScript errors from `scripts_17.js`.
- [ ] Tag Assistant shows the sequence: one `begin_checkout` -> `add_shipping_info` -> `add_payment_info` -> `purchase`.
- [ ] Repeating checkout step navigation does not duplicate already-sent event values.
- [ ] All acceptance criteria met.
</verification>
<success_criteria>
- `begin_checkout` no longer fires automatically on every checkout step.
- `add_shipping_info` and `add_payment_info` fire on their intended checkout stages.
- Existing `purchase` event remains functional.
- Changes are scoped to `pdgoogleanalytycs4pro` unless a checkout-template blocker is discovered.
- A completion summary is written after implementation.
</success_criteria>
<output>
After completion, create `.paul/phases/03-ga4-checkout-events/03-01-SUMMARY.md`.
</output>