Skip to content

Performance

The replacer is designed to be cheap enough to run on every request without measurable impact. A few things help keep it that way.

Variable definitions are fetched once per request, keyed by sales channel + scope. Subsequent content scans within the same request reuse the cached data. A page with 50 CMS blocks and 10 distinct variables only loads the variable list once.

Before doing any string work, the replacer:

  1. Checks the plugin-level toggle for the current scope — if off, returns immediately.
  2. Scans the content for the literal { character — if not present, returns immediately.
  3. Loads variables only when there is at least one candidate placeholder.

Pages without {...} placeholders pay almost nothing.

  • Long content with many placeholders. Each placeholder is a hash-map lookup — fast but linear.
  • Nested variables. Each nested reference is another lookup and replace. Keep nesting shallow (one level by design, see Nested variables).
  • Large per-variable CSS / JS payloads. The injection itself is constant cost, but a heavy CSS / JS block ends up in the page HTML and the browser pays for it.
  • Use scopes to keep the variable list short per scope. A variable scoped to Category is not loaded on CMS-only requests.
  • Cap nested depth — the engine stops at one level anyway. If you find yourself wanting deeper nesting, restructure your variables.
  • Keep CSS / JS small. A few rules and a few lines of init code is the sweet spot.
  • Clear cache after content changes. Cache invalidation is the slowest part of the lifecycle — make sure your editorial workflow includes a cache flush.

If you suspect the plugin is hot in a profile:

  • Add Symfony profiler / Blackfire spans around the storefront rendering of a sample page.
  • Compare with the same page when CMS replacement is off — the difference is the plugin’s contribution.
  • Reproduce in a clean environment before optimising; many “slow” cases are actually slow CMS rendering, not the replacement.