From 7e26134d734a69747b1f9d6a3715c6735de97147 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Tue, 23 Jan 2024 11:28:05 -0800 Subject: [PATCH 01/12] Drop 4.7 from CI [ci skip] --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 788286bc239..3708a14df45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,6 @@ on: push: branches: - develop - - '4.7' pull_request: permissions: contents: read From 759edf01fecfe8efb0ccd1d372c123766fa4e660 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Tue, 23 Jan 2024 11:29:17 -0800 Subject: [PATCH 02/12] Capital M [ci skip] --- .../utils/PruneOrphanedMatrixBlocksController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/console/controllers/utils/PruneOrphanedMatrixBlocksController.php b/src/console/controllers/utils/PruneOrphanedMatrixBlocksController.php index 60cc9b04895..286c64cf6c5 100644 --- a/src/console/controllers/utils/PruneOrphanedMatrixBlocksController.php +++ b/src/console/controllers/utils/PruneOrphanedMatrixBlocksController.php @@ -16,7 +16,7 @@ use yii\console\ExitCode; /** - * Prunes orphaned matrix blocks for each site. + * Prunes orphaned Matrix blocks for each site. * * @author Pixel & Tonic, Inc. * @since 4.7.0 @@ -24,7 +24,7 @@ class PruneOrphanedMatrixBlocksController extends Controller { /** - * Prunes orphaned matrix blocks for each site. + * Prunes orphaned Matrix blocks for each site. * * @return int */ @@ -40,9 +40,9 @@ public function actionIndex(): int // get all sites $sites = Craft::$app->getSites()->getAllSites(); - // for each site get all matrix blocks with owner that doesn't exist for this site + // for each site get all Matrix blocks with owner that doesn't exist for this site foreach ($sites as $site) { - $this->stdout(sprintf('Finding orphaned matrix blocks for site "%s" ... ', $site->getName())); + $this->stdout(sprintf('Finding orphaned Matrix blocks for site "%s" ... ', $site->getName())); $esSubQuery = (new Query()) ->from(['es' => Table::ELEMENTS_SITES]) From 8112d103641e3ae7346c7ebfd3d19ca3bdd33fd7 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Tue, 23 Jan 2024 15:52:27 -0800 Subject: [PATCH 03/12] craftcms/cloud: * [ci skip] --- src/console/controllers/SetupController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console/controllers/SetupController.php b/src/console/controllers/SetupController.php index cfdcd896ea8..26d9401024a 100644 --- a/src/console/controllers/SetupController.php +++ b/src/console/controllers/SetupController.php @@ -609,7 +609,7 @@ public function actionCloud(): int $io = new ConsoleIO($input, $output, new HelperSet([new QuestionHelper()])); Craft::$app->getComposer()->install([ - 'craftcms/cloud' => '^1.0.0', + 'craftcms/cloud' => '*', ], $io); $message = sprintf('Extension %s', $moduleInstalled ? 'updated' : 'installed'); From 7447808979ecd27a92857ade64335fd382215921 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Fri, 26 Jan 2024 09:26:38 -0800 Subject: [PATCH 04/12] Set empty Dropdown values and their initial delta value consistently --- CHANGELOG.md | 4 ++++ src/fields/Dropdown.php | 15 +++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d6437a4e17..12b18838e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Release Notes for Craft CMS 4 +## Unreleased + +- Fixed a bug where empty Dropdown fields were getting treated as dirty when unchanged. + ## 4.7.0 - 2024-01-23 > [!NOTE] diff --git a/src/fields/Dropdown.php b/src/fields/Dropdown.php index dbffa36d571..e3bf893a375 100644 --- a/src/fields/Dropdown.php +++ b/src/fields/Dropdown.php @@ -11,6 +11,8 @@ use craft\base\Element; use craft\base\ElementInterface; use craft\base\SortableFieldInterface; +use craft\fields\data\MultiOptionsFieldData; +use craft\fields\data\OptionData; use craft\fields\data\SingleOptionFieldData; use craft\helpers\Cp; @@ -107,21 +109,22 @@ private function inputHtmlInternal(mixed $value, ?ElementInterface $element, boo } } - $encValue = $this->encodeValue($value); - if ($encValue === null || $encValue === '') { - $encValue = '__BLANK__'; - } - return Cp::selectizeHtml([ 'id' => $this->getInputId(), 'describedBy' => $this->describedBy, 'name' => $this->handle, - 'value' => $encValue, + 'value' => $this->encodeValue($value), 'options' => $options, 'disabled' => $static, ]); } + protected function encodeValue(MultiOptionsFieldData|OptionData|string|null $value): string|array|null + { + $encValue = parent::encodeValue($value); + return $encValue === null || $encValue === '' ? '__BLANK__' : $encValue; + } + /** * @inheritdoc */ From 335609a0a8f316801b9cf8d4c4dc516c23cec4a0 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Fri, 26 Jan 2024 14:33:39 -0800 Subject: [PATCH 05/12] Message fix [ci skip] --- src/controllers/ElementsController.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/controllers/ElementsController.php b/src/controllers/ElementsController.php index 598f048239a..7b8d181b4f5 100644 --- a/src/controllers/ElementsController.php +++ b/src/controllers/ElementsController.php @@ -1686,9 +1686,7 @@ public function actionUpdateFieldLayout(): ?Response 'initialDeltaValues' => Craft::$app->getView()->getInitialDeltaValues(), ]; - return $this->_asSuccess(Craft::t('app', '{type} saved.', [ - 'type' => Craft::t('app', 'Draft'), - ]), $element, $data, true); + return $this->_asSuccess('Field layout updated.', $element, $data, true); } private function _fieldLayoutData(ElementInterface $element): array From 2d18557da70122bca75a6b9de38f97caf64eff17 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Sun, 28 Jan 2024 15:54:56 -0800 Subject: [PATCH 06/12] Fixed Recent Entries bug [ci skip] --- CHANGELOG.md | 1 + .../recententries/dist/RecentEntriesWidget.js | 2 +- .../dist/RecentEntriesWidget.js.map | 2 +- .../recententries/src/RecentEntriesWidget.js | 41 +++++-------------- 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b18838e17..4b2d09861b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - Fixed a bug where empty Dropdown fields were getting treated as dirty when unchanged. +- Fixed a bug where Recent Entries widgets were getting mangled when new entries were created via Quick Post widgets. ## 4.7.0 - 2024-01-23 diff --git a/src/web/assets/recententries/dist/RecentEntriesWidget.js b/src/web/assets/recententries/dist/RecentEntriesWidget.js index 73d9b031d94..d112f20a2a3 100644 --- a/src/web/assets/recententries/dist/RecentEntriesWidget.js +++ b/src/web/assets/recententries/dist/RecentEntriesWidget.js @@ -1,2 +1,2 @@ -!function(){var t;t=jQuery,Craft.RecentEntriesWidget=Garnish.Base.extend({params:null,$widget:null,$body:null,$container:null,$tbody:null,hasEntries:null,init:function(i,e){this.params=e,this.$widget=t("#widget"+i),this.$body=this.$widget.find(".body:first"),this.$container=this.$widget.find(".recententries-container:first"),this.$tbody=this.$container.find("tbody:first"),this.hasEntries=!!this.$tbody.length,this.$widget.data("widget").on("destroy",this.destroy.bind(this)),Craft.RecentEntriesWidget.instances.push(this)},addEntry:function(i){this.$container.css("margin-top",0);var e=this.$container.height();if(!this.hasEntries){var n=t('').prependTo(this.$container);this.$tbody=t("").appendTo(n)}this.$tbody.prepend('");var s=this.$container.height()-e;this.$container.css("margin-top",-s);var a={"margin-top":0};this.hasEntries||(a["margin-bottom"]=-e,this.hasEntries=!0),this.$container.velocity(a)},destroy:function(){Craft.RecentEntriesWidget.instances.splice(t.inArray(this,Craft.RecentEntriesWidget.instances),1),this.base()}},{instances:[]})}(); +!function(){var t;t=jQuery,Craft.RecentEntriesWidget=Garnish.Base.extend({params:null,$widget:null,$body:null,$container:null,$list:null,hasEntries:null,init:function(i,e){this.params=e,this.$widget=t("#widget"+i),this.$body=this.$widget.find(".body:first"),this.$container=this.$body.find(".recententries-container:first"),this.$list=this.$container.find("ol:first"),this.hasEntries=!!this.$list.length,this.$widget.data("widget").on("destroy",this.destroy.bind(this)),Craft.RecentEntriesWidget.instances.push(this)},addEntry:function(i){this.hasEntries||(this.$list=t("
    ").appendTo(this.$container)),this.$list.prepend('
  1. '+'')+Craft.escapeHtml(i.title)+' '+Craft.escapeHtml((i.dateCreated?Craft.formatDate(i.dateCreated):"")+(i.dateCreated&&i.username&&Craft.edition==Craft.Pro?", ":"")+(i.username&&Craft.edition==Craft.Pro?i.username:""))+"
  2. "),this.hasEntries||(this.$container.find(".zilch").remove(),this.hasEntries=!0)},destroy:function(){Craft.RecentEntriesWidget.instances.splice(t.inArray(this,Craft.RecentEntriesWidget.instances),1),this.base()}},{instances:[]})}(); //# sourceMappingURL=RecentEntriesWidget.js.map \ No newline at end of file diff --git a/src/web/assets/recententries/dist/RecentEntriesWidget.js.map b/src/web/assets/recententries/dist/RecentEntriesWidget.js.map index f8df9e74127..022957cf24f 100644 --- a/src/web/assets/recententries/dist/RecentEntriesWidget.js.map +++ b/src/web/assets/recententries/dist/RecentEntriesWidget.js.map @@ -1 +1 @@ -{"version":3,"file":"RecentEntriesWidget.js","mappings":"YAAA,IAAWA,IA0FRC,OAvFDC,MAAMC,oBAAsBC,QAAQC,KAAKC,OACvC,CACEC,OAAQ,KACRC,QAAS,KACTC,MAAO,KACPC,WAAY,KACZC,OAAQ,KACRC,WAAY,KAEZC,KAAM,SAAUC,EAAUP,GACxBQ,KAAKR,OAASA,EACdQ,KAAKP,QAAUR,EAAE,UAAYc,GAC7BC,KAAKN,MAAQM,KAAKP,QAAQQ,KAAK,eAC/BD,KAAKL,WAAaK,KAAKP,QAAQQ,KAAK,kCACpCD,KAAKJ,OAASI,KAAKL,WAAWM,KAAK,eACnCD,KAAKH,aAAeG,KAAKJ,OAAOM,OAEhCF,KAAKP,QAAQU,KAAK,UAAUC,GAAG,UAAWJ,KAAKK,QAAQC,KAAKN,OAE5Db,MAAMC,oBAAoBmB,UAAUC,KAAKR,KAC3C,EAEAS,SAAU,SAAUC,GAClBV,KAAKL,WAAWgB,IAAI,aAAc,GAClC,IAAIC,EAAYZ,KAAKL,WAAWkB,SAEhC,IAAKb,KAAKH,WAAY,CAEpB,IAAIiB,EAAS7B,EAAE,mCAAmC8B,UAChDf,KAAKL,YAEPK,KAAKJ,OAASX,EAAE,YAAY+B,SAASF,EACvC,CAEAd,KAAKJ,OAAOqB,QACV,oBAGEP,EAAMQ,IACN,KACA/B,MAAMgC,WAAWT,EAAMU,OALzB,4BAQEjC,MAAMgC,YACHT,EAAMW,YAAclC,MAAMmC,WAAWZ,EAAMW,aAAe,KACxDX,EAAMW,aACPX,EAAMa,UACNpC,MAAMqC,SAAWrC,MAAMsC,IACnB,KACA,KACHf,EAAMa,UAAYpC,MAAMqC,SAAWrC,MAAMsC,IACtCf,EAAMa,SACN,KAjBV,qBAwBF,IACEG,EADc1B,KAAKL,WAAWkB,SACLD,EAE3BZ,KAAKL,WAAWgB,IAAI,cAAee,GAEnC,IAAIC,EAAQ,CAAC,aAAc,GAGtB3B,KAAKH,aACR8B,EAAM,kBAAoBf,EAC1BZ,KAAKH,YAAa,GAGpBG,KAAKL,WAAWiC,SAASD,EAC3B,EAEAtB,QAAS,WACPlB,MAAMC,oBAAoBmB,UAAUsB,OAClC5C,EAAE6C,QAAQ9B,KAAMb,MAAMC,oBAAoBmB,WAC1C,GAEFP,KAAK+B,MACP,GAEF,CACExB,UAAW,I","sources":["webpack:///./RecentEntriesWidget.js"],"sourcesContent":["(function ($) {\n /** global: Craft */\n /** global: Garnish */\n Craft.RecentEntriesWidget = Garnish.Base.extend(\n {\n params: null,\n $widget: null,\n $body: null,\n $container: null,\n $tbody: null,\n hasEntries: null,\n\n init: function (widgetId, params) {\n this.params = params;\n this.$widget = $('#widget' + widgetId);\n this.$body = this.$widget.find('.body:first');\n this.$container = this.$widget.find('.recententries-container:first');\n this.$tbody = this.$container.find('tbody:first');\n this.hasEntries = !!this.$tbody.length;\n\n this.$widget.data('widget').on('destroy', this.destroy.bind(this));\n\n Craft.RecentEntriesWidget.instances.push(this);\n },\n\n addEntry: function (entry) {\n this.$container.css('margin-top', 0);\n var oldHeight = this.$container.height();\n\n if (!this.hasEntries) {\n // Create the table first\n var $table = $('
'+Craft.escapeHtml(i.title)+' '+Craft.escapeHtml((i.dateCreated?Craft.formatDate(i.dateCreated):"")+(i.dateCreated&&i.username&&Craft.edition==Craft.Pro?", ":"")+(i.username&&Craft.edition==Craft.Pro?i.username:""))+"
').prependTo(\n this.$container\n );\n this.$tbody = $('').appendTo($table);\n }\n\n this.$tbody.prepend(\n '' +\n '' +\n ''\n );\n\n var newHeight = this.$container.height(),\n heightDiff = newHeight - oldHeight;\n\n this.$container.css('margin-top', -heightDiff);\n\n var props = {'margin-top': 0};\n\n // Also animate the \"No entries exist\" text out of view\n if (!this.hasEntries) {\n props['margin-bottom'] = -oldHeight;\n this.hasEntries = true;\n }\n\n this.$container.velocity(props);\n },\n\n destroy: function () {\n Craft.RecentEntriesWidget.instances.splice(\n $.inArray(this, Craft.RecentEntriesWidget.instances),\n 1\n );\n this.base();\n },\n },\n {\n instances: [],\n }\n );\n})(jQuery);\n"],"names":["$","jQuery","Craft","RecentEntriesWidget","Garnish","Base","extend","params","$widget","$body","$container","$tbody","hasEntries","init","widgetId","this","find","length","data","on","destroy","bind","instances","push","addEntry","entry","css","oldHeight","height","$table","prependTo","appendTo","prepend","url","escapeHtml","title","dateCreated","formatDate","username","edition","Pro","heightDiff","props","velocity","splice","inArray","base"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"RecentEntriesWidget.js","mappings":"YAAA,IAAWA,IAuERC,OApEDC,MAAMC,oBAAsBC,QAAQC,KAAKC,OACvC,CACEC,OAAQ,KACRC,QAAS,KACTC,MAAO,KACPC,WAAY,KACZC,MAAO,KACPC,WAAY,KAEZC,KAAM,SAAUC,EAAUP,GACxBQ,KAAKR,OAASA,EACdQ,KAAKP,QAAUR,EAAE,UAAYc,GAC7BC,KAAKN,MAAQM,KAAKP,QAAQQ,KAAK,eAC/BD,KAAKL,WAAaK,KAAKN,MAAMO,KAAK,kCAClCD,KAAKJ,MAAQI,KAAKL,WAAWM,KAAK,YAClCD,KAAKH,aAAeG,KAAKJ,MAAMM,OAE/BF,KAAKP,QAAQU,KAAK,UAAUC,GAAG,UAAWJ,KAAKK,QAAQC,KAAKN,OAE5Db,MAAMC,oBAAoBmB,UAAUC,KAAKR,KAC3C,EAEAS,SAAU,SAAUC,GACbV,KAAKH,aAERG,KAAKJ,MAAQX,EAAE,SAAS0B,SAASX,KAAKL,aAGxCK,KAAKJ,MAAMgB,QACT,iCAAgC,mBAClBF,EAAMG,IAAG,MACrB1B,MAAM2B,WAAWJ,EAAMK,OAFzB,4BAKE5B,MAAM2B,YACHJ,EAAMM,YAAc7B,MAAM8B,WAAWP,EAAMM,aAAe,KACxDN,EAAMM,aACPN,EAAMQ,UACN/B,MAAMgC,SAAWhC,MAAMiC,IACnB,KACA,KACHV,EAAMQ,UAAY/B,MAAMgC,SAAWhC,MAAMiC,IACtCV,EAAMQ,SACN,KAdV,gBAqBGlB,KAAKH,aACRG,KAAKL,WAAWM,KAAK,UAAUoB,SAC/BrB,KAAKH,YAAa,EAEtB,EAEAQ,QAAS,WACPlB,MAAMC,oBAAoBmB,UAAUe,OAClCrC,EAAEsC,QAAQvB,KAAMb,MAAMC,oBAAoBmB,WAC1C,GAEFP,KAAKwB,MACP,GAEF,CACEjB,UAAW,I","sources":["webpack:///./RecentEntriesWidget.js"],"sourcesContent":["(function ($) {\n /** global: Craft */\n /** global: Garnish */\n Craft.RecentEntriesWidget = Garnish.Base.extend(\n {\n params: null,\n $widget: null,\n $body: null,\n $container: null,\n $list: null,\n hasEntries: null,\n\n init: function (widgetId, params) {\n this.params = params;\n this.$widget = $('#widget' + widgetId);\n this.$body = this.$widget.find('.body:first');\n this.$container = this.$body.find('.recententries-container:first');\n this.$list = this.$container.find('ol:first');\n this.hasEntries = !!this.$list.length;\n\n this.$widget.data('widget').on('destroy', this.destroy.bind(this));\n\n Craft.RecentEntriesWidget.instances.push(this);\n },\n\n addEntry: function (entry) {\n if (!this.hasEntries) {\n // Create the list first\n this.$list = $('
    ').appendTo(this.$container);\n }\n\n this.$list.prepend(\n '
  1. ' +\n `` +\n Craft.escapeHtml(entry.title) +\n ' ' +\n '' +\n Craft.escapeHtml(\n (entry.dateCreated ? Craft.formatDate(entry.dateCreated) : '') +\n (entry.dateCreated &&\n entry.username &&\n Craft.edition == Craft.Pro\n ? ', '\n : '') +\n (entry.username && Craft.edition == Craft.Pro\n ? entry.username\n : '')\n ) +\n '' +\n '
  2. '\n );\n\n // Also animate the \"No entries exist\" text out of view\n if (!this.hasEntries) {\n this.$container.find('.zilch').remove();\n this.hasEntries = true;\n }\n },\n\n destroy: function () {\n Craft.RecentEntriesWidget.instances.splice(\n $.inArray(this, Craft.RecentEntriesWidget.instances),\n 1\n );\n this.base();\n },\n },\n {\n instances: [],\n }\n );\n})(jQuery);\n"],"names":["$","jQuery","Craft","RecentEntriesWidget","Garnish","Base","extend","params","$widget","$body","$container","$list","hasEntries","init","widgetId","this","find","length","data","on","destroy","bind","instances","push","addEntry","entry","appendTo","prepend","url","escapeHtml","title","dateCreated","formatDate","username","edition","Pro","remove","splice","inArray","base"],"sourceRoot":""} \ No newline at end of file diff --git a/src/web/assets/recententries/src/RecentEntriesWidget.js b/src/web/assets/recententries/src/RecentEntriesWidget.js index edb2562dedb..142dd7c645e 100644 --- a/src/web/assets/recententries/src/RecentEntriesWidget.js +++ b/src/web/assets/recententries/src/RecentEntriesWidget.js @@ -7,16 +7,16 @@ $widget: null, $body: null, $container: null, - $tbody: null, + $list: null, hasEntries: null, init: function (widgetId, params) { this.params = params; this.$widget = $('#widget' + widgetId); this.$body = this.$widget.find('.body:first'); - this.$container = this.$widget.find('.recententries-container:first'); - this.$tbody = this.$container.find('tbody:first'); - this.hasEntries = !!this.$tbody.length; + this.$container = this.$body.find('.recententries-container:first'); + this.$list = this.$container.find('ol:first'); + this.hasEntries = !!this.$list.length; this.$widget.data('widget').on('destroy', this.destroy.bind(this)); @@ -24,23 +24,14 @@ }, addEntry: function (entry) { - this.$container.css('margin-top', 0); - var oldHeight = this.$container.height(); - if (!this.hasEntries) { - // Create the table first - var $table = $('
' +\n '' +\n Craft.escapeHtml(entry.title) +\n ' ' +\n '' +\n Craft.escapeHtml(\n (entry.dateCreated ? Craft.formatDate(entry.dateCreated) : '') +\n (entry.dateCreated &&\n entry.username &&\n Craft.edition == Craft.Pro\n ? ', '\n : '') +\n (entry.username && Craft.edition == Craft.Pro\n ? entry.username\n : '')\n ) +\n '' +\n '
').prependTo( - this.$container - ); - this.$tbody = $('').appendTo($table); + // Create the list first + this.$list = $('
    ').appendTo(this.$container); } - this.$tbody.prepend( - '
' + - '' + - '' + '' ); - var newHeight = this.$container.height(), - heightDiff = newHeight - oldHeight; - - this.$container.css('margin-top', -heightDiff); - - var props = {'margin-top': 0}; - // Also animate the "No entries exist" text out of view if (!this.hasEntries) { - props['margin-bottom'] = -oldHeight; + this.$container.find('.zilch').remove(); this.hasEntries = true; } - - this.$container.velocity(props); }, destroy: function () { From a4dfeb74dcad3ace4dcc5cae2393e6a6c7b349e0 Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Sun, 28 Jan 2024 18:45:34 -0600 Subject: [PATCH 07/12] Minor typos and grammar --- src/web/twig/Extension.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/web/twig/Extension.php b/src/web/twig/Extension.php index a482840c886..7f03229e413 100644 --- a/src/web/twig/Extension.php +++ b/src/web/twig/Extension.php @@ -558,7 +558,7 @@ public function currencyFilter(mixed $value, ?string $currency = null, array $op } /** - * Formats the value in bytes as a size in human readable form for example `12 kB`. + * Formats the value in bytes as a size in human-readable form, for example `12 kB`. * * @param mixed $value * @param int|null $decimals @@ -945,7 +945,7 @@ private function isRegex(string $str): bool * @param DateTimeInterface|DateInterval|string $date A date * @param string|null $format The target format, null to use the default * @param DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged - * @param string|null $locale The target locale the date should be formatted for. By default the current system locale will be used. + * @param string|null $locale The target locale the date should be formatted for. By default, the current system locale will be used. * @return string */ public function dateFilter(TwigEnvironment $env, mixed $date, ?string $format = null, mixed $timezone = null, ?string $locale = null): string @@ -1044,7 +1044,7 @@ public function rssFilter(TwigEnvironment $env, mixed $date, mixed $timezone = n * @param DateTimeInterface|string $date A date * @param string|null $format The target format, null to use the default * @param DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged - * @param string|null $locale The target locale the date should be formatted for. By default the current systme locale will be used. + * @param string|null $locale The target locale the date should be formatted for. By default, the current system locale will be used. * @return string */ public function timeFilter(TwigEnvironment $env, mixed $date, ?string $format = null, mixed $timezone = null, ?string $locale = null): string @@ -1074,7 +1074,7 @@ public function timeFilter(TwigEnvironment $env, mixed $date, ?string $format = * @param DateTimeInterface|string $date A date * @param string|null $format The target format, null to use the default * @param DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged - * @param string|null $locale The target locale the date should be formatted for. By default the current systme locale will be used. + * @param string|null $locale The target locale the date should be formatted for. By default, the current system locale will be used. * @return string */ public function datetimeFilter(TwigEnvironment $env, mixed $date, ?string $format = null, mixed $timezone = null, ?string $locale = null): string @@ -1139,7 +1139,7 @@ public function filterFilter(TwigEnvironment $env, iterable $arr, ?callable $arr } /** - * Groups an array by a the results of an arrow function, or value of a property. + * Groups an array by the results of an arrow function, or value of a property. * * @param iterable $arr * @param callable|string $arrow The arrow function or property name that determines the group the item should be grouped in @@ -1574,11 +1574,11 @@ public function shuffleFunction(iterable $arr): array * * @param string|Asset $svg An SVG asset, a file path, or raw SVG markup * @param bool|null $sanitize Whether the SVG should be sanitized of potentially - * malicious scripts. By default the SVG will only be sanitized if an asset + * malicious scripts. By default, the SVG will only be sanitized if an asset * or markup is passed in. (File paths are assumed to be safe.) * @param bool|null $namespace Whether class names and IDs within the SVG * should be namespaced to avoid conflicts with other elements in the DOM. - * By default the SVG will only be namespaced if an asset or markup is passed in. + * By default, the SVG will only be namespaced if an asset or markup is passed in. * @param string|null $class A CSS class name that should be added to the `` element. * (This argument is deprecated. The `|attr` filter should be used instead.) * @return string From d868102b737827c4c370c49b67f792e21bb8b6b7 Mon Sep 17 00:00:00 2001 From: Iwona Just Date: Mon, 29 Jan 2024 08:36:15 +0000 Subject: [PATCH 08/12] fix for optgroup and "0" label in options field condition rule --- src/fields/conditions/OptionsFieldConditionRule.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/fields/conditions/OptionsFieldConditionRule.php b/src/fields/conditions/OptionsFieldConditionRule.php index 32cd3e4b960..952cf9d00bd 100644 --- a/src/fields/conditions/OptionsFieldConditionRule.php +++ b/src/fields/conditions/OptionsFieldConditionRule.php @@ -24,7 +24,12 @@ protected function options(): array /** @var BaseOptionsField $field */ $field = $this->field(); return Collection::make($field->options) - ->filter(fn(array $option) => $option['value'] !== null && $option['value'] !== '' && !empty($option['label'])) + ->filter(fn(array $option) => (array_key_exists('value', $option) && + $option['value'] !== null && + $option['value'] !== '' && + $option['label'] !== null && + $option['label'] !== '' + )) ->map(fn(array $option) => [ 'value' => $option['value'], 'label' => $option['label'], From 13ff8b718f953704b8300b4c366e064c0d773380 Mon Sep 17 00:00:00 2001 From: Tim Kelty Date: Mon, 29 Jan 2024 10:18:03 -0500 Subject: [PATCH 09/12] Remove useless catch --- src/mail/Mailer.php | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/mail/Mailer.php b/src/mail/Mailer.php index 6733c854b6e..454e6d9e35a 100644 --- a/src/mail/Mailer.php +++ b/src/mail/Mailer.php @@ -12,7 +12,6 @@ use craft\helpers\App; use craft\helpers\Template; use craft\web\View; -use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Throwable; use yii\base\InvalidConfigException; use yii\helpers\Markdown; @@ -175,22 +174,6 @@ public function send($message): bool $message->setBcc([]); } - try { - return parent::send($message); - } catch (TransportExceptionInterface $e) { - $eMessage = $e->getMessage(); - - // Remove the stack trace to get rid of any sensitive info. - $eMessage = substr($eMessage, 0, strpos($eMessage, 'Stack trace:') - 1); - Craft::warning('Error sending email: ' . $eMessage); - - // Save the exception on the message, for plugins to make use of - if ($message instanceof Message) { - $message->error = $e; - } - - $this->afterSend($message, false); - return false; - } + return parent::send($message); } } From bb00ebde94c5cc00c54348d4c1870e64e56fb4f1 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Mon, 29 Jan 2024 10:03:35 -0800 Subject: [PATCH 10/12] Release notes [ci skip] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2d09861b9..197866d69f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - Fixed a bug where empty Dropdown fields were getting treated as dirty when unchanged. - Fixed a bug where Recent Entries widgets were getting mangled when new entries were created via Quick Post widgets. +- Fixed an error that occurred when adding a Dropdown field condition rule, if the field contained any optgroups. ([#14224](https://github.com/craftcms/cms/issues/14224)) +- Fixed a bug where Dropdown field condition rules weren’t displaying `0` options. ([#14232](https://github.com/craftcms/cms/pull/14232)) ## 4.7.0 - 2024-01-23 From c50c36e34c6cee23efaf5a84549b1dce4d9bb5d4 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Mon, 29 Jan 2024 10:57:32 -0800 Subject: [PATCH 11/12] Stop showing timestamp meta for unpublished drafts Resolves #14204 --- CHANGELOG.md | 1 + src/base/Element.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 197866d69f6..a68c1b7246f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Unpublished drafts no longer show “Created at” or “Updated at” metadata values. ([#14204](https://github.com/craftcms/cms/issues/14204)) - Fixed a bug where empty Dropdown fields were getting treated as dirty when unchanged. - Fixed a bug where Recent Entries widgets were getting mangled when new entries were created via Quick Post widgets. - Fixed an error that occurred when adding a Dropdown field condition rule, if the field contained any optgroups. ([#14224](https://github.com/craftcms/cms/issues/14224)) diff --git a/src/base/Element.php b/src/base/Element.php index 42c4a199a38..30ed42beddc 100644 --- a/src/base/Element.php +++ b/src/base/Element.php @@ -5082,10 +5082,10 @@ public function getMetadata(): array return $icon . Html::tag('span', $label); }, ], $event->metadata, [ - Craft::t('app', 'Created at') => $this->dateCreated + Craft::t('app', 'Created at') => $this->dateCreated && !$this->getIsUnpublishedDraft() ? $formatter->asDatetime($this->dateCreated, Formatter::FORMAT_WIDTH_SHORT) : false, - Craft::t('app', 'Updated at') => $this->dateUpdated + Craft::t('app', 'Updated at') => $this->dateUpdated && !$this->getIsUnpublishedDraft() ? $formatter->asDatetime($this->dateUpdated, Formatter::FORMAT_WIDTH_SHORT) : false, Craft::t('app', 'Notes') => function() { From 918a8e1eafed45d70f78043c92635d3e2aac7e21 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Mon, 29 Jan 2024 10:59:27 -0800 Subject: [PATCH 12/12] Finish 4.7.1 --- CHANGELOG.md | 2 +- src/config/app.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a68c1b7246f..bd2d2feb766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Release Notes for Craft CMS 4 -## Unreleased +## 4.7.1 - 2024-01-29 - Unpublished drafts no longer show “Created at” or “Updated at” metadata values. ([#14204](https://github.com/craftcms/cms/issues/14204)) - Fixed a bug where empty Dropdown fields were getting treated as dirty when unchanged. diff --git a/src/config/app.php b/src/config/app.php index 858c2e2778a..9bab3926884 100644 --- a/src/config/app.php +++ b/src/config/app.php @@ -3,7 +3,7 @@ return [ 'id' => 'CraftCMS', 'name' => 'Craft CMS', - 'version' => '4.7.0', + 'version' => '4.7.1', 'schemaVersion' => '4.5.3.0', 'minVersionRequired' => '3.7.11', 'basePath' => dirname(__DIR__), // Defines the @app alias
' + - '' + + this.$list.prepend( + '
  • ' + + `` + Craft.escapeHtml(entry.title) + ' ' + '' + @@ -56,24 +47,14 @@ : '') ) + '' + - '