Skip to content

[6.x] Fix named transform handles, unsupported asset transforms, and GraphQL immediately - #20594

Merged
riasvdv merged 5 commits into
6.xfrom
rias/cms-2671-6x-upgrade-discards-the-transform-index-and
Nov 11, 2026
Merged

riasvdv merged 5 commits into
6.xfrom
rias/cms-2671-6x-upgrade-discards-the-transform-index-and

Conversation

@riasvdv

@riasvdv riasvdv commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes the GraphQL and asset regressions from #20588 for sites upgraded from Craft 5:

@transform(handle: "f1500")          before: _1500xAUTO_fit_center-center_100_none_ns/   after: _f1500/
url @transform(width: 320) on .mp4   before: NotSupportedException fails the query       after: the video's own URL
asset.getUrl({width: 320}) on .mp4   before: null                                         after: the video's own URL
url @transform(..., immediately: true)  before: unknown argument                          after: generated transform URL
  • Named transforms keep their handle. AssetTransformers passes the named transform to drivers as AssetTransformRequest::$namedTransform when the definition doesn't override its parameters. The craft driver stores and indexes it under _{handle}.
  • Unsupported assets fall back to their own values. GraphQL transform fields, getUrl() with a transform, and the transform arguments of getWidth(), getHeight(), getFormat() and getMimeType() return the asset's own values on NotSupportedException, as in Craft 5, and don't report it. Asset::transform(), MCP and the transform controller still throw.
  • immediately is passed to every driver. AssetTransformRequest::$immediately (nullable) carries the caller's preference. withImmediateTransforms(), immediateTransforms() and IMMEDIATE_TRANSFORMS_CONTEXT move to AssetTransformers, and CraftAssetTransformDriver keeps its beta.1 method and constant as deprecated forwarders.
  • GraphQL immediately is back as a per-query transform argument.

Unchanged on purpose: the upgrade still clears the transform index, because Craft 6 stores transforms under _{volumeUid}/. craftcms/docs#801 documents how to move Craft 5 transforms there so they're reused.

Evidence

Each new test fails without its fix and passes with it:

  • ImageTransformerTest › keeps named transform handles: f1500 and ['transform' => 'f1500'] index as _f1500; overrides still use the parameter string.
  • Gql/AssetTransformsTest › resolves source values for Assets the transformer can't transform: before, the query returned NotSupportedException; after, the video's URL, size, format and MIME type.
  • Gql/AssetTransformsTest › generates craft transforms before returning their URLs when requested: immediately: true returns a URL whose file exists on disk; without it, a generate-transform URL.
  • AssetTransformersTest › returns the source values for unsupported assets; passes immediate generation requests to drivers (null, true, false).
  • Adapter AssetTransformCompatibilityTest › source URL for unsupported assets in native and legacy assets; legacy image transformers get immediately: true.

Related issues

riasvdv and others added 5 commits November 10, 2026 22:30
AssetTransformers now passes the named Image Transform to drivers as AssetTransformRequest::$namedTransform when a definition uses one without overriding its parameters. The craft driver generates and indexes it under its handle, so GraphQL named transforms are stored at _{handle}/ again rather than under a parameter string.

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a1c75f-81cb-7691-a8d8-f4023e7fe794
When an asset's transformer throws NotSupportedException, such as for a video in a mixed Assets field, GraphQL transform fields, getUrl() with a transform, and the transform arguments of getWidth(), getHeight(), getFormat() and getMimeType() now return the asset's own values, as in Craft 5, and the exception isn't reported. Asset::transform(), MCP and the transform controller still throw.

The legacy Asset overrides the new _runTransform() hook instead of _tryTransform(), so it shares the same fallback.

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a1c75f-81cb-7691-a8d8-f4023e7fe794
AssetTransformRequest now carries a nullable $immediately, filled from the caller's preference, so drivers decide what to do with it instead of only the craft driver reading the context. withImmediateTransforms(), immediateTransforms() and IMMEDIATE_TRANSFORMS_CONTEXT live on AssetTransformers. CraftAssetTransformDriver keeps its beta.1 method and constant as deprecated forwarders.

Legacy image transformers get the value through the request rather than their constructor.

Amp-Thread-ID: https://ampcode.com/threads/T-01a1c75f-81cb-7691-a8d8-f4023e7fe794
Co-authored-by: Amp <amp@ampcode.com>
Transform arguments and the @Transform directive accept immediately again. It's removed from the transform definition and runs the transform within AssetTransformers::withImmediateTransforms(), so static builds can get generated transform URLs per query rather than only through the disk's generate_transforms_before_page_load setting.

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a1c75f-81cb-7691-a8d8-f4023e7fe794
[ci skip]

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a1c75f-81cb-7691-a8d8-f4023e7fe794
@linear-code

linear-code Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

CMS-2671

@github-actions

Copy link
Copy Markdown

📚 Storybook previews

@craftcms/ui — open Storybook

No changed components detected in this Storybook.

resources/js — open Storybook

No changed components detected in this Storybook.

@riasvdv
riasvdv merged commit 4c436cc into 6.x Nov 11, 2026
@riasvdv
riasvdv deleted the rias/cms-2671-6x-upgrade-discards-the-transform-index-and branch November 11, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants