Skip to content

Release - #1195

Open
pirate-bot wants to merge 9 commits into
masterfrom
development
Open

Release#1195
pirate-bot wants to merge 9 commits into
masterfrom
development

Conversation

@pirate-bot

@pirate-bot pirate-bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Linked issues

This release will close the following issues once merged:

Public changelog

  • Fixed image replacement failing when a cache token was numeric.
  • Fixed placeholder-first images missing responsive srcset and dimensions.
  • Fixed Image Storage transfers retrying a failed step without end
  • Added option to keep hand-written image sizes attributes
  • Fixed pages with many images running out of memory.
  • Fixed repeated database errors filling error logs on frontend pages
  • Fixed restored images getting extra numbered copies after interrupted rollbacks

pirate-bot and others added 3 commits October 19, 2026 15:46
Individual cache tokens are stored as the API returned them, which can be
a number. get_active_cache_booster() passed that value straight to
Optimole::image(), whose cache buster is typed as a string, so image URL
replacement threw a TypeError and broke the request. Cast the token to a
string, and fall back to an empty token for non-scalar values.

Closes #1187


Claude-Session: https://claude.ai/code/session_01WPwFxvA5VPq8sd4EzsNFFA

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@pirate-bot

pirate-bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator Author

Plugin build for 863751c is ready 🛎️!

selul and others added 6 commits October 22, 2026 00:01
…URL (#1190)

* fix: don't take a data: placeholder in a lazy-load attribute as the image URL

The image regex matches the `src=` at the end of any `*-src=` attribute, so
in `<img data-src="data:image/gif;..." src="photo.jpg">` it captured the
placeholder. The tag replacer then ran against `data:image/gif`: no
profiler srcset or dimensions, and a data-opt-id shared by every image
with that placeholder.

A lazy-load attribute whose value starts with data: is now skipped, so
the real src is used. A data: value in a plain src is still matched, so
images owned by another lazy-load script are handled as before.

Fixes #1186

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPwFxvA5VPq8sd4EzsNFFA

* test: cover data: placeholders without a src and their lazy-load result

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPwFxvA5VPq8sd4EzsNFFA

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: stop retrying a failing transfer step forever

When a background transfer step threw (an API error, a lookup that
keeps failing), it was rescheduled 10 seconds later with the same step,
with no limit. The transfer stayed "in progress" in the dashboard and
never finished.

The failed attempts of a step are now counted; after 5 in a row the
chain moves on to the next step, so the transfer can reach its end and
the images left behind can be retried. A successful step clears the
count.

Refs #1108

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* Keep step failures per transfer in an option and don't report success after skips

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* Fix the finish branch comment

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

---------

Co-authored-by: Claude <noreply@anthropic.com>
* feat: let an image keep its own sizes attribute

The page profiler adds its measured breakpoints to an image's sizes
attribute unless the value contains calc() or a similar formula. Sites
with hand-written sizes had no supported way to keep them.

An image with data-optml-keep-sizes now keeps its existing sizes
attribute (srcset candidates are still added). The
optml_keep_existing_sizes filter does the same site-wide without
changing the markup.

Refs #1115

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* Clarify keep-sizes log, FAQ and tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* Check the attribute keeps sizes before the filter overrides it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

---------

Co-authored-by: Claude <noreply@anthropic.com>
* fix: bound the in-memory attachment ID cache

The request-local map in Optml_Attachment_Cache kept every distinct URL
looked up during a request, including misses, with no limit. It now keeps
at most 2000 URLs and drops the older half when full; dropped URLs are
still served from the persistent cache (transient or object cache).

Refs #1139

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* Cover the cache-miss path in the memory cap test and fix the value type

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

---------

Co-authored-by: Claude <noreply@anthropic.com>
…f sync" logs (#1196)

* fix: pass the page through unprocessed after a fatal error

A fatal error that hits while MySQL is still sending rows leaves the
connection out of sync, so every profiler and cache read at shutdown
logged "Commands out of sync". Skip processing in that case.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* test: cover both fatal-error pass-through paths

Read the last PHP error through a private seam so tests can simulate a
fatal error. New buffer tests check that the default in-handler mode and
the shutdown-capture mode both pass the page through unprocessed; each
fails when its guard is removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* docs: give the error reader seam a precise callable type

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

---------

Co-authored-by: Claude <noreply@anthropic.com>
…pted rollbacks (#1191)

* fix: make the transfer lock atomic and clean up files left by interrupted rollbacks

Two requests that started a transfer at the same moment could both take the
transfer lock, because it was read and then written. The lock is now stored
with an insert that fails when the row already exists (wp_cache_add with a
persistent object cache).

A rollback that died after moving the restored file into uploads left that
file behind, so the retry got a suffixed name (.1-1.webp) while references
kept the old one. The moved file is now recorded on the attachment until the
rollback finishes, the retry removes it first, and the attachment points to
the restored file right after the move instead of after the sub-sizes.

Refs #1136

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* fix: reuse the file left by an interrupted rollback instead of deleting it

Review follow-up on the rollback cleanup:
- the retry writes the downloaded image over the file the interrupted
  attempt left behind, instead of deleting it before the sideload, so a
  failed move never leaves the attachment pointing at a missing file;
- the pending-file meta is also cleared when the retry ends in the branch
  for attachments whose local metadata was already saved;
- the uploads-dir check normalizes both paths, so it works on Windows;
- the lock expiry is written again after the insert;
- native parameter and return types on the new helpers.

Refs #1136

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* Write the restored file through a temporary copy and keep the lock expiry after a racing release

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

* Add native types to the failing stream test helper

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEXWtYdE6e3ALYtqtP8j2p

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment