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

Skip to content

Persist the state of rendered Site Goals widgets in the database #12859

Description

@jimmymadon

Feature Description

In #12765, we abruptly prevent showing the widget if an event provider is deactivated after the widget was setup - this should not be the case for now. In the future, Issues #12773 and #12774 will implement a flow with appropriate notices to remove the widget with the user's full understanding. So for now, the Site Goals widgets should rely on a persisted state for their rendering: once a widget has been shown, it should stay shown even if the underlying conditions later change (e.g. the corresponding event provider plugin is deactivated, or events stop being detected).

Furthermore, both the new internal feature metric (#12776) and the Site Health debug field (#12601) need to know which Site Goals widgets (Online store performance / Lead generation performance) are currently shown to the user. Rather than recomputing the Widget Rendering Conditions (implemented in #12765) in multiple places, we should compute this state once and persist it server-side in the database, so it can be read by any consumer.


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

Acceptance criteria

  • A Site Goals widget should become "active" when its rendering conditions are met:
    • ecommerce: at least one e-commerce event is detected and at least one e-commerce event provider plugin (WooCommerce or Easy Digital Downloads) is active.
    • lead: at least one lead event is detected and at least one lead event provider plugin (Contact Form 7, Mailchimp, Ninja Forms, OptinMonster, Popup Maker or WPForms) is active.
  • The active state of the widgets should be persisted in the database as a new site-wide setting.
  • Once a widget has become active, it must remain active even if its rendering conditions are no longer met.
  • The persisted state should be readable in both the standard and view-only dashboard contexts.

Implementation Brief

  • Add categorized event-name constants to includes/Modules/Analytics_4/Conversion_Reporting/Conversion_Reporting_Events_Sync.php, mirroring the JS constants CONVERSION_REPORTING_LEAD_EVENTS / CONVERSION_REPORTING_ECOMMERCE_EVENTS in assets/js/modules/analytics-4/datastore/constants.ts:
    • LEAD_EVENT_NAMES = array( 'contact', 'generate_lead', 'submit_lead_form' )
    • ECOMMERCE_EVENT_NAMES = array( 'purchase', 'add_to_cart' )
  • In includes/Core/Conversion_Tracking/Conversion_Tracking.php, extract the provider-category logic currently inlined in inline_js_base_data() (which sets hasActiveLeadEventProviders / hasActiveEcommerceEventProviders from Hide Site Goals widgets if corresponding event provider plugins are not installed #12765) into a new public get_active_provider_categories() method returning the unique get_category() values of get_active_providers() (a subset of array( Conversion_Events_Provider::CATEGORY_LEAD, Conversion_Events_Provider::CATEGORY_ECOMMERCE )). Refactor inline_js_base_data() to use it.
  • Free up the Modules\Analytics_4\Site_Goals_Settings class name by moving the existing per-user Site Goals settings class (introduced in Add Site goals user settings and persist Site Goals side panel metric selections #12780, currently includes/Modules/Analytics_4/Site_Goals_Settings.php, extends User_Setting) into the Core/User namespace — similar to the existing Core/User/Audience_SettingsModules/Analytics_4/Audience_Settings split:
    • Move it to includes/Core/User/Site_Goals_Settings.php (Google\Site_Kit\Core\User\Site_Goals_Settings) and change its OPTION from googlesitekit_analytics-4_site_goals_settings to googlesitekit_site_goals_settings.
    • Update the use imports / references in Get_Site_Goals_Settings, Save_Site_Goals_Settings and Analytics_4 to the new namespace. To avoid confusion with the new site-wide class below, hold the per-user instance under a distinct property (e.g. $this->user_site_goals_settings) and update the datapoint wiring accordingly.
  • Add the new site-wide setting class to persist the active-widgets state, following the site-wide Audience_Settings pattern (includes/Modules/Analytics_4/Audience_Settings.php):
    • Create includes/Modules/Analytics_4/Site_Goals_Settings.php (Google\Site_Kit\Modules\Analytics_4\Site_Goals_Settings) extending Setting and implementing Setting_With_ViewOnly_Keys_Interface, with OPTION = 'googlesitekit_analytics-4_site_goals_settings' (the module-prefixed name, freed up by the move above).
    • Single key activeWidgets defaulting to array(); sanitize to a unique subset of array( 'ecommerce', 'lead' ) (reuse Sanitize::sanitize_string_list and filter to the allowed enum values).
    • Mark activeWidgets as a view-only key so it is exposed in the view-only dashboard.
    • Add a merge() helper (as the site-wide Audience_Settings does) that unions the incoming categories with the existing ones and never drops existing values.
    • Instantiate and register() it in Analytics_4::register() alongside audience_settings, and store it on a $site_goals_settings property (mirroring $this->audience_settings).
  • Persist the state during the detected-events sync. In Conversion_Reporting_Provider::cron_callback(), after sync_detected_events() computes the current detectedEvents:
    • Compute the qualifying widget categories: include ecommerce when ECOMMERCE_EVENT_NAMES intersects the detected events and Conversion_Events_Provider::CATEGORY_ECOMMERCE is in Conversion_Tracking::get_active_provider_categories(); include lead analogously.
    • merge() these into the site-wide Site_Goals_Settings (union with existing activeWidgets), so the value only ever grows. Conversion_Tracking can be instantiated from the Context already available to the provider.
  • Make the Site Goals widgets render from the persisted state:
    • Expose activeWidgets to JS through the existing modules/analytics-4 settings datastore (it is part of the registered setting and a view-only key), and add a small selector/helper to read whether a given category is active.
    • Update the isActive callbacks of the analyticsOnlineStorePerformance and analyticsLeadGenerationPerformance widgets in assets/js/modules/analytics-4/widgets/index.js so a widget renders when its category is present in activeWidgets.

Test Coverage

  • Add a Site_Goals_SettingsTest for the new site-wide class (mirroring tests/phpunit/integration/Modules/Analytics_4/Audience_SettingsTest.php) asserting the default is an empty array, that the sanitize callback drops invalid values and de-duplicates, and that only ecommerce/lead are allowed. Move/update the existing per-user Site_Goals_Settings test to match its new Core/User namespace and option name.
  • In tests/phpunit/integration/Core/Conversion_Tracking/Conversion_TrackingTest.php, add test_get_active_provider_categories() covering no providers, lead only, ecommerce only, and both (using the existing FakeLeadEventProvider_Active / FakeEcommerceEventProvider_Active fixtures), and confirm the existing test_inline_js_base_data__* tests still pass after the refactor.
  • Add sync-level tests (alongside the existing Conversion_Reporting_Events_Sync / Conversion_Reporting_Provider tests) asserting:
    • Detected events of a set with no active provider of that category => category is not added.
    • Active provider of a category with no detected events of that set => category is not added.
    • Both conditions met => category is added to activeWidgets.
    • Stickiness: once a category is persisted, a subsequent sync where the conditions are no longer met leaves it in activeWidgets.
    • Both categories can be present simultaneously.
  • Add JS tests for the widget isActive logic (alongside assets/js/modules/analytics-4/widgets/index.test.js) asserting that each Site Goals widget renders when its category is in activeWidgets even when the live conditions are not met, and renders via the live conditions when activeWidgets is still empty.

QA Brief

  • Setup SK with siteGoals feature flag, Analytics connected, Tester plugin installed.
  • After changing detected events/plugins, trigger the conversion-reporting events sync cron using WP Crontrol (googlesitekit_cron_conversion_reporting_events action). Inspect state with wp option get googlesitekit_analytics-4_site_goals_settings (or check in the wp_options table).
  • Tester Settings → Analytics → Conversion reporting, set an ecommerce event (e.g. purchase).
  • Activate WooCommerce (or Easy Digital Downloads) and trigger the sync.
  • Verify the Online store performance widget shows and activeWidgets contains ecommerce.
  • Deactivate the plugin and re-sync → verify the widget still shows (sticky).
  • Repeat with a lead event (e.g. contact) and a lead plugin (e.g. Contact Form 7).
  • Verify the Lead generation performance widget shows and activeWidgets contains lead.
  • Deactivate the plugin and re-sync → verify the widget still shows.
  • Event detected but no matching provider active → widget does not show / category not added.
  • Provider active but no matching event → widget does not show / category not added.
  • Confirm the persisted widget also renders in the view-only dashboard.

Changelog entry

  • Site Goals widget status are now site-wide with other settings being user-specific.

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Fields

    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