30% off Pro plugins with LAUNCH30 See plugins

Requires the free Dragon Speed Doctor, version 1.1.1 or later, active. The free plugin finds which plugin is slowing your site with a one-off, on-demand scan. Pro turns that into an ongoing record: scans that run on their own schedule and right after an update, a 12-month history to compare against, and alerts that only fire once a slowdown has been confirmed by a second scan.

Pro works per site: on a single site, or on multisite activated site by site. Network activation is refused with a message asking you to activate it on each site instead.

Licence

Enter your licence key on the plugin's Licence tab (keys are in your dragoncore.ltd dashboard). The licence is sold annually by site count; keys are stored encrypted, and you can deactivate a site from the same screen to move an activation within your tier. Updates are delivered automatically to licensed sites. If the licence lapses, the plugin keeps working with every Pro feature on each activated site; what stops is new versions, downloads and support, and renewing restores all three on the same key. Every Pro tab is visible even when unlicensed; an unlicensed tab shows a notice linking back to Licence rather than being hidden or greyed out.

Monitoring settings

The Monitoring tab controls:

  • Run automatic scans - off, weekly or daily. Off means exactly that: no scan runs on its own, and nothing here nags you about it.
  • Quiet hour - the site-local hour (0-23) scheduled scans and the weekly summary run around, with a little random jitter so every licensed site is not hitting its own server at the same second.
  • After an update - runs a follow-up scan 10 minutes after a plugin, theme or core update finishes, debounced so a bulk update of several plugins only books one follow-up. If another scan is still running when it is due, it is pushed back 15 minutes, up to 4 times per update.
  • Measure wp-admin - off by default. A scheduled or after-update scan only measures a wp-admin page when this is on AND a specific administrator account is chosen to measure as; otherwise the admin page is dropped from that scan's page set. This applies to any scan run under the 'scheduled' or 'update' source - including wp speed-doctor-pro run (see WP-CLI below) - but never to a manual scan from the free plugin's own Results tab or its own wp speed-doctor scan command.
  • Alert email recipients, Webhook URL and Slack webhook URL - alerts go by email, signed webhook and Slack, to whichever are set; at least one must be set for an alert to be delivered anywhere, and the tab shows which channels are currently configured. Until the settings are first saved, email goes to the site's admin address; once saved, the list you chose is used, even an empty one. The signing secret shows "Set - rotate it to see a copy" when it was created automatically and has never been shown; rotating it shows the new one once. See "Webhook signature" below.
  • When to send - immediate (as it happens) or digest (held back and folded into the weekly summary).
  • Weekly summary - a Monday message, at the quiet hour, listing any confirmed slowdowns since the last one (or saying there were none).
  • Uninstall - "Delete all Pro data when this plugin is uninstalled". See "Uninstall" below.

Scheduled scans run through the same tick chain a manual scan uses, resumed by a short-lived cron event every 30 seconds until it finishes, so a single request never has to carry a whole scan's runtime.

History tab

Shows a chart per monitored page (front-end response time over the last 12 months, oldest scans pruned after 365 days), a "biggest movers" list comparing the newest scan against one you pick, and the confirmed slowdown alerts recorded so far. History starts empty until the first scan (manual or scheduled) records a row.

Confirmed alerts

A single scan running slower than usual only ever raises a suspicion, never an alert on its own - a scheduled or after-update scan can be noisy (server load, a one-off external timeout) and a lone bad reading is not evidence of a real regression. When a scheduled or after-update scan looks slower than its own reference history, Pro books a second, confirming scan about 5 minutes later. An alert is sent only when that confirming scan independently reproduces the same slowdown against the same reference data; otherwise the suspicion is dropped and nothing is sent. A suspicion left unconfirmed for more than 8 days is also dropped without alerting - by then the world has moved on. A manual scan from the free plugin's own Results tab, or its own wp speed-doctor scan command, is recorded to history but never raises or confirms a suspicion; Pro's own wp speed-doctor-pro run (see WP-CLI below) uses the same 'scheduled' or 'update' source a real schedule would, so it participates in this flow exactly as a scheduled scan does.

A confirmed alert names the pages and plugins involved and how much slower they measured, and what changed: a plugin that updated (with both versions), a plugin newly added alongside it ("WooCommerce is about 90ms slower; woo-gift-cards was added."), and, when every page got slower, a WordPress or theme update at the same time ("This coincides with WordPress updating from 7.1 to 7.1.1."). An alert led by one plugin is titled "{plugin} got slower"; a site-wide one is titled "Pages got slower", with the site name in front of it in the email subject and the Slack message. It goes to every configured channel (email, signed webhook, Slack), immediately or held for the weekly summary, depending on the "When to send" setting above.

Webhook signature

Before a webhook or Slack request is sent, the destination host is resolved and every address it answers with is checked: a host that resolves to a private, loopback, link-local, carrier-grade NAT or reserved address is refused. A webhook request carries two headers:

  • X-DragonSpeedDoctor-Signature: sha256=<hex hmac>
  • X-DragonSpeedDoctor-Timestamp: the Unix timestamp the request was sent

The signed string is <timestamp>.<raw request body>, HMAC-SHA256 with your webhook secret (shown once when generated, regenerable from the Monitoring tab). A receiver should reject a request whose timestamp is more than 300 seconds from its own clock, then recompute the signature and compare it with a constant-time comparison.

php
function dsdp_verify_alert_signature( string $body, string $signature, string $timestamp, string $secret, int $tolerance = 300 ): bool {
	if ( abs( time() - (int) $timestamp ) > $tolerance ) {
		return false;
	}

	$expected = 'sha256=' . hash_hmac( 'sha256', (int) $timestamp . '.' . $body, $secret );

	return hash_equals( $expected, $signature );
}

Slack destinations get the same public-address check as webhooks, and the URL's host must be exactly hooks.slack.com.

The breakdown panel

On the free plugin's Results tab, Pro adds a breakdown under each verdict: the database query shapes (literal values stripped, never stored) and the outgoing HTTP hosts attributed to that plugin, most expensive first. It explains where a plugin's impact on a page comes from, not a second opinion on how much impact it had - the timing verdict itself is still the free plugin's own measurement.

The breakdown is measured on a real front-end page request, not guessed from a static scan: once a scan completes, a short-lived cron event fetches a few of the scan's own front-end pages a second time with a signed profiling flag, reads back what each attributed plugin queried or called out to during that request, and stores the median per plugin against the scan's history row. Because this pass runs in WP-Cron, where no user is logged in, it only ever covers front-end pages - a wp-admin page in the scan's page set is skipped for this specific pass, even when "Measure wp-admin" is switched on for the scan itself. A breakdown can therefore be missing for an older scan, an unlicensed site, or a scan whose pass has not run yet; the panel simply prints nothing in that case rather than an empty box.

Site Health

Site Health includes a dsdp_schedule test, under the "Performance" badge:

  • Good - a scheduled (or confirmation) scan finished within 2x the chosen frequency's interval, or scheduled scans are switched off entirely (switching them off is a deliberate choice, not something to nag about).
  • Critical - the last 2 (or more) scheduled/after-update attempts in a row were refused by the free plugin's own preflight - it is actively stopping scans from running at all, not just a one-off. This streak is counted independently of whether an alert was actually delivered for any of those attempts, and resets to 0 the next time a scheduled or after-update scan finishes cleanly.
  • Recommended - the scan is overdue for any other reason: no scan has completed within 2x the chosen interval, but fewer than 2 blocked attempts in a row - most likely WP-Cron is not running on the site, or a single blocked attempt has not (yet) repeated.

Before the first scheduled scan has ever run, the test reports Good with "First scheduled check: {date}" when one is booked, or Recommended with "Scheduled checks are not booked yet. Open the Monitoring tab to set them up." when none is. A booked first check whose time passed long ago (more than 2x the interval) reads as overdue instead.

WP-CLI

bash
wp speed-doctor-pro history [--limit=<n>] [--format=table|json]
wp speed-doctor-pro run [--source=scheduled|update]
wp speed-doctor-pro alert-test

history lists the recorded 12-month history (default 20 rows, capped at 1000), with a count of how many groups in each row landed in the high, medium and low impact bands. It only reads and works without a licence.

run starts a scan the same way the schedule would (--source=scheduled by default, or --source=update for the after-update path, which is also what the "Measure wp-admin" setting above applies to) and drives it synchronously in the current process - printing progress and waiting up to 30 minutes for it to finish - rather than leaving it for WP-Cron to pick up. It refuses to start a second scan while one is already running, and exits non-zero if the scan could not be started or did not finish within the timeout.

alert-test sends a test message to every configured channel (the same "Send test alert" action available from the Monitoring tab) and reports each channel's result; it exits non-zero when no channel is configured or none of them delivered.

Uninstall

Deleting the plugin keeps all its data by default, so a reinstall picks up where you left off. To remove everything this add-on stores (its 12-month history table, its own options, its scheduled tasks, and its delivery/digest state) on uninstall, opt in first on the Monitoring tab, under Uninstall: tick Delete all Pro data when this plugin is uninstalled, then save. The free plugin's own scan data and settings are controlled by its own uninstall setting and are never touched by this add-on's uninstall routine.