← Back to work

Web performance

Speed work on 4korners.org, the public WordPress site of the nonprofit I work for. I measured where the time and the bytes went, then cut the homepage from 14 MB to 3 MB and brought the cached server response to 0.1 to 0.2 s on every page, from 1.3 to 2.8 s before.

Architecture

VisitorsPage cache (WP Super Cache)WordPress + Elementor
The cache answers with a ready page instead of building it on each request, and images come resized and in WebP from Jetpack's image CDN.

The site runs WordPress with Elementor Pro on a VPS. Before this work it had no page cache, so the server built every page on each request, and images made up about 90% of the homepage's 14 MB. I turned on WP Super Cache with a daily preload, switched off an unused events calendar that still loaded its files on every page, and replaced a partner logo that weighed about 5 MB with a 24 KB copy. Images now go through Jetpack's free image CDN, which resizes each one to the size it is shown at and serves it as WebP.

Key decisions

Keep Elementor, fix the speed separately

Before touching anything, I audited whether to move off Elementor. A static export would add a second subscription and a new publish step, and a rebuild, as a block theme or as a headless site, would never pay for itself. The slow pages had cheaper causes that had nothing to do with the page builder, so Elementor stayed.

Measure, then fix the biggest cost first

The first plan targeted CSS and JavaScript. Switching off the unused events calendar cut the homepage's CSS and JavaScript by 55%, but the server response did not move, and the first browser measurement showed images were about 90% of the page. So I put the effort into the page cache and the images, on the current server, without waiting for the planned move to a new host.

An image CDN instead of an optimizer plugin

The host blocks PHP's exec(), so the optimizer plugin I installed could only run in a limited cloud mode, and a later check showed it was doing nothing at all. I turned on Jetpack's free image CDN instead, and image weight on the homepage fell from 7.6 MB to 1.6 MB. It skips CSS background images, so the 853 KB hero photo is still the largest file on the page, and I chose to leave it.

The hard part

The live site was loading its fonts from staging

Fonts and bold text looked right in the Elementor editor and wrong on the live site. All 13 font stylesheets that Elementor keeps on the server loaded their fonts from the staging site, which sends no CORS header, so browsers blocked them and visitors got a fallback font, probably since March 2025. Elementor's regenerate tool does not touch those files, so I rewrote the URLs in them to the live domain, kept backups for rollback, and confirmed zero font errors in the browser. The rule since then: copies go from production to staging, never the other way.

Security and performance

  • Switching a plugin off is not the same as removing it: its files can still be reached from the web. I delete plugins the site no longer uses, as I did with an unused paid add-on.
  • Every change on the live server starts with a backup. The font fix kept a copy of each file it rewrote, so any step could be rolled back.

Stack

WordPressElementor ProWP Super CacheJetpack Site Accelerator

Links