How can we help?

Search for answers or browse our knowledge base.

Table of Contents

Create your own custom WordPress activity log extension

Keep a record of any WordPress change you want in the activity log

WP Activity Log offers very comprehensive logging capabilities. It is able to keep a log of a wide variety of user and system activities, including activities in certain 3rd party plugins. In certain cases, however, users may want to include additional activities in the log that are not supported by WP Activity Log out of the box.


If you would like to track additional activities, you can do so by building your own custom WordPress activity log extension. This article explains how.

How do WP Activity Log sensors work?

For every set of changes, WP Activity Log has a sensor (what are the activity log sensors?). For example, to monitor all the login and logouts on WordPress, the plugin has a sensor called LogInOut.php.

All sensor files can be found in the following plugin directory:  /wp-security-audit-log/classes/sensors/.

The activity log events

If you are not familiar with events, first read the document What are WordPress activity log events. If you wish to study how our sensors work, all the Events that the plugin uses are declared in the file defaults.php, which can be found in the root directory of our plugin (/wp-content/plugins/wp-security-audit-log).

Refer to the complete list of WordPress activity log event IDs for more information about every event ID.

Using our example activity log extension plugin as a base, custom events should be placed in the file  wsal-extension-example/wp-security-audit-log/sensors/class-my-custom-sensor.php (link to the file on Github). Here you will find a base class laid out for your, ready for creating your own events, but before proceeding there are some basics to cover, which we outline below.

What event IDs should you use?

When choosing event IDs for your events, it’s important to choose a unique event ID that we will never use, to ensure you don’t experience conflicts. We suggest you use event IDs starting at 1000000 (one million) – we do not plan of using more than 1,000,000 event IDs, so it is safe to use such event IDs.

Read the rest of this post for more detailed explanation of how to build your sensor.

Failure to choose a unique code will result in an error notice being shown so do take care before proceeding further.

Important: get in touch with our support team to discuss the event IDs so we can reserve them for you.

WP Activity Log sensors documentation and sample code

Creating your code

The code in the sample sensor wsal-extension-example/wp-security-audit-log/sensors/class-my-custom-sensor.php (link to the file on Github) is fully documented  but just in case here is also a quick introduction.

First, at the top of you’re new class, you will need to declare the correct namespace as well as include the Alert Manager class provided by WP Activity Log.

namespace WSAL\Plugin_Sensors;
use WSAL\Controllers\Alert_Manager;
From there simply create your fresh class, being careful to check for conflicts when doing so with the use of ‘class_exists’
if ( ! class_exists( '\WSAL\Plugin_Sensors\My_Custom_Sensor' ) ) {
	/**
	 * Custom Sensors for PLUGINNAME plugin.
	 *
	 * Class file for alert manager.
	 *
	 * @since   1.0.0
	 * @package wsal
	 * @subpackage wsal-PLUGINNAME
	 */
	class My_Custom_Sensor {
		/**
		 * Listening to events using hooks.
		 * Here you can code your own custom sensors for triggering your custom events.
		 */
		public static function init() {
			// Begin adding your own custom hook and functions here.
		}
	}
}

Now you have the basis ready, the next and last part is where you should have the actual sensor code, i.e. the code that specifies how the event is fired. This is where you should also specify the details about the event that is created in the WordPress activity log, including the severity, code, ID, text,m and any other variables that you want to use in the text.

An example of what this could look like is the following, taken from our very own Tablepress sensor:

if ( ! class_exists( '\WSAL\Plugin_Sensors\My_Custom_Sensor' ) ) {
    /**
     * Custom Sensors for PLUGINNAME plugin.
     *
     * Class file for alert manager.
     *
     * @since   1.0.0
     * @package wsal
     * @subpackage wsal-PLUGINNAME
     */
    class My_Custom_Sensor {
        /**
         * Listening to events using hooks.
         * Here you can code your own custom sensors for triggering your custom events.
         */
        public static function init() {
            add_action( 'tablepress_event_added_table', [ $this, 'event_table_added' ] );
        }
        /**
        * Report new Tables being created.
        *
        * Collect old post data before post update event.
        *
        * @since 1.0.0
        *
        * @param int $table_id - Table ID.
        */
        public function event_table_added( $table_id ) {
            $editor_link = esc_url(
                add_query_arg(
                    array(
                        'table_id' => $table_id,
                        'action'   => 'edit',
                    ),
                    admin_url( 'admin.php?page=tablepress' )
                )
            );      
            $event_id = ( isset( $_POST['action'] ) && 'tablepress_import' == $_POST['action'] ) ? 1234 : 4321;
            $variables = array(
                'table_name' => sanitize_text_field( get_the_title( $this->imported_table_id ) ),
                'table_id'   => $table_id,
                'columns'    => ( isset( $_POST[ 'table' ] ) ) ? intval( $_POST[ 'table' ][ 'columns' ] ) : 0,
                'rows'       => ( isset( $_POST[ 'table' ] ) ) ? intval( $_POST[ 'table' ][ 'rows' ] ) : 0,
                'EditorLink' => $editor_link,
            );
            $this->plugin->alerts->Trigger( $event_id, $variables );
            return;
        }   
    }
}

In the above, we can see the function event_table_added is being triggered from the tablepress_event_added_table action and recording the event accordingly.

This can of course be any function running on any trigger you wish, you have total control.

Save and name your sensor file

Once you are ready with the code save the sensor file in your custom plugin’s directory. In keeping with WordPress coding standard, the file name for your sensor should be in line with the class name.

So if your class is called My_Awesome_Event, the sensor should be saved under /sensors/class-my-awesome-event.php.

Declaring the events in WP Activity Log

Once you create your sensor file to trigger your unique Event ID, you now need to declare what this ID means in terms of an alert. To do this head to the custom-alerts file located in /wsal-extension-example/wp-security-audit-log/class-my-custom-alerts.php (link to the file on Github).

Below is the sample code which adds 1 event, however you can add as many via this array as you wish:

public static function get_custom_alerts(): array {
			return array(
				esc_html__( 'PLUGINNAME', 'wp-security-audit-log' ) => array(
					esc_html__( 'PLUGINNAME Content', 'wp-security-audit-log' ) => array(
						array(
							1234,
							WSAL_LOW,
							esc_html__( 'Test event X', 'wp-security-audit-log' ),
							esc_html__( 'This is a test event', 'wp-security-audit-log' ),
							'wpforms',
							'created',
						),
					),
				),
			);
		}
public static function get_custom_alerts(): array {
    return array(
        esc_html__( 'PLUGINNAME', 'wp-security-audit-log' ) => array(
            esc_html__( 'PLUGINNAME Content', 'wp-security-audit-log' ) => array(
                array(
                    1234,
                    WSAL_LOW,
                    esc_html__( 'Test event X', 'wp-security-audit-log' ),
                    esc_html__( 'This is a test event', 'wp-security-audit-log' ),
                    'wpforms',
                    'created',
                ),
            ),
        ),
    );
}

Once the custom events have been declared and the code is ready, navigate to the Enable/Disable Alerts node. You should be able to see your custom events in the Third Party Support tab, as seen in the below screenshot.

Custom alerts in WP Activity Log

That’s it! Should you run into any issues, kindly get in touch with our team by opening a support ticket.

Updating existing custom sensors to work with WP Activity Log 4.5+

In WP Activity Log update 4.5 we refactored the plugin’s core to a more efficient and faster model. With this update, we had to change the way custom activity log sensors work and interact with the plugin. As such, custom sensors developed for versions earlier than WP Activity Log 4.5 need to be updated. This section highlights the changes required.

Directory changes

Previously, custom sensors were placed inside the wp-security-audit-log/custom-sensors directory. These have now been moved to wp-security-audit-log/sensors.

Declaring custom events

In older versions, custom events were stored in the file wp-security-audit-log/custom-alerts.php, and contained a simple array. Here is an example:

/**
* Our list of events.
*
* @package WSAL
*/

$custom_alerts = array(
   esc_html__( 'Custom Event', 'wsal-wpforms' ) => array(
       esc_html__( 'Form Content', 'wsal-wpforms' ) => array(

           array(
               5500,
               WSAL_LOW,
               esc_html__( 'A form was created, modified or deleted', 'wsal-wpforms' ),
               esc_html__( 'The Form called %PostTitle%.', 'wsal-wpforms' ),
               array(
                   esc_html__( 'Form ID', 'wsal-wpforms' ) => '%PostID%',
               ),
               array(
                   esc_html__( 'View form in the editor', 'wsal-wpforms' ) => '%EditorLinkForm%',
               ),
               'wpforms_forms',
               'created',
           ),

From WP Activity Log version 4.5 onwards, custom sensors are loaded by a class. This class must reside in the wp-security-audit-log/ directory, for example, wp-security-audit-log/class-my-custom-alerts.php. This class must use the provided WSAL\Custom_Alerts class and returns your array of custom alerts via the get_custom_alerts() function.

Here is an example of what this looks like now:

<?php
/**
* Custom Alerts.
*
* Class file for alert manager.
*
* @since   1.0.0
*
* @package wsal
*/

declare(strict_types=1);

namespace WSAL\Custom_Alerts;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
   exit;
}

if ( ! class_exists( '\WSAL\Custom_Alerts\My_Custom_Alerts' ) ) {

   class My_Custom_Alerts {

       /**
        * Returns the structure of the alerts for extension.
        *
        * @return array
        *
        * @since latest
        */
       public static function get_custom_alerts(): array {
           return array(
               esc_html__( 'WPForms', 'wsal-wpforms' ) => array(
                   esc_html__( 'Form Content', 'wsal-wpforms' ) => array(

                       array(
                           5500,
                           WSAL_LOW,
                           esc_html__( 'A form was created, modified or deleted', 'wsal-wpforms' ),
                           esc_html__( 'The Form called %PostTitle%.', 'wsal-wpforms' ),
                           array(
                               esc_html__( 'Form ID', 'wsal-wpforms' ) => '%PostID%',
                           ),
                           array(
                               esc_html__( 'View form in the editor', 'wsal-wpforms' ) => '%EditorLinkForm%',
                           ),
                           'wpforms_forms',
                           'created',
                       ),

Sensor file changes

In previous iterations of our custom sensors, the sensor itself relied on extending a core WP Activity Log class called WSAL_AbstractSensor. This gave the sensor access to our event-triggering functions. However, this is no longer the case. 

For reference and comparison, here is an example of what the sensor previously looked like:

<?php

/**
* Custom Sensors.
*
* Class file for alert manager.
*
* @since   1.0.0
* @package Wsal
*/

/**
* Custom sensor class to process WPForms events.
*
* @since 1.0.0
*/
class WSAL_Sensors_CustomSensor extends WSAL_AbstractSensor {

   /**
    * Hook events related to sensor.
    *
    * @since 1.0.0
    */
   public function HookEvents() {
       // add_actions here
   }

   // etc

In the old sensor class, we would add our actions to the specific HookEvents function. However, from version 4.5 onwards, custom sensors must use the namespace WSAL\Plugin_Sensors and Alert_Manager classes provided by WP Activity Log. Custom sensors must also be coded in line with the WordPress Coding Standards.

Here is what a sensor file should look like now:

<?php
/**
* Custom Sensor
*
* Class file for alert manager.
*
* @since   1.0.0
* @package Wsal
*/

declare(strict_types=1);

namespace WSAL\Plugin_Sensors;
use WSAL\Controllers\Alert_Manager;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

if ( ! class_exists( '\WSAL\Plugin_Sensors\My_Custom_Sensor' ) ) {
    /**
     * Custom sensor class
     *
     * @since 1.0.0
     */
    class My_Custom_Sensor {
        /**
         * Hook events related to sensor.
         *
         * @since 1.0.0
         */
        public static function init() {
          // add_actions here
        }

      // etc

Event triggering changes

From 4.5 onwards, events are triggered by the Alert_Manager class, as shown to be required in the above point. To make a simple comparison, this is what triggering an event looked like pre-WP Activity Log 4.5:

$this->plugin->alerts->trigger_event_if( $alert_code, $variables, $condition );

This is what it should look like in versions 4.5 onwards:

Alert_Manager::trigger_event_if( $alert_code, $variables, $condition );

IMPORTANT: Including your new sensor/alert files

Once you have prepared all of the above, the final step is to require your new files. This is done by adding the following to your extensions main plugin file:

add_action(
   'wsal_sensors_manager_add',
   /**
   * Adds sensors classes to the Class Helper
   *
   * @return void
   *
   * @since latest
   */
   function () {
       require_once __DIR__ . '/wp-security-audit-log/sensors/class-my-custom-sensor.php';

       Classes_Helper::add_to_class_map(
           array(
               'WSAL\\Plugin_Sensors\\My_Custom_Sensor' => __DIR__ . '/wp-security-audit-log/sensors/class-my-custom-sensor.php',
           )
       );
   }
);

add_action(
   'wsal_custom_alerts_register',
   /**
   * Adds sensors classes to the Class Helper
   *
   * @return void
   *
   * @since latest
   */
   function () {
       require_once __DIR__ . '/wp-security-audit-log/class-my-custom-alerts.php';

       Classes_Helper::add_to_class_map(
           array(
               'WSAL\\Custom_Alerts\\My_Custom_Alerts' => __DIR__ . '/wp-security-audit-log/class-my-custom-alerts.php',
           )
       );
   }
);

Once done, you should be able to continue triggering events as normal.

Register your custom event IDs with us

Have you created an extension that may be of use to others? If you create your own sensor and custom events, you can contact us and register your custom events, especially if you are creating events for a plugin or a component that is available to the public. By registering the events, you ensure they’re not used by anyone else, thus avoiding conflicts.