From 8e5c5fd4bfa241e4ced1846112aa0524671de73f Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Wed, 10 Dec 2025 11:14:05 +0100 Subject: [PATCH 1/3] delay get_option( 'option_optimizer' ) to 'shutdown' --- src/class-plugin.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/class-plugin.php b/src/class-plugin.php index 37c73fe..9830533 100644 --- a/src/class-plugin.php +++ b/src/class-plugin.php @@ -60,7 +60,7 @@ public static function get_instance() { * @return void */ public function register_hooks() { - $this->accessed_options = \get_option( 'option_optimizer', [ 'used_options' => [] ] )['used_options']; + $this->accessed_options = []; // Hook into all actions and filters to monitor option accesses. // @phpstan-ignore-next-line -- The 'all' hook does not need a return. @@ -135,9 +135,15 @@ public function update_tracked_options() { // Retrieve the existing option_optimizer data. $option_optimizer = get_option( 'option_optimizer', [ 'used_options' => [] ] ); - $option_optimizer['used_options'] = $this->accessed_options; + if ( ! $this->should_reset ) { + foreach ( $this->accessed_options as $option_name => $count ) { + if ( ! isset( $option_optimizer['used_options'][ $option_name ] ) ) { + $option_optimizer['used_options'][ $option_name ] = 0; + } - if ( $this->should_reset ) { + $option_optimizer['used_options'][ $option_name ] += $count; + } + } else { $option_optimizer['used_options'] = []; } From 168ff77e50c3506697e95c6d23ac67295d04349c Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Wed, 10 Dec 2025 15:42:59 +0100 Subject: [PATCH 2/3] already set --- src/class-plugin.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/class-plugin.php b/src/class-plugin.php index 9830533..82a03fb 100644 --- a/src/class-plugin.php +++ b/src/class-plugin.php @@ -60,8 +60,6 @@ public static function get_instance() { * @return void */ public function register_hooks() { - $this->accessed_options = []; - // Hook into all actions and filters to monitor option accesses. // @phpstan-ignore-next-line -- The 'all' hook does not need a return. \add_filter( 'all', [ $this, 'monitor_option_accesses' ] ); From 0bc9aee610fe2c7833fff8a3ec19c46eb00296df Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Wed, 10 Dec 2025 15:45:12 +0100 Subject: [PATCH 3/3] update data every 5 mins --- src/class-plugin.php | 100 +++++++++++++++++++++++++++++++++++++------ uninstall.php | 3 ++ 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/class-plugin.php b/src/class-plugin.php index 82a03fb..db60b33 100644 --- a/src/class-plugin.php +++ b/src/class-plugin.php @@ -123,6 +123,9 @@ protected function add_option_usage( $option_name ) { /** * Update the 'option_optimizer' option with the list of used options at the end of the page load. * + * Uses transient batching to reduce database writes - only flushes to the main option + * every 5 minutes instead of on every request. + * * @return void */ public function update_tracked_options() { @@ -130,22 +133,95 @@ public function update_tracked_options() { if ( isset( $_GET['page'] ) && $_GET['page'] === 'aaa-option-optimizer' ) { return; } - // Retrieve the existing option_optimizer data. - $option_optimizer = get_option( 'option_optimizer', [ 'used_options' => [] ] ); - if ( ! $this->should_reset ) { - foreach ( $this->accessed_options as $option_name => $count ) { - if ( ! isset( $option_optimizer['used_options'][ $option_name ] ) ) { - $option_optimizer['used_options'][ $option_name ] = 0; - } + // Handle reset: clear batch and main option. + if ( $this->should_reset ) { + \delete_transient( 'option_optimizer_batch' ); - $option_optimizer['used_options'][ $option_name ] += $count; - } - } else { + $option_optimizer = \get_option( 'option_optimizer', [ 'used_options' => [] ] ); $option_optimizer['used_options'] = []; + \update_option( 'option_optimizer', $option_optimizer, false ); + return; + } + + // Get the batch data. + $batch_data = $this->get_batch_data(); + + // Add current request's options to the batch. + foreach ( $this->accessed_options as $option_name => $count ) { + if ( ! isset( $batch_data['options'][ $option_name ] ) ) { + $batch_data['options'][ $option_name ] = 0; + } + $batch_data['options'][ $option_name ] += $count; + } + + // Check if it's time to flush the batch. + $should_flush = ( \time() - $batch_data['last_flush'] ) >= $this->get_flush_interval(); + + // Flush batch to main option every 5 minutes. + if ( ! empty( $batch_data['options'] ) && $should_flush ) { + $this->flush_batch_to_option( $batch_data['options'] ); + + // Reset the batch data. + $batch_data = [ + 'options' => [], + 'last_flush' => \time(), + ]; + } + + // No expiry - batch is explicitly deleted on flush, expiry would only cause data loss. + \set_transient( 'option_optimizer_batch', $batch_data, 0 ); + } + + /** + * Get the batch data. + * + * @return array + */ + protected function get_batch_data() { + // Get existing batch (stores both data and flush timestamp in one transient). + $batch_data = \get_transient( 'option_optimizer_batch' ); + if ( ! \is_array( $batch_data ) || ! isset( $batch_data['options'], $batch_data['last_flush'] ) ) { + $batch_data = [ + 'options' => [], + 'last_flush' => \time(), + ]; + } + + return $batch_data; + } + + /** + * Get the flush interval. + * + * @return int + */ + protected function get_flush_interval() { + return (int) \apply_filters( 'aaa_option_optimizer_flush_interval', 5 * MINUTE_IN_SECONDS ); + } + + /** + * Flush the batched data to the main option_optimizer option. + * + * @param array $batch The batched option usage data. + * + * @return void + */ + protected function flush_batch_to_option( $batch ) { + + if ( empty( $batch ) ) { + return; + } + + $option_optimizer = \get_option( 'option_optimizer', [ 'used_options' => [] ] ); + + foreach ( $batch as $option_name => $count ) { + if ( ! isset( $option_optimizer['used_options'][ $option_name ] ) ) { + $option_optimizer['used_options'][ $option_name ] = 0; + } + $option_optimizer['used_options'][ $option_name ] += $count; } - // Update the 'option_optimizer' option with the new list. - update_option( 'option_optimizer', $option_optimizer, false ); + \update_option( 'option_optimizer', $option_optimizer, false ); } } diff --git a/uninstall.php b/uninstall.php index 4fa17e2..08493b6 100644 --- a/uninstall.php +++ b/uninstall.php @@ -12,5 +12,8 @@ exit; } +// Delete the batch transient. +delete_transient( 'option_optimizer_batch' ); + // Delete the plugin option. delete_option( 'option_optimizer' );