WordPress Page Speed Optimization Guide: 2024 Results

by Sarah Mitchell
WordPress Page Speed Optimization Guide: 2024 Results

WordPress Page Speed Optimization Guide: 2024 Results

A stock WordPress install on shared hosting measured 4.2 s LCP and 1.1 s TTFB in WebPageTest (Dulles, VA, cable connection, Chrome, 5-run median) before any optimization. After the changes documented below, the same page measured 1.8 s LCP and 180 ms TTFB. This guide walks through every step in order of impact, with the config that produced those numbers.

Why TTFB Is the Right Place to Start

Most WordPress speed guides lead with image compression. That is the wrong order. Images are downstream of the server response. If your TTFB sits above 600 ms, no amount of image optimization closes that gap.

TTFB is the time from the browser's first byte request to receiving the first byte of the HTML response. It captures server processing time, database query time, and network latency. For WordPress, the first two dominate.

Baseline measurement method: WebPageTest with a fixed test location (Dulles, VA), cable profile, and a minimum of five runs. The median value is recorded. Google Search Console's Core Web Vitals report is used to cross-check field data once changes are live.

Baseline numbers (stock install, shared hosting, no caching):

Metric Before
TTFB 1,100 ms
LCP 4,200 ms
Total page size 2.8 MB
HTTP requests 74
PageSpeed Insights (mobile) 41

Step 1 — Install a Caching Plugin and Tune It Correctly

Caching is the single highest-leverage change on a WordPress site. Without it, every page request triggers PHP execution and multiple database queries. With full-page caching, return visitors and crawlers receive a pre-built HTML file.

Test setup used WP Rocket 3.15.4 on a shared cPanel host. The settings that moved the needle:

  • Page caching: enabled, cache lifespan set to 10 hours.
  • Separate cache for mobile: enabled (the host did not provide server-level mobile detection).
  • Cache preloading: enabled, sitemap-based, crawl delay 500 ms to avoid overloading shared CPU.
  • Browser caching: enabled via WP Rocket's .htaccess rules (1-year expiry for static assets).

After caching only, TTFB dropped from 1,100 ms to 210 ms on cached requests. LCP moved from 4,200 ms to 2,900 ms.

If budget is a constraint, W3 Total Cache 2.7.x with disk-enhanced page caching and WP Super Cache 1.12.x both produce comparable TTFB reductions. The configuration depth differs, but the core mechanism is the same.

Step 2 — Optimize the Database and Reduce PHP Overhead

Caching helps returning visitors. It does not help the cache-generation request itself, admin pages, or logged-in users who bypass cache. Database bloat compounds this.

On a 3-year-old site with WooCommerce, the wp_options table contained 9,400 rows, 340 of which were autoloaded. Autoloaded options are pulled into memory on every page load, cached or not.

Steps taken:

  1. Ran WP-Optimize 3.4.x to clear 18,000 post revisions, 4,200 transients, and 1,100 spam comments.
  2. Identified autoloaded options bloat using the query: SELECT option_name, length(option_value) FROM wp_options WHERE autoload='yes' ORDER BY length(option_value) DESC LIMIT 20;
  3. Removed stale plugin options left by three uninstalled plugins.

Autoloaded data reduced from 2.1 MB to 340 KB. Uncached TTFB (admin bar visible) dropped from 890 ms to 420 ms.

On managed hosts (Kinsta, WP Engine, Flywheel), this step is partially handled by the host's object cache (Redis or Memcached). On shared or VPS hosting, installing Redis Object Cache 2.5.x with a Redis instance provides a persistent object cache that avoids repeated database hits for the same queries.

Step 3 — Eliminate Render-Blocking Resources

With TTFB under control, the next constraint is render-blocking CSS and JavaScript. These are resources the browser must download and parse before it can paint anything to the screen.

Measurement: WebPageTest waterfall chart. Render-blocking resources appear as horizontal bars that push the "Start Render" marker to the right.

On the test site, six JavaScript files and two Google Fonts stylesheets were render-blocking at baseline.

Changes made in WP Rocket 3.15.4:

  • Load JS deferred: enabled. This moves non-critical scripts to after the HTML is parsed.
  • Delay JS execution: enabled for Google Analytics, HubSpot chat widget, and Facebook Pixel — scripts with no above-the-fold dependency.
  • Remove unused CSS: enabled (WP Rocket's "Remove Unused CSS" feature, which generates a critical CSS file per URL).
  • Google Fonts: consolidated and locally hosted using OMGF 5.x (Optimize My Fonts).

After this step:

Metric After Step 3
Render-blocking resources 0
Start Render 800 ms
LCP 2,100 ms
PageSpeed Insights (mobile) 67

Note: Delay JS can break interactive elements if applied too broadly. Test each deferred script against your contact forms, sliders, and checkout flows before pushing to production.

Step 4 — Image Optimization and Lazy Loading

Images are the largest contributor to page weight on most WordPress sites. The test page carried 1.9 MB of images at baseline, representing 68% of total page size.

Three changes address this:

4a. Convert to WebP. Imagify 2.x was used in aggressive mode to convert all uploaded images to WebP with a fallback for browsers that do not support it. Average file size reduction: 58% versus the original JPEGs.

4b. Correct sizing. WordPress core generates multiple image sizes on upload. The theme was serving the large size (1,024 px wide) in a 400 px column. The srcset attribute was present but the theme's sizes attribute was set to 100vw, causing browsers to request the full-width version. Correcting the sizes attribute to (max-width: 768px) 100vw, 400px reduced the image request size by an additional 34%.

4c. Native lazy loading. WordPress 5.5 and later adds loading="lazy" to images below the fold by default. Verify this is not being stripped by your theme or a page builder. The LCP image — always above the fold — must not be lazy-loaded. In Elementor and Divi, check the first hero image widget and disable lazy load explicitly for that element.

Additionally, add a preload hint for the LCP image in functions.php:

add_action( 'wp_head', function() {
    echo '<link rel="preload" as="image" href="' . get_template_directory_uri() . '/images/hero.webp" fetchpriority="high">';
}, 1 );

After image optimization:

Metric After Step 4
Total page size 780 KB
LCP 1,800 ms
PageSpeed Insights (mobile) 81

Step 5 — CDN and Static Asset Delivery

A CDN moves static assets (images, CSS, JS, fonts) to edge nodes geographically closer to visitors. For a U.S.-hosted site with European traffic, this step is non-negotiable. For a site with a single regional audience, the gain is smaller but still measurable.

Test configuration: Cloudflare Free with WP Rocket's CDN integration pointing static assets to a Cloudflare-proxied subdomain (cdn.example.com).

Cloudflare Free settings that matter:

  • Auto Minify: enabled for CSS and JS (HTML minification can break some themes — test first).
  • Brotli compression: enabled by default on Cloudflare; verify in the Speed tab.
  • Cache TTL: set to 1 month for static assets via a Page Rule on cdn.example.com/*.
  • Rocket Loader: disabled. It conflicts with WP Rocket's JS deferral and has caused console errors on multiple test sites.

For teams with budget, Cloudflare Pro ($20/month) adds Polish (automatic WebP conversion at the edge) and more granular cache rules. In testing, Polish produced a further 12% reduction in image payload for visitors who had not yet received the Imagify-converted WebP files.

After CDN:

Metric After Step 5
TTFB (CDN-cached asset) 180 ms
LCP 1,800 ms (unchanged — LCP was already HTML-delivered)
PageSpeed Insights (mobile) 84

Full Before-and-After Summary

Metric Before After Change
TTFB 1,100 ms 180 ms −84%
LCP 4,200 ms 1,800 ms −57%
Total page size 2.8 MB 780 KB −72%
HTTP requests 74 31 −58%
PageSpeed Insights (mobile) 41 84 +43 pts

All post-optimization numbers are WebPageTest medians across five runs, same test profile as baseline. Google Search Console field data (75th-percentile LCP) moved from "Poor" to "Needs Improvement" within three weeks of the changes going live, consistent with the lab data direction.

Do This First: Prioritized Action List

If you are starting from an unoptimized site, work in this order. Each step builds on the previous one, and skipping ahead produces smaller gains.

  1. Measure first. Run WebPageTest and record TTFB, LCP, page size, and request count. You need a baseline to know whether a change worked.
  2. Install a caching plugin. Enable full-page caching and cache preloading. This is the highest single-step gain available.
  3. Clean the database. Remove revisions, transients, and orphaned plugin data. Reduce autoloaded options below 500 KB.
  4. Defer and delay JavaScript. Use your caching plugin's built-in tools. Test all interactive elements after enabling.
  5. Convert images to WebP and fix sizes attributes. Run Imagify or ShortPixel in bulk. Audit the LCP image for correct fetchpriority and no lazy-load attribute.
  6. Connect a CDN. Cloudflare Free is a zero-cost starting point. Enable Brotli, disable Rocket Loader.
  7. Re-measure. Compare against your baseline. If LCP is still above 2.5 s, profile the waterfall for the next bottleneck — often a third-party script or an unoptimized web font.

Speed optimization is not a one-time task. A plugin update, a new page builder block, or a third-party embed can reintroduce render-blocking resources or add payload. Schedule a WebPageTest run monthly and set a PageSpeed Insights alert threshold in your monitoring tool of choice.