Claude Code analysis #36639
Replies: 1 comment
|
This is very interesting, as I do have quite a few long-running, large pages and I can attest to Elementor's performance being fairly poor in v4. I've taken to dividing these pages up into templates, and loading the sections individually via the "Template" widget in Elementor. This was an issue in v3, and still is in v4. Elementor v4 often shows me the "Do you want to open in Safe Mode?" popup when loading anything beyond a small page. I have not measured anything meaningful, as this is outside of my pay-grade when it comes to fixing Elementor's issues lol. However, in my humble experience the editor's heavy loading is spot-on and has gotten worse in v4. It legit costs my agency money as I sit and have to wait for Elementor throughout my day. |
Uh oh!
There was an error while loading. Please reload this page.
Describe the Problem
I'm sure the team did the same and used AI to analyze the Elementor code base 😄
Info: I've used the compiled version, not the source from the repo
Of course it still needs to be verified if everything is true but I'm sure some are valid and need to be fixed to improve performance. E.g. I've turned of AI in the user settings, why does it still load the AI/MCP stack?
Elementor 4.2.0 — Biggest Editor Performance Issues
TL;DR: The editor's three dominant costs are (1) rebuilding the entire widget/control configuration in PHP from scratch on every single editor open — with zero persistent caching anywhere in that path, (2) shipping and booting two complete UI frameworks plus a ~2.4MB always-on AI/MCP JavaScript stack, and (3) re-serializing and re-rendering the whole document twice on every autosave.
1. No caching of widget/control config — full rebuild on every editor open (PHP, highest impact)
Every time the editor opens, PHP executes register_controls() for every registered widget (~34 core widgets + WP widgets + Pro), each adding dozens of controls, multiplied per responsive breakpoint. This happens twice per open: once when get_initial_config() embeds the config into the page (core/base/document.php:749-758 → includes/managers/widgets.php:378-386), and again when the editor fires the get_widgets_config AJAX call (includes/managers/widgets.php:391-410). Results are memoized only within the request (Controls_Manager::$stacks) — a grep across the whole path finds zero uses of transients or object cache. Both config AJAX handlers even call wp_raise_memory_limit(), a tell that Elementor knows this is heavy. The frontend has a controls-optimization gate (core/frontend/performance.php:20-30), but it explicitly disables itself in admin/AJAX/REST, so the editor always builds the full stacks.
Related: the settings-managers config (kit, page settings, preferences) is built twice per load with no memoization (core/settings/manager.php:142-169, called from both editor-common-scripts-settings.php:27 and document.php:709), and a hardcoded list of ~1,670 Google/system fonts (includes/fonts.php) is JSON-serialized into the inline ElementorConfig blob on every open via the Font control's settings (includes/controls/font.php:43-48).
2. Two full frameworks + an always-on AI stack (JS payload, highest impact on load time)
editor-loader-v2.js boots both the legacy Backbone/Marionette editor (editor.min.js, 1.27MB, 108 Marionette references) and the new React editor (54 packages under assets/js/packages/, 7.1MB minified total) in the same window, kept in continuous sync through editor-v1-adapters — every edit crosses that bridge. On top of that:
3. Every autosave does a double full-document pass (runtime, highest recurring cost)
On every autosave and manual save, save_elements() (core/base/document.php:1382-1403):
Cost scales with page size and repeats on the autosave timer. Each save also deletes the cached post CSS, forcing an O(elements × controls) re-parse on the next preview reload.
4. Server-rendered widget refresh runs query_posts() per call
While editing widgets that render server-side (shortcode, posts/loop widgets, sidebars), each throttled refresh (1/second) fires the render_widget AJAX handler, which rebuilds a full WordPress main query via query_posts() (includes/managers/widgets.php:489) before rendering — plus in-flight requests get aborted, wasting the server work already done.
5. Preview iframe loads assets for every widget that exists
includes/preview.php:258,315 enqueues the styles and scripts of all registered widget types into the preview iframe, whether or not they're on the page — and the frontend's conditional-CSS optimization is explicitly bypassed in preview mode (multiple is_preview_mode() forks in includes/frontend.php). Swiper (512KB), flatpickr, galleries, etc. all ride along.
6. Icon fonts and manifests
The icon picker eagerly serves manifests for full icon libraries: Font Awesome JSON manifests alone are over 1MB (solid.json 612KB, brands.json 453KB) plus eicons.json (499KB) — all loadable lazily only when the icon control opens.
Propose a Solution
Additional Context
Claude review with Fable 5
Agreement
All reactions