Contents
Hooks reference - Plugixa Activity Log
Every hook is prefixed plugixa_activity_log_. Add listeners from a small plugin
of your own, or from your theme’s functions.php.
Two rules hold for all of them. No hook lets you edit or delete a stored event: the log is append-only, and the hooks act before a row is written or after it is read. And nothing here needs the plugin to be active: an action nobody listens to does nothing, so code that records an event keeps working when Activity Log is switched off.
Write path
How an event gets from “something happened” to a row. In order: the code is checked, the row is built, the veto runs, the message is written, the details are adjusted and redacted, the row is adjusted, and everything is stored in one batch at the end of the request.
Record an event of your own
do_action( 'plugixa_activity_log_record', 880001, array(
'object_id' => $order_id, // reserved: becomes a column
'object_label' => $order_title, // reserved: becomes a column
'status' => 'shipped', // everything else is stored as details
) );
| Action | Arguments |
|---|---|
plugixa_activity_log_record |
int $code, array $context |
An unknown or switched-off code is a silent no-op. Register the code first, with the filter below, or nothing is recorded.
Values under keys that look like credentials (password, token, secret,
api_key and similar) are replaced with [redacted] before anything is stored.
Long strings are cut and deep arrays are trimmed, so one entry cannot become
enormous.
Register event definitions
use PlugixaActivityLog\Core\Events\EventDefinition;
use PlugixaActivityLog\Core\Events\Severity;
add_filter( 'plugixa_activity_log_event_definitions', function ( array $definitions ) {
$definitions[880001] = new EventDefinition(
880001, // stable code, never reused
'Orders', // section label
Severity::Medium, // Informational, Low, Medium, High, Critical
'order', // object type
'shipped', // action (the verb)
'Order {object} was marked {status} by {user}.',
true, // recorded by default
'my-plugin', // module id
'my-plugin', // group key
'My plugin' // group label
);
return $definitions;
} );
| Filter | Arguments | Return |
|---|---|---|
plugixa_activity_log_event_definitions |
array $definitions (code => EventDefinition) |
The same map |
Placeholders are {name}, filled from the context, plus three reserved ones:
{user}, {ip} and {object}. The sentence is written once, when the event
is stored, so improving a template later does not rewrite history. A code that
is already taken is ignored. Pick codes well away from the plugin’s own, which
all sit below 10000.
Veto an event
add_filter( 'plugixa_activity_log_should_record', function ( $record, $row, $context, $definition, $actor ) {
if ( 2002 === $definition->code && 'revision_test' === ( $context['post_type'] ?? '' ) ) {
return false;
}
return $record;
}, 10, 5 );
| Filter | Arguments | Return |
|---|---|---|
plugixa_activity_log_should_record |
bool $record, array $row, array $context, EventDefinition $definition, Actor $actor |
false drops the event |
This is where Exclusions
apply. $row holds the columns (user_id, user_role, ip, object_id and
so on) without message or details yet. $actor has user_id, login, role,
roles, ip, user_agent and source (web, ajax, rest, cron or
cli). The built-in exclusions leave events 9000 and above alone; a listener of
your own should too.
Adjust what is stored
| Filter | Arguments | For |
|---|---|---|
plugixa_activity_log_event_context |
array $context, array $row, EventDefinition $definition, Actor $actor |
Adding to or removing from the details. Runs after the message is written, so it cannot change the sentence |
plugixa_activity_log_event_row |
array $row, EventDefinition $definition, Actor $actor |
Changing a column just before storage. Keys may be changed, never added or removed |
add_filter( 'plugixa_activity_log_event_context', function ( $context, $row ) {
$context['environment'] = wp_get_environment_type();
return $context;
}, 10, 2 );
Both also run on events brought in by the
importer. The
Privacy settings use
event_row to shorten the IP address.
Before and after the write
| Action | Arguments | Fires |
|---|---|---|
plugixa_activity_log_before_flush |
none | Just before buffered events are written. Anything recorded here joins the batch |
plugixa_activity_log_events_written |
array $rows |
After a batch has been stored |
add_action( 'plugixa_activity_log_events_written', function ( array $rows ) {
foreach ( $rows as $row ) {
if ( (int) $row['severity'] >= 3 ) {
my_queue_push( $row['event_code'], $row['message'] );
}
}
} );
Do not do slow work in events_written. It runs at the end of the request
that recorded the events, often a visitor’s page view. Queue the work and
return. Rows carry every column except id. severity is a number from 0
(informational) to 4 (critical). Imported and resequenced events do not fire it.
Monitors and modules
| Filter | Arguments | For |
|---|---|---|
plugixa_activity_log_monitor_available |
bool $available, string $id |
Overriding whether a monitor’s target plugin is detected as present |
plugixa_activity_log_modules |
string[] $classes |
Contributing a whole module, a class implementing ModuleInterface |
Notifications
| Filter | Arguments | For |
|---|---|---|
plugixa_activity_log_notification_targets |
array $targets, array $row |
Adding deliveries for one stored event. Each is { channel, target, meta, delay }, with delay in minutes |
plugixa_activity_log_notification_channels |
array $channels |
Registering a channel: type => callable( array $delivery ): true|WP_Error, where $delivery has target, events and meta |
add_filter( 'plugixa_activity_log_notification_targets', function ( array $targets, array $row ) {
if ( 1006 === (int) $row['event_code'] ) {
$targets[] = array( 'channel' => 'email', 'target' => 'security@example.com', 'meta' => array(), 'delay' => 0 );
}
return $targets;
}, 10, 2 );
Deliveries are queued and sent by WP-Cron, never on the recording request.
meta is stored with the queued delivery, so never put a secret in it. Events
9000 and above never reach these filters. See
Notifications.
Read path
What is sent to the admin app and the REST API.
| Filter | Arguments | For |
|---|---|---|
plugixa_activity_log_event_item |
array $item, array $row |
Adding to what a client receives for one event, in the list and in the inspector |
plugixa_activity_log_object_url |
string $url, string $type, int $id |
Changing the link shown for an event’s object |
plugixa_activity_log_health_checks |
array $checks, array $report |
Adding items to the Health screen’s checks |
plugixa_activity_log_bootstrap_payload |
array $payload |
Adding datasets to the app’s start-up payload |
plugixa_activity_log_admin_config |
array $config |
Adding a fact to the configuration printed for the admin app |
plugixa_activity_log_admin_i18n_strings |
array $strings |
Adding or changing strings the admin app shows |
add_filter( 'plugixa_activity_log_object_url', function ( $url, $type, $id ) {
return 'order' === $type ? admin_url( 'admin.php?page=my-orders&order=' . $id ) : $url;
}, 10, 3 );
event_item runs once per row, so a listener that needs a lookup should batch
it or cache it. admin_config is printed into the page, so keep secrets out of
it.
A health check is an array with id (a unique slug), label, status (good,
warning or critical), value (a short figure) and hint (one sentence).
An item without an id or a label is dropped. See
Health.
add_filter( 'plugixa_activity_log_health_checks', function ( array $checks, array $report ) {
$checks[] = array(
'id' => 'my_queue',
'label' => 'My queue',
'status' => 'warning',
'value' => '12 waiting',
'hint' => 'The export queue has not drained for an hour.',
);
return $checks;
}, 10, 2 );
Settings and access
A setting belongs to the code that reads it. To own one, claim it in both of the first two filters: a key that neither claims is discarded from a save.
| Filter | Arguments | For |
|---|---|---|
plugixa_activity_log_settings_defaults |
array $defaults |
Declaring a setting and its default |
plugixa_activity_log_sanitize_settings |
array $clean, array $input |
Cleaning your setting from the raw payload |
plugixa_activity_log_settings_choices |
array $choices |
Supplying the options a settings control offers |
plugixa_activity_log_config_settings_keys |
string[] $keys |
Which settings are printed for the app before its first paint |
plugixa_activity_log_capabilities |
array $map |
Adding to the permission map handed to the admin app |
plugixa_activity_log_manage_capabilities |
string[] $capabilities |
Capabilities that are enough, on their own, to open the app |
| Action | Arguments | Fires |
|---|---|---|
plugixa_activity_log_settings_saved |
array $settings, array $before |
After the settings are saved, from the screen, the REST API or WP-CLI |
add_filter( 'plugixa_activity_log_settings_defaults', fn ( array $defaults ) => $defaults + array( 'my_threshold' => 10 ) );
add_filter( 'plugixa_activity_log_sanitize_settings', function ( array $clean, array $input ) {
$clean['my_threshold'] = max( 1, min( 100, (int) ( $input['my_threshold'] ?? 10 ) ) );
return $clean;
}, 10, 2 );
add_action( 'plugixa_activity_log_settings_saved', function ( array $settings, array $before ) {
if ( $settings['retention_days'] !== $before['retention_days'] ) {
my_notify_compliance( $before['retention_days'], $settings['retention_days'] );
}
}, 10, 2 );
The capability map only hides controls in the app. It enforces nothing: every route asks again on the server. See Access.
Lifecycle
| Action | Arguments | Fires |
|---|---|---|
plugixa_activity_log_fs_loaded |
none | The licensing SDK has loaded, before the plugin boots |
plugixa_activity_log_loaded |
Container $container |
The plugin has fully booted |
plugixa_activity_log_register_rest_routes |
string $namespace, Container $container |
When REST routes are registered, so your own can join the namespace |
plugixa_activity_log_admin_submenus |
string $parent_slug, callable $render |
When the admin menu is built, so you can add a submenu |
plugixa_activity_log_enqueue_assets |
string $hook_suffix |
On the plugin’s own screen, once the app bundle is enqueued |
plugixa_activity_log_activated |
none | On activation, after the tables exist |
plugixa_activity_log_deactivated |
none | On deactivation. Clear your scheduled jobs here |
plugixa_activity_log_uninstall |
none | While uninstall is erasing data, before the tables are dropped |
add_action( 'plugixa_activity_log_uninstall', function () {
delete_option( 'my_addon_state' );
} );
uninstall fires only when data is being erased. Deleting the plugin keeps
the log by default, and then this action does not fire at all. See the Uninstall
section of Settings.
Pro filters PRO
These exist only with Plugixa Activity Log Pro.
| Filter | Arguments | For |
|---|---|---|
plugixa_activity_log_file_scan_roots PRO |
array $roots (core, plugins, themes, uploads => absolute path) |
The folders the file scan reads |
plugixa_activity_log_file_scan_skip_extensions PRO |
string[] $extensions (lower case, no dot) |
File extensions a plugin or theme scan does not read |
plugixa_activity_log_woocommerce_gateways PRO |
array $list (gateway id => name) |
The payment methods the WooCommerce monitor recognises |
plugixa_activity_log_mirror_directory PRO |
string $dir (absolute path, no trailing slash) |
The folder a file mirror writes to. It runs after the PLUGIXA_ACTIVITY_LOG_MIRROR_DIR constant, so a filter has the last word |
The Pro alert rules and mirrors plug into the free hooks above
(notification_targets, notification_channels and events_written). They
have no private entry point of their own.
Troubleshooting
| Symptom | Usual cause |
|---|---|
do_action( 'plugixa_activity_log_record', ... ) records nothing |
The code is not registered, or the event is switched off on the Events screen. |
| A custom definition does not appear | Its code is already taken, or the filter was added after the catalogue was first read. Add it as your plugin loads. |
A key added in event_row is not stored |
Keys may be changed there, not added. Use event_context for new details. |
A value shows as [redacted] |
Its key looks like a credential. Rename the key if it is not one. |
| A custom setting is not saved | It is not claimed in both settings_defaults and sanitize_settings. |
uninstall never ran |
Deleting the plugin kept the data, which is the default. |
events_written slowed the site down |
It runs on the recording request. Queue the work. |