Contents
WP-CLI - Plugixa Activity Log
One command, wp activity-log, that reads the log and manages it from a
terminal. It is part of the free plugin.
wp activity-log list --min_severity=high --per-page=20
wp activity-log tail --group=authentication
wp activity-log disable 1000 1001
wp activity-log prune --dry-run
wp activity-log import wsal --dry-run
Three things to know first
Times are UTC. The log stores every event in UTC and the terminal prints
them as stored, whatever the site’s time zone is. The admin screens convert to
local time; the CLI does not. The one exception runs the other way: --date_from
and --date_to are read in the site’s time zone, exactly as the screen’s date
filter is.
Every change made from the CLI is logged, with source “cli”. Switching an
event off, switching a monitor, changing a setting and pruning all go through
the same code the admin screens use, so they are checked the same way and leave
the same entry in the log. The entry’s details carry source: cli, and it has
no IP address, because a terminal has none. It has no user either, unless you
run the command with WP-CLI’s own --user= flag.
The CLI sees the whole network. On multisite, somebody with a shell can read
the database anyway, so the command is not confined to one site. Narrow it on
purpose with --site_id=<id>.
The subcommands
| Subcommand | Does |
|---|---|
list |
List events, newest first |
get <id> |
Show one event in full |
tail |
Print new events as they happen |
stats |
Totals for a period |
events |
The event catalogue, and whether each event is recorded |
enable <code>... |
Start recording events |
disable <code>... |
Stop recording events |
monitors |
List the monitors and whether each runs |
monitor <id> |
Switch a monitor on or off |
prune |
Apply the retention settings now |
settings get |
Read one setting, or all of them |
settings set |
Change one setting |
import wsal |
Import history from WP Activity Log |
list
List events, newest first.
wp activity-log list
wp activity-log list --min_severity=high --per-page=20
wp activity-log list --user_login=alex --date_from=2026-10-01 --format=csv
wp activity-log list --search="plugin activated" --fields=id,time,message
| Flag | Does |
|---|---|
--per-page=<n> |
How many. Default 50, at most 200 |
--before-id=<id> |
Only events older than this id: the next page |
--format=<format> |
table (default), json, csv, yaml, ids or count |
--fields=<fields> |
Comma-separated columns. Default id,time,severity,code,user,ip,message |
--<filter>=<value> |
Any filter below |
The filters are the same ones the REST API accepts, with the same names:
| Filter | Matches |
|---|---|
--severity |
Exact severities, comma separated: informational, low, medium, high, critical |
--min_severity |
At least this severe |
--event_code |
Event codes, comma separated |
--group, --module |
An event group such as authentication, or the module that owns the events |
--user_id, --user_login, --user_role |
Who acted. --user_login also matches the name typed at a failed sign-in |
--ip |
An exact address |
--object_type, --object_id, --action |
What it was about, and the verb |
--search |
Free text over the message, the item and the user |
--date_from, --date_to |
Y-m-d or ISO 8601, read in the site’s time zone |
--site_id |
One site of a network |
Note the spelling. The paging flags use hyphens (--per-page, --before-id)
and the filters use underscores (--min_severity, --user_login).
A filter value the plugin does not understand is ignored, not an error, so check the result if a filter seems to have done nothing.
To page through a large log, pass the last id you saw:
wp activity-log list --per-page=200 --format=ids
wp activity-log list --per-page=200 --before-id=48211
get
Show one event in full, including everything that was captured.
wp activity-log get 48211
wp activity-log get 48211 --format=yaml
| Flag | Does |
|---|---|
--format=<format> |
json (default) or yaml |
An id that does not exist is an error: Event 48211 does not exist.
tail
Print new events as they happen, until you press Ctrl-C.
wp activity-log tail
wp activity-log tail --group=authentication
wp activity-log tail --min_severity=high --interval=5
| Flag | Does |
|---|---|
--interval=<seconds> |
How often to look. Default 2, at least 1 |
--<filter>=<value> |
Any filter list accepts |
It starts from the newest event that matches and prints only what arrives afterwards, oldest first, one line each: id, time, severity, code, user, address and message.
stats
Totals for a period.
wp activity-log stats
wp activity-log stats --days=7
wp activity-log stats --days=90 --format=json
| Flag | Does |
|---|---|
--days=<days> |
The window. Default 30, at most 365 |
--format=<format> |
table (default) or json |
The table prints the totals. --format=json returns everything the
Dashboard draws: totals, events
per day, counts by severity, the most active users and addresses, and the recent
high-severity events.
events
The event catalogue: every event the plugin can record, and whether it is on.
wp activity-log events
wp activity-log events --format=csv > events.csv
| Flag | Does |
|---|---|
--format=<format> |
table (default), json, csv or yaml |
The columns are code, group, severity, enabled, default and message.
default shows whether the event is on out of the box, so a row where enabled
and default disagree is one somebody changed.
enable and disable
Start or stop recording one or more events, by code.
wp activity-log disable 1000 1001
wp activity-log enable 1000
Both take one or more event codes and no flags.
Disabling stops new entries only. What is already in the log is kept.
An unknown code is an error, and nothing is changed when one is: fix the list and run it again. The change is recorded as event 9000, Activity Log settings were changed.
monitors and monitor
monitors lists the monitors and whether each runs.
wp activity-log monitors
wp activity-log monitors --format=json
| Flag | Does |
|---|---|
--format=<format> |
table (default), json, csv or yaml |
The columns are id, label, enabled and core. A core monitor cannot be
switched off.
monitor switches one, by the id from that list.
wp activity-log monitor php_errors --enable
wp activity-log monitor not_found --disable
| Flag | Does |
|---|---|
--enable |
Switch it on |
--disable |
Switch it off |
Pass exactly one of the two. Neither, or both, is an error.
Switching a monitor off also cancels its scheduled jobs. The change is recorded as event 9002. See Monitors.
prune
Apply the retention settings now, instead of waiting for the daily job.
wp activity-log prune --dry-run
wp activity-log prune
| Flag | Does |
|---|---|
--dry-run |
Only say how many events would be removed |
Run the dry run before shortening the retention period on a log you care about. It counts and writes nothing.
A real prune that removes anything is recorded as event 9001. See Retention.
settings get and settings set
Read or change a setting.
wp activity-log settings get
wp activity-log settings get retention_days
wp activity-log settings set retention_days 30
wp activity-log settings set view_roles '["editor"]'
wp activity-log settings set notify_enabled true
| Form | Does |
|---|---|
settings get |
Print every setting, as JSON |
settings get <key> |
Print one setting |
settings set <key> <value> |
Change one setting |
A value that parses as JSON is used as JSON. That is how lists and switches
are set: '["editor"]', true, 30. Anything else is a plain string. Quote a
list so the shell does not interpret the brackets.
An unknown key is an error, and the message lists the keys that exist. A typo in a terminal deserves to be told, not silently dropped.
The value goes through the same checks as the Settings screen, so what is
stored may differ from what you typed. settings set records_per_page 5000
stores 200, the maximum, and the command prints the value as stored:
Success: records_per_page = 200
The setting names are keys such as retention_days, retention_max_rows,
view_roles, excluded_ips, privacy_ip_mode and trusted_proxy_header.
settings get with no key is the complete list for your build, and every key
is listed with its default in the
Developer reference.
What each one does is on the
Settings page.
import
Import the history of another activity log plugin. The only source is wsal,
WP Activity Log.
wp activity-log import wsal --dry-run
wp activity-log import wsal --from=2025-01-01
wp activity-log import wsal --skip-unmapped
| Flag | Does |
|---|---|
--dry-run |
Only count what would be imported |
--from=<date> |
Only events from this day on (YYYY-MM-DD) |
--skip-unmapped |
Leave out events this plugin has no equivalent for, instead of keeping them as generic imported events |
Without --dry-run the command does the whole import itself, in the terminal,
and does not hand it to the background job. Imported events keep their original
dates and send no notifications, the import resumes where it stopped, and it
never imports an event twice. See
Importing from WP Activity Log.
Where to run it
cd /path/to/wordpress
wp activity-log list
On a multisite, add --url= for the site the plugin is active on. A command
that fails prints the reason and exits with code 1, so it can be used in a
script:
wp activity-log list --min_severity=critical --date_from=$(date +%F) --format=count
Troubleshooting
| Symptom | Usual cause |
|---|---|
| “‘activity-log’ is not a registered wp command” | The plugin is not active on the site WP-CLI is pointed at, or --url= is missing on multisite. |
| Times are hours away from what the screen shows | The CLI prints UTC. The screen converts to local time. |
--per_page or --min-severity did nothing |
Paging flags use hyphens, filters use underscores. |
| A filter seems to be ignored | Its value was not understood, and an unknown value is dropped. |
| “Pass exactly one of –enable or –disable.” | monitor needs one of the two flags. |
| “That monitor cannot be switched off.” | It is a core monitor. |
“Event … does not exist.” from disable |
One code is unknown, and nothing was changed. |
| A setting was stored with a different value | It was pulled into its allowed range, or an invalid entry was dropped. |
prune removed fewer events than the dry run said |
One run works within a time budget and books a follow-up. Run it again. |