Skip to content
Performance

How we took WordPress from 4 seconds to 180 ms

WordPress performance step by step: how we made a WordPress site 22 times faster with FrankenPHP Worker Mode, Redis and a plugin cleanup.

Stian BrendlienCEO at PXL
Published
Updated
Reading time
8 min
A modern grey train leaves a tunnel through an autumn mountain landscape, while an older red train runs on the track above

In short

  • WordPress performance comes from the architecture: server, PHP version, plugins, database and hosting are connected, and a caching plugin leaves the root cause in place.
  • FrankenPHP Worker Mode keeps WordPress in memory for a TTFB under 30 ms, while Redis Object Cache removes most of the database load.
  • After a plugin cleanup, a move from Elementor to Gutenberg and CI/CD with performance testing, most WordPress sites get a response time below 200 milliseconds.

WordPress performance starts with the architecture

WordPress performance comes from the architecture: the server, the PHP version, the number of plugins, the database and the hosting environment. They're connected, and one bottleneck drags down the rest. A caching plugin fixes none of this. In our measurements, FrankenPHP Worker Mode gives a TTFB under 30 ms, and Redis Object Cache removes most of the database load.

Most WordPress sites we see take between 2 and 5 seconds to load. Google recommends under 2.5 seconds for Largest Contentful Paint. According to Google/SOASTA Research (2017), the probability of a mobile visitor bouncing increases 32% as page load time goes from 1 to 3 seconds. That costs you traffic, rankings and conversions.

With the right infrastructure and a few structural changes, most WordPress sites get below 200 milliseconds in total response time. Here's how we do it.

Why is WordPress slow?

WordPress itself isn't slow. The problem is the sum of decisions made around it. Some were deliberate, but most were made by the agency that built the site three years ago and never looked at it again.

Too many plugins

Each plugin adds JavaScript, CSS and database queries. 20 plugins can mean 400 KB of extra JavaScript and 50+ database queries per page view. Some plugins load their resources on every page, including pages that don't use them.

We regularly see sites with 25-40 active plugins. Three of them do the same thing, five haven't been updated in over a year, and two have known security holes that nobody has dealt with.

Heavy page builders

Elementor, WPBakery and Divi let people without coding skills build websites, which is a real need. The price is performance.

A typical Elementor page loads 300-500 KB of extra JavaScript and CSS on every page, including pages that use no Elementor features. Every widget generates nested HTML that makes the page heavier than it needs to be. Gutenberg with custom blocks is a better choice for performance.

Shared hosting

You share a server with hundreds of other websites, so when a neighbouring site gets a traffic spike, you feel it. The PHP version is often outdated (7.x is still common, even though PHP 7.4 reached end of life in November 2022), and you have no control over the server configuration.

Shared hosting is fine for a hobby blog. For a business website that has to bring in leads and sales, it's indefensible.

Slow database without caching

The WordPress database model (the EAV pattern in wp_postmeta) is flexible but slow at scale. Without an object cache, the database does the same work for every visitor. More than 100 queries per page view is common on poorly configured sites.

FrankenPHP: the server that changes the equation

Traditional WordPress hosting uses Apache or Nginx with PHP-FPM. Every time someone visits the site, the server starts PHP from scratch: it loads the WordPress core and all plugins, connects to the database, builds the page and sends it to the browser. Then it does the same for the next visitor.

FrankenPHP is a PHP application server built on the Caddy web server. In Worker Mode, the WordPress application stays in memory and can respond straight away.

The difference in practice:

  • Traditional PHP-FPM gives a TTFB of 200-400 ms at best, and often 1-4 seconds on shared hosting.
  • FrankenPHP Worker Mode gives a TTFB under 30 ms in our measurements.

FrankenPHP also includes automatic HTTPS via Let's Encrypt, HTTP/2 and HTTP/3 without extra setup, and Early Hints, which let the browser start loading resources before the page is fully generated.

Moving from shared hosting to FrankenPHP alone typically cuts TTFB by 90-99%, without changing a single line of code.

Redis: the database that lives in memory

The second most important change after the server switch is Redis Object Cache. Redis keeps query results in memory, so WordPress doesn't have to ask the MySQL database on every page visit.

A site with 127 database queries per page view can drop to 8-10, because the rest hit the cache. Shopping carts and sessions come from Redis instead of MySQL, and queues for email and ERP synchronisation run in the background without affecting performance.

Redis runs as an infrastructure service alongside WordPress. A caching plugin inside WordPress is a compromise, while Redis fixes the problem itself.

Plugin cleanup: fewer, lighter, better

After the infrastructure, we tackle the plugins. The rule is simple: if 50 lines of clean code can do it, that's better than a plugin.

What we usually remove

  • Caching plugins (unnecessary with Redis and FrankenPHP)
  • SEO plugins that overlap
  • "Optimisation" plugins that actually make the site slower
  • Inactive plugins that still load code in the background
  • Contact form plugins with 400 KB of JavaScript for a three-field form

What we replace with our own code

We build lightweight WPFluent plugins with MVC architecture for contact forms, newsletter integration, custom post types and similar features that plugins often only half solve. One of these is typically 10-20 KB. The plugins it replaces are 1-3 MB.

JavaScript goes from over 1 MB to under 350 KB, and CSS from over 600 KB to under 150 KB.

Elementor out, Gutenberg in

This part takes the longest, but the effect is large. We move the Elementor content to Gutenberg with custom blocks that output clean, semantic HTML.

With custom Gutenberg blocks you get:

  • Clean HTML without nested shortcode spaghetti
  • No Elementor JavaScript framework (300-500 KB saved)
  • Better accessibility (WCAG), because you control the HTML structure
  • A faster editing experience in wp-admin
  • Simpler maintenance for as long as the site runs

For new projects, we recommend staying away from Elementor. If the project doesn't need WordPress, Sanity + Next.js gives even better performance without the plugin problems.

Core Web Vitals: the numbers Google cares about

Google measures user experience with three metrics. The thresholds on web.dev apply to the 75th percentile of page loads, on mobile and desktop.

LCP (Largest Contentful Paint) measures how quickly the main content appears. Google recommends under 2.5 seconds, and after optimisation we typically see 0.8-1.2 seconds.

INP (Interaction to Next Paint) measures response time when the user clicks or scrolls. Google recommends under 200 ms. After optimisation it's typically 10-30 ms.

CLS (Cumulative Layout Shift) measures visual stability. Google recommends under 0.1, and after optimisation it's typically 0.01.

Google confirms that Core Web Vitals are used by its ranking systems. It also stresses that there's no single signal and that relevant content still wins. Good scores are no guarantee, but red Core Web Vitals give competitors with equally good content an edge.

How to measure WordPress performance

Three free tools give you the answer.

Google PageSpeed Insights shows both lab data and field data from real users. The test takes 30 seconds and tells you exactly what's wrong.

Google Search Console shows how Core Web Vitals develop across your whole site. The trend tells you as much as any single score.

Query Monitor is a WordPress plugin that shows database queries, hooks, PHP memory use and load time per component. It reveals which plugins actually slow the site down.

Run PageSpeed Insights now. If the score is below 70, you have a problem that's costing you money.

What about caching plugins?

WP Super Cache, W3 Total Cache and LiteSpeed Cache all promise faster websites, and they partly deliver.

A caching plugin stores finished HTML pages and serves them without running PHP. That's better than nothing, but it covers up an architecture problem:

  • The cache has to be cleared when content changes, and that often fails
  • Logged-in users (shopping cart, account pages) don't get cached content
  • The first visit after the cache is cleared is as slow as having no cache
  • The plugin makes an already complex stack more complex

With FrankenPHP Worker Mode and Redis, you don't need caching plugins. The server is fast enough to generate every page in real time.

Image compression and lazy loading

Images often account for most of the load time, even when TTFB is low. A few simple steps help:

  • Convert to WebP or AVIF (40-60% smaller than JPEG)
  • Use responsive srcset so the browser fetches the right size for the device
  • Lazy-load all images below the fold
  • Compress at 75-85% quality (the difference isn't visible, but the files get much smaller)

A 4 MB JPEG hero image is probably the most common performance mistake we see. As a WebP at the right size it's 200 KB, with the same visual quality.

Version control and CI/CD

Performance needs ongoing attention. New plugins, content changes and WordPress updates can make the site slower again, and without a pipeline to catch it, performance drops gradually.

With Lighthouse in the CI/CD pipeline, the build is blocked if performance drops below the threshold. Every deploy is tested automatically, so slower code doesn't reach production.

When optimization isn't enough

Sometimes replacing WordPress pays off more than optimising it.

If the site is a pure content site without e-commerce or heavy integrations, Sanity + Next.js is a better starting point. Static generation gives load times under 100 ms without caching, plugins or PHP, and maintenance costs less because there are no plugins to keep updated.

If you have a working WordPress site with e-commerce, integrations and an editorial team that knows the tool, modernising with FrankenPHP, WPFluent and CI/CD is almost always the right call. Don't migrate just for the sake of it.

Summary

WordPress performance comes down to five things:

  1. Server: FrankenPHP Worker Mode cuts TTFB by 90-99%. Move away from shared hosting.
  2. Cache: Redis Object Cache removes most of the database load and runs as a separate service alongside WordPress.
  3. Plugins: Use fewer and lighter plugins, and replace heavy ones with your own code where it makes sense.
  4. Frontend: Remove Elementor, use Gutenberg with custom blocks and compress your images.
  5. Pipeline: CI/CD with automated performance testing stops slower code before it reaches production.

Do all five and you go from seconds to milliseconds. Do just points 1 and 2 and you're already ahead of most of the WordPress sites we analyse.

Not sure where to start? Get in touch for a no-obligation performance analysis, and we'll tell you what will make the biggest difference for your budget.

Frequently asked questions

Can every WordPress site become fast?

Most can become much faster. Sites with clean code and few plugins gain the most from FrankenPHP. Sites built in Elementor with 40 plugins take more work, but even there we typically see response times 5-10 times faster.

Does a caching plugin help with WordPress performance?

Partly. A caching plugin can speed up repeat visits, but too many plugins, a slow database, outdated PHP and shared hosting are all still there under the cache.

What is FrankenPHP Worker Mode?

FrankenPHP is a PHP application server built on the Caddy web server. Worker Mode keeps WordPress in memory between requests, so each page view skips the startup cost and gets a TTFB under 30 ms.

Does WordPress performance affect SEO?

Yes. Google confirms that Core Web Vitals are used by its ranking systems, although relevant content still weighs most. Slow pages also cost visitors: when a mobile page takes 3 seconds instead of 1, the probability of a bounce rises by 32% (Google/SOASTA, 2017).

What does performance optimisation cost?

A performance review starts at NOK 10,000, and full optimisation at NOK 50,000, depending on scope. Managed hosting with FrankenPHP costs from NOK 3,000/month. See the pricing overview.

Should we optimise WordPress or switch to Sanity?

If your site has an online store or complex integrations, we modernise WordPress. If it's a pure content site, Sanity + Next.js may give better results at a lower total cost.

Written by

Stian Brendlien

CEO at PXL

Stian has built and run web platforms for more than 18 years, including 13 years as CTO at Anbudstorget and five as contracted tech lead at GlobalConnect. He is a full-stack developer and the one you talk to about CI/CD, Kubernetes and architecture.

Is your website slower than it should be?

We run a no-obligation performance analysis and tell you what can be improved.

All articles