Why Is My WordPress Site Slow? A Diagnostic Decision Tree
Stop guessing why your WordPress site is slow. Diagnose by the symptom: high TTFB, slow LCP, laggy INP, or jumpy CLS each lead to a different fix family.
A WordPress site is slow because one of four specific things is failing, and the fix family for each is almost completely different from the other three. The four symptoms are a high Time to First Byte, a slow Largest Contentful Paint, a laggy Interaction to Next Paint, and a jumpy Cumulative Layout Shift. The mistake almost every site owner makes, and that almost every plugin tutorial reinforces, is to treat slowness as one undifferentiated problem and reach for a caching plugin as the universal answer. Caching addresses exactly one of the four symptoms cleanly, partially helps a second, and does nothing at all for the third and fourth.
So the diagnostic answer to "why is my WordPress site slow" begins with measuring which of those four numbers is bad before you change a single setting. Open PageSpeed Insights, run your URL, and look at the field data section first. The Chrome User Experience Report shows you what real visitors are experiencing on your domain over the last twenty-eight days. Whichever metric is in the red or amber zone is your branch in the decision tree. If TTFB is over 800 milliseconds, your problem lives on the server. If LCP is over 2.5 seconds but TTFB is fine, your problem is in the front-end render path. If INP is over 200 milliseconds, your problem is JavaScript execution. If CLS is over 0.1, your problem is layout instability. Each branch leads to a different cause-and-fix family, and walking the wrong branch wastes weeks.
Branch one: high TTFB points at the server, the database, or PHP
Time to First Byte is the duration between a browser asking for your page and the first byte of the response coming back. If that number is high, nothing else you do in the browser matters, because the browser is sitting on its hands waiting for WordPress to finish thinking. A healthy WordPress TTFB on a cached page is under 200 milliseconds. Anywhere between 200 and 600 is acceptable but worth investigating. Above 800 is failing, and above 1.5 seconds means your server is the entire problem and front-end optimization is a distraction. The cause family for high TTFB is small and almost always one of three things.
The first cause is shared hosting that is genuinely overcommitted. Cheap shared hosts run hundreds of accounts on a single physical machine and the noisy-neighbor effect at peak hours can add seconds to your response time even when your own site is doing nothing wrong. The fix is not a caching plugin. The fix is moving to a managed WordPress host that runs PHP-FPM with sane worker counts, OPcache properly configured, and a separate database server. Hosts like Kinsta, WP Engine, Pressable, and Cloudways routinely deliver TTFBs under 250 milliseconds on uncached requests because the underlying infrastructure was built for WordPress instead of being a general LAMP environment with WordPress dropped on top.
The second cause is a slow database, which on WordPress almost always means autoloaded options that have ballooned out of control. Every page load on WordPress runs a query that fetches all options flagged as autoload from the wp_options table. On a clean install that table holds maybe a megabyte of data. On a site that has accumulated five years of plugin installs, transients that were never cleaned, and abandoned settings from page builders, that table can hit fifty or a hundred megabytes. Fetching that on every request, parsing it, and unserializing the contents adds real time. The diagnostic is to run a query that lists the largest autoloaded options. The fix is to delete options belonging to uninstalled plugins, set genuinely large options to autoload="no", and clean expired transients on a cron.
The third cause is PHP itself, and specifically running an old version of it without OPcache. PHP 8.2 and 8.3 are between thirty and fifty percent faster than PHP 7.4 on the same WordPress workload, and OPcache, which keeps compiled PHP bytecode in memory, is the difference between a TTFB of 300 milliseconds and a TTFB of a second. Many older managed hosts default OPcache to a memory ceiling that is too small for a real site, and the cache thrashes. Your hosting support can confirm the version and the OPcache settings in five minutes. If you are below PHP 8.1 you have left performance on the table that no plugin can recover.
Branch two: slow LCP points at the hero render path
If TTFB is healthy but LCP is still over 2.5 seconds, the server has done its job and the browser is now the slow link. Largest Contentful Paint is the moment the largest image, video, or text block in the viewport finishes rendering. The cause family for slow LCP centers on three things: render-blocking resources in the head, an oversized hero image, and bad font loading. Each contributes its own slice of the total.
Render-blocking CSS and JavaScript are the most common culprit on WordPress because page builders ship enormous stylesheets that the browser must download, parse, and apply before it can paint anything. Elementor's frontend bundle alone runs around 350 kilobytes of CSS and JavaScript before any of your own content loads. Bricks is leaner, custom Gutenberg themes leaner still, but the principle is the same. The fix is critical CSS extraction, which inlines the styles needed for the above-the-fold content directly into the HTML head and defers everything else. Plugins like FlyingPress, Perfmatters, and the paid tier of WP Rocket do this competently. Going further, audit which plugins enqueue scripts on every page when they are needed only on one. A contact form plugin that loads its assets globally is wasting a quarter second on every other URL on your site.
The hero image is the next layer. If your homepage hero is a 1.8 megabyte JPEG, no amount of caching will rescue your LCP, because the browser still has to download those 1.8 megabytes before it can paint the largest element. The discipline is non-negotiable: hero images go through a build pipeline that produces AVIF and WebP variants at multiple breakpoints, the source is no wider than 2400 pixels, and the file is referenced with explicit width and height attributes plus fetchpriority="high". On a modern WordPress build that hero file should land between 60 and 150 kilobytes. Anything larger is a bug, not a stylistic choice.
Font loading is the third leg. WordPress sites that ship Google Fonts via @import or via remote stylesheets pay a roundtrip penalty before any text can render, and if the fonts arrive late the LCP element, which is often a heading, paints late. The fix is to self-host the font files, preload the two or three weights you actually use, and apply font-display: swap so the page renders in a fallback face while the web font is in flight. That single change frequently shaves four hundred milliseconds off LCP on a content site.
Branch three: laggy INP points at JavaScript on the main thread
Interaction to Next Paint replaced First Input Delay as a Core Web Vital in March 2024, and it is the metric most WordPress sites are now failing without realizing it. INP measures how long the page takes to visually respond when a user taps, clicks, or types. The threshold for "good" is 200 milliseconds. WordPress sites running heavy page builders, multiple analytics scripts, and chat widgets routinely come in at 400 to 600. The cause is almost entirely JavaScript blocking the main thread, and the fix family is different from anything caching can address.
The single biggest contributor is third-party scripts. Google Tag Manager loaded synchronously, a Facebook pixel, a Hotjar session recorder, an Intercom chat widget, and a cookie consent banner can together occupy the main thread for upwards of two seconds during the early page lifecycle. The visitor taps a menu, the browser tries to dispatch the event, the main thread is busy parsing Hotjar, and the tap registers two hundred milliseconds late. The fix is brutal pruning. Audit every third-party tag, decide which ones survive a justification test, and load the survivors with delayed-execution wrappers that wait until the user actually interacts before firing.
The second contributor is page builder JavaScript that hydrates interactivity widgets you never use. An accordion, a tab block, a carousel, a popup trigger, each ships its own JS handler, and on Elementor or Divi those handlers attach during page load whether the user ever opens the accordion or not. Switching to Gutenberg blocks that ship minimal JavaScript, or to a builder like Bricks or Breakdance that loads handlers on demand, drops INP by half on a typical marketing site. If you cannot switch builders, the next-best move is to identify the long tasks in Chrome DevTools Performance panel, find which script is responsible, and either remove the feature or load it lazily.
The third contributor on commerce sites is WooCommerce cart fragments, an AJAX call that fires on every page load to keep the mini-cart in sync. On a low-traffic store this is fine. On a busy product page with multiple variants it can stall the main thread for hundreds of milliseconds. Disabling cart fragments on non-cart pages is a one-line snippet and a noticeable INP win.
Branch four: jumpy CLS points at layout reservations, not at speed
Cumulative Layout Shift is technically a stability metric rather than a speed metric, but visitors experience it as slowness because the page feels broken while it settles. CLS is high when elements appear or resize after initial paint without the layout having reserved space for them. The fix family is small and almost embarrassingly simple, which is why it is also the metric WordPress sites most often leave broken for years.
The most common cause is images and embeds that ship without explicit width and height attributes. The browser does not know how tall the image will be until the file arrives, so it leaves zero pixels of vertical space, paints the surrounding text, and then jumps everything down when the image finally lands. The fix is to ensure every image, video, and iframe in your content has width and height attributes set, which lets the browser reserve the correct aspect ratio in advance. Modern WordPress core has emitted these attributes by default since 5.5, but plugins and page builders frequently strip or override them. Audit your hero, your in-content images, and your YouTube embeds.
The second cause is web fonts swapping in late and reflowing text. The fix is the same self-host-and-preload discipline that helps LCP, plus declaring size-adjust and ascent-override values in the @font-face rule so the fallback font occupies the same vertical metrics as the web font. The third cause is ad slots, cookie banners, and notification bars that inject themselves into the DOM after first paint without reserved space. Reserve the slot height in CSS even if the slot is sometimes empty.
What to do once you know which branch you are on
The decision tree is useful only if you act on the branch it points you to. If TTFB is your problem, do not buy a caching plugin, change hosts. If LCP is your problem, do not change hosts, fix the render path. If INP is your problem, do not optimize images, prune scripts. If CLS is your problem, do not do anything that involves a build pipeline, just add width and height attributes. The single biggest reason WordPress sites stay slow for years is owners doing the wrong work confidently, because a generic blog post told them caching is the answer to a question they had not specified.
WitsCode runs a paid WordPress speed diagnostic that produces a written report tied to your specific field data, identifies which of the four branches you are on, and recommends the smallest change that moves the failing metric into green. We do this because the diagnostic is the work, and the implementation is usually a fraction of the time once the right branch has been identified. If you have read this far and you are not certain which branch your site is on, you are the audience this article was written for, and the field-data screenshot from PageSpeed Insights is the only thing we need to begin.
Get weekly field notes.
Practical writing on shipping products, straight to your inbox. No spam.
Need help with this?
WordPress Development
We design and build web apps, MVPs, and SaaS products. Talk to us about what you are working on.
Talk to usWant to discuss wp speed & core web vitals for your business?
Start a project and we'll talk through where you are, what's working, and the highest-leverage moves for the next 90 days.