-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathclass-plugin.php
More file actions
185 lines (163 loc) · 4.39 KB
/
class-plugin.php
File metadata and controls
185 lines (163 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<?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 );
}
}
}