[ $this, 'sanitize_settings' ], ] ); } /** * Sanitize settings. * * This merges the settings into the existing option_optimizer option structure. * * @param array $input Settings input. * @return array Sanitized settings merged with existing option data. */ public function sanitize_settings( $input ): array { // Get the existing option_optimizer data to preserve other keys. $existing = \get_option( self::OPTION_NAME, [] ); // Initialize settings array if it doesn't exist. if ( ! isset( $existing['settings'] ) ) { $existing['settings'] = []; } // Sanitize the option_tracking setting. $option_tracking = 'pre_option'; if ( isset( $input['settings']['option_tracking'] ) ) { $input_option_tracking = \sanitize_text_field( $input['settings']['option_tracking'] ); if ( \in_array( $input_option_tracking, [ 'pre_option', 'legacy' ], true ) ) { $option_tracking = $input_option_tracking; } } $existing['settings']['option_tracking'] = $option_tracking; // Return the full option structure with merged settings. return $existing; } /** * Get settings. * * @return array Settings from the settings subarray. */ public static function get_settings(): array { $defaults = [ 'option_tracking' => 'pre_option', ]; $option_optimizer = \get_option( self::OPTION_NAME, [] ); $settings = isset( $option_optimizer['settings'] ) ? $option_optimizer['settings'] : []; return \wp_parse_args( $settings, $defaults ); } /** * Get option tracking. * * @return string Option tracking. */ public static function get_option_tracking(): string { $settings = self::get_settings(); return $settings['option_tracking'] ?? 'pre_option'; } /** * Register the settings link for the plugins page. * * @param array $links The plugin action links. * @param string $file The plugin file. * * @return array */ public function filter_plugin_actions( $links, $file ): array { /* Static so we don't call plugin_basename on every plugin row. */ static $this_plugin; if ( ! $this_plugin ) { $this_plugin = \plugin_basename( AAA_OPTION_OPTIMIZER_FILE ); } if ( $file === $this_plugin ) { $settings_link = '' . \__( 'Optimize Options', 'aaa-option-optimizer' ) . ''; // Put our link before other links. \array_unshift( $links, $settings_link ); } return $links; } /** * Adds the admin page under the Tools menu. * * @return void */ public function add_admin_page() { \add_management_page( __( 'AAA Option Optimizer', 'aaa-option-optimizer' ), __( 'Option Optimizer', 'aaa-option-optimizer' ), 'manage_options', 'aaa-option-optimizer', [ $this, 'render_admin_page_ajax' ] ); } /** * Enqueue our scripts. * * @param string $hook The current page hook. * * @return void */ public function enqueue_scripts( $hook ) { if ( $hook !== 'tools_page_aaa-option-optimizer' ) { return; } \wp_enqueue_style( 'aaa-option-optimizer', plugin_dir_url( AAA_OPTION_OPTIMIZER_FILE ) . 'css/style.css', [], '2.0.1' ); \wp_enqueue_script( 'aaaoo-datatables', plugin_dir_url( AAA_OPTION_OPTIMIZER_FILE ) . 'js/vendor/datatables.min.js', [], // Dependencies. '2.3.2', true // In footer. ); \wp_enqueue_style( 'aaaoo-datatables', \plugin_dir_url( AAA_OPTION_OPTIMIZER_FILE ) . 'js/vendor/datatables.min.css', [], '2.3.2' ); \wp_enqueue_script( 'aaa-option-optimizer-admin-js', \plugin_dir_url( AAA_OPTION_OPTIMIZER_FILE ) . 'js/admin-script.js', [ 'jquery', 'aaaoo-datatables' ], // Dependencies. \filemtime( \plugin_dir_path( AAA_OPTION_OPTIMIZER_FILE ) . 'js/admin-script.js' ), // Version. true // In footer. ); \wp_localize_script( 'aaa-option-optimizer-admin-js', 'aaaOptionOptimizer', [ 'root' => \esc_url_raw( \rest_url() ), 'nonce' => \wp_create_nonce( 'wp_rest' ), 'migration' => Database::get_migration_status(), 'i18n' => [ 'filterBySource' => \esc_html__( 'Filter by source', 'aaa-option-optimizer' ), 'showValue' => \esc_html__( 'Show', 'aaa-option-optimizer' ), 'addAutoload' => \esc_html__( 'Add autoload', 'aaa-option-optimizer' ), 'removeAutoload' => \esc_html__( 'Remove autoload', 'aaa-option-optimizer' ), 'deleteOption' => \esc_html__( 'Delete', 'aaa-option-optimizer' ), 'createOptionFalse' => \esc_html__( 'Create option with value false', 'aaa-option-optimizer' ), 'noAutoloadedButNotUsed' => \esc_html__( 'All autoloaded options are in use.', 'aaa-option-optimizer' ), 'noUsedButNotAutoloaded' => \esc_html__( 'All options that are used are autoloaded.', 'aaa-option-optimizer' ), 'noOptionsSelected' => \esc_html__( 'No options selected.', 'aaa-option-optimizer' ), 'bulkActions' => \esc_html__( 'Bulk actions', 'aaa-option-optimizer' ), 'noBulkActionSelected' => \esc_html__( 'No action selected.', 'aaa-option-optimizer' ), 'delete' => \esc_html__( 'Delete', 'aaa-option-optimizer' ), 'apply' => \esc_html__( 'Apply', 'aaa-option-optimizer' ), 'search' => \esc_html__( 'Search:', 'aaa-option-optimizer' ), 'migrating' => \esc_html__( 'Migrating...', 'aaa-option-optimizer' ), 'migrationComplete' => \esc_html__( 'Migration complete! Reloading page...', 'aaa-option-optimizer' ), 'migrationError' => \esc_html__( 'Migration error. Please try again.', 'aaa-option-optimizer' ), /* translators: %1$d: number of migrated options, %2$d: total number of options */ 'migratedOf' => \esc_html__( 'Migrated %1$d of %2$d options', 'aaa-option-optimizer' ), 'entries' => [ '_' => \esc_html__( 'entries', 'aaa-option-optimizer' ), '1' => \esc_html__( 'entry', 'aaa-option-optimizer' ), ], 'sInfo' => sprintf( // translators: %1$s is the start, %2$s is the end, %3$s is the total, %4$s is the entries. \esc_html__( 'Showing %1$s to %2$s of %3$s %4$s', 'aaa-option-optimizer' ), '_START_', '_END_', '_TOTAL_', '_ENTRIES-TOTAL_' ), 'sInfoEmpty' => \esc_html__( 'Showing 0 to 0 of 0 entries', 'aaa-option-optimizer' ), 'sInfoFiltered' => sprintf( // translators: %1$s is the max, %2$s is the entries-max. \esc_html__( '(filtered from %1$s total %2$s)', 'aaa-option-optimizer' ), '_MAX_', '_ENTRIES-MAX_' ), 'sZeroRecords' => \esc_html__( 'No matching records found', 'aaa-option-optimizer' ), 'oAria' => [ 'orderable' => \esc_html__( ': Activate to sort', 'aaa-option-optimizer' ), 'orderableReverse' => \esc_html__( ': Activate to invert sorting', 'aaa-option-optimizer' ), 'orderableRemove' => \esc_html__( ': Activate to remove sorting', 'aaa-option-optimizer' ), 'paginate' => [ 'first' => \esc_html__( 'First', 'aaa-option-optimizer' ), 'last' => \esc_html__( 'Last', 'aaa-option-optimizer' ), 'next' => \esc_html__( 'Next', 'aaa-option-optimizer' ), 'previous' => \esc_html__( 'Previous', 'aaa-option-optimizer' ), ], ], ], ] ); } /** * Renders the admin page. * * @return void */ public function render_admin_page_ajax() { $option_optimizer = \get_option( 'option_optimizer', [ 'used_options' => [] ] ); global $wpdb; $autoload_values = \wp_autoload_values_to_autoload(); $placeholders = \implode( ',', \array_fill( 0, \count( $autoload_values ), '%s' ) ); // phpcs:disable WordPress.DB $result = $wpdb->get_row( $wpdb->prepare( "SELECT count(*) AS count, SUM( LENGTH( option_value ) ) as autoload_size FROM {$wpdb->options} WHERE autoload IN ( $placeholders )", $autoload_values ) ); // phpcs:enable WordPress.DB // Check if migration is needed. $migration_status = Database::get_migration_status(); ?>


render_settings_tab( $option_optimizer, $result ); ?>
$option_optimizer The option optimizer data. * @param object $result The database query result with current stats. * * @return void */ private function render_settings_tab( $option_optimizer, $result ): void { $settings = self::get_settings(); // Check if settings were saved. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce check not needed here. if ( isset( $_GET['settings-updated'] ) ) { ?>

count ), \number_format( ( $result->autoload_size / 1024 ), 1 ) ); ?>