Last active
April 11, 2025 07:54
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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