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.

What to do next

  • The data the hooks carry, over HTTP: REST API.
  • The codes already in use: Events.
  • Add a check of your own to: Health.

Quick Links