Repository navigation
Connectors: Show filesystem credentials modal on plugin install - #78367
westonruter wants to merge 21 commits into
Conversation
When `FS_METHOD` is not `direct` and FTP credentials have not been stored, the REST `/wp/v2/plugins` endpoint rejects an install attempt up front, surfacing only a generic "Failed to install plugin" snackbar on the Connectors screen. Plugins > Add Plugin handles the same case by displaying the standard "Connection Information" modal. Print that modal on the Connectors screen, expose `filesystemCredentialsRequired` via the script module data, and route through `wp.updates.installPlugin()` when credentials are required so the legacy AJAX install path supplies them. After the install succeeds, activate via REST and refresh the plugin entity.
|
Size Change: 0 B Total Size: 8.21 MB ℹ️ View Unchanged
|
There was a problem hiding this comment.
Pull request overview
This PR fixes the Connectors plugin-install flow when the WordPress filesystem method is not direct (e.g. FTP), by mirroring Core’s standard “Connection Information” modal behavior so users have a clear path to provide credentials and complete installation.
Changes:
- Enqueues Core’s updates installer script and prints the filesystem credentials modal footer markup on the Connectors admin screen.
- Exposes a
filesystemCredentialsRequiredflag to the Connectors script module so the client can choose the correct install mechanism. - Updates the Connectors install hook to route through
wp.updates.installPlugin()when credentials are required, then activates via REST.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
lib/experimental/connectors/load.php |
Adds Connectors-screen setup for updates script + filesystem credentials modal, and exposes a “credentials required” flag to script module data. |
routes/connectors-home/use-connector-plugin.ts |
Adds a wp.updates-based install path when filesystem credentials are needed, and suppresses snackbar on user-cancel. |
routes/connectors-home/default-connectors.tsx |
Reads the new script module flag and passes it into the connector install hook. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Flaky tests detected in 530755e. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/26016663464
|
- Register the install event handlers with on()/off() instead of one() and filter by slug. With one(), a concurrent install of a different plugin firing first would consume the one-shot handler and leave the promise pending. on() + explicit cleanup() only tears down once the matching slug's event arrives. - Replace the brittle "cancel via hard-coded error message string" detection. installPluginViaWpUpdates() now resolves with 'installed' | 'canceled' so cancel is a normal control-flow outcome the caller branches on, while genuine install failures still reject. Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
I tested this PR locally with The provider connector cards now open the standard “Connection Information” filesystem credentials modal as expected. I tested this with the OpenAI connector, and canceling the modal returned the button back to I noticed one related case that still seems to use the old REST install path: the top “Install the AI plugin” callout. When clicking that button on the same Connectors screen, it shows “Failed to install the AI plugin.” instead of opening the filesystem credentials modal. Steps:
Expected: the standard filesystem credentials modal opens, matching the provider connector install flow. Actual: the install fails with the generic AI plugin install error. |
The "Install the AI plugin" button in AiPluginCallout had the same silent-failure bug as the connector install: it POSTed directly to the REST plugin endpoint, which rejects the install up front when FS_METHOD is not 'direct' and credentials have not been stored. Reuse the now-exported installPluginViaWpUpdates() helper so the AI plugin install routes through wp.updates.installPlugin() (surfacing the standard "Connection Information" modal) when credentials are required, then activates via REST. The non-FS path is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-fs-credentials Resolved a modify/delete conflict from trunk #78228, which relocated the Connectors loader out of lib/experimental/connectors/load.php and consolidated it into lib/compat/wordpress-7.0/connectors.php. The filesystem-credentials additions (the load-{hook} screen setup, the credentials-modal printer, and the script-module-data filter) were ported into the new connectors.php location; the obsolete experimental/connectors/load.php was removed (its default-connectors.php require is now handled directly by lib/load.php). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ekamran Great catch! This is fixed now in 8d3b1c2. The merge conflicts are also fixed in 9ae49aa after #78228, although this may cause problems if this is cherry-picked to |
|
Here's a screen recording showing the installation of the AI plugin via FTP: AI.plugin.install.via.FTP.mov(Ignore Chrome's warning about an insecure FTP password! |
If we intend to backport this PR to WP 7.0, we can backport #78228 to the |
request_filesystem_credentials() returns true (no credentials needed), false (needed but not provided), or an array (needed and provided). Only the explicit false sentinel should set filesystemCredentialsRequired, so compare with `false === $stored` instead of `! $stored`. This avoids coercing a (theoretical) empty-array return to "required" and matches the strict-boolean expectation of PHPStan, mirroring the Performance Lab counterpart which already uses the strict comparison. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for the follow-up fix here. I pulled the latest PR head ( After rebuilding the Gutenberg assets, I can confirm the UI behavior looks fixed for both paths I checked:
One thing I noticed while checking the latest branch: the targeted unit test for the AI plugin callout is still failing locally: npm run test:unit -- routes/connectors-home/test/ai-plugin-callout.tsx --runInBandFailure: From a quick look, |
|
I was also able to get the failing The patch updates the After that change, the focused test passes locally: npm run test:unit -- routes/connectors-home/test/ai-plugin-callout.tsx --runInBandHappy to share the patch or open a small follow-up PR if that would be helpful. |
|
@westonruter would it help if I build t-hamano's |
🤖 PR meta 🤖🎉 PropsIf 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. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
Updated as activity occurs, without notifying anyone named here. Add the 📦 Bundle sizeSize Change: 0 B Total Size: 8.63 MB
⚡ PerformanceShow the resultsClient side metrics exclude the server response time. front-end-block-theme
front-end-classic-theme
media-processing
media-upload
post-editor
site-editor
🏁 Flaky testsSome tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information. Navigates the items list via UP/DOWN arrow keys in
|
Resolve conflicts after trunk bumped the minimum WordPress version to 7.0 and moved to Vitest: - Move the Connectors filesystem credentials setup from the removed lib/compat/wordpress-7.0/connectors.php into lib/compat/plugin/connectors.php. - Drop the root @types/jquery devDependency, since root devDependencies were moved into workspaces, and use minimal local jQuery types instead. - Port the AiPluginCallout filesystem credentials tests to Vitest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVht4racQmKuYmELHoLXdx
…le error Instead of computing `filesystemCredentialsRequired` on the server and exposing it through script module data, attempt the standard REST plugin install first and fall back to `wp.updates.installPlugin()` only when the endpoint rejects with the `fs_unavailable` error code. The REST response becomes the single source of truth, and the PHP flag is removed. The Connectors screen still enqueues the `updates` script and prints the filesystem credentials modal so the fallback can show it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVht4racQmKuYmELHoLXdx
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: t-hamano <54422211+t-hamano@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01FVht4racQmKuYmELHoLXdx
|
@ekamran Thanks for the offer! I've resolved the conflicts with @westonruter, could you take a look when you have a chance? |
|
Thanks for picking this up. I tested the latest head ( The main flows work:
I found three issues:
For 2 and 3, I tried calling |
|
@jorgefilipecosta @westonruter this looks to be the remaining Connectors-related item slated for 7.2, so I'm checking in to see what this additionally needs to be ready for commit? |
|
Hi Jeff, from the testing side, this is what is still open. On this PR: the fs_unavailable approach works, but the three issues from my earlier comment are still open, as the head ( The branch also needs a trunk merge: the "Required changes from trunk" check is failing. On the core side, WordPress/wordpress-develop#13953 still adds the Happy to re-test both with the FTP setup once they are updated. |
t-hamano
left a comment
There was a problem hiding this comment.
Suggestions to fix the button getting stuck on "Installing…" when admin-ajax returns an invalid response, reported in #78367 (comment).
…nses Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com>
t-hamano
left a comment
There was a problem hiding this comment.
Suggestions to fix the remaining issues reported in #78367 (comment): the button still getting stuck on "Installing…" after credentials are entered, the modal opening with an error already shown, and focus being lost when the modal closes.
…sponses Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com>
…he active element Co-authored-by: t-hamano <54422211+t-hamano@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011g9URwXY34pb67XjPhYPjQ
|
49ca8c3 fixes the lint error from Instead of reading |
Co-authored-by: t-hamano <54422211+t-hamano@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011g9URwXY34pb67XjPhYPjQ
Co-authored-by: t-hamano <54422211+t-hamano@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011g9URwXY34pb67XjPhYPjQ
|
I believe all the issues raised here have now been addressed. Also, since the implementation changed from exposing a |
Important
The corresponding wordpress-develop backport PR has not been created yet. Once the approach is validated here and approved, the core PR will be created.Edited by @t-hamano: Core backport PR: WordPress/wordpress-develop#15889
Summary
Fixes the Connectors install flow when
FS_METHODis notdirect— for example,ftpext/ftpsockets. The current behavior is a generic "Failed to install plugin for X." snackbar with no path forward; Plugins > Add Plugin already handles the same case by showing the standard "Connection Information" modal.This PR mirrors that flow on the Connectors screen:
lib/experimental/connectors/load.php— on the Connectors page only, enqueuewp.updates, printwp_print_request_filesystem_credentials_modal()in the footer, and exposefilesystemCredentialsRequiredvia thescript_module_data_options-connectors-wp-adminfilter.routes/connectors-home/use-connector-plugin.ts— whenfilesystemCredentialsRequiredis true, route throughwp.updates.installPlugin()(which knows how to surface the FTP credentials modal, collect creds, and POST them with the install). After success, activate via the existing REST flow and refresh the plugin entity. Cancelling the modal silently aborts.routes/connectors-home/default-connectors.tsx— read the new flag and forward touseConnectorPlugin.Edited by @t-hamano:
lib/compat/plugin/connectors.php— on the Connectors page only, enqueuewp.updatesand printwp_print_request_filesystem_credentials_modal()in the footer.routes/connectors-home/use-connector-plugin.ts/ai-plugin-callout.tsx— install via the REST plugin endpoint first. If it rejects withfs_unavailable, fall back towp.updates.installPlugin(), which shows the FTP credentials modal, collects credentials, and POSTs them with the install. After success, activate via REST and refresh the plugin entity. Cancelling the modal silently aborts. Any other REST error shows the existing error notice.Fixes Core-65223.
Screenshots
Open AI plugin is not installed yet:
Clicking Install causes the FTP credentials modal to appear:
Providing credentials results in the plugin being active and ready for setup:
Test plan
Reproduces against an environment where the filesystem method requires credentials:
ai-provider-for-openai) is not installed.directfilesystem environment — the install proceeds via REST as before, no modal.Use of AI Tools
Claude Opus 4.7 was used to create the PR and validate the fix.
Claude prompt and conversation summary
Prompt
Investigation
FS_METHOD≠direct, while Plugins > Add Plugin handles it correctly.request_filesystem_credentials()+wp_print_request_filesystem_credentials_modal()inwp-admin/includes/file.phprender the "Connection Information" modal.wp.updates.installPlugin()(inwp-admin/js/updates.js) wraps the AJAX call, includes_fs_nonceand FTP credentials in the POST body, shows the modal whenshouldRequestFilesystemCredentialsis true, and fireswp-plugin-install-success/wp-plugin-install-errorjQuery events.useConnectorPluginhook callssaveEntityRecord( 'root', 'plugin', … ), which hitsWP_REST_Plugins_Controller::create_item. That controller callsis_filesystem_available(), which returns afs_unavailableWP_Errorup front whenever FS_METHOD isn'tdirectand no credentials are stored — so the REST endpoint can never accept FTP creds in its JSON body.lib/experimental/connectors/load.phpand the per-page enqueue/render is auto-generated frompackages/wp-build/templates/page-wp-admin.php.template(not safe to edit directly), so additions must hook off the connectors menu page specifically.Implementation (commit 171d758)
Branch:
fix/65223-connectors-fs-credentialsin WordPress/gutenberg.lib/experimental/connectors/load.php: capture the$hook_suffixfromadd_submenu_page()and register aload-{hook_suffix}action thatwp.updates, andadmin_footerto printwp_print_request_filesystem_credentials_modal()+wp_print_admin_notice_templates().Also added a
script_module_data_options-connectors-wp-adminfilter that exposesfilesystemCredentialsRequired: boolbased onget_filesystem_method()and stored credentials.routes/connectors-home/use-connector-plugin.ts: added a newrequiresFilesystemCredentialsoption to the hook. When set, the install path routes through a newinstallPluginViaWpUpdates(slug)helper that callswp.updates.installPlugin({ slug })and resolves on thewp-plugin-install-successjQuery event (rejects onwp-plugin-install-error, silently aborts oncredential-modal-cancel). After install succeeds, it activates via the existing REST flow and invalidates the plugin entity resolution.routes/connectors-home/default-connectors.tsx: added agetRequiresFilesystemCredentials()reader on the script module data and forwarded it touseConnectorPlugin.Verification
Tested in Chrome at
http://localhost:8000/wp-admin/options-general.php?page=options-connectors-wp-adminagainst an environment withFS_METHOD=ftpsockets:ftp/ftpuser/ftppass), submitted, andwp plugin status ai-provider-for-openaireportedStatus: Active. The React UI flipped the button to Cancel and auto-expanded the API KEY entry form, matching the direct-FS path.filesystemCredentialsRequired: true, the modal<div>present,wp.updates.installPluginloaded, andwp.updates.shouldRequestFilesystemCredentials: true.After verification: deleted the installed
ai-provider-for-openaiplugin and theftp_credentialsoption to leave the env in a re-testable state.Generated by Claude Code