OIntel v1.0.0
A comprehensive WordPress site intelligence and diagnostics dashboard — 0–100 health score, 25+ automated checks, historical snapshots, session tracking, and exportable reports. Entirely self-hosted.
What OIntel does
Unlike narrow tools like Query Monitor (developer-only) or WP Site Health (limited, no history), OIntel delivers a full intelligence layer — scores, history, alerts, and reports — with no external accounts required.
Getting installed
Manual installation
ointel/ folder to /wp-content/plugins/.Via WP-CLI
BASHwp plugin install ointel.zip --activate
wp ointel scan
On activation / deactivation / uninstall
| Event | What happens |
|---|---|
| Activation | Creates 5 custom database tables · Schedules background scan cron (daily) · Schedules weekly report email |
| Deactivation | Removes scheduled cron events · All data preserved (tables and options remain) |
| Uninstall | If Remove on uninstall is enabled in Settings, all tables and options are permanently deleted |
Plugin architecture
manage_options.Admin interface
Built on the Orravo Design System — scoped CSS tokens, dark/light toggle, 2-row sticky header. The WP sidebar is hidden on all plugin pages; navigation lives entirely within #ointel-wrap.
| Tab | Purpose |
|---|---|
| Dashboard | Health score ring, category breakdown, fix list, 30-scan score history chart |
| Environment | PHP, WP version, SSL, memory, disk, extensions, cron status |
| Plugins | Plugin list, update status, vulnerability scan, orphaned tables |
| Performance | TTFB, DB table sizes, autoload options, transients, revisions |
| Content | Posts without images, orphaned media, stale drafts, excerpts, content counts |
| Snapshots | Take / delete snapshots, compare two snapshots side-by-side |
| Sessions | Active sessions, login history, admin activity log |
| Alerts | Email/Slack alert configuration, alert log |
| Reports | Generate & download HTML report, scan history |
| Settings | All plugin settings |
How the score works
A weighted 0–100 score computed across four categories. Within each category, base score starts at 100 and deductions are applied per failing check.
Deduction scale
| Status | Base deduction |
|---|---|
| Critical | 20 pts (or score_impact, whichever is higher). Category floor: 0. |
| Warning | 8 pts (or score_impact, whichever is higher) |
| Info | 0 pts — informational only |
| OK | 0 pts — passing check |
Grade scale
| Grade | Score range |
|---|---|
| A | 90 – 100 |
| B | 80 – 89 |
| C | 70 – 79 |
| D | 60 – 69 |
| F | 0 – 59 |
Fix list & score history
The Top Items to Fix panel ranks actionable items (critical + warning) by severity first, then score_impact descending. Up to 5 items shown with estimated gain if resolved.
Every background scan stores the health score with a timestamp. The Dashboard shows a line chart of the last 30 scans for trend tracking.
All 28+ checks
Environment (15+ checks)
| Check ID | Label | Max deduction |
|---|---|---|
php_version | PHP Version | 10 pts |
wp_version | WordPress Version | 5 pts |
wp_debug | WP Debug Mode | 5 pts |
ssl | HTTPS / SSL | 15 pts |
ssl_expiry | SSL Certificate Expiry | 10 pts |
memory_limit | PHP Memory Limit | 8 pts |
max_exec | Max Execution Time | 3 pts |
rest_api | REST API | 8 pts |
wp_cron | WP-Cron | 0 pts (info) |
admin_email | Admin Email | 4 pts |
mysql_version | MySQL / MariaDB Version | 4 pts |
wpconfig_perms | wp-config.php Permissions | 5 pts |
disk_space | Disk Space | 10 pts |
php_ext_required | Required PHP Extensions | 8 pts |
php_ext_recommended | Recommended PHP Extensions | 0 pts (info) |
multisite | Multisite Detection | 0 pts (info) |
Plugin intelligence
| Check ID | Label | Max deduction |
|---|---|---|
plugin_updates | Plugin Updates Available | 12 pts |
stale_plugins | Stale Plugins (2+ years) | 8 pts |
inactive_plugins | Inactive Plugins | 0 pts (info) |
vulnerabilities | Known Vulnerabilities | 20 pts |
orphaned_tables | Orphaned DB Tables | 0 pts (info) |
Performance checks
| Check ID | Label | Max deduction |
|---|---|---|
ttfb | Server Response Time (TTFB) | 8 pts |
autoload | Autoloaded Options Size | 12 pts |
expired_transients | Expired Transients | 6 pts |
revisions | Post Revisions | 6 pts |
db_size | Total Database Size | 0 pts (info) |
db_overhead | Database Table Overhead | 3 pts |
object_cache | Object Cache | 0 pts (info) |
uploads_size | Uploads Directory Size | 0 pts (info) |
Content checks
| Check ID | Label | Max deduction |
|---|---|---|
no_featured_image | Posts Without Featured Images | 0 pts (info) |
orphaned_media | Orphaned Media | 0 pts (info) |
stale_drafts | Stale Drafts (6+ months) | 0 pts (info) |
no_excerpt | Posts Without Excerpts | 0 pts (info) |
content_count | Published Content | 0 pts (info) |
user_count | Registered Users | 0 pts (info) |
Point-in-time snapshots
Each snapshot captures a full site state diff — WordPress version, PHP, theme, every plugin with version, post/user counts, DB size, memory, health score, and all check results. Stored as compressed JSON in wp_ointel_snapshots.
Taking snapshots
| Method | How |
|---|---|
| Manual | Dashboard → Snapshots tab → Take Snapshot → optionally label it → Save |
| Automatic | Enable Automatic daily snapshots in Settings — runs via WP-Cron |
| WP-CLI | wp ointel snapshot "Before plugin update" |
Diff comparison
Select any two snapshots from the dropdown selectors and click Compare. OIntel performs a field-by-field diff and returns: score delta, changed fields with before/after values, highlighted plugin version changes and active plugin count differences.
Retention
The Keep Last N Snapshots setting (default: 30, max: 100) automatically prunes older snapshots after each new one is taken.
Session intelligence
When Track Sessions is enabled, OIntel hooks into WP's session system to log active sessions, login events, and admin activity.
| Data tracked | Fields stored |
|---|---|
| Active sessions | User ID, session token, IP address, user agent, last activity (shows sessions active in last 30 min) |
| Successful logins | User ID, username, IP, timestamp |
| Failed login attempts | Attempted username, IP, timestamp |
| Admin activity | User ID, action key, object, IP, timestamp — every admin page view and form submission |
Alerts & notifications
Alert conditions
| Condition | Trigger |
|---|---|
| New critical issue | Any scan produces a Critical check result |
| Score drop | Health score drops by ≥ N points (configurable threshold, default 10) |
| SSL expiry | SSL certificate expiring within 30 days |
| Plugin updates | Any plugin has a pending update |
Channels
Email: Sends an HTML email to the configured alert address with a View Dashboard CTA button.
Slack: Enter an Incoming Webhook URL from your Slack app settings. All alert conditions also post to Slack when a webhook is configured.
Weekly report: Enable Weekly Summary Report to receive a full HTML report every Monday at 08:00, including health score, all check results, and the fix list.
Alert log & testing
All sent alerts are recorded in wp_ointel_alert_log with type, channel, recipient, status, and timestamp. Click Send Test Alert on the Alerts tab to verify email/Slack configuration without triggering a real scan.
HTML reports
Fully self-contained, print-ready HTML exports. No external dependencies — works offline.
Report contents
- Site name, URL, and report date
- Health score ring with letter grade (A–F)
- Critical / Warning / Info / OK counts
- Top 5 items to fix with estimated score impact
- Full check results grouped by category
Export: Reports → Export HTML Report → preview in iframe → Download HTML or Print / Save PDF via the browser print dialog.
White-label reports
Enable White-Label Reports in Settings to remove OIntel footer branding. Optionally supply a custom logo URL that appears at the top of exported reports. Designed for agencies delivering monthly health reports to clients.
WP-CLI export
BASHwp ointel report --file=/tmp/site-report.html
Background scanner
OIntel uses WP-Cron to run health scans automatically. Configure the frequency in Settings.
What the scanner does
OIntel_Checks::run_all().OIntel_Health::calculate().wp_ointel_scan_log.Frequency & modes
| Option | Cron key |
|---|---|
| Hourly | ointel_hourly |
| Daily (default) | ointel_daily |
| Weekly | ointel_weekly |
Lightweight Mode skips TTFB measurement and the WPVulnDB API call — recommended for resource-constrained hosting environments.
Manual trigger: Dashboard → Run Scan button calls OIntel_Scanner::run_manual() via AJAX.
REST API endpoints
Base namespace: ointel/v1. All endpoints require manage_options capability unless Allow public REST is enabled in Settings.
GET /wp-json/ointel/v1/health-score
Returns the health score from the most recent scan.
JSON{
"score": 87,
"grade": "B",
"critical": 0,
"warning": 3,
"scanned": "2026-04-25 09:14:00"
}
GET /wp-json/ointel/v1/checks
Returns all check results from the last scan. Filter by ?status=critical|warning|info|ok.
JSON{
"checks": [
{
"id": "ssl",
"category": "Environment",
"label": "HTTPS / SSL",
"status": "ok",
"message": "HTTPS active",
"detail": "Site is served over HTTPS.",
"score_impact": 0
}
],
"total": 28
}
GET /wp-json/ointel/v1/snapshots
Returns snapshot history. Query param: ?limit=10 (max 50).
POST /wp-json/ointel/v1/scan
Triggers a fresh scan. Requires manage_options.
JSON{
"scan_id": 42,
"score": 87,
"critical": 0,
"warning": 3,
"duration": 1240,
"checks": 28
}
WP-CLI commands
All commands are under the wp ointel namespace.
wp ointel scan
Run a full health scan.
BASHwp ointel scan
wp ointel scan --format=json # also supports: table (default), yaml
OUTPUT+----------+--------+
| Field | Value |
+----------+--------+
| Score | 87/100 |
| Critical | 0 |
| Warnings | 3 |
| Checks | 28 |
| Duration | 1240ms |
| Scan ID | 42 |
+----------+--------+
wp ointel snapshot
BASHwp ointel snapshot # no label
wp ointel snapshot "Before plugin update" # with label
wp ointel report
BASHwp ointel report # stdout
wp ointel report --file=/tmp/report.html # write to file
wp ointel snapshots
BASHwp ointel snapshots
wp ointel snapshots --limit=20
Filters & actions
ointel_checks
Add, remove, or modify checks in the health engine.
PHPadd_filter( 'ointel_checks', function( array $checks ): array {
$checks[] = [
'id' => 'my_custom_check',
'category' => 'Environment',
'label' => 'My Custom Check',
'status' => 'ok', // critical | warning | info | ok
'message' => 'Everything looks good.',
'detail' => 'Optional additional detail.',
'score_impact' => 0,
];
return $checks;
} );
ointel_snapshot_data
Add custom data fields to every snapshot.
PHPadd_filter( 'ointel_snapshot_data', function( array $data ): array {
$data['woocommerce_product_count'] = wp_count_posts( 'product' )->publish ?? 0;
return $data;
} );
ointel_alert_conditions
Add custom alert conditions that fire after every scan. The message key is a callable that receives the current checks array and health data.
PHPadd_filter( 'ointel_alert_conditions', function( array $conditions ): array {
$conditions[] = [
'type' => 'my_custom_alert',
'message' => function( array $checks, array $health ): string {
return 'My custom alert triggered. Score: ' . $health['score'];
},
];
return $conditions;
} );
should_fire logic is not called automatically — you must hook into ointel_alert_conditions and handle firing by calling OIntel_Alerts::evaluate() or OIntel_DB::insert_alert() directly.ointel_report_sections
Add custom sections to HTML reports.
PHPadd_filter( 'ointel_report_sections', function( array $sections ): array {
$sections[] = [
'title' => 'WooCommerce Checks',
'checks' => [
[
'label' => 'Products',
'status' => 'ok',
'message' => '142 published products',
'detail' => '',
],
],
];
return $sections;
} );
Database tables
All table names are prefixed with the WordPress table prefix ($wpdb->prefix). Five tables created on activation.
ointel_snapshots
| Column | Type | Description |
|---|---|---|
id | BIGINT UNSIGNED | Primary key |
label | VARCHAR(200) | Human-readable label |
type | VARCHAR(20) | manual or auto |
score | TINYINT UNSIGNED | Health score at snapshot time |
data_json | LONGTEXT | JSON blob of site state data |
issues_json | LONGTEXT | JSON blob of check results |
created_at | DATETIME | Snapshot timestamp |
ointel_scan_log
| Column | Type | Description |
|---|---|---|
id | BIGINT UNSIGNED | Primary key |
started_at | DATETIME | When scan started |
duration_ms | INT UNSIGNED | Scan duration in milliseconds |
score | TINYINT UNSIGNED | Health score |
issues_critical | SMALLINT UNSIGNED | Count of critical issues |
issues_warning | SMALLINT UNSIGNED | Count of warnings |
issues_info | SMALLINT UNSIGNED | Count of info items |
issues_ok | SMALLINT UNSIGNED | Count of passing checks |
results_json | LONGTEXT | Full check results JSON |
triggered_by | VARCHAR(20) | manual, cron, cli, rest |
ointel_alert_log
| Column | Type | Description |
|---|---|---|
id | BIGINT UNSIGNED | Primary key |
type | VARCHAR(50) | Alert type key |
channel | VARCHAR(20) | email or slack |
message | TEXT | Alert message body |
recipients | TEXT | Email address(es) or Slack channel |
status | VARCHAR(20) | sent or failed |
sent_at | DATETIME | When alert was sent |
ointel_sessions & ointel_activity_log
| Table | Key columns |
|---|---|
ointel_sessions | user_id, session_token, ip, user_agent, last_activity, created_at |
ointel_activity_log | user_id, action (e.g. login, login_failed), object, ip, created_at |
Settings reference
All settings stored in wp_options under key ointel_settings.
| Key | Type | Default | Description |
|---|---|---|---|
scan_frequency | string | ointel_daily | Cron schedule: ointel_hourly, ointel_daily, ointel_weekly |
snapshot_keep | int | 30 | Number of snapshots to retain (max 100) |
auto_snapshot | bool | false | Take automatic daily snapshots |
lightweight_mode | bool | false | Skip TTFB and vulnerability checks |
track_sessions | bool | false | Enable session + activity tracking |
adminbar_badge | bool | false | Show critical count badge in admin bar |
alert_email_enabled | bool | false | Enable email alerts |
alert_email | string | admin email | Alert recipient address |
alert_new_critical | bool | false | Alert on new critical issues |
alert_score_drop | bool | false | Alert on score drop |
score_drop_threshold | int | 10 | Minimum drop in points to trigger alert |
alert_ssl | bool | false | Alert on SSL expiry warning |
alert_plugin_updates | bool | false | Alert on available plugin updates |
slack_webhook | string | — | Slack incoming webhook URL |
weekly_report | bool | false | Send weekly HTML report email |
white_label | bool | false | Remove OIntel branding from reports |
white_label_logo | string | — | Custom logo URL for white-label reports |
wpvulndb_api_key | string | — | WPScan API token for vulnerability checks |
rest_public | bool | false | Allow unauthenticated REST access to health-score |
remove_on_uninstall | bool | false | Delete all data on plugin uninstall |
How OIntel stacks up
| Feature | OIntel | Query Monitor | WP Site Health | Google Site Kit |
|---|---|---|---|---|
| Health score (0–100) | ✓ | — | — | — |
| Historical snapshots | ✓ | — | — | — |
| Snapshot diff | ✓ | — | — | — |
| Actionable recommendations | ✓ | — | Limited | — |
| Plugin vulnerability scan | ✓ | — | — | — |
| Email alerts | ✓ | — | — | — |
| Slack alerts | ✓ | — | — | — |
| Exportable HTML/PDF report | ✓ | — | — | — |
| White-label reports | ✓ | — | — | — |
| Session tracking | ✓ | — | — | — |
| REST API | ✓ | — | — | — |
| WP-CLI | ✓ | — | — | — |
| No external account | ✓ | ✓ | ✓ | — |
| Self-hosted | ✓ | ✓ | ✓ | — |
| Developer-friendly hooks | ✓ | ✓ | Limited | — |
Plans & pricing
- Full health dashboard & all check categories
- Environment, plugin, performance & content checks
- Snapshot system (last 5 retained)
- Email alerts (basic)
- HTML report export
- Unlimited snapshots + diff comparison (up to 100)
- White-label reports (agency branding)
- WPVulnDB vulnerability scanning
- Slack alerts
- Scheduled weekly report emails
- Performance deep-dive (DB optimisation suggestions)
- WP-CLI commands
- All Pro features
- Centralised multi-site scanning via REST API
- Agency dashboard (roadmap)
Security model
OIntel is built on a strict read-only principle — it inspects your site, never modifies it.
| # | Principle | How it's enforced |
|---|---|---|
| 1 | No file writes | OIntel never writes to the filesystem outside its own database tables |
| 2 | No code execution | User input is never evaluated or executed |
| 3 | Admin-only | All AJAX actions, REST writes, and admin pages require manage_options |
| 4 | Nonce verification | Every AJAX action verifies a WordPress nonce |
| 5 | Input sanitization | All user input sanitized before storage |
| 6 | Output escaping | All output uses esc_html(), esc_attr(), esc_url() appropriately |
| 7 | External requests | Only TTFB measurement (internal) and optional WPVulnDB API call. All use wp_remote_get() with timeouts |
| 8 | SQL safety | All database queries use $wpdb->prepare() with placeholders |
What's shipped
- Health score dashboard (0–100, 4 categories, 28+ checks)
- Score history chart (last 30 scans)
- Prioritised fix list ranked by score impact
- Environment checks: PHP, WP, SSL, SSL expiry, memory, max_exec, REST API, WP-Cron, admin email, MySQL, file permissions, disk space, PHP extensions, multisite
- Plugin intelligence: updates, stale, vulnerability scan (WPVulnDB), orphaned tables
- Performance checks: TTFB, autoload options, expired transients, revisions, DB table sizes, object cache, uploads size
- Content checks: featured images, orphaned media, stale drafts, excerpts, content counts, user counts
- Snapshot system: manual + auto, 30-snapshot history, field-by-field diff comparison
- Session intelligence: active sessions, login tracking, admin activity log
- Email alerts: critical issues, score drop, SSL expiry, plugin updates
- Slack webhook alerts
- Admin bar badge (critical count)
- HTML report export with white-label option
- Weekly scheduled report email
- Background scan scheduler (hourly/daily/weekly, lightweight mode)
- REST API: health-score, checks, snapshots, scan endpoints
- WP-CLI:
scan,snapshot,report,snapshotscommands - Developer filters:
ointel_checks,ointel_snapshot_data,ointel_alert_conditions,ointel_report_sections - Clean install/uninstall hooks with optional data removal
- Full rebrand from
fsi_/FSI_toointel_/OINTEL_ - Orravo design system UI (dark/light, top-nav, scoped CSS tokens)
Got a question about OIntel?
Reach out directly — Kenneth replies within 24 hours.
