Skip to content

Clone global data when bootstrapping datastores.#12824

Open
techanvil wants to merge 10 commits into
developfrom
enhancement/5798-add-global-data-helper
Open

Clone global data when bootstrapping datastores.#12824
techanvil wants to merge 10 commits into
developfrom
enhancement/5798-add-global-data-helper

Conversation

@techanvil

@techanvil techanvil commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Addresses issue:

Relevant technical choices

I've only used the getGlobalData() helper where the retrieved data is an object, not a primitive. Using in all cases adds a lot of extra error logging which complicates testing and doesn't add any real value, as the main point of this helper is to clone structured data.

PR Author Checklist

  • My code is tested and passes existing unit tests.
  • My code has an appropriate set of unit tests which all pass.
  • My code is backward-compatible with WordPress 5.2 and PHP 7.4.
  • My code follows the WordPress coding standards.
  • My code has proper inline documentation.
  • I have added a QA Brief on the issue linked above.
  • I have signed the Contributor License Agreement (see https://cla.developers.google.com/).

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

Code Reviewer Checklist

  • Run the code.
  • Ensure the acceptance criteria are satisfied.
  • Reassess the implementation with the IB.
  • Ensure no unrelated changes are included.
  • Ensure CI checks pass.
  • Check Storybook where applicable.
  • Ensure there is a QA Brief.
  • Ensure there are no unexpected significant changes to file sizes.

Merge Reviewer Checklist

  • Ensure the PR has the correct target branch.
  • Double-check that the PR is okay to be merged.
  • Ensure the corresponding issue has a ZenHub release assigned.
  • Add a changelog message to the issue.

@techanvil techanvil force-pushed the enhancement/5798-add-global-data-helper branch from fc16153 to 6f29e30 Compare June 2, 2026 10:03
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

🤖 This comment is automatically updated by CI workflows. Each section is managed independently.

🎭 Playwright reports for 8650016:

📚 Storybook for 8650016:

📦 Build files for 8650016:

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 2.92 MB

ℹ️ View Unchanged
Filename Size Change
dist/assets/blocks/reader-revenue-manager/block-editor-plugin/editor-styles.css 124 B 0 B
dist/assets/blocks/reader-revenue-manager/block-editor-plugin/editor-styles.js 0 B 0 B 🆕
dist/assets/blocks/reader-revenue-manager/block-editor-plugin/index.js 42.7 kB 0 B
dist/assets/blocks/reader-revenue-manager/common/editor-styles.css 307 B 0 B
dist/assets/blocks/reader-revenue-manager/common/editor-styles.js 0 B 0 B 🆕
dist/assets/blocks/reader-revenue-manager/contribute-with-google/index.js 5.8 kB 0 B
dist/assets/blocks/reader-revenue-manager/contribute-with-google/non-site-kit-user.js 5.01 kB 0 B
dist/assets/blocks/reader-revenue-manager/subscribe-with-google/index.js 5.81 kB 0 B
dist/assets/blocks/reader-revenue-manager/subscribe-with-google/non-site-kit-user.js 5 kB 0 B
dist/assets/blocks/sign-in-with-google/editor-styles.css 84 B 0 B
dist/assets/blocks/sign-in-with-google/editor-styles.js 0 B 0 B 🆕
dist/assets/blocks/sign-in-with-google/index.js 18.5 kB 0 B
dist/assets/css/googlesitekit-admin-css-********************.min.css 72.1 kB 0 B
dist/assets/css/googlesitekit-adminbar-css-********************.min.css 12.7 kB 0 B
dist/assets/css/googlesitekit-authorize-application-css-********************.min.css 851 B 0 B
dist/assets/css/googlesitekit-wp-dashboard-css-********************.min.css 9.07 kB 0 B
dist/assets/js/146-********************.js 960 B 0 B
dist/assets/js/201-********************.js 2.85 kB 0 B
dist/assets/js/273-********************.js 52.5 kB 0 B
dist/assets/js/314-********************.js 100 kB 0 B
dist/assets/js/315-********************.js 3.08 kB 0 B
dist/assets/js/379-********************.js 3.7 kB 0 B
dist/assets/js/397-********************.js 477 kB 0 B
dist/assets/js/590-********************.js 1.88 kB 0 B
dist/assets/js/640-********************.js 2.35 kB 0 B
dist/assets/js/909-********************.js 1.01 kB 0 B
dist/assets/js/analytics-advanced-tracking-********************.js 404 B 0 B
dist/assets/js/googlesitekit-activation-********************.js 25.1 kB 0 B
dist/assets/js/googlesitekit-ad-blocking-recovery-********************.js 61.2 kB +113 B (+0.18%)
dist/assets/js/googlesitekit-admin-pointers-tracking-********************.js 5.36 kB 0 B
dist/assets/js/googlesitekit-adminbar-********************.js 36.7 kB 0 B
dist/assets/js/googlesitekit-api-********************.js 8.04 kB 0 B
dist/assets/js/googlesitekit-block-tracking-********************.js 5.55 kB 0 B
dist/assets/js/googlesitekit-components-********************.js 6.21 kB 0 B
dist/assets/js/googlesitekit-consent-mode-********************.js 26 kB 0 B
dist/assets/js/googlesitekit-data-********************.js 1.88 kB +128 B (+7.31%) 🔍
dist/assets/js/googlesitekit-datastore-forms-********************.js 7.2 kB 0 B
dist/assets/js/googlesitekit-datastore-location-********************.js 1.64 kB +124 B (+8.17%) 🔍
dist/assets/js/googlesitekit-datastore-pdf-********************.js 1.2 kB 0 B
dist/assets/js/googlesitekit-datastore-site-********************.js 19 kB +121 B (+0.64%)
dist/assets/js/googlesitekit-datastore-ui-********************.js 7.36 kB 0 B
dist/assets/js/googlesitekit-datastore-user-********************.js 23.5 kB +155 B (+0.66%)
dist/assets/js/googlesitekit-entity-dashboard-********************.js 74.7 kB +123 B (+0.16%)
dist/assets/js/googlesitekit-events-provider-contact-form-7-********************.js 2.35 kB 0 B
dist/assets/js/googlesitekit-events-provider-easy-digital-downloads-********************.js 1.12 kB 0 B
dist/assets/js/googlesitekit-events-provider-mailchimp-********************.js 2.34 kB 0 B
dist/assets/js/googlesitekit-events-provider-ninja-forms-********************.js 2.3 kB 0 B
dist/assets/js/googlesitekit-events-provider-optin-monster-********************.js 2.22 kB 0 B
dist/assets/js/googlesitekit-events-provider-popup-maker-********************.js 2.44 kB 0 B
dist/assets/js/googlesitekit-events-provider-woocommerce-********************.js 1.08 kB 0 B
dist/assets/js/googlesitekit-events-provider-wpforms-********************.js 2.44 kB 0 B
dist/assets/js/googlesitekit-i18n-********************.js 4.43 kB 0 B
dist/assets/js/googlesitekit-key-metrics-setup-********************.js 55.4 kB +120 B (+0.22%)
dist/assets/js/googlesitekit-main-dashboard-********************.js 182 kB +124 B (+0.07%)
dist/assets/js/googlesitekit-metric-selection-********************.js 60.4 kB +122 B (+0.2%)
dist/assets/js/googlesitekit-modules-********************.js 27.2 kB +105 B (+0.39%)
dist/assets/js/googlesitekit-modules-ads-********************.js 47.8 kB +124 B (+0.26%)
dist/assets/js/googlesitekit-modules-adsense-********************.js 139 kB +100 B (+0.07%)
dist/assets/js/googlesitekit-modules-analytics-4-********************.js 215 kB +119 B (+0.06%)
dist/assets/js/googlesitekit-modules-pagespeed-insights-********************.js 23.5 kB 0 B
dist/assets/js/googlesitekit-modules-reader-revenue-manager-********************.js 53.7 kB +109 B (+0.2%)
dist/assets/js/googlesitekit-modules-search-console-********************.js 66.5 kB +102 B (+0.15%)
dist/assets/js/googlesitekit-modules-sign-in-with-google-********************.js 34.2 kB +111 B (+0.33%)
dist/assets/js/googlesitekit-modules-tagmanager-********************.js 31.1 kB +115 B (+0.37%)
dist/assets/js/googlesitekit-notifications-********************.js 69.2 kB +105 B (+0.15%)
dist/assets/js/googlesitekit-polyfills-********************.js 228 B 0 B
dist/assets/js/googlesitekit-settings-********************.js 137 kB +123 B (+0.09%)
dist/assets/js/googlesitekit-splash-********************.js 82.5 kB +114 B (+0.14%)
dist/assets/js/googlesitekit-user-input-********************.js 53.1 kB +116 B (+0.22%)
dist/assets/js/googlesitekit-vendor-********************.js 314 kB 0 B
dist/assets/js/googlesitekit-vendor-lazy-pdf-********************.js 8.33 kB 0 B
dist/assets/js/googlesitekit-widgets-********************.js 105 kB +126 B (+0.12%)
dist/assets/js/googlesitekit-wp-dashboard-********************.js 62 kB 0 B
dist/assets/js/runtime-********************.js 1.95 kB 0 B

compressed-size-action

@techanvil techanvil changed the title Enhancement/5798 add global data helper Clone global data when bootstrapping datastores. Jun 2, 2026

@aaemnnosttv aaemnnosttv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @techanvil – this LGTM, just a few suggestions worth considering.

I'm also curious if the underlying issue is still relevant for stores that use the Immer-based createReducer – I seem to recall that this might be doing this kind of dereferencing already anyways but you also worked on that and might know better off the top of your head?

Comment thread assets/js/googlesitekit/data/utils.js Outdated
Comment on lines +442 to +443
* @param {string} propertyName Property of the global data object.
* @param {string} [childPropertyName] Optional. Property of the object matched by `propertyName`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not to overcomplicate things, but why not use a path here like lodash.get accepts, in which case this could be much more flexible than parent [> child] only. We could also use get internally and return a clone of the value with some kind of not-found symbol perhaps as the default value?

@techanvil techanvil Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This occurred to me too, but I didn't want to stray too far from the IB. Using a Symbol for the not-found value is a good shout, I didn't think of that. I've applied your suggested change.

Comment thread assets/js/googlesitekit/data/utils.js Outdated
*
* @param {string} propertyName Property of the global data object.
* @param {string} [childPropertyName] Optional. Property of the object matched by `propertyName`.
* @return {*} The global data object, or the child property value if provided.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In the past we've defined the last parameter as _global = global to allow for cleaner DI in testing. E.g. createTrackEvent

Any reason not to do the same here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I don't see any reason not to - I've added _global as the last parameter.


it( 'should return the deep cloned global data object when no child property name is provided', () => {
const globalData = { foo: 'bar', baz: { qux: 'quux' } };
global[ propertyName ] = globalData;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we do end up using the real global here, we should ensure it's cleaned up afterEach to avoid leaking out of the test.

@techanvil techanvil Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good shout, but as per your suggestion I've switched to a mock global object.

email: 'admin@example.com',
name: 'admin',
picture: 'https://path/to/image',
full_name: 'Dr Funkenstein',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm glad we're keeping this 😄

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed!

@aaemnnosttv

Copy link
Copy Markdown
Collaborator

Once sync'd with develop, E2E should run again as well.

@techanvil

Copy link
Copy Markdown
Collaborator Author

Thanks @techanvil – this LGTM, just a few suggestions worth considering.

I'm also curious if the underlying issue is still relevant for stores that use the Immer-based createReducer – I seem to recall that this might be doing this kind of dereferencing already anyways but you also worked on that and might know better off the top of your head?

Thanks @aaemnnosttv, I've applied your suggestions.

Re. Immer, it looks like it clones on write, but uses the original object until this point, so this change may still provide some value to Immer-enabled stores.

@aaemnnosttv aaemnnosttv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @techanvil – not sure what happened here but my comments didn't go through before 🙈

Comment on lines +452 to +453
* @param {string} propertyName Property of the global data object.
* @param {string} [path] Optional. Path to a value of the object matched by `propertyName`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks! I might not have been entirely clear in my previous suggestion, or you may be preferring to stick closer to the IB like you said, but I was actually suggesting to collapse both propertyName and the optional childPropertyName into a single path, so this is more of a light wrapper around _.get with error handling. I don't feel super strongly about it, but it seems unnecessary to allow for two path arguments when the one supports both.

path = undefined,
_global = global
) {
if ( ! _global[ propertyName ] ) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This should probably be more specific to ! hasOwnProperty rather than a falsy value, no? I realize this is probably only going to be used with object values, but it's a bit inconsistent to throw an error only for the top-level path.

Following on my previous comment, WDYT about simplifying it to this?

function getGlobalData( path, _global ) {
    const value = _.get( _global, path );

    if ( value === undefined ) throw new Error();

	return cloneDeep( value );
}

_.get can't tell the difference between a set undefined value and missing value as the default value is returned for anything that resolves to undefined rather than something for sure missing/not-found, so my suggestion to add a symbol is probably over-complicating things 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants