← Back
CASE STUDY · MAY 2026 · 4 DAYS OF OPTIMIZATION

How we rescued chinaglobalsouth.com

A WordPress site with 250k visits/month that was crashing with 502s, eaten by invisible bots, and with a bug-filled theme. In 4 days: zero crashes, attacks blocked, performance recovered.

Monthly traffic
250k
visits / month
Requests analyzed
18,239
in 4 days
Stack
WP Engine
PHP 8.2 · MySQL 8.4 · CF
Active plugins
42
including Wordfence Free

CHAPTER 1

The site was going down. Nobody knew why.

The client reported vague symptoms: "wp-admin is super slow", "sometimes the site throws an error", "the editor hangs when saving". Without observability, that's all the owner can describe — symptoms, not causes.

We activated an event-capture mu-plugin (which later became Pulse) and in the first 24 hours we saw the full picture:

💥
9 × 502
errors every 4 hours

Human level: the site fails 1 in every 100 visitors — and you don't know when or who.
Technical level: PHP-FPM takes more than 60 seconds to respond and nginx throws upstream timeout.

🐛
98
PHP errors every 2 hours

Human level: your site keeps writing to an error file nobody reads. It's disk not used for serving.
Technical level: PHP 8 warnings from accessing array offset without validation.

🐢
10.7s
P95 latency (worst 5%)

Human level: 1 in every 20 visitors waited more than 10 seconds for a page to load.
Technical level: P95 percentile at 10,730ms — borderline timeout in many cases.

💾
509 MB
of MySQL overhead

Human level: half a gigabyte of junk in the database that every query has to navigate around.
Technical level: wp_options tables + unrotated logs consuming space + I/O.

CHAPTER 2

The attack nobody saw

While analyzing the logs, one IP appeared making a very strange pattern. Each request took 23 to 34 seconds and generated 3,000+ SQL queries. It was an SEO spam bot abusing the WordPress search engine, hitting it with URLs like:

/page/61?s=news+am+cleantalkorg2.ru+World+News+The+New+York+Times+Breaking+News...

Why did nobody see it?

  • The site returned 200 OK at the end — from the outside "everything fine".
  • Wordfence Free didn't block behavioral patterns.
  • Each request consumed a PHP worker for 30 seconds.
  • It happened 10+ times per hour, for weeks.

The real cost: ~5 minutes of PHP-time spent per hour on spam. That's 1 worker permanently occupied by a bot. Meanwhile, real visitors were waiting in queue.

VISIBILITY DURING THE ATTACK

The attack had been active for weeks. Pulse found it in 1 hour.

CHAPTER 3

21 identical bugs. The same one, copy-pasted.

The theme had the same bug repeated 21 times across 11 different files. Accessing an array key without first checking the array existed. PHP 8 throws a warning. The warning goes to disk. Multiplied by thousands of visitors.

BEFORE Original code — dangerous
$thumb = wp_get_attachment_image_src(...);
$thumb = filter_var($thumb[0], FILTER_VALIDATE_URL)
            ? $thumb[0]
            : 'fallback.jpg';

If $thumb is false (the post has no image), accessing $thumb[0] triggers a PHP 8 warning.

AFTER We validate before accessing
$thumb = wp_get_attachment_image_src(...);
$thumb_url = (is_array($thumb) && isset($thumb[0]))
              ? $thumb[0] : '';
$thumb = filter_var($thumb_url, FILTER_VALIDATE_URL)
            ? $thumb_url
            : 'fallback.jpg';

No warnings. No overhead. Bonus: we added esc_url() in other places — free XSS mitigation.

BUG PROPAGATION BY FILE

The same error was copied into 11 theme files. Any of them could trigger it.

CHAPTER 4

The 67-second cron

A cron event appeared consuming almost 70 full seconds. But WordPress doesn't tell you which hook is slow inside a cron run — it only tells you the wp-cron.php file took N seconds. We built a profiler that captures per-hook timing, and on the first slow cron we caught the culprit:

BREAKDOWN OF THE 67s CRON

The first hook consumed 99% of total time.

THE CULPRIT
memberful_wp_cron_sync
61.832 seconds
per execution

Root cause: the Memberful plugin syncs with its API pulling all members each time (non-incremental).

Recommended fix: lower cron frequency, or move to Action Scheduler to run in background without blocking user-facing PHP workers.

Without Pulse's cron profiler, this would be invisible. Wordfence doesn't see it. Sucuri doesn't see it. New Relic would cost $99+/month.

CHAPTER 5

Wordfence was there. Blocking nothing.

The site had Wordfence Free installed. People assume they're protected. But Wordfence Free doesn't detect behavioral patterns — it only blocks based on a list of known signatures. Modern attacks are behavioral, not signatures.

COVERAGE BY ATTACK TYPE

The radar shows how much each solution covers.

Wordfence Free

Free but limited

Good for: login lockouts, malware scanner, basic IP reputation.
Did not block: the 5 attack types most affecting this site.

SysWP Shield + Pulse

Behavioral + observability

Good for: all of the above + behavioral firewall, custom rules, 16-signal bot scoring, slow request tracking.
Blocked: the 5 attacks Wordfence missed.

📊 The difference in numbers

  • Wordfence Free: ~5 attacks blocked/h
  • Shield + Pulse: ~80 attacks blocked/h
  • 16× more detection.

BLOCKED ATTACKS OVER TIME

Day 1: only Wordfence (5/h). Day 3+: Shield active (80–122/h).

CHAPTER 6

Day by day, the numbers dropped.

This is the real evolution, metric by metric, over the 4 days of optimization. Each deploy was reflected in the latency percentiles.

LATENCY — ALL PERCENTILES

P50 (typical), P95 (worst 5%), P99 (worst 1%), AVG (average).

502 ERRORS / DAY

Zero 5xx per day since Day 2.

PHP ERRORS / HOUR

From ~50/h to essentially zero.

LATENCY — BEFORE VS AFTER

Direct comparison of percentiles.

STATUS CODE DISTRIBUTION (4 hours, day 4)

The 7% of 403s are attacks blocked by Shield. The 200s are happy visitors.

CHAPTER 7

509 MB of junk. Recoverable.

Security plugin logs not rotated (568 MB), AdRotate trackers (177 MB), tables with years of accumulated overhead. Every MySQL query had to navigate this dead weight. We identified and cleaned it in batches.

TOP TABLES WITH RECOVERABLE OVERHEAD

These MB are not useful data. They are blank pages between rows.

FINAL RESULT

From "fragile" to "solid" in 4 days

9 × 502 / 4h
0 × 5xx in 18,239 requests
98 PHP errors / 2h
~0 PHP errors from theme
P95: 10,730 ms
P95: 7,639 ms (−29%)
AVG: 5,261 ms
AVG: 3,866 ms (−27%)
cleantalkorg attack: invisible for 2+ weeks
Detected in 1 hour · blocked in 4h
~5 attacks blocked/h
~80 attacks blocked/h
67s cron undiagnosed
Memberful identified in 1 execution
21 PHP bugs copy-pasted
All fixed (+ XSS esc for free)
509 MB DB overhead
~50 MB after cleanup

The technical conclusion

Without observability, you can't see it. Without seeing it, you can't fix it. The cleantalkorg attack had been active for weeks. The 21 theme bugs were generating constant noise. The Memberful cron had never been diagnosed. All of that was invisible to Wordfence, to the client, to WP Engine's logs. Once visible, the solutions took hours, not weeks.

WANT THE SAME FOR YOUR SITE

Pulse is coming.

Join the waitlist. The first 500 get 50% lifetime discount and private beta access.

Join the list