Why Your WordPress Site Is Slow: 17 Fixes Ranked by Impact WordPress site speed optimisation — 17 fixes ranked by impact for Indian sites

WordPress ships lean. A fresh install with the default Twenty Twenty-Four theme and no plugins scores above 90 on PageSpeed Insights without any optimisation. The slowness almost every business owner complains about is self-inflicted: accumulated plugins, unoptimised images, shared hosting with servers in the US, and no caching. This guide ranks 17 specific fixes by how much load time each one realistically removes, so you know where to spend your time and money first.

Diagnosing Before Fixing

Before touching any settings, run two diagnostic tests. First, open GTmetrix from its Mumbai test location and check your Fully Loaded Time — this is the metric that reflects actual user experience, not the "Performance Score" number. A site that gets an A on the score but takes 8 seconds to fully load is a slow site for your visitors. Second, run Google PageSpeed Insights on both your homepage and a typical blog post URL; the mobile report is what matters for Indian users, the majority of whom browse on a Jio 4G connection.

For context: a Jio 4G connection in Kerala typically delivers 15–30 Mbps download speeds with 30–60ms latency. A realistic target for a Kerala business site is a Fully Loaded Time under 3 seconds and an LCP (Largest Contentful Paint) under 2.5 seconds on mobile. If your GTmetrix waterfall chart shows the initial server response (TTFB) taking over 800ms, your hosting is the problem — no amount of minification will overcome a slow server response.

Save your baseline numbers before applying any fixes. This lets you quantify improvement and stop when you've reached a good-enough threshold rather than chasing diminishing returns.

Fix 1–3: High Impact (More Than 1.5 Seconds Each)

Fix 1 — Switch to a managed WordPress host or a VPS with a Mumbai data centre. This is the single most impactful change available to any Indian WordPress site. Shared hosting plans sold by Indian providers at ₹99–₹199/month typically place your site on servers in the US or Singapore, because Indian data centre capacity is more expensive. Every page request from a visitor in Trivandrum to a US-based server adds 120–200ms of round-trip latency before a single byte of your page loads. Moving to Cloudways (starting around ₹1,800/month with a DigitalOcean Mumbai server) or Kinsta (starting around ₹3,500/month) eliminates this latency and typically cuts TTFB from 1.5–3 seconds to under 300ms. Nothing else on this list comes close to this impact for sites currently on cheap shared hosting.

Fix 2 — Enable Redis or Memcached object caching. WordPress queries the database to build almost every page element: menu items, widgets, post metadata, user data, options. On a busy site or a site with complex queries, database round trips stack up. Redis object caching stores the results of these queries in memory so subsequent requests skip the database entirely. On a site with a 50-plugin setup I audited for a Kochi-based e-commerce client, enabling Redis cut database query time from 780ms to 65ms per page load. Cloudways enables Redis with one click in their control panel. On cPanel hosting, you need Memcached instead, configured via the LiteSpeed Cache or W3 Total Cache plugin.

Fix 3 — Implement full-page caching. Full-page caching stores the complete HTML output of each page so that repeat visitors receive a pre-built static file rather than waiting for WordPress to execute PHP and query the database. For a page that previously required 400ms of PHP execution plus 300ms of database queries, a cached response delivers the entire page in 15–30ms. WP Rocket handles this with minimal configuration. W3 Total Cache provides equivalent performance free but requires correctly configuring page cache, browser cache, and Gzip compression separately. Enable caching before anything else in the plugin configuration list — it is the foundation every other speed fix builds on.

Fix 4–6: Significant Impact (0.8–1.5 Seconds)

Fix 4 — Serve WebP images with automatic JPEG fallback. Images are typically 40–60% of total page weight on a well-coded WordPress site. A full-width hero image saved as a JPEG at 1920px wide and reasonable quality is commonly 300–600 KB. The same image in WebP format is 180–380 KB at identical visual quality. ShortPixel and Imagify both convert your existing library to WebP automatically and serve the WebP version via a <picture> element with a JPEG fallback for browsers that don't support WebP (now a very small minority). For a Kerala tourism or real estate site where photography defines the experience, this single fix removes more weight from your pages than minifying all CSS and JS combined.

Fix 5 — Defer unused JavaScript from inactive or low-priority plugins. Most WordPress sites carry JavaScript that loads on every page from plugins that only function on specific pages — a slider script loading on a text-only blog post, a booking calendar script loading on the homepage. Use Query Monitor (free plugin) to identify which scripts are enqueued on which pages. Then either use WP Rocket's "Delay JavaScript Execution" feature or manually conditionally enqueue scripts in functions.php so they only load where needed. Removing 200–400 KB of JavaScript from pages that don't need it saves 0.8–1.2 seconds on mobile connections.

Fix 6 — Move your WordPress server to the AWS ap-south-1 (Mumbai) region. If you're on a VPS or cloud hosting with location choice and your audience is primarily Kerala and South India, select the Mumbai AWS region, or DigitalOcean's BLR1 (Bengaluru) region. Server geography is distinct from CDN edge caching — your origin server's location determines TTFB for requests that miss the cache (first-time visitors, logged-in users, dynamic pages). Mumbai gives Indian visitors a latency advantage of 80–150ms per request compared to Singapore, and 150–250ms compared to US-East regions.

Fix 7–10: Moderate Impact (0.3–0.8 Seconds)

Fix 7 — Lazy load images and iframes. WordPress adds loading="lazy" to images by default since version 5.5, but iframes (YouTube embeds, Google Maps) are not lazy loaded automatically. Install a plugin like Lazy Load by WP Rocket (free) to add lazy loading to iframes. Also verify your theme hasn't stripped the loading="lazy" attribute from images during custom output. One important exception: never lazy load your hero image — the LCP element must load immediately, so give it loading="eager".

Fix 8 — Minify and combine CSS and JavaScript. Minification removes whitespace, comments, and redundant characters from your CSS and JS files without changing how they function. Combining merges multiple files into one to reduce HTTP request count. Your caching plugin handles both. Enable CSS minification first and test — it rarely causes problems. Enable JS minification next and test. Be cautious with JS file combining: combining all scripts into one file can break plugins that expect their scripts to load in a specific order. If combining causes layout issues, disable combining but keep minification.

Fix 9 — Set up Cloudflare's free CDN for static asset delivery. Cloudflare serves your images, CSS, and JavaScript files from edge nodes closest to your visitors. For a visitor in Kozhikode accessing a site hosted in Mumbai, Cloudflare may serve static assets from its Chennai or Mumbai edge — but critically, it also handles DDoS protection, provides free SSL, and caches assets across repeat visitors globally. The free tier is sufficient for almost all Kerala business sites. Change your nameservers to Cloudflare, enable its CDN proxy (orange cloud icon in DNS settings), and set Browser Cache TTL to 30 days for static assets.

Fix 10 — Move non-critical scripts to the footer. Scripts that load in the <head> block the browser from rendering the page until they finish downloading and executing — this is called render-blocking. Scripts that don't need to execute before the page renders (analytics, chat widgets, social sharing buttons) should load in the footer. In your caching plugin settings, look for "Load JS deferred" or "Move scripts to footer." In functions.php, replace wp_enqueue_script calls that use false as the fifth argument (header loading) with true (footer loading) for your own theme scripts.

Fix 11–14: Cumulative Wins (0.1–0.3 Seconds Each)

Fix 11 — Limit WordPress post revisions to 5. By default, WordPress saves a new revision every time you update a post. A frequently edited post can accumulate 50–100 revisions in the database. These don't slow individual page loads directly, but they bloat the database over time, making backup and restore operations slower and increasing the size of your database queries for post metadata. Add this line to wp-config.php: define( 'WP_POST_REVISIONS', 5 ); This caps revisions at 5 per post going forward without deleting existing ones.

Fix 12 — Clean the database regularly. Install WP-Optimize or use Rank Math's database cleanup tool to delete: auto-draft posts (WordPress creates these constantly), spam and trash comments, expired transients (temporary data cached by plugins that is never cleaned up), and orphaned post metadata (metadata rows for posts that have been deleted). On a 3-year-old site, this cleanup commonly reduces database size by 30–60% and speeds up queries proportionally. Schedule this cleanup monthly rather than doing it once.

Fix 13 — Remove unused plugins completely — not just deactivate them. Deactivated plugins don't execute their main code, but they remain on disk and some still hook into WordPress's loading process. More importantly, every installed plugin is a potential attack surface. Go through your installed plugins list and delete anything you haven't used in 3 months. Each removed plugin is one fewer HTTP request, one fewer database query set, and a smaller codebase for WordPress to scan on every request. I've seen sites cut 0.3 seconds from load time just by deleting 8–10 genuinely unused plugins.

Fix 14 — Disable WordPress's default emoji script. WordPress loads a small JavaScript file on every page to render emoji characters. If you're not using emoji in your content (which most business sites aren't), this script is dead weight. Add this to your theme's functions.php:

add_action( 'init', function() {
    remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
    remove_action( 'wp_print_styles', 'print_emoji_styles' );
    remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
    remove_action( 'admin_print_styles', 'print_emoji_styles' );
} );

This removes one JavaScript HTTP request and one CSS HTTP request from every page load — small individually, but meaningful when combined with the other fixes in this section.

Fix 15–17: INP and CLS Improvements

Fix 15 — Preload the LCP image in your theme's functions.php. The LCP (Largest Contentful Paint) is typically your hero image — the largest image visible in the viewport on page load. By default, the browser discovers this image only after parsing HTML and CSS, which introduces a discovery delay. Preloading tells the browser to fetch the image immediately, before it would naturally find it. Add this to functions.php:

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

Preloading the hero image on the homepage typically improves LCP by 200–500ms on mobile. Use it specifically for the image that is the LCP element — preloading multiple images wastes bandwidth.

Fix 16 — Set explicit width and height attributes on all images. When a browser loads a page without knowing image dimensions, it cannot reserve space for images during initial layout. As images load, they push content down — this is Cumulative Layout Shift (CLS), one of Google's Core Web Vitals. Adding explicit width and height attributes to every <img> tag tells the browser the aspect ratio upfront so it reserves the correct space. WordPress generates these attributes for images added through the media library since version 5.5. Check that your theme and page builder are not stripping them during custom output.

Fix 17 — Use font-display: swap for Google Fonts. When Google Fonts are loading, the browser can either show invisible text (waiting for the font to arrive — this contributes to poor LCP) or show fallback system font text immediately and swap to the loaded font when it arrives. The swap behaviour is better for users and for Core Web Vitals. Add &display=swap to your Google Fonts URL in your theme's enqueue call:

wp_enqueue_style(
    'google-fonts',
    'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap',
    array(),
    null
);

Also consider self-hosting your fonts using the google-webfonts-helper tool — this eliminates the external DNS lookup and connection to fonts.googleapis.com entirely, saving 100–200ms on first load.

Tools to Verify Improvements

After applying fixes, measure with the same tools you used for your baseline. In GTmetrix, the Waterfall tab is your most useful diagnostic. Each row is one HTTP request — you can see which resources take longest, which block rendering, and whether your caching headers are set correctly. Look for the "Wait" time on each resource (server processing time) versus "Receive" time (download time). Long Wait times on HTML indicate hosting or caching problems; long Receive times on images indicate oversized files.

Google PageSpeed Insights gives you field data (real users from the Chrome User Experience Report) alongside lab data (simulated test). For an Indian site, focus on the mobile field data — if enough users have visited your site, you'll see actual CWV scores from real Jio and Airtel connections. Lab scores from a simulated connection can be misleading for India because they use a throttled 4G profile calibrated to US network conditions, not Indian network conditions.

WebPageTest at webpagetest.org lets you test from a Mumbai location on a specific connection speed. Run a 3-run test from their Mumbai mobile node on a 4G connection. The median run gives you a reliable baseline. The filmstrip view shows exactly when visual content appears, frame by frame — this is invaluable for understanding whether your LCP improvement translated into visible content appearing faster for real users.

For a practical example of how these fixes apply together on an actual project, read the WordPress speed optimisation case study covering a 4-hour real-world project. For the foundational SEO configuration that should accompany speed work, the WordPress SEO 30-step checklist covers both in the same setup flow.

Frequently Asked Questions

Which caching plugin is better: WP Rocket or W3 Total Cache?

WP Rocket (around ₹3,500–₹5,000/year) is significantly easier to configure correctly. You install it, enable page caching, enable Gzip compression, and you're done — it works reliably on almost every shared and managed host in India. W3 Total Cache is free but requires configuring page cache, database cache, object cache, and browser cache separately, and incorrect combinations on a shared host can actually slow your site or cause white screens. For a first-time site owner or a business owner without a developer, WP Rocket is worth the annual fee purely for the reduction in configuration error risk. For developers who understand caching layers, W3 Total Cache achieves equivalent results at no cost.

Does page speed really affect rankings in India?

Yes, but it is not the dominant ranking factor for local service queries. Google uses Core Web Vitals as a tiebreaker — if two pages have similar content quality and backlink profiles, the faster one wins. For a dentist in Thrissur or a tour operator in Munnar targeting local queries, Google Business Profile signals (reviews, categories, proximity) carry considerably more weight than whether the site loads in 2.1 seconds versus 3.4 seconds. Speed matters most for competitive national terms and for user experience metrics that affect bounce rate and conversion. Fix the high-impact items in this list, aim for a sub-3-second fully loaded time on a Jio 4G connection, and then focus your energy on content quality and local SEO rather than chasing a perfect PageSpeed score.

Why does my WordPress site get slower as it grows?

Three compounding problems: plugin accumulation, database growth, and absent cache invalidation strategy. Every plugin you install adds PHP code that executes on every page load — even plugins you've deactivated can add overhead if their code remains on disk and partially hooks into WordPress's loading process. The database accumulates post revisions, spam comments, expired transients from plugins, and orphaned metadata from deleted posts. A WordPress database that started at 5 MB can grow to 500 MB of mostly redundant data, slowing every query. Finally, caching plugins need a coherent expiry strategy — a cache that never expires serves stale content; a cache that expires too frequently provides no benefit. Review installed plugins quarterly, clean the database every 3–6 months, and set cache expiry to 12–24 hours for standard content sites.