Monitoring WordPress Sites — What Breaks, and How to Catch It
By most estimates, WordPress powers somewhere north of 40% of all websites — which means when we talk about "monitoring a website," odds are we're talking about monitoring WordPress. And WordPress fails in its own particular ways: a plugin auto-update at 3 AM, a white screen that still returns HTTP 200, a scheduler that only runs when someone visits, and an attack surface that every bot on the internet has memorized. Generic ping-the-homepage monitoring misses most of it.
Here's what actually breaks on WordPress sites, and how to instrument for each one.
Auto-updates break sites while you sleep
Automatic plugin and theme updates are, on balance, a good thing — most WordPress compromises exploit known vulnerabilities in outdated plugins, and auto-update closes that window. But it also means your site changes itself at arbitrary hours with nobody watching. A plugin update that fatals on your PHP version, conflicts with another plugin, or breaks the theme's template hooks takes the site down at 3 AM on a Tuesday, and you find out from a customer email.
The fixes are layered:
- Monitor at an interval that matches the risk. If your site can change itself hourly, a daily manual glance isn't monitoring. External checks every few minutes catch the broken update before your audience does.
- Stagger risk. Keep auto-update on for security releases, but consider manual updates for major plugin versions — and do those when you're awake and watching.
- Alert on response-time shifts too. A "successful" update that doubles page generation time is a slow-motion incident.
The white screen of death returns 200
WordPress's most famous failure mode — the blank white page from a PHP fatal error — frequently ships with a 200 OK status code, depending on where in the render the error lands. WP_DEBUG off (as it should be in production) means no error text, just emptiness. A status-code monitor sees 200 and stays green while every visitor sees nothing.
Recent WordPress versions try to catch fatal errors with a recovery mode ("There has been a critical error on this website") — which is better, but that page can also return in ways a naive check calls healthy.
The answer is keyword assertions:
- Assert presence of a string that only exists when the page truly rendered — your footer copyright, a nav label, a product heading.
- Assert absence of the failure tells:
Fatal error,There has been a critical error,Warning:,Error establishing a database connection. That last one is the classic — the database-down page is a fully rendered, cheerful HTTP 200 on many configurations.
One monitor with a presence and an absence assertion catches the white screen, the critical-error page, and the database error — none of which a status-code check reliably sees.
wp-cron only runs when someone visits
WordPress's scheduler, wp-cron, has a design surprise: it isn't cron. It piggybacks on page views — scheduled tasks run when a visitor happens to hit the site after a task comes due. Two bad consequences:
- Low-traffic sites don't run their tasks. Scheduled posts miss their publish time, backups don't fire overnight (when traffic is lowest and backups are scheduled), update checks lag.
- High-traffic sites pay a tax — wp-cron logic firing on real user requests at the worst time.
The standard fix is switching to real cron. Disable the built-in trigger in wp-config.php:
define('DISABLE_WP_CRON', true);
Then run it on a real schedule — and while you're editing that crontab, give it a heartbeat so you'll know if it ever stops:
*/5 * * * * curl -fsS -m 30 https://example.com/wp-cron.php?doing_wp_cron > /dev/null \
&& curl -fsS -m 10 https://hb.example.com/ping/YOUR-CHECK-ID > /dev/null
The && means the heartbeat ping only fires when wp-cron actually ran successfully. If the server reboots and cron doesn't come back, if the crontab gets lost in a migration, or if wp-cron starts erroring — the ping goes silent and the missed heartbeat alerts you. Without this, a dead scheduler is invisible: the site looks fine, and you discover the problem when you need last night's backup and it doesn't exist.
Defacement and malicious plugins — watch for what changed
WordPress's popularity makes it the internet's favorite compromise target. And a compromised site is often still up — uptime monitoring stays green while the site serves spam links, a defacement page, or a skimmer script injected by a malicious or backdoored plugin. Pharma-spam injections are frequently invisible to the site owner entirely: shown only to search engine crawlers, poisoning your rankings for weeks before anyone notices.
This is where change detection earns its keep:
- Content change monitoring on key pages flags unexpected diffs — new outbound links, injected keywords, a replaced homepage.
- Watch the rendered page, not just the HTML you deployed — injected scripts often ride in via a plugin or database, not your theme files.
- Alert on new external domains appearing in your pages. Your homepage suddenly loading a script from an unfamiliar domain is the single strongest compromise signal there is.
Pair that with security-header and blacklist checks, and you'll hear about a compromise from your monitoring instead of from Google's "This site may be hacked" label.
xmlrpc.php — the door nobody uses but attackers love
xmlrpc.php is WordPress's legacy remote API. Almost nothing legitimate needs it anymore (the modern REST API replaced most use cases), but it remains a favorite for brute-force amplification — system.multicall lets an attacker try hundreds of password guesses in a single request — and for DDoS pingback abuse. If you don't use it, block it:
location = /xmlrpc.php {
deny all;
}
Then add a monitor that expects the block — a check on /xmlrpc.php asserting a 403. If a plugin update, a host migration or a well-meaning colleague quietly re-opens it, you'll know the day it happens instead of the day it's abused.
Staging is not production
A surprising number of WordPress outages are really process failures: the update was tested on staging, worked, and broke production anyway — different PHP version, different plugin set, an object cache that exists on one and not the other. Monitor both, separately. Staging monitors can alert at low severity to a Slack channel; production pages a human. And check that staging isn't leaking into search results while you're at it — an indexed staging site splits your SEO and occasionally exposes half-configured plugins to the same bots probing production.
Monitoring that speaks WordPress
None of this requires WordPress-specific tooling — it requires monitoring that goes deeper than "did it return 200." CompleteStatus covers the full list from one dashboard: uptime checks with keyword presence/absence assertions (the white screen, the database error page), heartbeat monitoring for your real-cron wp-cron setup, content change detection for defacement and injected scripts, SSL and domain expiry, and status-code assertions to verify your xmlrpc block stays blocked. When you do run planned plugin upgrades, use scheduled maintenance windows so the work doesn't page anyone — we've written up how to run maintenance windows properly.
Start monitoring your WordPress site free — the checks above take about ten minutes to set up, and the first broken auto-update they catch pays for the effort many times over.