Skip to content

Don't take a data: placeholder in a lazy-load attribute as the image URL - #1190

Merged
pirate-bot merged 3 commits into
developmentfrom
fix/data-uri-image-url
Oct 21, 2026
Merged

pirate-bot merged 3 commits into
developmentfrom
fix/data-uri-image-url

Conversation

@selul

@selul selul commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Requested by Marius · project thread

All Submissions:

  • Have you followed the Optimole Contributing guideline?
  • Does your code follow the WordPress' coding standards?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?

Changes proposed in this Pull Request:

Before: in '<img data-src="data:image/gif;base64,…" src="photo.jpg">', the image parser took data:image/gif as the image URL. The tag replacer then worked on the placeholder: the image got no profiler srcset or dimensions, and its data-opt-id came from the placeholder, so every image with that placeholder shared one ID.

After: the parser skips a data: value in a lazy-load attribute and uses the real src. The image gets its dimensions, srcset and its own data-opt-id.

Why it happened: by default the attribute alternation in parse_images_from_html() is just src, and the \s? before it is optional. So it also matches the src= at the end of data-src=, data-lazy-src= and so on, and takes whichever comes first.

How: the regex now has two branches. A plain src= is matched as before, including a data: value. Any other *src= attribute (and the optml_possible_src_attributes ones) is skipped when its value starts with data: (case-insensitive).

Why a plain data: src is still matched: when another lazy-load script owns the image (src="data:…" data-lazy-src="photo.jpg"), Optimole currently leaves the tag alone and only rewrites URLs. Skipping data: everywhere would make it process those tags and add a second <noscript>. Test_Lazyload::test_check_with_no_script and test_check_with_multiple_images_in_no_script failed that way with the broader version, so this PR keeps that behaviour.

What changes for other markup: a tag whose only source attributes are data: lazy attributes and no src (for example '&lt;img data-src="data:…"&gt;') is no longer picked up by the tag replacer. Before, it was processed against the placeholder URL, which did nothing useful.

Closes #1186.

How to test the changes in this Pull Request:

  1. Test_Replacer::test_parse_images_skips_data_uri_in_lazy_attribute: double quotes, single quotes, data-lazy-src, src first, and upper-case DATA-SRC/DATA: all give the real URL and the whole tag.
  2. Test_Replacer::test_parse_images_keeps_data_uri_src: src="data:…" data-lazy-src="…" still gives data:image/gif.
  3. Test_Dimension_Replacement::test_dimensions_injected_when_data_src_placeholder_comes_first: with profiler data seeded for the real URL, the tag gets width="1920", height="1080" and the real URL's data-opt-id. On development it gets data-opt-id=771715633, which comes from the placeholder, and no dimensions.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully ran tests with your changes locally?
Check on ce5764e Result
New tests PASS on the fix. On development, 2 of 3 fail as expected (the data-uri src test passes on both, as intended)
Mutation: drop the plain-src branch test_parse_images_keeps_data_uri_src fails
Full PHPUnit suite (PHP 8.3) PASS, 431 tests (baseline 428)
Regex on PHP 7.4 and 8.3, incl. escaped JSON markup same results
phpcs, PHPStan on inc/manager.php PASS

Not proven: the full suite on PHP 7.4 (my local 7.4 container fails at bootstrap on development too), and a live site with the page profiler, since that needs the Optimole service. The Codex review step was replaced by a self-review because the Codex CLI isn't available in this environment.


Generated by Claude Code

…mage 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
@selul selul self-assigned this Oct 20, 2026
@pirate-bot

pirate-bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Plugin build for a9f9857 is ready 🛎️!

@selul
selul requested a review from pirate-bot October 20, 2026 15:31

@pirate-bot pirate-bot left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes requested

The parser fix works, but add tests for the tag shapes it now changes, including the new lazy-load result.

Validation details
  • Files reviewed: 3/3 changed files.
  • An isolated run of the base and HEAD regex used the real character class cp /repo/inc/config.php /repo/inc/app_replacer.php /repo/inc/manager.php /workspace/checks/LC1/; cp /workspace/review/re… printed DIFFER=1,2,3,4,5,6,7,9,11 (run R3). HEAD never took the placeholder and never matched across tags.
  • On PHP 8.3 with PHPUnit 9.6, two of the three new tests fail on pr-base and all pass on HEAD.
  • Test_Replacer and Test_Dimension_Replacement pass on HEAD.
  • Test_Lazyload::test_dam_lazyloading fails on HEAD and on pr-base alike in the sandbox.
  • A lazy-load probe showed no duplicate attributes and one <noscript> per tag `cat > /workspace/checks/RUN1b/Integration_Lazy_Example.php <<'EOF'
Untested areas - The full suite and PHP 7.4 were not run. - No browser check covered a tag that keeps `data-src="data:…"` next to `data-opt-src`. - Profiler `srcset` and crop handling for the fixed tag shape were not asserted.
🤖 Automated review · run code-review-agent_6ad78946a17627.14574941. --- **🤖 Review agent** — review posted ✅ on `ce5764e1` · [changes requested · 2 findings](https://github.com//pull/1190#pullrequestreview-5587756317) · 19 min Run `code-review-agent_6ad78946a17627.14574941` · [trail](https://agents.vertistudio.com/admin/trails/github-pr/Codeinwp-optimole-wp-1190)

Comment thread tests/test-replacer.php
Comment thread inc/manager.php
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPwFxvA5VPq8sd4EzsNFFA
@selul
selul requested a review from pirate-bot October 20, 2026 16:02

@pirate-bot pirate-bot left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The PR passes. The new tests cover the requested tag shapes and fail without the parser fix.

Validation details
  • Files reviewed: 4/4 changed files. Only the tests changed since the prior review.
  • With the pr-base parser, the new lazy-load test fails set -o pipefail; cd /workspace/checks/RUN2a/base && timeout 600 vendor/bin/phpunit --do-not-cache-result --filter 'Test_… printed Failures: 1 (run R5).
  • On HEAD, the same test passes set -o pipefail; cd /repo && timeout 600 vendor/bin/phpunit --do-not-cache-result --filter 'Test_Lazyload::test_lazyload… printed OK (1 test, 6 assertions) (run R7).
  • With the pr-base parser, the new replacer test fails set -o pipefail; cd /workspace/checks/RUN2a/base && timeout 600 vendor/bin/phpunit --do-not-cache-result --filter 'Test_… printed Failures: 1 (run R6).
  • On HEAD, Test_Lazyload, Test_Replacer and Test_Dimension_Replacement fail only test_dam_lazyloading set -o pipefail; cd /repo; timeout 900 vendor/bin/phpunit --do-not-cache-result --filter 'Test_(Lazyload|Replacer|Dimens… (run R4, exit 0).
  • The parser and security checks come from run code-review-agent_6ad78946a17627.14574941 and were not rerun.
Untested areas
  • The suite did not run on PHP 7.4.
  • No live site with the page profiler was checked.
  • This run did not check test_dam_lazyloading on pr-base.

🤖 Automated review · run code-review-agent_6ad7909ba62382.76864001.


🤖 Review agent — review posted ✅ on 6f5f8b14 · approved · 0 findings · 9 min

Run code-review-agent_6ad7909ba62382.76864001 · trail

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPwFxvA5VPq8sd4EzsNFFA
@pirate-bot
pirate-bot merged commit e29c894 into development Oct 21, 2026
11 of 12 checks passed
@pirate-bot
pirate-bot deleted the fix/data-uri-image-url branch October 21, 2026 21:01
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.

2 participants