diff --git a/CHANGELOG.md b/CHANGELOG.md index 45302a9174e..d22d1f36a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Fixed a bug where named image transforms generated by the `craft` asset transformer were stored and indexed by their parameters rather than their handle. ([#20588](https://github.com/craftcms/cms/issues/20588), [#20594](https://github.com/craftcms/cms/pull/20594)) - Fixed an error that occurred when transforming an asset that its asset transformer can’t transform, such as a video, via GraphQL or the transform arguments of `asset.getWidth()`, `getHeight()`, `getFormat()`, and `getMimeType()`. The asset’s own URL, dimensions, format, and MIME type are returned instead. ([#20588](https://github.com/craftcms/cms/issues/20588), [#20594](https://github.com/craftcms/cms/pull/20594)) - Fixed a bug where `asset.getUrl()` and `asset.url` returned `null` for assets that their asset transformer can’t transform, when a transform was set, rather than the asset’s own URL. ([#20588](https://github.com/craftcms/cms/issues/20588), [#20594](https://github.com/craftcms/cms/pull/20594)) +- Fixed a bug where saving plugin settings with “Save and continue editing” or Command/Ctrl + S could redirect to the front-end homepage. ([#20619](https://github.com/craftcms/cms/pull/20619)) - GraphQL transform arguments now accept `immediately` again, which asks the asset transformer to generate the transform before returning its URL. ([#20588](https://github.com/craftcms/cms/issues/20588), [#20594](https://github.com/craftcms/cms/pull/20594)) - Asset transform drivers now receive whether the transform should be generated immediately in `$request->immediately`, including legacy image transformers. ([#20588](https://github.com/craftcms/cms/issues/20588), [#20594](https://github.com/craftcms/cms/pull/20594)) - Added `CraftCms\Cms\Asset\Data\AssetTransformRequest::$immediately` and `$namedTransform`. ([#20588](https://github.com/craftcms/cms/issues/20588), [#20594](https://github.com/craftcms/cms/pull/20594)) diff --git a/src/Http/Controllers/PluginsController.php b/src/Http/Controllers/PluginsController.php index b56b47ab8bc..b2f018d7f06 100644 --- a/src/Http/Controllers/PluginsController.php +++ b/src/Http/Controllers/PluginsController.php @@ -180,6 +180,15 @@ public function saveSettings(Request $request, string $handle): Response abort_if(is_null($plugin), 404, 'Plugin not found.'); + // Save and continue editing posts no `redirect`. Return to the settings + // page, as Craft 5's form did, rather than to the Referer, which browsers + // may trim to the site's origin. Legacy forms that post the + // `plugins/save-plugin-settings` action from their own pages still go + // back to them. + $settingsUrl = $request->expectsJson() || $request->isActionRequest() + ? null + : Url::cpUrl("settings/plugins/{$handle}"); + $requestClass = $plugin->getSettingsRequestClass(); $settings = $request->input('settings', []); @@ -198,7 +207,7 @@ public function saveSettings(Request $request, string $handle): Response throw ValidationException::withMessages($errors); } - return $this->asSuccess(t('Plugin settings saved.')); + return $this->asSuccess(t('Plugin settings saved.'), redirect: $this->getPostedRedirectUrl() ?? $settingsUrl); } public function renderSettingsUi(Request $request, string $handle): JsonResponse diff --git a/tests/Feature/Http/Controllers/PluginsControllerTest.php b/tests/Feature/Http/Controllers/PluginsControllerTest.php index b1d9744f275..c1b80d3fdc7 100644 --- a/tests/Feature/Http/Controllers/PluginsControllerTest.php +++ b/tests/Feature/Http/Controllers/PluginsControllerTest.php @@ -290,6 +290,16 @@ public function getReadOnlySettingsResponse(): mixed expect($settings->bar)->toBe('baz'); })->with(['JSON' => true, 'form' => false]); +test('saveSettings without a posted redirect returns to the settings page, not the Referer', function () { + // Save and continue editing posts no `redirect`, and some browsers send + // only the origin as the Referer. + $this->withHeader('Referer', url('/')) + ->post(action([PluginsController::class, 'saveSettings'], ['test-plugin']), [ + 'settings' => ['foo' => 'bar', 'bar' => 'baz'], + ]) + ->assertRedirect(cp_url('settings/plugins/test-plugin')); +}); + test('saveSettings returns settings model validation errors for JSON requests without saving', function () { $url = action([PluginsController::class, 'saveSettings'], ['test-plugin']); app(ProjectConfig::class)->set('plugins.test-plugin.settings', ['foo' => 'saved value', 'bar' => 'saved bar']);