Debug Logging
UnBlock includes a lightweight debug logger for diagnosing expression, query, and template errors. It is disabled by default and produces zero overhead in production.
Enabling
Add this constant to wp-config.php:
define( 'UNBK_DEBUG', true );
When disabled (the default), all do_action( 'unblock/log/...' ) calls are pure no-ops — no listeners are registered, no files are created.
Log Files
Location: wp-content/uploads/unblock/logs/
Filename format: {Y-m-d}-{hash}.log
The hash suffix is generated via wp_hash(), making filenames unpredictable without access to wp-config.php. One file per day — all entries for the same day append to the same file.
Entry Format
[2026-02-16 14:32:01] [ERROR] Expression resolution failed {"expression":"post.invalid_field","error":"Unknown provider field"}
[2026-02-16 14:32:01] [WARNING] Invalid date value or modifier {"error":"Failed to parse time string"}
Log Levels
| Hook | Level | Fired When |
|---|---|---|
unblock/log/error | ERROR | Expression resolution, query execution, or class instantiation fails |
unblock/log/warning | WARNING | Non-critical issue (e.g. invalid date modifier) |
unblock/log/debug | DEBUG | Available for custom diagnostic logging |
Third-Party Integration
Any code can hook into unblock/log/{level} regardless of whether UNBK_DEBUG is enabled:
// Forward errors to Query Monitor.
add_action( 'unblock/log/error', function ( string $message, array $context ): void {
do_action( 'qm/error', $message, $context );
}, 10, 2 );
// Send errors to Sentry.
add_action( 'unblock/log/error', function ( string $message, array $context ): void {
\Sentry\captureMessage( $message, \Sentry\Severity::error() );
}, 10, 2 );
// Listen to all levels.
foreach ( [ 'error', 'warning', 'debug' ] as $level ) {
add_action( "unblock/log/{$level}", 'my_custom_handler', 10, 2 );
}
Security
The logger is designed with zero attack surface when disabled:
- Constant-gated — No log file or directory is created unless
UNBK_DEBUGis explicitlytrue. - Hashed filenames —
wp_hash()makes log filenames unguessable (primary protection on Nginx). .htaccess—deny from allblocks direct HTTP access on Apache/LiteSpeed.index.html— Prevents directory listing as a fallback.
Next steps
- Actions — plugin lifecycle and form hooks
- Data filters — providers, meta, and expression extensions