Audit Log
There are two logs, and they answer different questions.
| Log | Lives in | Read by | Survives a compromised admin |
|---|---|---|---|
instance-audit-log | PHP error log or syslog | Whoever collects your logs | ✅ |
| Simple History | The WordPress database | Administrators, in the admin | ❌ |
Simple History is the convenient one — searchable, in the admin, next to the work. The audit log is the one that still exists after somebody with database access tidies up behind themselves.
Audit Log
Section titled “Audit Log”instance-audit-log writes one JSON line per event:
{"type":"wp_audit","event":"user_role_changed","time":"2026-08-27T09:14:22+00:00","site":"example.com","user_id":1,"user_login":"joren","ip":"203.0.113.10","forwarded_for":null,"request_uri":"/wp/wp-admin/user-edit.php","context":{"target_user_id":7,"new_role":"administrator","old_roles":["editor"]}}What Is Recorded
Section titled “What Is Recorded”| Area | Events |
|---|---|
| Authentication | login, login_failed, logout, password_reset_requested, password_reset_completed |
| Accounts | user_created, user_deleted, user_role_changed, user_updated |
| Code and config | plugin_activated, plugin_deactivated, theme_switched, option_updated |
| Content and media | post_status_changed, post_deleted, attachment_added, attachment_deleted |
| Bulk export | export_started |
| Lockouts | login_lockout, login_lockout_address, login_lockout_released |
option_updated covers a short watch list rather than every option — logging all of them is unreadable.
The list is the ones that change who can get in or where the site points: siteurl, home, admin_email, users_can_register, default_role, template, stylesheet, blog_public.
add_filter('instance_audit_log_watched_options', function (array $options): array { $options[] = 'woocommerce_store_address';
return $options;});Transport
Section titled “Transport”Lines go to the PHP error log by default, which is what most hosting collects. Switch to the system logger when the host ships to journald or rsyslog:
Config::define('INSTANCE_AUDIT_LOG_TRANSPORT', 'syslog');Logging Your Own Events
Section titled “Logging Your Own Events”if (function_exists('instance_audit_log')) { instance_audit_log('invoice_exported', [ 'invoice_id' => $invoice->ID, 'format' => 'pdf', ]);}Addresses
Section titled “Addresses”Each line carries two: ip is REMOTE_ADDR, the only address the application can trust, and forwarded_for is the raw X-Forwarded-For header, recorded as a hint because the client controls it.
Simple History
Section titled “Simple History”instance-simple-history-config sets defaults for the plugin and is inert when it is not installed.
| Default | Value | Why |
|---|---|---|
| Retention | 90 days | Entries hold usernames and IP addresses, which are personal data |
| View history capability | manage_options | Reading the log is an administrator task, not an editor one |
| View settings capability | manage_options | As above |
| Dashboard widget | Off | The log has its own admin page |
add_filter('instance_simple_history_retention_days', function (): int { return 30;});
