Skip to content

Prevent fatal error in webp_uploads_filter_wp_get_attachment_image() when wp_get_attachment_image_src() returns false and during rest_prepare_attachment filtering#2565

Merged
westonruter merged 13 commits into
trunkfrom
fix/2563-fatal-error-in-get-attachment-image
Jul 3, 2026
Merged

Prevent fatal error in webp_uploads_filter_wp_get_attachment_image() when wp_get_attachment_image_src() returns false and during rest_prepare_attachment filtering#2565
westonruter merged 13 commits into
trunkfrom
fix/2563-fatal-error-in-get-attachment-image

Conversation

@westonruter

@westonruter westonruter commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #2563

Relevant technical choices

See #2563 (comment)

Use of AI Tools

Claude Code with Claude Opus 4.8 used for code review and writing tests.

@github-actions github-actions Bot added the [Plugin] Modern Image Formats Issues for the Modern Image Formats plugin (formerly WebP Uploads) label Jul 2, 2026
@westonruter westonruter marked this pull request as ready for review July 2, 2026 23:15
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @vladte4, @1aTa, @Dave-LB.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Unlinked contributors: vladte4, 1aTa, Dave-LB.

Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: mukeshpanchal27 <mukesh27@git.wordpress.org>
Co-authored-by: b1ink0 <b1ink0@git.wordpress.org>
Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@westonruter westonruter changed the title [WIP] Debug fatal error in Modern Image Formats in webp_uploads_filter_wp_get_attachment_image() Prevent fatal error in webp_uploads_filter_wp_get_attachment_image() when wp_get_attachment_image_src() returns false Jul 2, 2026
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.35%. Comparing base (726398d) to head (3e10b34).

Additional details and impacted files
@@            Coverage Diff             @@
##            trunk    #2565      +/-   ##
==========================================
- Coverage   70.38%   70.35%   -0.03%     
==========================================
  Files          91       91              
  Lines        7850     7867      +17     
==========================================
+ Hits         5525     5535      +10     
- Misses       2325     2332       +7     
Flag Coverage Δ
multisite 70.35% <100.00%> (-0.03%) ⬇️
single 35.17% <23.80%> (-0.43%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@westonruter westonruter added the [Type] Bug An existing feature is broken label Jul 3, 2026
@westonruter westonruter added this to the webp-uploads 2.7.1 milestone Jul 3, 2026

@mukeshpanchal27 mukeshpanchal27 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @westonruter for the PR!

Here's what I tested:

  1. Check out the trunk branch.

  2. Add the following filter to prevent the fatal error in webp_uploads_filter_wp_get_attachment_image():

    add_filter( 'wp_get_attachment_image_src', '__return_false' );
  3. Add new page and add Image block.

  4. Check out the PR branch fix/2563-fatal-error-in-get-attachment-image.

  5. Reload the page.

  6. Select the same image that was uploaded in the previous test (in my case, car.jpeg).

  7. Observe the critical error returned by the REST endpoint.

{
    "code": "internal_server_error",
    "message": "<p>There has been a critical error on this website.<\/p><p><a href=\"https:\/\/wordpress.org\/documentation\/article\/faq-troubleshooting\/\">Learn more about troubleshooting WordPress.<\/a><\/p>",
    "data": {
        "status": 500,
        "error": {
            "type": 1,
            "message": "Uncaught TypeError: str_replace(): Argument #3 ($subject) must be of type array|string, null given in \/var\/www\/html\/wp-content\/plugins\/webp-uploads\/rest-api.php:41\nStack trace:\n#0 \/var\/www\/html\/wp-content\/plugins\/webp-uploads\/rest-api.php(41): str_replace('', 'car-300x169.avi...', NULL)\n#1 \/var\/www\/html\/wp-includes\/class-wp-hook.php(343): webp_uploads_update_rest_attachment(Object(WP_REST_Response), Object(WP_Post))\n#2 \/var\/www\/html\/wp-includes\/plugin.php(205): WP_Hook->apply_filters(Object(WP_REST_Response), Array)\n#3 \/var\/www\/html\/wp-includes\/rest-api\/endpoints\/class-wp-rest-attachments-controller.php(1081): apply_filters('rest_prepare_at...', Object(WP_REST_Response), Object(WP_Post), Object(WP_REST_Request))\n#4 \/var\/www\/html\/wp-includes\/rest-api\/endpoints\/class-wp-rest-posts-controller.php(669): WP_REST_Attachments_Controller->prepare_item_for_response(Object(WP_Post), Object(WP_REST_Request))\n#5 \/var\/www\/html\/wp-includes\/rest-api\/class-wp-rest-server.php(1287): WP_REST_Posts_Controller->get_item(Object(WP_REST_Request))\n#6 \/var\/www\/html\/wp-includes\/rest-api\/class-wp-rest-server.php(1120): WP_REST_Server->respond_to_request(Object(WP_REST_Request), '\/wp\/v2\/media\/(?...', Array, NULL)\n#7 \/var\/www\/html\/wp-includes\/rest-api\/class-wp-rest-server.php(435): WP_REST_Server->dispatch(Object(WP_REST_Request))\n#8 \/var\/www\/html\/wp-includes\/rest-api.php(471): WP_REST_Server->serve_request('\/wp\/v2\/media\/95')\n#9 \/var\/www\/html\/wp-includes\/class-wp-hook.php(341): rest_api_loaded(Object(WP))\n#10 \/var\/www\/html\/wp-includes\/class-wp-hook.php(365): WP_Hook->apply_filters('', Array)\n#11 \/var\/www\/html\/wp-includes\/plugin.php(570): WP_Hook->do_action(Array)\n#12 \/var\/www\/html\/wp-includes\/class-wp.php(418): do_action_ref_array('parse_request', Array)\n#13 \/var\/www\/html\/wp-includes\/class-wp.php(821): WP->parse_request('')\n#14 \/var\/www\/html\/wp-includes\/functions.php(1343): WP->main('')\n#15 \/var\/www\/html\/wp-blog-header.php(16): wp()\n#16 \/var\/www\/html\/index.php(17): require('\/var\/www\/html\/w...')\n#17 {main}\n  thrown",
            "file": "\/var\/www\/html\/wp-content\/plugins\/webp-uploads\/rest-api.php",
            "line": 41
        }
    },
    "additional_errors": []
}
Screenshot 2026-07-03 at 9 11 27 AM

Comment thread plugins/webp-uploads/hooks.php Outdated
* @return string The filtered HTML.
*/
function webp_uploads_filter_wp_get_attachment_image( string $html, int $attachment_id, $size, bool $icon, array $attr ): string {
function webp_uploads_filter_wp_get_attachment_image( string $html, int $attachment_id, $size, bool $icon, $attr ): string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Make $attachment_id accept string as well, and cast it to int afterward, as many plugins send the attachment ID as a string. This was also reported on the support forum:

https://wordpress.org/support/topic/fatal-error-after-2-7-0/

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 0442a52

Co-authored-by: b1ink0 <b1ink0@git.wordpress.org>
@westonruter

Copy link
Copy Markdown
Member Author

@mukeshpanchal27 I'm having trouble reproducing the issue with the steps you reported.

@westonruter

westonruter commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

I think I can reproduce it now. I had to switch to WebP instead of AVIF, because I wasn't getting modern images generated at all 😕

PHP Warning:  Undefined array key "source_url" in /var/www/src/wp-content/plugins/performance/plugins/webp-uploads/rest-api.php on line 39
PHP Deprecated:  urlencode(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/src/wp-includes/formatting.php on line 5718

$image_url_basename = wp_basename( $details['source_url'] );

And here:

Uncaught Error: str_replace(): Argument #3 ($subject) must be of type array|string, null given in /var/www/src/wp-content/plugins/performance/plugins/webp-uploads/rest-api.php on line 41

$mime_details['source_url'] = str_replace( $image_url_basename, $mime_details['file'], $details['source_url'] );

Both seem to be addressed by making sure that source_url is set and is a string.

Co-authored-by: mukeshpanchal27 <mukesh27@git.wordpress.org>
@westonruter

Copy link
Copy Markdown
Member Author

@mukeshpanchal27 Please try now.

@westonruter

westonruter commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

Build for testing:

  1. webp-uploads.zip
  2. webp-uploads.zip
  3. webp-uploads.zip

westonruter and others added 6 commits July 3, 2026 11:42
Add `@covers` tags to the existing Test_WebP_Uploads_REST_API tests and add
regression tests for the defensive guards in webp_uploads_update_rest_attachment(),
covering a missing/non-string `source_url`, a missing/invalid mime source `file`
in both the per-size and full-size loops, and non-array response data.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…filter

Convert the query-string test into a data-provider-driven test covering an
empty string, a query string, an array, and an invalid `false` value passed
as the `$attr` argument, asserting each is normalized before being passed to
the inner `webp_uploads_filter_wp_get_attachment_image` filter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@westonruter westonruter dismissed mukeshpanchal27’s stale review July 3, 2026 19:27

Reported issue has been addressed

* @param string|mixed $html HTML img element or empty string on failure.
* @param int|numeric-string $attachment_id Image attachment ID.
* @param string|array{int, int} $size Requested image size.
* @param bool|mixed $icon Whether the image should fall back to a mime type icon.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This isn't actually ever not a bool as far as I know, but I figured best to just let this be untyped for consistency with the other params. Using mixed here prevents PHPCS from complaining that there is no native type hint.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a fatal type error in the WebP Uploads plugin’s wp_get_attachment_image filter callback when WordPress passes a non-array $attr value (notably when wp_get_attachment_image_src() returns false). It also hardens the REST API response mutation to avoid notices/fatals when expected array keys/types are missing.

Changes:

  • Relax and normalize arguments in webp_uploads_filter_wp_get_attachment_image() to safely handle non-string HTML, non-int attachment IDs, and string/non-array $attr.
  • Add defensive checks in webp_uploads_update_rest_attachment() before rewriting source_url fields.
  • Add/extend PHPUnit coverage for these edge cases (including “no image returned” and REST API malformed data scenarios).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
plugins/webp-uploads/tests/test-rest-api.php Adds tests covering REST response edge cases (missing/invalid source_url, invalid sources entries, non-array response data).
plugins/webp-uploads/tests/test-load.php Adds tests for wp_get_attachment_image() rewrite behavior when wp_get_attachment_image_src() returns false and for $attr normalization.
plugins/webp-uploads/rest-api.php Adds type/key guards to prevent invalid REST attachment data from triggering errors during source URL rewriting.
plugins/webp-uploads/hooks.php Makes the wp_get_attachment_image filter callback resilient to core passing non-array $attr and other unexpected argument types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plugins/webp-uploads/tests/test-load.php
Comment thread plugins/webp-uploads/tests/test-load.php
Comment thread plugins/webp-uploads/hooks.php

@adamsilverstein adamsilverstein left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the quick fix.

@westonruter westonruter merged commit eeb3a57 into trunk Jul 3, 2026
27 of 32 checks passed
@westonruter westonruter deleted the fix/2563-fatal-error-in-get-attachment-image branch July 3, 2026 22:39
@westonruter westonruter changed the title Prevent fatal error in webp_uploads_filter_wp_get_attachment_image() when wp_get_attachment_image_src() returns false Prevent fatal error in webp_uploads_filter_wp_get_attachment_image() when wp_get_attachment_image_src() returns false and harden rest_prepare_attachment filtering Jul 3, 2026
@westonruter westonruter changed the title Prevent fatal error in webp_uploads_filter_wp_get_attachment_image() when wp_get_attachment_image_src() returns false and harden rest_prepare_attachment filtering Prevent fatal error in webp_uploads_filter_wp_get_attachment_image() when wp_get_attachment_image_src() returns false and during rest_prepare_attachment filtering Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Plugin] Modern Image Formats Issues for the Modern Image Formats plugin (formerly WebP Uploads) [Type] Bug An existing feature is broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modern Image Formats (webp-uploads) v2.7.0

5 participants