Skip to content

Commit 7aab354

Browse files
committed
Merge branch '4.x' into bugfix/18577-namespacing-and-aria-attributes
2 parents 1c05830 + d401ae8 commit 7aab354

278 files changed

Lines changed: 3964 additions & 5445 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v16.13.1
1+
v22

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Release Notes for Craft CMS 4
22

3+
## Unreleased
4+
5+
- Fixed a bug where GraphQL results were getting cached even if they contained transform generation URLs. ([#18581](https://github.com/craftcms/cms/issues/18581))
6+
37
## 4.17.11 - 2026-03-17
48

59
- Fixed an error that could occur after running the `utils/fix-field-layout-uids` command. ([#18516](https://github.com/craftcms/cms/issues/18516))

package-lock.json

Lines changed: 3565 additions & 5152 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,54 +19,54 @@
1919
],
2020
"devDependencies": {
2121
"@craftcms/webpack": "file:packages/craftcms-webpack",
22-
"@playwright/test": "^1.19.2",
22+
"@playwright/test": "^1.58.2",
2323
"husky": "^9.1.7",
24-
"lint-staged": "^16.1.6",
25-
"prettier": "^2.7.1",
26-
"tailwindcss": "^3.0.18",
27-
"vue-apexcharts": "^1.6.2"
24+
"lint-staged": "^16.4.0",
25+
"prettier": "^2.8.8",
26+
"tailwindcss": "^3.4.19",
27+
"vue-apexcharts": "^1.7.0"
2828
},
2929
"dependencies": {
3030
"@benmajor/jquery-touch-events": "^2.0.3",
3131
"@craftcms/sass": "file:packages/craftcms-sass",
3232
"@craftcms/vue": "file:packages/craftcms-vue",
3333
"@selectize/selectize": "selectize/selectize.js#master",
34-
"@types/jquery": "^3.5.7",
34+
"@types/jquery": "^3.5.34",
3535
"accounting": "^0.4.1",
36-
"axios": "^1.12.2",
37-
"blueimp-file-upload": "^10.31.0",
38-
"d3": "^4.11.0",
39-
"d3-format": "^1.4.4",
40-
"d3-time-format": "^2.2.3",
36+
"axios": "^1.13.6",
37+
"blueimp-file-upload": "^10.32.0",
38+
"d3": "^4.13.0",
39+
"d3-format": "^1.4.5",
40+
"d3-time-format": "^2.3.0",
4141
"event-stream": "3.3.5",
42-
"fabric": "^1.7.19",
43-
"graphiql": "~1.7.2",
42+
"fabric": "^1.7.22",
43+
"graphiql": "~1.11.5",
4444
"graphiql-explorer": "^0.9.0",
45-
"graphql": "^15.8.0",
46-
"htmx.org": "^1.6.1",
47-
"iframe-resizer": "^4.3.2",
45+
"graphql": "^15.10.1",
46+
"htmx.org": "^1.9.12",
47+
"iframe-resizer": "^4.4.5",
4848
"inputmask": "^5.0.9",
49-
"jquery": "^3.6.0",
50-
"jquery-ui": "^1.14.0",
49+
"jquery": "^3.7.1",
50+
"jquery-ui": "^1.14.2",
5151
"jquery.payment": "^3.0.0",
5252
"picturefill": "^3.0.3",
5353
"punycode": "^2.3.1",
5454
"react": "^16.14.0",
5555
"react-dom": "^16.14.0",
56-
"timepicker": "^1.13.18",
56+
"timepicker": "^1.14.1",
5757
"ttf2woff2": "^5.0.0",
58-
"typescript": "^4.7.4",
59-
"v-tooltip": "^2.0.3",
60-
"velocity-animate": "^1.5.0",
61-
"vue": "^2.6.14",
58+
"typescript": "^4.9.5",
59+
"v-tooltip": "^2.1.3",
60+
"velocity-animate": "^1.5.2",
61+
"vue": "^2.7.16",
6262
"vue-autosuggest": "^2.2.0",
6363
"vue-awesome-swiper": "^4.1.1",
6464
"vue-cleave": "^1.2.2",
65-
"vue-lodash": "^1.0.3",
66-
"vue-router": "^3.5.4",
65+
"vue-lodash": "^1.0.4",
66+
"vue-router": "^3.6.5",
6767
"vuex": "^3.6.2",
6868
"whatwg-fetch": "^0.11.1",
6969
"xregexp": "^3.2.0",
70-
"yii2-pjax": "~2.0.1"
70+
"yii2-pjax": "~2.0.8"
7171
}
7272
}

src/gql/ElementQueryConditionBuilder.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public function extractQueryConditions(?FieldInterface $startingParentField = nu
157157

158158
// Load up all eager loading rules.
159159
$extractedConditions = [
160-
'with' => $this->_traversAndBuildPlans($startingNode, $rootPlan, $startingParentField, null, $startingParentField ? $startingParentField->context : 'global'),
160+
'with' => $this->_traverseAndBuildPlans($startingNode, $rootPlan, $startingParentField, null, $startingParentField ? $startingParentField->context : 'global'),
161161
];
162162

163163
if (!empty($rootPlan->criteria['withTransforms'])) {
@@ -387,7 +387,7 @@ private function _isInsideAssetQuery(): bool
387387
* @param string $context the context in which to search fields
388388
* @return array
389389
*/
390-
private function _traversAndBuildPlans(Node $parentNode, EagerLoadPlan $parentPlan, ?FieldInterface $parentField = null, ?Node $wrappingFragment = null, string $context = 'global'): array
390+
private function _traverseAndBuildPlans(Node $parentNode, EagerLoadPlan $parentPlan, ?FieldInterface $parentField = null, ?Node $wrappingFragment = null, string $context = 'global'): array
391391
{
392392
$subNodes = $parentNode->selectionSet->selections ?? [];
393393
$plans = [];
@@ -534,7 +534,7 @@ private function _traversAndBuildPlans(Node $parentNode, EagerLoadPlan $parentPl
534534
$traverseContext = $context;
535535
}
536536

537-
$plan->nested = $this->_traversAndBuildPlans($subNode, $plan, $nodeName === self::LOCALIZED_NODENAME ? $parentField : $craftContentField, $wrappingFragment, $traverseContext);
537+
$plan->nested = $this->_traverseAndBuildPlans($subNode, $plan, $nodeName === self::LOCALIZED_NODENAME ? $parentField : $craftContentField, $wrappingFragment, $traverseContext);
538538
}
539539
}
540540
// If not, see if it's a fragment
@@ -556,7 +556,7 @@ private function _traversAndBuildPlans(Node $parentNode, EagerLoadPlan $parentPl
556556
// Build the prefix, load the context and proceed in a recursive manner
557557
try {
558558
$gqlFragmentEntity = $parentField->getGqlFragmentEntityByName($nodeName);
559-
$plan->nested = $this->_traversAndBuildPlans($subNode, $plan, $parentField, $wrappingFragment, $gqlFragmentEntity->getFieldContext());
559+
$plan->nested = $this->_traverseAndBuildPlans($subNode, $plan, $parentField, $wrappingFragment, $gqlFragmentEntity->getFieldContext());
560560

561561
// Correct the handles and, maybe, aliases.
562562
foreach ($plan->nested as $nestedPlan) {
@@ -568,11 +568,11 @@ private function _traversAndBuildPlans(Node $parentNode, EagerLoadPlan $parentPl
568568
}
569569
// This is to be expected, depending on whether the fragment is targeted towards the field itself instead of its subtypes.
570570
} catch (InvalidArgumentException) {
571-
$plan->nested = $this->_traversAndBuildPlans($subNode, $plan, $parentField, $wrappingFragment, $context);
571+
$plan->nested = $this->_traverseAndBuildPlans($subNode, $plan, $parentField, $wrappingFragment, $context);
572572
}
573573
// If we are not, just expand the fragment and traverse it as if on the same level in the query tree
574574
} else {
575-
$plan->nested = $this->_traversAndBuildPlans($subNode, $plan, $parentField, $wrappingFragment, $context);
575+
$plan->nested = $this->_traverseAndBuildPlans($subNode, $plan, $parentField, $wrappingFragment, $context);
576576
}
577577
}
578578

src/services/Gql.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ public function executeQuery(
534534

535535
[$dep, $duration] = $elementsService->stopCollectingCacheInfo();
536536

537-
if (empty($event->result['errors']) && $cacheKey) {
537+
if (empty($event->result['errors']) && $cacheKey && $this->shouldCache($event->result)) {
538538
$this->setCachedResult($cacheKey, $event->result, $dep, $duration);
539539
}
540540
}
@@ -545,6 +545,23 @@ public function executeQuery(
545545
return $event->result ?? [];
546546
}
547547

548+
private function shouldCache(array $result): bool
549+
{
550+
foreach ($result as $value) {
551+
if (is_string($value)) {
552+
if (str_contains(stripslashes($value), 'assets/generate-transform')) {
553+
return false;
554+
}
555+
} elseif (is_array($value)) {
556+
if (!$this->shouldCache($value)) {
557+
return false;
558+
}
559+
}
560+
}
561+
562+
return true;
563+
}
564+
548565
/**
549566
* Invalidates all GraphQL result caches.
550567
*

src/web/assets/admintable/dist/css/app.css

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/web/assets/admintable/dist/css/app.css.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/web/assets/admintable/dist/js/app.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/web/assets/admintable/dist/js/app.js.LICENSE.txt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,3 @@
66
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
77
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
88
*/
9-
10-
/**!
11-
* Sortable 1.15.6
12-
* @author RubaXa <trash@rubaxa.org>
13-
* @author owenm <owen23355@gmail.com>
14-
* @license MIT
15-
*/

0 commit comments

Comments
 (0)