Add REST and datastore APIs for audience settings
Feature Description
Add REST and datastore APIs for audience settings. This essentially means the following REST endpoints:
-
GET audience-settings -
POST audience-settings
And the following datastore selectors and actions (including additional Redux infra as needed):
-
getConfiguredAudiences() -
haveConfiguredAudiencesChanged() -
setConfiguredAudiences() -
isAudienceSegmentationWidgetHidden() -
setAudienceSegmentationWidgetHidden() -
saveAudienceSettings()
See REST infrastructure and datastore configuration in the design doc.
Do not alter or remove anything below. The following sections will be managed by moderators only.
Acceptance criteria
REST API Endpoints Implementation
- Implement the
GET audience-settingsendpoint in theanalytics-4module to fetch user settings for audiences. This endpoint should return an object containing the following:-
configuredAudiences: An array, with a default value ofnull. -
isAudienceSegmentationWidgetHidden: A boolean, with a default value offalse.
-
- Implement the
POST audience-settingsendpoint in theanalytics-4module to update user settings for audiences. This endpoint should accept an object that may contain theconfiguredAudiencesarray and theisAudienceSegmentationWidgetHiddenboolean value, and update the corresponding settings.
Datastore Implementation
- Implement
getConfiguredAudiences()selector in theanalytics-4partial datastore. This selector should retrieve theconfiguredAudiencesarray from theGET audience-settingsendpoint. - Implement
haveConfiguredAudiencesChanged()in theanalytics-4partial datastore to check if the local state for the configured audiences has changed. - Implement
setConfiguredAudiences( audienceResourceNames )in theanalytics-4partial datastore to set the local state of the configured audiences. - Implement
isAudienceSegmentationWidgetHidden()selector in theanalytics-4partial datastore. This selector should retrieve the current value of theisAudienceSegmentationWidgetHiddensetting via theGET audience-settingsendpoint. - Implement
setAudienceSegmentationWidgetHidden( isWidgetHidden )action in theanalytics-4partial datastore. This action should update the local state of theisAudienceSegmentationWidgetHiddensetting. - Implement
saveAudienceSettings()action in theanalytics-4partial datastore. This action should persist the local state of the audience settings via thePOST audience-settingsendpoint.
Implementation Brief
REST API Endpoints
In includes/Modules/Analytics_4:
- [x] Create new class
Audience_Settingsthat extendsUser_Settingclass with the following:- [x] It should largely mirror the
Key_Metrics_Settingsclass. - [x] Replace the
OPTIONCONSTANT with the valuegooglesitekit_audience_settings. - [x] Replace
isWidgetHiddenwithisAudienceSegmentationWidgetHiddenandwidgetSlugswithconfiguredAudiences.
- [x] It should largely mirror the
In includes/Modules/Analytics_4.php:
- [x] In the
get_datapoint_definitions()method within theaudienceSegmentationfeature flag enabled block:- [x] Add a new
GET:audience-settingsendpoint to fetch audience user settings. - [x] Add a new
POST:audience-settingsendpoint to update audience user settings.
- [x] Add a new
- [x] In the
create_data_request()method:- [x] Add a case for the new
GET:audience-settingsendpoint to fetch audience user settings.- [x] Use the
Audience_Settings::get()method to retrieve thegooglesitekit_audience_settingsoption. - [x] Return the
configuredAudiencesandisAudienceSegmentationWidgetHiddensettings.
- [x] Use the
- [x] Add a case for the new
POST:audience-settingsendpoint to update the user settings for audiences.- [x] Validate the request data and ensure the
configuredAudiencesis an array andisAudienceSegmentationWidgetHiddenis a boolean. - [x] Use the
Audience_Settings::merge()method to update thegooglesitekit_audience_settingsoption. - [x] Return the updated
configuredAudiencesandisAudienceSegmentationWidgetHiddensettings.
- [x] Validate the request data and ensure the
- [x] Add a case for the new
Fetch Stores
- [x] Create a new file named
audience-settings.jswithin theassets/js/modules/analytics-4/datastore/directory. - [x] Utilize
createFetchStoreto establish fetch stores for theGET audience-settingsandPOST audience-settingsendpoints. These stores will handle fetching and updating the audience settings from the REST API. - [x] These can share the same reducer using the
createReducerfunction from theImmerlibrary. It should set both theaudienceSettings.settingsandaudienceSettings.savedSettingsproperties in the state.- [x] For
GET audience-settings:- [x] Define a base name, such as
getAudienceSettings. - [x] The store should manage to fetch the audience settings, including
configuredAudiencesandisAudienceSegmentationWidgetHidden.
- [x] Define a base name, such as
- [x] For
POST audience-settings:- [x] Define a base name, such as
saveAudienceSettings. - [x] Validate the request data and ensure the
configuredAudiencesis an array andisAudienceSegmentationWidgetHiddenis a boolean.
- [x] Define a base name, such as
- [x] For
Base Initial State
- [x] Add
audienceSettingsto the initial state with the value of an empty object. - [x] Eventually, the
audienceSettingsobject will containsettingsandsavedSettingsproperties.
Resolvers
- [x] Implement a resolver for
*getAudienceSettings()to ensure that the audience settings are fetched from the server when the data is not already present in the state. - [x] The resolver should check the existing state to determine if the fetch has already occurred to prevent unnecessary network requests.
Selectors
- [x]
getAudienceSettings(): This selector should return theaudienceSettings.settingsstate. - [x]
getConfiguredAudiences(): Use thegetAudienceSettingsselector to retrieve theconfiguredAudiencesarray from the audience settings. - [x]
isAudienceSegmentationWidgetHidden(): Use thegetAudienceSettingsselector to retrieve theisAudienceSegmentationWidgetHiddensetting from the audience settings. - [x]
haveConfiguredAudiencesChanged(): This selector should return the result of a comparison between thesettingsandsavedSettingsproperties of theaudienceSettingsstate.
Actions
- [x]
setConfiguredAudiences( audienceResourceNames ): This action should locally update the list of configured audiences of theaudienceSettings.settingsstate. - [x]
setAudienceSegmentationWidgetHidden( isWidgetHidden ): This action should locally update theisAudienceSegmentationWidgetHiddensetting of theaudienceSettings.settingsstate. - [x]
saveAudienceSettings(): This action should call the fetch store-generatedfetchSaveAudienceSettingsaction with the currentaudienceSettings.settingsstate.
Test Coverage
- [x] Add tests for the
Audience_Settingsclass methods. - [x] Unit tests should be created for the new selectors and actions.
QA Brief
- Make sure you have Site Kit set up with Google Analytics 4.
- Ensure the
audienceSegmentationfeature flag is enabled. - Open the developer tools in your browser and navigate to the console tab.
- Execute the following newly added audience settings actions and selectors in the console.
Actions
Action: setConfiguredAudiences( audienceResourceNames: Array<string> )
-
Execute the action by running the following command:
googlesitekit.data.dispatch('modules/analytics-4').setConfiguredAudiences( [ 'audienceResourceName1', 'audienceResourceName2' ] ) -
Verify that the action has updated the client-side state correctly.
-
Run the selector to double-check:
googlesitekit.data.select('modules/analytics-4').getConfiguredAudiences()It should return the updated array.
Action: setAudienceSegmentationWidgetHidden( isWidgetHidden: boolean )
-
Execute the action by running the following command:
googlesitekit.data.dispatch('modules/analytics-4').setAudienceSegmentationWidgetHidden( true ) -
Verify that the action has updated the client-side state correctly.
-
Run the selector to double-check:
googlesitekit.data.select('modules/analytics-4').isAudienceSegmentationWidgetHidden()It should return the updated boolean value.
Action: saveAudienceSettings()
-
Execute the action by running the following command:
googlesitekit.data.dispatch('modules/analytics-4').saveAudienceSettings() -
Check the network tab for a
POSTrequest toaudience-settingsand verify that the request payload contains the correct data if the state has changed.
Selectors
Selector: getAudienceSettings(): Object
-
Execute the selector:
googlesitekit.data.select('modules/analytics-4').getAudienceSettings() -
Verify that it either returns the correct object with
configuredAudiencesandisAudienceSegmentationWidgetHiddenproperties or triggers a network request to fetch the audience settings.
Selector: getConfiguredAudiences(): Array<string>
-
Execute the selector:
googlesitekit.data.select('modules/analytics-4').getConfiguredAudiences() -
Verify that it returns the array of configured audience resource names or an empty array.
Selector: isAudienceSegmentationWidgetHidden(): boolean
-
Execute the selector:
googlesitekit.data.select('modules/analytics-4').isAudienceSegmentationWidgetHidden() -
Verify that it returns the boolean value of
isAudienceSegmentationWidgetHidden.
Selector: haveConfiguredAudiencesChanged(): boolean
-
Execute the selector:
googlesitekit.data.select('modules/analytics-4').haveConfiguredAudiencesChanged() -
Verify that it returns a boolean value indicating whether the
configuredAudienceshave changed.
Changelog entry
- Introduce infrastructure for managing Audience settings.
- A new
GET audience-settingsendpoint should be implemented to fetch user settings for audiences in theanalytics-4module. This endpoint should return an object containing the keyisAudienceSegmentationWidgetHiddenwith a boolean value. The default value for this key should befalse.
@hussain-t, I think the default value should be the one selected by the primary admin (module owner), right? See the design doc:
When the feature has been set up, all subsequent users (i.e. view-only and secondary admin users)
will see the audience selection of the primary admin until they make a change themselves. After this
point, their own settings will take precedence and there will be no way to revert to the primary
admin’s settings.
https://docs.google.com/document/d/1MGD5Djy6AeeZC4zBtHqS-lQEWD9jw0kf-IIWw-jLCFU/edit?tab=t.0#heading=h.q4hnjsnlu3ha
@eugene-manuilov @hussain-t actually, per-user settings are fine here.
For one thing this setting was not intended to follow the primary admin's.
More importantly to be aware of though, is we're actually removing this primary/secondary user settings aspect altogether due to complications with that approach.
Instead, we are going to take the approach where each user's settings are initialised according to some logic and don't attempt to follow a root setting at all (see this comment thread on the design doc).
I will be updating the design doc soon, apologies for the confusion in the meantime!
Ok, thanks, @techanvil. So the default value should be neither false nor the primary admin's selection, but the value set in the Analytics settings, right? Then how is it going to work for the beginning, when nobody has selected it yet?
For example, if I am the first one who selects to show the feature, then my user settings will be updated as well as the Analytics settings, right? But then, if I decide to turn it off, then it will be turned off only for me and all other users will continue seeing it, right? So, to turn it off for all users, everyone will need to go to the settings and manually turn it off for themselves?
@eugene-manuilov, I think the default value should be false - it's similar to the isWidgetHidden Key Metrics setting which is a user setting:
https://github.com/google/site-kit-wp/blob/c173f6c206ce0b7f2eb0777b0acfe3bfe649c385/includes/Core/Key_Metrics/Key_Metrics_Settings.php#L48-L53
This KM setting already works in the same way - each (admin) user controls their own setting, there's no way to toggle it for all users.
There is admittedly a bit of a functionality gap for view-only users - both for Audience Segmentation, and for KM as it stands. I have raised this with Mariya in a thread on the design doc. Seeing as KM already works like this I suspect we'll continue as specced for the most part, but it might be worth waiting for her thoughts on this before we finalise the AC here.
Update: Due to ongoing changes to the design doc, we may well want to expand the scope of this issue to include the additional configuredAudiences setting.
Let's hold off until this additional thread on the design doc is also resolved.
Update: With Evan having approved the changes, and Mariya already having given her general approval for the direction (so really just needing to sign off on the details), it's clear we will be including configuredAudiences in these settings and not continuing with the previous specced two tier settings approach.
Therefore, I have updated the datastore configuration in the design doc, and updated the Feature Description for this issue accordingly. @hussain-t, please note that the definition for setAudienceSegmentationWidgetHidden() has changed as a result for consistency with the configuredAudiences related functions. The GET:audience-settings endpoint definition has also been tweaked to include configuredAudiences.
Although there are still a few last details to approve in the threads linked in the previous two comments, I think we can now safely proceed with this issue as specified.
Thanks, @techanvil 👍
Thanks, @hussain-t and @techanvil. AC ✔️
@hussain-t, as discussed on Slack the AC does need a small tweak:
We can't use
getConfiguredAudiences()to return the value forisAudienceSegmentationWidgetHidden()becausegetConfiguredAudiences()only returnsconfiguredAudiencesand notisAudienceSegmentationWidgetHidden.
I've assigned this back to you in AC for an update.
Thanks, @techanvil. I have updated the AC to retrieve the current value of the isAudienceSegmentationWidgetHidden setting directly via the GET audience-settings endpoint.
Thanks @hussain-t, the AC LGTM :white_check_mark:
Assigning to you in IB as requested. Remember, we don't literally have to directly fetch the value from GET audience-settings in each selector, we can create additional Redux infrastructure as needed e.g. a common getAudienceSettings() and so forth.
In
includes/Modules/Analytics_4.php:
- [ ] Create a constant for
audience-settingswith the valuegooglesitekit_audience_settings.- [ ] ...
- [ ] In the
create_data_request()method:
- [ ] Add a case for the new
GET:audience-settingsendpoint to fetch audience user settings.
- [ ] Use the
User_Options::get()method to retrieve thegooglesitekit_audience_settingsoption.- [ ] ...
- [ ] Add a case for the new
POST:audience-settingsendpoint to update the user settings for audiences.
- [ ] ...
- [ ] Use the
User_Options::set()method to update thegooglesitekit_audience_settingsoption.- [ ] ...
@hussain-t, we should not use the User_Options class directly. Instead we need to create a new class that extends User_Setting in the Analytics_4 namespace and use it in the Analytics_4 module. Everything else is good.
IB ✔️
QA Update ✅
- Tested on dev environment.
- Verified all Actions and Selectors under QAB.
- Verified all Actions and Selectors giving expected results.
Action: setConfiguredAudiences( audienceResourceNames: Array
Action: setAudienceSegmentationWidgetHidden( isWidgetHidden: boolean )
Action: saveAudienceSettings()
Changed boolean value from true to false -
Change settings -
SELECTORS
Selector: getAudienceSettings(): Object
Selector: getConfiguredAudiences(): Array
Selector: isAudienceSegmentationWidgetHidden(): boolean
Selector: haveConfiguredAudiencesChanged(): boolean
On changing the configured audiences it return the value true -