Skip to content

Activity Log ​

Who changed what and when: content, sign-ins, settings, users and roles.

kitloom/activity-log · admins: kitloom/activity-log-filament, kitloom/activity-log-nova

Video lessons ​

Recorded in the Filament admin; the Nova admin works the same way.

Activity Log
Activity Log Settings

The site's activity log on spatie/laravel-activitylog: who changed which post, term, option or account, who signed in and who failed to, from which address and when. The admin is kitloom/activity-log-filament or kitloom/activity-log-nova.

What is logged ​

log_nameeventFrom
contentcreated, updated, published, trashed, restored, deletedKitloom\WpSchema\Events\* — every post and taxonomy model, whatever wrote it
contentcreated, approved, unapproved, spammed, trashed, restoredKitloom\WpSchema\Events\CommentPosted, CommentStatusChanged — comments and product reviews, from the site's form, an admin or an agent
authlogin, logout, failedLaravel's auth events
settingscreated, updated, deletedKitloom\Settings\Events\SettingSaved, SettingDeleted — every write, through SettingWriter, a settings page or the model
rolescreated, updated, deletedKitloom\Permissions\Events\RoleSaved, RoleDeleted (the role editor), UserRoleChanged (a user given another role), PermissionsSynced (permissions that reached roles when a module or post type declared them)
userscreated, deletedthe Eloquent events of the model the default guard signs in with
activity_logclearedthe log cleared by hand
  • An update keeps the fields that changed (changed), and the old and new values of the title, slug, status, parent, author, date, order and comment status. The content, the excerpt and a post's password are logged as changed, without values; for the body, the excerpt and a term's description the entry keeps what the edit did (diff). A save that changed nothing is not logged; publishing, trashing and restoring are entries of their own, not an update of the status.
  • Revisions, menu items (a saved menu rewrites every item), oEmbed caches, customizer changesets (content.ignore_types) and auto-drafts are left out.
  • A comment is logged under its record — comment by Ada on "Dune" approved, type the comment type (comment, review), title the record's, status (approved, hold, spam, trash) and from for a move — by the user the writer acted for. What it said, the commenter's email and address are not kept. Order notes and WooCommerce's other internal rows of the comments table are left out, and so is a comment type named in content.ignore_types.
  • A failed sign-in keeps the login that was tried — never the password — and the account it named, if there is one.
  • An option whose name looks like a secret (*pass*, *key*, *token*, *secret*, *dsn*… — settings.secret) is logged as changed without values. Transients, cron and rewrite_rules are not logged (settings.ignore). Values over 500 characters are cut.
  • A role created or deleted keeps its permissions; a change keeps a new name and the permissions added and taken away, by name, not the whole list again. Permissions that reach roles on their own (PermissionsSynced) are an updated entry per role with permissions_added, source=sync, and like when the grant followed a related capability — causer is the system. A user given another role — on their screen, as a new account's default role, or taken over from WordPress at sign-in — is an updated entry of type user with the old and the new role. Here the causer is the actor the event carries, not whoever is signed in.
  • Nothing is logged while migrations run.

Every entry has type (the post type, the taxonomy, option, role, user) and title in its properties, via — web for a request a person made, console for the console, the queue and the scheduler — and, during a request, ip. The causer is whoever is signed in (the default guard); with nobody, the admin shows "System" for the console and "Visitor" for the web. by keeps the causer's login, so the log still names a deleted account. The email is never kept.

The old and new values are in attribute_changes, the way spatie's LogsActivity keeps them — {"old": {…}, "attributes": {…}}, old left out of a creation and attributes out of a deletion — so an entry written by spatie's activity() reads the same. The properties keep only kitloom's own data: the above, changed (every field that changed, those without values too) and diff.

Writing an entry never breaks what is being logged: a failure is reported (report()), not thrown.

php
use Kitloom\ActivityLog\Models\ActivityLog;
use Kitloom\WpSchema\WpSchema;

$changes = WpSchema::query(ActivityLog::KEY)->where('log_name', 'content')->ofType('book')->latest('id')->limit(20)->get();

Where things are kept ​

WhatWhere
Entriesspatie's table, activity_log (the table of the registry's model — spatie 5 has no activitylog.table_name) with the site's table prefix in front — migrated with the application's migrations, nothing to publish
ModelKitloom\ActivityLog\Models\ActivityLog (extends spatie's Activity), key activity_log in the ModelRegistry; spatie's activity() and activitylog:clean are pointed at the same class
Retentionoption activity_log_retention_days: 90 unless set, 0 keeps everything

activity-log:prune deletes entries older than the retention (--days for one run); the module schedules it daily — the application's schedule:run has to run. It runs on one server of several, by a lock in the cache, so a site on several servers needs a shared cache store (Redis, the database) — with each server's own cache the lock is local and the task runs on every one. Clearing by hand (ActivityLogs::clear($actor, $olderThanDays)) takes manage_activity_log and leaves a cleared entry; reading the log in the admins takes view_activity_log. Both go to administrators.

AI agents ​

With kitloom/ai installed, an agent whose user has view_activity_log reads the log (activity_list): when, who, what, the record and the fields changed, filtered by log, event, user, record type, date or text. Clearing the log stays a person's. kitloom-activity-log.ai.register false — no log tool.

Personal data ​

With kitloom/privacy, Tools → Export Personal Data lists the entries about the person the address belongs to: what their account did, what was done to it (signed in, given a role), the sign-ins that failed with their address and what happened to their comments — when, the area, the event, what, and the IP address where it was theirs (an entry they made, a failed sign-in). The address of an administrator who changed their account is not exported.

Erase Personal Data keeps the entries and cuts the person out of them. The log is the site's audit: which post was published, which option changed, by whom — the owner still needs to read what happened, and deleting entries on request would let anyone wipe their tracks. What identifies the person goes: the account as causer or subject, the IP address of their entries and failed sign-ins, the login a failed sign-in tried, and their name in the entry's title, description and by, which say "Anonymous". Entries about their comments say "Anonymous" for the author; the comments themselves are kitloom/privacy's. The report counts the entries made anonymous and says that the log keeps them. The retention prunes them in time as usual; an owner who must keep the person's identity in the log for a security case turns the export and erasure off (privacy.register) and answers that request by hand.

Comments are matched by the address or the user they still have, so the log's eraser runs before the comments eraser of kitloom/privacy takes both away: providers register in the order Composer installs the packages, activity-log before privacy.

Configuration ​

config/kitloom-activity-log.php (php artisan vendor:publish --tag=kitloom-activity-log-config):

  • log.content, log.auth, log.settings, log.roles, log.users — each kind of logging on or off. spatie's ACTIVITY_LOGGER_ENABLED turns everything off.
  • ip.enabled, ip.anonymize — the address is kept in full by default: a security log has to tell where a run of failed sign-ins comes from, and the retention bounds how long it is kept. anonymize keeps the network only (IPv4 without the last octet, IPv6 without the last 80 bits). Behind a proxy the application's TrustProxies decides what Request::ip() is.
  • content.ignore_types, settings.ignore, settings.secret, settings.max_value_length.
  • schedule — the daily pruning.
  • privacy.register — the personal data export and erasure (kitloom/privacy).
  • filament.register, nova.register — the admin sections.

What the application overrides ​

  • The model: ModelRegistry::use(ActivityLog::KEY, App\Models\ActivityLog::class) with a subclass of the package's; the admins and spatie's helpers read the class from the registry.

Tests ​

From the application that installs the package: php vendor/bin/phpunit --testsuite ActivityLog.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]