Skip to content

feat(analytics): auto-provision GA4 custom dimensions#4657

Open
adekbadek wants to merge 4 commits intotrunkfrom
feat/ga4-custom-dims-NPPM-2738
Open

feat(analytics): auto-provision GA4 custom dimensions#4657
adekbadek wants to merge 4 commits intotrunkfrom
feat/ga4-custom-dims-NPPM-2738

Conversation

@adekbadek
Copy link
Copy Markdown
Member

@adekbadek adekbadek commented Apr 13, 2026

All Submissions:

Changes proposed in this Pull Request:

Automatically provisions Newspack's standard set of GA4 event-scoped custom dimensions (27 total, covering Gate Intelligence, reader identity, prompt attribution, checkout, and content context) on the publisher's connected GA4 property.

Triggered automatically when Site Kit's googlesitekit_analytics-4_settings option gains a propertyID or the property changes, via a single-shot wp_schedule_single_event keyed on the property ID. Also exposed as wp newspack ga4-dimensions provision[--dry-run]. Provisioning is idempotent (existing parameter names are skipped) and per-dimension failures are logged but don't abort the run. The newspack_ga4_dimensions_provisioned option stores a summary of the last run keyed on property ID.

Auth source: Newspack OAuth primary, Site Kit fallback

Site Kit's Analytics module only requests analytics.readonly by default; analytics.edit is granted on-demand for SK-initiated write actions, so publishers who connected an existing GA4 property via Site Kit hit a 403 on the Admin API. Newspack's own Google OAuth (_newspack_google_oauth) already has analytics.edit in Google_OAuth::REQUIRED_SCOPES, so GA4_Custom_Dimensions::with_admin_client() now prefers it (via a raw-HTTP client against analyticsadmin.googleapis.com/v1beta) and falls back to Site Kit when Newspack OAuth isn't configured or the call errors. Active path is surfaced as an Auth source: line in CLI output and in the summary option. Prerequisite: analyticsadmin.googleapis.com enabled on the Newspack OAuth proxy's GCP project (done, prod + staging). Edge case: sites with neither Newspack OAuth nor Site Kit edit-scope still 403 – they need to reconnect Site Kit to grant edit.

Closes NPPM-2738.

How to test the changes in this Pull Request:

  1. On a site with Site Kit active but not yet connected to GA4, run wp newspack ga4-dimensions provision --dry-run. It should error out with "No GA4 property ID configured in Site Kit."
  2. Connect Site Kit to a GA4 property. Confirm a newspack_ga4_provision_dimensions scheduled action appears (wp cron event list | grep ga4); wait for or manually trigger it. Verify all 27 Newspack dimensions exist in GA4 (Admin → Property → Custom definitions → Custom dimensions).
  3. Re-run wp newspack ga4-dimensions provision and ... --dry-run. Both should be no-ops (0 missing, every dimension reports as already existing).
  4. Auth-source selection. On a site with Newspack OAuth connected (wp option get _newspack_google_oauth returns a populated option) and Site Kit in readonly mode, run wp newspack ga4-dimensions provision --dry-run. Output should include Auth source: newspack and successfully list existing event-scoped dimensions. On a site with Site Kit in edit mode and no Newspack OAuth, the same command should print Auth source: sitekit.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Provisions Newspack's standard set of GA4 event-scoped custom dimensions
on the publisher's connected property, so downstream analytics features
(Gate Intelligence, reader segmentation) can query Newspack event
parameters without publishers configuring GA4 manually.

Dimensions are provisioned via Site Kit's authenticated Admin API
client, so the API call is attributed to Site Kit's Google Cloud
project (which already has analyticsadmin.googleapis.com enabled) and
uses Site Kit's stored credentials. Auto-trigger fires when Site Kit's
GA4 propertyID is first set or changes, via a single-shot background
action. A WP-CLI command is also provided for manual runs and dry-run
status checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds automated GA4 Admin API provisioning of Newspack’s standard event-scoped custom dimensions on the connected GA4 property (via Site Kit’s authenticated client), plus a WP-CLI command for manual/dry-run execution.

Changes:

  • Extends the Site Kit Analytics wrapper with GA4 custom-dimension list/create methods (Admin API).
  • Introduces a GA4 custom-dimensions provisioner that schedules a one-shot cron run when Site Kit’s GA4 propertyID is set/changed.
  • Adds wp newspack ga4-dimensions provision [--dry-run] CLI support.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
includes/plugins/google-site-kit/class-googlesitekitanalytics.php Adds Admin API helpers to list/create GA4 custom dimensions.
includes/plugins/google-site-kit/class-ga4-custom-dimensions.php Implements scheduling, status, and provisioning logic for Newspack’s GA4 custom dimensions set.
includes/cli/class-initializer.php Registers the new GA4 dimensions WP-CLI command.
includes/cli/class-ga4-dimensions.php Implements newspack ga4-dimensions provision (incl. --dry-run).
includes/class-newspack.php Boots the GA4 provisioning feature by including the new provisioner class.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread includes/plugins/google-site-kit/class-ga4-custom-dimensions.php Outdated
Comment thread includes/plugins/google-site-kit/class-ga4-custom-dimensions.php Outdated
Comment thread includes/plugins/google-site-kit/class-ga4-custom-dimensions.php Outdated
Comment thread includes/plugins/google-site-kit/class-googlesitekitanalytics.php
Comment thread includes/plugins/google-site-kit/class-ga4-custom-dimensions.php Outdated
Comment thread includes/plugins/google-site-kit/class-ga4-custom-dimensions.php Outdated
- Explicitly include class-googlesitekitanalytics.php from the plugin
  bootstrap instead of relying on classmap autoload.
- Guard is_array on Site Kit settings in the add-option callback.
- Guard missing/empty customDimensions in the list response.
- Merge previous run's created list only when property_id matches so
  switching properties doesn't carry over stale entries.
- Restore previous user ID after wp_set_current_user via try/finally so
  we don't leak an authenticated identity into subsequent operations.
- Drop the obsolete 50-dim cap docblock wording; the code now handles
  property-level rejections per-dimension.
@adekbadek adekbadek marked this pull request as ready for review April 13, 2026 10:44
@adekbadek adekbadek requested a review from a team as a code owner April 13, 2026 10:44
@adekbadek adekbadek added the [Status] Needs Review The issue or pull request needs to be reviewed label Apr 13, 2026
The previous commit unconditionally included class-googlesitekitanalytics.php
from the plugin bootstrap to satisfy a review suggestion, but the class
extends Site Kit's Module base class — which doesn't exist in the test
environment where Site Kit isn't active. Parsing the file at bootstrap
fatals with "Class Google\Site_Kit\Core\Modules\Module not found".

The lazy-load pattern was intentional: the file is only required when
setup_sitekit_ga4() runs (after confirming Site Kit is active), and
GA4_Custom_Dimensions::with_analytics_module() already guards on
GOOGLESITEKIT_PLUGIN_MAIN_FILE before any class_exists() / autoload
lookup, so the lazy approach is safe for both runtime and tests.
@leogermani
Copy link
Copy Markdown
Contributor

The dry run works, but when trying to actually create the dimensions with my standard sitekit connection, I get a bunch of

  "error": {
    "code": 403,
    "message": "Request had insufficient authentication scopes.",
    "errors": [
      {
        "message": "Insufficient Permission",
        "domain": "global",
        "reason": "insufficientPermissions"
      }
    ],
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT",
        "domain": "googleapis.com",
        "metadata": {
          "service": "analyticsadmin.googleapis.com",
          "method": "google.analytics.admin.v1beta.AnalyticsAdminService.CreateCustomDimension"
        }
      }
    ]
  }

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@adekbadek
Copy link
Copy Markdown
Member Author

adekbadek commented Apr 23, 2026

Context on the 403 ACCESS_TOKEN_SCOPE_INSUFFICIENT:

Site Kit's Analytics module requests only READONLY_SCOPE (Analytics_4::get_scopes()); EDIT_SCOPE is granted incrementally, only on SK write actions (create-property, create-custom-dimension, enhanced-measurement-settings, etc.). Publishers who connected an existing GA4 property never triggered that prompt.

Newspack's own OAuth already holds analytics.edit via Google_OAuth::REQUIRED_SCOPES, so preferring it avoids asking publishers to reconnect SK. Newspack previously provisioned custom dimensions through this OAuth, but against Universal Analytics' Management API (retired with UA). GA4's Admin API is a separate GCP product – same OAuth scope, different enablement toggle. analyticsadmin.googleapis.com is now enabled on the Newspack OAuth proxy's GCP project (prod + staging); no user reauth required.

Edge case: sites with neither Newspack OAuth nor SK edit still 403 – they need to reconnect Site Kit.

@leogermani – you can run the following snippet to check if you have either auth:

wp option get _newspack_google_oauth >/dev/null 2>&1 && np=YES || np=NO; wp db query "SELECT 1 FROM wp_usermeta WHERE meta_key='googlesitekit_auth_granted_scopes' AND meta_value LIKE '%analytics.edit%' LIMIT 1" --skip-column-names 2>/dev/null | grep -q 1 && sk=YES || sk=NO; echo "SK:$sk | NP:$np"

@adekbadek adekbadek requested a review from leogermani April 23, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Status] Needs Review The issue or pull request needs to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants