WP Manifestindependent plugin directory
manifest / developer / query-origin-tracer

Query Origin Tracer WP Registry grade A. No security issues foundWP RegistryNo security issues foundOpen the reportA

Trace slow and stuck WordPress database queries to their originating requests, visitors, plugins, themes, and PHP call stacks.

★ 0stars
37release downloads
v2.0.1latest · 3mo ago

Install

Download query-origin-tracer-2.0.1.zip From the v2.0.1 release on GitHub, Jul 18, 2026

Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/andrecmsilva/query-origin-tracer/releases/download/v2.0.1/query-origin-tracer-2.0.1.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Find the WordPress request, visitor, plugin, theme, or PHP call stack behind a database query.

Query Origin Tracer is a production diagnostics plugin for investigating slow, repeated, and stuck WordPress database queries. It records structured JSONL evidence and includes WP-CLI commands for starting targeted captures, following results live, and cleaning up afterward.

[!WARNING] This is a temporary diagnostic tool, not an always-on profiler. Captured SQL, request data, and headers may contain sensitive information. Use it for focused investigations and disable it when the capture is complete.

Why use it?

A slow query log can tell you what ran. Query Origin Tracer helps answer the harder questions:

  • Which request caused it?
  • Which plugin, MU-plugin, theme, or application code initiated it?
  • What PHP stack led to the query?
  • Which visitor or upstream request was involved?
  • Is a query currently stuck inside a PHP worker?
  • Are recurring queries the same shape with different values?

What it captures

  • Raw SQL and a normalized query fingerprint
  • Execution time for completed queries
  • PHP call stack with file and line numbers
  • Detected plugin, MU-plugin, theme, or application origin
  • Request URI, method, host, referer, and user agent
  • REMOTE_ADDR, CF-Connecting-IP, True-Client-IP, X-Forwarded-For, and CF-Ray
  • REST, AJAX, cron, WP-CLI, admin, and XML-RPC context
  • Authenticated WordPress user ID when already available
  • PID, request ID, site/blog ID, current memory, and peak memory
  • Optional per-PID records for queries that have started but not returned

How v2.0 works

Query Origin Tracer installs as a normal plugin in wp-content/plugins/query-origin-tracer/. When activated, it creates a small managed bootstrap at:

wp-content/mu-plugins/query-origin-tracer-loader.php

The bootstrap loads the tracer early enough to observe queries initiated before ordinary plugins load, while the plugin itself remains manageable through the standard WordPress lifecycle.

  • Activation creates the early loader and activation marker.
  • Deactivation removes the loader and marker but preserves captured evidence.
  • Deletion removes the loader, marker, configuration, logs, in-flight records, stored options, and any legacy MU-only installation.
  • Capture is opt-in: activating the plugin alone does not begin tracing queries.

Requirements

  • WordPress 5.8 or newer
  • PHP 7.4 or newer
  • WP-CLI for capture management and the live reader

Installation

WordPress Admin

  1. Download the latest release ZIP.
  2. Open Plugins → Add New → Upload Plugin.
  3. Upload, install, and activate Query Origin Tracer.

WP-CLI

wp plugin install /path/to/query-origin-tracer.zip --activate

Manual

cp -a query-origin-tracer wp-content/plugins/
wp plugin activate query-origin-tracer

The default state directory for a typical /home/USER/public_html installation is outside the document root:

/home/USER/.query-origin-tracer

To use another location, define it in wp-config.php before WordPress loads:

define( 'QOT_STATE_DIR', '/secure/path/.query-origin-tracer' );

Quick start

Capture queries taking at least 250 ms:

wp query-origin enable --mode=slow --min-seconds=0.25

Capture starts on subsequent WordPress requests. Open the site from another terminal or browser, making sure the request reaches WordPress rather than being served entirely from a page cache or CDN.

Follow the latest records live:

wp query-origin list

list is intentionally blocking: it continues waiting for new matching queries until you press Ctrl+C. The default slow mode may remain empty on a healthy site because it only records individual database queries taking at least 250 ms.

For a first-run verification, temporarily capture every query, generate one uncached request, then print the results without following:

wp query-origin enable --mode=all --max-per-request=25
curl -sS "https://example.com/?qot-test=$(date +%s)" >/dev/null
wp query-origin list --last=25 --no-follow
wp query-origin disable

Run the curl request from another terminal if the first terminal is already following the log.

Check the current configuration:

wp query-origin status

When the investigation is complete:

wp query-origin disable

Disabling capture preserves the evidence. Remove it explicitly with:

wp query-origin clear

Capture recipes

Find actively stuck queries

In-flight mode maintains one current-query file per PHP PID. If a query never returns, its record remains available for inspection.

wp query-origin enable --mode=slow --min-seconds=0.25 --inflight=1
wp query-origin inflight

Or inspect recent records directly:

find ~/.query-origin-tracer/inflight -type f -name '*.json' -mmin -10 -print -exec jq . {} \;

Capture every completed query

Use this only for short, targeted windows:

wp query-origin enable --mode=all --max-per-request=100

Filter by SQL

Regular expressions must include delimiters:

wp query-origin enable \
  --mode=all \
  --sql-include='~wp_actionscheduler_|SQL_CALC_FOUND_ROWS|wp_postmeta~i' \
  --inflight=1

Filter by request

wp query-origin enable \
  --mode=all \
  --request-include='~wp-json|admin-ajax\.php|wp-cron\.php~i'

Filter by visitor IP

IP matching uses exact values:

wp query-origin enable --mode=all --ip='203.0.113.10,2001:db8::10'

Reading results

Live WP-CLI reader

wp query-origin list prints the latest 10 records and continues following new queries until Ctrl+C. Each result includes the host, request URI and query string, remote address, user agent, UTC start time, SQL, detected origin, duration, and current/peak PHP memory.

# Start with the latest 25 records and continue following.
wp query-origin list --last=25

# Follow only records written after the command starts.
wp query-origin list --last=0

# Print the latest 50 records and exit.
wp query-origin list --last=50 --no-follow

# Poll the log every 100 milliseconds.
wp query-origin list --poll=0.10

The reader handles ordinary appends, log truncation after clear, and log-file recreation.

Raw JSONL

tail -F ~/.query-origin-tracer/events.jsonl | jq .

Group recurring query shapes:

jq -r '.fingerprint' ~/.query-origin-tracer/events.jsonl \
  | sort | uniq -c | sort -nr | head -30

Group queries by detected component:

jq -r '[.origin.type, .origin.component] | @tsv' ~/.query-origin-tracer/events.jsonl \
  | sort | uniq -c | sort -nr | head -30

Show stack traces for queries over one second:

jq -r '
  select(.duration_seconds >= 1)
  | "\n=== \(.duration_ms) ms | \(.request_uri) ===\n"
    + (.stack[] | "\(.file):\(.line) \(.call)")
' ~/.query-origin-tracer/events.jsonl

Command reference

Command Purpose
wp query-origin enable Start or update a capture
wp query-origin status Show configuration, log location, and in-flight count
wp query-origin list Read and optionally follow completed-query records
wp query-origin inflight Display queries currently associated with PHP PIDs
wp query-origin disable Stop tracing while retaining evidence
wp query-origin clear Delete completed-query and in-flight records

Operational and privacy notes

  • SAVEQUERIES times every $wpdb query and collects caller information. Expect additional CPU and memory overhead.
  • In-flight mode writes and removes a small file for each eligible query. Enable it only while investigating active hangs.
  • SQL, URIs, headers, and user metadata can contain personal data, credentials, or tokens. Protect the state directory and sanitize evidence before sharing it.
  • State directories and files are created with restrictive permissions and should remain outside the document root.
  • CF-Connecting-IP is trustworthy only when the origin accepts traffic exclusively from Cloudflare or otherwise prevents clients from spoofing it.

Limitations

  • With the managed MU loader, tracing begins after MU-plugins load. If the server prevents the loader from being created, the tracer still runs as an ordinary plugin but begins later in bootstrap.
  • It cannot observe bootstrap queries that ran before the tracer loaded.
  • It cannot observe direct mysqli or PDO connections created outside the active WordPress $wpdb implementation.
  • It cannot observe queries avoided entirely by object caching.
  • A custom db.php drop-in must implement WordPress's SAVEQUERIES and log_query_custom_data behavior for completed-query timing. In-flight capture may still help when the standard query filter is implemented.

Upgrade from v1.x

Version 2.0 replaces the legacy MU-only package with a standard WordPress plugin. Activation and uninstall routines detect and clean up the earlier package automatically. Install and activate v2.0 through the normal plugin workflow; it will manage the early bootstrap from there.

Changelog

2.0.1

  • Clarified that capture begins on subsequent WordPress requests.
  • Added actionable first-run guidance when no completed query has matched.
  • Explained the live reader's blocking behavior and all-query verification workflow.

2.0.0

  • Converted the legacy MU-only package into a standard WordPress plugin.
  • Added an activation-managed early MU bootstrap.
  • Added complete deactivation, uninstall, and v1 migration cleanup.

Verify or remove the installation

wp plugin status query-origin-tracer
wp query-origin status
ls -l wp-content/mu-plugins/query-origin-tracer-loader.php

To remove the tracer and all plugin-created diagnostic data:

wp plugin deactivate query-origin-tracer
wp plugin delete query-origin-tracer

License

Query Origin Tracer is licensed under the GNU General Public License v2.0 or later.

Releases

3 releases. Each count is every asset in that release; expand a row for the breakdown.

Tag
Published
Assets
Downloads
v2.0.1 latest
Jul 18, 2026 3mo ago
query-origin-tracer-2.0.1.zip
29
Jul 18, 2026 3mo ago
query-origin-tracer-2.0.0.zip
8
Jul 18, 2026 3mo ago
tag only
—
A grade

Security

Query Origin Tracer 2.0.1 · audited by WP Registry

No security issues found.

Audited release
2.0.1
Findings
none
Worst severity
—
Content hash
e82e2cfa774bc929ebc72658…

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.