Beqlic Activity Log for WP
This is a Wordpress Activity Control plugin
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/becliq-devs/beqlic-activity-log/archive/refs/heads/main.zipReadme
Beqlic Activity Log for WP
A self-contained WordPress activity log / audit trail plugin. It records who created, edited or deleted content across your whole site, when (to the second), and exactly what changed — and lets you revert any single action back to its previous state. It can also email you a recurring activity report.
Built as a lightweight, dependency-free alternative to commercial audit-log plugins. Everything lives in one folder; no external services are called.
Features
- 📋 Full activity log stored in its own database table, shown in a searchable, sortable, paginated admin screen.
- 👤 Who did it — user name, user ID, role, and IP address for every action.
- 🕒 Exact timestamp — full date/time plus a human "x ago" hint.
- 🔍 What changed — field-level diffs (
old value → new value) for edits. - 🚦 Severity levels — every event is tagged Info / Notice / Warning / Critical and carries a stable numeric event ID, so you can filter and prioritise.
- ↩️ Per-action Revert — each entry has its own button to restore the previous state. Reverts are themselves logged for a complete audit trail.
- 🔔 Instant alerts — email someone the moment an event at or above a chosen severity is recorded (independent of the digest).
- 📊 Dashboard overview — an "at a glance" widget on the WordPress dashboard: totals (24h / 7d / 30d), counts by severity, most active users, and recent warnings/critical events.
- ✉️ Email reports — send a summary of all activity to any address on a Daily / Weekly / Monthly schedule (or disable). Includes a "send test report now" button.
- 🗓️ On-demand reports — generate a report for any custom date range, as a formatted, client-ready PDF and/or a CSV. Email it or download it (both formats download as a ZIP).
- ⬇️ CSV export — download the log (respecting the current filters) for spreadsheets or external retention.
- 🧹 Retention control — automatically purge entries older than N days.
- ⚙️ Granular toggles — turn each event category on or off from the settings page.
- 🔒 Safe by default — capability checks (
manage_options), nonces on every revert/export, prepared SQL statements, and output escaping throughout.
Tracked events
| Area | Events |
|---|---|
| Posts / Pages / CPTs | created · updated · trashed · restored · permanently deleted |
| Users | registered · profile updated · role changed · deleted |
| Taxonomy terms | created · updated · deleted |
| Media library | uploaded · edited · deleted |
| Comments | posted · approved · unapproved · spam · trashed · deleted · edited |
| Navigation menus | created · updated · deleted |
| Widgets | added · settings updated · removed |
| WooCommerce | order created · order status changed · stock quantity changed · stock status changed (only when WooCommerce is active) |
| Site settings | any watched option changed (title, tagline, URLs, admin email, membership, reading, discussion, permalinks…) |
| Any option (advanced, opt-in) | changes to any WordPress option — captures most plugins' settings generically, with transients/locks/internal noise filtered out |
| Themes | switched · installed · updated · deleted |
| Plugins | activated · deactivated · installed · updated · deleted |
| WordPress core | updated |
| Backups | completed · failed (Duplicator / Duplicator Pro) |
| Authentication | login · logout · failed login · login from new IP · password reset requested · password reset |
What can be reverted
| Action | Revert behaviour |
|---|---|
| Post updated | Restores title, content, excerpt, status and slug |
| Post trashed | Restores it from trash |
| Post deleted | Recreates the post with its meta and taxonomy terms (new ID) |
| User profile updated | Restores email, display name, website and roles |
| Term deleted | Recreates the term |
| Setting changed | Restores the previous value of the option |
| Plugin activated / deactivated | Toggles the plugin back to its previous state |
Actions like created, login, etc. are intentionally not revertible and show N/A.
Requirements
- WordPress 5.6+ (uses the
wp_after_insert_posthook) - PHP 7.2+ (PHP 8.0+ required for the bundled PDF engine; CSV works on any supported version)
- The PDF report uses the bundled Dompdf library in
vendor/— keep that folder when deploying. If it's missing, the plugin transparently falls back to CSV.
Installation
- Copy the
beqlic-activity-logfolder intowp-content/plugins/. (or download a release zip and upload it via Plugins → Add New → Upload Plugin) - Activate Beqlic Activity Log for WP from the Plugins screen. Activation creates the log table.
- Open Activity Log in the admin menu to view events.
- Open Activity Log → Settings to configure email reports, retention, and which events to track.
Usage
Viewing activity
wp-admin → Activity Log. Search by keyword, or filter by action, object type and date range. Columns: Date & time, User, Role, Action, Object, What changed, Revert.
Reverting an action
Find a row with a Revert button, click it, confirm the prompt. The item is restored, the row is marked Reverted (so it can't be reverted twice), and a new audit entry records the rollback.
Email reports
In Settings, set a recipient email and pick a frequency. Reports are sent via WP-Cron and contain a summary plus a table of actions for the period. Use Send test report now to confirm delivery.
Advanced option logging ("log any option change")
Settings → What to log → Advanced option logging. Off by default; tick the box to enable.
What it does. Almost every plugin (and WordPress itself) stores its settings as rows in the WordPress options table — Yoast's SEO config, Contact Form 7, WooCommerce settings, your theme options, and so on. Normally Beqlic only records changes to a curated list of important core options (site title, tagline, site URLs, admin email, membership, reading/discussion settings, permalinks…). When you turn on advanced option logging, Beqlic instead watches every option and records a log entry whenever any option's value actually changes.
In practice this gives you generic, cross-plugin settings auditing without writing any plugin-specific code: if a setting changes in roughly any plugin, you'll see who changed it and when — with a before → after comparison.
What each entry looks like.
- Severity:
Info(the curated core settings stay at the higherNoticelevel, so the important ones still stand out). - What changed: a
previous value → new valuediff (long/array values are shortened for display). - Revertible: yes — each entry gets a Revert button that restores the option to its previous value.
- Event ID:
6002(any_option_updated), versus6000for curated settings.
Noise is filtered automatically. Logging every option would be overwhelming, so Beqlic skips the high-churn / internal ones, including:
- Transients and site transients (
_transient_*,_site_transient_*, anything containingtransient). - Locks and session data (
*_lock,session_tokens,_wp_session_*). - WordPress internals that change constantly or are covered elsewhere — e.g.
cron,rewrite_rules,recently_edited,recently_activated, andactive_plugins(plugin activation/deactivation is already logged as its own event). - Beqlic's own options.
When to use it. Leave it off for a clean, high-signal log of the events that matter most. Turn it on when you want deep forensic coverage — for example, to catch a setting being changed by a plugin you don't have a dedicated integration for, or while investigating an incident. It is more verbose, so expect more entries.
Tuning. A few plugins write counter- or timestamp-style options on every page load. If one of those floods your log, you can exclude it with the bal_should_log_option filter (see Developer notes) — return false for the option names you want ignored.
Project structure
beqlic-activity-log/
├── beqlic-activity-log.php # Main file: constants, bootstrap, activation/deactivation
├── uninstall.php # Drops the table + options on plugin delete
├── readme.txt # WordPress.org-style readme
├── README.md
├── assets/
│ └── admin.css # Badges, diff styling, layout
├── vendor/ # Bundled libraries (Dompdf, for PDF reports)
└── includes/
├── class-bal-db.php # Custom table: create / insert / query / export / purge
├── class-bal-logger.php # Hooks into WP events, event registry, records them
├── class-bal-revert.php # Per-action revert handlers
├── class-bal-reports.php # Scheduled + on-demand reports, CSV/PDF, retention
├── class-bal-pdf.php # Formatted PDF report (Dompdf)
├── class-bal-alerts.php # Instant email alerts on high-severity events
├── class-bal-dashboard.php # "At a glance" admin dashboard widget
├── class-bal-settings.php # Settings page (Settings API) + on-demand report tool
└── class-bal-admin.php # Admin menu + log viewer (WP_List_Table) + CSV export
How it works
- A custom table
{prefix}_bal_activity_logstores every entry, including its severity, a stable event ID, and an optional JSON snapshot of the previous state used for reverts. - Events are captured through native WordPress hooks (
wp_after_insert_post,before_delete_post,profile_update,created_term,updated_option,add_attachment,wp_insert_comment,wp_create_nav_menu,switch_theme,upgrader_process_complete,activated_plugin,wp_login, …). - Each logical event is defined once in a central registry (
BAL_Logger::events()) that maps it to a numeric ID and a default severity, so labels, filtering and alerting stay consistent. - The admin list table reads, filters (severity / action / type / date / search) and paginates entries; the revert controller restores state and writes a follow-up audit entry.
- After every write the logger fires
bal_after_log, which the alerts module uses to send an immediate email when the entry meets the configured severity threshold. - Reports run on a WP-Cron schedule (
daily/ customweekly/monthly), which also performs the retention purge. - A version-stamped upgrade routine (
bal_maybe_upgrade()) keeps the table schema current on existing installs without a manual reactivation.
Developer notes
- Skip an entry before it's stored:
add_filter( 'bal_pre_log_entry', function ( $row ) { if ( 'setting' === $row['object_type'] ) { return false; // don't log settings changes } return $row; } ); - React to any logged event (e.g. forward to Slack):
add_action( 'bal_after_log', function ( $id, $row ) { if ( 'critical' === $row['severity'] ) { // notify an external service… } }, 10, 2 ); - Tune which options "log any option" mode records:
add_filter( 'bal_should_log_option', function ( $log, $option ) { if ( 0 === strpos( $option, 'myplugin_cache_' ) ) { return false; // ignore this plugin's churny options } return $log; }, 10, 2 ); - The event registry (
BAL_Logger::events()) returnsevent_key => array( event_id, severity ). Severities are ordered withBAL_Logger::severity_weight()(info < notice < warning < critical). - All settings live under a single option key,
bal_settings. - Uninstalling the plugin drops the table, deletes the options and clears the cron event.
Security
- Every admin action checks
current_user_can( 'manage_options' ). - Revert and test-report requests are protected by nonces.
- All database access uses
$wpdb->prepare(); all output is escaped.
Changelog
1.5.0
- On-demand reports can now be produced as a formatted, client-ready PDF (bundled Dompdf), a CSV, or both.
- Each format works for both the Email report and Download buttons; downloading both formats yields a ZIP.
- PDF includes a branded header, a summary (totals + severity breakdown) and a styled, colour-coded events table; full Unicode/Greek support.
1.4.0
- Added an opt-in "log any option change" advanced mode: logs changes to any WordPress option (Info severity, revertible), giving generic, cross-plugin settings coverage. Transients, locks, session tokens and other high-churn internals are filtered out, and the list is tunable via the
bal_should_log_optionfilter.
1.3.1
- On-demand report dates now use dd/mm/yyyy.
- On-demand report now has two buttons: Email report (HTML + CSV) and Download CSV to my computer (no email).
1.3.0
- Added an "at a glance" dashboard widget (totals, severity breakdown, top users, recent warnings/critical).
- Added on-demand reports for a custom date range, emailed with a CSV attachment.
- Added backup logging for Duplicator / Duplicator Pro (completed & failed builds).
1.2.0
- Added widget tracking (add / settings update / remove) for classic and block widget areas.
- Added WooCommerce tracking (order created, order status changed, stock quantity & status changes); only active when WooCommerce is installed. Products and coupons remain covered by the post logger.