WordPress Signals Reference
The plugin emits raw signals — single-occurrence observations. No aggregation, deduplication, or alerting happens in the plugin itself. All intelligence lives in the Logystera processor.
Bounded signal volume. Per-request caps prevent runaway emission. Each signal type has a fixed maximum per request, with a global cap of 200 events. The plugin never becomes an unbounded source of data regardless of what happens on the site.
Controlled cardinality. The plugin sends raw payloads, but the Logystera processor decides which fields become metrics labels. You cannot accidentally create runaway metrics — every label is explicitly declared in the platform's metric definitions.
!!! info "Glossary" Time series database (TSDB): A database optimized for storing values that change over time (e.g. "requests per minute"). Each data point is a timestamp + value. Logystera uses VictoriaMetrics as its TSDB.
**Cardinality:** The number of unique label combinations on a metric. Example: a metric with label `hook` tracking 11 hooks = cardinality 11. If you added `user_id` (thousands) × `hook` (11) × `path` (unlimited), cardinality explodes to millions — slow queries, high memory, high cost. The plugin avoids this by design: the processor controls which fields become labels.
Event schema
Every signal sent to the gateway has exactly four top-level keys:
{
"event_type": "auth.attempt",
"timestamp": 1706000000,
"labels": {
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"site": { "url": "https://example.com/", "blog": 1 },
"req": { "method": "POST", "uri": "/wp-login.php", "ua": "Mozilla/5.0..." },
"actor": { "user_id": 0, "ip": "1.2.3.4" }
},
"payload": { ... }
}
Labels (always present)
| Field | Type | Description |
|---|---|---|
labels.request_id |
string |
UUID v4. Correlates all events from the same PHP request. |
labels.site.url |
string |
Site home URL. |
labels.site.blog |
int |
Blog ID. Always 1 on single-site installs. |
labels.req.method |
string |
HTTP verb: GET, POST, etc. |
labels.req.uri |
string |
Full URI with sensitive query params redacted to [redacted]. |
labels.req.ua |
string |
User agent string. |
labels.actor.user_id |
int |
WordPress user ID. 0 = logged-out visitor. |
labels.actor.ip |
string |
Client IP. Optionally anonymized — see Configuration. |
Signals
wp.environment
Emitted every flush cycle (every 15 minutes) as a snapshot. Includes a changed flag indicating whether the environment actually changed since the last emit. Leads all other signals in the batch so the processor always has current environment context.
{
"wp_version": "6.7.1",
"php_version": "8.2.18",
"plugin_count": 2,
"plugins": ["akismet/akismet.php", "logystera/logystera.php"],
"theme": "twentytwentyfour",
"theme_version": "1.2",
"multisite": false,
"changed": false,
"debug_mode": false,
"object_cache": true,
"disk_free_gb": 42.7,
"memory_limit_mb": 256,
"wp_memory_limit_mb": 256,
"server_software": "nginx/1.24.0",
"php_sapi": "fpm-fcgi",
"hosting": {
"provider": "siteground",
"confidence": 85,
"all_scores": { "siteground": 85, "kinsta": 0, "aws": 10, "unknown": 5 }
}
}
| Field | Type | Description |
|---|---|---|
debug_mode |
bool |
true if WP_DEBUG is enabled. |
object_cache |
bool |
true if an external object cache (Redis/Memcached) is active (wp_using_ext_object_cache()). |
disk_free_gb |
float |
Free disk space on the ABSPATH partition in GB. |
memory_limit_mb |
int |
Effective PHP memory limit in MB (ini_get('memory_limit')). The actual cap enforced by the host. -1 means unlimited. |
wp_memory_limit_mb |
int |
Memory limit WordPress requested via WP_MEMORY_LIMIT. If lower than memory_limit_mb, the host is capping below what WP wants. |
server_software |
string |
Value of $_SERVER['SERVER_SOFTWARE'] (e.g. "nginx/1.24.0"). |
php_sapi |
string |
PHP SAPI name (e.g. "fpm-fcgi", "apache2handler"). |
hosting.provider |
string |
Detected hosting provider (e.g. "siteground", "kinsta", "aws", "unknown"). Cached for 24 hours. |
hosting.confidence |
int |
Detection confidence, 0–100. |
hosting.all_scores |
object |
All candidate providers with their scores. |
When memory_limit_mb < wp_memory_limit_mb, the host is restricting PHP below WordPress's requested limit — this correlates with memory_near_limit signals firing more frequently.
The hosting object is determined using 5 signal layers: PHP constants, active plugins, rDNS/hostname patterns, response headers (loopback request), and path patterns. The result is cached as a WordPress transient for 24 hours to avoid repeated loopback requests.
Hook flag: environment_signals (default: ON)
Rate limit: 1 per flush cycle.
wp.search
Emitted on frontend search requests. Hooked on parse_query, fires only for the main query when is_search() is true.
{
"query": "wordpress security",
"query_len": 20
}
| Field | Type | Description |
|---|---|---|
query |
string |
Sanitized search term, truncated to 200 characters. |
query_len |
int |
Character length of the search term. |
Hook flag: search_signals (default: ON)
Rate limit: 10 per request.
http.request
Emitted once per request at shutdown. Captures transport-level data and performance.
{
"path": "/wp-admin/plugins.php",
"query": "?plugin_status=active",
"status": 200,
"is_admin": true,
"is_ajax": false,
"is_cron": false,
"is_rest": false,
"fingerprint": "GET /wp-admin/plugins.php",
"execution_time_ms": 312,
"peak_memory_mb": 18.4,
"referer_host": "google.com",
"referer_type": "search"
}
ajax_action is included when $_REQUEST['action'] is set. rest_route is included on REST requests. referer_host and referer_type are only present when an HTTP Referer header is present; referer_type is always "direct" when there is no referer.
| Field | Type | Description |
|---|---|---|
referer_host |
string |
Lowercase hostname of the HTTP Referer, stripped of www. prefix. Only present when a referer header exists. |
referer_type |
string |
Classified traffic source. One of: search, social, internal, external, direct (no referer). |
Search engines classified as search: Google, Bing, Yahoo, DuckDuckGo, Baidu, Yandex.
Domains classified as social: Facebook, Instagram, Twitter/X, LinkedIn, Pinterest, Reddit, YouTube, TikTok.
internal means the referer host matches the site's own domain. All other referers are external.
Rate limit: 1 per request.
auth.attempt
Emitted on every login attempt — both success and failure.
{
"success": false,
"username_hash": "a1b2c3d4...",
"username_len": 5
}
Usernames are always HMAC-SHA256 hashed. The raw username is never transmitted.
Rate limit: 50 per request.
auth.logout
Emitted when a user logs out.
{
"user_id": 42
}
Rate limit: 5 per request.
rest.request
Emitted on every REST API response. Complements http.request with semantic route data.
{
"route": "/wp/v2/posts",
"method": "GET",
"status": 200,
"namespace": "wp/v2"
}
REST calls emit both http.request and rest.request. They are correlated via labels.request_id. Do not double-count traffic — use http.request for volume metrics.
Rate limit: 20 per request.
php.warning
Emitted for each PHP warning, notice, or deprecated error.
{
"message": "Undefined variable: foo",
"file": "/var/www/html/wp-content/plugins/my-plugin/class.php",
"line": 42,
"severity": "E_WARNING",
"fingerprint": "a1b2c3...",
"source": "plugin"
}
source is one of: plugin, theme, core, unknown.
Backtrace function arguments are always stripped before transmission.
Rate limit: 50 per request.
php.fatal
Emitted when a PHP fatal error is detected at shutdown.
{
"type": "E_ERROR",
"message": "Call to undefined function foo()",
"file": "/var/www/html/wp-content/plugins/my-plugin/class.php",
"line": 88,
"fingerprint": "b2c3d4...",
"source": "plugin"
}
Rate limit: 3 per request.
cron.run
Emitted once when WordPress processes a cron batch (DOING_CRON).
{
"execution_time_ms": 1420,
"peak_memory_mb": 22.1,
"had_error": true,
"error_type": "E_WARNING",
"error_message": "...",
"error_file": "...",
"error_line": 33
}
had_error and error fields are only present when a PHP error occurred during the cron run.
Rate limit: 1 per request.
wp.cron
Emitted from logystera_cron_tick (every 5 minutes) and via the WordPress missed_schedule action.
type: health_check
Full queue snapshot emitted every tick regardless of queue state.
{
"type": "health_check",
"total": 14,
"overdue": 0,
"overdue_ratio": 0.0,
"max_delay_sec": 0,
"avg_delay_sec": 0,
"overdue_hooks": []
}
overdue_hooks lists the hook names of overdue jobs (up to 10).
type: missed_schedule
Emitted when a scheduled post fails to publish at its scheduled time.
{
"type": "missed_schedule",
"post_id": 4521,
"post_type": "post",
"scheduled": "2026-03-04 22:00:00",
"delay_sec": 3612
}
Hook flag: cron_signals (default: ON)
Rate limit: 20 per request.
perf.hook_timing
Emitted at shutdown on 10% of requests. Records hooks that took longer than 50ms, up to 20 per request.
{
"hooks": [
{ "hook": "the_content", "ms": 134.2, "source": "woocommerce" },
{ "hook": "wp_head", "ms": 87.5, "source": "theme:flavor" }
],
"count": 2,
"total_ms": 221.7
}
Each slow hook includes a source field identifying the plugin or theme with the most callbacks on that hook (heuristic for likely cause). Format: "woocommerce" for plugins, "theme:astra" for themes. Omitted when the source is WordPress core or unresolvable.
Tracked hooks: init, wp_loaded, template_redirect, wp_head, wp_footer, the_content, wp_enqueue_scripts, admin_init, admin_menu, rest_api_init, woocommerce_init.
Hook flag: hook_timing (default: OFF — performance impact)
Rate limit: 1 per request.
wp.integrity
Emitted when wp-config.php or .htaccess hash changes since the last hourly check.
{
"type": "file_changed",
"file": "wp-config",
"old_hash": "a1b2c3d4...",
"new_hash": "e5f6a7b8..."
}
file is one of: wp-config, htaccess.
Hook flag: integrity_signals (default: ON)
Rate limit: 5 per request.
wp.state_change
Emitted on plugin/theme/core lifecycle events.
{
"type": "plugin_activated",
"name": "akismet/akismet.php"
}
type values: plugin_activated, plugin_deactivated, theme_switched, core_updated, plugin_updated, theme_updated, translation_updated.
Rate limit: 10 per request.
upload_blocked
Emitted when WordPress blocks a file upload due to dangerous extension.
{
"filename": "shell.php",
"ext": "php",
"size": 1024,
"mime": "application/x-httpd-php"
}
Rate limit: 10 per request.
memory_near_limit
Emitted at shutdown when peak PHP memory usage exceeds 90% of WP_MEMORY_LIMIT.
{
"peak_mb": 118.2,
"limit_mb": 128,
"percent": 92
}
Rate limit: 1 per request.
Database error signals
Emitted at shutdown when $wpdb->last_error is non-empty. Classified into subtypes:
| Signal | Trigger condition |
|---|---|
db_error |
Generic database error |
db_deadlock |
Deadlock detected |
db_lock_timeout |
Lock wait timeout |
db_connection_failed |
Cannot connect to MySQL |
db_connection_limit |
Too many connections |
db_table_crashed |
Table crash detected |
db_disk_full |
Disk full error |
db_access_denied |
Access denied |
All database signals share the same payload shape:
{
"error": "Table 'wp_options' is marked as crashed",
"query_hash": "a1b2c3..."
}
Raw SQL is never included. Only query_hash (SHA-1) is transmitted.
Rate limit: 10 per request (shared across all db_* types).
Data privacy
| Field | Treatment |
|---|---|
| Usernames | HMAC-SHA256 hashed only. Raw value never transmitted. |
| SQL queries | Never emitted. SHA-1 hash only. |
| URL query strings | Preserved, but sensitive params redacted to [redacted]. |
| IP addresses | Optionally anonymized. See Configuration. |
| PHP backtraces | Function arguments stripped. File, line, function only. |
| Headers | Authorization, Cookie, Set-Cookie never captured. |
Sensitive query param names that are always redacted: token, secret, password, passwd, key, api_key, apikey, access_token, refresh_token, nonce, _wpnonce, session, jwt, code, auth.
Global rate limits
| Scope | Limit |
|---|---|
| Total events per request | 200 (hard cap) |
| Pending event buffer | 10,000 (events dropped when full) |