HEX
Server: LiteSpeed
System: Linux eko108.isimtescil.net 4.18.0-477.21.1.lve.1.el8.x86_64 #1 SMP Tue Sep 5 23:08:35 UTC 2023 x86_64
User: uyarreklamcomtr (11202)
PHP: 7.4.33
Disabled: opcache_get_status
Upload Files
File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/cli.tar
crawler.cls.php000064400000012225151540213720007476 0ustar00<?php

namespace LiteSpeed\CLI;

defined('WPINC') || exit();

use LiteSpeed\Debug2;
use LiteSpeed\Base;
use LiteSpeed\Task;
use LiteSpeed\Crawler as Crawler2;
use WP_CLI;

/**
 * Crawler
 */
class Crawler extends Base
{
	private $__crawler;

	public function __construct()
	{
		Debug2::debug('CLI_Crawler init');

		$this->__crawler = Crawler2::cls();
	}

	/**
	 * List all crawler
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # List all crawlers
	 *     $ wp litespeed-crawler l
	 *
	 */
	public function l()
	{
		$this->list();
	}

	/**
	 * List all crawler
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # List all crawlers
	 *     $ wp litespeed-crawler list
	 *
	 */
	public function list()
	{
		$crawler_list = $this->__crawler->list_crawlers();
		$summary = Crawler2::get_summary();
		if ($summary['curr_crawler'] >= count($crawler_list)) {
			$summary['curr_crawler'] = 0;
		}
		$is_running = time() - $summary['is_running'] <= 900;

		$CRAWLER_RUN_INTERVAL = defined('LITESPEED_CRAWLER_RUN_INTERVAL') ? LITESPEED_CRAWLER_RUN_INTERVAL : 600; // Specify time in seconds for the time between each run interval
		if ($CRAWLER_RUN_INTERVAL > 0) {
			$recurrence = '';
			$hours = (int) floor($CRAWLER_RUN_INTERVAL / 3600);
			if ($hours) {
				if ($hours > 1) {
					$recurrence .= sprintf(__('%d hours', 'litespeed-cache'), $hours);
				} else {
					$recurrence .= sprintf(__('%d hour', 'litespeed-cache'), $hours);
				}
			}
			$minutes = (int) floor(($CRAWLER_RUN_INTERVAL % 3600) / 60);
			if ($minutes) {
				$recurrence .= ' ';
				if ($minutes > 1) {
					$recurrence .= sprintf(__('%d minutes', 'litespeed-cache'), $minutes);
				} else {
					$recurrence .= sprintf(__('%d minute', 'litespeed-cache'), $minutes);
				}
			}
		}

		$list = array();
		foreach ($crawler_list as $i => $v) {
			$hit = !empty($summary['crawler_stats'][$i][Crawler2::STATUS_HIT]) ? $summary['crawler_stats'][$i][Crawler2::STATUS_HIT] : 0;
			$miss = !empty($summary['crawler_stats'][$i][Crawler2::STATUS_MISS]) ? $summary['crawler_stats'][$i][Crawler2::STATUS_MISS] : 0;

			$blacklisted = !empty($summary['crawler_stats'][$i][Crawler2::STATUS_BLACKLIST]) ? $summary['crawler_stats'][$i][Crawler2::STATUS_BLACKLIST] : 0;
			$blacklisted += !empty($summary['crawler_stats'][$i][Crawler2::STATUS_NOCACHE]) ? $summary['crawler_stats'][$i][Crawler2::STATUS_NOCACHE] : 0;

			if (isset($summary['crawler_stats'][$i][Crawler2::STATUS_WAIT])) {
				$waiting = $summary['crawler_stats'][$i][Crawler2::STATUS_WAIT] ?: 0;
			} else {
				$waiting = $summary['list_size'] - $hit - $miss - $blacklisted;
			}

			$analytics = 'Waiting: ' . $waiting;
			$analytics .= '     Hit: ' . $hit;
			$analytics .= '     Miss: ' . $miss;
			$analytics .= '     Blocked: ' . $blacklisted;

			$running = '';
			if ($i == $summary['curr_crawler']) {
				$running = 'Pos: ' . ($summary['last_pos'] + 1);
				if ($is_running) {
					$running .= '(Running)';
				}
			}

			$status = $this->__crawler->is_active($i) ? '✅' : '❌';

			$list[] = array(
				'ID' => $i + 1,
				'Name' => wp_strip_all_tags($v['title']),
				'Frequency' => $recurrence,
				'Status' => $status,
				'Analytics' => $analytics,
				'Running' => $running,
			);
		}

		WP_CLI\Utils\format_items('table', $list, array('ID', 'Name', 'Frequency', 'Status', 'Analytics', 'Running'));
	}

	/**
	 * Enable one crawler
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Turn on 2nd crawler
	 *     $ wp litespeed-crawler enable 2
	 *
	 */
	public function enable($args)
	{
		$id = $args[0] - 1;
		if ($this->__crawler->is_active($id)) {
			WP_CLI::error('ID #' . $id . ' had been enabled');
			return;
		}

		$this->__crawler->toggle_activeness($id);
		WP_CLI::success('Enabled crawler #' . $id);
	}

	/**
	 * Disable one crawler
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Turn off 1st crawler
	 *     $ wp litespeed-crawler disable 1
	 *
	 */
	public function disable($args)
	{
		$id = $args[0] - 1;
		if (!$this->__crawler->is_active($id)) {
			WP_CLI::error('ID #' . $id . ' has been disabled');
			return;
		}

		$this->__crawler->toggle_activeness($id);
		WP_CLI::success('Disabled crawler #' . $id);
	}

	/**
	 * Run crawling
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Start crawling
	 *     $ wp litespeed-crawler r
	 *
	 */
	public function r()
	{
		$this->run();
	}

	/**
	 * Run crawling
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Start crawling
	 *     $ wp litespeed-crawler run
	 *
	 */
	public function run()
	{
		self::debug('⚠️⚠️⚠️ Forced take over lane (CLI)');
		$this->__crawler->Release_lane();

		Task::async_call('crawler');

		$summary = Crawler2::get_summary();

		WP_CLI::success('Start crawling. Current crawler #' . ($summary['curr_crawler'] + 1) . ' [position] ' . $summary['last_pos'] . ' [total] ' . $summary['list_size']);
	}

	/**
	 * Reset position
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Reset crawler position
	 *     $ wp litespeed-crawler reset
	 *
	 */
	public function reset()
	{
		$this->__crawler->reset_pos();

		$summary = Crawler2::get_summary();

		WP_CLI::success('Reset position. Current crawler #' . ($summary['curr_crawler'] + 1) . ' [position] ' . $summary['last_pos'] . ' [total] ' . $summary['list_size']);
	}
}
debug.cls.php000064400000001044151540213720007122 0ustar00<?php
namespace LiteSpeed\CLI;
defined('WPINC') || exit();

use LiteSpeed\Debug2;
use LiteSpeed\Report;
use WP_CLI;

/**
 * Debug API CLI
 */
class Debug
{
	private $__report;

	public function __construct()
	{
		Debug2::debug('CLI_Debug init');

		$this->__report = Report::cls();
	}

	/**
	 * Send report
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Send env report to LiteSpeed
	 *     $ wp litespeed-debug send
	 *
	 */
	public function send()
	{
		$num = $this->__report->post_env();
		WP_CLI::success('Report Number = ' . $num);
	}
}
image.cls.php000064400000006454151540213720007130 0ustar00<?php

namespace LiteSpeed\CLI;

defined('WPINC') || exit();

use LiteSpeed\Lang;
use LiteSpeed\Debug2;
use LiteSpeed\Img_Optm;
use LiteSpeed\Utility;
use WP_CLI;

/**
 * Image Optm API CLI
 */
class Image
{
	private $__img_optm;

	public function __construct()
	{
		Debug2::debug('CLI_Cloud init');

		$this->__img_optm = Img_Optm::cls();
	}

	/**
	 * Batch toggle optimized images w/ original images
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Switch to original images
	 *     $ wp litespeed-image batch_switch orig
	 *
	 *     # Switch to optimized images
	 *     $ wp litespeed-image batch_switch optm
	 *
	 */
	public function batch_switch($param)
	{
		$type = $param[0];
		$this->__img_optm->batch_switch($type);
	}

	/**
	 * Send image optimization request to QUIC.cloud server
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Send image optimization request
	 *     $ wp litespeed-image push
	 *
	 */
	public function push()
	{
		$this->__img_optm->new_req();
	}

	/**
	 * Pull optimized images from QUIC.cloud server
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Pull images back from cloud
	 *     $ wp litespeed-image pull
	 *
	 */
	public function pull()
	{
		$this->__img_optm->pull(true);
	}

	/**
	 * Show optimization status based on local data
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Show optimization status
	 *     $ wp litespeed-image s
	 *
	 */
	public function s()
	{
		$this->status();
	}

	/**
	 * Show optimization status based on local data
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Show optimization status
	 *     $ wp litespeed-image status
	 *
	 */
	public function status()
	{
		$summary = Img_Optm::get_summary();
		$img_count = $this->__img_optm->img_count();
		foreach (Lang::img_status() as $k => $v) {
			if (isset($img_count["img.$k"])) {
				$img_count["$v - images"] = $img_count["img.$k"];
				unset($img_count["img.$k"]);
			}
			if (isset($img_count["group.$k"])) {
				$img_count["$v - groups"] = $img_count["group.$k"];
				unset($img_count["group.$k"]);
			}
		}

		foreach (array('reduced', 'reduced_webp', 'reduced_avif') as $v) {
			if (!empty($summary[$v])) {
				$summary[$v] = Utility::real_size($summary[$v]);
			}
		}

		if (!empty($summary['last_requested'])) {
			$summary['last_requested'] = date('m/d/y H:i:s', $summary['last_requested']);
		}

		$list = array();
		foreach ($summary as $k => $v) {
			$list[] = array('key' => $k, 'value' => $v);
		}

		$list2 = array();
		foreach ($img_count as $k => $v) {
			if (!$v) {
				continue;
			}
			$list2[] = array('key' => $k, 'value' => $v);
		}

		WP_CLI\Utils\format_items('table', $list, array('key', 'value'));

		WP_CLI::line(WP_CLI::colorize('%CImages in database summary:%n'));
		WP_CLI\Utils\format_items('table', $list2, array('key', 'value'));
	}

	/**
	 * Clean up unfinished image data from QUIC.cloud server
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Clean up unfinished requests
	 *     $ wp litespeed-image clean
	 *
	 */
	public function clean()
	{
		$this->__img_optm->clean();

		WP_CLI::line(WP_CLI::colorize('%CLatest status:%n'));

		$this->status();
	}

	/**
	 * Remove original image backups
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Remove original image backups
	 *     $ wp litespeed-image rm_bkup
	 *
	 */
	public function rm_bkup()
	{
		$this->__img_optm->rm_bkup();
	}
}
online.cls.php000064400000015500151540213720007322 0ustar00<?php

namespace LiteSpeed\CLI;

defined('WPINC') || exit();

use LiteSpeed\Debug2;
use LiteSpeed\Cloud;
use WP_CLI;

/**
 * QUIC.cloud API CLI
 */
class Online
{
	private $__cloud;

	public function __construct()
	{
		Debug2::debug('CLI_Cloud init');

		$this->__cloud = Cloud::cls();
	}

	/**
	 * Init domain on QUIC.cloud server (See https://quic.cloud/terms/)
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Activate domain on QUIC.cloud (! Require SERVER IP setting to be set first)
	 *     $ wp litespeed-online init
	 *
	 */
	public function init()
	{
		$resp = $this->__cloud->init_qc_cli();
		if (!empty($resp['qc_activated'])) {
			$main_domain = !empty($resp['main_domain']) ? $resp['main_domain'] : false;
			$this->__cloud->update_qc_activation($resp['qc_activated'], $main_domain);
			WP_CLI::success('Init successfully. Activated type: ' . $resp['qc_activated']);
		} else {
			WP_CLI::error('Init failed!');
		}
	}

	/**
	 * Init domain CDN service on QUIC.cloud server (See https://quic.cloud/terms/)
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Activate domain CDN on QUIC.cloud (support --format=json)
	 *	   $ wp litespeed-online cdn_init --method=cname|ns
	 *     $ wp litespeed-online cdn_init --method=cname|ns --ssl-cert=xxx.pem --ssl-key=xxx
	 *     $ wp litespeed-online cdn_init --method=cfi --cf-token=xxxxxxxx
	 *     $ wp litespeed-online cdn_init --method=cfi --cf-token=xxxxxxxx  --ssl-cert=xxx.pem --ssl-key=xxx
	 *
	 */
	public function cdn_init($args, $assoc_args)
	{
		if (empty($assoc_args['method'])) {
			WP_CLI::error('Init CDN failed! Missing parameters `--method`.');
			return;
		}
		if ((!empty($assoc_args['ssl-cert']) && empty($assoc_args['ssl-key'])) || (empty($assoc_args['ssl-cert']) && !empty($assoc_args['ssl-key']))) {
			WP_CLI::error('Init CDN failed! SSL cert must be present together w/ SSL key.');
			return;
		}

		if ($assoc_args['method'] == 'cfi' && empty($assoc_args['cf-token'])) {
			WP_CLI::error('Init CDN failed! CFI must set `--cf-token`.');
			return;
		}

		$cert = !empty($assoc_args['ssl-cert']) ? $assoc_args['ssl-cert'] : '';
		$key = !empty($assoc_args['ssl-key']) ? $assoc_args['ssl-key'] : '';
		$cf_token = !empty($assoc_args['cf-token']) ? $assoc_args['cf-token'] : '';

		$resp = $this->__cloud->init_qc_cdn_cli($assoc_args['method'], $cert, $key, $cf_token);
		if (!empty($resp['qc_activated'])) {
			$main_domain = !empty($resp['main_domain']) ? $resp['main_domain'] : false;
			$this->__cloud->update_qc_activation($resp['qc_activated'], $main_domain, true);
		}
		if (!empty($assoc_args['format']) && $assoc_args['format'] == 'json') {
			WP_CLI::log(json_encode($resp));
			return;
		}
		if (!empty($resp['qc_activated'])) {
			WP_CLI::success('Init QC CDN successfully. Activated type: ' . $resp['qc_activated']);
		} else {
			WP_CLI::error('Init QC CDN failed!');
		}

		if (!empty($resp['cname'])) {
			WP_CLI::success('cname: ' . $resp['cname']);
		}
		if (!empty($resp['msgs'])) {
			WP_CLI::success('msgs: ' . var_export($resp['msgs'], true));
		}
	}

	/**
	 * Link user account by api key
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Link user account by api key
	 *     $ wp litespeed-online link --email=xxx@example.com --api-key=xxxx
	 *
	 */
	public function link($args, $assoc_args)
	{
		if (empty($assoc_args['email']) || empty($assoc_args['api-key'])) {
			WP_CLI::error('Link to QUIC.cloud failed! Missing parameters `--email` or `--api-key`.');
			return;
		}

		$resp = $this->__cloud->link_qc_cli($assoc_args['email'], $assoc_args['api-key']);
		if (!empty($resp['qc_activated'])) {
			$main_domain = !empty($resp['main_domain']) ? $resp['main_domain'] : false;
			$this->__cloud->update_qc_activation($resp['qc_activated'], $main_domain, true);
			WP_CLI::success('Link successfully!');
			WP_CLI::log(json_encode($resp));
		} else {
			WP_CLI::error('Link failed!');
		}
	}

	/**
	 * Sync usage data from QUIC.cloud
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Sync QUIC.cloud service usage info
	 *     $ wp litespeed-online sync
	 *
	 */
	public function sync($args, $assoc_args)
	{
		$json = $this->__cloud->sync_usage();

		if (!empty($assoc_args['format'])) {
			WP_CLI::print_value($json, $assoc_args);
			return;
		}

		WP_CLI::success('Sync successfully');

		$list = array();
		foreach (Cloud::$SERVICES as $v) {
			$list[] = array(
				'key' => $v,
				'used' => !empty($json['usage.' . $v]['used']) ? $json['usage.' . $v]['used'] : 0,
				'quota' => !empty($json['usage.' . $v]['quota']) ? $json['usage.' . $v]['quota'] : 0,
				'PayAsYouGo_Used' => !empty($json['usage.' . $v]['pag_used']) ? $json['usage.' . $v]['pag_used'] : 0,
				'PayAsYouGo_Balance' => !empty($json['usage.' . $v]['pag_bal']) ? $json['usage.' . $v]['pag_bal'] : 0,
			);
		}

		WP_CLI\Utils\format_items('table', $list, array('key', 'used', 'quota', 'PayAsYouGo_Used', 'PayAsYouGo_Balance'));
	}

	/**
	 * Check QC account status
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Check QC account status
	 *     $ wp litespeed-online cdn_status
	 *
	 */
	public function cdn_status($args, $assoc_args)
	{
		$resp = $this->__cloud->cdn_status_cli();
		WP_CLI::log(json_encode($resp));
	}

	/**
	 * List all QUIC.cloud services
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # List all services tag
	 *     $ wp litespeed-online services
	 *
	 */
	public function services($args, $assoc_args)
	{
		if (!empty($assoc_args['format'])) {
			WP_CLI::print_value(Cloud::$SERVICES, $assoc_args);
			return;
		}

		$list = array();
		foreach (Cloud::$SERVICES as $v) {
			$list[] = array(
				'service' => $v,
			);
		}

		WP_CLI\Utils\format_items('table', $list, array('service'));
	}

	/**
	 * List all QUIC.cloud servers in use
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # List all QUIC.cloud servers in use
	 *     $ wp litespeed-online nodes
	 *
	 */
	public function nodes($args, $assoc_args)
	{
		$json = Cloud::get_summary();

		$list = array();
		$json_output = array();
		foreach (Cloud::$SERVICES as $v) {
			$server = !empty($json['server.' . $v]) ? $json['server.' . $v] : '';
			$list[] = array(
				'service' => $v,
				'server' => $server,
			);
			$json_output[] = array($v => $server);
		}

		if (!empty($assoc_args['format'])) {
			WP_CLI::print_value($json_output, $assoc_args);
			return;
		}

		WP_CLI\Utils\format_items('table', $list, array('service', 'server'));
	}

	/**
	 * Detect closest node server for current service
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Detect closest node for one service
	 *     $ wp litespeed-online ping img_optm
	 *     $ wp litespeed-online ping img_optm --force
	 *
	 */
	public function ping($param, $assoc_args)
	{
		$svc = $param[0];
		$force = !empty($assoc_args['force']);

		$json = $this->__cloud->detect_cloud($svc, $force);
		if ($json) {
			WP_CLI::success('Updated closest server.');
		}
		WP_CLI::log('svc = ' . $svc);
		WP_CLI::log('node = ' . ($json ?: '-'));
	}
}
option.cls.php000064400000021155151540213720007351 0ustar00<?php
namespace LiteSpeed\CLI;

defined('WPINC') || exit();

use LiteSpeed\Base;
use LiteSpeed\Admin_Settings;
use LiteSpeed\Utility;
use WP_CLI;

/**
 * LiteSpeed Cache option Interface
 */
class Option extends Base
{
	/**
	 * Set an individual LiteSpeed Cache option.
	 *
	 * ## OPTIONS
	 *
	 * <key>
	 * : The option key to update.
	 *
	 * <newvalue>
	 * : The new value to set the option to.
	 *
	 * ## EXAMPLES
	 *
	 *     # Set to not cache the login page
	 *     $ wp litespeed-option set cache-priv false
	 *     $ wp litespeed-option set 'cdn-mapping[url][0]' https://cdn.EXAMPLE.com
	 *     $ wp litespeed-option set media-lqip_exc $'line1\nline2'
	 *
	 */
	public function set($args, $assoc_args)
	{
		/**
		 * Note: If the value is multiple dimensions like cdn-mapping, need to specially handle it both here and in `const.default.json`
		 *
		 * For CDN/Crawler mutlti dimension settings, if all children are empty in one line, will delete that line. To delete one line, just set all to empty.
		 * E.g. to delete cdn-mapping[0], need to run below:
		 * 											`set cdn-mapping[url][0] ''`
		 * 											`set cdn-mapping[inc_img][0] ''`
		 * 											`set cdn-mapping[inc_css][0] ''`
		 * 											`set cdn-mapping[inc_js][0] ''`
		 * 											`set cdn-mapping[filetype][0] ''`
		 */
		$key = $args[0];
		$val = $args[1];

		/**
		 * For CDN mapping, allow:
		 * 		`set 'cdn-mapping[url][0]' https://the1st_cdn_url`
		 * 		`set 'cdn-mapping[inc_img][0]' true`
		 * 		`set 'cdn-mapping[inc_img][0]' 1`
		 * @since  2.7.1
		 *
		 * For Crawler cookies:
		 * 		`set 'crawler-cookies[name][0]' my_currency`
		 * 		`set 'crawler-cookies[vals][0]' "USD\nTWD"`
		 *
		 * For multi lines setting:
		 * 		`set media-lqip_exc $'img1.jpg\nimg2.jpg'`
		 */

		// Build raw data
		$raw_data = array(
			Admin_Settings::ENROLL => array($key),
		);

		// Contains child set
		if (strpos($key, '[')) {
			parse_str($key . '=' . $val, $key2);
			$raw_data = array_merge($raw_data, $key2);
		} else {
			$raw_data[$key] = $val;
		}

		$this->cls('Admin_Settings')->save($raw_data);
		WP_CLI::line("$key:");
		$this->get($args, $assoc_args);
	}

	/**
	 * Get the plugin options.
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Get all options
	 *     $ wp litespeed-option all
	 *     $ wp litespeed-option all --json
	 *
	 */
	public function all($args, $assoc_args)
	{
		$options = $this->get_options();

		if (!empty($assoc_args['format'])) {
			WP_CLI::print_value($options, $assoc_args);
			return;
		}

		$option_out = array();

		$buf = WP_CLI::colorize('%CThe list of options:%n');
		WP_CLI::line($buf);

		foreach ($options as $k => $v) {
			if ($k == self::O_CDN_MAPPING || $k == self::O_CRAWLER_COOKIES) {
				foreach ($v as $k2 => $v2) {
					// $k2 is numeric
					if (is_array($v2)) {
						foreach ($v2 as $k3 => $v3) {
							// $k3 = 'url/inc_img/name/vals'
							if (is_array($v3)) {
								$option_out[] = array('key' => '', 'value' => '');
								foreach ($v3 as $k4 => $v4) {
									$option_out[] = array('key' => $k4 == 0 ? "{$k}[$k3][$k2]" : '', 'value' => $v4);
								}
								$option_out[] = array('key' => '', 'value' => '');
							} else {
								$option_out[] = array('key' => "{$k}[$k3][$k2]", 'value' => $v3);
							}
						}
					}
				}
				continue;
			} elseif (is_array($v) && $v) {
				// $v = implode( PHP_EOL, $v );
				$option_out[] = array('key' => '', 'value' => '');
				foreach ($v as $k2 => $v2) {
					$option_out[] = array('key' => $k2 == 0 ? $k : '', 'value' => $v2);
				}
				$option_out[] = array('key' => '', 'value' => '');
				continue;
			}

			if (array_key_exists($k, self::$_default_options) && is_bool(self::$_default_options[$k]) && !$v) {
				$v = 0;
			}

			if ($v === '' || $v === array()) {
				$v = "''";
			}

			$option_out[] = array('key' => $k, 'value' => $v);
		}

		WP_CLI\Utils\format_items('table', $option_out, array('key', 'value'));
	}

	/**
	 * Get the plugin options.
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Get one option
	 *     $ wp litespeed-option get cache-priv
	 *     $ wp litespeed-option get 'cdn-mapping[url][0]'
	 *
	 */
	public function get($args, $assoc_args)
	{
		$id = $args[0];

		$child = false;
		if (strpos($id, '[')) {
			parse_str($id, $id2);
			Utility::compatibility();
			$id = array_key_first($id2);

			$child = array_key_first($id2[$id]); // `url`
			if (!$child) {
				WP_CLI::error('Wrong child key');
				return;
			}
			$numeric = array_key_first($id2[$id][$child]); // `0`
			if ($numeric === null) {
				WP_CLI::error('Wrong 2nd level numeric key');
				return;
			}
		}

		if (!isset(self::$_default_options[$id])) {
			WP_CLI::error('ID not exist [id] ' . $id);
			return;
		}

		$v = $this->conf($id);
		$default_v = self::$_default_options[$id];

		/**
		 * For CDN_mapping and crawler_cookies
		 * Examples of option name:
		 * 		cdn-mapping[url][0]
		 * 		crawler-cookies[name][1]
		 */
		if ($id == self::O_CDN_MAPPING) {
			if (!in_array($child, array(self::CDN_MAPPING_URL, self::CDN_MAPPING_INC_IMG, self::CDN_MAPPING_INC_CSS, self::CDN_MAPPING_INC_JS, self::CDN_MAPPING_FILETYPE))) {
				WP_CLI::error('Wrong child key');
				return;
			}
		}
		if ($id == self::O_CRAWLER_COOKIES) {
			if (!in_array($child, array(self::CRWL_COOKIE_NAME, self::CRWL_COOKIE_VALS))) {
				WP_CLI::error('Wrong child key');
				return;
			}
		}

		if ($id == self::O_CDN_MAPPING || $id == self::O_CRAWLER_COOKIES) {
			if (!empty($v[$numeric][$child])) {
				$v = $v[$numeric][$child];
			} else {
				if ($id == self::O_CDN_MAPPING) {
					if (in_array($child, array(self::CDN_MAPPING_INC_IMG, self::CDN_MAPPING_INC_CSS, self::CDN_MAPPING_INC_JS))) {
						$v = 0;
					} else {
						$v = "''";
					}
				} else {
					$v = "''";
				}
			}
		}

		if (is_array($v)) {
			$v = implode(PHP_EOL, $v);
		}

		if (!$v && $id != self::O_CDN_MAPPING && $id != self::O_CRAWLER_COOKIES) {
			// empty array for CDN/crawler has been handled
			if (is_bool($default_v)) {
				$v = 0;
			} elseif (!is_array($default_v)) {
				$v = "''";
			}
		}

		WP_CLI::line($v);
	}

	/**
	 * Export plugin options to a file.
	 *
	 * ## OPTIONS
	 *
	 * [--filename=<path>]
	 * : The default path used is CURRENTDIR/lscache_wp_options_DATE-TIME.txt.
	 * To select a different file, use this option.
	 *
	 * ## EXAMPLES
	 *
	 *     # Export options to a file.
	 *     $ wp litespeed-option export
	 *
	 */
	public function export($args, $assoc_args)
	{
		if (isset($assoc_args['filename'])) {
			$file = $assoc_args['filename'];
		} else {
			$file = getcwd() . '/litespeed_options_' . date('d_m_Y-His') . '.data';
		}

		if (!is_writable(dirname($file))) {
			WP_CLI::error('Directory not writable.');
			return;
		}

		$data = $this->cls('Import')->export(true);

		if (file_put_contents($file, $data) === false) {
			WP_CLI::error('Failed to create file.');
		} else {
			WP_CLI::success('Created file ' . $file);
		}
	}

	/**
	 * Import plugin options from a file.
	 *
	 * The file must be formatted as such:
	 * option_key=option_value
	 * One per line.
	 * A Semicolon at the beginning of the line indicates a comment and will be skipped.
	 *
	 * ## OPTIONS
	 *
	 * <file>
	 * : The file to import options from.
	 *
	 * ## EXAMPLES
	 *
	 *     # Import options from CURRENTDIR/options.txt
	 *     $ wp litespeed-option import options.txt
	 *
	 */
	public function import($args, $assoc_args)
	{
		$file = $args[0];
		if (!file_exists($file) || !is_readable($file)) {
			WP_CLI::error('File does not exist or is not readable.');
		}

		$res = $this->cls('Import')->import($file);

		if (!$res) {
			WP_CLI::error('Failed to parse serialized data from file.');
		}

		WP_CLI::success('Options imported. [File] ' . $file);
	}

	/**
	 * Import plugin options from a remote file.
	 *
	 * The file must be formatted as such:
	 * option_key=option_value
	 * One per line.
	 * A Semicolon at the beginning of the line indicates a comment and will be skipped.
	 *
	 * ## OPTIONS
	 *
	 * <url>
	 * : The URL to import options from.
	 *
	 * ## EXAMPLES
	 *
	 *     # Import options from https://domain.com/options.txt
	 *     $ wp litespeed-option import_remote https://domain.com/options.txt
	 *
	 */

	public function import_remote($args, $assoc_args)
	{
		$file = $args[0];

		$tmp_file = download_url($file);

		if (is_wp_error($tmp_file)) {
			WP_CLI::error('Failed to download file.');
			return;
		}

		$res = $this->cls('Import')->import($tmp_file);

		if (!$res) {
			WP_CLI::error('Failed to parse serialized data from file.');
		}

		WP_CLI::success('Options imported. [File] ' . $file);
	}

	/**
	 * Reset all options to default.
	 *
	 * ## EXAMPLES
	 *
	 *     # Reset all options
	 *     $ wp litespeed-option reset
	 *
	 */
	public function reset()
	{
		$this->cls('Import')->reset();
	}
}
presets.cls.php000064400000002660151540213720007526 0ustar00<?php
namespace LiteSpeed\CLI;
defined('WPINC') || exit();

use LiteSpeed\Debug2;
use LiteSpeed\Preset;
use WP_CLI;

/**
 * Presets CLI
 */

class Presets
{
	private $__preset;

	public function __construct()
	{
		Debug2::debug('CLI_Presets init');

		$this->__preset = Preset::cls();
	}

	/**
	 * Applies a standard preset's settings.
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Apply the preset called "basic"
	 *     $ wp litespeed-presets apply basic
	 *
	 */

	public function apply($args)
	{
		$preset = $args[0];

		if (!isset($preset)) {
			WP_CLI::error('Please specify a preset to apply.');
			return;
		}

		return $this->__preset->apply($preset);
	}

	/**
	 * Returns sorted backup names.
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Get all backups
	 *     $ wp litespeed-presets get_backups
	 *
	 */

	public function get_backups()
	{
		$backups = $this->__preset->get_backups();

		foreach ($backups as $backup) {
			WP_CLI::line($backup);
		}
	}

	/**
	 * Restores settings from the backup file with the given timestamp, then deletes the file.
	 *
	 * ## OPTIONS
	 *
	 * ## EXAMPLES
	 *
	 *     # Restore the backup with the timestamp 1667485245
	 *     $ wp litespeed-presets restore 1667485245
	 *
	 */

	public function restore($args)
	{
		$timestamp = $args[0];

		if (!isset($timestamp)) {
			WP_CLI::error('Please specify a timestamp to restore.');
			return;
		}

		return $this->__preset->restore($timestamp);
	}
}
purge.cls.php000064400000015244151540213720007165 0ustar00<?php
namespace LiteSpeed\CLI;

defined('WPINC') || exit();

use LiteSpeed\Core;
use LiteSpeed\Router;
use LiteSpeed\Admin_Display;
use WP_CLI;

/**
 * LiteSpeed Cache Purge Interface
 */
class Purge
{
	/**
	 * List all site domains and ids on the network.
	 *
	 * For use with the blog subcommand.
	 *
	 * ## EXAMPLES
	 *
	 *     # List all the site domains and ids in a table.
	 *     $ wp litespeed-purge network_list
	 */
	public function network_list($args)
	{
		if (!is_multisite()) {
			WP_CLI::error('This is not a multisite installation!');

			return;
		}
		$buf = WP_CLI::colorize("%CThe list of installs:%n\n");

		if (version_compare($GLOBALS['wp_version'], '4.6', '<')) {
			$sites = wp_get_sites();
			foreach ($sites as $site) {
				$buf .= WP_CLI::colorize('%Y' . $site['domain'] . $site['path'] . ':%n ID ' . $site['blog_id']) . "\n";
			}
		} else {
			$sites = get_sites();
			foreach ($sites as $site) {
				$buf .= WP_CLI::colorize('%Y' . $site->domain . $site->path . ':%n ID ' . $site->blog_id) . "\n";
			}
		}

		WP_CLI::line($buf);
	}

	/**
	 * Sends an ajax request to the site. Takes an action and the nonce string to perform.
	 *
	 * @since 1.0.14
	 */
	private function _send_request($action, $extra = array())
	{
		$data = array(
			Router::ACTION => $action,
			Router::NONCE => wp_create_nonce($action),
		);
		if (!empty($extra)) {
			$data = array_merge($data, $extra);
		}

		$url = admin_url('admin-ajax.php');
		WP_CLI::debug('URL is ' . $url);

		$out = WP_CLI\Utils\http_request('GET', $url, $data);
		return $out;
	}

	/**
	 * Purges all cache entries for the blog (the entire network if multisite).
	 *
	 * ## EXAMPLES
	 *
	 *     # Purge Everything associated with the WordPress install.
	 *     $ wp litespeed-purge all
	 *
	 */
	public function all($args)
	{
		if (is_multisite()) {
			$action = Core::ACTION_QS_PURGE_EMPTYCACHE;
		} else {
			$action = Core::ACTION_QS_PURGE_ALL;
		}

		$purge_ret = $this->_send_request($action);

		if ($purge_ret->success) {
			WP_CLI::success(__('Purged All!', 'litespeed-cache'));
		} else {
			WP_CLI::error('Something went wrong! Got ' . $purge_ret->status_code);
		}
	}

	/**
	 * Purges all cache entries for the blog.
	 *
	 * ## OPTIONS
	 *
	 * <blogid>
	 * : The blog id to purge
	 *
	 * ## EXAMPLES
	 *
	 *     # In a multisite install, purge only the shop.example.com cache (stored as blog id 2).
	 *     $ wp litespeed-purge blog 2
	 *
	 */
	public function blog($args)
	{
		if (!is_multisite()) {
			WP_CLI::error('Not a multisite installation.');
			return;
		}
		$blogid = $args[0];
		if (!is_numeric($blogid)) {
			$error = WP_CLI::colorize('%RError: invalid blog id entered.%n');
			WP_CLI::line($error);
			$this->network_list($args);
			return;
		}
		$site = get_blog_details($blogid);
		if ($site === false) {
			$error = WP_CLI::colorize('%RError: invalid blog id entered.%n');
			WP_CLI::line($error);
			$this->network_list($args);
			return;
		}
		switch_to_blog($blogid);

		$purge_ret = $this->_send_request(Core::ACTION_QS_PURGE_ALL);
		if ($purge_ret->success) {
			WP_CLI::success(__('Purged the blog!', 'litespeed-cache'));
		} else {
			WP_CLI::error('Something went wrong! Got ' . $purge_ret->status_code);
		}
	}

	/**
	 * Purges all cache tags related to a url.
	 *
	 * ## OPTIONS
	 *
	 * <url>
	 * : The url to purge.
	 *
	 * ## EXAMPLES
	 *
	 *     # Purge the front page.
	 *     $ wp litespeed-purge url https://mysite.com/
	 *
	 */
	public function url($args)
	{
		$data = array(
			Router::ACTION => Core::ACTION_QS_PURGE,
		);
		$url = $args[0];
		$deconstructed = wp_parse_url($url);
		if (empty($deconstructed)) {
			WP_CLI::error('url passed in is invalid.');
			return;
		}

		if (is_multisite()) {
			if (get_blog_id_from_url($deconstructed['host'], '/') === 0) {
				WP_CLI::error('Multisite url passed in is invalid.');
				return;
			}
		} else {
			$deconstructed_site = wp_parse_url(get_home_url());
			if ($deconstructed['host'] !== $deconstructed_site['host']) {
				WP_CLI::error('Single site url passed in is invalid.');
				return;
			}
		}

		WP_CLI::debug('url is ' . $url);

		$purge_ret = WP_CLI\Utils\http_request('GET', $url, $data);
		if ($purge_ret->success) {
			WP_CLI::success(__('Purged the url!', 'litespeed-cache'));
		} else {
			WP_CLI::error('Something went wrong! Got ' . $purge_ret->status_code);
		}
	}

	/**
	 * Helper function for purging by ids.
	 *
	 * @access private
	 * @since 1.0.15
	 * @param array $args The id list to parse.
	 * @param string $select The purge by kind
	 * @param function(int $id) $callback The callback function to check the id.
	 */
	private function _purgeby($args, $select, $callback)
	{
		$filtered = array();
		foreach ($args as $val) {
			if (!ctype_digit($val)) {
				WP_CLI::debug('[LSCACHE] Skip val, not a number. ' . $val);
				continue;
			}
			$term = $callback($val);
			if (!empty($term)) {
				WP_CLI::line($term->name);
				$filtered[] = in_array($callback, array('get_tag', 'get_category')) ? $term->name : $val;
			} else {
				WP_CLI::debug('[LSCACHE] Skip val, not a valid term. ' . $val);
			}
		}

		if (empty($filtered)) {
			WP_CLI::error('Arguments must be integer ids.');
			return;
		}

		$str = implode(',', $filtered);

		$purge_titles = array(
			0 => 'Category',
			1 => 'Post ID',
			2 => 'Tag',
			3 => 'URL',
		);

		WP_CLI::line('Will purge the following: [' . $purge_titles[$select] . '] ' . $str);

		$data = array(
			Admin_Display::PURGEBYOPT_SELECT => $select,
			Admin_Display::PURGEBYOPT_LIST => $str,
		);

		$purge_ret = $this->_send_request(Core::ACTION_PURGE_BY, $data);
		if ($purge_ret->success) {
			WP_CLI::success(__('Purged!', 'litespeed-cache'));
		} else {
			WP_CLI::error('Something went wrong! Got ' . $purge_ret->status_code);
		}
	}

	/**
	 * Purges cache tags for a WordPress tag
	 *
	 * ## OPTIONS
	 *
	 * <ids>...
	 * : the Term IDs to purge.
	 *
	 * ## EXAMPLES
	 *
	 *     # Purge the tag ids 1, 3, and 5
	 *     $ wp litespeed-purge tag 1 3 5
	 *
	 */
	public function tag($args)
	{
		$this->_purgeby($args, Admin_Display::PURGEBY_TAG, 'get_tag');
	}

	/**
	 * Purges cache tags for a WordPress category
	 *
	 * ## OPTIONS
	 *
	 * <ids>...
	 * : the Term IDs to purge.
	 *
	 * ## EXAMPLES
	 *
	 *     # Purge the category ids 1, 3, and 5
	 *     $ wp litespeed-purge category 1 3 5
	 *
	 */
	public function category($args)
	{
		$this->_purgeby($args, Admin_Display::PURGEBY_CAT, 'get_category');
	}

	/**
	 * Purges cache tags for a WordPress Post/Product
	 *
	 * @alias product
	 *
	 * ## OPTIONS
	 *
	 * <ids>...
	 * : the Post IDs to purge.
	 *
	 * ## EXAMPLES
	 *
	 *     # Purge the post ids 1, 3, and 5
	 *     $ wp litespeed-purge post_id 1 3 5
	 *
	 */
	public function post_id($args)
	{
		$this->_purgeby($args, Admin_Display::PURGEBY_PID, 'get_post');
	}
}
class-wc-cli-com-command.php000064400000014327151542652700011744 0ustar00<?php
/**
 * WC_CLI_COM_Command class file.
 *
 * @package WooCommerce\CLI
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Allows to interact with extensions from WCCOM marketplace via CLI.
 *
 * @version 6.8
 * @package WooCommerce
 */
class WC_CLI_COM_Command {
	const APPLICATION_PASSWORD_SECTION_URL = 'https://woocommerce.com/my-account/#application-passwords';

	/**
	 * Registers a commands for managing WooCommerce.com extensions.
	 */
	public static function register_commands() {
		WP_CLI::add_command( 'wc com extension list', array( 'WC_CLI_COM_Command', 'list_extensions' ) );
		WP_CLI::add_command( 'wc com disconnect', array( 'WC_CLI_COM_Command', 'disconnect' ) );
		WP_CLI::add_command( 'wc com connect', array( 'WC_CLI_COM_Command', 'connect' ) );
	}

	/**
	 * List extensions owned by the connected site
	 *
	 * [--format]
	 * : If set, the command will use the specified format. Possible values are table, json, csv and yaml. By default the table format will be used.
	 *
	 * [--fields]
	 * : If set, the command will show only the specified fields instead of showing all the fields in the output.
	 *
	 * ## EXAMPLES
	 *
	 *     # List extensions owned by the connected site in table format with all the fields
	 *     $ wp wc com extension list
	 *
	 *     # List the product slug of the extension owned by the connected site in csv format
	 *     $ wp wc com extension list --format=csv --fields=product_slug
	 *
	 * @param  array $args  WP-CLI positional arguments.
	 * @param  array $assoc_args  WP-CLI associative arguments.
	 */
	public static function list_extensions( array $args, array $assoc_args ) {
		$data = WC_Helper::get_subscriptions();

		$data = array_values( $data );

		$formatter = new \WP_CLI\Formatter(
			$assoc_args,
			array(
				'product_slug',
				'product_name',
				'auto_renew',
				'expires_on',
				'expired',
				'sites_max',
				'sites_active',
				'maxed',
			)
		);

		$data = array_map(
			function( $item ) {
				$product_slug      = '';
				$product_url_parts = explode( '/', $item['product_url'] );
				if ( count( $product_url_parts ) > 2 ) {
					$product_slug = $product_url_parts[ count( $product_url_parts ) - 2 ];
				}
				return array(
					'product_slug' => $product_slug,
					'product_name' => htmlspecialchars_decode( $item['product_name'] ),
					'auto_renew'   => $item['autorenew'] ? 'On' : 'Off',
					'expires_on'   => gmdate( 'Y-m-d', $item['expires'] ),
					'expired'      => $item['expired'] ? 'Yes' : 'No',
					'sites_max'    => $item['sites_max'],
					'sites_active' => $item['sites_active'],
					'maxed'        => $item['maxed'] ? 'Yes' : 'No',
				);
			},
			$data
		);

		$formatter->display_items( $data );
	}

	/**
	 * ## OPTIONS
	 *
	 * [--yes]
	 * : Do not prompt for confirmation.
	 *
	 * ## EXAMPLES
	 *
	 *     # Disconnect from site.
	 *     $ wp wc com disconnect
	 *
	 *     # Disconnect without prompt for confirmation.
	 *     $ wp wc com disconnect --yes
	 *
	 * @param array $args Positional arguments to include when calling the command.
	 * @param array $assoc_args Associative arguments to include when calling the command.

	 * @return void
	 * @throws \WP_CLI\ExitException If WP_CLI::$capture_exit is true.
	 */
	public static function disconnect( array $args, array $assoc_args ) {
		if ( ! WC_Helper::is_site_connected() ) {
			WP_CLI::error( __( 'Your store is not connected to WooCommerce.com. Run `wp wc com connect` command.', 'woocommerce' ) );
		}

		WP_CLI::confirm( __( 'Are you sure you want to disconnect your store from WooCommerce.com?', 'woocommerce' ), $assoc_args );
		WC_Helper::disconnect();
		WP_CLI::success( __( 'You have successfully disconnected your store from WooCommerce.com', 'woocommerce' ) );
	}

	/**
	 * Connects to WooCommerce.com with application-password.
	 *
	 * [--password]
	 * : If set, password won't be prompt.
	 *
	 * [--force]
	 * : If set, site will be disconnected and a new connection will be forced.
	 *
	 * ## EXAMPLES
	 *
	 *     # Connect to WCCOM using password.
	 *     $ wp wc com connect
	 *
	 *     # force connecting to WCCOM even if site is already connected.
	 *     $ wp wc com connect --force
	 *
	 *     # Pass password to comman.
	 *     $ wp wc com connect --password=PASSWORD
	 *
	 * @param array $args Positional arguments to include when calling the command.
	 * @param array $assoc_args Associative arguments to include when calling the command.
	 *
	 * @return void
	 * @throws \WP_CLI\ExitException If WP_CLI::$capture_exit is true.
	 */
	public static function connect( array $args, array $assoc_args ) {
		$password = \WP_CLI\Utils\get_flag_value( $assoc_args, 'password' );
		$force    = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );

		if ( WC_Helper::is_site_connected() ) {
			if ( $force ) {
				WC_Helper::disconnect();
			} else {
				WP_CLI::error( __( 'Your store is already connected.', 'woocommerce' ) );

				return;
			}
		}

		if ( empty( $password ) ) {
			// translators: %s is the URL for the application-password section in WooCommerce.com.
			WP_CLI::log( sprintf( __( 'If you don\'t have an application password (not your account password), generate a password from %s', 'woocommerce' ), esc_url( self::APPLICATION_PASSWORD_SECTION_URL ) ) );
			$password = self::ask( __( 'Connection password:', 'woocommerce' ) );
		}
		$password = sanitize_text_field( $password );
		if ( empty( $password ) ) {
			// translators: %s is the URL for the application-password section in WooCommerce.com.
			WP_CLI::error( sprintf( __( 'Invalid password. Generate a new one from %s.', 'woocommerce' ), esc_url( self::APPLICATION_PASSWORD_SECTION_URL ) ) );
		}

		$auth = WC_Helper::connect_with_password( $password );
		if ( is_wp_error( $auth ) ) {
			WP_CLI::error( $auth->get_error_message() );
		}

		if ( WC_Helper::is_site_connected() ) {
			WP_CLI::success( __( 'Store connected successfully.', 'woocommerce' ) );
		}
	}

	/**
	 * We are asking a question and returning an answer as a string.
	 *
	 * @param  string $question The question being prompt.
	 *
	 * @return string
	 */
	protected static function ask( $question ) {
		// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fwrite
		// Adding space to question and showing it.
		fwrite( STDOUT, $question . ' ' );

		return trim( fgets( STDIN ) );
		// phpcs:enable
	}
}
class-wc-cli-com-extension-command.php000064400000006317151542652710013757 0ustar00<?php
/**
 * WC_CLI_COM_Command class file.
 *
 * @package WooCommerce\CLI
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'Plugin_Command' ) ) {
	exit;
}

/**
 * Allows to interact with extensions from WCCOM marketplace via CLI.
 *
 * @version 6.8
 * @package WooCommerce
 */
class WC_CLI_COM_Extension_Command extends Plugin_Command {
	/**
	 * Registers a commands for managing WooCommerce.com extensions.
	 */
	public static function register_commands() {
		WP_CLI::add_command( 'wc com extension', 'WC_CLI_COM_Extension_Command' );
	}

	/**
	 * Installs one or more plugins from wccom marketplace.
	 *
	 * ## OPTIONS
	 *
	 * <extension>...
	 * : One or more plugins to install. Accepts a plugin slug.
	 *
	 * [--force]
	 * : If set, the command will overwrite any installed version of the plugin, without prompting
	 * for confirmation.
	 *
	 * [--activate]
	 * : If set, the plugin will be activated immediately after install.
	 *
	 * [--activate-network]
	 * : If set, the plugin will be network activated immediately after install
	 *
	 * [--insecure]
	 * : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack.
	 *
	 * ## EXAMPLES
	 *
	 *     # Install the latest version from woocommerce.com and activate
	 *     $ wp wc com extension install automatewoo --activate
	 *     Downloading install package from http://s3.amazonaws.com/bucketname/automatewoo.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef......
	 *     Using cached file '/home/vagrant/.wp-cli/cache/plugin/automatewoo.zip'...
	 *     Unpacking the package...
	 *     Installing the plugin...
	 *     Plugin installed successfully.
	 *     Activating 'automatewoo'...
	 *     Plugin 'automatewoo' activated.
	 *     Success: Installed 1 of 1 plugins.
	 *
	 *     # Forcefully re-install an installed plugin
	 *     $ wp wc com extension install automatewoo --force
	 *     Downloading install package from http://s3.amazonaws.com/bucketname/automatewoo.zip?AWSAccessKeyId=123&Expires=456&Signature=abcdef...
	 *     Unpacking the package...
	 *     Installing the plugin...
	 *     Removing the old version of the plugin...
	 *     Plugin updated successfully
	 *     Success: Installed 1 of 1 plugins.
	 *
	 * @param array $args WP-CLI positional arguments.
	 * @param array $assoc_args WP-CLI associative arguments.
	 */
	public function install( $args, $assoc_args ) {
		$subscriptions         = WC_Helper_Updater::get_available_extensions_downloads_data();
		$extension             = reset( $args );
		$extension_package_url = null;

		// Remove `--version` as we don't support it.
		unset( $assoc_args['version'] );

		// Filter by slug.
		foreach ( $subscriptions as $subscription ) {
			if ( $subscription['slug'] === $extension && ! is_null( $subscription['package'] ) ) {

				$extension_package_url = $subscription['package'];
				break;
			}
		}

		// No package found.
		if ( is_null( $extension_package_url ) ) {
			WP_CLI::warning( sprintf( 'We couldn\'t find a Subscription for \'%s\'', $extension ) );
			WP_CLI\Utils\report_batch_operation_results( $this->item_type, 'install', count( $args ), 0, 1 );

			return;
		}

		parent::install( array( $extension_package_url ), $assoc_args );
	}
}
class-wc-cli-rest-command.php000064400000032270151542652730012143 0ustar00<?php
/**
 * WP_CLI_Rest_Command class file.
 *
 * @package WooCommerce\CLI
 */

use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Utilities\NumberUtil;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Main Command for WooCommerce CLI.
 *
 * Since a lot of WC operations can be handled via the REST API, we base our CLI
 * off of Restful to generate commands for each WooCommerce REST API endpoint
 * so most of the logic is shared.
 *
 * Forked from wp-cli/restful (by Daniel Bachhuber, released under the MIT license https://opensource.org/licenses/MIT).
 * https://github.com/wp-cli/restful
 *
 * @version 3.0.0
 * @package WooCommerce
 */
class WC_CLI_REST_Command {
	/**
	 * Endpoints that have a parent ID.
	 * Ex: Product reviews, which has a product ID and a review ID.
	 *
	 * @var array
	 */
	protected $routes_with_parent_id = array(
		'customer_download',
		'product_review',
		'order_note',
		'shop_order_refund',
	);

	/**
	 * Name of command/endpoint object.
	 *
	 * @var string
	 */
	private $name;

	/**
	 * Endpoint route.
	 *
	 * @var string
	 */
	private $route;

	/**
	 * Main resource ID.
	 *
	 * @var int
	 */
	private $resource_identifier;

	/**
	 * Schema for command.
	 *
	 * @var array
	 */
	private $schema;

	/**
	 * List of supported IDs and their description (name => desc).
	 *
	 * @var array
	 */
	private $supported_ids = array();

	/**
	 * Sets up REST Command.
	 *
	 * @param string $name   Name of endpoint object (comes from schema).
	 * @param string $route  Path to route of this endpoint.
	 * @param array  $schema Schema object.
	 */
	public function __construct( $name, $route, $schema ) {
		$this->name = $name;

		preg_match_all( '#\([^\)]+\)#', $route, $matches );
		$first_match  = $matches[0];
		$resource_id  = ! empty( $matches[0] ) ? array_pop( $matches[0] ) : null;
		$this->route  = rtrim( $route );
		$this->schema = $schema;

		$this->resource_identifier = $resource_id;
		if ( in_array( $name, $this->routes_with_parent_id, true ) ) {
			$is_singular = substr( $this->route, - strlen( $resource_id ) ) === $resource_id;
			if ( ! $is_singular ) {
				$this->resource_identifier = $first_match[0];
			}
		}
	}

	/**
	 * Passes supported ID arguments (things like product_id, order_id, etc) that we should look for in addition to id.
	 *
	 * @param array $supported_ids List of supported IDs.
	 */
	public function set_supported_ids( $supported_ids = array() ) {
		$this->supported_ids = $supported_ids;
	}

	/**
	 * Returns an ID of supported ID arguments (things like product_id, order_id, etc) that we should look for in addition to id.
	 *
	 * @return array
	 */
	public function get_supported_ids() {
		return $this->supported_ids;
	}

	/**
	 * Create a new item.
	 *
	 * @subcommand create
	 *
	 * @param array $args WP-CLI positional arguments.
	 * @param array $assoc_args WP-CLI associative arguments.
	 */
	public function create_item( $args, $assoc_args ) {
		$assoc_args            = self::decode_json( $assoc_args );
		list( $status, $body ) = $this->do_request( 'POST', $this->get_filled_route( $args ), $assoc_args );
		if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
			WP_CLI::line( $body['id'] );
		} else {
			WP_CLI::success( "Created {$this->name} {$body['id']}." );
		}
	}

	/**
	 * Delete an existing item.
	 *
	 * @subcommand delete
	 *
	 * @param array $args WP-CLI positional arguments.
	 * @param array $assoc_args WP-CLI associative arguments.
	 */
	public function delete_item( $args, $assoc_args ) {
		list( $status, $body ) = $this->do_request( 'DELETE', $this->get_filled_route( $args ), $assoc_args );
		$object_id = isset( $body['id'] ) ? $body['id'] : '';
		if ( ! $object_id && isset( $body['slug'] ) ) {
			$object_id = $body['slug'];
		}

		if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
			WP_CLI::line( $object_id );
		} else {
			if ( empty( $assoc_args['force'] ) ) {
				WP_CLI::success( __( 'Trashed', 'woocommerce' ) . " {$this->name} {$object_id}" );
			} else {
				WP_CLI::success( __( 'Deleted', 'woocommerce' ) . " {$this->name} {$object_id}." );
			}
		}
	}

	/**
	 * Get a single item.
	 *
	 * @subcommand get
	 *
	 * @param array $args WP-CLI positional arguments.
	 * @param array $assoc_args WP-CLI associative arguments.
	 */
	public function get_item( $args, $assoc_args ) {
		$route                           = $this->get_filled_route( $args );
		list( $status, $body, $headers ) = $this->do_request( 'GET', $route, $assoc_args );

		if ( ! empty( $assoc_args['fields'] ) ) {
			$body = self::limit_item_to_fields( $body, $assoc_args['fields'] );
		}

		if ( empty( $assoc_args['format'] ) ) {
			$assoc_args['format'] = 'table';
		}

		if ( 'headers' === $assoc_args['format'] ) {
			echo wp_json_encode( $headers );
		} elseif ( 'body' === $assoc_args['format'] ) {
			echo wp_json_encode( $body );
		} elseif ( 'envelope' === $assoc_args['format'] ) {
			echo wp_json_encode(
				array(
					'body'    => $body,
					'headers' => $headers,
					'status'  => $status,
				)
			);
		} else {
			$formatter = $this->get_formatter( $assoc_args );
			$formatter->display_item( $body );
		}
	}

	/**
	 * List all items.
	 *
	 * @subcommand list
	 *
	 * @param array $args WP-CLI positional arguments.
	 * @param array $assoc_args WP-CLI associative arguments.
	 */
	public function list_items( $args, $assoc_args ) {
		if ( ! empty( $assoc_args['format'] ) && 'count' === $assoc_args['format'] ) {
			$method = 'HEAD';
		} else {
			$method = 'GET';
		}

		if ( ! isset( $assoc_args['per_page'] ) || empty( $assoc_args['per_page'] ) ) {
			$assoc_args['per_page'] = '100';
		}

		list( $status, $body, $headers ) = $this->do_request( $method, $this->get_filled_route( $args ), $assoc_args );
		if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) {
			$items = array_column( $body, 'id' );
		} else {
			$items = $body;
		}

		if ( ! empty( $assoc_args['fields'] ) ) {
			foreach ( $items as $key => $item ) {
				$items[ $key ] = self::limit_item_to_fields( $item, $assoc_args['fields'] );
			}
		}

		if ( empty( $assoc_args['format'] ) ) {
			$assoc_args['format'] = 'table';
		}

		if ( ! empty( $assoc_args['format'] ) && 'count' === $assoc_args['format'] ) {
			echo (int) $headers['X-WP-Total'];
		} elseif ( 'headers' === $assoc_args['format'] ) {
			echo wp_json_encode( $headers );
		} elseif ( 'body' === $assoc_args['format'] ) {
			echo wp_json_encode( $body );
		} elseif ( 'envelope' === $assoc_args['format'] ) {
			echo wp_json_encode(
				array(
					'body'    => $body,
					'headers' => $headers,
					'status'  => $status,
					'api_url' => $this->api_url,
				)
			);
		} else {
			$formatter = $this->get_formatter( $assoc_args );
			$formatter->display_items( $items );
		}
	}

	/**
	 * Update an existing item.
	 *
	 * @subcommand update
	 *
	 * @param array $args WP-CLI positional arguments.
	 * @param array $assoc_args WP-CLI associative arguments.
	 */
	public function update_item( $args, $assoc_args ) {
		$assoc_args            = self::decode_json( $assoc_args );
		list( $status, $body ) = $this->do_request( 'POST', $this->get_filled_route( $args ), $assoc_args );
		if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
			WP_CLI::line( $body['id'] );
		} else {
			WP_CLI::success( __( 'Updated', 'woocommerce' ) . " {$this->name} {$body['id']}." );
		}
	}

	/**
	 * Do a REST Request
	 *
	 * @param string $method Request method. Examples: 'POST', 'PUT', 'DELETE' or 'GET'.
	 * @param string $route Resource route.
	 * @param array  $assoc_args Associative arguments passed to the originating WP-CLI command.
	 *
	 * @return array
	 */
	private function do_request( $method, $route, $assoc_args ) {
		wc_maybe_define_constant( 'REST_REQUEST', true );

		$request = new WP_REST_Request( $method, $route );
		if ( in_array( $method, array( 'POST', 'PUT' ), true ) ) {
			$request->set_body_params( $assoc_args );
		} else {
			foreach ( $assoc_args as $key => $value ) {
				$request->set_param( $key, $value );
			}
		}
		if ( Constants::is_true( 'SAVEQUERIES' ) ) {
			$original_queries = is_array( $GLOBALS['wpdb']->queries ) ? array_keys( $GLOBALS['wpdb']->queries ) : array();
		}
		$response = rest_do_request( $request );
		if ( Constants::is_true( 'SAVEQUERIES' ) ) {
			$performed_queries = array();
			foreach ( (array) $GLOBALS['wpdb']->queries as $key => $query ) {
				if ( in_array( $key, $original_queries, true ) ) {
					continue;
				}
				$performed_queries[] = $query;
			}
			usort(
				$performed_queries,
				function( $a, $b ) {
					if ( $a[1] === $b[1] ) {
						return 0;
					}
					return ( $a[1] > $b[1] ) ? -1 : 1;
				}
			);

			$query_count      = count( $performed_queries );
			$query_total_time = 0;
			foreach ( $performed_queries as $query ) {
				$query_total_time += $query[1];
			}
			$slow_query_message = '';
			if ( $performed_queries && 'wc' === WP_CLI::get_config( 'debug' ) ) {
				$slow_query_message .= '. Ordered by slowness, the queries are:' . PHP_EOL;
				foreach ( $performed_queries as $i => $query ) {
					$i++;
					$bits                = explode( ', ', $query[2] );
					$backtrace           = implode( ', ', array_slice( $bits, 13 ) );
					$seconds             = NumberUtil::round( $query[1], 6 );
					$slow_query_message .= <<<EOT
{$i}:
- {$seconds} seconds
- {$backtrace}
- {$query[0]}
EOT;
					$slow_query_message .= PHP_EOL;
				}
			} elseif ( 'wc' !== WP_CLI::get_config( 'debug' ) ) {
				$slow_query_message = '. Use --debug=wc to see all queries.';
			}
			$query_total_time = NumberUtil::round( $query_total_time, 6 );
			WP_CLI::debug( "wc command executed {$query_count} queries in {$query_total_time} seconds{$slow_query_message}", 'wc' );
		}

		$error = $response->as_error();

		if ( $error ) {
			// For authentication errors (status 401), include a reminder to set the --user flag.
			// WP_CLI::error will only return the first message from WP_Error, so we will pass a string containing both instead.
			if ( 401 === $response->get_status() ) {
				$errors   = $error->get_error_messages();
				$errors[] = __( 'Make sure to include the --user flag with an account that has permissions for this action.', 'woocommerce' ) . ' {"status":401}';
				$error    = implode( "\n", $errors );
			}
			WP_CLI::error( $error );
		}
		return array( $response->get_status(), $response->get_data(), $response->get_headers() );
	}

	/**
	 * Get Formatter object based on supplied parameters.
	 *
	 * @param array $assoc_args Parameters passed to command. Determines formatting.
	 * @return \WP_CLI\Formatter
	 */
	protected function get_formatter( &$assoc_args ) {
		if ( ! empty( $assoc_args['fields'] ) ) {
			if ( is_string( $assoc_args['fields'] ) ) {
				$fields = explode( ',', $assoc_args['fields'] );
			} else {
				$fields = $assoc_args['fields'];
			}
		} else {
			if ( ! empty( $assoc_args['context'] ) ) {
				$fields = $this->get_context_fields( $assoc_args['context'] );
			} else {
				$fields = $this->get_context_fields( 'view' );
			}
		}
		return new \WP_CLI\Formatter( $assoc_args, $fields );
	}

	/**
	 * Get a list of fields present in a given context
	 *
	 * @param string $context Scope under which the request is made. Determines fields present in response.
	 * @return array
	 */
	private function get_context_fields( $context ) {
		$fields = array();
		foreach ( $this->schema['properties'] as $key => $args ) {
			if ( empty( $args['context'] ) || in_array( $context, $args['context'], true ) ) {
				$fields[] = $key;
			}
		}
		return $fields;
	}

	/**
	 * Get the route for this resource
	 *
	 * @param  array $args Positional arguments passed to the originating WP-CLI command.
	 * @return string
	 */
	private function get_filled_route( $args = array() ) {
		$supported_id_matched = false;
		$route                = $this->route;

		foreach ( $this->get_supported_ids() as $id_name => $id_desc ) {
			if ( 'id' !== $id_name && strpos( $route, '<' . $id_name . '>' ) !== false && ! empty( $args ) ) {
				$route                = str_replace( array( '(?P<' . $id_name . '>[\d]+)', '(?P<' . $id_name . '>\w[\w\s\-]*)' ), $args[0], $route );
				$supported_id_matched = true;
			}
		}

		if ( ! empty( $args ) ) {
			$id_replacement = $supported_id_matched && ! empty( $args[1] ) ? $args[1] : $args[0];
			$route          = str_replace( array( '(?P<id>[\d]+)', '(?P<id>[\w-]+)' ), $id_replacement, $route );
		}

		return rtrim( $route );
	}

	/**
	 * Reduce an item to specific fields.
	 *
	 * @param  array $item Item to reduce.
	 * @param  array $fields Fields to keep.
	 * @return array
	 */
	private static function limit_item_to_fields( $item, $fields ) {
		if ( empty( $fields ) ) {
			return $item;
		}
		if ( is_string( $fields ) ) {
			$fields = explode( ',', $fields );
		}
		foreach ( $item as $i => $field ) {
			if ( ! in_array( $i, $fields, true ) ) {
				unset( $item[ $i ] );
			}
		}
		return $item;
	}

	/**
	 * JSON can be passed in some more complicated objects, like the payment gateway settings array.
	 * This function decodes the json (if present) and tries to get it's value.
	 *
	 * @param array $arr Array that will be scanned for JSON encoded values.
	 *
	 * @return array
	 */
	protected function decode_json( $arr ) {
		foreach ( $arr as $key => $value ) {
			if ( '[' === substr( $value, 0, 1 ) || '{' === substr( $value, 0, 1 ) ) {
				$arr[ $key ] = json_decode( $value, true );
			} else {
				continue;
			}
		}
		return $arr;
	}

}
class-wc-cli-runner.php000064400000020362151542652740011063 0ustar00<?php
/**
 * WP_CLI_Runner class file.
 *
 * @package WooCommerce\CLI
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * WC API to WC CLI Bridge.
 *
 * Hooks into the REST API, figures out which endpoints come from WC,
 * and registers them as CLI commands.
 *
 * Forked from wp-cli/restful (by Daniel Bachhuber, released under the MIT license https://opensource.org/licenses/MIT).
 * https://github.com/wp-cli/restful
 *
 * @version 3.0.0
 * @package WooCommerce
 */
class WC_CLI_Runner {
	/**
	 * Endpoints to disable (meaning they will not be available as CLI commands).
	 * Some of these can either be done via WP already, or are offered with
	 * some other changes (like tools).
	 *
	 * @var array
	 */
	private static $disabled_endpoints = array(
		'settings',
		'settings/(?P<group_id>[\w-]+)',
		'settings/(?P<group_id>[\w-]+)/batch',
		'settings/(?P<group_id>[\w-]+)/(?P<id>[\w-]+)',
		'system_status',
		'system_status/tools',
		'system_status/tools/(?P<id>[\w-]+)',
		'reports',
		'reports/sales',
		'reports/top_sellers',
	);

	/**
	 * The version of the REST API we should target to
	 * generate commands.
	 *
	 * @var string
	 */
	private static $target_rest_version = 'v2';

	/**
	 * Register's all endpoints as commands once WP and WC have all loaded.
	 */
	public static function after_wp_load() {
		global $wp_rest_server;
		$wp_rest_server = new WP_REST_Server();
		do_action( 'rest_api_init', $wp_rest_server );

		$request = new WP_REST_Request( 'GET', '/' );
		$request->set_param( 'context', 'help' );
		$response      = $wp_rest_server->dispatch( $request );
		$response_data = $response->get_data();
		if ( empty( $response_data ) ) {
			return;
		}

		// Loop through all of our endpoints and register any valid WC endpoints.
		foreach ( $response_data['routes'] as $route => $route_data ) {
			// Only register endpoints for WC and our target version.
			if ( substr( $route, 0, 4 + strlen( self::$target_rest_version ) ) !== '/wc/' . self::$target_rest_version ) {
				continue;
			}

			// Only register endpoints with schemas.
			if ( empty( $route_data['schema']['title'] ) ) {
				/* translators: %s: Route to a given WC-API endpoint */
				WP_CLI::debug( sprintf( __( 'No schema title found for %s, skipping REST command registration.', 'woocommerce' ), $route ), 'wc' );
				continue;
			}
			// Ignore batch endpoints.
			if ( 'batch' === $route_data['schema']['title'] ) {
				continue;
			}
			// Disable specific endpoints.
			$route_pieces   = explode( '/', $route );
			$endpoint_piece = str_replace( '/wc/' . $route_pieces[2] . '/', '', $route );
			if ( in_array( $endpoint_piece, self::$disabled_endpoints, true ) ) {
				continue;
			}

			self::register_route_commands( new WC_CLI_REST_Command( $route_data['schema']['title'], $route, $route_data['schema'] ), $route, $route_data );
		}
	}

	/**
	 * Generates command information and tells WP CLI about all
	 * commands available from a route.
	 *
	 * @param string $rest_command WC-API command.
	 * @param string $route Path to route endpoint.
	 * @param array  $route_data Command data.
	 * @param array  $command_args WP-CLI command arguments.
	 */
	private static function register_route_commands( $rest_command, $route, $route_data, $command_args = array() ) {
		// Define IDs that we are looking for in the routes (in addition to id)
		// so that we can pass it to the rest command, and use it here to generate documentation.
		$supported_ids = array(
			'product_id'   => __( 'Product ID.', 'woocommerce' ),
			'customer_id'  => __( 'Customer ID.', 'woocommerce' ),
			'order_id'     => __( 'Order ID.', 'woocommerce' ),
			'refund_id'    => __( 'Refund ID.', 'woocommerce' ),
			'attribute_id' => __( 'Attribute ID.', 'woocommerce' ),
			'zone_id'      => __( 'Zone ID.', 'woocommerce' ),
			'instance_id'  => __( 'Instance ID.', 'woocommerce' ),
			'id'           => __( 'The ID for the resource.', 'woocommerce' ),
			'slug'         => __( 'The slug for the resource.', 'woocommerce' ),
		);
		$rest_command->set_supported_ids( $supported_ids );
		$positional_args = array_keys( $supported_ids );
		$parent             = "wc {$route_data['schema']['title']}";
		$supported_commands = array();

		// Get a list of supported commands for each route.
		foreach ( $route_data['endpoints'] as $endpoint ) {
			preg_match_all( '#\([^\)]+\)#', $route, $matches );
			$resource_id   = ! empty( $matches[0] ) ? array_pop( $matches[0] ) : null;
			$trimmed_route = rtrim( $route );
			$is_singular   = substr( $trimmed_route, - strlen( $resource_id ?? '' ) ) === $resource_id;

			// List a collection.
			if ( array( 'GET' ) === $endpoint['methods'] && ! $is_singular ) {
				$supported_commands['list'] = ! empty( $endpoint['args'] ) ? $endpoint['args'] : array();
			}
			// Create a specific resource.
			if ( array( 'POST' ) === $endpoint['methods'] && ! $is_singular ) {
				$supported_commands['create'] = ! empty( $endpoint['args'] ) ? $endpoint['args'] : array();
			}
			// Get a specific resource.
			if ( array( 'GET' ) === $endpoint['methods'] && $is_singular ) {
				$supported_commands['get'] = ! empty( $endpoint['args'] ) ? $endpoint['args'] : array();
			}
			// Update a specific resource.
			if ( in_array( 'POST', $endpoint['methods'], true ) && $is_singular ) {
				$supported_commands['update'] = ! empty( $endpoint['args'] ) ? $endpoint['args'] : array();
			}
			// Delete a specific resource.
			if ( array( 'DELETE' ) === $endpoint['methods'] && $is_singular ) {
				$supported_commands['delete'] = ! empty( $endpoint['args'] ) ? $endpoint['args'] : array();
			}
		}

		foreach ( $supported_commands as $command => $endpoint_args ) {
			$synopsis = array();
			$arg_regs = array();
			$ids      = array();

			foreach ( $supported_ids as $id_name => $id_desc ) {
				if ( strpos( $route, '<' . $id_name . '>' ) !== false ) {
					$synopsis[] = array(
						'name'        => $id_name,
						'type'        => 'positional',
						'description' => $id_desc,
						'optional'    => false,
					);
					$ids[]      = $id_name;
				}
			}

			foreach ( $endpoint_args as $name => $args ) {
				if ( ! in_array( $name, $positional_args, true ) || strpos( $route, '<' . $id_name . '>' ) === false ) {
					$arg_regs[] = array(
						'name'        => $name,
						'type'        => 'assoc',
						'description' => ! empty( $args['description'] ) ? $args['description'] : '',
						'optional'    => empty( $args['required'] ),
					);
				}
			}

			foreach ( $arg_regs as $arg_reg ) {
				$synopsis[] = $arg_reg;
			}

			if ( in_array( $command, array( 'list', 'get' ), true ) ) {
				$synopsis[] = array(
					'name'        => 'fields',
					'type'        => 'assoc',
					'description' => __( 'Limit response to specific fields. Defaults to all fields.', 'woocommerce' ),
					'optional'    => true,
				);
				$synopsis[] = array(
					'name'        => 'field',
					'type'        => 'assoc',
					'description' => __( 'Get the value of an individual field.', 'woocommerce' ),
					'optional'    => true,
				);
				$synopsis[] = array(
					'name'        => 'format',
					'type'        => 'assoc',
					'description' => __( 'Render response in a particular format.', 'woocommerce' ),
					'optional'    => true,
					'default'     => 'table',
					'options'     => array(
						'table',
						'json',
						'csv',
						'ids',
						'yaml',
						'count',
						'headers',
						'body',
						'envelope',
					),
				);
			}

			if ( in_array( $command, array( 'create', 'update', 'delete' ), true ) ) {
				$synopsis[] = array(
					'name'        => 'porcelain',
					'type'        => 'flag',
					'description' => __( 'Output just the id when the operation is successful.', 'woocommerce' ),
					'optional'    => true,
				);
			}

			$methods = array(
				'list'   => 'list_items',
				'create' => 'create_item',
				'delete' => 'delete_item',
				'get'    => 'get_item',
				'update' => 'update_item',
			);

			$before_invoke = null;
			if ( empty( $command_args['when'] ) && \WP_CLI::get_config( 'debug' ) ) {
				$before_invoke = function() {
					wc_maybe_define_constant( 'SAVEQUERIES', true );
				};
			}

			WP_CLI::add_command(
				"{$parent} {$command}",
				array( $rest_command, $methods[ $command ] ),
				array(
					'synopsis'      => $synopsis,
					'when'          => ! empty( $command_args['when'] ) ? $command_args['when'] : '',
					'before_invoke' => $before_invoke,
				)
			);
		}
	}
}
class-wc-cli-tool-command.php000064400000005546151542652740012152 0ustar00<?php
/**
 * WC_CLI_Tool_Command class file.
 *
 * @package WooCommerce\CLI
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Hooks up our system status tools to the CLI.
 *
 * Forked from wp-cli/restful (by Daniel Bachhuber, released under the MIT license https://opensource.org/licenses/MIT).
 * https://github.com/wp-cli/restful
 *
 * @version 3.0.0
 * @package WooCommerce
 */
class WC_CLI_Tool_Command {

	/**
	 * Registers just a 'list' and 'run' command to the WC CLI
	 * since we only want to enable certain actions on the system status
	 * tools endpoints.
	 */
	public static function register_commands() {
		global $wp_rest_server;

		$request       = new WP_REST_Request( 'OPTIONS', '/wc/v2/system_status/tools' );
		$response      = $wp_rest_server->dispatch( $request );
		$response_data = $response->get_data();
		if ( empty( $response_data ) ) {
			return;
		}

		$parent             = 'wc tool';
		$supported_commands = array( 'list', 'run' );
		foreach ( $supported_commands as $command ) {
			$synopsis = array();
			if ( 'run' === $command ) {
				$synopsis[] = array(
					'name'        => 'id',
					'type'        => 'positional',
					'description' => __( 'The id for the resource.', 'woocommerce' ),
					'optional'    => false,
				);
				$method     = 'update_item';
				$route      = '/wc/v2/system_status/tools/(?P<id>[\w-]+)';
			} elseif ( 'list' === $command ) {
				$synopsis[] = array(
					'name'        => 'fields',
					'type'        => 'assoc',
					'description' => __( 'Limit response to specific fields. Defaults to all fields.', 'woocommerce' ),
					'optional'    => true,
				);
				$synopsis[] = array(
					'name'        => 'field',
					'type'        => 'assoc',
					'description' => __( 'Get the value of an individual field.', 'woocommerce' ),
					'optional'    => true,
				);
				$synopsis[] = array(
					'name'        => 'format',
					'type'        => 'assoc',
					'description' => __( 'Render response in a particular format.', 'woocommerce' ),
					'optional'    => true,
					'default'     => 'table',
					'options'     => array(
						'table',
						'json',
						'csv',
						'ids',
						'yaml',
						'count',
						'headers',
						'body',
						'envelope',
					),
				);
				$method     = 'list_items';
				$route      = '/wc/v2/system_status/tools';
			}

			$before_invoke = null;
			if ( empty( $command_args['when'] ) && WP_CLI::get_config( 'debug' ) ) {
				$before_invoke = function() {
					wc_maybe_define_constant( 'SAVEQUERIES', true );
				};
			}

			$rest_command = new WC_CLI_REST_Command( 'system_status_tool', $route, $response_data['schema'] );

			WP_CLI::add_command(
				"{$parent} {$command}",
				array( $rest_command, $method ),
				array(
					'synopsis'      => $synopsis,
					'when'          => ! empty( $command_args['when'] ) ? $command_args['when'] : '',
					'before_invoke' => $before_invoke,
				)
			);
		}
	}

}
class-wc-cli-tracker-command.php000064400000002353151542652750012622 0ustar00<?php
/**
 * WC_CLI_Tracker_Command class file.
 *
 * @package WooCommerce\CLI
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Allows access to tracker snapshot for transparency and debugging.
 *
 * @since 5.5.0
 * @package WooCommerce
 */
class WC_CLI_Tracker_Command {

	/**
	 * Registers a command for showing WooCommerce Tracker snapshot data.
	 */
	public static function register_commands() {
		WP_CLI::add_command( 'wc tracker snapshot', array( 'WC_CLI_Tracker_Command', 'show_tracker_snapshot' ) );
	}

	/**
	 * Dump tracker snapshot data to screen.
	 *
	 * ## EXAMPLES
	 *
	 * wp wc tracker snapshot --format=yaml
	 * wp wc tracker snapshot --format=json
	 *
	 * ## OPTIONS
	 *
	 * [--format=<format>]
	 * : Render output in a particular format, see WP_CLI\Formatter for details.
	 *
	 * @see \WP_CLI\Formatter
	 * @see WC_Tracker::get_tracking_data()
	 * @param array $args WP-CLI positional arguments.
	 * @param array $assoc_args WP-CLI associative arguments.
	 */
	public static function show_tracker_snapshot( $args, $assoc_args ) {
		$snapshot_data = WC_Tracker::get_tracking_data();

		$formatter = new \WP_CLI\Formatter(
			$assoc_args,
			array_keys( $snapshot_data )
		);

		$formatter->display_items( array( $snapshot_data ) );
	}
}
class-wc-cli-update-command.php000064400000005102151542652760012445 0ustar00<?php
/**
 * WC_CLI_Update_Command class file.
 *
 * @package WooCommerce\CLI
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Allows updates via CLI.
 *
 * @version 3.0.0
 * @package WooCommerce
 */
class WC_CLI_Update_Command {

	/**
	 * Registers the update command.
	 */
	public static function register_commands() {
		WC()->call_static( WP_CLI::class, 'add_command', 'wc update', array( 'WC_CLI_Update_Command', 'update' ) );
	}

	/**
	 * Runs all pending WooCommerce database updates.
	 */
	public static function update() {
		global $wpdb;

		$wpdb->hide_errors();

		include_once WC_ABSPATH . 'includes/class-wc-install.php';
		include_once WC_ABSPATH . 'includes/wc-update-functions.php';

		$current_db_version = get_option( 'woocommerce_db_version' );
		$update_count       = 0;
		$callbacks          = WC_Install::get_db_update_callbacks();
		$callbacks_to_run   = array();

		foreach ( $callbacks as $version => $update_callbacks ) {
			if ( version_compare( $current_db_version, $version, '<' ) ) {
				foreach ( $update_callbacks as $update_callback ) {
					$callbacks_to_run[] = $update_callback;
				}
			}
		}

		if ( empty( $callbacks_to_run ) ) {
			// Ensure DB version is set to the current WC version to match WP-Admin update routine.
			WC_Install::update_db_version();

			WC()->call_static(
				WP_CLI::class,
				'success',
				/* translators: %s Database version number */
				sprintf( __( 'No updates required. Database version is %s', 'woocommerce' ), get_option( 'woocommerce_db_version' ) )
			);
			return;
		}

		WC()->call_static(
			WP_CLI::class,
			'log',
			/* translators: 1: Number of database updates 2: List of update callbacks */
			sprintf( __( 'Found %1$d updates (%2$s)', 'woocommerce' ), count( $callbacks_to_run ), implode( ', ', $callbacks_to_run ) )
		);

		$progress = WC()->call_function(
			'WP_CLI\Utils\make_progress_bar',
			__( 'Updating database', 'woocommerce' ),
			count( $callbacks_to_run ) // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
		);

		foreach ( $callbacks_to_run as $update_callback ) {
			call_user_func( $update_callback );
			$update_count ++;
			$progress->tick();
		}

		WC_Install::update_db_version();
		$progress->finish();

		WC_Admin_Notices::remove_notice( 'update', true );

		WC()->call_static(
			WP_CLI::class,
			'success',
			/* translators: 1: Number of database updates performed 2: Database version number */
			sprintf( __( '%1$d update functions completed. Database version is %2$s', 'woocommerce' ), absint( $update_count ), get_option( 'woocommerce_db_version' ) )
		);
	}
}