Skip to content

Frontend image replacement fatals when Preload\Links is unavailable #1121

Description

@pirate-bot

Summary

Frontend image replacement can terminate with a class-not-found fatal while processing page images.

Expected behavior: Image processing remains safe when the preload helper cannot be resolved.

Actual behavior: Processing reaches a call to the preload helper and the request terminates with Class "…Preload\\Links" not found.

Impact: Affected frontend requests can return an incomplete or blank response instead of rendered content.

Customer context

  • Product / area: Optimole WordPress plugin, frontend image/tag replacement
  • Version: 4.2.10 and 4.2.11
  • Environment: WordPress 7.1; PHP 8.3.33 and 8.5.9
  • Integration / third party: Themeisle SDK 3.3.57 and 3.3.58 reported, but the crash location is outside SDK code
  • Reported error / symptom: Class "…Preload\\Links" not found at inc/tag_replacer.php:301
  • Impact: 2 occurrences across 2 distinct production sites in the telemetry query window.

Reproduction notes

  1. Install Optimole 4.2.10 or 4.2.11 in a state where the Composer autoloader is unavailable or unreadable. This condition is inferred from the source and production error; it was not reproduced locally.
  2. Request frontend content containing an image that Optimole parses for replacement.
  3. The reported execution path reaches process_image_tags() and terminates with Class "…Preload\\Links" not found.

Telemetry confirms this occurred twice on two production sites; the original installation state is unavailable.

Diagnosis

Conclusion

Production telemetry records the fatal at the exact call site during frontend content replacement. The repository confirms that this call is unconditional after an image tag is processed, while loading the Composer autoloader is conditional on vendor/autoload.php being readable. This creates a reachable fatal path when the namespaced preload class is unavailable.

Where this likely occurs

  • inc/tag_replacer.phpOptml_Tag_Replacer::process_image_tags() lines 197–321 processes parsed image tags; lines 301–302 directly invoke Links::is_preloaded() and Links::preload_tag().
  • inc/tag_replacer.php — file line 3 imports OptimoleWP\Preload\Links, matching the crash class name.
  • inc/manager.phpOptml_Manager::process_images_from_content() lines 587–595 applies the tag-replacement filter when frontend content contains images; Optml_Manager::replace_content() line 482 reaches the same flow through output buffering.
  • inc/main.phpOptml_Main::instance() lines 95–99 includes vendor/autoload.php only if it is readable.
  • composer.jsonautoload lines 18–24 maps OptimoleWP\ to inc/v2/; inc/v2/Preload/Links.php lines 2–9 defines the expected OptimoleWP\Preload\Links class.
  • Commit d096d4bb28e01ddc56c5fce937adbd20d4b0fa63 introduced the preload reference, class, and PSR-4 mapping. The inc/tag_replacer.php blob is unchanged from v4.2.8 through v4.2.11; v4.2.10 is 060fd3fe424f5fd239304fd8dd7f6736fb90596d and v4.2.11 is e9ee20c5a5e10565d2f8ffc56aa77fe76b202332.

Engineering notes

The class file and its Composer PSR-4 mapping are present in the inspected source, so the telemetry does not by itself establish why the class was unavailable on the affected installations. The release workflow runs composer install --no-dev, and .distignore does not exclude vendor, which suggests clean release artifacts are intended to contain Composer autoload metadata. The observed failure is nevertheless reachable because the legacy loader only handles Optml* classes and does not load the OptimoleWP\ namespace. The report covers the frontend image-processing path only; it does not establish scope for other namespaced classes or installation/update mechanisms.

Test coverage status

No relevant coverage was found during inspection. The tests/ search found no test exercising Preload\Links, Links::is_preloaded(), Links::preload_tag(), or missing/unreadable Composer autoload behavior. tests/test-replacer.php covers tag replacer behavior generally, but this failure path was not identified in the inspected test references.

What to verify or explore next

  • Reproduce with an affected release where vendor/autoload.php is absent or unreadable, then render frontend content containing an image that reaches process_image_tags().
  • Inspect the installed file inventory and generated Composer autoload metadata from a failing installation, if safely available, to distinguish an incomplete package from an update/integrity state.
  • Run the relevant PHP test suite around tests/test-replacer.php in an environment with the WordPress test dependencies installed.
  • Verify whether other frontend paths that call OptimoleWP\ classes exhibit the same behavior when Composer autoload registration is unavailable.

Unknowns / follow-up

  • The telemetry class name is abbreviated, although the crash file, line, and source import align with OptimoleWP\Preload\Links.
  • No failing site file inventory, update mechanism, or package checksum was included in the telemetry.
  • The available repository checkout lacks vendor/, so generated Composer autoload files could not be inspected locally.

Confidence

Confidence: 88/100

Production telemetry captured the frontend fatal on two sites, and repository inspection confirms an unguarded call to the reported namespaced class while Composer autoload registration is conditional. The affected releases retain this path; no release-to-release regression window is proven.

Crash telemetry

Occurrences 2
Distinct sites 2
First seen 2026-08-26 21:02 UTC
Last seen 2026-08-26 23:11 UTC
Crash location product:inc/tag_replacer.php:301
Request context frontend
Inside Themeisle SDK no
Product versions 4.2.10, 4.2.11
WP versions 7.1
PHP versions 8.3.33, 8.5.9
SDK versions 3.3.57, 3.3.58

Source: automated crash report — optimole-wp, fingerprint bd4546aaf46e2fa5e4d66a97b913b966
Generated by bug-report-triage (ID: bug-report-triage_6a8fd2c36d0528.83961830)

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions