Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
### Content Management
- Collapsed Matrix blocks now show their entries’ UI labels as preview text, whenever possible. ([#18484](https://github.com/craftcms/cms/discussions/18484))
- Element-level actions within nested element management fields (Matrix, Addresses, etc.) now consistently affect all selected elements, when performed on a selected element. ([#18561](https://github.com/craftcms/cms/pull/18561))
- Elements within Matrix and Addresses fields now have “Paste above” actions when a compatible element is copied. ([#17406](https://github.com/craftcms/cms/discussions/17406))
- Elements within Matrix and Addresses fields now have “Paste above” actions when a compatible element is copied. ([#17406](https://github.com/craftcms/cms/discussions/17406))
- Elements now keep track of the index page’s URL their edit page was linked to from, and explicitly redirect back to that page after save, rather than always redirecting to the referrer. ([#18680](https://github.com/craftcms/cms/pull/18680))
- Addresses fields now have a “Copy all addresses” field-level action. ([#18561](https://github.com/craftcms/cms/pull/18561))
- Matrix fields’ “Expand”, “Collapse”, and “Copy” field-level actions now always affect all nested entries, regardless of whether any entries are selected. ([#18561](https://github.com/craftcms/cms/pull/18561))
- Matrix fields no longer have “Duplicate” and “Delete” field-level actions. ([#18561](https://github.com/craftcms/cms/pull/18561))
Expand Down
16 changes: 15 additions & 1 deletion src/base/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
use craft\helpers\Db;
use craft\helpers\ElementHelper;
use craft\helpers\Html;
use craft\helpers\Json;
use craft\helpers\StringHelper;
use craft\helpers\Template;
use craft\helpers\UrlHelper;
Expand Down Expand Up @@ -1285,6 +1286,7 @@ public static function indexHtml(
'nestedInputNamespace' => $viewState['nestedInputNamespace'] ?? null,
'tableName' => static::pluralDisplayName(),
'elementQuery' => self::elementQueryWithAllDescendants($elementQuery),
'returnUrl' => $viewState['returnUrl'] ?? null,
];

$db = Craft::$app->getDb();
Expand Down Expand Up @@ -3940,12 +3942,20 @@ public function getAltActions(): array
$elementsService = Craft::$app->getElements();
$canSaveCanonical = $elementsService->canSaveCanonical($this);

$returnUrl = Craft::$app->getRequest()->getQueryParam('returnUrl');
$redirectParams = array_filter([
'returnUrl' => $returnUrl,
]);

$altActions = [
[
'label' => $isUnpublishedDraft && $canSaveCanonical
? Craft::t('app', 'Create and continue editing')
: Craft::t('app', 'Save and continue editing'),
'redirect' => '{cpEditUrl}',
'params' => array_filter([
'redirectParams' => !empty($redirectParams) ? Json::encode($redirectParams) : null,
]),
'shortcut' => true,
'retainScroll' => true,
'eventData' => ['autosave' => false],
Expand All @@ -3962,7 +3972,10 @@ public function getAltActions(): array
'shortcut' => true,
'shift' => true,
'eventData' => ['autosave' => false],
'params' => ['addAnother' => 1],
'params' => [
'addAnother' => 1,
'returnUrl' => $returnUrl,
],
];
}

Expand All @@ -3987,6 +4000,7 @@ public function getAltActions(): array
'params' => [
'asUnpublishedDraft' => true,
'deleteProvisionalDraft' => true,
'redirectParams' => !empty($redirectParams) ? Json::encode($redirectParams) : null,
],
];
}
Expand Down
1 change: 1 addition & 0 deletions src/controllers/ElementIndexesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,7 @@ protected function elementResponseData(bool $includeContainer, bool $includeActi
[
...$this->viewState,
'fieldLayouts' => $this->fieldLayouts,
'returnUrl' => $this->request->getParam('returnUrl'),
],
$this->sourceKey,
$this->context,
Expand Down
26 changes: 25 additions & 1 deletion src/controllers/ElementsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,19 @@ public function actionEdit(?ElementInterface $element, ?int $elementId = null):
[$docTitle, $title] = $this->_editElementTitles($element);
$enabledForSite = $element->getEnabledForSite();
$hasRoute = $element->getRoute() !== null;
$redirectUrl = $this->request->getValidatedQueryParam('returnUrl') ?? UrlHelper::cpReferralUrl() ?? ElementHelper::postEditUrl($element);

$redirectUrl = $this->request->getQueryParam('returnUrl');
if ($redirectUrl) {
// only require the URL to be hashed if it contains Twig code
$validated = Craft::$app->getSecurity()->validateData($redirectUrl);
if ($validated !== false) {
$redirectUrl = $validated;
} elseif (str_contains($redirectUrl, '{')) {
throw new BadRequestHttpException("Invalid returnUrl param: $redirectUrl");
}
} else {
$redirectUrl = ElementHelper::postEditUrl($element);
}

// Site statuses
if ($canEditMultipleSites) {
Expand Down Expand Up @@ -1040,9 +1052,16 @@ private function _additionalButtons(

// Revert content from this revision
if ($isRevision && $canSaveCanonical && $element->hasRevisions()) {
$returnUrl = $this->request->getQueryParam('returnUrl');
$components[] = Html::beginForm() .
Html::actionInput('elements/revert') .
Html::redirectInput('{cpEditUrl}') .
($returnUrl
? Html::hiddenInput('redirectParams', Json::encode([
'returnUrl' => $returnUrl,
]))
: ''
) .
Html::hiddenInput('elementId', (string)$canonical->id) .
Html::hiddenInput('revisionId', (string)$element->revisionId) .
Html::button(Craft::t('app', 'Revert content from this revision'), [
Expand Down Expand Up @@ -3012,6 +3031,11 @@ private function _asSuccess(
]);
}

$returnUrl = $this->request->getParam('returnUrl');
if ($returnUrl) {
$url = UrlHelper::urlWithParams($url, ['returnUrl' => $returnUrl]);
}

$response->redirect($url);
}

Expand Down
3 changes: 1 addition & 2 deletions src/controllers/EntryTypesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use craft\helpers\Cp;
use craft\helpers\Html;
use craft\helpers\StringHelper;
use craft\helpers\UrlHelper;
use craft\models\EntryType;
use craft\models\Section;
use craft\web\Controller;
Expand Down Expand Up @@ -125,7 +124,7 @@ public function actionEdit(?int $entryTypeId = null, ?EntryType $entryType = nul
if (!$this->readOnly) {
$response
->action('entry-types/save')
->redirectUrl(UrlHelper::cpReferralUrl() ?? 'settings/entry-types')
->redirectUrl('settings/entry-types')
->addAltAction(Craft::t('app', 'Save and continue editing'), [
'redirect' => 'settings/entry-types/{id}',
'shortcut' => true,
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/FieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public function actionEditField(?int $fieldId = null, ?FieldInterface $field = n
if (!$this->readOnly) {
$response
->action('fields/save-field')
->redirectUrl(UrlHelper::cpReferralUrl() ?? 'settings/fields')
->redirectUrl('settings/fields')
->addAltAction(Craft::t('app', 'Save and continue editing'), [
'redirect' => 'settings/fields/edit/{id}',
'shortcut' => true,
Expand Down
16 changes: 16 additions & 0 deletions src/helpers/Cp.php
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ public static function chipHtml(Chippable $component, array $config = []): strin
* - `class` – Class name(s) that should be added to the container element
* - `context` – The context the chip is going to be shown in (`index`, `field`, etc.)
* - `hyperlink` – Whether the chip label should be hyperlinked to the element’s URL
* - `returnUrl` – The `returnUrl` param that should be added to the hyperlink URL
* - `id` – The chip’s `id` attribute
* - `inputName` – The `name` attribute that should be set on a hidden input, if set
* - `inputValue` – The `value` attribute that should be set on the hidden input, if `inputName` is set. Defaults to [[\craft\base\Identifiable::getId()`]].
Expand Down Expand Up @@ -555,6 +556,7 @@ public static function elementChipHtml(ElementInterface $element, array $config
'attributes' => [],
'autoReload' => true,
'context' => 'index',
'returnUrl' => null,
'id' => sprintf('chip-%s', mt_rand()),
'inputName' => null,
'selectable' => false,
Expand All @@ -574,6 +576,7 @@ public static function elementChipHtml(ElementInterface $element, array $config
'data' => array_filter([
'settings' => $config['autoReload'] ? [
'context' => $config['context'],
'returnUrl' => $config['returnUrl'],
'showDraftName' => $config['showDraftName'],
'showProvisionalDraftLabel' => $config['showProvisionalDraftLabel'],
] : false,
Expand Down Expand Up @@ -629,6 +632,7 @@ public static function elementChipHtml(ElementInterface $element, array $config
* - `autoReload` – Whether the card should auto-reload itself when it’s saved
* - `context` – The context the card is going to be shown in (`index`, `field`, etc.)
* - `hyperlink` – Whether the card label should be hyperlinked to the element’s URL
* - `returnUrl` – The `returnUrl` param that should be added to the hyperlink URL
* - `id` – The card’s `id` attribute
* - `inputName` – The `name` attribute that should be set on the hidden input, if `context` is set to `field`
* - `selectable` – Whether the card should include a checkbox input
Expand All @@ -648,6 +652,7 @@ public static function elementCardHtml(ElementInterface $element, array $config
'autoReload' => true,
'context' => 'index',
'hyperlink' => false,
'returnUrl' => null,
'id' => sprintf('card-%s', mt_rand()),
'inputName' => null,
'selectable' => false,
Expand Down Expand Up @@ -728,6 +733,7 @@ public static function elementCardHtml(ElementInterface $element, array $config
'data' => array_filter([
'settings' => $config['autoReload'] ? [
'hyperlink' => $config['hyperlink'],
'returnUrl' => $config['returnUrl'],
'selectable' => $config['selectable'],
'context' => $config['context'],
'id' => Craft::$app->getView()->namespaceInputId($config['id']),
Expand Down Expand Up @@ -1154,6 +1160,16 @@ private static function elementLabelHtml(ElementInterface $element, array $confi
$config['context'] !== 'modal' &&
($url = $attributes['data']['cp-url'] ?? null)
) {
$returnUrl = $config['returnUrl'] ?? null;
if ($returnUrl) {
if (str_contains($returnUrl, '{')) {
$returnUrl = Craft::$app->getSecurity()->hashData($returnUrl);
}
$url = UrlHelper::urlWithParams($url, [
'returnUrl' => $returnUrl,
]);
}

$content = Html::tag('a', Html::tag('span', $content), [
'class' => ['label-link'],
'href' => $url,
Expand Down
1 change: 1 addition & 0 deletions src/helpers/UrlHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ public static function cpHost(): string
*
* @return string|null
* @since 5.9.0
* @deprecated in 5.10.0
*/
public static function cpReferralUrl(): ?string
{
Expand Down
2 changes: 2 additions & 0 deletions src/templates/_elements/cardsview/elements.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% set context = context ?? 'index' %}
{% set hyperlink = hyperlink ?? (context in ['index', 'embedded-index']) %}
{% set returnUrl = returnUrl ?? null %}

{% apply spaceless %}
{% for element in elements %}
Expand All @@ -14,6 +15,7 @@
selectable,
sortable,
hyperlink,
returnUrl,
}) }}
{% endtag %}
{% endfor %}
Expand Down
2 changes: 2 additions & 0 deletions src/templates/_elements/tableview/elements.twig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{% set showHeaderColumn = showHeaderColumn ?? false %}
{% set context = context ?? 'index' %}
{% set hyperlink = hyperlink ?? (context in ['index', 'embedded-index']) %}
{% set returnUrl = returnUrl ?? null %}

{% for element in elements %}
{% set totalDescendants = structure
Expand Down Expand Up @@ -90,6 +91,7 @@
class: ['chromeless'],
},
hyperlink,
returnUrl,
}) %}
{% if not showHeaderColumn %}
{% set chip = chip|attr({class: 'hide-label'}) %}
Expand Down
2 changes: 2 additions & 0 deletions src/templates/_elements/thumbsview/elements.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% set context = context ?? 'index' %}
{% set hyperlink = hyperlink ?? (context in ['index', 'embedded-index']) %}
{% set returnUrl = returnUrl ?? null %}

{% apply spaceless %}
{% for element in elements %}
Expand All @@ -15,6 +16,7 @@
selectable: selectable,
sortable: sortable,
hyperlink,
returnUrl,
}) }}
{% endtag %}
{% endfor %}
Expand Down
13 changes: 13 additions & 0 deletions src/web/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use craft\elements\User;
use craft\events\DefineBehaviorsEvent;
use craft\helpers\Cp;
use craft\helpers\Json;
use craft\helpers\UrlHelper;
use yii\base\Action;
use yii\base\InvalidArgumentException;
use yii\base\InvalidConfigException;
Expand Down Expand Up @@ -650,6 +652,17 @@ protected function getPostedRedirectUrl(?object $object = null): ?string
$url = $this->getView()->renderObjectTemplate($url, $object);
}

$params = $this->request->getBodyParam('redirectParams');
if ($params) {
try {
$params = Json::decode($params);
} catch (InvalidArgumentException $e) {
throw new BadRequestHttpException($e->getMessage(), previous: $e);
}

$url = UrlHelper::urlWithParams($url, $params);
}

return $url;
}

Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/web/assets/cp/src/js/BaseElementIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,7 @@ Craft.BaseElementIndex = Garnish.Base.extend(
selectable: this.selectable,
sortable: this.sortable && sortAttribute === 'sortOrder',
prevalidate: this.settings.prevalidate,
returnUrl: document.location.href,
};

params.viewState.showHeaderColumn = this.settings.showHeaderColumn;
Expand Down