Skip to content

Instantly share code, notes, and snippets.

@bonny
Last active April 11, 2025 07:54
Show Gist options
  • Save bonny/29e0818051525b1a4f52c75a58244a3c to your computer and use it in GitHub Desktop.
Save bonny/29e0818051525b1a4f52c75a58244a3c to your computer and use it in GitHub Desktop.
WordPress plugin that logs when a options are modified. Create folder `/plugins/simple-history-options-logger` and add file inside folder. Then active plugin in WordPress admin.
<?php
/**
* Plugin Name: Simple History Options Logger
* Description: Logs changes to selected WordPress options in Simple History
* Version: 1.0.0
* Author: Simple History
* Text Domain: simple-history-options-logger
* Domain Path: /languages
* Requires at least: 5.0
* Requires PHP: 7.4
*
* @package SimpleHistoryOptionsLogger
*/
namespace SimpleHistoryOptionsLogger;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Initialize the plugin.
add_action( 'plugins_loaded', [ '\SimpleHistoryOptionsLogger\Simple_History_Options_Logger', 'get_instance' ] );
/**
* Main plugin class
*/
class Simple_History_Options_Logger {
/**
* Plugin instance
*
* @var Simple_History_Options_Logger|null
*/
private static $instance = null;
/**
* List of option names to log when updated.
* Edit this array to monitor more options.
*
* @var array
*/
protected $options_to_log = [
'blogname',
'blogdescription',
'admin_email',
];
/**
* Get singleton instance
*
* @return Simple_History_Options_Logger The plugin instance
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
$this->init_hooks();
}
/**
* Initialize hooks
*
* @return void
*/
private function init_hooks() {
add_action( 'update_option', [ $this, 'log_option_update' ], 10, 3 );
add_action( 'delete_option', [ $this, 'log_option_delete' ], 10, 1 );
add_action( 'add_option', [ $this, 'log_option_add' ], 10, 1 );
}
/**
* Gets a simplified backtrace for logging purposes.
*
* @return array Backtrace information including the backtrace summary string.
*/
public function get_backtrace_info() {
// Get the full backtrace.
$backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 5 );
$trace = [];
// Skip the first two entries which would be this function and the logger function.
for ( $i = 2; $i < count( $backtrace ) && $i < 5; $i++ ) {
$item = $backtrace[$i];
$trace[] = [
'file' => isset( $item['file'] ) ? basename( $item['file'] ) : 'unknown',
'line' => isset( $item['line'] ) ? $item['line'] : 0,
'function' => isset( $item['function'] ) ? $item['function'] : 'unknown',
'class' => isset( $item['class'] ) ? $item['class'] : '',
];
}
// Get a summary using WordPress built-in function.
$summary = '';
if ( function_exists( 'wp_debug_backtrace_summary' ) ) {
$summary = wp_debug_backtrace_summary( null, 0, true );
}
return [
'trace' => $trace,
'summary' => $summary,
];
}
/**
* Fires immediately before an option value is updated.
*
* @param string $option Name of the option to update.
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
* @return array|void Backtrace information if logged, void otherwise.
*/
public function log_option_update( $option, $old_value, $value ) {
if ( ! in_array( $option, $this->options_to_log, true ) ) {
return;
}
// Check if SimpleLogger exists before using it.
if ( ! function_exists( '\SimpleLogger' ) ) {
return;
}
// Get backtrace information.
$backtrace_info = $this->get_backtrace_info();
// Log the update.
\SimpleLogger()->info(
sprintf( 'Option "%s" updated from "%s" to "%s"', $option, $old_value, $value ),
[
'context' => 'options',
'option' => $option,
'old_value' => $old_value,
'new_value' => $value,
'backtrace' => $backtrace_info['trace'],
'backtrace_summary' => $backtrace_info['summary'],
]
);
return $backtrace_info;
}
/**
* Log when an option is deleted.
*
* @param string $option Name of the option to delete.
* @return array|void Backtrace information if logged, void otherwise.
*/
public function log_option_delete( $option ) {
if ( ! in_array( $option, $this->options_to_log, true ) ) {
return;
}
// Check if SimpleLogger exists before using it.
if ( ! function_exists( '\SimpleLogger' ) ) {
return;
}
// Get backtrace information.
$backtrace_info = $this->get_backtrace_info();
// Log the deletion.
\SimpleLogger()->info(
sprintf( 'Option "%s" deleted', $option ),
[
'context' => 'options',
'option' => $option,
'backtrace' => $backtrace_info['trace'],
'backtrace_summary' => $backtrace_info['summary'],
]
);
return $backtrace_info;
}
/**
* Log when an option is added.
*
* @param string $option Name of the option to add.
* @return array|void Backtrace information if logged, void otherwise.
*/
public function log_option_add( $option ) {
if ( ! in_array( $option, $this->options_to_log, true ) ) {
return;
}
// Check if SimpleLogger exists before using it.
if ( ! function_exists( '\SimpleLogger' ) ) {
return;
}
// Get backtrace information.
$backtrace_info = $this->get_backtrace_info();
// Log the addition.
\SimpleLogger()->info(
sprintf( 'Option "%s" added', $option ),
[
'context' => 'options',
'option' => $option,
'backtrace' => $backtrace_info['trace'],
'backtrace_summary' => $backtrace_info['summary'],
]
);
return $backtrace_info;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment