Skip to content

[6.x] Return to plugin settings after "Save and continue editing" - #20619

Merged
riasvdv merged 2 commits into
6.xfrom
fix-plugin-settings-continue-editing-redirect
Nov 12, 2026
Merged

riasvdv merged 2 commits into
6.xfrom
fix-plugin-settings-continue-editing-redirect

Conversation

@riasvdv

@riasvdv riasvdv commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Description

On a plugin's settings screen, "Save and continue editing" (the Save menu item and Ctrl/Command + S) posts no redirect. PluginsController::saveSettings() then fell back to back(), which follows the Referer header. A browser that sends only the origin as the Referer, such as one in an embedded frame or with Referrer-Policy: origin, saved successfully and then landed on the front-end homepage.

 saveSettings()
-  asSuccess()                                   // no redirect posted → back() → Referer
+  asSuccess(redirect: posted redirect
+                      ?? cpUrl("settings/plugins/{handle}"))

How 5.x handled it. 5.x never used the Referer here:

  • settings/plugins/_settings.twig gave "Save and continue editing" an explicit hashed redirect to settings/plugins/{handle}, marked as the save shortcut.
  • With no redirect posted, Controller::asSuccess() fell back to redirectToPostedUrl(), which used the current request's path.

Why the fix is in saveSettings() and not asSuccess(). The 5.x request-path fallback worked because 5.x forms posted to their own page URL with an action param. 6.x posts to dedicated routes such as settings/plugins/{handle}/enable and utilities/clear-caches, many of which have no GET route. Making asSuccess() fall back to the request URL would send those requests to a 404 or 405. Here, the 5.x behavior was the explicit redirect to the settings page, and that's what this restores:

  • A posted redirect still wins, so the plain Save button still lands on Settings.
  • JSON requests (slideouts) get no redirect, as before.
  • Legacy forms that post the plugins/save-plugin-settings action from their own pages (the yii2-adapter bridge) keep back(). Sending them to settings/plugins/{handle} could take them away from a custom settings page.

Other things the port missed, not changed here:

  • CpScreenResponse::saveShortcutRedirectUrl() (set by VolumesController and EditElementController) reaches the Inertia shell as saveShortcutRedirect, but nothing in resources/js reads it. It's also sent unencrypted, so the client couldn't post it as redirect as it is. In 5.x, cp.twig hashed it and CP.js posted it on Ctrl/Command + S. Those screens currently work anyway, through asModelSuccess()'s fallback to the edit URL.
  • Other settings screens whose "Save and continue editing" relies on asSuccess()'s back() have the same exposure to an origin-only Referer.
  • Validation failures also follow the Referer, through asFailure()'s back() and Laravel's url()->previous() for ValidationException and form requests. With an origin-only Referer, a plugin settings save that fails validation still redirects to /. A fix for that would cover every control panel form, so it belongs in its own change.

Evidence

New test in PluginsControllerTest:

post saveSettings('test-plugin') with Referer: <site origin>, no `redirect`
  → assertRedirect(cp_url('settings/plugins/test-plugin'))
  • Before: fails, Expected 'https://localhost/admin/settings/plugins/test-plugin', Actual 'http://localhost'.
    After: passes, along with the rest of PluginsControllerTest (39 tests).

Save and continue editing posts no redirect, so saveSettings() fell back
to back(), which follows the Referer. A browser that sends only the origin
as the Referer landed on the front-end homepage. Craft 5's settings form
posted an explicit redirect to settings/plugins/{handle}; default to that.

Amp-Thread-ID: https://ampcode.com/threads/T-01a1cf29-3473-71f2-90eb-bc081d7fb15b
Co-authored-by: Amp <amp@ampcode.com>
@github-actions

Copy link
Copy Markdown

📚 Storybook previews

@craftcms/ui — open Storybook

No changed components detected in this Storybook.

resources/js — open Storybook

No changed components detected in this Storybook.

[ci skip]

Amp-Thread-ID: https://ampcode.com/threads/T-01a1cf29-3473-71f2-90eb-bc081d7fb15b
Co-authored-by: Amp <amp@ampcode.com>
@riasvdv
riasvdv merged commit 9fc3d7b into 6.x Nov 12, 2026
@riasvdv
riasvdv deleted the fix-plugin-settings-continue-editing-redirect branch November 12, 2026 10:16
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.

1 participant