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