Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.15 #16490

Draft
wants to merge 57 commits into
base: 5.x
Choose a base branch
from
Draft

4.15 #16490

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
2e0f00b
New translations app.php (Thai)
shinybrad Jan 22, 2025
f7b6aa5
New translations app.php (Thai)
shinybrad Jan 22, 2025
d5fea72
New translations app.php (Dutch)
shinybrad Jan 22, 2025
09aea31
New translations app.php (Thai)
shinybrad Jan 22, 2025
2eb222c
remove invisible Unicode special characters from search keywords
i-just Jan 22, 2025
6f12622
adjust tests
i-just Jan 22, 2025
1263a19
New translations app.php (German, Switzerland)
shinybrad Jan 22, 2025
b7b73b5
New translations app.php (Thai)
shinybrad Jan 22, 2025
6388527
Prep 4.15 release notes
brandonkelly Jan 22, 2025
8f28308
New translations app.php (Thai)
shinybrad Jan 22, 2025
1e4fb94
Merge pull request #16477 from craftcms/t9n/4.x
brandonkelly Jan 22, 2025
9723e16
Merge branch '4.x' into bugfix/16457-unicode-special-chars-and-search
brandonkelly Jan 22, 2025
cbd337e
Cleanup
brandonkelly Jan 22, 2025
0b1283c
Release note
brandonkelly Jan 22, 2025
76b8643
Merge pull request #16483 from craftcms/bugfix/16457-unicode-special-…
brandonkelly Jan 22, 2025
7fe604f
Typo
brandonkelly Jan 22, 2025
95f92e4
Finish 4.14.1
brandonkelly Jan 23, 2025
2455dcf
New translations app.php (Thai)
shinybrad Jan 23, 2025
f167c56
New translations app.php (Thai)
shinybrad Jan 23, 2025
962e22e
New translations app.php (Thai)
shinybrad Jan 23, 2025
baa4cb1
New translations app.php (Thai)
shinybrad Jan 23, 2025
9f81f01
New translations app.php (Thai)
shinybrad Jan 23, 2025
8a12e4f
New translations app.php (Thai)
shinybrad Jan 23, 2025
12955b4
Fixed #16506
brandonkelly Jan 24, 2025
696dedb
Merge branch '4.x' into 4.15
brandonkelly Jan 25, 2025
012b965
Stop showing outdated attribute statuses for anything besides derivat…
brandonkelly Jan 25, 2025
56fcdaf
Merge branch '4.x' into 4.15
brandonkelly Jan 25, 2025
950a1dc
Delete pointless change data via GC
brandonkelly Jan 25, 2025
f7db48e
Release note
brandonkelly Jan 25, 2025
e83eccf
$transportAdapter is null here
brandonkelly Jan 25, 2025
e568e90
Merge pull request #16531 from craftcms/feature/less-changedfields
brandonkelly Jan 25, 2025
97baca5
Merge branch '4.x' into 4.15
brandonkelly Jan 25, 2025
45c09e5
Don't create ID cache tags if > 100 IDs
brandonkelly Jan 25, 2025
1391897
Merge pull request #16498 from craftcms/t9n/4.x
brandonkelly Jan 26, 2025
8c82495
Merge branch '4.x' into 4.15
brandonkelly Jan 26, 2025
37fdca9
Truncate the resourcepaths table
brandonkelly Jan 26, 2025
a61840f
Fixed mergeCanonicalChanges() for Matrix sub-fields
brandonkelly Jan 26, 2025
514d28d
when propagating element, cross site validate if we're changing the s…
i-just Jan 27, 2025
01869ca
ensure the db connection is closed before transaction events are regi…
joshuapease Jan 27, 2025
9058914
Exclude normal drafts too
brandonkelly Jan 27, 2025
dbef44d
Release note
brandonkelly Jan 27, 2025
b7fad82
Merge pull request #16533 from craftcms/bugfix/16505-crossvalidate-wh…
brandonkelly Jan 27, 2025
6e6d53f
Merge branch '4.x' into test-db-connection-fix
brandonkelly Jan 27, 2025
bd21abd
Release note
brandonkelly Jan 27, 2025
e7ac8ab
Remove ʻokina characters along with other punctuation
brandonkelly Jan 28, 2025
9ab9310
Make PHPStan happy
brandonkelly Jan 28, 2025
22c4b16
Finish 4.14.2
brandonkelly Jan 28, 2025
2f42a4a
Merge branch '4.x' into 4.15
brandonkelly Jan 29, 2025
1a95ee7
refactor: make test integration compatible with newer versions of `co…
Jan 29, 2025
a41444a
Fixed #16579
brandonkelly Jan 29, 2025
e716c71
Merge pull request #16580 from qrazi/patch_16577
brandonkelly Jan 29, 2025
8a01737
Release note for #16580
brandonkelly Jan 29, 2025
c3812c7
Don't filter out excluded descendants when checking for descendants
brandonkelly Jan 29, 2025
8d4bc53
Finish 4.14.3
brandonkelly Jan 29, 2025
34b7aba
Merge branch '4.x' into 4.15
brandonkelly Jan 30, 2025
5199f6e
--batch-size option for resave/* commands
brandonkelly Jan 30, 2025
c125954
Support for aria-label on nav items
brandonkelly Jan 30, 2025
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
11 changes: 11 additions & 0 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Release Notes for Craft CMS 4.15 (WIP)

### Administration
- Added the `--batch-size` option for `resave/*` commands. ([#16586](https://github.com/craftcms/cms/issues/16586))

### Extensibility
- Global nav items and breadcrumbs can now have `aria-label` attributes via an `ariaLabel` property.

### System
- The `changedattributes` and `changedfields` tables are now cleaned up during garbage collection. ([#16531](https://github.com/craftcms/cms/pull/16531))
- The `resourcepaths` table is now truncated when clearing control panel resources, via the Caches utility or the `clear-caches/cp-resources` command. ([#16514](https://github.com/craftcms/cms/issues/16514))
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Release Notes for Craft CMS 4

## 4.14.3 - 2025-01-29

- Added `craft\db\ExpressionBuilder`.
- Added `craft\db\ExpressionInterface`.
- Added compatibility with codeception/module-yii2 1.1.6+. ([#16580](https://github.com/craftcms/cms/pull/16580))
- Fixed a bug where `craft\db\QueryBatcher::getSlice()` wasn’t using the database connection passed to the class constructor. ([#16579](https://github.com/craftcms/cms/issues/16579))
- Fixed a bug where collapsed elements within element indexes in structure view weren’t showing their expand/collapse toggles.

## 4.14.2 - 2025-01-28

- Fixed a bug where Entries fields’ entry select modals could show expand/collapse toggles for Structure sections, for elements that didn’t have any selectable descendants. ([#16506](https://github.com/craftcms/cms/issues/16506))
- Fixed a bug where changes to custom fields within Matrix blocks weren’t getting merged into existing drafts for the same owner element. ([#16519](https://github.com/craftcms/cms/issues/16519))
- Fixed a bug where native fields (e.g. Title) were showing changed statuses when viewing revisions, if they had been updated since the time the revision was created.
- Fixed a bug where eager-loading element queries could create an excessive amount of cache invalidation tags.
- Fixed a bug where it was possible to enable elements for new sites with validation errors. ([#16505](https://github.com/craftcms/cms/issues/16505))
- Fixed a bug where setting `transaction: true` in the Codeception configuration wasn’t rolling back database DML changes after a test. ([#16546](https://github.com/craftcms/cms/issues/16546))
- Fixed a bug where ʻokina characters weren’t being removed in auto-generated slugs. ([#16548](https://github.com/craftcms/cms/issues/16548))

## 4.14.1 - 2025-01-22

- Fixed a bug where all multi-byte characters were getting stripped out of search indexes. ([#16457](https://github.com/craftcms/cms/issues/16457))

## 4.14.0.2 - 2025-01-21

- Fixed an error that occurred when creating a new Structure section. ([#16476](https://github.com/craftcms/cms/issues/16476))
Expand Down
24 changes: 22 additions & 2 deletions src/base/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use craft\behaviors\DraftBehavior;
use craft\behaviors\RevisionBehavior;
use craft\db\Connection;
use craft\db\ExcludeDescendantIdsExpression;
use craft\db\Query;
use craft\db\Table;
use craft\elements\actions\Delete;
Expand Down Expand Up @@ -1123,6 +1124,7 @@ public static function indexHtml(ElementQueryInterface $elementQuery, ?array $di
'collapsedElementIds' => Craft::$app->getRequest()->getParam('collapsedElementIds'),
'showCheckboxes' => $showCheckboxes,
'tableName' => static::pluralDisplayName(),
'elementQuery' => self::elemnetQueryWithAllDescendants($elementQuery),
];

$db = Craft::$app->getDb();
Expand Down Expand Up @@ -1196,6 +1198,24 @@ public static function indexHtml(ElementQueryInterface $elementQuery, ?array $di
return Craft::$app->getView()->renderTemplate($template, $variables);
}

private static function elemnetQueryWithAllDescendants(ElementQueryInterface $elementQuery): ElementQueryInterface
{
if (is_array($elementQuery->where)) {
foreach ($elementQuery->where as $key => $condition) {
if ($condition instanceof ExcludeDescendantIdsExpression) {
$elementQuery = clone $elementQuery;
unset($elementQuery->where[$key]);
break;
}
}
} elseif ($elementQuery->where instanceof ExcludeDescendantIdsExpression) {
$elementQuery = clone $elementQuery;
$elementQuery->where = null;
}

return $elementQuery;
}

/**
* Prepares an element query for an element index that includes a given table attribute.
*
Expand Down Expand Up @@ -4009,7 +4029,7 @@ public function isAttributeModified(string $name): bool
*/
private function _outdatedAttributes(): array
{
if (!static::trackChanges() || $this->getIsCanonical()) {
if (!static::trackChanges() || $this->getIsCanonical() || $this->getIsRevision()) {
return [];
}

Expand Down Expand Up @@ -4283,7 +4303,7 @@ public function isFieldModified(string $fieldHandle, bool $anySite = false): boo
*/
private function _outdatedFields(): array
{
if (!static::trackChanges() || !$this->getIsDraft() || $this->getIsCanonical()) {
if (!static::trackChanges() || $this->getIsCanonical() || $this->getIsRevision()) {
return [];
}

Expand Down
2 changes: 1 addition & 1 deletion src/config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
return [
'id' => 'CraftCMS',
'name' => 'Craft CMS',
'version' => '4.14.0.2',
'version' => '4.14.3',
'schemaVersion' => '4.5.3.0',
'minVersionRequired' => '3.7.11',
'basePath' => dirname(__DIR__), // Defines the @app alias
Expand Down
8 changes: 8 additions & 0 deletions src/console/controllers/ResaveController.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ final public static function normalizeTo(?string $to): callable
*/
public bool $queue = false;

/**
* @var int The number of entries that should be resaved per queue job, if --queue is passed.
* @since 4.15.0
*/
public int $batchSize = 100;

/**
* @var bool Whether to resave element drafts.
* @since 3.6.5
Expand Down Expand Up @@ -243,6 +249,7 @@ public function options($actionID): array
{
$options = parent::options($actionID);
$options[] = 'queue';
$options[] = 'batchSize';
$options[] = 'elementId';
$options[] = 'uid';
$options[] = 'site';
Expand Down Expand Up @@ -459,6 +466,7 @@ public function resaveElements(string $elementType, array $criteria = []): int
'ifInvalid' => $this->ifInvalid,
'touch' => $this->touch,
'updateSearchIndex' => $this->updateSearchIndex,
'batchSize' => $this->batchSize,
]));
$this->stdout($elementType::pluralDisplayName() . ' queued to be resaved.' . PHP_EOL);
return ExitCode::OK;
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/ElementIndexesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use craft\base\ElementActionInterface;
use craft\base\ElementExporterInterface;
use craft\base\ElementInterface;
use craft\db\ExcludeDescendantIdsExpression;
use craft\elements\actions\DeleteActionInterface;
use craft\elements\actions\Restore;
use craft\elements\conditions\ElementCondition;
Expand Down Expand Up @@ -645,7 +646,8 @@ protected function elementQuery(): ElementQueryInterface
}

if (!empty($descendantIds)) {
$query->andWhere(['not', ['elements.id' => $descendantIds]]);
/** @phpstan-ignore-next-line */
$query->andWhere(new ExcludeDescendantIdsExpression($descendantIds));
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions src/db/ExcludeDescendantIdsExpression.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\db;

use Craft;

/**
* ExcludeIdsExpression represents the condition SQL used to exclude certain
* descendant element IDs from an element query
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 4.14.3
*/
class ExcludeDescendantIdsExpression implements ExpressionInterface
{
/**
* Constructor
*
* @param int[] $elementIds The element IDs to exclude
*/
public function __construct(
private array $elementIds,
) {
}

/**
* @param array $params
* @return string
*/
public function getSql(array &$params): string
{
return Craft::$app->getDb()->getQueryBuilder()->buildCondition(['not', ['elements.id' => $this->elementIds]], $params);
}
}
33 changes: 33 additions & 0 deletions src/db/ExpressionBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\db;

use yii\base\NotSupportedException;
use yii\db\ExpressionBuilderInterface;
use yii\db\ExpressionBuilderTrait;
use yii\db\ExpressionInterface as BaseExpressionInterface;

/**
* ExpressionBuilder builds [[ExpressionInterface]] DB expressions.
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 4.14.3
*/
class ExpressionBuilder implements ExpressionBuilderInterface
{
use ExpressionBuilderTrait;

public function build(BaseExpressionInterface $expression, array &$params = [])
{
if (!$expression instanceof ExpressionInterface) {
throw new NotSupportedException(sprintf('$expression must be an instance of %s.', ExpressionInterface::class));
}

return $expression->getSql($params);
}
}
22 changes: 22 additions & 0 deletions src/db/ExpressionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\db;

use yii\db\ExpressionInterface as BaseExpressionInterface;

/**
* ExpressionInterface defines the common interface that should be implemented by expressions
* which should be built by [[ExpressionBuilder]].
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 4.14.3
*/
interface ExpressionInterface extends BaseExpressionInterface
{
public function getSql(array &$params): string;
}
2 changes: 1 addition & 1 deletion src/db/QueryBatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function getSlice(int $offset, int $limit): iterable
$slice = $query
->offset((is_int($queryOffset) ? $queryOffset : 0) + $offset)
->limit($limit)
->all();
->all($this->db);
} catch (QueryAbortedException) {
$slice = [];
}
Expand Down
5 changes: 5 additions & 0 deletions src/db/mysql/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use Composer\Util\Platform;
use Craft;
use craft\db\Connection;
use craft\db\ExpressionBuilder;
use craft\db\ExpressionInterface;
use craft\db\TableSchema;
use craft\helpers\App;
use craft\helpers\Db;
Expand Down Expand Up @@ -87,6 +89,9 @@ protected function findTableNames($schema = ''): array
public function createQueryBuilder(): QueryBuilder
{
return new QueryBuilder($this->db, [
'expressionBuilders' => [
ExpressionInterface::class => ExpressionBuilder::class,
],
'separator' => "\n",
]);
}
Expand Down
5 changes: 5 additions & 0 deletions src/db/pgsql/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use Composer\Util\Platform;
use Craft;
use craft\db\Connection;
use craft\db\ExpressionBuilder;
use craft\db\ExpressionInterface;
use craft\db\TableSchema;
use mikehaertl\shellcommand\Command as ShellCommand;
use yii\db\Exception;
Expand Down Expand Up @@ -49,6 +51,9 @@ class Schema extends \yii\db\pgsql\Schema
public function createQueryBuilder(): QueryBuilder
{
return new QueryBuilder($this->db, [
'expressionBuilders' => [
ExpressionInterface::class => ExpressionBuilder::class,
],
'separator' => "\n",
]);
}
Expand Down
7 changes: 5 additions & 2 deletions src/elements/db/ElementQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -2209,8 +2209,11 @@ public function getCacheTags(): array
"element::$this->elementType",
];

// If specific IDs were requested, then use those
if (is_numeric($this->id) || (is_array($this->id) && ArrayHelper::isNumeric($this->id))) {
// If (<= 100) specific IDs were requested, then use those
if (
is_numeric($this->id) ||
(is_array($this->id) && count($this->id) <= 100 && ArrayHelper::isNumeric($this->id))
) {
$queryTags = (array)$this->id;
} else {
$queryTags = $this->cacheTags();
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/ElementHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public static function normalizeSlug(string $slug): string
$slug = StringHelper::stripHtml($slug);

// Remove inner-word punctuation
$slug = preg_replace('/[\'"‘’“”\[\]\(\)\{\}:]/u', '', $slug);
$slug = preg_replace('/[\'"‘’“”ʻ\[\]\(\)\{\}:]/u', '', $slug);

// Make it lowercase
$generalConfig = Craft::$app->getConfig()->getGeneral();
Expand Down
8 changes: 2 additions & 6 deletions src/helpers/FileHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,9 @@ public static function sanitizeFilename(string $filename, array $options = []):
// Replace any control characters in the name with a space.
$filename = preg_replace("/\\x{00a0}/iu", ' ', $filename);

// Remove invisible chars from the filename
// https://github.com/craftcms/cms/issues/12741
// Remove soft hyphens (00ad), no break (0083),
// zero width space (200b), zero width non-joiner (200c), zero width joiner (200d),
// LTR character (200e), RTL character (200f),
// invisible times (2062), invisible comma (2063), invisible plus (2064),
// zero width non-break space (feff) in the filename
$filename = preg_replace('/\\x{00ad}|\\x{0083}|\\x{200b}|\\x{200c}|\\x{200d}|\\x{200e}|\\x{200f}|\\x{2062}|\\x{2063}|\\x{2064}|\\x{feff}/iu', '', $filename);
$filename = preg_replace(StringHelper::invisibleCharsRegex(), '', $filename);

// Strip any characters not allowed.
$filename = str_replace($disallowedChars, '', strip_tags($filename));
Expand Down
8 changes: 0 additions & 8 deletions src/helpers/MailerHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
use craft\mail\transportadapters\Smtp;
use craft\mail\transportadapters\TransportAdapterInterface;
use yii\base\Event;
use yii\helpers\Inflector;

/**
* Class MailerHelper
Expand Down Expand Up @@ -152,13 +151,6 @@ public static function settingsReport(Mailer $mailer, ?TransportAdapterInterface
foreach ($settingsAttributes as $name) {
$transportSettings[$transportAdapter->getAttributeLabel($name)] = $transportAdapter->$name;
}
} else {
// Otherwise just output whatever public properties we have available on the transport
/** @var array $asArray */
$asArray = (array)$transportAdapter;
foreach ($asArray as $name => $value) {
$transportSettings[Inflector::camel2words($name, true)] = $value;
}
}

foreach ($transportSettings as $label => $value) {
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/Search.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ public static function normalizeKeywords(array|string $str, array $ignore = [],
}
}

// Get rid of Unicode special characters
// Get rid of invisible Unicode special characters
// (see https://github.com/craftcms/cms/issues/16430)
$str = preg_replace('/[\x{80}-\x{10FFFF}]/u', '', $str);
$str = preg_replace(StringHelper::invisibleCharsRegex(), '', $str);

// Strip out new lines and superfluous spaces
return trim(preg_replace(['/[\n\r]+/u', '/\s{2,}/u'], ' ', $str));
Expand Down
Loading