Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add Site goals user settings and persist Site Goals side panel metric selections #12780

Description

@zutigrm

Feature Description

Add persisted per-user Site Goals settings so saved side panel selections survive dashboard reloads and are restored consistently for both the side panel and Site Goals widgets.


Do not alter or remove anything below. The following sections will be managed by moderators only.

Acceptance criteria

  • The Site Goals side panel settings are saved in the database per user.
    • If two admins saved different site goals settings, they will see different data in both widgets.
  • Reloading the dashboard page loads selected Site Goals settings by the current user from the database and uses them by both widgets and the side panel.
    • Side panel and widgets fall back to the default selection when no settings are saved for the current user.

Implementation Brief

Persisted user setting under Analytics module

  • Add includes/Modules/Analytics_4/Site_Goals_Settings.php

    • Extend User_Setting with option name googlesitekit_analytics-4_site_goals_settings
    • Constructor accepts User_Options instance
    • Type: object, default: empty array
    • merge( array $partial ) method: reads current settings, filters out null values, intersects with allowed keys (goalDrivers, visitorEngagement), merges into existing settings, saves
    • Sanitize callback: validates top-level keys are arrays, delegates each to sanitize_goal_type_selections() which validates ecommerce and lead sub-keys as string arrays via Sanitize::sanitize_string_list()
  • Add includes/Modules/Analytics_4/Datapoints/Get_Site_Goals_Settings.php

    • Follow the Get_Audience_Settings datapoint pattern
    • Constructor receives site_goals_settings via definition array
    • create_request returns closure that calls $site_goals_settings->get()
    • Permission: VIEW_DASHBOARD
  • Add includes/Modules/Analytics_4/Datapoints/Save_Site_Goals_Settings.php

    • Follow the Save_Audience_Settings datapoint pattern
    • Constructor receives site_goals_settings via definition array
    • create_request reads $data_request['settings'], calls $site_goals_settings->merge(), returns updated settings
    • Permission: VIEW_DASHBOARD
  • In includes/Modules/Analytics_4.php

    • Instantiate Site_Goals_Settings with $this->user_options in the constructor
    • Call $this->site_goals_settings->register() in register()
    • Register datapoint definitions: GET:site-goals-settings > Get_Site_Goals_Settings, POST:save-site-goals-settings > Save_Site_Goals_Settings, passing site_goals_settings instance via definition array
    • Preload modules/analytics-4/data/site-goals-settings via googlesitekit_apifetch_preload_paths filter
    • Delete site goals settings in on_deactivation() (follow audience settings pattern)

Datastore partial

  • Add assets/js/modules/analytics-4/datastore/site-goals-settings.js

    • Follow the audience-settings.js pattern within the Analytics module datastore
    • Create fetchGetSiteGoalsSettingsStore via createFetchStore: GET from modules/analytics-4/site-goals-settings, useCache: false
    • Reducer stores response into state.siteGoalsSettings.settings and state.siteGoalsSettings.savedSettings
    • Create fetchSaveSiteGoalsSettingsStore via createFetchStore: POST to modules/analytics-4/save-site-goals-settings with { settings } body, isAction: true, same reducer callback
    • Params validated via validateSiteGoalsSettings
    • validateSiteGoalsSettings / validateGoalTypeSelections: invariant checks that settings is a plain object, goalDrivers / visitorEngagement (if present) are plain objects with optional ecommerce / lead arrays
    • Initial state: siteGoalsSettings: undefined
    • Action saveSiteGoalsSettings( settings ) (createValidatedAction):
      • Clears previous action error
      • Resolves current settings via resolveSelect( MODULES_ANALYTICS_4 ).getSiteGoalsSettings()
      • Merges current settings with provided partial
      • Dispatches fetchSaveSiteGoalsSettings with the merged result
      • On error, sets action error. Returns { response, error }
    • Resolver getSiteGoalsSettings: fetches if state.siteGoalsSettings?.settings is undefined
    • Selectors:
      • getSiteGoalsSettings( state ) > state.siteGoalsSettings?.settings
      • getSiteGoalsGoalDrivers( state ) > state.siteGoalsSettings?.settings?.goalDrivers
      • getSiteGoalsVisitorEngagement( state ) > state.siteGoalsSettings?.settings?.visitorEngagement
      • isSavingSiteGoalsSettings( state ) > checks state.isFetchingSaveSiteGoalsSettings for any truthy value
  • In assets/js/modules/analytics-4/datastore/index.js, import and add siteGoalsSettings to combineStores

Selection panel - initialization from persisted settings

  • In assets/js/modules/analytics-4/components/site-goals/selection-panel/index.tsx
    • Read effectiveDrivers via select( MODULES_ANALYTICS_4 ).getSiteGoalsGoalDrivers() instead of CORE_FORMS SITE_GOALS_EFFECTIVE_DRIVERS
    • Read effectiveVisitorEngagement via select( MODULES_ANALYTICS_4 ).getSiteGoalsVisitorEngagement() instead of CORE_FORMS SITE_GOALS_EFFECTIVE_VISITOR_ENGAGEMENT
    • onSideSheetOpen callback: normalize via resolveGoalDriverSelectionState( effectiveDrivers || SITE_GOALS_DEFAULT_SELECTED_DRIVERS ) and resolveVisitorEngagementSelectionState( effectiveVisitorEngagement || SITE_GOALS_DEFAULT_SELECTED_VISITOR_ENGAGEMENT ), then set as staged CORE_FORMS values (SITE_GOALS_SELECTED_DRIVERS, SITE_GOALS_SELECTED_VISITOR_ENGAGEMENT)
    • Remove SITE_GOALS_EFFECTIVE_DRIVERS / SITE_GOALS_EFFECTIVE_VISITOR_ENGAGEMENT imports
    • Note: CORE_FORMS is retained only for in-panel staged/draft state (SITE_GOALS_SELECTED_DRIVERS, SITE_GOALS_SELECTED_VISITOR_ENGAGEMENT) which is transient and never persisted. CORE_UI is retained only for ephemeral panel-open state (SITE_GOALS_SELECTION_PANEL_OPENED_KEY). We need this currently for snapshoting the the flow, the usage of core forms will be replaced in separate issue that is aligning a new approach for all side panels

Selection panel footer - save flow

  • In assets/js/modules/analytics-4/components/site-goals/selection-panel/Footer.tsx
    • Make saveSettings async
    • Before updating CORE_FORMS, call await dispatch( MODULES_ANALYTICS_4 ).saveSiteGoalsSettings({ goalDrivers: sanitizedSelectionState, visitorEngagement: sanitizedVisitorEngagementSelectionState })
    • If error is returned, return { error } early (panel stays open, error notice shown by SaveErrorNotice)
    • Only on success: update CORE_FORMS staged values, return { error } (which is undefined)
    • Remove writes to SITE_GOALS_EFFECTIVE_DRIVERS / SITE_GOALS_EFFECTIVE_VISITOR_ENGAGEMENT in CORE_FORMS — these are superseded by MODULES_ANALYTICS_4 selectors and are now dead code
    • Wire isBusy={ isSavingSiteGoalsSettings } from select( MODULES_ANALYTICS_4 ) to SelectionPanelFooter
    • Wire savedItemSlugs from persisted MODULES_ANALYTICS_4 goal drivers (flattened via flattenSelections( resolveGoalDriverSelectionState( savedDrivers ) )), replacing the previous hardcoded []

Widget updates - read from MODULES_ANALYTICS_4

  • In assets/js/modules/analytics-4/components/site-goals/widgets/OnlineStorePerformanceWidget.tsx

    • Replace CORE_FORMS.getValue( SITE_GOALS_SELECTION_FORM, SITE_GOALS_EFFECTIVE_DRIVERS ) with select( MODULES_ANALYTICS_4 ).getSiteGoalsGoalDrivers()
    • Replace CORE_FORMS.getValue( SITE_GOALS_SELECTION_FORM, SITE_GOALS_EFFECTIVE_VISITOR_ENGAGEMENT ) with select( MODULES_ANALYTICS_4 ).getSiteGoalsVisitorEngagement()
    • Remove CORE_FORMS import and SITE_GOALS_EFFECTIVE_* / SITE_GOALS_SELECTION_FORM imports
    • Keep fallback to SITE_GOALS_DEFAULT_SELECTED_DRIVERS / SITE_GOALS_DEFAULT_SELECTED_VISITOR_ENGAGEMENT when selectors return undefined
  • In assets/js/modules/analytics-4/components/site-goals/widgets/LeadGenerationPerformanceWidget.tsx

    • Same pattern: replace CORE_FORMS effective driver read with select( MODULES_ANALYTICS_4 ).getSiteGoalsGoalDrivers()
    • Remove CORE_FORMS import and related constants
    • Keep fallback to defaults

Cleanup

  • Remove SITE_GOALS_EFFECTIVE_DRIVERS and SITE_GOALS_EFFECTIVE_VISITOR_ENGAGEMENT constant definitions from constants.ts if no non-test file references them after the above changes

Test Coverage

  • Add assets/js/modules/analytics-4/datastore/site-goals-settings.test.js

    • Selector test: getSiteGoalsSettings, getSiteGoalsGoalDrivers, getSiteGoalsVisitorEngagement populated after receive
    • Resolver test: fetches settings from endpoint when not yet loaded
    • Action test: saveSiteGoalsSettings with partial data posts merged settings to endpoint, updates store on success
    • Error test: saveSiteGoalsSettings returns { error } when the POST fails
    • isSavingSiteGoalsSettings returns true while save is in flight
    • Merge behavior: saving partial settings (only visitorEngagement) preserves existing goalDrivers
  • Update assets/js/modules/analytics-4/components/site-goals/selection-panel/index.test.tsx

    • Setup: seed MODULES_ANALYTICS_4 site goals settings in beforeEach
    • Save flow: mock POST endpoint, verify MODULES_ANALYTICS_4.getSiteGoalsGoalDrivers() reflects saved state after save
    • Visitor engagement save: same pattern, verify MODULES_ANALYTICS_4.getSiteGoalsVisitorEngagement() reflects saved state
  • Update widget test files (OnlineStorePerformanceWidget.test.tsx, LeadGenerationPerformanceWidget.test.tsx)

    • Setup: seed MODULES_ANALYTICS_4 site goals settings in beforeEach
    • Verify widgets render with default selections when settings are empty
    • Test with seeded visitor engagement settings to verify persisted settings drive widget behavior
  • Update story files (selection-panel/index.stories.tsx, OnlineStorePerformanceWidget.stories.tsx, LeadGenerationPerformanceWidget.stories.tsx)

    • Seed MODULES_ANALYTICS_4 site goals settings in common setup
  • Add PHP unit tests for Site_Goals_Settings

    • get() returns empty array by default
    • merge() saves goalDrivers and visitorEngagement correctly
    • merge() with partial data preserves existing settings
    • merge() ignores unknown keys
    • Sanitize callback strips non-string values, handles invalid input
  • Add PHP unit tests for Get_Site_Goals_Settings and Save_Site_Goals_Settings datapoints

    • GET returns saved settings or empty default
    • POST merges partial settings and returns updated result
    • Permission checks

QA Brief

Changelog entry

  • Update Site Goals settings to be persisted in the user settings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0High priorityTeam SIssues for Squad 1Type: EnhancementImprovement of an existing feature

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions