Connectors: Replace apiFetch with core-data store selectors#76333
Connectors: Replace apiFetch with core-data store selectors#76333jorgefilipecosta merged 2 commits intotrunkfrom
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: 0 B Total Size: 6.89 MB ℹ️ View Unchanged
|
|
Flaky tests detected in 7a6bb14. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/22904696226
|
Is this intentional? We can also replace these calls. I didn't push the code, but here's the diff: diff --git a/routes/connectors-home/use-connector-plugin.ts b/routes/connectors-home/use-connector-plugin.ts
index 73d2e00fd61..6843cb2abcd 100644
--- a/routes/connectors-home/use-connector-plugin.ts
+++ b/routes/connectors-home/use-connector-plugin.ts
@@ -1,7 +1,6 @@
/**
* WordPress dependencies
*/
-import apiFetch from '@wordpress/api-fetch';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect, useDispatch } from '@wordpress/data';
import { useState } from '@wordpress/element';
@@ -155,11 +154,12 @@ export function useConnectorPlugin( {
}
setIsBusy( true );
try {
- await apiFetch( {
- method: 'POST',
- path: '/wp/v2/plugins',
- data: { slug: pluginSlug, status: 'active' },
- } );
+ await saveEntityRecord(
+ 'root',
+ 'plugin',
+ { slug: pluginSlug, status: 'active' },
+ { throwOnError: true }
+ );
setPluginStatusOverride( 'active' );
// Re-fetch settings since the new plugin may register new settings.
invalidateResolution( 'getEntityRecord', [ 'root', 'site' ] );
@@ -177,11 +177,12 @@ export function useConnectorPlugin( {
}
setIsBusy( true );
try {
- await apiFetch( {
- method: 'PUT',
- path: `/wp/v2/plugins/${ pluginSlug }/plugin`,
- data: { status: 'active' },
- } );
+ await saveEntityRecord(
+ 'root',
+ 'plugin',
+ { plugin: `${ pluginSlug }/plugin`, status: 'active' },
+ { throwOnError: true }
+ );
setPluginStatusOverride( 'active' );
// Re-fetch settings since the activated plugin may register new settings.
invalidateResolution( 'getEntityRecord', [ 'root', 'site' ] ); |
There was a problem hiding this comment.
Pull request overview
This PR refactors the Connectors “use-connector-plugin” hook to rely on @wordpress/core-data entities (via useSelect/useDispatch) instead of direct apiFetch for reading site settings and plugin status, aiming to centralize caching and share resolver results across connector instances.
Changes:
- Read API key settings from
getEntityRecord( 'root', 'site' )rather than per-connector/wp/v2/settingsrequests. - Read plugin status from
getEntityRecords( 'root', 'plugin' )rather than imperative/wp/v2/pluginsfetching in an effect. - Save/remove API keys via
saveEntityRecord( 'root', 'site' ), keepingapiFetchonly for install/activate mutations and invalidating the site settings resolution afterward.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| setPluginStatusOverride( 'active' ); | ||
| // Re-fetch settings since the activated plugin may register new settings. | ||
| invalidateResolution( 'getEntityRecord', [ 'root', 'site' ] ); | ||
| setIsExpanded( true ); |
There was a problem hiding this comment.
After activating the plugin via apiFetch( PUT /wp/v2/plugins/... ), the hook only invalidates the site settings resolution. The root/plugin entity records remain cached, so derivedPluginStatus (and other connector cards) may not reflect activation without a reload. Invalidate the getEntityRecords resolution for ['root','plugin'] (and/or clear the local override once the refreshed store state is available) to keep store-driven status consistent across connectors.
| // Local override for immediate UI feedback after install/activate. | ||
| const [ pluginStatusOverride, setPluginStatusOverride ] = | ||
| useState< PluginStatus | null >( null ); |
There was a problem hiding this comment.
pluginStatusOverride is set to 'active' after install/activate, but it’s never cleared. This can leave the UI permanently reporting active even if the core-data root/plugin entity stays stale (or later changes), and it can also carry across prop changes (e.g. a different pluginSlug). Consider clearing the override once the derived status is 'active' (or whenever pluginSlug changes) so the hook returns to the canonical store-derived status.
| setPluginStatusOverride( 'active' ); | ||
| // Re-fetch settings since the new plugin may register new settings. | ||
| invalidateResolution( 'getEntityRecord', [ 'root', 'site' ] ); | ||
| setIsExpanded( true ); |
There was a problem hiding this comment.
After installing the plugin via apiFetch( POST /wp/v2/plugins ), the core-data getEntityRecords( 'root', 'plugin' ) cache is not invalidated/refetched. This means other connector instances (and derivedPluginStatus) can remain at not-installed/inactive until a hard refresh, defeating the goal of shared store state. In addition to the local override, invalidate the getEntityRecords resolution for ['root','plugin'] (or dispatch a store update) so the plugin list refreshes for all consumers.
gziolo
left a comment
There was a problem hiding this comment.
This is a solid improvement over the previous implementation — replacing per-connector apiFetch calls with shared core-data resolvers eliminates redundant network requests and aligns the hook with standard Gutenberg data layer patterns. The fallback logic for users without activate_plugins capability is nicely handled.
One thing to note: after install/activate, only getEntityRecord('root', 'site') is invalidated but getEntityRecords('root', 'plugin') is not — so the store-driven plugin status would remain stale if the component remounts before a full page reload. The pluginStatusOverride masks this in the current session, but adding an invalidation for ['root', 'plugin'] would keep things consistent.
Worth exploring @Mamaduka's suggestion to also replace the remaining apiFetch calls for install/activate with saveEntityRecord('root', 'plugin', ...). That would let the store auto-update the plugin entity records, removing the need for both the pluginStatusOverride workaround and the manual plugin invalidation. The site settings invalidation would still be necessary though, since activating a plugin can register new settings that weren't previously in the response.
|
My suggestion should resolve the |
Replace direct apiFetch calls in use-connector-plugin with
@wordpress/data store patterns (useSelect/useDispatch) so that
settings and plugin data are fetched once via core-data resolvers
and shared across all connector instances.
- Read settings via getEntityRecord('root', 'site') instead of
per-field GET /wp/v2/settings requests
- Read plugin status via getEntityRecords('root', 'plugin')
instead of imperative GET /wp/v2/plugins in a useEffect
- Save/remove API keys via saveEntityRecord('root', 'site')
instead of POST /wp/v2/settings, with improved validation
that also catches empty return values from the server
- Keep apiFetch only for install/activate plugin mutations,
with invalidateResolution to refresh settings afterward
dac7231 to
a2e9d06
Compare
| // After install/activate, if settings re-fetch reveals an existing key, | ||
| // update connected state (mirrors what the server would report on page load). | ||
| useEffect( () => { | ||
| if ( pluginStatusOverride === 'active' && currentApiKey ) { | ||
| setConnectedState( true ); | ||
| } | ||
| }, [ pluginStatusOverride, currentApiKey ] ); |
There was a problem hiding this comment.
Can we avoid this state syncing and just derive the connected state? I see that we're doing almost the same above.
There was a problem hiding this comment.
Good point, I removed the effect.
Replace all direct apiFetch calls in use-connector-plugin with
@wordpress/data store patterns (useSelect/useDispatch) so that
settings and plugin data are fetched once via core-data resolvers
and shared across all connector instances.
- Read settings via getEntityRecord('root', 'site') instead of
per-field GET /wp/v2/settings requests
- Read plugin status via getEntityRecords('root', 'plugin')
instead of imperative GET /wp/v2/plugins in a useEffect
- Save/remove API keys via saveEntityRecord('root', 'site')
instead of POST /wp/v2/settings, with improved validation
that also catches empty return values from the server
- Install/activate plugins via saveEntityRecord('root', 'plugin')
instead of direct POST/PUT to /wp/v2/plugins
- Remove apiFetch import entirely — no longer used
a2e9d06 to
7a6bb14
Compare
Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org> Co-authored-by: gziolo <gziolo@git.wordpress.org> Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
|
I just cherry-picked this PR to the wp/7.0 branch to get it included in the next release: 75640fb |
|
Thanks for the follow-ups, @jorgefilipecosta! |
This updates the pinned hash from the `gutenberg` from `9b8144036fa5faf75de43d4502ff9809fcf689ad` to `8c78d87453509661a9f28f978ba2c242d515563b`. The following changes are included: - Navigation Editor: Allow any blocks to be inserted by gating contentOnly insertion rules to section blocks (WordPress/gutenberg#76189) - Add `fetchpriority=low` to `IMG` tags in collapsed Details blocks (WordPress/gutenberg#76269) - Connectors: Add logo URL support for custom AI providers (WordPress/gutenberg#76190) - Cover Block: Add a playlist parameter to loop YouTube background videos. (WordPress/gutenberg#76004) - Connectors: Memoize getConnectors selector (WordPress/gutenberg#76339) - HTML Block: Fix broken layout (WordPress/gutenberg#76278) - Tests: Skip connector logo URL tests when AI Client is unavailable (WordPress/gutenberg#76343) - Navigation Overlay: Explicitly set fetchpriority for images (WordPress/gutenberg#76208) - Connectors: Show API key source for env vars and wp-config constants (WordPress/gutenberg#76355) - Connectors: Move API key validation and masking to REST dispatch level (WordPress/gutenberg#76327) - Connectors: Replace apiFetch with core-data store selectors (WordPress/gutenberg#76333) - Do not sync local attributes (WordPress/gutenberg#76267) - Add `fetchpriority=low` to `IMG` tags in collapsed Accordion Item blocks (WordPress/gutenberg#76336) - Implement disconnection debounce after initial connection (WordPress/gutenberg#76114) - Allow Post Content to be edited when 'Show template' is active and Post content is nested in a Template Part (WordPress/gutenberg#76305) - Fix: Document Bar: Back button flickers (WordPress/gutenberg#76320) - RTC: Move event hooks from editor to core-data (WordPress/gutenberg#76358) - fix(navigation): prevent right-justified submenu overflow in custom overlays (WordPress/gutenberg#76360) - Connectors: Add connectors registry for extensibility (WordPress/gutenberg#76364) - Connectors: Add empty state when no connectors are registered (WordPress/gutenberg#76375) - Temp: Disable RTC in the site editor (WordPress/gutenberg#76223) - Connectors: Add AI Experiments plugin callout with install/activate functionality (WordPress/gutenberg#76379) - Editor: Polish real-time collaboration presence UI and move Avatar to editor package (WordPress/gutenberg#75652) (WordPress/gutenberg#76365) - RTC: Add collaborator selection highlighting in rich text (WordPress/gutenberg#76107) - Sync changes from `wp_enqueue_global_styles()` to Gutenberg override (WordPress/gutenberg#76127) - [RTC] Fix performance regression on post save (WordPress/gutenberg#76370) - Media: Enable AVIF support for client-side uploads (WordPress/gutenberg#76371) - Connectors: Move plugin status computation to script module data (WordPress/gutenberg#76409) - Revisions: Skip rendered fields in REST API responses (WordPress/gutenberg#76347) - E2E Tests: Add connector setup flow tests with test AI provider (WordPress/gutenberg#76433) - RTC: Place sync connection modal in front of popover (WordPress/gutenberg#76431) - Connectors: Sync PHP code with WordPress Core (WordPress/gutenberg#76443) - Editor: Show own presence in collaborative editing sessions (WordPress/gutenberg#76413) (WordPress/gutenberg#76445) A full list of changes can be found on GitHub: https://github.com/WordPress/gutenberg/compare/9b8144036fa5faf75de43d4502ff9809fcf689ad…8c78d87453509661a9f28f978ba2c242d515563b. Log created with: git log --reverse --format="- %s" 9b8144036fa5faf75de43d4502ff9809fcf689ad..8c78d87453509661a9f28f978ba2c242d515563b | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy See #64595. git-svn-id: https://develop.svn.wordpress.org/trunk@61988 602fd350-edb4-49c9-b593-d223f7449a82
This updates the pinned hash from the `gutenberg` from `9b8144036fa5faf75de43d4502ff9809fcf689ad` to `8c78d87453509661a9f28f978ba2c242d515563b`. The following changes are included: - Navigation Editor: Allow any blocks to be inserted by gating contentOnly insertion rules to section blocks (WordPress/gutenberg#76189) - Add `fetchpriority=low` to `IMG` tags in collapsed Details blocks (WordPress/gutenberg#76269) - Connectors: Add logo URL support for custom AI providers (WordPress/gutenberg#76190) - Cover Block: Add a playlist parameter to loop YouTube background videos. (WordPress/gutenberg#76004) - Connectors: Memoize getConnectors selector (WordPress/gutenberg#76339) - HTML Block: Fix broken layout (WordPress/gutenberg#76278) - Tests: Skip connector logo URL tests when AI Client is unavailable (WordPress/gutenberg#76343) - Navigation Overlay: Explicitly set fetchpriority for images (WordPress/gutenberg#76208) - Connectors: Show API key source for env vars and wp-config constants (WordPress/gutenberg#76355) - Connectors: Move API key validation and masking to REST dispatch level (WordPress/gutenberg#76327) - Connectors: Replace apiFetch with core-data store selectors (WordPress/gutenberg#76333) - Do not sync local attributes (WordPress/gutenberg#76267) - Add `fetchpriority=low` to `IMG` tags in collapsed Accordion Item blocks (WordPress/gutenberg#76336) - Implement disconnection debounce after initial connection (WordPress/gutenberg#76114) - Allow Post Content to be edited when 'Show template' is active and Post content is nested in a Template Part (WordPress/gutenberg#76305) - Fix: Document Bar: Back button flickers (WordPress/gutenberg#76320) - RTC: Move event hooks from editor to core-data (WordPress/gutenberg#76358) - fix(navigation): prevent right-justified submenu overflow in custom overlays (WordPress/gutenberg#76360) - Connectors: Add connectors registry for extensibility (WordPress/gutenberg#76364) - Connectors: Add empty state when no connectors are registered (WordPress/gutenberg#76375) - Temp: Disable RTC in the site editor (WordPress/gutenberg#76223) - Connectors: Add AI Experiments plugin callout with install/activate functionality (WordPress/gutenberg#76379) - Editor: Polish real-time collaboration presence UI and move Avatar to editor package (WordPress/gutenberg#75652) (WordPress/gutenberg#76365) - RTC: Add collaborator selection highlighting in rich text (WordPress/gutenberg#76107) - Sync changes from `wp_enqueue_global_styles()` to Gutenberg override (WordPress/gutenberg#76127) - [RTC] Fix performance regression on post save (WordPress/gutenberg#76370) - Media: Enable AVIF support for client-side uploads (WordPress/gutenberg#76371) - Connectors: Move plugin status computation to script module data (WordPress/gutenberg#76409) - Revisions: Skip rendered fields in REST API responses (WordPress/gutenberg#76347) - E2E Tests: Add connector setup flow tests with test AI provider (WordPress/gutenberg#76433) - RTC: Place sync connection modal in front of popover (WordPress/gutenberg#76431) - Connectors: Sync PHP code with WordPress Core (WordPress/gutenberg#76443) - Editor: Show own presence in collaborative editing sessions (WordPress/gutenberg#76413) (WordPress/gutenberg#76445) A full list of changes can be found on GitHub: https://github.com/WordPress/gutenberg/compare/9b8144036fa5faf75de43d4502ff9809fcf689ad…8c78d87453509661a9f28f978ba2c242d515563b. Log created with: git log --reverse --format="- %s" 9b8144036fa5faf75de43d4502ff9809fcf689ad..8c78d87453509661a9f28f978ba2c242d515563b | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy See #64595. Built from https://develop.svn.wordpress.org/trunk@61988 git-svn-id: http://core.svn.wordpress.org/trunk@61270 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Summary
apiFetchcalls inuse-connector-pluginwith@wordpress/datastore patterns (useSelect/useDispatch) so settings and plugin data are fetched once via core-data resolvers and shared across all connector instancesgetEntityRecord('root', 'site')instead of per-fieldGET /wp/v2/settingsrequests — all connectors now share a single cached fetchgetEntityRecords('root', 'plugin')instead of an imperativeGET /wp/v2/pluginsin auseEffectsaveEntityRecord('root', 'site')with improved validation that catches both unchanged and empty return values from the serverapiFetchonly for install/activate plugin mutations, withinvalidateResolutionto refresh settings afterwardTest plan
/wp/v2/settingscall, not one per connector)activate_pluginscapability — should fall back to server-provided status