rebase from live enviornment

This commit is contained in:
Rachit Bhargava
2024-01-09 22:14:20 -05:00
parent ff0b49a046
commit 3a22fcaa4a
15968 changed files with 2344674 additions and 45234 deletions

View File

@@ -0,0 +1,199 @@
<?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://woo.com/my-account/#application-passwords';
/**
* Registers a commands for managing Woo.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 Woo.com. Run `wp wc com connect` command.', 'woocommerce' ) );
}
WP_CLI::confirm( __( 'Are you sure you want to disconnect your store from Woo.com?', 'woocommerce' ), $assoc_args );
WC_Helper::disconnect();
WP_CLI::success( __( 'You have successfully disconnected your store from Woo.com', 'woocommerce' ) );
}
/**
* Connects to Woo.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 Woo.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 Woo.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
}
}

View File

@@ -0,0 +1,103 @@
<?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 Woo.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 Woo.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 );
}
}

View File

@@ -0,0 +1,467 @@
<?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;
}
}

View File

@@ -0,0 +1,254 @@
<?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,
)
);
}
}
}

View File

@@ -0,0 +1,107 @@
<?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,
)
);
}
}
}

View File

@@ -0,0 +1,55 @@
<?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 ) );
}
}

View File

@@ -0,0 +1,95 @@
<?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' ) )
);
}
}