Merge pull request #12345 from woocommerce/remove/cli

Remove CLI
This commit is contained in:
Justin Shreve 2016-11-14 03:44:02 -08:00 committed by GitHub
commit b0f859f6a2
13 changed files with 2 additions and 6545 deletions

View File

@ -81,8 +81,6 @@ class WC_Autoloader {
$path = $this->include_path . 'admin/meta-boxes/';
} elseif ( strpos( $class, 'wc_admin' ) === 0 ) {
$path = $this->include_path . 'admin/';
} elseif ( strpos( $class, 'wc_cli_' ) === 0 ) {
$path = $this->include_path . 'cli/';
} elseif ( strpos( $class, 'wc_payment_token_' ) === 0 ) {
$path = $this->include_path . 'payment-tokens/';
}

View File

@ -1,23 +1,6 @@
<?php
/**
* Manage WooCommerce from CLI.
* Deprecated. No longer needed.
*
* @class WC_CLI
* @version 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
* @package WooCommerce
*/
class WC_CLI extends WP_CLI_Command {
}
WP_CLI::add_command( 'wc', 'WC_CLI' );
WP_CLI::add_command( 'wc coupon', 'WC_CLI_Coupon' );
WP_CLI::add_command( 'wc customer', 'WC_CLI_Customer' );
WP_CLI::add_command( 'wc order', 'WC_CLI_Order' );
WP_CLI::add_command( 'wc product', 'WC_CLI_Product' );
WP_CLI::add_command( 'wc product category', 'WC_CLI_Product_Category' );
WP_CLI::add_command( 'wc report', 'WC_CLI_Report' );
WP_CLI::add_command( 'wc tax', 'WC_CLI_Tax' );
WP_CLI::add_command( 'wc tool', 'WC_CLI_Tool' );

View File

@ -1,407 +0,0 @@
<?php
/**
* WooCommerce CLI Command.
*
* Base class that must be extended by any WooCommerce sub commands.
*
* @class WC_CLI_Command
* @version 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
class WC_CLI_Command extends WP_CLI_Command {
/**
* Add common cli arguments to argument list before WP_Query is run.
*
* @since 2.5.0
* @param array $base_args Required arguments for the query (e.g. `post_type`, etc)
* @param array $assoc_args Arguments provided in when invoking the command
* @return array
*/
protected function merge_wp_query_args( $base_args, $assoc_args ) {
$args = array();
// date
if ( ! empty( $assoc_args['created_at_min'] ) || ! empty( $assoc_args['created_at_max'] ) || ! empty( $assoc_args['updated_at_min'] ) || ! empty( $assoc_args['updated_at_max'] ) ) {
$args['date_query'] = array();
// resources created after specified date
if ( ! empty( $assoc_args['created_at_min'] ) ) {
$args['date_query'][] = array( 'column' => 'post_date_gmt', 'after' => $this->parse_datetime( $assoc_args['created_at_min'] ), 'inclusive' => true );
}
// resources created before specified date
if ( ! empty( $assoc_args['created_at_max'] ) ) {
$args['date_query'][] = array( 'column' => 'post_date_gmt', 'before' => $this->parse_datetime( $assoc_args['created_at_max'] ), 'inclusive' => true );
}
// resources updated after specified date
if ( ! empty( $assoc_args['updated_at_min'] ) ) {
$args['date_query'][] = array( 'column' => 'post_modified_gmt', 'after' => $this->parse_datetime( $assoc_args['updated_at_min'] ), 'inclusive' => true );
}
// resources updated before specified date
if ( ! empty( $assoc_args['updated_at_max'] ) ) {
$args['date_query'][] = array( 'column' => 'post_modified_gmt', 'before' => $this->parse_datetime( $assoc_args['updated_at_max'] ), 'inclusive' => true );
}
}
// Search.
if ( ! empty( $assoc_args['q'] ) ) {
$args['s'] = $assoc_args['q'];
}
// Number of post to show per page.
if ( ! empty( $assoc_args['limit'] ) ) {
$args['posts_per_page'] = $assoc_args['limit'];
}
// Number of post to displace or pass over.
if ( ! empty( $assoc_args['offset'] ) ) {
$args['offset'] = $assoc_args['offset'];
}
// order (ASC or DESC, DESC by default).
if ( ! empty( $assoc_args['order'] ) ) {
$args['order'] = $assoc_args['order'];
}
// orderby.
if ( ! empty( $assoc_args['orderby'] ) ) {
$args['orderby'] = $assoc_args['orderby'];
// allow sorting by meta value
if ( ! empty( $assoc_args['orderby_meta_key'] ) ) {
$args['meta_key'] = $assoc_args['orderby_meta_key'];
}
}
// allow post status change
if ( ! empty( $assoc_args['post_status'] ) ) {
$args['post_status'] = $assoc_args['post_status'];
unset( $assoc_args['post_status'] );
}
// filter by a list of post ids
if ( ! empty( $assoc_args['in'] ) ) {
$args['post__in'] = explode( ',', $assoc_args['in'] );
unset( $assoc_args['in'] );
}
// exclude by a list of post ids
if ( ! empty( $assoc_args['not_in'] ) ) {
$args['post__not_in'] = explode( ',', $assoc_args['not_in'] );
unset( $assoc_args['not_in'] );
}
// posts page.
$args['paged'] = ( isset( $assoc_args['page'] ) ) ? absint( $assoc_args['page'] ) : 1;
$args = apply_filters( 'woocommerce_cli_query_args', $args, $assoc_args );
return array_merge( $base_args, $args );
}
/**
* Add common cli arguments to argument list before WP_User_Query is run.
*
* @since 2.5.0
* @param array $base_args required arguments for the query (e.g. `post_type`, etc)
* @param array $assoc_args arguments provided in when invoking the command
* @return array
*/
protected function merge_wp_user_query_args( $base_args, $assoc_args ) {
$args = array();
// Custom Role
if ( ! empty( $assoc_args['role'] ) ) {
$args['role'] = $assoc_args['role'];
}
// Search
if ( ! empty( $assoc_args['q'] ) ) {
$args['search'] = $assoc_args['q'];
}
// Limit number of users returned.
if ( ! empty( $assoc_args['limit'] ) ) {
$args['number'] = absint( $assoc_args['limit'] );
}
// Offset
if ( ! empty( $assoc_args['offset'] ) ) {
$args['offset'] = absint( $assoc_args['offset'] );
}
// date
if ( ! empty( $assoc_args['created_at_min'] ) || ! empty( $assoc_args['created_at_max'] ) ) {
$args['date_query'] = array();
// resources created after specified date
if ( ! empty( $assoc_args['created_at_min'] ) ) {
$args['date_query'][] = array( 'after' => $this->parse_datetime( $assoc_args['created_at_min'] ), 'inclusive' => true );
}
// resources created before specified date
if ( ! empty( $assoc_args['created_at_max'] ) ) {
$args['date_query'][] = array( 'before' => $this->parse_datetime( $assoc_args['created_at_max'] ), 'inclusive' => true );
}
}
// Order (ASC or DESC, ASC by default).
if ( ! empty( $assoc_args['order'] ) ) {
$args['order'] = $assoc_args['order'];
}
// Orderby.
if ( ! empty( $assoc_args['orderby'] ) ) {
$args['orderby'] = $assoc_args['orderby'];
}
$args = apply_filters( 'woocommerce_cli_user_query_args', $args, $assoc_args );
return array_merge( $base_args, $args );
}
/**
* Parse an RFC3339 datetime into a MySQl datetime.
*
* Invalid dates default to unix epoch.
*
* @since 2.5.0
* @param string $datetime RFC3339 datetime
* @return string MySQl datetime (YYYY-MM-DD HH:MM:SS)
*/
protected function parse_datetime( $datetime ) {
// Strip millisecond precision (a full stop followed by one or more digits)
if ( strpos( $datetime, '.' ) !== false ) {
$datetime = preg_replace( '/\.\d+/', '', $datetime );
}
// default timezone to UTC
$datetime = preg_replace( '/[+-]\d+:+\d+$/', '+00:00', $datetime );
try {
$datetime = new DateTime( $datetime, new DateTimeZone( 'UTC' ) );
} catch ( Exception $e ) {
$datetime = new DateTime( '@0' );
}
return $datetime->format( 'Y-m-d H:i:s' );
}
/**
* Format a unix timestamp or MySQL datetime into an RFC3339 datetime.
*
* @since 2.5.0
* @param int|string $timestamp unix timestamp or MySQL datetime
* @param bool $convert_to_utc
* @return string RFC3339 datetime
*/
protected function format_datetime( $timestamp, $convert_to_utc = false ) {
if ( $convert_to_utc ) {
$timezone = new DateTimeZone( wc_timezone_string() );
} else {
$timezone = new DateTimeZone( 'UTC' );
}
try {
if ( is_numeric( $timestamp ) ) {
$date = new DateTime( "@{$timestamp}" );
} else {
$date = new DateTime( $timestamp, $timezone );
}
// convert to UTC by adjusting the time based on the offset of the site's timezone
if ( $convert_to_utc ) {
$date->modify( -1 * $date->getOffset() . ' seconds' );
}
} catch ( Exception $e ) {
$date = new DateTime( '@0' );
}
return $date->format( 'Y-m-d\TH:i:s\Z' );
}
/**
* Get formatter object based on supplied arguments.
*
* @since 2.5.0
* @param array $assoc_args Associative args from CLI to determine formatting
* @return \WP_CLI\Formatter
*/
protected function get_formatter( $assoc_args ) {
$args = $this->get_format_args( $assoc_args );
return new \WP_CLI\Formatter( $args );
}
/**
* Get default fields for formatter.
*
* Class that extends WC_CLI_Command should override this method.
*
* @since 2.5.0
* @return null|string|array
*/
protected function get_default_format_fields() {
return null;
}
/**
* Get format args that will be passed into CLI Formatter.
*
* @since 2.5.0
* @param array $assoc_args Associative args from CLI
* @return array Formatter args
*/
protected function get_format_args( $assoc_args ) {
$format_args = array(
'fields' => $this->get_default_format_fields(),
'field' => null,
'format' => 'table',
);
if ( isset( $assoc_args['fields'] ) ) {
$format_args['fields'] = $assoc_args['fields'];
}
if ( isset( $assoc_args['field'] ) ) {
$format_args['field'] = $assoc_args['field'];
}
if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], array( 'count', 'ids', 'table', 'csv', 'json' ) ) ) {
$format_args['format'] = $assoc_args['format'];
}
return $format_args;
}
/**
* Flatten multidimensional array in which nested array will be prefixed with
* parent keys separated with dot char, e.g. given an array:
*
* array(
* 'a' => array(
* 'b' => array(
* 'c' => ...
* )
* )
* )
*
* a flatten array would contain key 'a.b.c' => ...
*
* @since 2.5.0
* @param array $arr Array that may contains nested array
* @param string $prefix Prefix
*
* @return array Flattened array
*/
protected function flatten_array( $arr, $prefix = '' ) {
$flattened = array();
foreach ( $arr as $key => $value ) {
if ( is_array( $value ) ) {
if ( sizeof( $value ) > 0 ) {
// Full access to whole elements if indices are numerical.
$flattened[ $prefix . $key ] = $value;
// This is naive assumption that if element with index zero
// exists then array indices are numberical.
if ( ! empty( $value[0] ) ) {
// Allow size of array to be accessed, i.e., a.b.arr.size
$flattened[ $prefix . $key . '.size' ] = sizeof( $value );
}
$flattened = array_merge( $flattened, $this->flatten_array( $value, $prefix . $key . '.' ) );
} else {
$flattened[ $prefix . $key ] = '';
// Tells user that size of this array is zero.
$flattened[ $prefix . $key . '.size' ] = 0;
}
} else {
$flattened[ $prefix . $key ] = $value;
}
}
return $flattened;
}
/**
* Unflatten array will make key 'a.b.c' becomes nested array:
*
* array(
* 'a' => array(
* 'b' => array(
* 'c' => ...
* )
* )
* )
*
* @since 2.5.0
* @param array $arr Flattened array
* @return array
*/
protected function unflatten_array( $arr ) {
$unflatten = array();
foreach ( $arr as $key => $value ) {
$key_list = explode( '.', $key );
$first_key = array_shift( $key_list );
$first_key = $this->get_normalized_array_key( $first_key );
if ( sizeof( $key_list ) > 0 ) {
$remaining_keys = implode( '.', $key_list );
$subarray = $this->unflatten_array( array( $remaining_keys => $value ) );
foreach ( $subarray as $sub_key => $sub_value ) {
$sub_key = $this->get_normalized_array_key( $sub_key );
if ( ! empty( $unflatten[ $first_key ][ $sub_key ] ) ) {
$unflatten[ $first_key ][ $sub_key ] = array_merge_recursive( $unflatten[ $first_key ][ $sub_key ], $sub_value );
} else {
$unflatten[ $first_key ][ $sub_key ] = $sub_value;
}
}
} else {
$unflatten[ $first_key ] = $value;
}
}
return $unflatten;
}
/**
* Get normalized array key. If key is a numeric one it will be converted
* as absolute integer.
*
* @since 2.5.0
* @param string $key Array key
* @return string|int
*/
protected function get_normalized_array_key( $key ) {
if ( is_numeric( $key ) ) {
$key = absint( $key );
}
return $key;
}
/**
* Check if the value is equal to 'yes', 'true' or '1'
*
* @since 2.5.4
* @param string $value
* @return boolean
*/
protected function is_true( $value ) {
return ( 'yes' === $value || 'true' === $value || '1' === $value ) ? true : false;
}
}

View File

@ -1,672 +0,0 @@
<?php
/**
* Manage Coupons.
*
* @since 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
class WC_CLI_Coupon extends WC_CLI_Command {
/**
* Create a coupon.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Associative args for the new coupon.
*
* [--porcelain]
* : Outputs just the new coupon id.
*
* ## AVAILABLE FIELDS
*
* These fields are available for create command:
*
* * code
* * type
* * amount
* * description
* * expiry_date
* * individual_use
* * product_ids
* * exclude_product_ids
* * usage_limit
* * usage_limit_per_user
* * limit_usage_to_x_items
* * usage_count
* * enable_free_shipping
* * product_category_ids
* * exclude_product_category_ids
* * minimum_amount
* * maximum_amount
* * customer_emails
*
* ## EXAMPLES
*
* wp wc coupon create --code=new-coupon --type=percent
*
*/
public function create( $__, $assoc_args ) {
global $wpdb;
try {
$porcelain = isset( $assoc_args['porcelain'] );
unset( $assoc_args['porcelain'] );
$assoc_args = apply_filters( 'woocommerce_cli_create_coupon_data', $assoc_args );
// Check if coupon code is specified.
if ( ! isset( $assoc_args['code'] ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_missing_coupon_code', sprintf( __( 'Missing parameter %s', 'woocommerce' ), 'code' ) );
}
$coupon_code = apply_filters( 'woocommerce_coupon_code', $assoc_args['code'] );
// Check for duplicate coupon codes.
$coupon_found = $wpdb->get_var( $wpdb->prepare( "
SELECT $wpdb->posts.ID
FROM $wpdb->posts
WHERE $wpdb->posts.post_type = 'shop_coupon'
AND $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_title = '%s'
", $coupon_code ) );
if ( $coupon_found ) {
throw new WC_CLI_Exception( 'woocommerce_cli_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ) );
}
$defaults = array(
'type' => 'fixed_cart',
'amount' => 0,
'individual_use' => false,
'product_ids' => array(),
'exclude_product_ids' => array(),
'usage_limit' => '',
'usage_limit_per_user' => '',
'limit_usage_to_x_items' => '',
'usage_count' => '',
'expiry_date' => '',
'enable_free_shipping' => false,
'product_category_ids' => array(),
'exclude_product_category_ids' => array(),
'exclude_sale_items' => false,
'minimum_amount' => '',
'maximum_amount' => '',
'customer_emails' => array(),
'description' => '',
);
$coupon_data = wp_parse_args( $assoc_args, $defaults );
// Validate coupon types
if ( ! in_array( wc_clean( $coupon_data['type'] ), array_keys( wc_get_coupon_types() ) ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_coupon_type', sprintf( __( 'Invalid coupon type - the coupon type must be any of these: %s', 'woocommerce' ), implode( ', ', array_keys( wc_get_coupon_types() ) ) ) );
}
$new_coupon = array(
'post_title' => $coupon_code,
'post_content' => '',
'post_status' => 'publish',
'post_author' => get_current_user_id(),
'post_type' => 'shop_coupon',
'post_excerpt' => $coupon_data['description'],
);
$id = wp_insert_post( $new_coupon, $wp_error = false );
if ( is_wp_error( $id ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_cannot_create_coupon', $id->get_error_message() );
}
// Set coupon meta
update_post_meta( $id, 'discount_type', $coupon_data['type'] );
update_post_meta( $id, 'coupon_amount', wc_format_decimal( $coupon_data['amount'] ) );
update_post_meta( $id, 'individual_use', ( $this->is_true( $coupon_data['individual_use'] ) ) ? 'yes' : 'no' );
update_post_meta( $id, 'product_ids', implode( ',', array_filter( array_map( 'intval', $coupon_data['product_ids'] ) ) ) );
update_post_meta( $id, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $coupon_data['exclude_product_ids'] ) ) ) );
update_post_meta( $id, 'usage_limit', absint( $coupon_data['usage_limit'] ) );
update_post_meta( $id, 'usage_limit_per_user', absint( $coupon_data['usage_limit_per_user'] ) );
update_post_meta( $id, 'limit_usage_to_x_items', absint( $coupon_data['limit_usage_to_x_items'] ) );
update_post_meta( $id, 'usage_count', absint( $coupon_data['usage_count'] ) );
update_post_meta( $id, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $coupon_data['expiry_date'] ) ) );
update_post_meta( $id, 'free_shipping', ( $this->is_true( $coupon_data['enable_free_shipping'] ) ) ? 'yes' : 'no' );
update_post_meta( $id, 'product_categories', array_filter( array_map( 'intval', $coupon_data['product_category_ids'] ) ) );
update_post_meta( $id, 'exclude_product_categories', array_filter( array_map( 'intval', $coupon_data['exclude_product_category_ids'] ) ) );
update_post_meta( $id, 'exclude_sale_items', ( $this->is_true( $coupon_data['exclude_sale_items'] ) ) ? 'yes' : 'no' );
update_post_meta( $id, 'minimum_amount', wc_format_decimal( $coupon_data['minimum_amount'] ) );
update_post_meta( $id, 'maximum_amount', wc_format_decimal( $coupon_data['maximum_amount'] ) );
update_post_meta( $id, 'customer_email', array_filter( array_map( 'sanitize_email', $coupon_data['customer_emails'] ) ) );
do_action( 'woocommerce_cli_create_coupon', $id, $coupon_data );
if ( $porcelain ) {
WP_CLI::line( $id );
} else {
WP_CLI::success( "Created coupon $id." );
}
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Delete one or more coupons.
*
* ## OPTIONS
*
* <id>...
* : The coupon ID to delete.
*
* ## EXAMPLES
*
* wp wc coupon delete 123
*
* wp wc coupon delete $(wp wc coupon list --format=ids)
*
*/
public function delete( $args, $assoc_args ) {
$exit_code = 0;
foreach ( $this->get_many_coupons_from_ids_or_codes( $args, true ) as $coupon ) {
do_action( 'woocommerce_cli_delete_coupon', $coupon->get_id() );
$r = wp_delete_post( $coupon->get_id(), true );
if ( $r ) {
WP_CLI::success( "Deleted coupon " . $coupon->get_id() );
} else {
$exit_code += 1;
WP_CLI::warning( "Failed deleting coupon " . $coupon->get_id() );
}
}
exit( $exit_code ? 1 : 0 );
}
/**
* Get a coupon.
*
* ## OPTIONS
*
* <coupon>
* : Coupon ID or code
*
* [--field=<field>]
* : Instead of returning the whole coupon fields, returns the value of a single fields.
*
* [--fields=<fields>]
* : Get a specific subset of the coupon's fields.
*
* [--format=<format>]
* : Accepted values: table, json, csv. Default: table.
*
* ## AVAILABLE FIELDS
*
* These fields are available for get command:
*
* * id
* * code
* * type
* * amount
* * description
* * expiry_date
* * individual_use
* * product_ids
* * exclude_product_ids
* * usage_limit
* * usage_limit_per_user
* * limit_usage_to_x_items
* * usage_count
* * enable_free_shipping
* * product_category_ids
* * exclude_product_category_ids
* * minimum_amount
* * maximum_amount
* * customer_emails
*
* ## EXAMPLES
*
* wp wc coupon get 123 --field=discount_type
*
* wp wc coupon get disc50 --format=json > disc50.json
*
* @since 2.5.0
*/
public function get( $args, $assoc_args ) {
global $wpdb;
try {
$coupon = $this->get_coupon_from_id_or_code( $args[0] );
if ( ! $coupon ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_coupon', sprintf( __( 'Invalid coupon ID or code: %s', 'woocommerce' ), $args[0] ) );
}
$coupon_post = get_post( $coupon->get_id() );
$coupon_usage_limit = $coupon->get_usage_limit();
$coupon_usage_limit_per_user = $coupon->get_usage_limit_per_user();
$coupon_date_expires = $coupon->get_date_expires();
$coupon_data = array(
'id' => $coupon->get_id(),
'code' => $coupon->get_code(),
'type' => $coupon->get_discount_type(),
'created_at' => $this->format_datetime( $coupon_post->post_date_gmt ),
'updated_at' => $this->format_datetime( $coupon_post->post_modified_gmt ),
'amount' => wc_format_decimal( $coupon->get_amount(), 2 ),
'individual_use' => $coupon->get_individual_use(),
'product_ids' => implode( ', ', $coupon->get_product_ids() ),
'exclude_product_ids' => implode( ', ', $coupon->get_excluded_product_ids() ),
'usage_limit' => ( ! empty( $coupon_usage_limit ) ) ? $coupon_usage_limit : null,
'usage_limit_per_user' => ( ! empty( $coupon_usage_limit_per_user ) ) ? $coupon_usage_limit_per_user : null,
'limit_usage_to_x_items' => (int) $coupon->get_limit_usage_to_x_items(),
'usage_count' => (int) $coupon->get_usage_count(),
'expiry_date' => ( ! empty( $coupon_date_expires ) ) ? $this->format_datetime( $coupon_date_expires ) : null,
'enable_free_shipping' => $coupon->get_free_shipping(),
'product_category_ids' => implode( ', ', $coupon->get_product_categories() ),
'exclude_product_category_ids' => implode( ', ', $coupon->get_excluded_product_categories() ),
'exclude_sale_items' => $coupon->get_exclude_sale_items(),
'minimum_amount' => wc_format_decimal( $coupon->get_minimum_amount(), 2 ),
'maximum_amount' => wc_format_decimal( $coupon->get_maximum_amount(), 2 ),
'customer_emails' => implode( ', ', $coupon->get_email_restrictions() ),
'description' => $coupon_post->post_excerpt,
);
$coupon_data = apply_filters( 'woocommerce_cli_get_coupon', $coupon_data );
if ( empty( $assoc_args['fields'] ) ) {
$assoc_args['fields'] = array_keys( $coupon_data );
}
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_item( $coupon_data );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* List coupons.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Filter coupon based on coupon property.
*
* [--field=<field>]
* : Prints the value of a single field for each coupon.
*
* [--fields=<fields>]
* : Limit the output to specific coupon fields.
*
* [--format=<format>]
* : Acceptec values: table, csv, json, count, ids. Default: table.
*
* ## AVAILABLE FIELDS
*
* These fields will be displayed by default for each coupon:
*
* * id
* * code
* * type
* * amount
* * description
* * expiry_date
*
* These fields are optionally available:
*
* * individual_use
* * product_ids
* * exclude_product_ids
* * usage_limit
* * usage_limit_per_user
* * limit_usage_to_x_items
* * usage_count
* * free_shipping
* * product_category_ids
* * exclude_product_category_ids
* * exclude_sale_items
* * minimum_amount
* * maximum_amount
* * customer_emails
*
* Fields for filtering query result also available:
*
* * q Filter coupons with search query.
* * in Specify coupon IDs to retrieve.
* * not_in Specify coupon IDs NOT to retrieve.
* * created_at_min Filter coupons created after this date.
* * created_at_max Filter coupons created before this date.
* * updated_at_min Filter coupons updated after this date.
* * updated_at_max Filter coupons updated before this date.
* * page Page number.
* * offset Number of coupon to displace or pass over.
* * order Accepted values: ASC and DESC. Default: DESC.
* * orderby Sort retrieved coupons by parameter. One or more options can be passed.
*
* ## EXAMPLES
*
* wp wc coupon list
*
* wp wc coupon list --field=id
*
* wp wc coupon list --fields=id,code,type --format=json
*
* @since 2.5.0
* @subcommand list
*/
public function list_( $__, $assoc_args ) {
$query_args = $this->merge_wp_query_args( $this->get_list_query_args(), $assoc_args );
$formatter = $this->get_formatter( $assoc_args );
if ( 'ids' === $formatter->format ) {
$query_args['fields'] = 'ids';
$query = new WP_Query( $query_args );
echo implode( ' ', $query->posts );
} else {
$query = new WP_Query( $query_args );
$items = $this->format_posts_to_items( $query->posts );
$formatter->display_items( $items );
}
}
/**
* Get coupon types.
*
* ## EXAMPLES
*
* wp wc coupon types
*
* @since 2.5.0
*/
public function types( $__, $___ ) {
$coupon_types = wc_get_coupon_types();
foreach ( $coupon_types as $type => $label ) {
WP_CLI::line( sprintf( '%s: %s', $label, $type ) );
}
}
/**
* Update one or more coupons.
*
* ## OPTIONS
*
* <coupon>
* : The ID or code of the coupon to update.
*
* [--<field>=<value>]
* : One or more fields to update.
*
* ## AVAILABLE FIELDS
*
* These fields are available for update command:
*
* * code
* * type
* * amount
* * description
* * expiry_date
* * individual_use
* * product_ids
* * exclude_product_ids
* * usage_limit
* * usage_limit_per_user
* * limit_usage_to_x_items
* * usage_count
* * enable_free_shipping
* * product_category_ids
* * exclude_product_categories
* * exclude_product_category_ids
* * minimum_amount
* * maximum_amount
* * customer_emails
*
* ## EXAMPLES
*
* wp wc coupon update 123 --amount=5
*
* wp wc coupon update coupon-code --code=new-coupon-code
*
* @since 2.5.0
*/
public function update( $args, $assoc_args ) {
try {
$coupon = $this->get_coupon_from_id_or_code( $args[0] );
if ( ! $coupon ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_coupon', sprintf( __( 'Invalid coupon ID or code: %s', 'woocommerce' ), $args[0] ) );
}
$id = $coupon->get_id();
$coupon_code = $coupon->get_code();
$data = apply_filters( 'woocommerce_cli_update_coupon_data', $assoc_args, $id );
if ( isset( $data['code'] ) ) {
global $wpdb;
$coupon_code = apply_filters( 'woocommerce_coupon_code', $data['code'] );
// Check for duplicate coupon codes
$coupon_found = $wpdb->get_var( $wpdb->prepare( "
SELECT $wpdb->posts.ID
FROM $wpdb->posts
WHERE $wpdb->posts.post_type = 'shop_coupon'
AND $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_title = '%s'
AND $wpdb->posts.ID != %s
", $coupon_code, $id ) );
if ( $coupon_found ) {
throw new WC_CLI_Exception( 'woocommerce_cli_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ) );
}
}
$id = wp_update_post( array( 'ID' => intval( $id ), 'post_title' => $coupon_code, 'post_excerpt' => isset( $data['description'] ) ? $data['description'] : '' ) );
if ( 0 === $id ) {
throw new WC_CLI_Exception( 'woocommerce_cli_cannot_update_coupon', __( 'Failed to update coupon', 'woocommerce' ) );
}
if ( isset( $data['type'] ) ) {
// Validate coupon types.
if ( ! in_array( wc_clean( $data['type'] ), array_keys( wc_get_coupon_types() ) ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_coupon_type', sprintf( __( 'Invalid coupon type - the coupon type must be any of these: %s', 'woocommerce' ), implode( ', ', array_keys( wc_get_coupon_types() ) ) ) );
}
update_post_meta( $id, 'discount_type', $data['type'] );
}
if ( isset( $data['amount'] ) ) {
update_post_meta( $id, 'coupon_amount', wc_format_decimal( $data['amount'] ) );
}
if ( isset( $data['individual_use'] ) ) {
update_post_meta( $id, 'individual_use', ( $this->is_true( $data['individual_use'] ) ) ? 'yes' : 'no' );
}
if ( isset( $data['product_ids'] ) ) {
update_post_meta( $id, 'product_ids', implode( ',', array_filter( array_map( 'intval', $data['product_ids'] ) ) ) );
}
if ( isset( $data['exclude_product_ids'] ) ) {
update_post_meta( $id, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $data['exclude_product_ids'] ) ) ) );
}
if ( isset( $data['usage_limit'] ) ) {
update_post_meta( $id, 'usage_limit', absint( $data['usage_limit'] ) );
}
if ( isset( $data['usage_limit_per_user'] ) ) {
update_post_meta( $id, 'usage_limit_per_user', absint( $data['usage_limit_per_user'] ) );
}
if ( isset( $data['limit_usage_to_x_items'] ) ) {
update_post_meta( $id, 'limit_usage_to_x_items', absint( $data['limit_usage_to_x_items'] ) );
}
if ( isset( $data['usage_count'] ) ) {
update_post_meta( $id, 'usage_count', absint( $data['usage_count'] ) );
}
if ( isset( $data['expiry_date'] ) ) {
update_post_meta( $id, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $data['expiry_date'] ) ) );
}
if ( isset( $data['enable_free_shipping'] ) ) {
update_post_meta( $id, 'free_shipping', ( $this->is_true( $data['enable_free_shipping'] ) ) ? 'yes' : 'no' );
}
if ( isset( $data['product_category_ids'] ) ) {
update_post_meta( $id, 'product_categories', array_filter( array_map( 'intval', $data['product_category_ids'] ) ) );
}
if ( isset( $data['exclude_product_category_ids'] ) ) {
update_post_meta( $id, 'exclude_product_categories', array_filter( array_map( 'intval', $data['exclude_product_category_ids'] ) ) );
}
if ( isset( $data['exclude_sale_items'] ) ) {
update_post_meta( $id, 'exclude_sale_items', ( $this->is_true( $data['exclude_sale_items'] ) ) ? 'yes' : 'no' );
}
if ( isset( $data['minimum_amount'] ) ) {
update_post_meta( $id, 'minimum_amount', wc_format_decimal( $data['minimum_amount'] ) );
}
if ( isset( $data['maximum_amount'] ) ) {
update_post_meta( $id, 'maximum_amount', wc_format_decimal( $data['maximum_amount'] ) );
}
if ( isset( $data['customer_emails'] ) ) {
update_post_meta( $id, 'customer_email', array_filter( array_map( 'sanitize_email', $data['customer_emails'] ) ) );
}
do_action( 'woocommerce_cli_update_coupon', $id, $data );
WP_CLI::success( "Updated coupon $id." );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Get query args for list subcommand.
*
* @since 2.5.0
* @return array
*/
protected function get_list_query_args() {
return array(
'post_type' => 'shop_coupon',
'post_status' => 'publish',
'posts_per_page' => -1,
'order' => 'DESC',
);
}
/**
* Get default format fields that will be used in `list` and `get` subcommands.
*
* @since 2.5.0
* @return string
*/
protected function get_default_format_fields() {
return 'id,code,type,amount,description,expiry_date';
}
/**
* Format posts from WP_Query result to items in which each item contain
* common properties of item, for instance `post_title` will be `code`.
*
* @since 2.5.0
* @param array $posts Array of post
* @return array Items
*/
protected function format_posts_to_items( $posts ) {
$items = array();
foreach ( $posts as $post ) {
$coupon = new WC_Coupon;
$coupon->read( $post->ID );
$coupon_usage_limit = $coupon->get_usage_limit();
$coupon_usage_limit_per_user = $coupon->get_usage_limit_per_user();
$coupon_date_expires = $coupon->get_date_expires();
$items[] = array(
'id' => $post->ID,
'code' => $post->post_title,
'type' => $coupon->get_discount_type(),
'created_at' => $this->format_datetime( $post->post_date_gmt ),
'updated_at' => $this->format_datetime( $post->post_modified_gmt ),
'amount' => wc_format_decimal( $coupon->get_amount(), 2 ),
'individual_use' => $coupon->get_individual_use(),
'product_ids' => implode( ', ', is_array( $coupon->get_product_ids() ) ? $coupon->get_product_ids() : array() ),
'exclude_product_ids' => implode( ', ', is_array( $coupon->get_excluded_product_ids() ) ? $coupon->get_excluded_product_ids() : array() ),
'usage_limit' => ( ! empty( $coupon_usage_limit ) ) ? $coupon_usage_limit : null,
'usage_limit_per_user' => ( ! empty( $coupon_usage_limit_per_user ) ) ? $coupon_usage_limit_per_user : null,
'limit_usage_to_x_items' => (int) $coupon->get_limit_usage_to_x_items(),
'usage_count' => (int) $coupon->get_usage_count(),
'expiry_date' => ( ! empty( $coupon_date_expires ) ) ? $this->format_datetime( $coupon_date_expires ) : null,
'free_shipping' => $coupon->get_free_shipping(),
'product_category_ids' => implode( ', ', is_array( $coupon->get_product_categories() ) ? $coupon->get_product_categories() : array() ),
'exclude_product_category_ids' => implode( ', ', is_array( $coupon->get_excluded_product_categories() ) ? $coupon->get_excluded_product_categories() : array() ),
'exclude_sale_items' => $coupon->get_exclude_sale_items(),
'minimum_amount' => wc_format_decimal( $coupon->get_minimum_amount(), 2 ),
'maximum_amount' => wc_format_decimal( $coupon->get_maximum_amount(), 2 ),
'customer_emails' => implode( ', ', is_array( $coupon->get_email_restrictions() ) ? $coupon->get_email_restrictions() : array() ),
'description' => $post->post_excerpt,
);
}
return $items;
}
/**
* Get expiry_date format before saved into DB.
*
* @since 2.5.0
* @param string $expiry_date
* @return string
*/
protected function get_coupon_expiry_date( $expiry_date ) {
if ( '' !== $expiry_date ) {
return date( 'Y-m-d', strtotime( $expiry_date ) );
}
return '';
}
/**
* Get coupon from coupon's ID or code.
*
* @since 2.5.0
* @param int|string $coupon_id_or_code Coupon's ID or code
* @param bool $display_warning Display warning if ID or code is invalid. Default false.
* @return WC_Coupon
*/
protected function get_coupon_from_id_or_code( $coupon_id_or_code, $display_warning = false ) {
global $wpdb;
$code = $wpdb->get_var( $wpdb->prepare( "SELECT post_title FROM $wpdb->posts WHERE (id = %s OR post_title = %s) AND post_type = 'shop_coupon' AND post_status = 'publish' LIMIT 1", $coupon_id_or_code, $coupon_id_or_code ) );
if ( ! $code ) {
if ( $display_warning ) {
WP_CLI::warning( "Invalid coupon ID or code $coupon_id_or_code" );
}
return null;
}
return new WC_Coupon( $code );
}
/**
* Get coupon from coupon's ID or code.
*
* @since 2.5.0
* @param array $args Coupon's IDs or codes
* @param bool $display_warning Display warning if ID or code is invalid. Default false.
* @return WC_Coupon
*/
protected function get_many_coupons_from_ids_or_codes( $args, $display_warning = false ) {
$coupons = array();
foreach ( $args as $arg ) {
$code = $this->get_coupon_from_id_or_code( $arg, $display_warning );
if ( $code ) {
$coupons[] = $code;
}
}
return $coupons;
}
}

View File

@ -1,742 +0,0 @@
<?php
/**
* Manage Customers.
*
* @since 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
class WC_CLI_Customer extends WC_CLI_Command {
/**
* Create a customer.
*
* ## OPTIONS
*
* <email>
* : The email address of the customer to create.
*
* [--<field>=<value>]
* : Associative args for the new customer.
*
* [--porcelain]
* : Outputs just the new customer id.
*
* ## AVAILABLE FIELDS
*
* These fields are optionally available for create command:
*
* * username
* * password
* * first_name
* * last_name
*
* Billing address fields:
*
* * billing_address.first_name
* * billing_address.last_name
* * billing_address.company
* * billing_address.address_1
* * billing_address.address_2
* * billing_address.city
* * billing_address.state
* * billing_address.postcode
* * billing_address.country
* * billing_address.email
* * billing_address.phone
*
* Shipping address fields:
*
* * shipping_address.first_name
* * shipping_address.last_name
* * shipping_address.company
* * shipping_address.address_1
* * shipping_address.address_2
* * shipping_address.city
* * shipping_address.state
* * shipping_address.postcode
* * shipping_address.country
*
* ## EXAMPLES
*
* wp wc customer create new-customer@example.com --first_name=Akeda
*
* @since 2.5.0
*/
public function create( $args, $assoc_args ) {
global $wpdb;
try {
$porcelain = isset( $assoc_args['porcelain'] );
unset( $assoc_args['porcelain'] );
$assoc_args['email'] = $args[0];
$data = apply_filters( 'woocommerce_cli_create_customer_data', $this->unflatten_array( $assoc_args ) );
// Sets the username.
$data['username'] = ! empty( $data['username'] ) ? $data['username'] : '';
// Sets the password.
$data['password'] = ! empty( $data['password'] ) ? $data['password'] : '';
// Attempts to create the new customer.
$id = wc_create_new_customer( $data['email'], $data['username'], $data['password'] );
// Checks for an error in the customer creation.
if ( is_wp_error( $id ) ) {
throw new WC_CLI_Exception( $id->get_error_code(), $id->get_error_message() );
}
// Added customer data.
$this->update_customer_data( $id, $data );
do_action( 'woocommerce_cli_create_customer', $id, $data );
if ( $porcelain ) {
WP_CLI::line( $id );
} else {
WP_CLI::success( "Created customer $id." );
}
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Delete one or more customers.
*
* ## OPTIONS
*
* <customer>...
* : The customer ID, email, or username to delete.
*
* ## EXAMPLES
*
* wp wc customer delete 123
*
* wp wc customer delete $(wp wc customer list --format=ids)
*
* @since 2.5.0
*/
public function delete( $args, $assoc_args ) {
$exit_code = 0;
foreach ( $args as $arg ) {
try {
$customer = $this->get_user( $arg );
do_action( 'woocommerce_cli_delete_customer', $customer['id'] );
$r = wp_delete_user( $customer['id'] );
if ( $r ) {
WP_CLI::success( "Deleted customer {$customer['id']}." );
} else {
$exit_code += 1;
WP_CLI::warning( "Failed deleting customer {$customer['id']}." );
}
} catch ( WC_CLI_Exception $e ) {
WP_CLI::warning( $e->getMessage() );
}
}
exit( $exit_code ? 1 : 0 );
}
/**
* View customer downloads.
*
* ## OPTIONS
*
* <customer>
* : The customer ID, email or username.
*
* [--field=<field>]
* : Instead of returning the whole customer fields, returns the value of a single fields.
*
* [--fields=<fields>]
* : Get a specific subset of the customer's fields.
*
* [--format=<format>]
* : Accepted values: table, json, csv. Default: table.
*
* ## AVAILABLE FIELDS
*
* * download_id
* * download_name
* * access_expires
*
* ## EXAMPLES
*
* wp wc customer downloads 123
*
* @since 2.5.0
*/
public function downloads( $args, $assoc_args ) {
try {
$user = $this->get_user( $args[0] );
$downloads = array();
foreach ( wc_get_customer_available_downloads( $user['id'] ) as $key => $download ) {
$downloads[ $key ] = $download;
$downloads[ $key ]['access_expires'] = $this->format_datetime( $download['access_expires'] );
}
$downloads = apply_filters( 'woocommerce_cli_customer_downloads', $downloads, $user, $assoc_args );
if ( empty( $assoc_args['fields'] ) ) {
$assoc_args['fields'] = $this->get_customer_download_fields();
}
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_items( $downloads );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Get a customer.
*
* ## OPTIONS
*
* <customer>
* : Customer ID, email, or username.
*
* [--field=<field>]
* : Instead of returning the whole customer fields, returns the value of a single fields.
*
* [--fields=<fields>]
* : Get a specific subset of the customer's fields.
*
* [--format=<format>]
* : Accepted values: table, json, csv. Default: table.
*
* ## AVAILABLE FIELDS
*
* * id
* * email
* * first_name
* * last_name
* * created_at
* * username
* * last_order_id
* * last_order_date
* * orders_count
* * total_spent
* * avatar_url
*
* Billing address fields:
*
* * billing_address.first_name
* * billing_address.last_name
* * billing_address.company
* * billing_address.address_1
* * billing_address.address_2
* * billing_address.city
* * billing_address.state
* * billing_address.postcode
* * billing_address.country
* * billing_address.email
* * billing_address.phone
*
* Shipping address fields:
*
* * shipping_address.first_name
* * shipping_address.last_name
* * shipping_address.company
* * shipping_address.address_1
* * shipping_address.address_2
* * shipping_address.city
* * shipping_address.state
* * shipping_address.postcode
* * shipping_address.country
*
* Fields for filtering query result also available:
*
* * role Filter customers associated with certain role.
* * q Filter customers with search query.
* * created_at_min Filter customers whose registered after this date.
* * created_at_max Filter customers whose registered before this date.
* * limit The maximum returned number of results.
* * offset Offset the returned results.
* * order Accepted values: ASC and DESC. Default: DESC.
* * orderby Sort retrieved customers by parameter. One or more options can be passed.
*
* ## EXAMPLES
*
* wp wc customer get 123 --field=email
*
* wp wc customer get customer-login --format=json
*
* @since 2.5.0
*/
public function get( $args, $assoc_args ) {
try {
$user = $this->get_user( $args[0] );
if ( empty( $assoc_args['fields'] ) ) {
$assoc_args['fields'] = array_keys( $user );
}
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_item( $user );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* List customers.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Filter customer based on customer property.
*
* [--field=<field>]
* : Prints the value of a single field for each customer.
*
* [--fields=<fields>]
* : Limit the output to specific customer fields.
*
* [--format=<format>]
* : Acceptec values: table, csv, json, count, ids. Default: table.
*
* ## AVAILABLE FIELDS
*
* These fields will be displayed by default for each customer:
*
* * id
* * email
* * first_name
* * last_name
* * created_at
*
* These fields are optionally available:
*
* * username
* * last_order_id
* * last_order_date
* * orders_count
* * total_spent
* * avatar_url
*
* Billing address fields:
*
* * billing_address.first_name
* * billing_address.last_name
* * billing_address.company
* * billing_address.address_1
* * billing_address.address_2
* * billing_address.city
* * billing_address.state
* * billing_address.postcode
* * billing_address.country
* * billing_address.email
* * billing_address.phone
*
* Shipping address fields:
*
* * shipping_address.first_name
* * shipping_address.last_name
* * shipping_address.company
* * shipping_address.address_1
* * shipping_address.address_2
* * shipping_address.city
* * shipping_address.state
* * shipping_address.postcode
* * shipping_address.country
*
* Fields for filtering query result also available:
*
* * role Filter customers associated with certain role.
* * q Filter customers with search query.
* * created_at_min Filter customers whose registered after this date.
* * created_at_max Filter customers whose registered before this date.
* * limit The maximum returned number of results.
* * offset Offset the returned results.
* * order Accepted values: ASC and DESC. Default: DESC.
* * orderby Sort retrieved customers by parameter. One or more options can be passed.
*
* ## EXAMPLES
*
* wp wc customer list
*
* wp wc customer list --field=id
*
* wp wc customer list --fields=id,email,first_name --format=json
*
* @subcommand list
* @since 2.5.0
*/
public function list_( $__, $assoc_args ) {
$query_args = $this->merge_wp_user_query_args( $this->get_list_query_args(), $assoc_args );
$formatter = $this->get_formatter( $assoc_args );
if ( 'ids' === $formatter->format ) {
$query_args['fields'] = 'ids';
$query = new WP_User_Query( $query_args );
echo implode( ' ', $query->results );
} else {
$query = new WP_User_Query( $query_args );
$items = $this->format_users_to_items( $query->results );
$formatter->display_items( $items );
}
}
/**
* View customer orders.
*
* ## OPTIONS
*
* <customer>
* : The customer ID, email or username.
*
* [--field=<field>]
* : Instead of returning the whole customer fields, returns the value of a single fields.
*
* [--fields=<fields>]
* : Get a specific subset of the customer's fields.
*
* [--format=<format>]
* : Accepted values: table, json, csv. Default: table.
*
* ## AVAILABLE FIELDS
*
* For more fields, see: wp wc order list --help
*
* ## EXAMPLES
*
* wp wc customer orders 123
*
* @since 2.5.0
*/
public function orders( $args, $assoc_args ) {
try {
WP_CLI::run_command( array( 'wc', 'order', 'list' ), array( 'customer_id' => $args[0] ) );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Update one or more customers.
*
* ## OPTIONS
*
* <customer>
* : Customer ID, email, or username.
*
* [--<field>=<value>]
* : One or more fields to update.
*
* ## AVAILABLE FIELDS
*
* These fields are available for update command:
*
* * email
* * password
* * first_name
* * last_name
*
* Billing address fields:
*
* * billing_address.first_name
* * billing_address.last_name
* * billing_address.company
* * billing_address.address_1
* * billing_address.address_2
* * billing_address.city
* * billing_address.state
* * billing_address.postcode
* * billing_address.country
* * billing_address.email
* * billing_address.phone
*
* Shipping address fields:
*
* * shipping_address.first_name
* * shipping_address.last_name
* * shipping_address.company
* * shipping_address.address_1
* * shipping_address.address_2
* * shipping_address.city
* * shipping_address.state
* * shipping_address.postcode
* * shipping_address.country
*
* ## EXAMPLES
*
* wp wc customer update customer-login --first_name=akeda --last_name=bagus
*
* wp wc customer update customer@example.com --password=new-password
*
* @since 2.5.0
*/
public function update( $args, $assoc_args ) {
try {
$user = $this->get_user( $args[0] );
$data = $this->unflatten_array( $assoc_args );
$data = apply_filters( 'woocommerce_cli_update_customer_data', $data );
// Customer email.
if ( isset( $data['email'] ) ) {
wp_update_user( array( 'ID' => $user['id'], 'user_email' => sanitize_email( $data['email'] ) ) );
}
// Customer password.
if ( isset( $data['password'] ) ) {
wp_update_user( array( 'ID' => $user['id'], 'user_pass' => wc_clean( $data['password'] ) ) );
}
// Update customer data.
$this->update_customer_data( $user['id'], $data );
do_action( 'woocommerce_cli_update_customer', $user['id'], $data );
WP_CLI::success( "Updated customer {$user['id']}." );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Get query args for list subcommand.
*
* @since 2.5.0
* @return array
*/
protected function get_list_query_args() {
return array(
'role' => 'customer',
'orderby' => 'registered',
);
}
/**
* Get default format fields that will be used in `list` and `get` subcommands.
*
* @since 2.5.0
* @return string
*/
protected function get_default_format_fields() {
return 'id,email,first_name,last_name,created_at';
}
/**
* Format users from WP_User_Query result to items in which each item contain
* common properties of item.
*
* @since 2.5.0
* @param array $users Array of user
* @return array Items
*/
protected function format_users_to_items( $users ) {
$items = array();
foreach ( $users as $user ) {
try {
$items[] = $this->get_user( $user->ID );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::warning( $e->getMessage() );
}
}
return $items;
}
/**
* Get user from given user ID, email, or login
*
* @throws WC_CLI_Exception
*
* @since 2.5.0
* @param mixed $id_email_or_login
* @return array|WP_Error
*/
protected function get_user( $id_email_or_login ) {
global $wpdb;
if ( is_numeric( $id_email_or_login ) ) {
$user = get_user_by( 'id', $id_email_or_login );
} elseif ( is_email( $id_email_or_login ) ) {
$user = get_user_by( 'email', $id_email_or_login );
} else {
$user = get_user_by( 'login', $id_email_or_login );
}
if ( ! $user ) {
/* translators: %s: id email or login */
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_customer', sprintf( __( 'Invalid customer "%s"', 'woocommerce' ), $id_email_or_login ) );
}
// Get info about user's last order
$last_order = $wpdb->get_row( "SELECT id, post_date_gmt
FROM $wpdb->posts AS posts
LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
WHERE meta.meta_key = '_customer_user'
AND meta.meta_value = {$user->ID}
AND posts.post_type = 'shop_order'
AND posts.post_status IN ( '" . implode( "','", array_keys( wc_get_order_statuses() ) ) . "' )
ORDER BY posts.ID DESC
" );
$customer = array(
'id' => $user->ID,
'created_at' => $this->format_datetime( $user->user_registered ),
'email' => $user->user_email,
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'username' => $user->user_login,
'role' => $user->roles[0],
'last_order_id' => is_object( $last_order ) ? $last_order->get_id() : null,
'last_order_date' => is_object( $last_order ) ? $this->format_datetime( $last_order->post_date_gmt ) : null,
'orders_count' => wc_get_customer_order_count( $user->ID ),
'total_spent' => wc_format_decimal( wc_get_customer_total_spent( $user->ID ), 2 ),
'avatar_url' => $this->get_avatar_url( $user->customer_email ),
'billing_address' => array(
'first_name' => $user->billing_first_name,
'last_name' => $user->billing_last_name,
'company' => $user->billing_company,
'address_1' => $user->billing_address_1,
'address_2' => $user->billing_address_2,
'city' => $user->billing_city,
'state' => $user->billing_state,
'postcode' => $user->billing_postcode,
'country' => $user->billing_country,
'email' => $user->billing_email,
'phone' => $user->billing_phone,
),
'shipping_address' => array(
'first_name' => $user->shipping_first_name,
'last_name' => $user->shipping_last_name,
'company' => $user->shipping_company,
'address_1' => $user->shipping_address_1,
'address_2' => $user->shipping_address_2,
'city' => $user->shipping_city,
'state' => $user->shipping_state,
'postcode' => $user->shipping_postcode,
'country' => $user->shipping_country,
),
);
// Allow dot notation for nested array so that user can specifies field
// like 'billing_address.first_name'.
return $this->flatten_array( $customer );
}
/**
* Wrapper for @see get_avatar() which doesn't simply return
* the URL so we need to pluck it from the HTML img tag
*
* Kudos to https://github.com/WP-API/WP-API for offering a better solution
*
* @since 2.5.0
* @param string $email the customer's email
* @return string the URL to the customer's avatar
*/
protected function get_avatar_url( $email ) {
$avatar_html = get_avatar( $email );
// Get the URL of the avatar from the provided HTML
preg_match( '/src=["|\'](.+)[\&|"|\']/U', $avatar_html, $matches );
if ( isset( $matches[1] ) && ! empty( $matches[1] ) ) {
return esc_url_raw( $matches[1] );
}
return null;
}
/**
* Add/Update customer data.
*
* @since 2.5.0
* @param int $id The customer ID
* @param array $data
*/
protected function update_customer_data( $id, $data ) {
// Customer first name.
if ( isset( $data['first_name'] ) ) {
update_user_meta( $id, 'first_name', wc_clean( $data['first_name'] ) );
}
// Customer last name.
if ( isset( $data['last_name'] ) ) {
update_user_meta( $id, 'last_name', wc_clean( $data['last_name'] ) );
}
// Customer billing address.
if ( isset( $data['billing_address'] ) ) {
foreach ( $this->get_customer_billing_address_fields() as $address ) {
if ( isset( $data['billing_address'][ $address ] ) ) {
update_user_meta( $id, 'billing_' . $address, wc_clean( $data['billing_address'][ $address ] ) );
}
}
}
// Customer shipping address.
if ( isset( $data['shipping_address'] ) ) {
foreach ( $this->get_customer_shipping_address_fields() as $address ) {
if ( isset( $data['shipping_address'][ $address ] ) ) {
update_user_meta( $id, 'shipping_' . $address, wc_clean( $data['shipping_address'][ $address ] ) );
}
}
}
do_action( 'woocommerce_cli_update_customer_data', $id, $data );
}
/**
* Get customer billing address fields.
*
* @since 2.5.0
* @return array
*/
protected function get_customer_billing_address_fields() {
return apply_filters( 'woocommerce_cli_customer_billing_address_fields', array(
'first_name',
'last_name',
'company',
'address_1',
'address_2',
'city',
'state',
'postcode',
'country',
'email',
'phone',
) );
}
/**
* Get customer shipping address fields.
*
* @since 2.5.0
* @return array
*/
protected function get_customer_shipping_address_fields() {
return apply_filters( 'woocommerce_cli_customer_shipping_address_fields', array(
'first_name',
'last_name',
'company',
'address_1',
'address_2',
'city',
'state',
'postcode',
'country',
) );
}
/**
* Get customer download fields.
*
* @since 2.5.0
* @return array
*/
protected function get_customer_download_fields() {
return apply_filters( 'woocommerce_cli_customer_download_fields', array(
'download_id',
'download_name',
'access_expires',
) );
}
}

View File

@ -1,46 +0,0 @@
<?php
/**
* WooCommerce CLI Exception Class.
*
* Extends Exception to provide additional data.
*
* @since 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class WC_CLI_Exception extends Exception {
/** @var string sanitized error code */
protected $error_code;
/**
* Setup exception, requires 3 params:
*
* error code - machine-readable, e.g. `woocommerce_invalid_product_id`
* error message - friendly message, e.g. 'Product ID is invalid'
*
* @since 2.5.0
* @param string $error_code
* @param string $error_message user-friendly translated error message
*/
public function __construct( $error_code, $error_message ) {
$this->error_code = $error_code;
parent::__construct( $error_message );
}
/**
* Returns the error code
*
* @since 2.5.0
* @return string
*/
public function getErrorCode() {
return $this->error_code;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,160 +0,0 @@
<?php
/**
* Manage Product Categories.
*
* @since 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
class WC_CLI_Product_Category extends WC_CLI_Command {
/**
* Get product category.
*
* ## OPTIONS
*
* <id>
* : Product category ID.
*
* [--field=<field>]
* : Instead of returning the whole product category fields, returns the value of a single fields.
*
* [--fields=<fields>]
* : Get a specific subset of the product category's fields.
*
* [--format=<format>]
* : Accepted values: table, json, csv. Default: table.
*
* ## AVAILABLE FIELDS
*
* * id
* * name
* * slug
* * parent
* * description
* * display
* * image
* * count
*
* ## EXAMPLES
*
* wp wc product category get 123
*
* @since 2.5.0
*/
public function get( $args, $assoc_args ) {
try {
$product_category = $this->get_product_category( $args[0] );
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_item( $product_category );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* List of product categories.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Filter products based on product property.
*
* [--field=<field>]
* : Prints the value of a single field for each product.
*
* [--fields=<fields>]
* : Limit the output to specific product fields.
*
* [--format=<format>]
* : Acceptec values: table, csv, json, count, ids. Default: table.
*
* ## AVAILABLE FIELDS
*
* * id
* * name
* * slug
* * parent
* * description
* * display
* * image
* * count
*
* ## EXAMPLES
*
* wp wc product category list
*
* wp wc product category list --fields=id,name --format=json
*
* @subcommand list
* @since 2.5.0
*/
public function list_( $__, $assoc_args ) {
try {
$product_categories = array();
$terms = get_terms( 'product_cat', array( 'hide_empty' => false, 'fields' => 'ids' ) );
foreach ( $terms as $term_id ) {
$product_categories[] = $this->get_product_category( $term_id );
}
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_items( $product_categories );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Get product category properties from given term ID.
*
* @since 2.5.0
* @param int $term_id Category term ID
* @return array
* @throws WC_CLI_Exception
*/
protected function get_product_category( $term_id ) {
$term_id = absint( $term_id );
$term = get_term( $term_id, 'product_cat' );
if ( is_wp_error( $term ) || is_null( $term ) ) {
/* translators: %s: product category ID */
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_product_category_id', sprintf( __( 'Invalid product category ID "%s"', 'woocommerce' ), $term_id ) );
}
$term_id = intval( $term->term_id );
// Get category display type.
$display_type = get_woocommerce_term_meta( $term_id, 'display_type' );
// Get category image.
$image = '';
if ( $image_id = get_woocommerce_term_meta( $term_id, 'thumbnail_id' ) ) {
$image = wp_get_attachment_url( $image_id );
}
return array(
'id' => $term_id,
'name' => $term->name,
'slug' => $term->slug,
'parent' => $term->parent,
'description' => $term->description,
'display' => $display_type ? $display_type : 'default',
'image' => $image ? esc_url( $image ) : '',
'count' => intval( $term->count ),
);
}
/**
* Get default format fields that will be used in `list` and `get` subcommands.
*
* @since 2.5.0
* @return string
*/
protected function get_default_format_fields() {
return 'id,name,slug,parent,description,display,image,count';
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,371 +0,0 @@
<?php
/**
* Show Reports.
*
* @since 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
class WC_CLI_Report extends WC_CLI_Command {
/**
* List reports.
*
* ## OPTIONS
*
* [--format=<format>]
* : Acceptec values: table, csv, json, count, ids. Default: table.
*
* ## EXAMPLES
*
* wp wc report list
*
* @subcommand list
* @since 2.5.0
*/
public function list_( $__, $assoc_args ) {
$reports = array( 'sales', 'sales/top_sellers' );
$formatter = $this->get_formatter(
array_merge(
array( 'fields' => array_keys( $reports ) ),
$assoc_args
)
);
if ( 'ids' === $formatter->format ) {
echo implode( ' ', $reports );
} else {
$formatter->display_item( $reports );
}
}
/**
* View sales report.
*
* ## OPTIONS
*
* [--field=<field>]
* : Instead of returning the whole report fields, returns the value of a single fields.
*
* [--fields=<fields>]
* : Get a specific subset of the report's fields.
*
* [--format=<format>]
* : Accepted values: table, json, csv. Default: table.
*
* [--period=<period>]
* : The supported periods are: week, month, last_month, and year. If invalid
* period is supplied, week is used. If period is not specified, the current
* day is used.
*
* [--date_min]
* : Return sales for a specific start date. The date need to be in the YYYY-MM-AA format.
*
* [--date_max]
* : Return sales for a specific end date. The dates need to be in the YYYY-MM-AA format.
*
* [--limit]
* : Limit report result. Default: 12.
*
* ## AVAILABLE FIELDS
*
* These fields are available for get command:
*
* * total_sales
* * average_sales
* * total_orders
* * total_items
* * total_tax
* * total_shipping
* * total_discount
* * totals_grouped_by
* * totals
* * total_customers
*
* ## EXAMPLES
*
* wp wc report sales
*
* wp wc report sales --period=last_month
*
* @since 2.5.0
*/
public function sales( $__, $assoc_args ) {
$reporter = $this->get_reporter( $assoc_args );
// new customers
$users_query = new WP_User_Query(
array(
'fields' => array( 'user_registered' ),
'role' => 'customer',
)
);
$customers = $users_query->get_results();
foreach ( $customers as $key => $customer ) {
if ( strtotime( $customer->user_registered ) < $reporter->start_date || strtotime( $customer->user_registered ) > $reporter->end_date ) {
unset( $customers[ $key ] );
}
}
$total_customers = count( $customers );
$report_data = $reporter->get_report_data();
$period_totals = array();
// setup period totals by ensuring each period in the interval has data
for ( $i = 0; $i <= $reporter->chart_interval; $i ++ ) {
switch ( $reporter->chart_groupby ) {
case 'day' :
$time = date( 'Y-m-d', strtotime( "+{$i} DAY", $reporter->start_date ) );
break;
default :
$time = date( 'Y-m', strtotime( "+{$i} MONTH", $reporter->start_date ) );
break;
}
// set the customer signups for each period
$customer_count = 0;
foreach ( $customers as $customer ) {
if ( date( ( 'day' == $reporter->chart_groupby ) ? 'Y-m-d' : 'Y-m', strtotime( $customer->user_registered ) ) == $time ) {
$customer_count++;
}
}
$period_totals[ $time ] = array(
'sales' => wc_format_decimal( 0.00, 2 ),
'orders' => 0,
'items' => 0,
'tax' => wc_format_decimal( 0.00, 2 ),
'shipping' => wc_format_decimal( 0.00, 2 ),
'discount' => wc_format_decimal( 0.00, 2 ),
'customers' => $customer_count,
);
}
// add total sales, total order count, total tax and total shipping for each period
foreach ( $report_data->orders as $order ) {
$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) );
if ( ! isset( $period_totals[ $time ] ) ) {
continue;
}
$period_totals[ $time ]['sales'] = wc_format_decimal( $order->total_sales, 2 );
$period_totals[ $time ]['tax'] = wc_format_decimal( $order->total_tax + $order->total_shipping_tax, 2 );
$period_totals[ $time ]['shipping'] = wc_format_decimal( $order->total_shipping, 2 );
}
foreach ( $report_data->order_counts as $order ) {
$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) );
if ( ! isset( $period_totals[ $time ] ) ) {
continue;
}
$period_totals[ $time ]['orders'] = (int) $order->count;
}
// add total order items for each period
foreach ( $report_data->order_items as $order_item ) {
$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $order_item->post_date ) ) : date( 'Y-m', strtotime( $order_item->post_date ) );
if ( ! isset( $period_totals[ $time ] ) ) {
continue;
}
$period_totals[ $time ]['items'] = (int) $order_item->order_item_count;
}
// add total discount for each period
foreach ( $report_data->coupons as $discount ) {
$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $discount->post_date ) ) : date( 'Y-m', strtotime( $discount->post_date ) );
if ( ! isset( $period_totals[ $time ] ) ) {
continue;
}
$period_totals[ $time ]['discount'] = wc_format_decimal( $discount->discount_amount, 2 );
}
$sales_data = array(
'total_sales' => $report_data->total_sales,
'net_sales' => $report_data->net_sales,
'average_sales' => $report_data->average_sales,
'total_orders' => $report_data->total_orders,
'total_items' => $report_data->total_items,
'total_tax' => wc_format_decimal( $report_data->total_tax + $report_data->total_shipping_tax, 2 ),
'total_shipping' => $report_data->total_shipping,
'total_refunds' => $report_data->total_refunds,
'total_discount' => $report_data->total_coupons,
'totals_grouped_by' => $reporter->chart_groupby,
'totals' => $period_totals,
'total_customers' => $total_customers,
);
$sales_data = apply_filters( 'woocommerce_cli_sales_report', $sales_data );
if ( empty( $assoc_args['fields'] ) ) {
$assoc_args['fields'] = array_keys( $sales_data );
}
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_item( $sales_data );
}
/**
* View report of top sellers.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Filter report based on report property.
*
* [--field=<field>]
* : Prints the value of a single field for each seller.
*
* [--fields=<fields>]
* : Limit the output to specific report fields.
*
* [--format=<format>]
* : Acceptec values: table, csv, json, count, ids. Default: table.
*
* [--period=<period>]
* : The supported periods are: week, month, last_month, and year. If invalid
* period is supplied, week is used. If period is not specified, the current
* day is used.
*
* [--date_min]
* : Return sales for a specific start date. The date need to be in the YYYY-MM-AA format.
*
* [--date_max]
* : Return sales for a specific end date. The dates need to be in the YYYY-MM-AA format.
*
* [--limit]
* : Limit report result. Default: 12.
*
* ## AVAILABLE FIELDS
*
* These fields will be displayed by default for each row:
*
* * title
* * product_id
* * quantity
*
* ## EXAMPLES
*
* wp wc report top_sellers
*
* wp wc report top_sellers --period=last_month
*
* @since 2.5.0
*/
public function top_sellers( $__, $assoc_args ) {
$reporter = $this->get_reporter( $assoc_args );
$top_sellers = $reporter->get_order_report_data( array(
'data' => array(
'_product_id' => array(
'type' => 'order_item_meta',
'order_item_type' => 'line_item',
'function' => '',
'name' => 'product_id',
),
'_qty' => array(
'type' => 'order_item_meta',
'order_item_type' => 'line_item',
'function' => 'SUM',
'name' => 'order_item_qty',
),
),
'order_by' => 'order_item_qty DESC',
'group_by' => 'product_id',
'limit' => isset( $assoc_args['limit'] ) ? absint( $assoc_args['limit'] ) : 12,
'query_type' => 'get_results',
'filter_range' => true,
) );
$top_sellers_data = array();
foreach ( $top_sellers as $top_seller ) {
$product = wc_get_product( $top_seller->product_id );
if ( $product ) {
$top_sellers_data[] = array(
'title' => $product->get_title(),
'product_id' => $top_seller->product_id,
'quantity' => $top_seller->order_item_qty,
);
}
}
$top_sellers_data = apply_filters( 'woocommerce_cli_top_sellers_report', $top_sellers_data );
$formatter = $this->get_formatter( $assoc_args );
if ( 'ids' === $formatter->format ) {
$query_args['fields'] = 'ids';
echo implode( ' ', wp_list_pluck( $top_sellers_data, 'product_id' ) );
} else {
$formatter->display_items( $top_sellers_data );
}
}
/**
* Setup the report object and parse any date filtering
*
* @since 2.5.0
* @param array $assoc_args Arguments provided in when invoking the command
* @return WC_Report_Sales_By_Date
*/
private function get_reporter( $assoc_args ) {
include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' );
include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-report-sales-by-date.php' );
$report = new WC_Report_Sales_By_Date();
if ( empty( $assoc_args['period'] ) ) {
// custom date range
$assoc_args['period'] = 'custom';
if ( ! empty( $assoc_args['date_min'] ) || ! empty( $assoc_args['date_max'] ) ) {
// overwrite _GET to make use of WC_Admin_Report::calculate_current_range() for custom date ranges
$_GET['start_date'] = $this->parse_datetime( $assoc_args['date_min'] );
$_GET['end_date'] = isset( $assoc_args['date_max'] ) ? $this->parse_datetime( $assoc_args['date_max'] ) : null;
} else {
// default custom range to today
$_GET['start_date'] = $_GET['end_date'] = date( 'Y-m-d', current_time( 'timestamp' ) );
}
} else {
// ensure period is valid
if ( ! in_array( $assoc_args['period'], array( 'week', 'month', 'last_month', 'year' ) ) ) {
$assoc_args['period'] = 'week';
}
// TODO: change WC_Admin_Report class to use "week" instead, as it's more consistent with other periods
// allow "week" for period instead of "7day"
if ( 'week' === $assoc_args['period'] ) {
$assoc_args['period'] = '7day';
}
}
$report->calculate_current_range( $assoc_args['period'] );
return $report;
}
/**
* Get default format fields that will be used in `list` and `get` subcommands.
*
* @since 2.5.0
* @return string
*/
protected function get_default_format_fields() {
return 'title,product_id,quantity';
}
}

View File

@ -1,685 +0,0 @@
<?php
/**
* Manage Taxes.
*
* @since 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
class WC_CLI_Tax extends WC_CLI_Command {
/**
* Create a tax rate.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Associative args for the new tax rate.
*
* [--porcelain]
* : Outputs just the new tax rate id.
*
* ## AVAILABLE FIELDS
*
* These fields are available for create command:
*
* * country
* * state
* * postcode
* * city
* * rate
* * name
* * priority
* * compound
* * shipping
* * class
* * order
*
* ## EXAMPLES
*
* wp wc tax create --country=US --rate=5 --class=standard --type=percent
*
* @since 2.5.0
*/
public function create( $__, $assoc_args ) {
$porcelain = isset( $assoc_args['porcelain'] );
unset( $assoc_args['porcelain'] );
$assoc_args = apply_filters( 'woocommerce_cli_create_tax_rate_data', $assoc_args );
$tax_data = array(
'tax_rate_country' => '',
'tax_rate_state' => '',
'tax_rate' => '',
'tax_rate_name' => '',
'tax_rate_priority' => 1,
'tax_rate_compound' => 0,
'tax_rate_shipping' => 1,
'tax_rate_order' => 0,
'tax_rate_class' => '',
);
foreach ( $tax_data as $key => $value ) {
$new_key = str_replace( 'tax_rate_', '', $key );
$new_key = 'tax_rate' === $new_key ? 'rate' : $new_key;
if ( isset( $assoc_args[ $new_key ] ) ) {
if ( in_array( $new_key, array( 'compound', 'shipping' ) ) ) {
$tax_data[ $key ] = $assoc_args[ $new_key ] ? 1 : 0;
} else {
$tax_data[ $key ] = $assoc_args[ $new_key ];
}
}
}
// Create tax rate.
$id = WC_Tax::_insert_tax_rate( $tax_data );
// Add locales.
if ( ! empty( $assoc_args['postcode'] ) ) {
WC_Tax::_update_tax_rate_postcodes( $id, wc_clean( $assoc_args['postcode'] ) );
}
if ( ! empty( $assoc_args['city'] ) ) {
WC_Tax::_update_tax_rate_cities( $id, wc_clean( $assoc_args['city'] ) );
}
do_action( 'woocommerce_cli_create_tax_rate', $id, $tax_data );
if ( $porcelain ) {
WP_CLI::line( $id );
} else {
WP_CLI::success( "Created tax rate $id." );
}
}
/**
* Create a tax class.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Associative args for the new tax class.
*
* [--porcelain]
* : Outputs just the new tax class slug.
*
* ## AVAILABLE FIELDS
*
* These fields are available for create command:
*
* * name
*
* ## EXAMPLES
*
* wp wc tax create_class --name="Reduced Rate"
*
* @since 2.5.0
*/
public function create_class( $__, $assoc_args ) {
try {
$porcelain = isset( $assoc_args['porcelain'] );
unset( $assoc_args['porcelain'] );
$assoc_args = apply_filters( 'woocommerce_cli_create_tax_class_data', $assoc_args );
// Check if name is specified.
if ( ! isset( $assoc_args['name'] ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_missing_name', sprintf( __( 'Missing parameter %s', 'woocommerce' ), 'name' ) );
}
$name = sanitize_text_field( $assoc_args['name'] );
$slug = sanitize_title( $name );
$classes = WC_Tax::get_tax_classes();
$exists = false;
// Check if class exists.
foreach ( $classes as $key => $class ) {
if ( sanitize_title( $class ) === $slug ) {
$exists = true;
break;
}
}
// Return error if tax class already exists.
if ( $exists ) {
throw new WC_CLI_Exception( 'woocommerce_cli_cannot_create_tax_class', __( 'Tax class already exists', 'woocommerce' ) );
}
// Add the new class
$classes[] = $name;
update_option( 'woocommerce_tax_classes', implode( "\n", $classes ) );
do_action( 'woocommerce_cli_create_tax_class', $slug, array( 'name' => $name ) );
if ( $porcelain ) {
WP_CLI::line( $slug );
} else {
WP_CLI::success( "Created tax class $slug." );
}
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Delete one or more tax rates.
*
* ## OPTIONS
*
* <id>...
* : The tax rate ID to delete.
*
* ## EXAMPLES
*
* wp wc tax delete 123
*
* wp wc tax delete $(wp wc tax list --format=ids)
*
* @since 2.5.0
*/
public function delete( $args, $assoc_args ) {
$exit_code = 0;
foreach ( $args as $tax_id ) {
$tax_id = absint( $tax_id );
$tax = WC_Tax::_get_tax_rate( $tax_id );
if ( is_null( $tax ) ) {
$exit_code += 1;
WP_CLI::warning( "Failed deleting tax rate {$tax_id}." );
continue;
}
do_action( 'woocommerce_cli_delete_tax_rate', $tax_id );
WC_Tax::_delete_tax_rate( $tax_id );
WP_CLI::success( "Deleted tax rate {$tax_id}." );
}
exit( $exit_code ? 1 : 0 );
}
/**
* Delete one or more tax classes.
*
* ## OPTIONS
*
* <slug>...
* : The tax class slug to delete.
*
* ## EXAMPLES
*
* wp wc tax delete_class reduced-rate
*
* wp wc tax delete_class $(wp wc tax list_class --format=ids)
*
* @since 2.5.0
*/
public function delete_class( $args, $assoc_args ) {
$classes = WC_Tax::get_tax_classes();
$exit_code = 0;
foreach ( $args as $slug ) {
$slug = sanitize_title( $slug );
$deleted = false;
foreach ( $classes as $key => $class ) {
if ( sanitize_title( $class ) === $slug ) {
unset( $classes[ $key ] );
$deleted = true;
break;
}
}
if ( $deleted ) {
WP_CLI::success( "Deleted tax class {$slug}." );
} else {
$exit_code += 1;
WP_CLI::warning( "Failed deleting tax class {$slug}." );
}
}
update_option( 'woocommerce_tax_classes', implode( "\n", $classes ) );
exit( $exit_code ? 1 : 0 );
}
/**
* Get a tax rate.
*
* ## OPTIONS
*
* <id>
* : Tax rate ID
*
* [--field=<field>]
* : Instead of returning the whole tax rate fields, returns the value of a single fields.
*
* [--fields=<fields>]
* : Get a specific subset of the tax rates fields.
*
* [--format=<format>]
* : Accepted values: table, json, csv. Default: table.
*
* ## AVAILABLE FIELDS
*
* These fields are available for get command:
*
* * id
* * country
* * state
* * postcode
* * city
* * rate
* * name
* * priority
* * compound
* * shipping
* * order
* * class
*
* ## EXAMPLES
*
* wp wc tax get 123 --field=rate
*
* wp wc tax get 321 --format=json > rate321.json
*
* @since 2.5.0
*/
public function get( $args, $assoc_args ) {
global $wpdb;
try {
$tax_data = $this->format_taxes_to_items( array( $args[0] ) );
if ( empty( $tax_data ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_tax_rate', sprintf( __( 'Invalid tax rate ID: %s', 'woocommerce' ), $args[0] ) );
}
$tax_data = apply_filters( 'woocommerce_cli_get_tax_rate', $tax_data[0] );
if ( empty( $assoc_args['fields'] ) ) {
$assoc_args['fields'] = array_keys( $tax_data );
}
$formatter = $this->get_formatter( $assoc_args );
$formatter->display_item( $tax_data );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* List taxes.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Filter tax based on tax property.
*
* [--field=<field>]
* : Prints the value of a single field for each tax.
*
* [--fields=<fields>]
* : Limit the output to specific tax fields.
*
* [--format=<format>]
* : Acceptec values: table, csv, json, count, ids. Default: table.
*
* ## AVAILABLE FIELDS
*
* These fields will be displayed by default for each tax:
*
* * id
* * country
* * state
* * postcode
* * city
* * rate
* * name
* * priority
* * compound
* * shipping
* * class
*
* These fields are optionally available:
*
* * order
*
* Fields for filtering query result also available:
*
* * class Sort by tax class.
* * page Page number.
*
* ## EXAMPLES
*
* wp wc tax list
*
* wp wc tax list --field=id
*
* wp wc tax list --fields=id,rate,class --format=json
*
* @since 2.5.0
* @subcommand list
*/
public function list_( $__, $assoc_args ) {
$query_args = $this->merge_tax_query_args( array(), $assoc_args );
$formatter = $this->get_formatter( $assoc_args );
$taxes = $this->query_tax_rates( $query_args );
if ( 'ids' === $formatter->format ) {
$_taxes = array();
foreach ( $taxes as $tax ) {
$_taxes[] = $tax->tax_rate_id;
}
echo implode( ' ', $_taxes );
} else {
$items = $this->format_taxes_to_items( $taxes );
$formatter->display_items( $items );
}
}
/**
* List tax classes.
*
* ## OPTIONS
*
* [--<field>=<value>]
* : Filter tax class based on tax class property.
*
* [--field=<field>]
* : Prints the value of a single field for each tax class.
*
* [--fields=<fields>]
* : Limit the output to specific tax class fields.
*
* [--format=<format>]
* : Acceptec values: table, csv, json, count, ids. Default: table.
*
* ## AVAILABLE FIELDS
*
* These fields will be displayed by default for each tax class:
*
* * slug
* * name
*
* ## EXAMPLES
*
* wp wc tax list_class
*
* wp wc tax list_class --field=slug
*
* wp wc tax list_class --format=json
*
* @since 2.5.0
* @subcommand list_class
*/
public function list_class( $__, $assoc_args ) {
// Set default fields for tax classes
if ( empty( $assoc_args['fields'] ) ) {
$assoc_args['fields'] = 'slug,name';
}
$formatter = $this->get_formatter( $assoc_args );
$items = array();
// Add standard class
$items[] = array(
'slug' => 'standard',
'name' => __( 'Standard rate', 'woocommerce' ),
);
$classes = WC_Tax::get_tax_classes();
foreach ( $classes as $class ) {
$items[] = apply_filters( 'woocommerce_cli_tax_class_response', array(
'slug' => sanitize_title( $class ),
'name' => $class,
), $class, $assoc_args, $this );
}
if ( 'ids' === $formatter->format ) {
$_slugs = array();
foreach ( $items as $item ) {
$_slugs[] = $item['slug'];
}
echo implode( ' ', $_slugs );
} else {
$formatter->display_items( $items );
}
}
/**
* Update a tax rate.
*
* ## OPTIONS
*
* <id>
* : The ID of the tax rate to update.
*
* [--<field>=<value>]
* : One or more fields to update.
*
* ## AVAILABLE FIELDS
*
* These fields are available for update command:
*
* * country
* * state
* * postcode
* * city
* * rate
* * name
* * priority
* * compound
* * shipping
* * class
*
* ## EXAMPLES
*
* wp wc tax update 123 --rate=5
*
* @since 2.5.0
*/
public function update( $args, $assoc_args ) {
try {
// Get current tax rate data
$tax_data = $this->format_taxes_to_items( array( $args[0] ) );
if ( empty( $tax_data ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_tax_rate', sprintf( __( 'Invalid tax rate ID: %s', 'woocommerce' ), $args[0] ) );
}
$current_data = $tax_data[0];
$id = $current_data['id'];
$data = apply_filters( 'woocommerce_cli_update_tax_rate_data', $assoc_args, $id );
$new_data = array();
$default_fields = array(
'tax_rate_country',
'tax_rate_state',
'tax_rate',
'tax_rate_name',
'tax_rate_priority',
'tax_rate_compound',
'tax_rate_shipping',
'tax_rate_order',
'tax_rate_class',
);
foreach ( $data as $key => $value ) {
$new_key = 'rate' === $key ? 'tax_rate' : 'tax_rate_' . $key;
// Check if the key is valid
if ( ! in_array( $new_key, $default_fields ) ) {
continue;
}
// Test new data against current data
if ( $value === $current_data[ $key ] ) {
continue;
}
// Fix compund and shipping values
if ( in_array( $key, array( 'compound', 'shipping' ) ) ) {
$value = $value ? 1 : 0;
}
$new_data[ $new_key ] = $value;
}
// Update tax rate
WC_Tax::_update_tax_rate( $id, $new_data );
// Update locales
if ( ! empty( $data['postcode'] ) && $current_data['postcode'] != $data['postcode'] ) {
WC_Tax::_update_tax_rate_postcodes( $id, wc_clean( $data['postcode'] ) );
}
if ( ! empty( $data['city'] ) && $current_data['city'] != $data['city'] ) {
WC_Tax::_update_tax_rate_cities( $id, wc_clean( $data['city'] ) );
}
do_action( 'woocommerce_cli_update_tax_rate', $id, $data );
WP_CLI::success( "Updated tax rate $id." );
} catch ( WC_CLI_Exception $e ) {
WP_CLI::error( $e->getMessage() );
}
}
/**
* Add common cli arguments to argument list before $wpdb->get_results() is run.
*
* @since 2.5.0
* @param array $base_args Required arguments for the query (e.g. `limit`, etc)
* @param array $assoc_args Arguments provided in when invoking the command
* @return array
*/
protected function merge_tax_query_args( $base_args, $assoc_args ) {
$args = array();
if ( ! empty( $assoc_args['class'] ) ) {
$args['class'] = $assoc_args['class'];
}
// Number of post to show per page.
if ( ! empty( $assoc_args['limit'] ) ) {
$args['posts_per_page'] = $assoc_args['limit'];
}
// posts page.
$args['paged'] = ( isset( $assoc_args['page'] ) ) ? absint( $assoc_args['page'] ) : 1;
$args = apply_filters( 'woocommerce_cli_tax_query_args', $args, $assoc_args );
return array_merge( $base_args, $args );
}
/**
* Helper method to get tax rates objects
*
* @since 2.5.0
*
* @param array $args
*
* @return array
*/
protected function query_tax_rates( $args ) {
global $wpdb;
$query = "
SELECT tax_rate_id
FROM {$wpdb->prefix}woocommerce_tax_rates
WHERE 1 = 1
";
// Filter by tax class
if ( ! empty( $args['class'] ) ) {
$class = 'standard' !== $args['class'] ? sanitize_title( $args['class'] ) : '';
$query .= " AND tax_rate_class = '$class'";
}
// Order tax rates
$order_by = ' ORDER BY tax_rate_order';
// Pagination
$per_page = isset( $args['posts_per_page'] ) ? $args['posts_per_page'] : get_option( 'posts_per_page' );
$offset = 1 < $args['paged'] ? ( $args['paged'] - 1 ) * $per_page : 0;
$pagination = sprintf( ' LIMIT %d, %d', $offset, $per_page );
return $wpdb->get_results( $query . $order_by . $pagination );
}
/**
* Get default format fields that will be used in `list` and `get` subcommands.
*
* @since 2.5.0
* @return string
*/
protected function get_default_format_fields() {
return 'id,country,state,postcode,city,rate,name,priority,compound,shipping,class';
}
/**
* Format taxes from query result to items in which each item contain
* common properties of item, for instance `tax_rate_id` will be `id`.
*
* @since 2.5.0
* @param array $taxes Array of tax rate.
* @return array Items
*/
protected function format_taxes_to_items( $taxes ) {
global $wpdb;
$items = array();
foreach ( $taxes as $tax_id ) {
$id = is_object( $tax_id ) ? $tax_id->tax_rate_id : $tax_id;
$id = absint( $id );
// Get tax rate details
$tax = WC_Tax::_get_tax_rate( $id );
if ( is_wp_error( $tax ) || empty( $tax ) ) {
continue;
}
$tax_data = array(
'id' => $tax['tax_rate_id'],
'country' => $tax['tax_rate_country'],
'state' => $tax['tax_rate_state'],
'postcode' => '',
'city' => '',
'rate' => $tax['tax_rate'],
'name' => $tax['tax_rate_name'],
'priority' => (int) $tax['tax_rate_priority'],
'compound' => (bool) $tax['tax_rate_compound'],
'shipping' => (bool) $tax['tax_rate_shipping'],
'order' => (int) $tax['tax_rate_order'],
'class' => $tax['tax_rate_class'] ? $tax['tax_rate_class'] : 'standard',
);
// Get locales from a tax rate
$locales = $wpdb->get_results( $wpdb->prepare( "
SELECT location_code, location_type
FROM {$wpdb->prefix}woocommerce_tax_rate_locations
WHERE tax_rate_id = %d
", $id ) );
if ( ! is_wp_error( $tax ) && ! is_null( $tax ) ) {
foreach ( $locales as $locale ) {
$tax_data[ $locale->location_type ] = $locale->location_code;
}
}
$items[] = $tax_data;
}
return $items;
}
}

View File

@ -1,29 +0,0 @@
<?php
/**
* Tools for WooCommerce.
*
* @since 2.5.0
* @package WooCommerce/CLI
* @category CLI
* @author WooThemes
*/
class WC_CLI_Tool extends WC_CLI_Command {
/**
* Clear the product/shop transients cache.
*
* ## EXAMPLES
*
* wp wc tool clear_transients
*
* @since 2.5.0
*/
public function clear_transients( $args, $assoc_args ) {
wc_delete_product_transients();
wc_delete_shop_order_transients();
WC_Cache_Helper::get_transient_version( 'shipping', true );
WP_CLI::success( 'Product transients and shop order transients were cleared.' );
}
}

View File

@ -290,10 +290,6 @@ final class WooCommerce {
include_once( WC_ABSPATH . 'includes/data-stores/class-wc-data-store-cpt.php' );
include_once( WC_ABSPATH . 'includes/data-stores/class-wc-coupon-data-store-cpt.php' );
if ( defined( 'WP_CLI' ) && WP_CLI ) {
include_once( WC_ABSPATH . 'includes/class-wc-cli.php' );
}
$this->query = new WC_Query();
$this->api = new WC_API();
}