Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 144 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 1 |
Performance | |
0.00% |
0 / 144 |
|
0.00% |
0 / 12 |
992 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
20 | |||
configureContainer | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
30 | |||
hooks | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
42 | |||
remove_epc_settings | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
nfd_asr_default | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
nfd_as_cleanup_batch_size | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
admin_bar_menu | |
0.00% |
0 / 36 |
|
0.00% |
0 / 1 |
30 | |||
add_management_page | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
add_nfd_subnav | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
render_performance_app | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
initialize_performance_app | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
register_performance_assets | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace NewfoldLabs\WP\Module\Performance; |
4 | |
5 | use NewfoldLabs\WP\ModuleLoader\Container; |
6 | use NewfoldLabs\WP\Module\Performance\Images\ImageManager; |
7 | use NewfoldLabs\WP\Module\Performance\RestApi\RestApi; |
8 | use NewfoldLabs\WP\Module\Performance\Data\Constants; |
9 | use NewfoldLabs\WP\Module\Performance\Services\I18nService; |
10 | use NewfoldLabs\WP\Module\Performance\LinkPrefetch\LinkPrefetch; |
11 | use NewfoldLabs\WP\Module\Performance\Cache\Cache; |
12 | use NewfoldLabs\WP\Module\Performance\Cache\ResponseHeaderManager; |
13 | use NewfoldLabs\WP\Module\Performance\Cloudflare\CloudflareFeaturesManager; |
14 | use NewfoldLabs\WP\Module\Performance\Fonts\FontManager; |
15 | use NewfoldLabs\WP\Module\Performance\Skip404\Skip404; |
16 | use NewfoldLabs\WP\Module\Performance\JetpackBoost\JetpackBoost; |
17 | |
18 | use function NewfoldLabs\WP\Module\Performance\get_cache_level; |
19 | |
20 | /** |
21 | * Main class for the performance module. |
22 | */ |
23 | class Performance { |
24 | |
25 | /** |
26 | * URL parameter used to purge the entire cache. |
27 | * |
28 | * @var string |
29 | */ |
30 | const PURGE_ALL = 'nfd_purge_all'; |
31 | |
32 | /** |
33 | * URL parameter used to purge the cache for a specific URL. |
34 | * |
35 | * @var string |
36 | */ |
37 | const PURGE_URL = 'nfd_purge_url'; |
38 | |
39 | /** |
40 | * Slug used for the Performance module's admin page. |
41 | * |
42 | * @var string |
43 | */ |
44 | const PAGE_SLUG = 'nfd-performance'; |
45 | |
46 | /** |
47 | * Dependency injection container. |
48 | * |
49 | * @var Container |
50 | */ |
51 | protected $container; |
52 | |
53 | /** |
54 | * Constructor. |
55 | * |
56 | * @param Container $container the container |
57 | */ |
58 | public function __construct( Container $container ) { |
59 | |
60 | $this->container = $container; |
61 | $this->configureContainer( $container ); |
62 | |
63 | $this->hooks(); |
64 | |
65 | new Cache( $container ); |
66 | new Skip404( $container ); |
67 | new PerformanceWPCLI(); |
68 | new Constants( $container ); |
69 | new CloudflareFeaturesManager( $container ); |
70 | new ImageManager( $container ); |
71 | new FontManager( $container ); |
72 | new HealthChecks( $container ); |
73 | |
74 | new LinkPrefetch( $container ); |
75 | |
76 | new JetpackBoost( $container ); |
77 | |
78 | if ( Permissions::is_authorized_admin() || Permissions::rest_is_authorized_admin() ) { |
79 | new RestAPI(); |
80 | } |
81 | |
82 | add_action( 'admin_bar_menu', array( $this, 'admin_bar_menu' ), 100 ); |
83 | add_action( 'admin_menu', array( $this, 'add_management_page' ) ); |
84 | add_action( 'load-tools_page_' . self::PAGE_SLUG, array( __CLASS__, 'initialize_performance_app' ) ); |
85 | add_filter( 'nfd_plugin_subnav', array( $this, 'add_nfd_subnav' ) ); |
86 | |
87 | ! defined( 'NFD_PERFORMANCE_PLUGIN_LANGUAGES_DIR' ) && define( 'NFD_PERFORMANCE_PLUGIN_LANGUAGES_DIR', dirname( $container->plugin()->file ) . '/vendor/newfold-labs/wp-module-performance/languages' ); |
88 | new I18nService( $container ); |
89 | } |
90 | |
91 | /** |
92 | * Constructor. |
93 | * |
94 | * @param Container $container the container. |
95 | */ |
96 | public function configureContainer( Container $container ) { |
97 | |
98 | $is_apache = false; |
99 | |
100 | // Ensure $is_apache is properly set, with a fallback for WP-CLI environment |
101 | if ( NFD_WPCLI::is_executing_wp_cli() ) { |
102 | // Attempt to detect Apache based on the SERVER_SOFTWARE header |
103 | $is_apache = isset( $_SERVER['SERVER_SOFTWARE'] ) && stripos( $_SERVER['SERVER_SOFTWARE'], 'apache' ) !== false; |
104 | |
105 | // Check for the existence of an .htaccess file (commonly used in Apache environments) |
106 | if ( ! $is_apache && file_exists( ABSPATH . '.htaccess' ) ) { |
107 | $is_apache = true; |
108 | } |
109 | } else { |
110 | global $is_apache; |
111 | } |
112 | |
113 | $container->set( 'isApache', $is_apache ); |
114 | |
115 | $container->set( |
116 | 'responseHeaderManager', |
117 | $container->service( |
118 | function () { |
119 | return new ResponseHeaderManager(); |
120 | } |
121 | ) |
122 | ); |
123 | } |
124 | |
125 | /** |
126 | * Add hooks. |
127 | */ |
128 | public function hooks() { |
129 | |
130 | add_action( 'admin_init', array( $this, 'remove_epc_settings' ), 99 ); |
131 | |
132 | /** |
133 | * On CLI requests, mod_rewrite is unavailable, so it fails to update |
134 | * the .htaccess file when save_mod_rewrite_rules() is called. This |
135 | * forces that to be true so updates from WP CLI work. |
136 | */ |
137 | if ( defined( 'WP_CLI' ) && WP_CLI ) { |
138 | add_filter( 'got_rewrite', '__return_true' ); |
139 | } |
140 | |
141 | if ( |
142 | isset( $_REQUEST['action'], $_REQUEST['plugin'] ) && |
143 | 'activate' === $_REQUEST['action'] && |
144 | $_REQUEST['plugin'] === $this->container->plugin()->basename |
145 | ) { |
146 | add_filter( |
147 | 'mod_rewrite_rules', |
148 | function ( $content ) { |
149 | add_action( |
150 | 'shutdown', |
151 | function () { |
152 | do_action( 'newfold_update_htaccess' ); |
153 | } |
154 | ); |
155 | return $content; |
156 | } |
157 | ); |
158 | } |
159 | |
160 | add_filter( 'action_scheduler_retention_period', array( $this, 'nfd_asr_default' ) ); |
161 | add_filter( 'action_scheduler_cleanup_batch_size', array( $this, 'nfd_as_cleanup_batch_size' ) ); |
162 | } |
163 | |
164 | /** |
165 | * Remove EPC Settings if needed |
166 | * |
167 | * @return void |
168 | */ |
169 | public function remove_epc_settings() { |
170 | global $wp_settings_fields, $wp_settings_sections; |
171 | //phpcs:ignore |
172 | // Remove the setting from EPC if it exists - TODO: Remove when no longer using EPC |
173 | if ( $this->container->get( 'hasMustUsePlugin' ) ) { |
174 | unset( $wp_settings_fields['general']['epc_settings_section'] ); |
175 | unset( $wp_settings_sections['general']['epc_settings_section'] ); |
176 | unregister_setting( 'general', 'endurance_cache_level' ); |
177 | unregister_setting( 'general', 'epc_skip_404_handling' ); |
178 | } |
179 | } |
180 | |
181 | /** |
182 | * Update the default action scheduler retention period to 5 days instead of 30. |
183 | * The actions scheduler table tends to grow to gigantic sizes and this should help. |
184 | * |
185 | * @hooked action_scheduler_retention_period |
186 | * @see ActionScheduler_QueueCleaner::delete_old_actions() |
187 | * |
188 | * @return int New retention period in seconds. |
189 | */ |
190 | public function nfd_asr_default() { |
191 | return 5 * constant( 'DAY_IN_SECONDS' ); |
192 | } |
193 | |
194 | /** |
195 | * Increase the batch size for the cleanup process from default of 20 to 1000. |
196 | * |
197 | * @hooked action_scheduler_cleanup_batch_size |
198 | * @see ActionScheduler_QueueCleaner::get_batch_size() |
199 | * |
200 | * @param int $batch_size Existing batch size; default is 20. |
201 | * |
202 | * @return int 1000 when running the cleanup process, otherwise the existing batch size. |
203 | */ |
204 | public function nfd_as_cleanup_batch_size( $batch_size ) { |
205 | /** |
206 | * Apply only to {@see ActionScheduler_QueueCleaner::delete_old_actions()} and not to |
207 | * {@see ActionScheduler_QueueCleaner::reset_timeouts()} or |
208 | * {@see ActionScheduler_QueueCleaner::mark_failures()} batch sizes. |
209 | */ |
210 | if ( ! did_filter( 'action_scheduler_retention_period' ) ) { |
211 | return $batch_size; |
212 | } |
213 | |
214 | return 1000; |
215 | } |
216 | |
217 | /** |
218 | * Add options to the WordPress admin bar. |
219 | * |
220 | * @param \WP_Admin_Bar $wp_admin_bar the admin bar. |
221 | */ |
222 | public function admin_bar_menu( \WP_Admin_Bar $wp_admin_bar ) { |
223 | |
224 | // If the EPC MU plugin exists, remove its cache clearing options. |
225 | if ( $this->container->get( 'hasMustUsePlugin' ) ) { |
226 | $wp_admin_bar->remove_node( 'epc_purge_menu' ); |
227 | } |
228 | |
229 | if ( current_user_can( 'manage_options' ) ) { |
230 | $wp_admin_bar->add_node( |
231 | array( |
232 | 'id' => 'nfd_purge_menu', |
233 | 'title' => __( 'Caching', 'wp-module-performance' ), |
234 | ) |
235 | ); |
236 | |
237 | $cache_level = get_cache_level(); |
238 | if ( $cache_level > 0 ) { |
239 | $wp_admin_bar->add_node( |
240 | array( |
241 | 'id' => 'nfd_purge_menu-purge_all', |
242 | 'title' => __( 'Purge All', 'wp-module-performance' ), |
243 | 'parent' => 'nfd_purge_menu', |
244 | 'href' => add_query_arg( array( self::PURGE_ALL => true ) ), |
245 | ) |
246 | ); |
247 | |
248 | if ( ! is_admin() ) { |
249 | $wp_admin_bar->add_node( |
250 | array( |
251 | 'id' => 'nfd_purge_menu-purge_single', |
252 | 'title' => __( 'Purge This Page', 'wp-module-performance' ), |
253 | 'parent' => 'nfd_purge_menu', |
254 | 'href' => add_query_arg( array( self::PURGE_URL => true ) ), |
255 | ) |
256 | ); |
257 | } |
258 | } |
259 | |
260 | $wp_admin_bar->add_node( |
261 | array( |
262 | 'id' => 'nfd_purge_menu-cache_settings', |
263 | 'title' => __( 'Cache Settings', 'wp-module-performance' ), |
264 | 'parent' => 'nfd_purge_menu', |
265 | 'href' => admin_url( 'tools.php?page=' . self::PAGE_SLUG ), |
266 | ) |
267 | ); |
268 | } |
269 | } |
270 | |
271 | /** |
272 | * Adds the Performance module to the WordPress Tools > Site Health menu. |
273 | * |
274 | * @return void |
275 | */ |
276 | public function add_management_page() { |
277 | |
278 | add_management_page( |
279 | __( 'Performance', 'wp-module-performance' ), |
280 | __( 'Performance', 'wp-module-performance' ), |
281 | 'manage_options', |
282 | self::PAGE_SLUG, |
283 | array( __CLASS__, 'render_performance_app' ) |
284 | ); |
285 | } |
286 | |
287 | /** |
288 | * Add to the Newfold subnav. |
289 | * |
290 | * @param array $subnav The nav array. |
291 | * @return array The filtered nav array |
292 | */ |
293 | public function add_nfd_subnav( $subnav ) { |
294 | $performance = array( |
295 | 'route' => self::PAGE_SLUG, |
296 | 'title' => __( 'Performance', 'wp-module-performance' ), |
297 | 'priority' => 30, |
298 | ); |
299 | array_push( $subnav, $performance ); |
300 | return $subnav; |
301 | } |
302 | |
303 | /** |
304 | * Outputs the HTML container for the Performance module's React application. |
305 | * |
306 | * @return void |
307 | */ |
308 | public static function render_performance_app() { |
309 | echo PHP_EOL; |
310 | echo '<!-- NFD:PERFORMANCE -->'; |
311 | echo PHP_EOL; |
312 | echo '<div id="' . esc_attr( self::PAGE_SLUG ) . '" class="' . esc_attr( self::PAGE_SLUG ) . '-container"></div>'; |
313 | echo PHP_EOL; |
314 | echo '<!-- /NFD:PERFORMANCE -->'; |
315 | echo PHP_EOL; |
316 | } |
317 | |
318 | /** |
319 | * Initializes the Performance module by registering and enqueuing its assets. |
320 | * |
321 | * @return void |
322 | */ |
323 | public static function initialize_performance_app() { |
324 | self::register_performance_assets(); |
325 | } |
326 | |
327 | /** |
328 | * Registers and enqueues the JavaScript and CSS assets for the Performance module. |
329 | * |
330 | * @return void |
331 | */ |
332 | public static function register_performance_assets() { |
333 | $build_dir = NFD_PERFORMANCE_BUILD_DIR; |
334 | $build_url = NFD_PERFORMANCE_BUILD_URL; |
335 | $asset_file = $build_dir . '/performance/performance.min.asset.php'; |
336 | |
337 | if ( is_readable( $asset_file ) ) { |
338 | $asset = include_once $asset_file; |
339 | |
340 | wp_register_script( |
341 | self::PAGE_SLUG, |
342 | $build_url . '/performance/performance.min.js', |
343 | $asset['dependencies'], |
344 | $asset['version'], |
345 | true |
346 | ); |
347 | |
348 | wp_register_style( |
349 | self::PAGE_SLUG, |
350 | $build_url . '/performance/performance.min.css', |
351 | array(), |
352 | $asset['version'] |
353 | ); |
354 | |
355 | wp_enqueue_script( self::PAGE_SLUG ); |
356 | wp_enqueue_style( self::PAGE_SLUG ); |
357 | } |
358 | } |
359 | } |