9 Signs It's Time to Leave WordPress

9 Signs It's Time to Leave WordPress

WordPress powers roughly 42% of all websites, and for a lot of them it's still the right tool. But 'most popular' and 'right for you' are different claims, and the gap between them is where most bad website years are spent. In fact, WordPress's share of the CMS market has been in its first sustained decline — down from about 65% of CMS-built sites in 2022 to under 60% in 2026 — which means a meaningful number of teams are concluding the same thing you might be. Here are nine signs it's time to leave WordPress, drawn from the patterns we see in real migrations.

Table of Contents
  1. 1. You feel anxiety before clicking 'Update'
  2. 2. Your plugin list has become an ecosystem of patches
  3. 3. Core Web Vitals are red and you've already 'optimized'
  4. 4. Security has become a part-time job
  5. 5. The costs keep creeping
  6. 6. Your editors work around the editor
  7. 7. Developers dread working on it
  8. 8. You're building things WordPress wasn't shaped for
  9. 9. You're reading this article
  10. What To Do Next

1. You feel anxiety before clicking 'Update'

Updates are supposed to be maintenance, not risk events. If your team screenshots the site before updating plugins, keeps a rollback plan for minor version bumps, or has a 'we don't touch it on Fridays' rule, the platform has stopped saving you time. That anxiety is the cost of an architecture where every plugin can modify anything.

2. Your plugin list has become an ecosystem of patches

A caching plugin to fix speed. A security plugin to fix the attack surface. An SEO plugin to fix metadata. A backup plugin to fix fragility. Each one is patching something the platform doesn't do well natively — and each adds its own update cycle, license fee, and conflict potential. When plugins exist mostly to fix WordPress rather than add business features, the foundation is the problem. Our plugin equivalents guide shows how much of a typical stack simply evaporates on a modern platform.

Laptop displaying analytics charts with declining metrics, illustrating a website performance review
When the metrics keep sliding despite the optimization plugins, look at the platform. Source: Pexels
Read also:

3. Core Web Vitals are red and you've already 'optimized'

You've installed the caching plugin, compressed the images, and hired someone to 'speed up the site' — twice. If mobile LCP still sits above 3 seconds, you're fighting the architecture: PHP rendering on every request, page builder markup, and plugin scripts loading on pages that don't need them. Static-first platforms make the fast path the default rather than an achievement. We ran the numbers in our CMS page speed benchmark.

4. Security has become a part-time job

The WordPress ecosystem logged over 11,000 new vulnerabilities in a single year, 91% of them in plugins. If you're paying for a security plugin, a firewall service, and malware scans — and still had an incident — you're not doing security wrong. The attack surface is just that large. Why headless architectures sidestep most of this is worth understanding before your next renewal.

5. The costs keep creeping

WordPress is free the way a puppy is free. Hosting, premium plugin renewals, maintenance retainers, and emergency fixes routinely add up to thousands per year for a business site — we itemize it in the real cost of running WordPress. The sign isn't the total; it's the trend line. If the bill grows every year while the site stays the same, you're renting technical debt.

6. Your editors work around the editor

Watch how content actually gets published. If writers draft in Google Docs because the editing experience is unpredictable, if publishing requires a developer 'just to check it looks right', or if half the Gutenberg blocks on the page are wrappers from a builder plugin — the CMS is failing at its one core job.

7. Developers dread working on it

Modern developers work in components, version control, and typed data. WordPress hands them a mix of PHP templates, database-stored markup, and plugin hooks that fire in unpredictable order. If every estimate for 'small change on the WordPress site' comes back padded, that padding is a price signal.

8. You're building things WordPress wasn't shaped for

A content API for a mobile app. A marketing site plus documentation plus a job board, each with different structures. Content reused across multiple frontends. WordPress can be bent into all of these, but headless and API-first platforms were designed for them — the difference shows up in every sprint.

9. You're reading this article

Slightly cheeky, but real: teams happy with their platform don't research leaving it. If several of these signs describe your situation, the question has already shifted from whether to what's next and when.

What To Do Next

Share

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

TL;DR — A custom session-cookie login flow appeared to succeed on localhost (the OTP verified, the response looked fine) but every subsequent request to a login-gated page treated the visitor as logged out. Identical code worked fine on the live HTTPS site. The cookie's Secure attribute was hardcoded to true — and per the cookie spec, browsers never store or send a Secure cookie over a plain, non-HTTPS connection.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Fix
  4. Lessons learned

Diagnostic

Check the actual Set-Cookie response header and the browser's own cookie storage panel — on localhost over http://, the cookie is sent by the server but never actually stored by the browser.

Root cause

// before -- assumes the app is always served over HTTPS
setCookie("session", token, { secure: true, httpOnly: true });
emdashkits.com

A cookie config that quietly assumes "we're always on HTTPS" breaks the instant you test over plain HTTP, which local dev servers commonly are.

Read also:

Fix

// after -- derive secure from the actual request protocol
const isHttps = request.url.startsWith("https://");
setCookie("session", token, { secure: isHttps, httpOnly: true });
emdashkits.com

Lessons learned

  • Any Secure-flagged cookie needs to key off the real request scheme, not an assumption baked in once at cookie-creation time.
  • "Works in production, silently fails in local dev" is a strong signal to check cookie flags before anything else in an auth flow.
  • Check other cookies in the same codebase for the same hardcoded assumption — if one cookie has this bug, sibling cookies set the same way are worth auditing too.
Share
Previous Article

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Comments

Write a comment

Related Articles

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

TL;DR — GA4's gtag.js snippet was installed correctly, the page loaded with no visible JavaScript error, and GA4's real-time report still showed zero activity. The CMS's default Content-Security-Policy had no allowance for analytics domains and no config option to add one — so every request to Google's tracking endpoints was blocked at the browser level before it could fail loudly.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Lessons learned

Diagnostic

Check the browser's dedicated CSP violation reporting, not the regular console error list — CSP blocks are reported through their own channel, not thrown as normal script errors, so "no console errors" doesn't mean nothing was blocked.

Root cause

The CSP's script-src and connect-src directives had no entry for googletagmanager.com or google-analytics.com, and the CMS exposed no configuration surface to add one — the only way in was patching the CSP directives directly.

// patch-package: add analytics domains to the existing CSP directives
scriptSrc.push("https://www.googletagmanager.com");
connectSrc.push("https://www.google-analytics.com", "https://www.googletagmanager.com");
emdashkits.com
Read also:

Lessons learned

  • "No console errors" is not proof nothing was blocked — CSP violations live in their own reporting surface and are easy to miss if you're only scanning for red error text.
  • Before adding any third-party script tag to a site with a CSP already in place, check the CSP's directives first rather than assuming a silently-empty analytics dashboard means a snippet-installation mistake.
Share
Previous Article

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Next Article

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)