PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / trunk
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization vtrunk
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / classes / WordPress / CLI.php
nitropack / classes / WordPress Last commit date
AdvancedCache 3 days ago Notifications 3 days ago Settings 3 days ago Admin.php 1 month ago CLI.php 3 days ago Config.php 1 year ago ConflictingPlugins.php 10 months ago Connect.php 3 days ago Cron.php 1 year ago Invalidations.php 2 months ago NitroPack.php 3 days ago Settings.php 4 months ago
CLI.php
673 lines
1 <?php
2
3 namespace NitroPack\WordPress;
4
5 use \WP_CLI;
6 use NitroPack\WordPress\Settings\OptimizationLevel;
7
8 defined( 'ABSPATH' ) || die( 'No script kiddies please!' );
9
10 class CLI {
11 /**
12 * Pair of public and private keys
13 *
14 * @var null|object
15 */
16 protected $keys;
17 /**
18 * Logger for logging events
19 *
20 * @var null|object
21 */
22 private $logger;
23 public function init() {
24 add_action( 'init', [ $this, 'register_hooks' ] );
25 $this->logger = NitroPack::getInstance()->getLogger();
26 }
27 public function register_hooks() {
28
29 $is_wp_cli = nitropack_is_wp_cli();
30
31 if ( ! is_admin() && ! $is_wp_cli && ! is_user_logged_in() )
32 return;
33
34 WP_CLI::add_command( "nitropack connect", [ $this, "nitropack_cli_connect" ] );
35 WP_CLI::add_command( "nitropack disconnect", [ $this, "nitropack_cli_disconnect" ] );
36 WP_CLI::add_command( "nitropack purge", [ $this, "nitropack_cli_purge" ] );
37 WP_CLI::add_command( "nitropack invalidate", [ $this, "nitropack_cli_invalidate" ] );
38 WP_CLI::add_command( "nitropack mode", [ $this, "nitropack_mode" ] );
39 WP_CLI::add_command( 'nitropack preview', [ $this, 'nitropack_preview' ] );
40 WP_CLI::add_command( "nitropack warmup", [ $this, "nitropack_warmup" ] );
41 WP_CLI::add_command( 'nitropack urls', [ $this, 'nitropack_urls' ] );
42 WP_CLI::add_command( 'nitropack excludedurls', [ $this, 'nitropack_excluded_urls' ] );
43 WP_CLI::add_command( 'nitropack excludes', [ $this, 'nitropack_excludes' ] );
44 }
45 /**
46 * Get site configuration.
47 *
48 * @return null|array Returns site configuration on success or exits with an error.
49 */
50 protected function get_site_config() {
51 $site_config = nitropack_get_site_config();
52 if ( empty( $site_config['siteId'] ) || empty( $site_config['siteSecret'] ) ) {
53 $this->logger->error( 'Cannot connect. The Site ID or Site Secret is missing' );
54 WP_CLI::error( 'Cannot connect. The Site ID or Site Secret is missing!' );
55 return;
56 }
57 return $site_config;
58 }
59 /**
60 * Generate and get public and private keys.
61 *
62 * @return object
63 */
64 protected function keys_instance() {
65 // This must be executed only once per request.
66 if ( empty( $this->keys ) ) {
67 $this->keys = \NitroPack\SDK\Crypto::generateKeyPair();
68 }
69
70 return $this->keys;
71 }
72 /**
73 * Get vendor API.
74 *
75 * @return \NitroPack\SDK\Api API.
76 */
77 protected function get_vendor_api() {
78 $nitro = get_nitropack_sdk();
79 return $nitro->getApi();
80 }
81 /**
82 * Connects a website to NitroPack
83 *
84 * ## OPTIONS
85 *
86 * <siteID>
87 * : The API Key obtained from https://nitropack.io/user/connect
88 *
89 * <siteSecret>
90 * : The API Secret Key obtained from https://nitropack.io/user/connect
91 *
92 * Example: wp nitropack connect siteID siteSecret
93 */
94
95 public function nitropack_cli_connect( $args, $assocArgs ) {
96 $siteId = ! empty( $args[0] ) ? $args[0] : "";
97 $siteSecret = ! empty( $args[1] ) ? $args[1] : "";
98 $nitropack_connect = new \NitroPack\WordPress\Connect;
99 $nitropack_connect->nitropack_verify_connect( $siteId, $siteSecret );
100 }
101
102 /**
103 * Disconnects a website from NitroPack
104 * Example: wp nitropack disconnect
105 */
106
107 public function nitropack_cli_disconnect( $args, $assocArgs ) {
108 $nitropack_connect = new \NitroPack\WordPress\Connect;
109 $nitropack_connect->nitropack_disconnect();
110 }
111
112 /**
113 * Purges a website's cache
114 * Example: wp nitropack purge
115 */
116
117 public function nitropack_cli_purge( $args, $assocArgs ) {
118 $host = ! empty( $assocArgs["purge-host"] ) ? $assocArgs["purge-host"] : NULL;
119 $url = ! empty( $assocArgs["purge-url"] ) ? $assocArgs["purge-url"] : NULL;
120 $tag = ! empty( $assocArgs["purge-tag"] ) ? $assocArgs["purge-tag"] : NULL;
121 $reason = ! empty( $assocArgs["purge-reason"] ) ? $assocArgs["purge-reason"] . ' via WP-CLI' : 'Light purge of all caches via WP-CLI';
122
123 if ( ! empty( $host ) ) {
124 /**
125 * Override the site url by the purge-host parameter
126 *
127 * @param string $host
128 * @return string
129 */
130 add_filter(
131 'nitropack_current_host',
132 function () use ($host) {
133 if ( ! preg_match( '#^http(s)?://#', $host ) ) {
134 $host = 'https://' . $host;
135 }
136 return $host;
137 }
138 );
139 }
140
141 if ( $url || $tag || $reason ) {
142 try {
143 if ( nitropack_sdk_purge( $url, $tag, $reason ) ) {
144 $this->logger->notice( 'Cache has been purged' );
145 WP_CLI::success( 'Cache has been purged.' );
146 }
147 } catch (\Exception $e) {
148 $this->logger->error( 'Cannot purge cache. Error: ' . $e );
149 WP_CLI::error( sprintf( 'Cannot purge cache. Error: %s', $e ) );
150 }
151 }
152 }
153
154 /**
155 * Invalidate a website's cache
156 * Example: wp nitropack invalidate
157 */
158
159 public function nitropack_cli_invalidate( $args, $assocArgs ) {
160 $url = ! empty( $assocArgs["purge-url"] ) ? $assocArgs["purge-url"] : NULL;
161 $tag = ! empty( $assocArgs["purge-tag"] ) ? $assocArgs["purge-tag"] : NULL;
162 $reason = ! empty( $assocArgs["purge-reason"] ) ? $assocArgs["purge-reason"] . ' via WP-CLI' : 'Manual invalidation of all pages via WP-CLI';
163 if ( $url || $tag || $reason ) {
164 try {
165 if ( nitropack_sdk_invalidate( $url, $tag, $reason ) ) {
166 $this->logger->notice( 'Cache has been invalidated' );
167 WP_CLI::success( 'Cache has been invalidated.' );
168 }
169 } catch (\Exception $e) {
170 $this->logger->error( 'Cannot invalidate cache. Error: ' . $e );
171 WP_CLI::error( sprintf( 'Error, cannot invalidate cache. %s', $e ) );
172 }
173 }
174 }
175 /**
176 * Start of PSB commands from WPEngine below.
177 *
178 * Set NitroPack mode.
179 *
180 * ## OPTIONS
181 *
182 * [<mode>]
183 * : Read or change mode.
184 *
185 * options:
186 * - 0 - off - readable only
187 * - 1 - standard
188 * - 2 - medium
189 * - 3 - strong
190 * - 4 - ludicrous
191 * - 5 - ludicrous+ for PSB only
192 * - 5/6 - custom - readable only
193 *
194 * Example: wp nitropack mode 3
195 * @when before_wp_load
196 *
197 * @param array $args Command arguments.
198 * @param array $assoc_args Command parameters.
199 */
200
201 public function nitropack_mode( $args ) {
202 //check it if the mode is number
203 $mode = isset( $args[0] ) ? intval( $args[0] ) : null;
204 $optimization_class = new OptimizationLevel();
205 //fetch the available modes for the website
206 $modes = $optimization_class->optimization_modes()['optimization_options'];
207 $modes_max = count( $modes ) - 1; // Subtract 1 to exclude the "custom" option
208 if ( $mode !== null && ( 1 > $mode || $modes_max < $mode ) ) {
209 $this->logger->error( 'The mode is invalid! Valid modes are from 1-' . $modes_max );
210 WP_CLI::error( 'The mode is invalid! Valid modes are from 1-' . $modes_max . '.' );
211 return;
212 }
213 $site_config = $this->get_site_config();
214 $keys = $this->keys_instance();
215 $url = new \NitroPack\SDK\IntegrationUrl( $mode ? 'quicksetup' : 'quicksetup_json', $site_config['siteId'], $site_config['siteSecret'] );
216 $headers = [
217 'X-Nitro-Public-Key' => base64_encode( $keys->publicKey ), // phpcs:ignore
218 ];
219
220 if ( $mode ) {
221 $response = \wp_remote_post(
222 $url->getUrl(),
223 [
224 'headers' => $headers,
225 'body' => [
226 'setting' => $mode,
227 ],
228 ]
229 );
230 } else {
231 $response = \wp_remote_get( $url->getUrl(), [ 'headers' => $headers ] );
232 }
233
234 if ( is_wp_error( $response ) ) {
235 /**
236 * Response error.
237 *
238 * @var WP_Error $error
239 */
240 $error = $response;
241 $this->logger->error( 'Optimization mode failed. Error: ' . $error->get_error_message() );
242 WP_CLI::error( $error->get_error_message() );
243 return;
244 }
245
246 if ( 200 !== $response['response']['code'] ) {
247 $this->logger->error( 'Optimization mode failed. Response: ' . $response['response']['code'] );
248 WP_CLI::debug( sprintf( 'Response body: %s.', $response['body'] ) );
249 WP_CLI::error( sprintf( 'Request has failed with %d %s.', $response['response']['code'], $response['response']['message'] ) );
250 return;
251 }
252 $mode_name = $optimization_class->fetch_optimization_name();
253 if ( $mode ) {
254 $this->logger->notice( 'Mode has been changed to ' . $mode_name . ')' );
255 WP_CLI::success( 'Mode has been changed to ' . $mode_name . '.' );
256 return;
257 }
258
259 $body = @json_decode( $response['body'], true ); // phpcs:ignore
260 if ( empty( $body['optimization_level'] ) ) {
261 $this->logger->error( 'Mode is missing in the response body' );
262 WP_CLI::error( 'Mode is missing in the response body!' );
263 return;
264 }
265
266 $this->logger->notice( 'Mode is ' . $mode_name . '' );
267 WP_CLI::success( sprintf( 'Mode is %s.', $mode_name ) );
268 }
269 /**
270 * NitroPack test mode.
271 *
272 * ## OPTIONS
273 *
274 * [<command>]
275 * : Get test mode status or change it.
276 * ---
277 * default: status
278 * options:
279 * - status
280 * - disable
281 * - enable
282 * ---
283 *
284 * @when before_wp_load
285 *
286 * @param array $args Command arguments.
287 * @param array $assoc_args Command parameters.
288 */
289 public function nitropack_preview( $args, $assoc_args ) {
290 $this->get_site_config();
291
292 /**
293 * SDK.
294 *
295 * @var \NitroPack\SDK\NitroPack $sdk
296 */
297 $sdk = get_nitropack()->getSdk();
298 try {
299 $command = empty( $args[0] ) ? 'status' : $args[0];
300 if ( 'enable' === $command ) {
301 $sdk->enableSafeMode();
302 } elseif ( 'disable' === $command ) {
303 $sdk->disableSafeMode();
304 } else {
305 $api = $this->get_vendor_api();
306 $status = $api->isSafeModeEnabled();
307 $this->logger->notice( 'Test mode is ' . ( $status ? 'enabled' : 'disabled' ) );
308 WP_CLI::success( sprintf( 'Test mode is %s.', $status ? 'enabled' : 'disabled' ) );
309 nitropack_fetch_config(); // Fetch the config to update SafeMode in the local cache file
310 return;
311 }
312 } catch (\Exception $e) {
313 $this->logger->error( 'Fail to ' . $command . ' test mode. Error: ' . $e->getMessage() );
314 WP_CLI::error( $e->getMessage(), false );
315 WP_CLI::error( sprintf( 'Failed to %s test mode.', $command ) );
316 return;
317 }
318 $this->logger->notice( 'Test mode has been ' . $command . 'd' );
319 WP_CLI::success( sprintf( 'Test mode has been %sd.', $command ) );
320 }
321 /**
322 * NitroPack cache warmup.
323 *
324 * ## OPTIONS
325 *
326 * [<command>]
327 * : Get cache warmup status or change it.
328 * ---
329 * default: status
330 * options:
331 * - status
332 * - disable
333 * - enable
334 * ---
335 *
336 * @when before_wp_load
337 *
338 * @param array $args Command arguments.
339 * @param array $assoc_args Command parameters.
340 */
341 public function nitropack_warmup( $args, $assoc_args ) {
342 $this->get_site_config();
343
344 $command = empty( $args[0] ) ? 'status' : $args[0];
345
346 /* Starts a warmup process for a website */
347 if ( 'run' === $command ) {
348 nitropack_run_warmup();
349 return;
350 }
351 /* Enables AND runs a warmup process for a website */
352 if ( 'enable' === $command ) {
353 nitropack_enable_warmup();
354 return;
355 }
356 /* Disables the warmup process for a website */
357 if ( 'disable' === $command ) {
358 nitropack_disable_warmup();
359 return;
360 }
361
362 try {
363 $api = $this->get_vendor_api();
364 $stats = $api->getWarmupStats();
365 if ( isset( $stats['status'] ) ) {
366 $stats['status'] = $stats['status'] ? 'enabled' : 'disabled';
367 }
368 WP_CLI\Utils\format_items(
369 'yaml',
370 array(
371 array(
372 'warmup' => $stats,
373 ),
374 ),
375 array(
376 'warmup',
377 )
378 );
379 $this->logger->notice( 'Get warmup status: ' . $stats['status'] );
380 } catch (\Exception $e) {
381 $this->logger->error( 'Failed to fetch warmup status. Error: ' . $e->getMessage() );
382 WP_CLI::error( $e->getMessage(), false );
383 WP_CLI::error( 'Failed to fetch warmup stats.' );
384 return;
385 }
386 }
387 /**
388 * NitroPack optimized URLs.
389 *
390 * ## OPTIONS
391 *
392 * [<command>]
393 * : Get optimized URLs or pending optimization.
394 * ---
395 * default: optimized
396 * options:
397 * - optimized
398 * - pending
399 * ---
400 *
401 * @when before_wp_load
402 *
403 * @param array $args Command arguments.
404 * @param array $assoc_args Command parameters.
405 */
406 public function nitropack_urls( $args, $assoc_args ) {
407 $this->get_site_config();
408
409 $command = empty( $args[0] ) ? 'optimized' : $args[0];
410
411 try {
412 $api = $this->get_vendor_api();
413 $result = array();
414 if ( 'optimized' === $command ) {
415 $result = $api->getUrls();
416 $this->logger->notice( 'Get optimized URLs' );
417 } elseif ( 'pending' === $command ) {
418 $result = $api->getPendingUrls();
419 $this->logger->notice( 'Get pending for optimization URLs' );
420 }
421
422 WP_CLI\Utils\format_items(
423 'yaml',
424 array(
425 array(
426 'urls' => $result,
427 ),
428 ),
429 array(
430 'urls',
431 )
432 );
433 } catch (\Exception $e) {
434 $this->logger->error( 'Get Optimized URLs. Error - ' . $e->getMessage() );
435 WP_CLI::error( $e->getMessage(), false );
436 WP_CLI::error( 'Failed to fetch URLs.' );
437 return;
438 }
439 }
440 /**
441 * NitroPack excluded URLs.
442 *
443 * ## OPTIONS
444 *
445 * [<command>]
446 * : Control excluded URLs.
447 * ---
448 * default: get
449 * options:
450 * - enable
451 * - disable
452 * - get
453 * - add
454 * - remove
455 * ---
456 *
457 * [<url_pattern>]
458 * : URL pattern.
459 *
460 * ## EXAMPLES
461 *
462 * # Enable feature to exclude any URL
463 * $ wp psb excludedurls enable
464 *
465 * # Exclude a contact page
466 * $ wp psb excludedurls add *\/contact
467 *
468 * @when before_wp_load
469 *
470 * @param array $args Command arguments.
471 * @param array $assoc_args Command parameters.
472 */
473 public function nitropack_excluded_urls( $args, $assoc_args ) {
474 $site_config = $this->get_site_config();
475
476 $command = empty( $args[0] ) ? '' : $args[0];
477 $url_pattern = empty( $args[1] ) ? '' : $args[1];
478
479 if ( ( 'add' === $command || 'remove' === $command ) && ! $url_pattern ) {
480 $this->logger->error( 'Enter valid URL' );
481 WP_CLI::error( 'Enter valid URL.' );
482 return;
483 }
484
485 try {
486 $api = $this->get_vendor_api();
487 switch ( $command ) {
488 case 'enable':
489 $api->enableExcludedUrls();
490 break;
491 case 'disable':
492 $api->disableExcludedUrls();
493 break;
494 case 'get':
495 $fetcher = new \NitroPack\SDK\Api\RemoteConfigFetcher( $site_config['siteId'], $site_config['siteSecret'] );
496 $response = $fetcher->get();
497 $config = @json_decode( $response, true ); // phpcs:ignore
498 if ( ! array_key_exists( 'DisabledURLs', $config ) ) {
499 $this->logger->error( 'Disabled URLs are not present in the respone. Vendor API might changed' );
500 WP_CLI::error( 'Disabled URLs are not present in the respone. Vendor API might changed.' );
501 return;
502 }
503 WP_CLI\Utils\format_items(
504 'yaml',
505 array(
506 array(
507 'excludes' => $config['DisabledURLs'],
508 ),
509 ),
510 array(
511 'excludes',
512 )
513 );
514 $this->logger->notice( 'Get excluded URLs' );
515 return;
516 case 'add':
517 $api->addExcludedUrl( $url_pattern );
518 $this->logger->notice( 'Add excluded URLs' );
519 break;
520 case 'remove':
521 $api->removeExcludedUrl( $url_pattern );
522 $this->logger->notice( 'Remove excluded URLs' );
523 break;
524 default:
525 $this->logger->error( 'Excluded URLs - enter valid sub-command.' );
526 WP_CLI::error( 'Enter valid sub-command.' );
527 return;
528 }
529 } catch (\Exception $e) {
530 $this->logger->error( "Failed to '" . $command . "' excluded URLs. Error: " . $e->getMessage() );
531 WP_CLI::error( $e->getMessage(), false );
532 WP_CLI::error( sprintf( 'Failed in %s excluded URL(s).', $command ) );
533 return;
534 }
535 $this->logger->notice( "Succeeded to '" . $command . "' excluded URL(s)" );
536 WP_CLI::success( sprintf( 'Succeeded to %s excluded URL(s).', $command ) );
537 }
538 /**
539 * NitroPack - JS, CSS, image, font excludes.
540 *
541 * ## OPTIONS
542 *
543 * [<command>]
544 * : Control excluded asset.
545 * ---
546 * default: get
547 * options:
548 * - enable
549 * - disable
550 * - get
551 * - add
552 * - remove
553 * ---
554 *
555 * [<url_pattern>]
556 * : URL pattern.
557 *
558 * [--resource=<type>]
559 * : Limit exclusion to a specific resource type.
560 * ---
561 * default: any
562 * options:
563 * - any
564 * - css
565 * - js
566 * - font
567 * - image
568 * ---
569 *
570 * [--device=<type>]
571 * : Limit exclusion to a specific device.
572 * ---
573 * default: any
574 * options:
575 * - any
576 * - desktop
577 * - tablet
578 * - mobile
579 * ---
580 *
581 * ## EXAMPLES
582 *
583 * # Enable feature to exclude any resource
584 * $ wp psb excludes enable
585 *
586 * # Exclude a contact page
587 * $ wp psb excludes add *\/script.js --resource=js
588 *
589 * @when before_wp_load
590 *
591 * @param array $args Command arguments.
592 * @param array $assoc_args Command parameters.
593 */
594 public function nitropack_excludes( $args, $assoc_args ) {
595 $this->get_site_config();
596
597 if ( ! class_exists( '\NitroPack\SDK\ExcludeEntry' ) ) {
598 $this->logger->error( 'The dependent plugin is incompatible' );
599 WP_CLI::error( 'The dependent plugin is incompatible.' );
600 return;
601 }
602
603 $command = empty( $args[0] ) ? '' : $args[0];
604 $url_pattern = empty( $args[1] ) ? '' : $args[1];
605
606 if ( ( 'add' === $command || 'remove' === $command ) && ! $url_pattern ) {
607 $this->logger->error( 'Enter valid URL' );
608 WP_CLI::error( 'Enter valid URL.' );
609 return;
610 }
611
612 try {
613 $api = $this->get_vendor_api();
614 switch ( $command ) {
615 case 'enable':
616 $api->enableExcludes();
617 break;
618 case 'disable':
619 $api->disableExcludes();
620 break;
621 case 'get':
622 $all_excludes = $api->getExcludes();
623 WP_CLI\Utils\format_items(
624 'yaml',
625 array(
626 array(
627 'excludes' => $all_excludes,
628 ),
629 ),
630 array(
631 'excludes',
632 )
633 );
634 $this->logger->notice( 'Get excludes' );
635 return;
636 case 'add':
637 $all_excludes = $api->getExcludes();
638
639 $new_exclude = new \NitroPack\SDK\ExcludeEntry();
640 $new_exclude->string = $url_pattern;
641 $new_exclude->device = empty( $assoc_args['device'] ) || 'any' === $assoc_args['device'] ? null : $assoc_args['device'];
642 $new_exclude->resourceType = empty( $assoc_args['resource'] ) || 'any' === $assoc_args['resource'] ? null : $assoc_args['resource']; // phpcs:ignore
643 $new_exclude->operation->all = true;
644
645 $all_excludes[] = $new_exclude;
646 $api->setExcludes( $all_excludes );
647 break;
648 case 'remove':
649 $all_excludes = $api->getExcludes();
650 $all_excludes = array_filter(
651 $all_excludes,
652 function ( $exclusion ) use ( $url_pattern ) {
653 return $exclusion->string !== $url_pattern;
654 }
655 );
656 $api->setExcludes( $all_excludes );
657 break;
658 default:
659 $this->logger->error( 'Enter valid sub-command' );
660 WP_CLI::error( 'Enter valid sub-command.' );
661 return;
662 }
663 } catch (\Exception $e) {
664 $this->logger->error( "Failed to '" . $command . "' exclude. Error: " . $e->getMessage() );
665 WP_CLI::error( $e->getMessage(), false );
666 WP_CLI::error( sprintf( 'Failed to %s exclude(s).', $command ) );
667 return;
668 }
669 $this->logger->notice( "Succeeded to '" . $command . "' exclude(s)" );
670 WP_CLI::success( sprintf( 'Succeeded to %s exclude(s).', $command ) );
671 }
672 }
673