You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
v1.5.0 — Security hardening, first/last-touch attribution, lead delivery reliability
Attribution cookies are no longer trusted. Values are type-checked, length-capped and sanitized before use; the marketing channel is recomputed server-side. Garbage or oversized cookies are ignored.
Leads endpoint locked down. Must be HTTPS on an approved host (dashboard.progressiodev.com; extend with the ppt_allowed_lead_hosts filter or the PPT_LEADS_ENDPOINT constant). Requests go through wp_safe_remote_post(), closing the SSRF / exfiltration path.
Lead contact fields validated (is_email, phone digit check, length caps). API key never rendered into the settings page and is also sent as Authorization: Bearer.
Stored page URLs keep only the path and marketing parameters — never full query strings. Cookies carry Secure on HTTPS. Measurement ID validated against G-XXXXXXXXXX.
Added uninstall.php (removes options, queue, cron) and directory index.php guards. Settings sanitizer no longer fatals on non-array input and works from WP-CLI/REST.
Added
First-touch attribution in a first-party cookie (configurable window, default 90 days) alongside per-session last touch, with a stable visitor ID. Both are sent on every GA4 event (first_* / traffic_*) and every lead.
Lead field mapping (Settings → Lead Field Mapping) to pin name/email/phone/message fields per form; improved label heuristics as the fallback. message is now captured.
Confirmed lead delivery with a WP-Cron retry queue (5 attempts, backoff). Status panel shows last sent / last error / queue size with "Send test lead" and "Retry queued leads" buttons.
GA4 generate_lead fires once the Leads API accepts a lead, carrying the dashboard's lead_id.
data-ppt-cta / data-ppt-label attributes as an alternative to CSS classes; file_download and video_start / video_progress / video_complete events (YouTube, Vimeo, HTML5).
Status panel: Measurement ID check, duplicate-gtag detection (Site Kit, MonsterInsights, ExactMetrics, GTM4WP), detected form plugins.
WP-CLI: wp ppt status | test-lead | queue | get | set.
Google Ads auto-tagged landings (gclid with no UTMs) were never attributed.
Sites on www. reported their own internal navigation as a referral source.
form_submit double-counted in Auto mode (generic fallback fired alongside the plugin-specific success event) and counted search/login/comment forms.
landingPage in lead payloads was the submitting page, not the landing page; pageUrl now carries the submitting page.
Contact Form 7 checkbox fields produced "Array". Fluent Forms current fluentform/submission_inserted hook supported.
Events fired before gtag.js finished loading were dropped; they now queue in dataLayer.
Upgrade notes
Requires WordPress 5.9 / PHP 8.0 (the code already depended on str_contains).
form_submit volume on Auto-mode sites will drop to roughly half on upgrade — that was the double count. Annotate your GA4 property on the deploy date.
traffic_source / traffic_medium now describe the last non-direct touch (falling back to first touch), matching GA4's own convention. New first_* and traffic_channel / first_channel parameters need registering as custom dimensions — run scripts/ga4-setup/create-custom-dimensions.js.
The dashboard must accept the new payload keys (deployed 13 Sep 2026). Until it returns an id, generate_lead fires without lead_id.