HEX
Server: Apache/2.4.65 (Debian)
System: Linux 88f31f35b0b8 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/aaa-option-optimizer/src/class-plugin.php
<?php
/**
 * Plugin functionality for AAA Option Optimizer.
 *
 * @package Progress_Planner\OptionOptimizer
 */

namespace Progress_Planner\OptionOptimizer;

/**
 * Core functionality of AAA Option Optimizer.
 */
class Plugin {
	/**
	 * The instance of the plugin.
	 *
	 * @var Plugin
	 */
	public static $instance;

	/**
	 * Holds the options accessed during the request with their access counts.
	 *
	 * @var array<string, int>
	 */
	protected $accessed_options = [];

	/**
	 * Whether the plugin is currently processing an option access.
	 * Used to prevent infinite recursion.
	 *
	 * @var bool
	 */
	protected $is_processing = false;

	/**
	 * Whether the plugin should reset the option_optimizer data.
	 *
	 * @var boolean
	 */
	protected $should_reset = false;

	/**
	 * Initializes the plugin.
	 *
	 * @return void
	 */
	public function __construct() {
		self::$instance = $this;
	}

	/**
	 * Gets the instance of the plugin.
	 *
	 * @return Plugin
	 */
	public static function get_instance() {
		// @phpstan-ignore-next-line -- The 'instance' property is set in the constructor.
		if ( ! self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Registers hooks.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( Admin_Page::get_option_tracking() === 'pre_option' ) {
			\add_filter( 'pre_option', [ $this, 'monitor_option_accesses_pre_option' ], PHP_INT_MAX, 2 );
		} else {
			// 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_legacy' ] );
		}

		// Use the shutdown action to update the option with tracked data.
		\add_action( 'shutdown', [ $this, 'update_tracked_options' ] );

		// Register the REST routes.
		$rest = new REST();
		$rest->register_hooks();

		if ( \is_admin() ) {
			// Register the admin page.
			$admin_page = new Admin_Page();
			$admin_page->register_hooks();
		}
	}

	/**
	 * Sets the 'should_reset' property.
	 *
	 * @param boolean $should_reset Whether the plugin should reset the option_optimizer data.
	 *
	 * @return void
	 */
	public function reset( $should_reset = true ) {
		$this->should_reset = $should_reset;
	}

	/**
	 * Monitor all actions and filters for option accesses.
	 *
	 * @param string $tag The current action or filter tag being executed.
	 *
	 * @return void
	 */
	public function monitor_option_accesses_legacy( $tag ) {
		if ( $this->is_processing ) {
			return;
		}

		// Check if the tag is related to an option access.
		if ( str_starts_with( $tag, 'option_' ) || str_starts_with( $tag, 'default_option_' ) ) {
			$this->is_processing = true;
			$option_name         = preg_replace( '#^(default_)?option_#', '', $tag );
			$this->add_option_usage( $option_name );
			$this->is_processing = false;
		}
	}

	/**
	 * Add an option to the list of used options if it's not already there.
	 *
	 * @param mixed  $pre The value to return instead of the option value.
	 * @param string $option_name Name of the option being accessed.
	 *
	 * @return mixed
	 */
	public function monitor_option_accesses_pre_option( $pre, $option_name ) {
		if ( $this->is_processing ) {
			return $pre;
		}

		// If the $pre is false the get_option() will not be short-circuited.
		if ( ! defined( 'WP_SETUP_CONFIG' ) && false === $pre ) {
			$this->is_processing = true;
			$this->add_option_usage( $option_name );
			$this->is_processing = false;
		}

		return $pre;
	}

	/**
	 * Add an option to the list of used options if it's not already there.
	 *
	 * @param string $option_name Name of the option being accessed.
	 *
	 * @return void
	 */
	protected function add_option_usage( $option_name ) {
		if ( ! array_key_exists( $option_name, $this->accessed_options ) ) {
			$this->accessed_options[ $option_name ] = 0;
		}

		++$this->accessed_options[ $option_name ];
	}

	/**
	 * Update the tracked options at the end of the page load.
	 *
	 * @return void
	 */
	public function update_tracked_options() {
		// phpcs:ignore WordPress.Security.NonceVerification -- not doing anything.
		if ( isset( $_GET['page'] ) && $_GET['page'] === 'aaa-option-optimizer' ) {
			return;
		}

		// Handle reset.
		if ( $this->should_reset ) {
			Database::clear_tracked_options();
			return;
		}

		// Write accessed options directly to the custom table.
		if ( ! empty( $this->accessed_options ) ) {
			Database::batch_insert( $this->accessed_options );
		}
	}
}