Skip to content

Image Editor reload appends stacking cache timestamp and doesn't reflect edits behind a CDN #595

Open

Description

@suprim-simple

Description

When you edit an image with the asset Image Editor from inside a CKEditor field, _reloadImage() in src/web/assets/ckeditor/src/image/imageeditor/imageeditorcommand.js builds a cache-busted src from srcInfo.baseSrc. But baseSrc comes from the greedy (.*) in _srcInfo()'s regex:

const match = src.match(/(.)#asset:(\d+)(?::transform:([a-zA-Z][a-zA-Z0-9_]))?/);
// baseSrc = match[1] → everything before "#asset:", INCLUDING any existing query
So baseSrc already contains the previously-appended ?, and _reloadImage() appends another one each time:

let newSrc = image.srcInfo.baseSrc + '?' + new Date().getTime() + '#asset:' + image.srcInfo.assetId;
The query string stacks on every edit, producing malformed URLs (a URL can only have one ?):

…/MT-3_2026-06-09-020259_hbsn.jpeg?0?1780971727673?1780971779690?1780971926837#asset:1395663
This stacked URL is then persisted into the stored field content.

A second, related problem: even with a single valid cache-buster, the editor swaps the src immediately on save with no allowance for CDN propagation. When assets are served through a CDN that caches by path / doesn't vary on the query string and invalidates asynchronously (e.g. CloudFront + AWS Serverless Image Handler, which is a very common Craft setup), the reload fetches the still-cached pre-edit image, so the edit doesn't visibly update — often requiring repeated saves or a hard refresh.

For reference, Craft core avoids this for its own thumbnails by deriving a stable, content-based buster from the asset's modified time (AssetsHelper::revUrl() / revParams() → ?v=), rather than appending a fresh timestamp onto whatever is already in the src.

imageeditorcommand.js

Steps to reproduce

  • Insert an image asset into a CKEditor field and save the entry.
  • Select the image → open the Image Editor → crop/rotate → Save.
  • Repeat step 2 two or three more times.
  • View the image src (editor "Source" view or the saved field content): the query string accumulates — ???… — instead of being replaced.
  • (If assets are behind a CDN like CloudFront/Serverless Image Handler) the edited image also fails to display the change until multiple saves / a hard refresh, because the stale CDN copy keeps being served.

Additional info
Craft version: 5.10.5
PHP version: 8.2.28
Database driver & version: MySQL 8.0.40
Plugins & versions:
CKEditor (craftcms/ckeditor), 5.x branch (CKEditor 5, ckeditor5 ^48.2.0)
AWS S3 (craftcms/aws-s3) 2.3.0 — assets on S3 served via CloudFront + Serverless Image Handler

Activity

  1. linear-code commented on Jun 9, 2026

    @linear-code
  2. self-assigned this
    on Jun 15, 2026
  3. i-just commented on Jun 16, 2026

    @i-just
    Contributor

    Hi @suprim-simple, thanks for reporting and for a clear description. I raised a PR for this. If you’re able to test this early, you can change your composer.json requirement to

    "craftcms/ckeditor": "5.x-dev#b906677332c9113903b26f35333fb862149f3d26 as 5.6.1"
    

    and run composer update

  4. suprim-simple commented on Aug 4, 2026

    @suprim-simple
    Author

    Hi @i-just 👋

    I've tested the changes. Two things:

    1. Malformed URL fix — ✅ confirmed working. The malformed/reversed asset URL issue is resolved on my end.

    2. Second issue (CDN propagation / browser cache) — ❌ still reproduces. When I crop/edit an already-inserted image in the CKEditor Image Editor and hit Save, the editor still shows the pre-edit (stale) image rather than the newly-cropped one.

    Environment:
    Craft version: 5.10.5
    PHP version: 8.2.28
    Database driver & version: MySQL 8.0.40
    Plugins & versions:
    CKEditor (craftcms/ckeditor), 5.x branch (CKEditor 5, ckeditor5 ^48.2.0)
    AWS S3 (craftcms/aws-s3) 2.3.0 — assets on S3 served via CloudFront + Serverless Image Handler

    Reproduction steps:

    1. Insert an image into a CKEditor field.
    2. Select it → open the Image Editor → crop/rotate → Save.
    3. The image in the editor still displays the original, un-cropped version.

    Key diagnostic — it's tied to the browser cache:

    • With DevTools → Network → "Disable cache" ticked (cache disabled), the edited image require hard refreshes then correctly and shows the crop. (does not wait CDN propagation could be fixed with timeout or )
    • With "Disable cache" unticked (normal browsing, cache enabled), the crop/edit still shows the stale image.
  5. i-just commented on Aug 7, 2026

    @i-just
    Contributor

    Hi @suprim-simple, thanks for testing this!

    Could you please let me know if you have revAssetUrls turned on or off (either via config/general.php or environment variable)?

  6. suprim-simple commented on Aug 9, 2026

    @suprim-simple
    Author

    Hi, yep I have revAssetUrls turned on for the project.

  7. brandonkelly commented on Aug 10, 2026

    @brandonkelly
    Member

    CKEditor 5.7.0 is out with the fix from #598. We’re still deciding what to do about the CDN issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions