Skip to content

Commit

Permalink
Unsaved drafts → unpublished drafts
Browse files Browse the repository at this point in the history
Resolves #5661
Resolves #7216
  • Loading branch information
brandonkelly committed Dec 4, 2020
1 parent 04c729b commit 182bcb3
Show file tree
Hide file tree
Showing 24 changed files with 360 additions and 283 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG-v3.6.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
### Added
- Craft now requires PHP 7.2.5 or later.
- Entries now begin life as “unpublished drafts” rather than “unsaved drafts”. They are no longer ephemeral; they will continue to exist until explicitly published or deleted. ([#5661](https://github.com/craftcms/cms/issues/5661), [#7216](https://github.com/craftcms/cms/issues/7216))
- User indexes can now include a “Groups” column. ([#7211](https://github.com/craftcms/cms/issues/7211))
- Volumes now have “Title Translation Method” and “Title Translation Key Format” settings, like entry types. ([#7135](https://github.com/craftcms/cms/issues/7135))
- It’s now possible to set sites’ Name settings to environment variables.
Expand All @@ -19,7 +20,9 @@
- Added the `{% tag %}` Twig tag.
- Added the `withGroups` user query param.
- Added the `relatedToAssets`, `relatedToCategories`, `relatedToEntries`, `relatedToTags`, and `relatedToUsers` arguments to GraphQL queries. ([#7110](https://github.com/craftcms/cms/issues/7110))
- Added the `isUnpublishedDraft` GraphQL field.
- Added `craft\base\ElementExporterInterface::isFormattable()`.
- Added `craft\base\ElementInterface::getIsUnpublishedDraft()`.
- Added `craft\base\VolumeTrait::$titleTranslationKeyFormat`.
- Added `craft\base\VolumeTrait::$titleTranslationMethod`.
- Added `craft\console\Controller::passwordPrompt()`.
Expand Down Expand Up @@ -52,6 +55,9 @@
- Added `craft\models\Site::getName()`.
- Added `craft\models\Site::setBaseUrl()`.
- Added `craft\models\Site::setName()`.
- Added `craft\services\Drafts::EVENT_AFTER_APPLY_DRAFT`.
- Added `craft\services\Drafts::EVENT_BEFORE_APPLY_DRAFT`.
- Added `craft\services\Drafts::publishDraft()`.
- Added `craft\services\Gql::GRAPHQL_COMPLEXITY_CPU_HEAVY`.
- Added `craft\services\Gql::GRAPHQL_COMPLEXITY_EAGER_LOAD`.
- Added `craft\services\Gql::GRAPHQL_COMPLEXITY_NPLUS1`.
Expand Down Expand Up @@ -83,14 +89,21 @@

### Deprecated
- Deprecated the `backup` and `restore` commands.
- Deprecated the `purgeUnsavedDraftsDuration` config setting.
- Deprecated the `siteName` config setting. Sites’ Name settings should be set to environment variables instead.
- Deprecated the `siteUrl` config setting. Sites’ Base URL settings should be set to aliases or environment variables instead. ([#3205](https://github.com/craftcms/cms/issues/3205))
- Deprecated the `relatedToAll` GraphQL query argument.
- Deprecated the `isUnsavedDraft` GraphQL field.
- Deprecated `craft\base\Element::getIsUnsavedDraft()`. `getIsUnpublishedDraft()` should be used instead.
- Deprecated `craft\db\Connection::trimObjectName()`.
- Deprecated `craft\gql\base\Resolver::getArrayableArguments()`.
- Deprecated `craft\gql\base\Resolver::prepareArguments()`.
- Deprecated `craft\helpers\App::logConfig()`.
- Deprecated `craft\services\Composer::$disablePackagist`.
- Deprecated `craft\services\Drafts::applyDraft()`. `publishDraft()` should be used instead.
- Deprecated `craft\services\Drafts::EVENT_AFTER_APPLY_DRAFT`. `EVENT_AFTER_PUBLISH_DRAFT` should be used instead.
- Deprecated `craft\services\Drafts::EVENT_BEFORE_APPLY_DRAFT`. `EVENT_BEFORE_PUBLISH_DRAFT` should be used instead.
- Deprecated `craft\services\Drafts::purgeUnsavedDrafts()`.
- Deprecated `craft\web\View::$minifyCss`.
- Deprecated `craft\web\View::$minifyJs`.

Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
## Unreleased (3.6)

### Added
- Entries now begin life as “unpublished drafts” rather than “unsaved drafts”. They are no longer ephemeral; they will continue to exist until explicitly published or deleted. ([#5661](https://github.com/craftcms/cms/issues/5661), [#7216](https://github.com/craftcms/cms/issues/7216))
- User indexes can now include a “Groups” column. ([#7211](https://github.com/craftcms/cms/issues/7211))
- It’s now possible to set sites’ Name settings to environment variables.
- Added the `{% tag %}` Twig tag.
- Added the `withGroups` user query param.
- Added the `relatedToAssets`, `relatedToCategories`, `relatedToEntries`, `relatedToTags`, and `relatedToUsers` arguments to GraphQL queries. ([#7110](https://github.com/craftcms/cms/issues/7110))
- Added the `isUnpublishedDraft` GraphQL field.
- Added `craft\base\ElementInterface::getIsUnpublishedDraft()`.
- Added `craft\events\RegisterGqlArgumentHandlersEvent`.
- Added `craft\gql\ArgumentManager`.
- Added `craft\gql\base\ArgumentHandler`.
Expand All @@ -27,6 +30,9 @@
- Added `craft\models\Site::getName()`.
- Added `craft\models\Site::setBaseUrl()`.
- Added `craft\models\Site::setName()`.
- Added `craft\services\Drafts::EVENT_AFTER_APPLY_DRAFT`.
- Added `craft\services\Drafts::EVENT_BEFORE_APPLY_DRAFT`.
- Added `craft\services\Drafts::publishDraft()`.

### Changed
- `craft\behaviors\EnvAttributeParserBehavior::$attributes` can now be set to an array with key/value pairs, where the key is the attribute name, and the value is the raw (unparsed) value, or a callable that returns the raw value.
Expand All @@ -35,10 +41,17 @@
- `craft\models\Site::getBaseUrl()` now has a `$parse` argument, which can be set to `false` to return the raw (unparsed) base URL.

### Deprecated
- Deprecated the `purgeUnsavedDraftsDuration` config setting.
- Deprecated the `siteName` config setting. Sites’ Name settings should be set to environment variables instead.
- Deprecated the `siteUrl` config setting. Sites’ Base URL settings should be set to aliases or environment variables instead. ([#3205](https://github.com/craftcms/cms/issues/3205))
- Deprecated the `isUnsavedDraft` GraphQL field.
- Deprecated `craft\base\Element::getIsUnsavedDraft()`. `getIsUnpublishedDraft()` should be used instead.
- Deprecated `craft\gql\base\Resolver::getArrayableArguments()`.
- Deprecated `craft\gql\base\Resolver::prepareArguments()`.
- Deprecated `craft\services\Drafts::applyDraft()`. `publishDraft()` should be used instead.
- Deprecated `craft\services\Drafts::EVENT_AFTER_APPLY_DRAFT`. `EVENT_AFTER_PUBLISH_DRAFT` should be used instead.
- Deprecated `craft\services\Drafts::EVENT_BEFORE_APPLY_DRAFT`. `EVENT_BEFORE_PUBLISH_DRAFT` should be used instead.
- Deprecated `craft\services\Drafts::purgeUnsavedDrafts()`.

### Fixed
- Fixed a JavaScript error that occurred when opening an element selector modal. ([#7186](https://github.com/craftcms/cms/issues/7186))
Expand Down
12 changes: 12 additions & 0 deletions src/base/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -1876,6 +1876,18 @@ public function getSourceUid(): string
/**
* @inheritdoc
*/
public function getIsUnpublishedDraft(): bool
{
return $this->getIsUnsavedDraft();
}

/**
* Returns whether the element is an unpublished draft.
*
* @return bool
* @since 3.2.0
* @deprecated in 3.6.0. Use [[getIsUnpublishedDraft()]] instead.
*/
public function getIsUnsavedDraft(): bool
{
if (!$this->getIsDraft()) {
Expand Down
6 changes: 3 additions & 3 deletions src/base/ElementInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -555,12 +555,12 @@ public function getSourceId();
public function getSourceUid(): string;

/**
* Returns whether the element is an unsaved draft.
* Returns whether the element is an unpublished draft.
*
* @return bool
* @since 3.2.0
* @since 3.6.0
*/
public function getIsUnsavedDraft(): bool;
public function getIsUnpublishedDraft(): bool;

/**
* Returns the field layout used by this element.
Expand Down
9 changes: 2 additions & 7 deletions src/config/GeneralConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -1010,15 +1010,11 @@ class GeneralConfig extends BaseObject

/**
* @var mixed The amount of time to wait before Craft purges drafts of new elements that were never formally saved.
*
* Set to `0` to disable this feature.
*
* See [[ConfigHelper::durationInSeconds()]] for a list of supported value types.
*
* @since 3.2.0
* @group Garbage Collection
* @deprecated in 3.6.0
*/
public $purgeUnsavedDraftsDuration = 2592000;
public $purgeUnsavedDraftsDuration = 0;

/**
* @var bool Whether SVG thumbnails should be rasterized.
Expand Down Expand Up @@ -1590,7 +1586,6 @@ public function init()
$this->elevatedSessionDuration = ConfigHelper::durationInSeconds($this->elevatedSessionDuration);
$this->invalidLoginWindowDuration = ConfigHelper::durationInSeconds($this->invalidLoginWindowDuration);
$this->purgePendingUsersDuration = ConfigHelper::durationInSeconds($this->purgePendingUsersDuration);
$this->purgeUnsavedDraftsDuration = ConfigHelper::durationInSeconds($this->purgeUnsavedDraftsDuration);
$this->rememberUsernameDuration = ConfigHelper::durationInSeconds($this->rememberUsernameDuration);
$this->rememberedUserSessionDuration = ConfigHelper::durationInSeconds($this->rememberedUserSessionDuration);
$this->softDeleteDuration = ConfigHelper::durationInSeconds($this->softDeleteDuration);
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/BaseEntriesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ protected function docTitle(Entry $entry): string
*/
protected function pageTitle(Entry $entry): string
{
if ($entry->getIsUnsavedDraft()) {
if ($entry->getIsUnpublishedDraft()) {
return Craft::t('app', 'Create a new entry');
}
return trim($entry->title) ?: Craft::t('app', 'Edit Entry');
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/EntriesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,6 @@ private function _populateEntryModel(Entry $entry)
}

// Revision notes
$entry->setRevisionNotes($this->request->getBodyParam('revisionNotes'));
$entry->setRevisionNotes($this->request->getBodyParam('notes'));
}
}
22 changes: 11 additions & 11 deletions src/controllers/EntryRevisionsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,14 +255,9 @@ public function actionSaveDraft()
$draft->setFieldValuesFromRequest($fieldsLocation);
$draft->updateTitle();

// Draft meta
/** @var Entry|DraftBehavior $draft */
$draft->draftName = $this->request->getBodyParam('draftName') ?? $draft->draftName;
$draft->draftNotes = $this->request->getBodyParam('draftNotes') ?? $draft->draftNotes;

$draft->setScenario(Element::SCENARIO_ESSENTIALS);

if ($draft->getIsUnsavedDraft() && $this->request->getBodyParam('propagateAll')) {
if ($draft->getIsUnpublishedDraft() && $this->request->getBodyParam('propagateAll')) {
$draft->propagateAll = true;
}

Expand Down Expand Up @@ -350,7 +345,7 @@ public function actionDeleteDraft(): Response
]);
}

return $this->redirectToPostedUrl();
return $this->redirectToPostedUrl($draft);
}

/**
Expand Down Expand Up @@ -417,7 +412,7 @@ public function actionPublishDraft()

// Even more permission enforcement
if ($draft->enabled && !Craft::$app->getUser()->checkPermission("publishEntries:{$section->uid}")) {
if ($draft->getIsUnsavedDraft()) {
if ($draft->getIsUnpublishedDraft()) {
// Just disable it
$draft->enabled = false;
} else {
Expand All @@ -435,7 +430,7 @@ public function actionPublishDraft()
$draft->setScenario(Element::SCENARIO_LIVE);
}

if ($draft->getIsUnsavedDraft() && $this->request->getBodyParam('propagateAll')) {
if ($draft->getIsUnpublishedDraft() && $this->request->getBodyParam('propagateAll')) {
$draft->propagateAll = true;
}

Expand All @@ -445,7 +440,7 @@ public function actionPublishDraft()
}

// Publish the draft (finally!)
$newEntry = Craft::$app->getDrafts()->applyDraft($draft);
$newEntry = Craft::$app->getDrafts()->publishDraft($draft);
} catch (InvalidElementException $e) {
$this->setFailFlash(Craft::t('app', 'Couldn’t publish draft.'));

Expand All @@ -462,7 +457,7 @@ public function actionPublishDraft()
]);
}

$this->setSuccessFlash(Craft::t('app', 'Entry saved.'));
$this->setSuccessFlash(Craft::t('app', 'Draft published.'));
return $this->redirectToPostedUrl($newEntry);
}

Expand Down Expand Up @@ -574,5 +569,10 @@ private function _setDraftAttributesFromPost(Entry $draft)
}

$draft->newParentId = $parentId ?: null;

// Draft meta
/** @var Entry|DraftBehavior $draft */
$draft->draftName = $this->request->getBodyParam('draftName') ?? $draft->draftName;
$draft->draftNotes = $this->request->getBodyParam('notes') ?? $draft->draftNotes;
}
}
2 changes: 1 addition & 1 deletion src/elements/db/ElementQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ private static function _supportsRevisionParams(): bool
*
* - A source element ID – matches drafts of that element
* - `'*'` – matches drafts of any source element
* - `false` – matches unsaved drafts that have no source element
* - `false` – matches unpublished drafts that have no source element
*
* @since 3.2.0
*/
Expand Down
2 changes: 1 addition & 1 deletion src/gql/base/ElementArguments.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public static function getDraftArguments(): array
'draftOf' => [
'name' => 'draftOf',
'type' => QueryArgument::getType(),
'description' => 'The source element ID that drafts should be returned for. Set to `false` to fetch unsaved drafts.',
'description' => 'The source element ID that drafts should be returned for. Set to `false` to fetch unpublished drafts.',
],
'draftId' => [
'name' => 'draftId',
Expand Down
7 changes: 6 additions & 1 deletion src/gql/interfaces/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,15 @@ public static function getDraftFieldDefinitions(): array
'type' => Type::int(),
'description' => 'The ID of the draft to return (from the `drafts` table)',
],
'isUnpublishedDraft' => [
'name' => 'isUnpublishedDraft',
'type' => Type::boolean(),
'description' => 'Returns whether this is an unpublished draft.',
],
'isUnsavedDraft' => [
'name' => 'isUnsavedDraft',
'type' => Type::boolean(),
'description' => 'Returns whether this is a draft.',
'description' => 'Returns whether this is an unpublished draft. **This field is deprecated.** `isUnpublishedDraft` should be used instead.',
],
'draftName' => [
'name' => 'draftName',
Expand Down
2 changes: 1 addition & 1 deletion src/gql/resolvers/mutations/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public function publishDraft($source, array $arguments, $context, ResolveInfo $r
$this->requireSchemaAction('entrytypes.' . $entryTypeUid, 'save');

/** @var Entry $draft */
$draft = Craft::$app->getDrafts()->applyDraft($draft);
$draft = Craft::$app->getDrafts()->publishDraft($draft);

return $draft->id;
}
Expand Down
Loading

0 comments on commit 182bcb3

Please sign in to comment.