Skip to content

Performance: get_site_settings() called per-URL without caching (100K+ redundant calls) #1031

@jonesch

Description

@jonesch

Summary

Optml_Settings::get_site_settings() is called once per image URL during output buffer processing, but it rebuilds its return array from scratch every time by calling $this->get() 39 times. Since the settings never change during a request, this results in massive redundant work on image-heavy pages.

Impact

On a WooCommerce variable product page with ~2,500 image URLs in the output buffer:

  • get_site_settings() called 2,500 times
  • Each call invokes get() 39 times + sub-methods (get_watermark 6×, get_quality 4×)
  • Total: ~136,000 calls to get() and is_allowed() per page
  • ~690ms wall time consumed by Optimole settings lookups alone

Profiled with PHP SPX on a real WooCommerce store (155 products, Woodmart theme, 46 <img> tags expanding to 2,500+ URLs via srcset/JSON-LD/variation data).

Root Cause

The call chain is:

wp_ob_end_flush_all (output buffer flush)
  → Optml_Manager::replace_content
    → Optml_Manager::do_url_replacement
      → Optml_Url_Replacer::build_url (×2,500)
        → normalize_image
          → apply_watermark
            → $this->settings->get_site_settings()  ← rebuilds array every time
              → $this->get() × 39
              → get_watermark() → get() × 6
              → get_quality() → get() × 4

get_site_settings() in inc/settings.php has no caching:

public function get_site_settings() {
    $service_data = $this->get( 'service_data' );
    // ... builds array with 39+ $this->get() calls ...
    return [ /* 39 keys */ ];
}

Suggested Fix

Add static caching to get_site_settings():

public function get_site_settings() {
    static $cached = null;
    if ( $cached !== null ) {
        return $cached;
    }

    $service_data = $this->get( 'service_data' );
    // ... existing code ...

    $cached = $result;
    return $result;
}

This reduces get() calls from ~136K to ~39 (a single invocation) and eliminates ~690ms on image-heavy pages.

Verification

Tested with a mu-plugin that subclasses Optml_Settings and caches get_site_settings():

Metric Before After Change
get() calls 136,244 14,050 -90%
get_site_settings() time 91ms 1.1ms -99%
Total wall time 3,944ms 3,339ms -605ms
Function calls 1,782,978 1,534,631 -248K

No functional changes — all settings are read-only during a request.

Environment

  • Optimole 4.0.3 (also confirmed unfixed in 4.2.1 on GitHub master)
  • WordPress 6.8.3
  • WooCommerce 10.4.4
  • PHP 8.2

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions