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