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

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions