Extension: MainWP Google Analytics Extension (GA4)
File: class/class-mainwp-ga-client.php
Severity: Data accuracy — client-facing reports overstate page, source, device and country figures by roughly 2×.
Summary
The extension caches two different date windows and presents both as though they describe the same period. Aggregate metrics (visits, users, page views) are fetched for the last 30 days. The breakdown datasets — pages, sessions/sources, countries — are fetched for the last 60 days, because they are given the previous period’s start date paired with the current period’s end date.
Anything consuming otherValues therefore shows roughly double the figures of anything consuming statsValues, with no indication that the periods differ.
Where it happens
$start_date = gmdate( 'Y-m-d', strtotime( '-' . $days . ' day' ) ); // -30
$end_date = gmdate( 'Y-m-d', time() ); // today
$start2_date = gmdate( 'Y-m-d', strtotime( '-' . ( 2 * $days ) . ' day' ) ); // -60
$end2_date = gmdate( 'Y-m-d', strtotime( '-' . ( 1 + $days ) . ' day' ) ); // -31
$values_detail = self::get_ga_stats_int_ga( $prop_id, $start_date, $end_date, 'detail', ... );
$values_detail_prev = self::get_ga_stats_int_ga( $prop_id, $start2_date, $end2_date, 'detail', ... );
$values_session = self::get_ga_stats_int_ga( $prop_id, $start2_date, $end_date, 'stats_session', ... );
$values_page = self::get_ga_stats_int_ga( $prop_id, $start2_date, $end_date, 'stats_pages_screens', ... );
$values_coutry = self::get_ga_stats_int_ga( $prop_id, $start2_date, $end_date, 'stats_country', ... );
$start2_date and $end2_date are correctly paired for $values_detail_prev, the previous-period comparison. The three breakdown fetches take $start2_date but $end_date, spanning both periods at once.
Evidence
| Value | |
|---|---|
statsValues.aggregates.screenPageViews (current period) |
356 |
| previous period page views, same cache | 1,792 |
sum of otherValues.stats_pages_screens |
2,148 |
356 + 1,792 = 2,148 exactly. The breakdown table is the two periods added together.
Cross-checked against the GA4 UI for the same property: the UI shows 116 views for the top page over 1–31 Aug and 127 over 28 Jul – 27 Aug; the cache shows 500. Calling get_ga_stats_int_ga() directly with explicit dates returns 116 and 125 respectively — matching the UI — which confirms the fetch is sound and only the date arguments are wrong.
A further symptom that makes this recognizable: the cached page list contains page titles that no longer exist, because it reaches back far enough to include titles changed during the previous period.
Suggested fix
$start2_date → $start_date on those three lines:
$values_session = self::get_ga_stats_int_ga( $prop_id, $start_date, $end_date, 'stats_session', ... );
$values_page = self::get_ga_stats_int_ga( $prop_id, $start_date, $end_date, 'stats_pages_screens', ... );
$values_coutry = self::get_ga_stats_int_ga( $prop_id, $start_date, $end_date, 'stats_country', ... );
The four graph_* fetches below also use $start2_date, $end_date. That may be deliberate if those graphs plot current against previous, so they are excluded from this report rather than assumed wrong.
Impact for Pro Reports users
The Pro Reports visits chart uses its own fetch and is unaffected. The Analytics Summary totals are only mildly wrong — a rolling 30 days rather than the report’s stated period. It is Top Pages, Traffic Sources, Devices and Countries that are materially overstated, and always upward, which makes them unlikely to be questioned by the client receiving them.