Merge branch 'master' into update/19345

This commit is contained in:
Mike Jolley 2018-03-19 18:00:28 +00:00
commit fb8b670cda
61 changed files with 2040 additions and 1376 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,9 @@ body {
max-width: 30%;
}
}
.wc-setup {
text-align: center;
}
.wc-setup-content {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
padding: 2em;
@ -20,6 +23,7 @@ body {
background: #fff;
overflow: hidden;
zoom: 1;
text-align: left;
h1, h2, h3, table {
margin: 0 0 20px;
@ -297,7 +301,6 @@ body {
}
}
.woocommerce-newsletter,
.woocommerce-tracker,
.updated {
padding: 24px 24px 0;
margin: 0 0 24px;
@ -312,9 +315,74 @@ body {
margin: 0 0 24px;
}
}
.woocommerce-tracker + .woocommerce-newsletter {
margin-top: -24px;
border-top: 2px dashed #ddd;
.woocommerce-tracker {
margin: 24px 0;
border: 1px solid #eee;
padding: 20px;
border-radius: 4px;
overflow: hidden;
p {
font-size: 14px;
line-height: 1.5em;
}
.checkbox {
line-height: 24px;
font-weight: 500;
font-size: 1em;
margin-top: 0;
margin-bottom: 20px;
input[type="checkbox"] {
opacity: 0;
position: absolute;
left: -9999px;
}
label {
position: relative;
display: inline-block;
padding-left: 28px;
&:before,
&:after {
position: absolute;
content: "";
display: inline-block;
}
&:before {
height: 16px;
width: 16px;
left: 0px;
top: 3px;
border: 1px solid #aaa;
background-color: #fff;
border-radius: 3px;
}
&:after {
height: 5px;
width: 9px;
border-left: 2px solid;
border-bottom: 2px solid;
transform: rotate(-45deg);
left: 4px;
top: 7px;
color: #fff;
}
}
input[type="checkbox"] + label::after {
content: none;
}
input[type="checkbox"]:checked + label::after {
content: "";
}
input[type="checkbox"]:focus + label::before {
outline: rgb(59, 153, 252) auto 5px;
}
input[type="checkbox"]:checked + label::before {
background: #935687;
border-color: #935687;
outline: none;
}
}
}
}
.wc-setup-steps {
@ -417,8 +485,8 @@ body {
.wc-setup-footer-links {
font-size: 0.85em;
color: #b5b5b5;
margin: 1.18em 0;
display: block;
margin: 1.18em auto;
display: inline-block;
text-align: center;
}
@ -828,11 +896,21 @@ h3.jetpack-reasons {
font-size: 14px;
}
.jetpack-logo {
.jetpack-logo, .wcs-notice {
display: block;
margin: 1.75em auto 2em auto;
max-height: 175px;
}
.activate-splash {
.jetpack-logo {
width: 170px;
margin-bottom: 0;
}
.wcs-notice {
margin-top: 1em;
padding-left: 57px;
}
}
.step {
text-align: center;
@ -1072,15 +1150,6 @@ p.jetpack-terms {
}
}
.allow-tracking {
color: #9f9f9f;
margin-top: 1em;
text-align: center;
font-size: 0.9em;
padding-top: 2em;
border-top: 1px solid #ccc;
}
.wc-wizard-service-setting-stripe_create_account, .wc-wizard-service-setting-ppec_paypal_reroute_requests {
display: flex;
align-items: flex-start;

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -112,9 +112,6 @@ jQuery( function ( $ ) {
if ( ! $country_input.val() ) {
$country_input.val( woocommerce_admin_meta_boxes_order.default_country ).change();
}
if ( ! $state_input.val() ) {
$state_input.val( woocommerce_admin_meta_boxes_order.default_state ).change();
}

File diff suppressed because one or more lines are too long

View File

@ -42,7 +42,7 @@
setTimeout( function() {
$form.trigger( 'check_variations' );
$form.trigger( 'wc_variation_form' );
$form.loading = loading;
$form.loading = false;
}, 100 );
};

File diff suppressed because one or more lines are too long

View File

@ -5465,12 +5465,11 @@ S2.define('select2/core',[
$(document).on('keydown', function (evt) {
var key = evt.which;
if (self.isOpen()) {
if (key === KEYS.ESC || key === KEYS.TAB ||
(key === KEYS.UP && evt.altKey)) {
if (key === KEYS.ESC || (key === KEYS.UP && evt.altKey)) {
self.close();
evt.preventDefault();
} else if (key === KEYS.ENTER) {
} else if (key === KEYS.ENTER || key === KEYS.TAB) {
self.trigger('results:select', {});
evt.preventDefault();

File diff suppressed because one or more lines are too long

View File

@ -5465,12 +5465,11 @@ S2.define('select2/core',[
$(document).on('keydown', function (evt) {
var key = evt.which;
if (self.isOpen()) {
if (key === KEYS.ESC || key === KEYS.TAB ||
(key === KEYS.UP && evt.altKey)) {
if (key === KEYS.ESC || (key === KEYS.UP && evt.altKey)) {
self.close();
evt.preventDefault();
} else if (key === KEYS.ENTER) {
} else if (key === KEYS.ENTER || key === KEYS.TAB) {
self.trigger('results:select', {});
evt.preventDefault();

File diff suppressed because one or more lines are too long

View File

@ -110,7 +110,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
wp_register_script( 'wc-shipping-classes', WC()->plugin_url() . '/assets/js/admin/wc-shipping-classes' . $suffix . '.js', array( 'jquery', 'wp-util', 'underscore', 'backbone' ), WC_VERSION );
wp_register_script( 'wc-clipboard', WC()->plugin_url() . '/assets/js/admin/wc-clipboard' . $suffix . '.js', array( 'jquery' ), WC_VERSION );
wp_register_script( 'select2', WC()->plugin_url() . '/assets/js/select2/select2.full' . $suffix . '.js', array( 'jquery' ), '4.0.3' );
wp_register_script( 'selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full' . $suffix . '.js', array( 'jquery' ), '1.0.3' );
wp_register_script( 'selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full' . $suffix . '.js', array( 'jquery' ), '1.0.4' );
wp_register_script( 'wc-enhanced-select', WC()->plugin_url() . '/assets/js/admin/wc-enhanced-select' . $suffix . '.js', array( 'jquery', 'selectWoo' ), WC_VERSION );
wp_localize_script(
'wc-enhanced-select',

View File

@ -2,15 +2,10 @@
/**
* Init WooCommerce data importers.
*
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 3.1.0
* @package WooCommerce/Admin
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
/**
* WC_Admin_Importers Class.
@ -111,7 +106,6 @@ class WC_Admin_Importers {
* The tax rate importer which extends WP_Importer.
*/
public function tax_rates_importer() {
// Load Importer API
require_once ABSPATH . 'wp-admin/includes/import.php';
if ( ! class_exists( 'WP_Importer' ) ) {
@ -122,10 +116,8 @@ class WC_Admin_Importers {
}
}
// includes
require dirname( __FILE__ ) . '/importers/class-wc-tax-rate-importer.php';
// Dispatch
$importer = new WC_Tax_Rate_Importer();
$importer->dispatch();
}
@ -139,11 +131,11 @@ class WC_Admin_Importers {
public function post_importer_compatibility() {
global $wpdb;
if ( empty( $_POST['import_id'] ) || ! class_exists( 'WXR_Parser' ) ) {
if ( empty( $_POST['import_id'] ) || ! class_exists( 'WXR_Parser' ) ) { // PHPCS: input var ok, CSRF ok.
return;
}
$id = absint( $_POST['import_id'] );
$id = absint( $_POST['import_id'] ); // PHPCS: input var ok.
$file = get_attached_file( $id );
$parser = new WXR_Parser();
$import_data = $parser->parse( $file );
@ -156,8 +148,8 @@ class WC_Admin_Importers {
if ( ! taxonomy_exists( $term['domain'] ) ) {
$attribute_name = wc_sanitize_taxonomy_name( str_replace( 'pa_', '', $term['domain'] ) );
// Create the taxonomy
if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies() ) ) {
// Create the taxonomy.
if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies(), true ) ) {
wc_create_attribute(
array(
'name' => $attribute_name,
@ -198,19 +190,19 @@ class WC_Admin_Importers {
check_ajax_referer( 'wc-product-import', 'security' );
if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['file'] ) ) {
if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['file'] ) ) { // PHPCS: input var ok.
wp_die( -1 );
}
include_once WC_ABSPATH . 'includes/admin/importers/class-wc-product-csv-importer-controller.php';
include_once WC_ABSPATH . 'includes/import/class-wc-product-csv-importer.php';
$file = wc_clean( $_POST['file'] );
$file = wc_clean( wp_unslash( $_POST['file'] ) ); // PHPCS: input var ok.
$params = array(
'delimiter' => ! empty( $_POST['delimiter'] ) ? wc_clean( $_POST['delimiter'] ) : ',',
'start_pos' => isset( $_POST['position'] ) ? absint( $_POST['position'] ) : 0,
'mapping' => isset( $_POST['mapping'] ) ? (array) $_POST['mapping'] : array(),
'update_existing' => isset( $_POST['update_existing'] ) ? (bool) $_POST['update_existing'] : false,
'delimiter' => ! empty( $_POST['delimiter'] ) ? wc_clean( wp_unslash( $_POST['delimiter'] ) ) : ',', // PHPCS: input var ok.
'start_pos' => isset( $_POST['position'] ) ? absint( $_POST['position'] ) : 0, // PHPCS: input var ok.
'mapping' => isset( $_POST['mapping'] ) ? (array) wc_clean( wp_unslash( $_POST['mapping'] ) ) : array(), // PHPCS: input var ok.
'update_existing' => isset( $_POST['update_existing'] ) ? (bool) $_POST['update_existing'] : false, // PHPCS: input var ok.
'lines' => apply_filters( 'woocommerce_product_import_batch_size', 30 ),
'parse' => true,
);
@ -231,7 +223,7 @@ class WC_Admin_Importers {
if ( 100 === $percent_complete ) {
// Clear temp meta.
$wpdb->delete( $wpdb->postmeta, array( 'meta_key' => '_original_id' ) );
$wpdb->delete( $wpdb->postmeta, array( 'meta_key' => '_original_id' ) ); // @codingStandardsIgnoreLine.
$wpdb->query(
"DELETE {$wpdb->posts}, {$wpdb->postmeta}, {$wpdb->term_relationships}
FROM {$wpdb->posts}
@ -243,6 +235,14 @@ class WC_Admin_Importers {
AND {$wpdb->posts}.post_status = 'importing'"
);
// Clear orphan variations.
$wpdb->query(
"DELETE products
FROM {$wpdb->posts} products
LEFT JOIN {$wpdb->posts} wp ON wp.ID = products.post_parent
WHERE wp.ID IS NULL AND products.post_type = 'product_variation';"
);
// Send success.
wp_send_json_success(
array(

View File

@ -171,12 +171,6 @@ class WC_Admin_Setup_Wizard {
unset( $default_steps['shipping'] );
}
// Hide the activate step if Jetpack is already active, but not
// if we're returning from connecting Jetpack on WordPress.com.
if ( class_exists( 'Jetpack' ) && Jetpack::is_active() && ! isset( $_GET['from'] ) && ! isset( $_GET['activate_error'] ) ) { // WPCS: CSRF ok, input var ok.
unset( $default_steps['activate'] );
}
// Whether or not there is a pending background install of Jetpack.
$pending_jetpack = ! class_exists( 'Jetpack' ) && get_option( 'woocommerce_setup_background_installing_jetpack' );
@ -298,21 +292,38 @@ class WC_Admin_Setup_Wizard {
* Output the steps.
*/
public function setup_wizard_steps() {
$output_steps = $this->steps;
$selected_features = array_filter( $this->wc_setup_activate_get_feature_list() );
// Hide the activate step if Jetpack is already active, unless WooCommerce Services
// features are selected, or unless the Activate step was already taken.
if ( class_exists( 'Jetpack' ) && Jetpack::is_active() && empty( $selected_features ) && 'yes' !== get_transient( 'wc_setup_activated' ) ) {
unset( $output_steps['activate'] );
}
?>
<ol class="wc-setup-steps">
<?php foreach ( $this->steps as $step_key => $step ) :
<?php
foreach ( $output_steps as $step_key => $step ) {
$is_completed = array_search( $this->step, array_keys( $this->steps ), true ) > array_search( $step_key, array_keys( $this->steps ), true );
if ( $step_key === $this->step ) : ?>
if ( $step_key === $this->step ) {
?>
<li class="active"><?php echo esc_html( $step['name'] ); ?></li>
<?php elseif ( $is_completed ) : ?>
<?php
} elseif ( $is_completed ) {
?>
<li class="done">
<a href="<?php echo esc_url( add_query_arg( 'step', $step_key, remove_query_arg( 'activate_error' ) ) ) ?>"><?php echo esc_html( $step['name'] ); ?></a>
<a href="<?php echo esc_url( add_query_arg( 'step', $step_key, remove_query_arg( 'activate_error' ) ) ); ?>"><?php echo esc_html( $step['name'] ); ?></a>
</li>
<?php else : ?>
<?php
} else {
?>
<li><?php echo esc_html( $step['name'] ); ?></li>
<?php endif; ?>
<?php endforeach; ?>
<?php
}
}
?>
</ol>
<?php
}
@ -476,12 +487,35 @@ class WC_Admin_Setup_Wizard {
<?php esc_html_e( 'I will also be selling products or services in person.', 'woocommerce' ); ?>
</label>
<?php if ( 'unknown' === get_option( 'woocommerce_allow_tracking', 'unknown' ) ) : ?>
<div class="allow-tracking">
<input type="checkbox" id="wc_tracker_optin" name="wc_tracker_optin" value="yes" checked />
<label for="wc_tracker_optin"><?php esc_html_e( 'Allow WooCommerce to collect non-sensitive diagnostic data and usage information.', 'woocommerce' ); ?></label>
<?php
if ( 'unknown' === get_option( 'woocommerce_allow_tracking', 'unknown' ) ) {
$tracking_opt_out = true;
// EU should be opt-in.
if ( in_array( $country, WC()->countries->get_european_union_countries(), true ) ) {
$tracking_opt_out = false;
}
// Respect the DNT header.
if ( ! empty( $_SERVER['HTTP_DNT'] ) ) { // WPCS: input var ok.
$tracking_opt_out = false;
}
?>
<div class="woocommerce-tracker">
<p class="checkbox">
<input type="checkbox" id="wc_tracker_optin" name="wc_tracker_optin" value="yes" <?php echo $tracking_opt_out ? 'checked' : ''; ?> />
<label for="wc_tracker_optin"><?php esc_html_e( 'Help WooCommerce improve by enabling usage tracking.', 'woocommerce' ); ?></label>
</p>
<p>
<?php
esc_html_e( 'Checking this box means making WooCommerce better &mdash; your store will be considered as we evaluate new features, judge the quality of an update, or determine if an improvement makes sense. If you do not check this box, we will not know this store exists and we will not collect any usage data.', 'woocommerce' );
echo ' <a target="_blank" href="https://woocommerce.com/usage-tracking/">' . esc_html__( 'Read more about what we collect.', 'woocommerce' ) . '</a>';
?>
</p>
</div>
<?php endif; ?>
<?php
}
?>
<p class="wc-setup-actions step">
<button type="submit" class="button-primary button button-large button-next" value="<?php esc_attr_e( "Let's go!", 'woocommerce' ); ?>" name="save_step"><?php esc_html_e( "Let's go!", 'woocommerce' ); ?></button>
</p>
@ -1675,8 +1709,9 @@ class WC_Admin_Setup_Wizard {
}
}
protected function wc_setup_activate_get_description() {
$description = false;
protected function wc_setup_activate_get_feature_list() {
$features = array();
$stripe_settings = get_option( 'woocommerce_stripe_settings', false );
$stripe_enabled = is_array( $stripe_settings )
&& isset( $stripe_settings['create_account'] ) && 'yes' === $stripe_settings['create_account']
@ -1685,32 +1720,35 @@ class WC_Admin_Setup_Wizard {
$ppec_enabled = is_array( $ppec_settings )
&& isset( $ppec_settings['reroute_requests'] ) && 'yes' === $ppec_settings['reroute_requests']
&& isset( $ppec_settings['enabled'] ) && 'yes' === $ppec_settings['enabled'];
$payment_enabled = $stripe_enabled || $ppec_enabled;
$taxes_enabled = (bool) get_option( 'woocommerce_setup_automated_taxes', false );
$features['payment'] = $stripe_enabled || $ppec_enabled;
$features['taxes'] = (bool) get_option( 'woocommerce_setup_automated_taxes', false );
$domestic_rates = (bool) get_option( 'woocommerce_setup_domestic_live_rates_zone', false );
$intl_rates = (bool) get_option( 'woocommerce_setup_intl_live_rates_zone', false );
$rates_enabled = $domestic_rates || $intl_rates;
$features['rates'] = $domestic_rates || $intl_rates;
/* translators: %s: list of features, potentially comma separated */
$description_base = __( 'Your store is almost ready! To activate services like %s, just connect with Jetpack.', 'woocommerce' );
return $features;
}
if ( $payment_enabled && $taxes_enabled && $rates_enabled ) {
$description = sprintf( $description_base, __( 'payment setup, automated taxes, live rates and discounted shipping labels', 'woocommerce' ) );
} else if ( $payment_enabled && $taxes_enabled ) {
$description = sprintf( $description_base, __( 'payment setup and automated taxes', 'woocommerce' ) );
} else if ( $payment_enabled && $rates_enabled ) {
$description = sprintf( $description_base, __( 'payment setup, live rates and discounted shipping labels', 'woocommerce' ) );
} else if ( $payment_enabled ) {
$description = sprintf( $description_base, __( 'payment setup', 'woocommerce' ) );
} else if ( $taxes_enabled && $rates_enabled ) {
$description = sprintf( $description_base, __( 'automated taxes, live rates and discounted shipping labels', 'woocommerce' ) );
} else if ( $taxes_enabled ) {
$description = sprintf( $description_base, __( 'automated taxes', 'woocommerce' ) );
} else if ( $rates_enabled ) {
$description = sprintf( $description_base, __( 'live rates and discounted shipping labels', 'woocommerce' ) );
protected function wc_setup_activate_get_feature_list_str() {
$features = $this->wc_setup_activate_get_feature_list();
if ( $features['payment'] && $features['taxes'] && $features['rates'] ) {
return __( 'payment setup, automated taxes, live rates and discounted shipping labels', 'woocommerce' );
} else if ( $features['payment'] && $features['taxes'] ) {
return __( 'payment setup and automated taxes', 'woocommerce' );
} else if ( $features['payment'] && $features['rates'] ) {
return __( 'payment setup, live rates and discounted shipping labels', 'woocommerce' );
} else if ( $features['payment'] ) {
return __( 'payment setup', 'woocommerce' );
} else if ( $features['taxes'] && $features['rates'] ) {
return __( 'automated taxes, live rates and discounted shipping labels', 'woocommerce' );
} else if ( $features['taxes'] ) {
return __( 'automated taxes', 'woocommerce' );
} else if ( $features['rates'] ) {
return __( 'live rates and discounted shipping labels', 'woocommerce' );
}
return $description;
return false;
}
/**
@ -1719,6 +1757,8 @@ class WC_Admin_Setup_Wizard {
public function wc_setup_activate() {
$this->wc_setup_activate_actions();
$jetpack_connected = class_exists( 'Jetpack' ) && Jetpack::is_active();
$has_jetpack_error = false;
if ( isset( $_GET['activate_error'] ) ) {
$has_jetpack_error = true;
@ -1728,19 +1768,57 @@ class WC_Admin_Setup_Wizard {
$error_message = $this->get_activate_error_message( sanitize_text_field( wp_unslash( $_GET['activate_error'] ) ) );
$description = $error_message;
} else {
$description = $this->wc_setup_activate_get_description();
$title = $description ?
__( 'Connect your store to Jetpack', 'woocommerce' ) :
__( 'Connect your store to Jetpack to enable extra features', 'woocommerce' );
$feature_list = $this->wc_setup_activate_get_feature_list_str();
$description = false;
if ( $feature_list ) {
if ( ! $jetpack_connected ) {
/* translators: %s: list of features, potentially comma separated */
$description_base = __( 'Your store is almost ready! To activate services like %s, just connect with Jetpack.', 'woocommerce' );
} else {
$description_base = __( 'Thanks for using Jetpack! Your store is almost ready: to activate services like %s, just connect your store.', 'woocommerce' );
}
$description = sprintf( $description_base, $feature_list );
}
if ( ! $jetpack_connected ) {
$title = $feature_list ?
__( 'Connect your store to Jetpack', 'woocommerce' ) :
__( 'Connect your store to Jetpack to enable extra features', 'woocommerce' );
$button_text = __( 'Continue with Jetpack', 'woocommerce' );
} elseif ( $feature_list ) {
$title = __( 'Connect your store to activate WooCommerce Services', 'woocommerce' );
$button_text = __( 'Continue with WooCommerce Services', 'woocommerce' );
} else {
wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
exit;
}
}
?>
<h1><?php echo esc_html( $title ); ?></h1>
<p><?php echo esc_html( $description ); ?></p>
<img
class="jetpack-logo"
src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/jetpack_vertical_logo.png' ); ?>"
alt="Jetpack logo"
/>
<?php if ( $jetpack_connected ) : ?>
<div class="activate-splash">
<img
class="jetpack-logo"
src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/jetpack_horizontal_logo.png' ); ?>"
alt="Jetpack logo"
/>
<img
class="wcs-notice"
src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/wcs-notice.png' ); ?>"
/>
</div>
<?php else : ?>
<img
class="jetpack-logo"
src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/jetpack_vertical_logo.png' ); ?>"
alt="Jetpack logo"
/>
<?php endif; ?>
<?php if ( $has_jetpack_error ) : ?>
<p class="wc-setup-actions step">
<a
@ -1762,53 +1840,55 @@ class WC_Admin_Setup_Wizard {
</p>
<form method="post" class="activate-jetpack">
<p class="wc-setup-actions step">
<button type="submit" class="button-primary button button-large" value="<?php esc_attr_e( 'Connect with Jetpack', 'woocommerce' ); ?>"><?php esc_html_e( 'Continue with Jetpack', 'woocommerce' ); ?></button>
<button type="submit" class="button-primary button button-large" value="<?php echo esc_attr( $button_text ); ?>"><?php echo esc_html( $button_text ); ?></button>
</p>
<input type="hidden" name="save_step" value="activate" />
<?php wp_nonce_field( 'wc-setup' ); ?>
</form>
<h3 class="jetpack-reasons">
<?php
echo esc_html( $description ?
__( "Bonus reasons you'll love Jetpack", 'woocommerce' ) :
__( "Reasons you'll love Jetpack", 'woocommerce' )
);
?>
</h3>
<ul class="wc-wizard-features">
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Better security', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( 'Protect your store from unauthorized access.', 'woocommerce' ); ?>
</p>
</li>
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Store stats', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( 'Get insights on how your store is doing, including total sales, top products, and more.', 'woocommerce' ); ?>
</p>
</li>
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Store monitoring', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( 'Get an alert if your store is down for even a few minutes.', 'woocommerce' ); ?>
</p>
</li>
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Product promotion', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( "Share new items on social media the moment they're live in your store.", 'woocommerce' ); ?>
</p>
</li>
</ul>
<?php if ( ! $jetpack_connected ) : ?>
<h3 class="jetpack-reasons">
<?php
echo esc_html( $description ?
__( "Bonus reasons you'll love Jetpack", 'woocommerce' ) :
__( "Reasons you'll love Jetpack", 'woocommerce' )
);
?>
</h3>
<ul class="wc-wizard-features">
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Better security', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( 'Protect your store from unauthorized access.', 'woocommerce' ); ?>
</p>
</li>
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Store stats', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( 'Get insights on how your store is doing, including total sales, top products, and more.', 'woocommerce' ); ?>
</p>
</li>
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Store monitoring', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( 'Get an alert if your store is down for even a few minutes.', 'woocommerce' ); ?>
</p>
</li>
<li class="wc-wizard-feature-item">
<p class="wc-wizard-feature-name">
<strong><?php esc_html_e( 'Product promotion', 'woocommerce' ); ?></strong>
</p>
<p class="wc-wizard-feature-description">
<?php esc_html_e( "Share new items on social media the moment they're live in your store.", 'woocommerce' ); ?>
</p>
</li>
</ul>
<?php endif; ?>
<?php endif; ?>
<?php
}
@ -1835,9 +1915,16 @@ class WC_Admin_Setup_Wizard {
public function wc_setup_activate_save() {
check_admin_referer( 'wc-setup' );
set_transient( 'wc_setup_activated', 'yes', MINUTE_IN_SECONDS * 10 );
// Leave a note for WooCommerce Services that Jetpack has been opted into.
update_option( 'woocommerce_setup_jetpack_opted_in', true );
if ( class_exists( 'Jetpack' ) && Jetpack::is_active() ) {
wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
exit;
}
WC_Install::background_installer( 'jetpack', array(
'file' => 'jetpack/jetpack.php',
'name' => __( 'Jetpack', 'woocommerce' ),

View File

@ -454,10 +454,9 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
// Search using CRUD.
if ( ! empty( $query_vars['s'] ) ) {
$data_store = WC_Data_Store::load( 'product' );
$ids = $data_store->search_products( wc_clean( $query_vars['s'] ), '', true, true );
$query_vars['post__in'] = array_merge( $ids, array( 0 ) );
// So we know we are searching products.
$data_store = WC_Data_Store::load( 'product' );
$ids = $data_store->search_products( wc_clean( wp_unslash( $query_vars['s'] ) ), '', true, true );
$query_vars['post__in'] = array_merge( $ids, array( 0 ) );
$query_vars['product_search'] = true;
unset( $query_vars['s'] );
}

View File

@ -360,6 +360,15 @@ class WC_Meta_Box_Order_Data {
if ( ! isset( $field['id'] ) ) {
$field['id'] = '_billing_' . $key;
}
$field_name = 'billing_' . $key;
if ( is_callable( array( $order, 'get_' . $field_name ) ) ) {
$field['value'] = $order->{"get_$field_name"}( 'edit' );
} else {
$field['value'] = $order->get_meta( '_' . $field_name );
}
switch ( $field['type'] ) {
case 'select':
woocommerce_wp_select( $field );
@ -462,6 +471,14 @@ class WC_Meta_Box_Order_Data {
$field['id'] = '_shipping_' . $key;
}
$field_name = 'shipping_' . $key;
if ( is_callable( array( $order, 'get_' . $field_name ) ) ) {
$field['value'] = $order->{"get_$field_name"}( 'edit' );
} else {
$field['value'] = $order->get_meta( '_' . $field_name );
}
switch ( $field['type'] ) {
case 'select':
woocommerce_wp_select( $field );

View File

@ -1,394 +1,393 @@
<?php
<?php // @codingStandardsIgnoreLine.
/**
* WooCommerce Shipping Settings
* WooCommerce Checkout Settings
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
* @version 2.5.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WC_Settings_Payment_Gateways', false ) ) {
return new WC_Settings_Payment_Gateways();
}
if ( ! class_exists( 'WC_Settings_Payment_Gateways', false ) ) :
/**
* WC_Settings_Payment_Gateways.
*/
class WC_Settings_Payment_Gateways extends WC_Settings_Page {
/**
* WC_Settings_Payment_Gateways.
* Constructor.
*/
class WC_Settings_Payment_Gateways extends WC_Settings_Page {
public function __construct() {
$this->id = 'checkout';
$this->label = _x( 'Checkout', 'Settings tab label', 'woocommerce' );
/**
* Constructor.
*/
public function __construct() {
$this->id = 'checkout';
$this->label = _x( 'Checkout', 'Settings tab label', 'woocommerce' );
add_action( 'woocommerce_admin_field_payment_gateways', array( $this, 'payment_gateways_setting' ) );
parent::__construct();
}
add_action( 'woocommerce_admin_field_payment_gateways', array( $this, 'payment_gateways_setting' ) );
parent::__construct();
}
/**
* Get sections.
*
* @return array
*/
public function get_sections() {
$sections = array(
'' => __( 'Checkout options', 'woocommerce' ),
);
/**
* Get sections.
*
* @return array
*/
public function get_sections() {
$sections = array(
'' => __( 'Checkout options', 'woocommerce' ),
);
if ( ! defined( 'WC_INSTALLING' ) ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
foreach ( $payment_gateways as $gateway ) {
$title = empty( $gateway->method_title ) ? ucfirst( $gateway->id ) : $gateway->method_title;
$sections[ strtolower( $gateway->id ) ] = esc_html( $title );
}
}
return apply_filters( 'woocommerce_get_sections_' . $this->id, $sections );
}
/**
* Get settings array.
*
* @param string $current_section
*
* @return array
*/
public function get_settings( $current_section = '' ) {
$settings = array();
if ( '' === $current_section ) {
$settings = apply_filters(
'woocommerce_payment_gateways_settings', array(
array(
'title' => __( 'Checkout process', 'woocommerce' ),
'type' => 'title',
'id' => 'checkout_process_options',
),
array(
'title' => __( 'Coupons', 'woocommerce' ),
'desc' => __( 'Enable the use of coupons', 'woocommerce' ),
'id' => 'woocommerce_enable_coupons',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'desc_tip' => __( 'Coupons can be applied from the cart and checkout pages.', 'woocommerce' ),
),
array(
'desc' => __( 'Calculate coupon discounts sequentially', 'woocommerce' ),
'id' => 'woocommerce_calc_discounts_sequentially',
'default' => 'no',
'type' => 'checkbox',
'desc_tip' => __( 'When applying multiple coupons, apply the first coupon to the full price and the second coupon to the discounted price and so on.', 'woocommerce' ),
'checkboxgroup' => 'end',
'autoload' => false,
),
array(
'title' => __( 'Checkout process', 'woocommerce' ),
'desc' => __( 'Enable guest checkout', 'woocommerce' ),
'desc_tip' => __( 'Allows customers to checkout without creating an account.', 'woocommerce' ),
'id' => 'woocommerce_enable_guest_checkout',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'autoload' => false,
),
array(
'desc' => __( 'Force secure checkout', 'woocommerce' ),
'id' => 'woocommerce_force_ssl_checkout',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => '',
'show_if_checked' => 'option',
'desc_tip' => sprintf( __( 'Force SSL (HTTPS) on the checkout pages (<a href="%s" target="_blank">an SSL Certificate is required</a>).', 'woocommerce' ), 'https://docs.woocommerce.com/document/ssl-and-https/#section-3' ),
),
'unforce_ssl_checkout' => array(
'desc' => __( 'Force HTTP when leaving the checkout', 'woocommerce' ),
'id' => 'woocommerce_unforce_ssl_checkout',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'show_if_checked' => 'yes',
),
array(
'type' => 'sectionend',
'id' => 'checkout_process_options',
),
array(
'title' => __( 'Checkout pages', 'woocommerce' ),
'desc' => __( 'These pages need to be set so that WooCommerce knows where to send users to checkout.', 'woocommerce' ),
'type' => 'title',
'id' => 'checkout_page_options',
),
array(
'title' => __( 'Cart page', 'woocommerce' ),
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) ),
'id' => 'woocommerce_cart_page_id',
'type' => 'single_select_page',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'desc_tip' => true,
),
array(
'title' => __( 'Checkout page', 'woocommerce' ),
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) ),
'id' => 'woocommerce_checkout_page_id',
'type' => 'single_select_page',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'desc_tip' => true,
),
array(
'title' => __( 'Terms and conditions', 'woocommerce' ),
'desc' => __( 'If you define a "Terms" page the customer will be asked if they accept them when checking out.', 'woocommerce' ),
'id' => 'woocommerce_terms_page_id',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'type' => 'single_select_page',
'args' => array( 'exclude' => wc_get_page_id( 'checkout' ) ),
'desc_tip' => true,
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'checkout_page_options',
),
array(
'title' => __( 'Checkout endpoints', 'woocommerce' ),
'type' => 'title',
'desc' => __( 'Endpoints are appended to your page URLs to handle specific actions during the checkout process. They should be unique.', 'woocommerce' ),
'id' => 'account_endpoint_options',
),
array(
'title' => __( 'Pay', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Pay" page.', 'woocommerce' ),
'id' => 'woocommerce_checkout_pay_endpoint',
'type' => 'text',
'default' => 'order-pay',
'desc_tip' => true,
),
array(
'title' => __( 'Order received', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Order received" page.', 'woocommerce' ),
'id' => 'woocommerce_checkout_order_received_endpoint',
'type' => 'text',
'default' => 'order-received',
'desc_tip' => true,
),
array(
'title' => __( 'Add payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Add payment method" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_add_payment_method_endpoint',
'type' => 'text',
'default' => 'add-payment-method',
'desc_tip' => true,
),
array(
'title' => __( 'Delete payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the delete payment method page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_delete_payment_method_endpoint',
'type' => 'text',
'default' => 'delete-payment-method',
'desc_tip' => true,
),
array(
'title' => __( 'Set default payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the setting a default payment method page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_set_default_payment_method_endpoint',
'type' => 'text',
'default' => 'set-default-payment-method',
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'checkout_endpoint_options',
),
array(
'title' => __( 'Payment gateways', 'woocommerce' ),
'desc' => __( 'Installed gateways are listed below. Drag and drop gateways to control their display order on the frontend.', 'woocommerce' ),
'type' => 'title',
'id' => 'payment_gateways_options',
),
array(
'type' => 'payment_gateways',
),
array(
'type' => 'sectionend',
'id' => 'payment_gateways_options',
),
)
);
if ( wc_site_is_https() ) {
unset( $settings['unforce_ssl_checkout'] );
}
}
return apply_filters( 'woocommerce_get_settings_' . $this->id, $settings, $current_section );
}
/**
* Output the settings.
*/
public function output() {
global $current_section;
// Load shipping methods so we can show any global options they may have.
if ( ! defined( 'WC_INSTALLING' ) ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
if ( $current_section ) {
foreach ( $payment_gateways as $gateway ) {
if ( in_array( $current_section, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ) ) ) {
$gateway->admin_options();
break;
}
}
} else {
$settings = $this->get_settings();
WC_Admin_Settings::output_fields( $settings );
foreach ( $payment_gateways as $gateway ) {
$title = empty( $gateway->method_title ) ? ucfirst( $gateway->id ) : $gateway->method_title;
$sections[ strtolower( $gateway->id ) ] = esc_html( $title );
}
}
/**
* Output payment gateway settings.
*/
public function payment_gateways_setting() {
?>
<tr valign="top">
<th scope="row" class="titledesc"><?php _e( 'Gateway display order', 'woocommerce' ); ?></th>
<td class="forminp">
<table class="wc_gateways widefat" cellspacing="0">
<thead>
<tr>
<?php
$columns = apply_filters(
'woocommerce_payment_gateways_setting_columns', array(
'sort' => '',
'name' => __( 'Gateway', 'woocommerce' ),
'id' => __( 'Gateway ID', 'woocommerce' ),
'status' => __( 'Enabled', 'woocommerce' ),
)
);
return apply_filters( 'woocommerce_get_sections_' . $this->id, $sections );
}
foreach ( $columns as $key => $column ) {
echo '<th class="' . esc_attr( $key ) . '">' . esc_html( $column ) . '</th>';
}
?>
</tr>
</thead>
<tbody>
<?php
foreach ( WC()->payment_gateways->payment_gateways() as $gateway ) {
/**
* Get settings array.
*
* @param string $current_section Section being shown.
* @return array
*/
public function get_settings( $current_section = '' ) {
$settings = array();
echo '<tr>';
if ( '' === $current_section ) {
$settings = apply_filters(
'woocommerce_payment_gateways_settings', array(
foreach ( $columns as $key => $column ) {
array(
'title' => __( 'Checkout process', 'woocommerce' ),
'type' => 'title',
'id' => 'checkout_process_options',
),
switch ( $key ) {
array(
'title' => __( 'Coupons', 'woocommerce' ),
'desc' => __( 'Enable the use of coupons', 'woocommerce' ),
'id' => 'woocommerce_enable_coupons',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'desc_tip' => __( 'Coupons can be applied from the cart and checkout pages.', 'woocommerce' ),
),
case 'sort':
echo '<td width="1%" class="sort">
<input type="hidden" name="gateway_order[]" value="' . esc_attr( $gateway->id ) . '" />
</td>';
break;
array(
'desc' => __( 'Calculate coupon discounts sequentially', 'woocommerce' ),
'id' => 'woocommerce_calc_discounts_sequentially',
'default' => 'no',
'type' => 'checkbox',
'desc_tip' => __( 'When applying multiple coupons, apply the first coupon to the full price and the second coupon to the discounted price and so on.', 'woocommerce' ),
'checkboxgroup' => 'end',
'autoload' => false,
),
case 'name':
$method_title = $gateway->get_title() ? $gateway->get_title() : __( '(no title)', 'woocommerce' );
echo '<td class="name">
<a href="' . admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( $gateway->id ) ) . '">' . esc_html( $method_title ) . '</a>
</td>';
break;
array(
'title' => __( 'Checkout process', 'woocommerce' ),
'desc' => __( 'Enable guest checkout', 'woocommerce' ),
'desc_tip' => __( 'Allows customers to checkout without creating an account.', 'woocommerce' ),
'id' => 'woocommerce_enable_guest_checkout',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'start',
'autoload' => false,
),
case 'id':
echo '<td class="id">' . esc_html( $gateway->id ) . '</td>';
break;
array(
'desc' => __( 'Force secure checkout', 'woocommerce' ),
'id' => 'woocommerce_force_ssl_checkout',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => '',
'show_if_checked' => 'option',
/* Translators: %s Docs URL. */
'desc_tip' => sprintf( __( 'Force SSL (HTTPS) on the checkout pages (<a href="%s" target="_blank">an SSL Certificate is required</a>).', 'woocommerce' ), 'https://docs.woocommerce.com/document/ssl-and-https/#section-3' ),
),
case 'status':
echo '<td class="status">';
echo ( 'yes' === $gateway->enabled ) ? '<span class="status-enabled tips" data-tip="' . esc_attr__( 'Yes', 'woocommerce' ) . '">' . esc_html__( 'Yes', 'woocommerce' ) . '</span>' : '-';
echo '</td>';
break;
'unforce_ssl_checkout' => array(
'desc' => __( 'Force HTTP when leaving the checkout', 'woocommerce' ),
'id' => 'woocommerce_unforce_ssl_checkout',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'end',
'show_if_checked' => 'yes',
),
default:
do_action( 'woocommerce_payment_gateways_setting_column_' . $key, $gateway );
break;
}
}
array(
'type' => 'sectionend',
'id' => 'checkout_process_options',
),
echo '</tr>';
}
?>
</tbody>
</table>
</td>
</tr>
<?php
array(
'title' => __( 'Checkout pages', 'woocommerce' ),
'desc' => __( 'These pages need to be set so that WooCommerce knows where to send users to checkout.', 'woocommerce' ),
'type' => 'title',
'id' => 'checkout_page_options',
),
array(
'title' => __( 'Cart page', 'woocommerce' ),
/* Translators: %s Page contents. */
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) ),
'id' => 'woocommerce_cart_page_id',
'type' => 'single_select_page',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'desc_tip' => true,
),
array(
'title' => __( 'Checkout page', 'woocommerce' ),
/* Translators: %s Page contents. */
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) ),
'id' => 'woocommerce_checkout_page_id',
'type' => 'single_select_page',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'desc_tip' => true,
),
array(
'title' => __( 'Terms and conditions', 'woocommerce' ),
'desc' => __( 'If you define a "Terms" page the customer will be asked if they accept them when checking out.', 'woocommerce' ),
'id' => 'woocommerce_terms_page_id',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'type' => 'single_select_page',
'args' => array( 'exclude' => wc_get_page_id( 'checkout' ) ),
'desc_tip' => true,
'autoload' => false,
),
array(
'type' => 'sectionend',
'id' => 'checkout_page_options',
),
array(
'title' => __( 'Checkout endpoints', 'woocommerce' ),
'type' => 'title',
'desc' => __( 'Endpoints are appended to your page URLs to handle specific actions during the checkout process. They should be unique.', 'woocommerce' ),
'id' => 'account_endpoint_options',
),
array(
'title' => __( 'Pay', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Pay" page.', 'woocommerce' ),
'id' => 'woocommerce_checkout_pay_endpoint',
'type' => 'text',
'default' => 'order-pay',
'desc_tip' => true,
),
array(
'title' => __( 'Order received', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Order received" page.', 'woocommerce' ),
'id' => 'woocommerce_checkout_order_received_endpoint',
'type' => 'text',
'default' => 'order-received',
'desc_tip' => true,
),
array(
'title' => __( 'Add payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the "Checkout &rarr; Add payment method" page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_add_payment_method_endpoint',
'type' => 'text',
'default' => 'add-payment-method',
'desc_tip' => true,
),
array(
'title' => __( 'Delete payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the delete payment method page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_delete_payment_method_endpoint',
'type' => 'text',
'default' => 'delete-payment-method',
'desc_tip' => true,
),
array(
'title' => __( 'Set default payment method', 'woocommerce' ),
'desc' => __( 'Endpoint for the setting a default payment method page.', 'woocommerce' ),
'id' => 'woocommerce_myaccount_set_default_payment_method_endpoint',
'type' => 'text',
'default' => 'set-default-payment-method',
'desc_tip' => true,
),
array(
'type' => 'sectionend',
'id' => 'checkout_endpoint_options',
),
array(
'title' => __( 'Payment gateways', 'woocommerce' ),
'desc' => __( 'Installed gateways are listed below. Drag and drop gateways to control their display order on the frontend.', 'woocommerce' ),
'type' => 'title',
'id' => 'payment_gateways_options',
),
array(
'type' => 'payment_gateways',
),
array(
'type' => 'sectionend',
'id' => 'payment_gateways_options',
),
)
);
if ( wc_site_is_https() ) {
unset( $settings['unforce_ssl_checkout'] );
}
}
/**
* Save settings.
*/
public function save() {
global $current_section;
return apply_filters( 'woocommerce_get_settings_' . $this->id, $settings, $current_section );
}
$wc_payment_gateways = WC_Payment_Gateways::instance();
/**
* Output the settings.
*/
public function output() {
global $current_section;
if ( ! $current_section ) {
// Prevent the T&Cs and checkout page from being set to the same page.
if ( isset( $_POST['woocommerce_terms_page_id'], $_POST['woocommerce_checkout_page_id'] ) && $_POST['woocommerce_terms_page_id'] === $_POST['woocommerce_checkout_page_id'] ) {
$_POST['woocommerce_terms_page_id'] = '';
}
// Load gateways so we can show any global options they may have.
$payment_gateways = WC()->payment_gateways->payment_gateways();
WC_Admin_Settings::save_fields( $this->get_settings() );
$wc_payment_gateways->process_admin_options();
} else {
foreach ( $wc_payment_gateways->payment_gateways() as $gateway ) {
if ( in_array( $current_section, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ) ) ) {
do_action( 'woocommerce_update_options_payment_gateways_' . $gateway->id );
$wc_payment_gateways->init();
}
if ( $current_section ) {
foreach ( $payment_gateways as $gateway ) {
if ( in_array( $current_section, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ), true ) ) {
$gateway->admin_options();
break;
}
}
} else {
$settings = $this->get_settings();
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
}
WC_Admin_Settings::output_fields( $settings );
}
}
endif;
/**
* Output payment gateway settings.
*/
public function payment_gateways_setting() {
?>
<tr valign="top">
<th scope="row" class="titledesc"><?php esc_html_e( 'Gateway display order', 'woocommerce' ); ?></th>
<td class="forminp">
<table class="wc_gateways widefat" cellspacing="0">
<thead>
<tr>
<?php
$columns = apply_filters(
'woocommerce_payment_gateways_setting_columns', array(
'sort' => '',
'name' => __( 'Gateway', 'woocommerce' ),
'id' => __( 'Gateway ID', 'woocommerce' ),
'status' => __( 'Enabled', 'woocommerce' ),
)
);
foreach ( $columns as $key => $column ) {
echo '<th class="' . esc_attr( $key ) . '">' . esc_html( $column ) . '</th>';
}
?>
</tr>
</thead>
<tbody>
<?php
foreach ( WC()->payment_gateways->payment_gateways() as $gateway ) {
echo '<tr>';
foreach ( $columns as $key => $column ) {
switch ( $key ) {
case 'sort':
echo '<td width="1%" class="sort">
<input type="hidden" name="gateway_order[]" value="' . esc_attr( $gateway->id ) . '" />
</td>';
break;
case 'name':
$method_title = $gateway->get_title() ? $gateway->get_title() : __( '(no title)', 'woocommerce' );
echo '<td class="name">
<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( $gateway->id ) ) ) . '">' . esc_html( $method_title ) . '</a>
</td>';
break;
case 'id':
echo '<td class="id">' . esc_html( $gateway->id ) . '</td>';
break;
case 'status':
echo '<td class="status">';
echo ( 'yes' === $gateway->enabled ) ? '<span class="status-enabled tips" data-tip="' . esc_attr__( 'Yes', 'woocommerce' ) . '">' . esc_html__( 'Yes', 'woocommerce' ) . '</span>' : '-';
echo '</td>';
break;
default:
do_action( 'woocommerce_payment_gateways_setting_column_' . $key, $gateway );
break;
}
}
echo '</tr>';
}
?>
</tbody>
</table>
</td>
</tr>
<?php
}
/**
* Save settings.
*/
public function save() {
global $current_section;
$wc_payment_gateways = WC_Payment_Gateways::instance();
if ( ! $current_section ) {
// Prevent the T&Cs and checkout page from being set to the same page.
if ( isset( $_POST['woocommerce_terms_page_id'], $_POST['woocommerce_checkout_page_id'] ) && $_POST['woocommerce_terms_page_id'] === $_POST['woocommerce_checkout_page_id'] ) { // WPCS: input var ok, CSRF ok.
$_POST['woocommerce_terms_page_id'] = '';
}
WC_Admin_Settings::save_fields( $this->get_settings() );
$wc_payment_gateways->process_admin_options();
$wc_payment_gateways->init();
} else {
foreach ( $wc_payment_gateways->payment_gateways() as $gateway ) {
if ( in_array( $current_section, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ), true ) ) {
do_action( 'woocommerce_update_options_payment_gateways_' . $gateway->id );
$wc_payment_gateways->init();
}
}
}
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
}
}
}
return new WC_Settings_Payment_Gateways();

View File

@ -1,16 +0,0 @@
<?php
/**
* Admin View: Notice - Tracking
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<div id="message" class="updated woocommerce-message woocommerce-tracker">
<p><?php printf( __( 'Want to help make WooCommerce even more awesome? Allow WooCommerce to collect non-sensitive diagnostic data and usage information, and get %1$s discount on your next WooThemes purchase. <a href="%2$s" target="_blank">Find out more</a>.', 'woocommerce' ), '20%', 'https://woocommerce.com/usage-tracking/' ); ?></p>
<p class="submit">
<a class="button-primary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc_tracker_optin', 'true' ), 'wc_tracker_optin', 'wc_tracker_nonce' ) ); ?>"><?php _e( 'Allow', 'woocommerce' ); ?></a>
<a class="skip button-secondary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc-hide-notice', 'tracking' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>"><?php _e( 'No, do not bother me again', 'woocommerce' ); ?></a>
</p>
</div>

View File

@ -214,6 +214,7 @@ function woocommerce_wp_select( $field ) {
$field_attributes['style'] = $field['style'];
$field_attributes['id'] = $field['id'];
$field_attributes['name'] = $field['name'];
$field_attributes['class'] = $field['class'];
$tooltip = ! empty( $field['description'] ) && false !== $field['desc_tip'] ? $field['description'] : '';
$description = ! empty( $field['description'] ) && false === $field['desc_tip'] ? $field['description'] : '';

View File

@ -4,15 +4,11 @@
*
* Handles WC-API endpoint requests.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.0
* @package WooCommerce/API
* @since 2.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
/**
* API class.
@ -130,78 +126,78 @@ class WC_API extends WC_Legacy_API {
*/
private function rest_api_includes() {
// Exception handler.
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-exception.php' );
include_once dirname( __FILE__ ) . '/api/class-wc-rest-exception.php';
// Authentication.
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-authentication.php' );
include_once dirname( __FILE__ ) . '/api/class-wc-rest-authentication.php';
// Abstract controllers.
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-posts-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-crud-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-terms-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-shipping-zones-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-settings-api.php' );
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-controller.php';
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-posts-controller.php';
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-crud-controller.php';
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-terms-controller.php';
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-shipping-zones-controller.php';
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-settings-api.php';
// REST API v1 controllers.
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-coupons-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-customer-downloads-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-customers-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-orders-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-order-notes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-order-refunds-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-attribute-terms-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-attributes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-categories-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-reviews-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-shipping-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-tags-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-products-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-report-sales-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-report-top-sellers-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-reports-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-tax-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-taxes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-webhook-deliveries-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-webhooks-controller.php' );
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-coupons-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-customer-downloads-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-customers-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-orders-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-order-notes-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-order-refunds-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-attribute-terms-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-attributes-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-categories-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-reviews-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-shipping-classes-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-product-tags-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-products-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-report-sales-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-report-top-sellers-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-reports-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-tax-classes-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-taxes-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-webhook-deliveries-controller.php';
include_once dirname( __FILE__ ) . '/api/v1/class-wc-rest-webhooks-controller.php';
// Legacy v2 code.
include_once( dirname( __FILE__ ) . '/api/legacy/class-wc-rest-legacy-coupons-controller.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/class-wc-rest-legacy-orders-controller.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/class-wc-rest-legacy-products-controller.php' );
include_once dirname( __FILE__ ) . '/api/legacy/class-wc-rest-legacy-coupons-controller.php';
include_once dirname( __FILE__ ) . '/api/legacy/class-wc-rest-legacy-orders-controller.php';
include_once dirname( __FILE__ ) . '/api/legacy/class-wc-rest-legacy-products-controller.php';
// REST API v2 controllers.
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-coupons-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-customer-downloads-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-customers-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-orders-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-network-orders-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-order-notes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-order-refunds-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-attribute-terms-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-attributes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-categories-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-reviews-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-shipping-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-tags-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-products-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-variations-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-report-sales-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-report-top-sellers-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-reports-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-settings-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-setting-options-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zones-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zone-locations-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zone-methods-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-tax-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-taxes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-webhook-deliveries-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-webhooks-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-system-status-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-system-status-tools-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-methods-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-payment-gateways-controller.php' );
include_once dirname( __FILE__ ) . '/api/class-wc-rest-coupons-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-customer-downloads-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-customers-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-orders-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-network-orders-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-order-notes-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-order-refunds-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-product-attribute-terms-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-product-attributes-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-product-categories-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-product-reviews-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-product-shipping-classes-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-product-tags-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-products-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-product-variations-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-report-sales-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-report-top-sellers-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-reports-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-settings-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-setting-options-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zones-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zone-locations-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zone-methods-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-tax-classes-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-taxes-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-webhook-deliveries-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-webhooks-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-system-status-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-system-status-tools-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-shipping-methods-controller.php';
include_once dirname( __FILE__ ) . '/api/class-wc-rest-payment-gateways-controller.php';
}
/**

View File

@ -4,15 +4,15 @@
*
* Handles wc-auth endpoint requests.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.4.0
* @package WooCommerce/API
* @since 2.4.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
/**
* Auth class.
*/
class WC_Auth {
/**
@ -28,23 +28,21 @@ class WC_Auth {
* @since 2.4.0
*/
public function __construct() {
// Add query vars
// Add query vars.
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Register auth endpoint
// Register auth endpoint.
add_action( 'init', array( __CLASS__, 'add_endpoint' ), 0 );
// Handle auth requests
add_action( 'parse_request', array( $this, 'handle_auth_requests' ), 0 );
// Handle auth requests.
add_action( 'parse_request.', array( $this, 'handle_auth_requests' ), 0 );
}
/**
* Add query vars.
*
* @since 2.4.0
*
* @param array $vars
*
* @param array $vars Query variables.
* @return string[]
*/
public function add_query_vars( $vars ) {
@ -66,9 +64,7 @@ class WC_Auth {
* Get scope name.
*
* @since 2.4.0
*
* @param string $scope
*
* @param string $scope Permission scope.
* @return string
*/
protected function get_i18n_scope( $scope ) {
@ -85,34 +81,32 @@ class WC_Auth {
* Return a list of permissions a scope allows.
*
* @since 2.4.0
*
* @param string $scope
*
* @param string $scope Permission scope.
* @return array
*/
protected function get_permissions_in_scope( $scope ) {
$permissions = array();
switch ( $scope ) {
case 'read' :
case 'read':
$permissions[] = __( 'View coupons', 'woocommerce' );
$permissions[] = __( 'View customers', 'woocommerce' );
$permissions[] = __( 'View orders and sales reports', 'woocommerce' );
$permissions[] = __( 'View products', 'woocommerce' );
break;
case 'write' :
break;
case 'write':
$permissions[] = __( 'Create webhooks', 'woocommerce' );
$permissions[] = __( 'Create coupons', 'woocommerce' );
$permissions[] = __( 'Create customers', 'woocommerce' );
$permissions[] = __( 'Create orders', 'woocommerce' );
$permissions[] = __( 'Create products', 'woocommerce' );
break;
case 'read_write' :
break;
case 'read_write':
$permissions[] = __( 'Create webhooks', 'woocommerce' );
$permissions[] = __( 'View and manage coupons', 'woocommerce' );
$permissions[] = __( 'View and manage customers', 'woocommerce' );
$permissions[] = __( 'View and manage orders and sales reports', 'woocommerce' );
$permissions[] = __( 'View and manage products', 'woocommerce' );
break;
break;
}
return apply_filters( 'woocommerce_api_permissions_in_scope', $permissions, $scope );
}
@ -121,27 +115,28 @@ class WC_Auth {
* Build auth urls.
*
* @since 2.4.0
*
* @param array $data
* @param string $endpoint
*
* @param array $data Data to build URL.
* @param string $endpoint Endpoint.
* @return string
*/
protected function build_url( $data, $endpoint ) {
$url = wc_get_endpoint_url( 'wc-auth/v' . self::VERSION, $endpoint, home_url( '/' ) );
return add_query_arg( array(
'app_name' => wc_clean( $data['app_name'] ),
'user_id' => wc_clean( $data['user_id'] ),
'return_url' => urlencode( $this->get_formatted_url( $data['return_url'] ) ),
'callback_url' => urlencode( $this->get_formatted_url( $data['callback_url'] ) ),
'scope' => wc_clean( $data['scope'] ),
), $url );
return add_query_arg(
array(
'app_name' => wc_clean( $data['app_name'] ),
'user_id' => wc_clean( $data['user_id'] ),
'return_url' => rawurlencode( $this->get_formatted_url( $data['return_url'] ) ),
'callback_url' => rawurlencode( $this->get_formatted_url( $data['callback_url'] ) ),
'scope' => wc_clean( $data['scope'] ),
), $url
);
}
/**
* Decode and format a URL.
* @param string $url
*
* @param string $url URL.
* @return string
*/
protected function get_formatted_url( $url ) {
@ -158,8 +153,10 @@ class WC_Auth {
* Make validation.
*
* @since 2.4.0
* @throws Exception When validate fails.
*/
protected function make_validation() {
$data = array();
$params = array(
'app_name',
'user_id',
@ -169,19 +166,21 @@ class WC_Auth {
);
foreach ( $params as $param ) {
if ( empty( $_REQUEST[ $param ] ) ) {
if ( empty( $_REQUEST[ $param ] ) ) { // WPCS: input var ok, CSRF ok.
/* translators: %s: parameter */
throw new Exception( sprintf( __( 'Missing parameter %s', 'woocommerce' ), $param ) );
}
$data[ $param ] = wp_unslash( $_REQUEST[ $param ] ); // WPCS: input var ok, CSRF ok, sanitization ok.
}
if ( ! in_array( $_REQUEST['scope'], array( 'read', 'write', 'read_write' ) ) ) {
if ( ! in_array( $data['scope'], array( 'read', 'write', 'read_write' ), true ) ) {
/* translators: %s: scope */
throw new Exception( sprintf( __( 'Invalid scope %s', 'woocommerce' ), wc_clean( $_REQUEST['scope'] ) ) );
throw new Exception( sprintf( __( 'Invalid scope %s', 'woocommerce' ), wc_clean( $data['scope'] ) ) );
}
foreach ( array( 'return_url', 'callback_url' ) as $param ) {
$param = $this->get_formatted_url( $_REQUEST[ $param ] );
$param = $this->get_formatted_url( $data[ $param ] );
if ( false === filter_var( $param, FILTER_VALIDATE_URL ) ) {
/* translators: %s: url */
@ -189,7 +188,7 @@ class WC_Auth {
}
}
$callback_url = $this->get_formatted_url( $_REQUEST['callback_url'] );
$callback_url = $this->get_formatted_url( $data['callback_url'] );
if ( 0 !== stripos( $callback_url, 'https://' ) ) {
throw new Exception( __( 'The callback_url needs to be over SSL', 'woocommerce' ) );
@ -201,17 +200,17 @@ class WC_Auth {
*
* @since 2.4.0
*
* @param string $app_name
* @param string $app_user_id
* @param string $scope
* @param string $app_name App name.
* @param string $app_user_id User ID.
* @param string $scope Scope.
*
* @return array
*/
protected function create_keys( $app_name, $app_user_id, $scope ) {
global $wpdb;
/* translators: 1: app name 2: scope 3: date 4: time */
$description = sprintf(
/* translators: 1: app name 2: scope 3: date 4: time */
__( '%1$s - API %2$s (created on %3$s at %4$s).', 'woocommerce' ),
wc_clean( $app_name ),
$this->get_i18n_scope( $scope ),
@ -221,7 +220,7 @@ class WC_Auth {
$user = wp_get_current_user();
// Created API keys.
$permissions = ( in_array( $scope, array( 'read', 'write', 'read_write' ) ) ) ? sanitize_text_field( $scope ) : 'read';
$permissions = in_array( $scope, array( 'read', 'write', 'read_write' ), true ) ? sanitize_text_field( $scope ) : 'read';
$consumer_key = 'ck_' . wc_rand_hash();
$consumer_secret = 'cs_' . wc_rand_hash();
@ -259,17 +258,16 @@ class WC_Auth {
*
* @since 2.4.0
*
* @param array $consumer_data
* @param string $url
*
* @throws Exception When validation fails.
* @param array $consumer_data Consumer data.
* @param string $url URL.
* @return bool
* @throws Exception
*/
protected function post_consumer_data( $consumer_data, $url ) {
$params = array(
'body' => json_encode( $consumer_data ),
'timeout' => 60,
'headers' => array(
'body' => wp_json_encode( $consumer_data ),
'timeout' => 60,
'headers' => array(
'Content-Type' => 'application/json;charset=' . get_bloginfo( 'charset' ),
),
);
@ -278,7 +276,7 @@ class WC_Auth {
if ( is_wp_error( $response ) ) {
throw new Exception( $response->get_error_message() );
} elseif ( 200 != $response['response']['code'] ) {
} elseif ( 200 !== intval( $response['response']['code'] ) ) {
throw new Exception( __( 'An error occurred in the request and at the time were unable to send the consumer data', 'woocommerce' ) );
}
@ -293,15 +291,15 @@ class WC_Auth {
public function handle_auth_requests() {
global $wp;
if ( ! empty( $_GET['wc-auth-version'] ) ) {
$wp->query_vars['wc-auth-version'] = $_GET['wc-auth-version'];
if ( ! empty( $_GET['wc-auth-version'] ) ) { // WPCS: input var ok, CSRF ok.
$wp->query_vars['wc-auth-version'] = wc_clean( wp_unslash( $_GET['wc-auth-version'] ) ); // WPCS: input var ok, CSRF ok.
}
if ( ! empty( $_GET['wc-auth-route'] ) ) {
$wp->query_vars['wc-auth-route'] = $_GET['wc-auth-route'];
$wp->query_vars['wc-auth-route'] = wc_clean( wp_unslash( $_GET['wc-auth-route'] ) ); // WPCS: input var ok, CSRF ok.
}
// wc-auth endpoint requests
// wc-auth endpoint requests.
if ( ! empty( $wp->query_vars['wc-auth-version'] ) && ! empty( $wp->query_vars['wc-auth-route'] ) ) {
$this->auth_endpoint( $wp->query_vars['wc-auth-route'] );
}
@ -311,8 +309,8 @@ class WC_Auth {
* Auth endpoint.
*
* @since 2.4.0
*
* @param string $route
* @throws Exception When validation fails.
* @param string $route Route.
*/
protected function auth_endpoint( $route ) {
ob_start();
@ -327,50 +325,74 @@ class WC_Auth {
$route = strtolower( wc_clean( $route ) );
$this->make_validation();
// Login endpoint
if ( 'login' == $route && ! is_user_logged_in() ) {
wc_get_template( 'auth/form-login.php', array(
'app_name' => $_REQUEST['app_name'],
'return_url' => add_query_arg( array( 'success' => 0, 'user_id' => wc_clean( $_REQUEST['user_id'] ) ), $this->get_formatted_url( $_REQUEST['return_url'] ) ),
'redirect_url' => $this->build_url( $_REQUEST, 'authorize' ),
) );
$data = wp_unslash( $_REQUEST ); // WPCS: input var ok, CSRF ok.
// Login endpoint.
if ( 'login' === $route && ! is_user_logged_in() ) {
wc_get_template(
'auth/form-login.php', array(
'app_name' => wc_clean( $data['app_name'] ),
'return_url' => add_query_arg(
array(
'success' => 0,
'user_id' => wc_clean( $data['user_id'] ),
), $this->get_formatted_url( $data['return_url'] )
),
'redirect_url' => $this->build_url( $data, 'authorize' ),
)
);
exit;
// Redirect with user is logged in
} elseif ( 'login' == $route && is_user_logged_in() ) {
wp_redirect( esc_url_raw( $this->build_url( $_REQUEST, 'authorize' ) ) );
} elseif ( 'login' === $route && is_user_logged_in() ) {
// Redirect with user is logged in.
wp_redirect( esc_url_raw( $this->build_url( $data, 'authorize' ) ) );
exit;
// Redirect with user is not logged in and trying to access the authorize endpoint
} elseif ( 'authorize' == $route && ! is_user_logged_in() ) {
wp_redirect( esc_url_raw( $this->build_url( $_REQUEST, 'login' ) ) );
} elseif ( 'authorize' === $route && ! is_user_logged_in() ) {
// Redirect with user is not logged in and trying to access the authorize endpoint.
wp_redirect( esc_url_raw( $this->build_url( $data, 'login' ) ) );
exit;
// Authorize endpoint
} elseif ( 'authorize' == $route && current_user_can( 'manage_woocommerce' ) ) {
wc_get_template( 'auth/form-grant-access.php', array(
'app_name' => $_REQUEST['app_name'],
'return_url' => add_query_arg( array( 'success' => 0, 'user_id' => wc_clean( $_REQUEST['user_id'] ) ), $this->get_formatted_url( $_REQUEST['return_url'] ) ),
'scope' => $this->get_i18n_scope( wc_clean( $_REQUEST['scope'] ) ),
'permissions' => $this->get_permissions_in_scope( wc_clean( $_REQUEST['scope'] ) ),
'granted_url' => wp_nonce_url( $this->build_url( $_REQUEST, 'access_granted' ), 'wc_auth_grant_access', 'wc_auth_nonce' ),
'logout_url' => wp_logout_url( $this->build_url( $_REQUEST, 'login' ) ),
'user' => wp_get_current_user(),
) );
} elseif ( 'authorize' === $route && current_user_can( 'manage_woocommerce' ) ) {
// Authorize endpoint.
wc_get_template(
'auth/form-grant-access.php', array(
'app_name' => wc_clean( $data['app_name'] ),
'return_url' => add_query_arg(
array(
'success' => 0,
'user_id' => wc_clean( $data['user_id'] ),
), $this->get_formatted_url( $data['return_url'] )
),
'scope' => $this->get_i18n_scope( wc_clean( $data['scope'] ) ),
'permissions' => $this->get_permissions_in_scope( wc_clean( $data['scope'] ) ),
'granted_url' => wp_nonce_url( $this->build_url( $data, 'access_granted' ), 'wc_auth_grant_access', 'wc_auth_nonce' ),
'logout_url' => wp_logout_url( $this->build_url( $data, 'login' ) ),
'user' => wp_get_current_user(),
)
);
exit;
// Granted access endpoint
} elseif ( 'access_granted' == $route && current_user_can( 'manage_woocommerce' ) ) {
if ( ! isset( $_GET['wc_auth_nonce'] ) || ! wp_verify_nonce( $_GET['wc_auth_nonce'], 'wc_auth_grant_access' ) ) {
} elseif ( 'access_granted' === $route && current_user_can( 'manage_woocommerce' ) ) {
// Granted access endpoint.
if ( ! isset( $_GET['wc_auth_nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['wc_auth_nonce'] ) ), 'wc_auth_grant_access' ) ) { // WPCS: input var ok.
throw new Exception( __( 'Invalid nonce verification', 'woocommerce' ) );
}
$consumer_data = $this->create_keys( $_REQUEST['app_name'], $_REQUEST['user_id'], $_REQUEST['scope'] );
$response = $this->post_consumer_data( $consumer_data, $this->get_formatted_url( $_REQUEST['callback_url'] ) );
$consumer_data = $this->create_keys( $data['app_name'], $data['user_id'], $data['scope'] );
$response = $this->post_consumer_data( $consumer_data, $this->get_formatted_url( $data['callback_url'] ) );
if ( $response ) {
wp_redirect( esc_url_raw( add_query_arg( array( 'success' => 1, 'user_id' => wc_clean( $_REQUEST['user_id'] ) ), $this->get_formatted_url( $_REQUEST['return_url'] ) ) ) );
wp_redirect(
esc_url_raw(
add_query_arg(
array(
'success' => 1,
'user_id' => wc_clean( $data['user_id'] ),
), $this->get_formatted_url( $data['return_url'] )
)
)
);
exit;
}
} else {
@ -380,7 +402,7 @@ class WC_Auth {
$this->maybe_delete_key( $consumer_data );
/* translators: %s: error message */
wp_die( sprintf( __( 'Error: %s.', 'woocommerce' ), $e->getMessage() ), __( 'Access denied', 'woocommerce' ), array( 'response' => 401 ) );
wp_die( sprintf( esc_html__( 'Error: %s.', 'woocommerce' ), esc_html( $e->getMessage() ) ), esc_html__( 'Access denied', 'woocommerce' ), array( 'response' => 401 ) );
}
}
@ -389,7 +411,7 @@ class WC_Auth {
*
* @since 2.4.0
*
* @param array $key
* @param array $key Key.
*/
private function maybe_delete_key( $key ) {
global $wpdb;

View File

@ -1,16 +1,15 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WooCommerce Autoloader.
*
* @class WC_Autoloader
* @version 2.3.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
* @package WooCommerce/Classes
* @version 2.3.0
*/
defined( 'ABSPATH' ) || exit;
/**
* Autoloader class.
*/
class WC_Autoloader {
@ -25,8 +24,8 @@ class WC_Autoloader {
* The Constructor.
*/
public function __construct() {
if ( function_exists( "__autoload" ) ) {
spl_autoload_register( "__autoload" );
if ( function_exists( '__autoload' ) ) {
spl_autoload_register( '__autoload' );
}
spl_autoload_register( array( $this, 'autoload' ) );
@ -37,7 +36,7 @@ class WC_Autoloader {
/**
* Take a class name and turn it into a file name.
*
* @param string $class
* @param string $class Class name.
* @return string
*/
private function get_file_name_from_class( $class ) {
@ -47,12 +46,12 @@ class WC_Autoloader {
/**
* Include a class file.
*
* @param string $path
* @return bool successful or not
* @param string $path File path.
* @return bool Successful or not.
*/
private function load_file( $path ) {
if ( $path && is_readable( $path ) ) {
include_once( $path );
include_once $path;
return true;
}
return false;
@ -61,7 +60,7 @@ class WC_Autoloader {
/**
* Auto-load WC classes on demand to reduce memory consumption.
*
* @param string $class
* @param string $class Class name.
*/
public function autoload( $class ) {
$class = strtolower( $class );
@ -70,14 +69,14 @@ class WC_Autoloader {
return;
}
$file = $this->get_file_name_from_class( $class );
$path = '';
$file = $this->get_file_name_from_class( $class );
$path = '';
if ( 0 === strpos( $class, 'wc_addons_gateway_' ) ) {
if ( 0 === strpos( $class, 'wc_addons_gateway_' ) ) {
$path = $this->include_path . 'gateways/' . substr( str_replace( '_', '-', $class ), 18 ) . '/';
} elseif ( 0 === strpos( $class, 'wc_gateway_' ) ) {
} elseif ( 0 === strpos( $class, 'wc_gateway_' ) ) {
$path = $this->include_path . 'gateways/' . substr( str_replace( '_', '-', $class ), 11 ) . '/';
} elseif ( 0 === strpos( $class, 'wc_shipping_' ) ) {
} elseif ( 0 === strpos( $class, 'wc_shipping_' ) ) {
$path = $this->include_path . 'shipping/' . substr( str_replace( '_', '-', $class ), 12 ) . '/';
} elseif ( 0 === strpos( $class, 'wc_shortcode_' ) ) {
$path = $this->include_path . 'shortcodes/';

View File

@ -2,13 +2,11 @@
/**
* Background Emailer
*
* @version 3.0.1
* @package WooCommerce/Classes
* @version 3.0.1
* @package WooCommerce/Classes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'WC_Background_Process', false ) ) {
include_once dirname( __FILE__ ) . '/abstracts/class-wc-background-process.php';
@ -59,7 +57,7 @@ class WC_Background_Emailer extends WC_Background_Process {
WC_Emails::send_queued_transactional_email( $callback['filter'], $callback['args'] );
} catch ( Exception $e ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
trigger_error( 'Transactional email triggered fatal error for callback ' . esc_html( $callback['filter'] ), E_USER_WARNING );
trigger_error( 'Transactional email triggered fatal error for callback ' . esc_html( $callback['filter'] ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
}
}
}
@ -89,7 +87,7 @@ class WC_Background_Emailer extends WC_Background_Process {
if ( ! headers_sent() ) {
header( 'Connection: close' );
}
@ob_end_flush();
@ob_end_flush(); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
flush();
}
}
@ -117,7 +115,7 @@ class WC_Background_Emailer extends WC_Background_Process {
// Pass cookies through with the request so nonces function.
$cookies = array();
foreach ( $_COOKIE as $name => $value ) {
foreach ( $_COOKIE as $name => $value ) { // WPCS: input var ok.
if ( 'PHPSESSID' === $name ) {
continue;
}

View File

@ -2,13 +2,11 @@
/**
* Background Updater
*
* @version 2.6.0
* @package WooCommerce/Classes
* @version 2.6.0
* @package WooCommerce/Classes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'WC_Background_Process', false ) ) {
include_once dirname( __FILE__ ) . '/abstracts/class-wc-background-process.php';

View File

@ -1,17 +1,15 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Breadcrumb class.
*
* @class WC_Breadcrumb
* @version 2.3.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
* @package WooCommerce/Classes
* @version 2.3.0
*/
defined( 'ABSPATH' ) || exit;
/**
* Breadcrumb class.
*/
class WC_Breadcrumb {
@ -25,8 +23,8 @@ class WC_Breadcrumb {
/**
* Add a crumb so we don't get lost.
*
* @param string $name
* @param string $link
* @param string $name Name.
* @param string $link Link.
*/
public function add_crumb( $name, $link = '' ) {
$this->crumbs[] = array(
@ -99,14 +97,14 @@ class WC_Breadcrumb {
$shop_page_id = wc_get_page_id( 'shop' );
$shop_page = get_post( $shop_page_id );
// If permalinks contain the shop page in the URI prepend the breadcrumb with shop
if ( $shop_page_id && $shop_page && isset( $permalinks['product_base'] ) && strstr( $permalinks['product_base'], '/' . $shop_page->post_name ) && get_option( 'page_on_front' ) != $shop_page_id ) {
// If permalinks contain the shop page in the URI prepend the breadcrumb with shop.
if ( $shop_page_id && $shop_page && isset( $permalinks['product_base'] ) && strstr( $permalinks['product_base'], '/' . $shop_page->post_name ) && intval( get_option( 'page_on_front' ) ) !== $shop_page_id ) {
$this->add_crumb( get_the_title( $shop_page ), get_permalink( $shop_page ) );
}
}
/**
* is home trail.
* Is home trail..
*/
private function add_crumbs_home() {
$this->add_crumb( single_post_title( '', false ) );
@ -120,7 +118,7 @@ class WC_Breadcrumb {
}
/**
* attachment trail.
* Attachment trail.
*/
private function add_crumbs_attachment() {
global $post;
@ -132,23 +130,27 @@ class WC_Breadcrumb {
/**
* Single post trail.
*
* @param int $post_id
* @param string $permalink
* @param int $post_id Post ID.
* @param string $permalink Post permalink.
*/
private function add_crumbs_single( $post_id = 0, $permalink = '' ) {
if ( ! $post_id ) {
global $post;
} else {
$post = get_post( $post_id );
$post = get_post( $post_id ); // WPCS: override ok.
}
if ( 'product' === get_post_type( $post ) ) {
$this->prepend_shop_page();
$terms = wc_get_product_terms( $post->ID, 'product_cat', apply_filters( 'woocommerce_breadcrumb_product_terms_args', array(
'orderby' => 'parent',
'order' => 'DESC',
) ) );
$terms = wc_get_product_terms(
$post->ID, 'product_cat', apply_filters(
'woocommerce_breadcrumb_product_terms_args', array(
'orderby' => 'parent',
'order' => 'DESC',
)
)
);
if ( $terms ) {
$main_term = apply_filters( 'woocommerce_breadcrumb_main_term', $terms[0], $terms );
@ -183,8 +185,8 @@ class WC_Breadcrumb {
$parent_id = $post->post_parent;
while ( $parent_id ) {
$page = get_post( $parent_id );
$parent_id = $page->post_parent;
$page = get_post( $parent_id );
$parent_id = $page->post_parent;
$parent_crumbs[] = array( get_the_title( $page->ID ), get_permalink( $page->ID ) );
}
@ -217,6 +219,8 @@ class WC_Breadcrumb {
$current_term = $GLOBALS['wp_query']->get_queried_object();
$this->prepend_shop_page();
/* translators: %s: product tag */
$this->add_crumb( sprintf( __( 'Products tagged &ldquo;%s&rdquo;', 'woocommerce' ), $current_term->name ) );
}
@ -224,7 +228,7 @@ class WC_Breadcrumb {
* Shop breadcrumb.
*/
private function add_crumbs_shop() {
if ( get_option( 'page_on_front' ) == wc_get_page_id( 'shop' ) ) {
if ( intval( get_option( 'page_on_front' ) ) === wc_get_page_id( 'shop' ) ) {
return;
}
@ -232,7 +236,7 @@ class WC_Breadcrumb {
if ( ! $_name ) {
$product_post_type = get_post_type_object( 'product' );
$_name = $product_post_type->labels->singular_name;
$_name = $product_post_type->labels->singular_name;
}
$this->add_crumb( $_name, get_post_type_archive_link( 'product' ) );
@ -255,7 +259,7 @@ class WC_Breadcrumb {
private function add_crumbs_category() {
$this_category = get_category( $GLOBALS['wp_query']->get_queried_object() );
if ( 0 != $this_category->parent ) {
if ( 0 !== intval( $this_category->parent ) ) {
$this->term_ancestors( $this_category->term_id, 'category' );
}
@ -267,6 +271,8 @@ class WC_Breadcrumb {
*/
private function add_crumbs_tag() {
$queried_object = $GLOBALS['wp_query']->get_queried_object();
/* translators: %s: tag name */
$this->add_crumb( sprintf( __( 'Posts tagged &ldquo;%s&rdquo;', 'woocommerce' ), single_tag_title( '', false ) ), get_tag_link( $queried_object->term_id ) );
}
@ -294,7 +300,7 @@ class WC_Breadcrumb {
$this->add_crumb( $taxonomy->labels->name );
if ( 0 != $this_term->parent ) {
if ( 0 !== intval( $this_term->parent ) ) {
$this->term_ancestors( $this_term->term_id, $this_term->taxonomy );
}
@ -308,14 +314,16 @@ class WC_Breadcrumb {
global $author;
$userdata = get_userdata( $author );
/* translators: %s: author name */
$this->add_crumb( sprintf( __( 'Author: %s', 'woocommerce' ), $userdata->display_name ) );
}
/**
* Add crumbs for a term.
*
* @param int $term_id
* @param string $taxonomy
* @param int $term_id Term ID.
* @param string $taxonomy Taxonomy.
*/
private function term_ancestors( $term_id, $taxonomy ) {
$ancestors = get_ancestors( $term_id, $taxonomy );
@ -334,8 +342,10 @@ class WC_Breadcrumb {
* Endpoints.
*/
private function endpoint_trail() {
// Is an endpoint showing?
if ( is_wc_endpoint_url() && ( $endpoint = WC()->query->get_current_endpoint() ) && ( $endpoint_title = WC()->query->get_endpoint_title( $endpoint ) ) ) {
$endpoint = is_wc_endpoint_url() ? WC()->query->get_current_endpoint() : '';
$endpoint_title = $endpoint ? WC()->query->get_endpoint_title( $endpoint ) : '';
if ( $endpoint_title ) {
$this->add_crumb( $endpoint_title );
}
}
@ -345,6 +355,7 @@ class WC_Breadcrumb {
*/
private function search_trail() {
if ( is_search() ) {
/* translators: %s: search term */
$this->add_crumb( sprintf( __( 'Search results for &ldquo;%s&rdquo;', 'woocommerce' ), get_search_query() ), remove_query_arg( 'paged' ) );
}
}
@ -354,6 +365,7 @@ class WC_Breadcrumb {
*/
private function paged_trail() {
if ( get_query_var( 'paged' ) ) {
/* translators: %d: page number */
$this->add_crumb( sprintf( __( 'Page %d', 'woocommerce' ), get_query_var( 'paged' ) ) );
}
}

View File

@ -2,16 +2,10 @@
/**
* WC_Cache_Helper class.
*
* @class WC_Cache_Helper
* @version 2.2.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
* @package WooCommerce/Classes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
/**
* WC_Cache_Helper.
@ -26,6 +20,8 @@ class WC_Cache_Helper {
add_action( 'admin_notices', array( __CLASS__, 'notices' ) );
add_action( 'delete_version_transients', array( __CLASS__, 'delete_version_transients' ) );
add_action( 'wp', array( __CLASS__, 'prevent_caching' ) );
add_action( 'clean_term_cache', array( __CLASS__, 'clean_term_cache' ), 10, 2 );
add_action( 'edit_terms', array( __CLASS__, 'clean_term_cache' ), 10, 2 );
}
/**
@ -93,7 +89,7 @@ class WC_Cache_Helper {
public static function geolocation_ajax_redirect() {
if ( 'geolocation_ajax' === get_option( 'woocommerce_default_customer_address' ) && ! is_checkout() && ! is_cart() && ! is_account_page() && ! is_ajax() && empty( $_POST ) ) { // WPCS: CSRF ok, input var ok.
$location_hash = self::geolocation_ajax_get_location_hash();
$current_hash = isset( $_GET['v'] ) ? wc_clean( wp_unslash( $_GET['v'] ) ) : ''; // WPCS: sanitization ok, input var ok.
$current_hash = isset( $_GET['v'] ) ? wc_clean( wp_unslash( $_GET['v'] ) ) : ''; // WPCS: sanitization ok, input var ok, CSRF ok.
if ( empty( $current_hash ) || $current_hash !== $location_hash ) {
global $wp;
@ -141,7 +137,10 @@ class WC_Cache_Helper {
if ( false === $transient_value || true === $refresh ) {
self::delete_version_transients( $transient_value );
set_transient( $transient_name, $transient_value = time() );
$transient_value = time();
set_transient( $transient_name, $transient_value );
}
return $transient_value;
}
@ -196,11 +195,40 @@ class WC_Cache_Helper {
if ( $enabled && ! in_array( '_wc_session_', $settings, true ) ) {
?>
<div class="error">
<p><?php echo wp_kses_post( sprintf( __( 'In order for <strong>database caching</strong> to work with WooCommerce you must add %1$s to the "Ignored Query Strings" option in <a href="%2$s">W3 Total Cache settings</a>.', 'woocommerce' ), '<code>_wc_session_</code>', esc_url( admin_url( 'admin.php?page=w3tc_dbcache' ) ) ) ); ?></p>
<p>
<?php
/* translators: 1: key 2: URL */
echo wp_kses_post( sprintf( __( 'In order for <strong>database caching</strong> to work with WooCommerce you must add %1$s to the "Ignored Query Strings" option in <a href="%2$s">W3 Total Cache settings</a>.', 'woocommerce' ), '<code>_wc_session_</code>', esc_url( admin_url( 'admin.php?page=w3tc_dbcache' ) ) ) );
?>
</p>
</div>
<?php
}
}
/**
* Clean term caches added by WooCommerce.
*
* @since 3.3.4
* @param array|int $ids Array of ids or single ID to clear cache for.
* @param string $taxonomy Taxonomy name.
*/
public static function clean_term_cache( $ids, $taxonomy ) {
if ( 'product_cat' === $taxonomy ) {
$ids = is_array( $ids ) ? $ids : array( $ids );
foreach ( $ids as $id ) {
$clear_ids[] = $id;
$clear_ids = array_merge( $clear_ids, get_ancestors( $id, 'product_cat', 'taxonomy' ) );
}
$clear_ids = array_unique( $clear_ids );
foreach ( $clear_ids as $id ) {
wp_cache_delete( 'product-category-hierarchy-' . $id, 'product_cat' );
}
}
}
}
WC_Cache_Helper::init();

View File

@ -6,13 +6,11 @@
*
* We suggest using the action woocommerce_cart_calculate_fees hook for adding fees.
*
* @author Automattic
* @package WooCommerce/Classes
* @version 3.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
/**
* WC_Cart_Fees class.
@ -80,7 +78,7 @@ final class WC_Cart_Fees {
public function add_fee( $args = array() ) {
$fee_props = (object) wp_parse_args( $args, $this->default_fee_props );
$fee_props->name = $fee_props->name ? $fee_props->name : __( 'Fee', 'woocommerce' );
$fee_props->tax_class = in_array( $fee_props->tax_class, array_merge( WC_Tax::get_tax_classes(), WC_Tax::get_tax_class_slugs() ), true ) ? $fee_props->tax_class: '';
$fee_props->tax_class = in_array( $fee_props->tax_class, array_merge( WC_Tax::get_tax_classes(), WC_Tax::get_tax_class_slugs() ), true ) ? $fee_props->tax_class : '';
$fee_props->taxable = wc_string_to_bool( $fee_props->taxable );
$fee_props->amount = wc_format_decimal( $fee_props->amount );
@ -92,7 +90,9 @@ final class WC_Cart_Fees {
return new WP_Error( 'fee_exists', __( 'Fee has already been added.', 'woocommerce' ) );
}
return $this->fees[ $fee_props->id ] = $fee_props;
$this->fees[ $fee_props->id ] = $fee_props;
return $this->fees[ $fee_props->id ];
}
/**

View File

@ -2,8 +2,8 @@
/**
* Cart session handling class.
*
* @author Automattic
* @package WooCommerce/Classes
* @version 3.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -105,7 +105,7 @@ final class WC_Cart_Session {
wc_add_notice( sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce' ), $product->get_name() ), 'error' );
do_action( 'woocommerce_remove_cart_item_from_session', $key, $values );
} elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) {
} elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound
$update_cart_session = true;
/* translators: %1$s: product name. %2$s product permalink */
wc_add_notice( sprintf( __( '%1$s has been removed from your cart because it has since been modified. You can add it back to your cart <a href="%2$s">here</a>.', 'woocommerce' ), $product->get_name(), $product->get_permalink() ), 'notice' );
@ -113,9 +113,11 @@ final class WC_Cart_Session {
} else {
// Put session data into array. Run through filter so other plugins can load their own session data.
$session_data = array_merge( $values, array(
'data' => $product,
) );
$session_data = array_merge(
$values, array(
'data' => $product,
)
);
$cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key );
// Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook.
@ -157,7 +159,7 @@ final class WC_Cart_Session {
if ( ! headers_sent() && did_action( 'wp_loaded' ) ) {
if ( ! $this->cart->is_empty() ) {
$this->set_cart_cookies( true );
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) {
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) { // WPCS: input var ok.
$this->set_cart_cookies( false );
}
}
@ -198,9 +200,11 @@ final class WC_Cart_Session {
*/
public function persistent_cart_update() {
if ( get_current_user_id() && apply_filters( 'woocommerce_persistent_cart_enabled', true ) ) {
update_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), array(
'cart' => $this->get_cart_for_session(),
) );
update_user_meta(
get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), array(
'cart' => $this->get_cart_for_session(),
)
);
}
}
@ -223,7 +227,7 @@ final class WC_Cart_Session {
if ( $set ) {
wc_setcookie( 'woocommerce_items_in_cart', 1 );
wc_setcookie( 'woocommerce_cart_hash', md5( wp_json_encode( $this->get_cart_for_session() ) ) );
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) {
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) { // WPCS: input var ok.
wc_setcookie( 'woocommerce_items_in_cart', 0, time() - HOUR_IN_SECONDS );
wc_setcookie( 'woocommerce_cart_hash', '', time() - HOUR_IN_SECONDS );
}

View File

@ -9,8 +9,8 @@
* - if something is being stored e.g. item total, store unrounded. This is so taxes can be recalculated later accurately.
* - if calculating a total, round (if settings allow).
*
* @author Automattic
* @package WooCommerce/Classes
* @version 3.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -102,16 +102,16 @@ final class WC_Cart_Totals {
* @var array
*/
protected $totals = array(
'fees_total' => 0,
'fees_total_tax' => 0,
'items_subtotal' => 0,
'items_subtotal_tax' => 0,
'items_total' => 0,
'items_total_tax' => 0,
'total' => 0,
'shipping_total' => 0,
'shipping_tax_total' => 0,
'discounts_total' => 0,
'fees_total' => 0,
'fees_total_tax' => 0,
'items_subtotal' => 0,
'items_subtotal_tax' => 0,
'items_total' => 0,
'items_total_tax' => 0,
'total' => 0,
'shipping_total' => 0,
'shipping_tax_total' => 0,
'discounts_total' => 0,
);
/**
@ -212,7 +212,7 @@ final class WC_Cart_Totals {
* into the same format for use by this class.
*
* Each item is made up of the following props, in addition to those returned by get_default_item_props() for totals.
* - key: An identifier for the item (cart item key or line item ID).
* - key: An identifier for the item (cart item key or line item ID).
* - cart_item: For carts, the cart item from the cart which may include custom data.
* - quantity: The qty for this line.
* - price: The line price in cents.
@ -312,13 +312,12 @@ final class WC_Cart_Totals {
$fee->taxes = wc_array_merge_recursive_numeric( $fee->taxes, WC_Tax::calc_tax( $fee->total * $proportion, WC_Tax::get_rates( $tax_class ) ) );
}
}
} elseif ( $fee->object->taxable ) {
$fee->taxes = WC_Tax::calc_tax( $fee->total, WC_Tax::get_rates( $fee->tax_class, $this->cart->get_customer() ), false );
}
}
$fee->taxes = apply_filters( 'woocommerce_cart_totals_get_fees_from_cart_taxes', $fee->taxes, $fee, $this );
$fee->taxes = apply_filters( 'woocommerce_cart_totals_get_fees_from_cart_taxes', $fee->taxes, $fee, $this );
$fee->total_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $fee->taxes ) );
// Set totals within object.
@ -366,13 +365,13 @@ final class WC_Cart_Totals {
foreach ( $this->coupons as $coupon ) {
switch ( $coupon->get_discount_type() ) {
case 'fixed_product' :
case 'fixed_product':
$coupon->sort = 1;
break;
case 'percent' :
case 'percent':
$coupon->sort = 2;
break;
case 'fixed_cart' :
case 'fixed_cart':
$coupon->sort = 3;
break;
default:
@ -391,7 +390,7 @@ final class WC_Cart_Totals {
* Sort coupons so discounts apply consistently across installs.
*
* In order of priority;
* - sort param
* - sort param
* - usage restriction
* - coupon value
* - ID
@ -422,10 +421,10 @@ final class WC_Cart_Totals {
*/
protected function remove_item_base_taxes( $item ) {
if ( $item->price_includes_tax && $item->taxable ) {
$base_tax_rates = WC_Tax::get_base_tax_rates( $item->product->get_tax_class( 'unfiltered' ) );
$base_tax_rates = WC_Tax::get_base_tax_rates( $item->product->get_tax_class( 'unfiltered' ) );
// Work out a new base price without the shop's base tax.
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
// Now we have a new item price (excluding TAX).
$item->price = round( $item->price - array_sum( $taxes ) );
@ -452,11 +451,11 @@ final class WC_Cart_Totals {
if ( $item->tax_rates !== $base_tax_rates ) {
// Work out a new base price without the shop's base tax.
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
$new_taxes = WC_Tax::calc_tax( $item->price - array_sum( $taxes ), $item->tax_rates, false );
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
$new_taxes = WC_Tax::calc_tax( $item->price - array_sum( $taxes ), $item->tax_rates, false );
// Now we have a new item price.
$item->price = $item->price - array_sum( $taxes ) + array_sum( $new_taxes );
$item->price = round( $item->price - array_sum( $taxes ) + array_sum( $new_taxes ) );
}
}
return $item;
@ -551,7 +550,8 @@ final class WC_Cart_Totals {
* Get taxes merged by type.
*
* @since 3.2.0
* @param array|string $types Types to merge and return. Defaults to all.
* @param bool $in_cents If returned value should be in cents.
* @param array|string $types Types to merge and return. Defaults to all.
* @return array
*/
protected function get_merged_taxes( $in_cents = false, $types = array( 'items', 'fees', 'shipping' ) ) {
@ -584,7 +584,7 @@ final class WC_Cart_Totals {
* Combine item taxes into a single array, preserving keys.
*
* @since 3.2.0
* @param array $taxes Taxes to combine.
* @param array $item_taxes Taxes to combine.
* @return array
*/
protected function combine_item_taxes( $item_taxes ) {

View File

@ -5,18 +5,14 @@
* The WooCommerce cart class stores cart data and active coupons as well as handling customer sessions and some cart related urls.
* The cart class also has a price calculation function which calls upon other classes to calculate totals.
*
* @version 2.1.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
* @package WooCommerce/Classes
* @version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
include_once( WC_ABSPATH . 'includes/legacy/class-wc-legacy-cart.php' );
include_once( WC_ABSPATH . 'includes/class-wc-cart-session.php' );
require_once WC_ABSPATH . 'includes/legacy/class-wc-legacy-cart.php';
require_once WC_ABSPATH . 'includes/class-wc-cart-session.php';
/**
* WC_Cart class.
@ -796,7 +792,8 @@ class WC_Cart extends WC_Legacy_Cart {
if ( get_option( 'woocommerce_hold_stock_minutes' ) > 0 && ! $product->backorders_allowed() ) {
$order_id = isset( WC()->session->order_awaiting_payment ) ? absint( WC()->session->order_awaiting_payment ) : 0;
$held_stock = $wpdb->get_var(
$wpdb->prepare( "
$wpdb->prepare(
"
SELECT SUM( order_item_meta.meta_value ) AS held_qty
FROM {$wpdb->posts} AS posts
LEFT JOIN {$wpdb->prefix}woocommerce_order_items as order_items ON posts.ID = order_items.order_id
@ -811,7 +808,7 @@ class WC_Cart extends WC_Legacy_Cart {
$product->get_stock_managed_by_id(),
$order_id
)
);
); // WPCS: unprepared SQL ok.
if ( $product->get_stock_quantity() < ( $held_stock + $product_qty_in_cart[ $product->get_stock_managed_by_id() ] ) ) {
/* translators: 1: product name 2: minutes */
@ -893,16 +890,16 @@ class WC_Cart extends WC_Legacy_Cart {
foreach ( $taxes as $key => $tax ) {
$code = WC_Tax::get_rate_code( $key );
if ( $code || $key === apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) ) {
if ( $code || apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) === $key ) {
if ( ! isset( $tax_totals[ $code ] ) ) {
$tax_totals[ $code ] = new stdClass();
$tax_totals[ $code ] = new stdClass();
$tax_totals[ $code ]->amount = 0;
}
$tax_totals[ $code ]->tax_rate_id = $key;
$tax_totals[ $code ]->is_compound = WC_Tax::is_compound( $key );
$tax_totals[ $code ]->label = WC_Tax::get_rate_label( $key );
$tax_totals[ $code ]->amount += wc_round_tax_total( $tax );
$tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ) );
$tax_totals[ $code ]->tax_rate_id = $key;
$tax_totals[ $code ]->is_compound = WC_Tax::is_compound( $key );
$tax_totals[ $code ]->label = WC_Tax::get_rate_label( $key );
$tax_totals[ $code ]->amount += wc_round_tax_total( $tax );
$tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ) );
}
}
@ -1055,10 +1052,10 @@ class WC_Cart extends WC_Legacy_Cart {
$cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', $cart_item_data, $product_id, $variation_id, $quantity );
// Generate a ID based on product ID, variation ID, variation data, and other cart item data.
$cart_id = $this->generate_cart_id( $product_id, $variation_id, $variation, $cart_item_data );
$cart_id = $this->generate_cart_id( $product_id, $variation_id, $variation, $cart_item_data );
// Find the cart item key in the existing cart.
$cart_item_key = $this->find_product_in_cart( $cart_id );
$cart_item_key = $this->find_product_in_cart( $cart_id );
// Force quantity to 1 if sold individually and check for existing item in cart.
if ( $product_data->is_sold_individually() ) {
@ -1077,6 +1074,7 @@ class WC_Cart extends WC_Legacy_Cart {
// Stock check - only check if we're managing stock and backorders are not allowed.
if ( ! $product_data->is_in_stock() ) {
/* translators: %s: product name */
throw new Exception( sprintf( __( 'You cannot add &quot;%s&quot; to the cart because the product is out of stock.', 'woocommerce' ), $product_data->get_name() ) );
}
@ -1090,12 +1088,15 @@ class WC_Cart extends WC_Legacy_Cart {
$products_qty_in_cart = $this->get_cart_item_quantities();
if ( isset( $products_qty_in_cart[ $product_data->get_stock_managed_by_id() ] ) && ! $product_data->has_enough_stock( $products_qty_in_cart[ $product_data->get_stock_managed_by_id() ] + $quantity ) ) {
throw new Exception( sprintf(
'<a href="%s" class="button wc-forward">%s</a> %s',
wc_get_cart_url(),
__( 'View Cart', 'woocommerce' ),
sprintf( __( 'You cannot add that amount to the cart &mdash; we have %1$s in stock and you already have %2$s in your cart.', 'woocommerce' ), wc_format_stock_quantity_for_display( $product_data->get_stock_quantity(), $product_data ), wc_format_stock_quantity_for_display( $products_qty_in_cart[ $product_data->get_stock_managed_by_id() ], $product_data ) )
) );
throw new Exception(
sprintf(
'<a href="%s" class="button wc-forward">%s</a> %s',
wc_get_cart_url(),
__( 'View Cart', 'woocommerce' ),
/* translators: 1: quantity in stock 2: current quantity */
sprintf( __( 'You cannot add that amount to the cart &mdash; we have %1$s in stock and you already have %2$s in your cart.', 'woocommerce' ), wc_format_stock_quantity_for_display( $product_data->get_stock_quantity(), $product_data ), wc_format_stock_quantity_for_display( $products_qty_in_cart[ $product_data->get_stock_managed_by_id() ], $product_data ) )
)
);
}
}
@ -1107,15 +1108,19 @@ class WC_Cart extends WC_Legacy_Cart {
$cart_item_key = $cart_id;
// Add item after merging with $cart_item_data - hook to allow plugins to modify cart item.
$this->cart_contents[ $cart_item_key ] = apply_filters( 'woocommerce_add_cart_item', array_merge( $cart_item_data, array(
'key' => $cart_item_key,
'product_id' => $product_id,
'variation_id' => $variation_id,
'variation' => $variation,
'quantity' => $quantity,
'data' => $product_data,
'data_hash' => wc_get_cart_item_data_hash( $product_data ),
) ), $cart_item_key );
$this->cart_contents[ $cart_item_key ] = apply_filters(
'woocommerce_add_cart_item', array_merge(
$cart_item_data, array(
'key' => $cart_item_key,
'product_id' => $product_id,
'variation_id' => $variation_id,
'variation' => $variation,
'quantity' => $quantity,
'data' => $product_data,
'data_hash' => wc_get_cart_item_data_hash( $product_data ),
)
), $cart_item_key
);
}
do_action( 'woocommerce_add_to_cart', $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data );
@ -1180,7 +1185,7 @@ class WC_Cart extends WC_Legacy_Cart {
/**
* Set the quantity for an item in the cart.
*
* @param string $cart_item_key contains the id of the cart item.
* @param string $cart_item_key contains the id of the cart item.
* @param int $quantity contains the quantity of the item.
* @param bool $refresh_totals whether or not to calculate totals after setting the new qty.
* @return bool
@ -1190,7 +1195,7 @@ class WC_Cart extends WC_Legacy_Cart {
do_action( 'woocommerce_before_cart_item_quantity_zero', $cart_item_key, $this );
unset( $this->cart_contents[ $cart_item_key ] );
} else {
$old_quantity = $this->cart_contents[ $cart_item_key ]['quantity'];
$old_quantity = $this->cart_contents[ $cart_item_key ]['quantity'];
$this->cart_contents[ $cart_item_key ]['quantity'] = $quantity;
do_action( 'woocommerce_after_cart_item_quantity_update', $cart_item_key, $quantity, $old_quantity, $this );
}
@ -1252,7 +1257,7 @@ class WC_Cart extends WC_Legacy_Cart {
$this->shipping_methods = $this->needs_shipping() ? $this->get_chosen_shipping_methods( WC()->shipping->calculate_shipping( $this->get_shipping_packages() ) ) : array();
$shipping_taxes = wp_list_pluck( $this->shipping_methods, 'taxes' );
$merged_taxes = array();
$merged_taxes = array();
foreach ( $shipping_taxes as $taxes ) {
foreach ( $taxes as $tax_id => $tax_amount ) {
if ( ! isset( $merged_taxes[ $tax_id ] ) ) {
@ -1280,7 +1285,7 @@ class WC_Cart extends WC_Legacy_Cart {
$chosen_methods = array();
// Get chosen methods for each package to get our totals.
foreach ( $calculated_shipping_packages as $key => $package ) {
$chosen_method = wc_get_chosen_shipping_method_for_package( $key, $package );
$chosen_method = wc_get_chosen_shipping_method_for_package( $key, $package );
if ( $chosen_method ) {
$chosen_methods[ $key ] = $package['rates'][ $chosen_method ];
}
@ -1324,7 +1329,8 @@ class WC_Cart extends WC_Legacy_Cart {
* @return array of cart items
*/
public function get_shipping_packages() {
return apply_filters( 'woocommerce_cart_shipping_packages',
return apply_filters(
'woocommerce_cart_shipping_packages',
array(
array(
'contents' => $this->get_items_needing_shipping(),
@ -1341,7 +1347,7 @@ class WC_Cart extends WC_Legacy_Cart {
'address' => $this->get_customer()->get_shipping_address(),
'address_2' => $this->get_customer()->get_shipping_address_2(),
),
'cart_subtotal' => $this->get_displayed_subtotal(),
'cart_subtotal' => $this->get_displayed_subtotal(),
),
)
);
@ -1445,10 +1451,18 @@ class WC_Cart extends WC_Legacy_Cart {
// Get user and posted emails to compare.
$current_user = wp_get_current_user();
$check_emails = array_unique( array_filter( array_map( 'strtolower', array_map( 'sanitize_email', array(
$posted['billing_email'],
$current_user->user_email,
) ) ) ) );
$check_emails = array_unique(
array_filter(
array_map(
'strtolower', array_map(
'sanitize_email', array(
$posted['billing_email'],
$current_user->user_email,
)
)
)
)
);
// Limit to defined email addresses.
$restrictions = $coupon->get_email_restrictions();
@ -1474,21 +1488,23 @@ class WC_Cart extends WC_Legacy_Cart {
}
// Check against billing emails of existing users.
$users_query = new WP_User_Query( array(
'fields' => 'ID',
'meta_query' => array(
array(
'key' => '_billing_email',
'value' => $check_emails,
'compare' => 'IN',
$users_query = new WP_User_Query(
array(
'fields' => 'ID',
'meta_query' => array(
array(
'key' => '_billing_email',
'value' => $check_emails,
'compare' => 'IN',
),
),
),
) );
)
); // WPCS: slow query ok.
$user_id_matches = array_unique( array_filter( array_merge( $user_id_matches, $users_query->get_results() ) ) );
foreach ( $user_id_matches as $user_id ) {
$usage_count += count( array_keys( $used_by, $user_id ) );
$usage_count += count( array_keys( $used_by, (string) $user_id, true ) );
}
if ( $usage_count >= $coupon->get_usage_limit_per_user() ) {
@ -1511,7 +1527,7 @@ class WC_Cart extends WC_Legacy_Cart {
foreach ( $check_emails as $check_email ) {
// With a direct match we return true.
if ( in_array( $check_email, $restrictions ) ) {
if ( in_array( $check_email, $restrictions, true ) ) {
return true;
}
@ -1545,7 +1561,7 @@ class WC_Cart extends WC_Legacy_Cart {
* Applies a coupon code passed to the method.
*
* @param string $coupon_code - The code to apply.
* @return bool True if the coupon is applied, false if it does not exist or cannot be applied.
* @return bool True if the coupon is applied, false if it does not exist or cannot be applied.
*/
public function apply_coupon( $coupon_code ) {
// Coupons are globally disabled.
@ -1615,7 +1631,7 @@ class WC_Cart extends WC_Legacy_Cart {
// Choose free shipping.
if ( $the_coupon->get_free_shipping() ) {
$packages = WC()->shipping->get_packages();
$packages = WC()->shipping->get_packages();
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
foreach ( $packages as $i => $package ) {
@ -1646,7 +1662,7 @@ class WC_Cart extends WC_Legacy_Cart {
}
foreach ( $this->get_applied_coupons() as $code ) {
$coupon = new WC_Coupon( $code );
$coupon = new WC_Coupon( $code );
$coupons[ $code ] = $coupon;
}
@ -1662,7 +1678,7 @@ class WC_Cart extends WC_Legacy_Cart {
*/
public function get_coupon_discount_amount( $code, $ex_tax = true ) {
$totals = $this->get_coupon_discount_totals();
$discount_amount = isset( $totals[ $code ] ) ? $totals[ $code ]: 0;
$discount_amount = isset( $totals[ $code ] ) ? $totals[ $code ] : 0;
if ( ! $ex_tax ) {
$discount_amount += $this->get_coupon_discount_tax_amount( $code );
@ -1701,8 +1717,8 @@ class WC_Cart extends WC_Legacy_Cart {
* @return bool
*/
public function remove_coupon( $coupon_code ) {
$coupon_code = wc_format_coupon_code( $coupon_code );
$position = array_search( $coupon_code, $this->get_applied_coupons(), true );
$coupon_code = wc_format_coupon_code( $coupon_code );
$position = array_search( $coupon_code, $this->get_applied_coupons(), true );
if ( false !== $position ) {
unset( $this->applied_coupons[ $position ] );
@ -1748,12 +1764,14 @@ class WC_Cart extends WC_Legacy_Cart {
* @param string $tax_class The tax class for the fee if taxable. A blank string is standard tax class. (default: '').
*/
public function add_fee( $name, $amount, $taxable = false, $tax_class = '' ) {
$this->fees_api()->add_fee( array(
'name' => $name,
'amount' => (float) $amount,
'taxable' => $taxable,
'tax_class' => $tax_class,
) );
$this->fees_api()->add_fee(
array(
'name' => $name,
'amount' => (float) $amount,
'taxable' => $taxable,
'tax_class' => $tax_class,
)
);
}
/**

View File

@ -1,18 +1,17 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Main checkout class.
* Checkout functionality
*
* The WooCommerce checkout class handles the checkout process, collecting user data and processing the payment.
*
* @class WC_Checkout
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
* @package WooCommerce/Classes
* @version 3.4.0
*/
defined( 'ABSPATH' ) || exit;
/**
* Checkout class.
*/
class WC_Checkout {
@ -32,6 +31,7 @@ class WC_Checkout {
/**
* Holds posted data for backwards compatibility.
*
* @var array
*/
protected $legacy_posted_data = array();
@ -60,32 +60,36 @@ class WC_Checkout {
/**
* See if variable is set. Used to support legacy public variables which are no longer defined.
*
* @param string $key
* @param string $key Key.
* @return bool
*/
public function __isset( $key ) {
return in_array( $key, array(
'enable_signup',
'enable_guest_checkout',
'must_create_account',
'checkout_fields',
'posted',
'shipping_method',
'payment_method',
'customer_id',
'shipping_methods',
) );
return in_array(
$key,
array(
'enable_signup',
'enable_guest_checkout',
'must_create_account',
'checkout_fields',
'posted',
'shipping_method',
'payment_method',
'customer_id',
'shipping_methods',
),
true
);
}
/**
* Sets the legacy public variables for backwards compatibility.
*
* @param string $key
* @param mixed $value
* @param string $key Key.
* @param mixed $value Value.
*/
public function __set( $key, $value ) {
switch ( $key ) {
case 'enable_signup' :
case 'enable_signup':
$bool_value = wc_string_to_bool( $value );
if ( $bool_value !== $this->is_registration_enabled() ) {
@ -94,7 +98,7 @@ class WC_Checkout {
add_filter( 'woocommerce_checkout_registration_enabled', $bool_value ? '__return_true' : '__return_false', 0 );
}
break;
case 'enable_guest_checkout' :
case 'enable_guest_checkout':
$bool_value = wc_string_to_bool( $value );
if ( $bool_value === $this->is_registration_required() ) {
@ -103,13 +107,13 @@ class WC_Checkout {
add_filter( 'woocommerce_checkout_registration_required', $bool_value ? '__return_false' : '__return_true', 0 );
}
break;
case 'checkout_fields' :
case 'checkout_fields':
$this->fields = $value;
break;
case 'shipping_methods' :
case 'shipping_methods':
WC()->session->set( 'chosen_shipping_methods', $value );
break;
case 'posted' :
case 'posted':
$this->legacy_posted_data = $value;
break;
}
@ -118,33 +122,32 @@ class WC_Checkout {
/**
* Gets the legacy public variables for backwards compatibility.
*
* @param string $key
*
* @param string $key Key.
* @return array|string
*/
public function __get( $key ) {
if ( in_array( $key, array( 'posted', 'shipping_method', 'payment_method' ) ) && empty( $this->legacy_posted_data ) ) {
if ( in_array( $key, array( 'posted', 'shipping_method', 'payment_method' ), true ) && empty( $this->legacy_posted_data ) ) {
$this->legacy_posted_data = $this->get_posted_data();
}
switch ( $key ) {
case 'enable_signup' :
case 'enable_signup':
return $this->is_registration_enabled();
case 'enable_guest_checkout' :
case 'enable_guest_checkout':
return ! $this->is_registration_required();
case 'must_create_account' :
case 'must_create_account':
return $this->is_registration_required() && ! is_user_logged_in();
case 'checkout_fields' :
case 'checkout_fields':
return $this->get_checkout_fields();
case 'posted' :
case 'posted':
wc_doing_it_wrong( 'WC_Checkout->posted', 'Use $_POST directly.', '3.0.0' );
return $this->legacy_posted_data;
case 'shipping_method' :
case 'shipping_method':
return $this->legacy_posted_data['shipping_method'];
case 'payment_method' :
case 'payment_method':
return $this->legacy_posted_data['payment_method'];
case 'customer_id' :
case 'customer_id':
return apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() );
case 'shipping_methods' :
case 'shipping_methods':
return (array) WC()->session->get( 'chosen_shipping_methods' );
}
}
@ -206,19 +209,19 @@ class WC_Checkout {
);
if ( 'no' === get_option( 'woocommerce_registration_generate_username' ) ) {
$this->fields['account']['account_username'] = array(
'type' => 'text',
'label' => __( 'Account username', 'woocommerce' ),
'required' => true,
'placeholder' => esc_attr__( 'Username', 'woocommerce' ),
'type' => 'text',
'label' => __( 'Account username', 'woocommerce' ),
'required' => true,
'placeholder' => esc_attr__( 'Username', 'woocommerce' ),
);
}
if ( 'no' === get_option( 'woocommerce_registration_generate_password' ) ) {
$this->fields['account']['account_password'] = array(
'type' => 'password',
'label' => __( 'Create account password', 'woocommerce' ),
'required' => true,
'placeholder' => esc_attr__( 'Password', 'woocommerce' ),
'type' => 'password',
'label' => __( 'Create account password', 'woocommerce' ),
'required' => true,
'placeholder' => esc_attr__( 'Password', 'woocommerce' ),
);
}
@ -254,29 +257,31 @@ class WC_Checkout {
/**
* Create an order. Error codes:
* 520 - Cannot insert order into the database.
* 521 - Cannot get order after creation.
* 522 - Cannot update order.
* 525 - Cannot create line item.
* 526 - Cannot create fee item.
* 527 - Cannot create shipping item.
* 528 - Cannot create tax item.
* 529 - Cannot create coupon item.
* 520 - Cannot insert order into the database.
* 521 - Cannot get order after creation.
* 522 - Cannot update order.
* 525 - Cannot create line item.
* 526 - Cannot create fee item.
* 527 - Cannot create shipping item.
* 528 - Cannot create tax item.
* 529 - Cannot create coupon item.
*
* @throws Exception
* @param $data Posted data.
* @throws Exception When checkout validation fails.
* @param array $data Posted data.
* @return int|WP_ERROR
*/
public function create_order( $data ) {
// Give plugins the opportunity to create an order themselves.
if ( $order_id = apply_filters( 'woocommerce_create_order', null, $this ) ) {
$order_id = apply_filters( 'woocommerce_create_order', null, $this );
if ( $order_id ) {
return $order_id;
}
try {
$order_id = absint( WC()->session->get( 'order_awaiting_payment' ) );
$cart_hash = md5( json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total );
$cart_hash = md5( wp_json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total );
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
$order = $order_id ? wc_get_order( $order_id ) : null;
/**
* If there is an order pending payment, we can resume it here so
@ -284,7 +289,7 @@ class WC_Checkout {
* different items or cost, create a new order. We use a hash to
* detect changes which is based on cart items + order total.
*/
if ( $order_id && ( $order = wc_get_order( $order_id ) ) && $order->has_cart_hash( $cart_hash ) && $order->has_status( array( 'pending', 'failed' ) ) ) {
if ( $order && $order->has_cart_hash( $cart_hash ) && $order->has_status( array( 'pending', 'failed' ) ) ) {
// Action for 3rd parties.
do_action( 'woocommerce_resume_order', $order_id );
@ -298,10 +303,10 @@ class WC_Checkout {
if ( is_callable( array( $order, "set_{$key}" ) ) ) {
$order->{"set_{$key}"}( $value );
// Store custom fields prefixed with wither shipping_ or billing_. This is for backwards compatibility with 2.6.x.
// TODO: Fix conditional to only include shipping/billing address fields in a smarter way without str(i)pos.
// Store custom fields prefixed with wither shipping_ or billing_. This is for backwards compatibility with 2.6.x.
// TODO: Fix conditional to only include shipping/billing address fields in a smarter way without str(i)pos.
} elseif ( ( 0 === stripos( $key, 'billing_' ) || 0 === stripos( $key, 'shipping_' ) )
&& ! in_array( $key, array( 'shipping_method', 'shipping_total', 'shipping_tax' ) ) ) {
&& ! in_array( $key, array( 'shipping_method', 'shipping_total', 'shipping_tax' ), true ) ) {
$order->update_meta_data( '_' . $key, $value );
}
}
@ -314,7 +319,7 @@ class WC_Checkout {
$order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
$order->set_customer_user_agent( wc_get_user_agent() );
$order->set_customer_note( isset( $data['order_comments'] ) ? $data['order_comments'] : '' );
$order->set_payment_method( isset( $available_gateways[ $data['payment_method'] ] ) ? $available_gateways[ $data['payment_method'] ] : $data['payment_method'] );
$order->set_payment_method( isset( $available_gateways[ $data['payment_method'] ] ) ? $available_gateways[ $data['payment_method'] ] : $data['payment_method'] );
$order->set_shipping_total( WC()->cart->get_shipping_total() );
$order->set_discount_total( WC()->cart->get_discount_total() );
$order->set_discount_tax( WC()->cart->get_discount_tax() );
@ -329,6 +334,7 @@ class WC_Checkout {
/**
* Action hook to adjust order before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order', $order, $data );
@ -347,40 +353,46 @@ class WC_Checkout {
/**
* Add line items to the order.
*
* @param WC_Order $order
* @param WC_Cart $cart
* @param WC_Order $order Order instance.
* @param WC_Cart $cart Cart instance.
*/
public function create_order_line_items( &$order, $cart ) {
foreach ( $cart->get_cart() as $cart_item_key => $values ) {
/**
* Filter hook to get initial item object.
*
* @since 3.1.0
*/
$item = apply_filters( 'woocommerce_checkout_create_order_line_item_object', new WC_Order_Item_Product(), $cart_item_key, $values, $order );
$product = $values['data'];
$item->legacy_values = $values; // @deprecated For legacy actions.
$item->legacy_cart_item_key = $cart_item_key; // @deprecated For legacy actions.
$item->set_props( array(
'quantity' => $values['quantity'],
'variation' => $values['variation'],
'subtotal' => $values['line_subtotal'],
'total' => $values['line_total'],
'subtotal_tax' => $values['line_subtotal_tax'],
'total_tax' => $values['line_tax'],
'taxes' => $values['line_tax_data'],
) );
$item->set_props(
array(
'quantity' => $values['quantity'],
'variation' => $values['variation'],
'subtotal' => $values['line_subtotal'],
'total' => $values['line_total'],
'subtotal_tax' => $values['line_subtotal_tax'],
'total_tax' => $values['line_tax'],
'taxes' => $values['line_tax_data'],
)
);
if ( $product ) {
$item->set_props( array(
'name' => $product->get_name(),
'tax_class' => $product->get_tax_class(),
'product_id' => $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(),
'variation_id' => $product->is_type( 'variation' ) ? $product->get_id() : 0,
) );
$item->set_props(
array(
'name' => $product->get_name(),
'tax_class' => $product->get_tax_class(),
'product_id' => $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(),
'variation_id' => $product->is_type( 'variation' ) ? $product->get_id() : 0,
)
);
}
$item->set_backorder_meta();
/**
* Action hook to adjust item before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order_line_item', $item, $cart_item_key, $values, $order );
@ -393,27 +405,30 @@ class WC_Checkout {
/**
* Add fees to the order.
*
* @param WC_Order $order
* @param WC_Cart $cart
* @param WC_Order $order Order instance.
* @param WC_Cart $cart Cart instance.
*/
public function create_order_fee_lines( &$order, $cart ) {
foreach ( $cart->get_fees() as $fee_key => $fee ) {
$item = new WC_Order_Item_Fee();
$item->legacy_fee = $fee; // @deprecated For legacy actions.
$item->legacy_fee_key = $fee_key; // @deprecated For legacy actions.
$item->set_props( array(
'name' => $fee->name,
'tax_class' => $fee->taxable ? $fee->tax_class: 0,
'amount' => $fee->amount,
'total' => $fee->total,
'total_tax' => $fee->tax,
'taxes' => array(
'total' => $fee->tax_data,
),
) );
$item->set_props(
array(
'name' => $fee->name,
'tax_class' => $fee->taxable ? $fee->tax_class : 0,
'amount' => $fee->amount,
'total' => $fee->total,
'total_tax' => $fee->tax,
'taxes' => array(
'total' => $fee->tax_data,
),
)
);
/**
* Action hook to adjust item before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order_fee_item', $item, $fee_key, $fee, $order );
@ -426,26 +441,27 @@ class WC_Checkout {
/**
* Add shipping lines to the order.
*
* @param WC_Order $order
* @param array $chosen_shipping_methods
* @param array $packages
* @param WC_Order $order Order Instance.
* @param array $chosen_shipping_methods Chosen shipping methods.
* @param array $packages Packages.
*/
public function create_order_shipping_lines( &$order, $chosen_shipping_methods, $packages ) {
foreach ( $packages as $package_key => $package ) {
if ( isset( $chosen_shipping_methods[ $package_key ], $package['rates'][ $chosen_shipping_methods[ $package_key ] ] ) ) {
/** @var WC_Shipping_Rate $shipping_rate */
$shipping_rate = $package['rates'][ $chosen_shipping_methods[ $package_key ] ];
$item = new WC_Order_Item_Shipping();
$item->legacy_package_key = $package_key; // @deprecated For legacy actions.
$item->set_props( array(
'method_title' => $shipping_rate->label,
'method_id' => $shipping_rate->method_id,
'instance_id' => $shipping_rate->instance_id,
'total' => wc_format_decimal( $shipping_rate->cost ),
'taxes' => array(
'total' => $shipping_rate->taxes,
),
) );
$item->set_props(
array(
'method_title' => $shipping_rate->label,
'method_id' => $shipping_rate->method_id,
'instance_id' => $shipping_rate->instance_id,
'total' => wc_format_decimal( $shipping_rate->cost ),
'taxes' => array(
'total' => $shipping_rate->taxes,
),
)
);
foreach ( $shipping_rate->get_meta_data() as $key => $value ) {
$item->add_meta_data( $key, $value, true );
@ -453,6 +469,7 @@ class WC_Checkout {
/**
* Action hook to adjust item before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order_shipping_item', $item, $package_key, $package, $order );
@ -466,24 +483,27 @@ class WC_Checkout {
/**
* Add tax lines to the order.
*
* @param WC_Order $order
* @param WC_Cart $cart
* @param WC_Order $order Order instance.
* @param WC_Cart $cart Cart instance.
*/
public function create_order_tax_lines( &$order, $cart ) {
foreach ( array_keys( $cart->get_cart_contents_taxes() + $cart->get_shipping_taxes() + $cart->get_fee_taxes() ) as $tax_rate_id ) {
if ( $tax_rate_id && apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) !== $tax_rate_id ) {
$item = new WC_Order_Item_Tax();
$item->set_props( array(
'rate_id' => $tax_rate_id,
'tax_total' => $cart->get_tax_amount( $tax_rate_id ),
'shipping_tax_total' => $cart->get_shipping_tax_amount( $tax_rate_id ),
'rate_code' => WC_Tax::get_rate_code( $tax_rate_id ),
'label' => WC_Tax::get_rate_label( $tax_rate_id ),
'compound' => WC_Tax::is_compound( $tax_rate_id ),
) );
$item->set_props(
array(
'rate_id' => $tax_rate_id,
'tax_total' => $cart->get_tax_amount( $tax_rate_id ),
'shipping_tax_total' => $cart->get_shipping_tax_amount( $tax_rate_id ),
'rate_code' => WC_Tax::get_rate_code( $tax_rate_id ),
'label' => WC_Tax::get_rate_label( $tax_rate_id ),
'compound' => WC_Tax::is_compound( $tax_rate_id ),
)
);
/**
* Action hook to adjust item before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order_tax_item', $item, $tax_rate_id, $order );
@ -497,21 +517,24 @@ class WC_Checkout {
/**
* Add coupon lines to the order.
*
* @param WC_Order $order
* @param WC_Cart $cart
* @param WC_Order $order Order instance.
* @param WC_Cart $cart Cart instance.
*/
public function create_order_coupon_lines( &$order, $cart ) {
foreach ( $cart->get_coupons() as $code => $coupon ) {
$item = new WC_Order_Item_Coupon();
$item->set_props( array(
'code' => $code,
'discount' => $cart->get_coupon_discount_amount( $code ),
'discount_tax' => $cart->get_coupon_discount_tax_amount( $code ),
) );
$item->set_props(
array(
'code' => $code,
'discount' => $cart->get_coupon_discount_amount( $code ),
'discount_tax' => $cart->get_coupon_discount_tax_amount( $code ),
)
);
$item->add_meta_data( 'coupon_data', $coupon->get_data() );
/**
* Action hook to adjust item before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order_coupon_item', $item, $code, $coupon, $order );
@ -525,10 +548,8 @@ class WC_Checkout {
* See if a fieldset should be skipped.
*
* @since 3.0.0
*
* @param string $fieldset_key
* @param array $data
*
* @param string $fieldset_key Fieldset key.
* @param array $data Posted data.
* @return bool
*/
protected function maybe_skip_fieldset( $fieldset_key, $data ) {
@ -550,12 +571,12 @@ class WC_Checkout {
public function get_posted_data() {
$skipped = array();
$data = array(
'terms' => (int) isset( $_POST['terms'] ),
'createaccount' => (int) ! empty( $_POST['createaccount'] ),
'payment_method' => isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : '',
'shipping_method' => isset( $_POST['shipping_method'] ) ? wc_clean( $_POST['shipping_method'] ) : '',
'ship_to_different_address' => ! empty( $_POST['ship_to_different_address'] ) && ! wc_ship_to_billing_address_only(),
'woocommerce_checkout_update_totals' => isset( $_POST['woocommerce_checkout_update_totals'] ),
'terms' => (int) isset( $_POST['terms'] ), // WPCS: input var ok, CSRF ok.
'createaccount' => (int) ! empty( $_POST['createaccount'] ), // WPCS: input var ok, CSRF ok.
'payment_method' => isset( $_POST['payment_method'] ) ? wc_clean( wp_unslash( $_POST['payment_method'] ) ) : '', // WPCS: input var ok, CSRF ok.
'shipping_method' => isset( $_POST['shipping_method'] ) ? wc_clean( wp_unslash( $_POST['shipping_method'] ) ) : '', // WPCS: input var ok, CSRF ok.
'ship_to_different_address' => ! empty( $_POST['ship_to_different_address'] ) && ! wc_ship_to_billing_address_only(), // WPCS: input var ok, CSRF ok.
'woocommerce_checkout_update_totals' => isset( $_POST['woocommerce_checkout_update_totals'] ), // WPCS: input var ok, CSRF ok.
);
foreach ( $this->get_checkout_fields() as $fieldset_key => $fieldset ) {
if ( $this->maybe_skip_fieldset( $fieldset_key, $data ) ) {
@ -566,17 +587,17 @@ class WC_Checkout {
$type = sanitize_title( isset( $field['type'] ) ? $field['type'] : 'text' );
switch ( $type ) {
case 'checkbox' :
$value = isset( $_POST[ $key ] ) ? 1 : '';
case 'checkbox':
$value = isset( $_POST[ $key ] ) ? 1 : ''; // WPCS: input var ok, CSRF ok.
break;
case 'multiselect' :
$value = isset( $_POST[ $key ] ) ? implode( ', ', wc_clean( $_POST[ $key ] ) ) : '';
case 'multiselect':
$value = isset( $_POST[ $key ] ) ? implode( ', ', wc_clean( wp_unslash( $_POST[ $key ] ) ) ) : ''; // WPCS: input var ok, CSRF ok.
break;
case 'textarea' :
$value = isset( $_POST[ $key ] ) ? wc_sanitize_textarea( $_POST[ $key ] ) : '';
case 'textarea':
$value = isset( $_POST[ $key ] ) ? wc_sanitize_textarea( wp_unslash( $_POST[ $key ] ) ) : ''; // WPCS: input var ok, CSRF ok.
break;
default :
$value = isset( $_POST[ $key ] ) ? wc_clean( $_POST[ $key ] ) : '';
default:
$value = isset( $_POST[ $key ] ) ? wc_clean( wp_unslash( $_POST[ $key ] ) ) : ''; // WPCS: input var ok, CSRF ok.
break;
}
@ -584,7 +605,7 @@ class WC_Checkout {
}
}
if ( in_array( 'shipping', $skipped ) && ( WC()->cart->needs_shipping_address() || wc_ship_to_billing_address_only() ) ) {
if ( in_array( 'shipping', $skipped, true ) && ( WC()->cart->needs_shipping_address() || wc_ship_to_billing_address_only() ) ) {
foreach ( $this->get_checkout_fields( 'shipping' ) as $key => $field ) {
$data[ $key ] = isset( $data[ 'billing_' . substr( $key, 9 ) ] ) ? $data[ 'billing_' . substr( $key, 9 ) ] : '';
}
@ -600,8 +621,8 @@ class WC_Checkout {
* Validates the posted checkout data based on field properties.
*
* @since 3.0.0
* @param array $data An array of posted data.
* @param WP_Error $errors
* @param array $data An array of posted data.
* @param WP_Error $errors Validation error.
*/
protected function validate_posted_data( &$data, &$errors ) {
foreach ( $this->get_checkout_fields() as $fieldset_key => $fieldset ) {
@ -617,26 +638,27 @@ class WC_Checkout {
$field_label = isset( $field['label'] ) ? $field['label'] : '';
switch ( $fieldset_key ) {
case 'shipping' :
case 'shipping':
/* translators: %s: field name */
$field_label = sprintf( __( 'Shipping %s', 'woocommerce' ), $field_label );
break;
case 'billing' :
break;
case 'billing':
/* translators: %s: field name */
$field_label = sprintf( __( 'Billing %s', 'woocommerce' ), $field_label );
break;
break;
}
if ( in_array( 'postcode', $format ) ) {
if ( in_array( 'postcode', $format, true ) ) {
$country = isset( $data[ $fieldset_key . '_country' ] ) ? $data[ $fieldset_key . '_country' ] : WC()->customer->{"get_{$fieldset_key}_country"}();
$data[ $key ] = wc_format_postcode( $data[ $key ], $country );
if ( '' !== $data[ $key ] && ! WC_Validation::is_postcode( $data[ $key ], $country ) ) {
/* translators: %s: field name */
$errors->add( 'validation', sprintf( __( '%s is not a valid postcode / ZIP.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ) );
}
}
if ( in_array( 'phone', $format ) ) {
if ( in_array( 'phone', $format, true ) ) {
$data[ $key ] = wc_format_phone_number( $data[ $key ] );
if ( '' !== $data[ $key ] && ! WC_Validation::is_phone( $data[ $key ] ) ) {
@ -645,7 +667,7 @@ class WC_Checkout {
}
}
if ( in_array( 'email', $format ) && '' !== $data[ $key ] ) {
if ( in_array( 'email', $format, true ) && '' !== $data[ $key ] ) {
$data[ $key ] = sanitize_email( $data[ $key ] );
if ( ! is_email( $data[ $key ] ) ) {
@ -655,11 +677,11 @@ class WC_Checkout {
}
}
if ( '' !== $data[ $key ] && in_array( 'state', $format ) ) {
if ( '' !== $data[ $key ] && in_array( 'state', $format, true ) ) {
$country = isset( $data[ $fieldset_key . '_country' ] ) ? $data[ $fieldset_key . '_country' ] : WC()->customer->{"get_{$fieldset_key}_country"}();
$valid_states = WC()->countries->get_states( $country );
if ( ! empty( $valid_states ) && is_array( $valid_states ) && sizeof( $valid_states ) > 0 ) {
if ( ! empty( $valid_states ) && is_array( $valid_states ) && count( $valid_states ) > 0 ) {
$valid_state_values = array_map( 'wc_strtoupper', array_flip( array_map( 'wc_strtoupper', $valid_states ) ) );
$data[ $key ] = wc_strtoupper( $data[ $key ] );
@ -668,7 +690,7 @@ class WC_Checkout {
$data[ $key ] = $valid_state_values[ $data[ $key ] ];
}
if ( ! in_array( $data[ $key ], $valid_state_values ) ) {
if ( ! in_array( $data[ $key ], $valid_state_values, true ) ) {
/* translators: 1: state field 2: valid states */
$errors->add( 'validation', sprintf( __( '%1$s is not valid. Please enter one of the following: %2$s', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>', implode( ', ', $valid_states ) ) );
}
@ -687,14 +709,14 @@ class WC_Checkout {
* Validates that the checkout has enough info to proceed.
*
* @since 3.0.0
* @param array $data An array of posted data.
* @param WP_Error $errors
* @param array $data An array of posted data.
* @param WP_Error $errors Validation errors.
*/
protected function validate_checkout( &$data, &$errors ) {
$this->validate_posted_data( $data, $errors );
$this->check_cart_items();
if ( empty( $data['woocommerce_checkout_update_totals'] ) && ! empty( $_POST['terms-field'] ) && empty( $data['terms'] ) && apply_filters( 'woocommerce_checkout_show_terms', wc_get_page_id( 'terms' ) > 0 ) ) {
if ( empty( $data['woocommerce_checkout_update_totals'] ) && ! empty( $_POST['terms-field'] ) && empty( $data['terms'] ) && apply_filters( 'woocommerce_checkout_show_terms', wc_get_page_id( 'terms' ) > 0 ) ) { // WPCS: input var ok, CSRF ok.
$errors->add( 'terms', __( 'You must accept our Terms &amp; Conditions.', 'woocommerce' ) );
}
@ -703,7 +725,8 @@ class WC_Checkout {
if ( empty( $shipping_country ) ) {
$errors->add( 'shipping', __( 'Please enter an address to continue.', 'woocommerce' ) );
} elseif ( ! in_array( WC()->customer->get_shipping_country(), array_keys( WC()->countries->get_shipping_countries() ) ) ) {
} elseif ( ! in_array( WC()->customer->get_shipping_country(), array_keys( WC()->countries->get_shipping_countries() ), true ) ) {
/* translators: %s: shipping location */
$errors->add( 'shipping', sprintf( __( 'Unfortunately <strong>we do not ship %s</strong>. Please enter an alternative shipping address.', 'woocommerce' ), WC()->countries->shipping_to_prefix() . ' ' . WC()->customer->get_shipping_country() ) );
} else {
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
@ -733,9 +756,9 @@ class WC_Checkout {
* Set address field for customer.
*
* @since 3.0.7
* @param $field string to update
* @param $key
* @param $data array of data to get the value from
* @param string $field String to update.
* @param string $key Field key.
* @param array $data Array of data to get the value from.
*/
protected function set_customer_address_fields( $field, $key, $data ) {
if ( isset( $data[ "billing_{$field}" ] ) ) {
@ -750,8 +773,8 @@ class WC_Checkout {
/**
* Update customer and session data from the posted checkout data.
*
* @since 3.0.0
* @param array $data
* @since 3.0.0
* @param array $data Posted data.
*/
protected function update_session( $data ) {
// Update both shipping and billing to the passed billing address first if set.
@ -767,7 +790,7 @@ class WC_Checkout {
array_walk( $address_fields, array( $this, 'set_customer_address_fields' ), $data );
WC()->customer->save();
// Update customer shipping and payment method to posted method
// Update customer shipping and payment method to posted method.
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
if ( is_array( $data['shipping_method'] ) ) {
@ -787,9 +810,9 @@ class WC_Checkout {
/**
* Process an order that does require payment.
*
* @since 3.0.0
* @param int $order_id
* @param string $payment_method
* @since 3.0.0
* @param int $order_id Order ID.
* @param string $payment_method Payment method.
*/
protected function process_order_payment( $order_id, $payment_method ) {
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
@ -798,13 +821,13 @@ class WC_Checkout {
return;
}
// Store Order ID in session so it can be re-used after payment failure
// Store Order ID in session so it can be re-used after payment failure.
WC()->session->set( 'order_awaiting_payment', $order_id );
// Process Payment
// Process Payment.
$result = $available_gateways[ $payment_method ]->process_payment( $order_id );
// Redirect to success/confirmation/payment page
// Redirect to success/confirmation/payment page.
if ( isset( $result['result'] ) && 'success' === $result['result'] ) {
$result = apply_filters( 'woocommerce_payment_successful_result', $result, $order_id );
@ -820,8 +843,8 @@ class WC_Checkout {
/**
* Process an order that doesn't require payment.
*
* @since 3.0.0
* @param int $order_id
* @since 3.0.0
* @param int $order_id Order ID.
*/
protected function process_order_without_payment( $order_id ) {
$order = wc_get_order( $order_id );
@ -829,10 +852,12 @@ class WC_Checkout {
wc_empty_cart();
if ( is_ajax() ) {
wp_send_json( array(
'result' => 'success',
'redirect' => apply_filters( 'woocommerce_checkout_no_payment_needed_redirect', $order->get_checkout_order_received_url(), $order ),
) );
wp_send_json(
array(
'result' => 'success',
'redirect' => apply_filters( 'woocommerce_checkout_no_payment_needed_redirect', $order->get_checkout_order_received_url(), $order ),
)
);
} else {
wp_safe_redirect(
apply_filters( 'woocommerce_checkout_no_payment_needed_redirect', $order->get_checkout_order_received_url(), $order )
@ -843,8 +868,9 @@ class WC_Checkout {
/**
* Create a new customer account if needed.
* @param array $data
* @throws Exception
*
* @throws Exception When not able to create customer.
* @param array $data Posted data.
*/
protected function process_customer( $data ) {
$customer_id = apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() );
@ -861,10 +887,10 @@ class WC_Checkout {
wp_set_current_user( $customer_id );
wc_set_customer_auth_cookie( $customer_id );
// As we are now logged in, checkout will need to refresh to show logged in data
// As we are now logged in, checkout will need to refresh to show logged in data.
WC()->session->set( 'reload_checkout', true );
// Also, recalculate cart totals to reveal any role-based discounts that were unavailable before registering
// Also, recalculate cart totals to reveal any role-based discounts that were unavailable before registering.
WC()->cart->calculate_totals();
}
@ -895,7 +921,7 @@ class WC_Checkout {
if ( is_callable( array( $customer, "set_{$key}" ) ) ) {
$customer->{"set_{$key}"}( $value );
// Store custom fields prefixed with wither shipping_ or billing_.
// Store custom fields prefixed with wither shipping_ or billing_.
} elseif ( 0 === stripos( $key, 'billing_' ) || 0 === stripos( $key, 'shipping_' ) ) {
$customer->update_meta_data( $key, $value );
}
@ -903,6 +929,7 @@ class WC_Checkout {
/**
* Action hook to adjust customer before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_update_customer', $customer, $data );
@ -918,7 +945,7 @@ class WC_Checkout {
*/
protected function send_ajax_failure_response() {
if ( is_ajax() ) {
// only print notices if not reloading the checkout, otherwise they're lost in the page reload
// Only print notices if not reloading the checkout, otherwise they're lost in the page reload.
if ( ! isset( WC()->session->reload_checkout ) ) {
ob_start();
wc_print_notices();
@ -940,6 +967,8 @@ class WC_Checkout {
/**
* Process the checkout after the confirm order button is pressed.
*
* @throws Exception When validation fails.
*/
public function process_checkout() {
try {
@ -956,6 +985,7 @@ class WC_Checkout {
do_action( 'woocommerce_before_checkout_process' );
if ( WC()->cart->is_empty() ) {
/* translators: %s: shop cart url */
throw new Exception( sprintf( __( 'Sorry, your session has expired. <a href="%s" class="wc-backward">Return to shop</a>', 'woocommerce' ), esc_url( wc_get_page_permalink( 'shop' ) ) ) );
}
@ -1000,8 +1030,8 @@ class WC_Checkout {
/**
* Get a posted address field after sanitization and validation.
*
* @param string $key
* @param string $type billing for shipping
* @param string $key Field key.
* @param string $type Type of address. Available options: 'billing' or 'shipping'.
* @return string
*/
public function get_posted_address_data( $key, $type = 'billing' ) {
@ -1016,12 +1046,12 @@ class WC_Checkout {
/**
* Gets the value either from the posted data, or from the users meta data.
*
* @param string $input
* @param string $input Input key.
* @return string
*/
public function get_value( $input ) {
if ( ! empty( $_POST[ $input ] ) ) {
return wc_clean( $_POST[ $input ] );
if ( ! empty( $_POST[ $input ] ) ) { // WPCS: input var ok, CSRF OK.
return wc_clean( wp_unslash( $_POST[ $input ] ) ); // WPCS: input var ok, CSRF OK.
} else {

View File

@ -220,7 +220,7 @@ class WC_Frontend_Scripts {
'selectWoo' => array(
'src' => self::get_asset_url( 'assets/js/selectWoo/selectWoo.full' . $suffix . '.js' ),
'deps' => array( 'jquery' ),
'version' => '1.0.3',
'version' => '1.0.4',
),
'wc-address-i18n' => array(
'src' => self::get_asset_url( 'assets/js/frontend/address-i18n' . $suffix . '.js' ),

View File

@ -463,7 +463,7 @@ class WC_Install {
}
}
$woocommerce_default_category = get_option( 'default_product_cat', 0 );
$woocommerce_default_category = (int) get_option( 'default_product_cat', 0 );
if ( ! $woocommerce_default_category || ! term_exists( $woocommerce_default_category, 'product_cat' ) ) {
$default_product_cat_id = 0;
@ -475,7 +475,7 @@ class WC_Install {
} else {
$result = wp_insert_term( _x( 'Uncategorized', 'Default category slug', 'woocommerce' ), 'product_cat', array( 'slug' => $default_product_cat_slug ) );
if ( ! empty( $result['term_taxonomy_id'] ) ) {
if ( ! is_wp_error( $result ) && ! empty( $result['term_taxonomy_id'] ) ) {
$default_product_cat_id = absint( $result['term_taxonomy_id'] );
}
}
@ -780,6 +780,15 @@ CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
$tables[] = "{$wpdb->prefix}woocommerce_termmeta";
}
/**
* Filter the list of known WooCommerce tables.
*
* If WooCommerce plugins need to add new tables, they can inject them here.
*
* @param array $tables An array of WooCommerce-specific database table names.
*/
$tables = apply_filters( 'woocommerce_install_get_tables', $tables );
return $tables;
}

View File

@ -1,4 +1,10 @@
<?php
/**
* Class WC_Product_Grouped file.
*
* @package WooCommerce\Classes\Products
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
@ -8,11 +14,9 @@ if ( ! defined( 'ABSPATH' ) ) {
*
* Grouped products cannot be purchased - they are wrappers for other products.
*
* @class WC_Product_Grouped
* @version 3.0.0
* @package WooCommerce/Classes/Products
* @category Class
* @author WooThemes
* @class WC_Product_Grouped
* @version 3.0.0
* @package WooCommerce/Classes/Products
*/
class WC_Product_Grouped extends WC_Product {
@ -27,6 +31,7 @@ class WC_Product_Grouped extends WC_Product {
/**
* Get internal type.
*
* @return string
*/
public function get_type() {
@ -61,8 +66,6 @@ class WC_Product_Grouped extends WC_Product {
* @return bool
*/
public function is_on_sale( $context = 'view' ) {
global $wpdb;
$children = array_filter( array_map( 'wc_get_product', $this->get_children( $context ) ), 'wc_products_array_filter_visible_grouped' );
$on_sale = false;
@ -89,7 +92,7 @@ class WC_Product_Grouped extends WC_Product {
* Returns the price in html format.
*
* @access public
* @param string $price (default: '')
* @param string $price (default: '').
* @return string
*/
public function get_price_html( $price = '' ) {
@ -143,7 +146,7 @@ class WC_Product_Grouped extends WC_Product {
/**
* Return the children of this product.
*
* @param string $context
* @param string $context What the value is for. Valid values are view and edit.
* @return array
*/
public function get_children( $context = 'view' ) {
@ -161,7 +164,7 @@ class WC_Product_Grouped extends WC_Product {
/**
* Return the children of this product.
*
* @param array $children
* @param array $children List of product children.
*/
public function set_children( $children ) {
$this->set_prop( 'children', array_filter( wp_parse_id_list( (array) $children ) ) );
@ -178,7 +181,7 @@ class WC_Product_Grouped extends WC_Product {
* upwards (from child to parent) when the variation is saved.
*
* @param WC_Product|int $product Product object or ID for which you wish to sync.
* @param bool $save If true, the product object will be saved to the DB before returning it.
* @param bool $save If true, the product object will be saved to the DB before returning it.
* @return WC_Product Synced product object.
*/
public static function sync( $product, $save = true ) {

View File

@ -152,7 +152,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Get shipping methods linked to this zone.
*
* @param bool $enabled_only Only return enabled methods.
* @param bool $enabled_only Only return enabled methods.
* @param string $context Getting shipping methods for what context. Valid values, admin, json.
* @return array of objects
*/
@ -191,7 +191,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
$methods[ $instance_id ]->method_order = absint( $raw_method->method_order );
$methods[ $instance_id ]->enabled = $raw_method->is_enabled ? 'yes' : 'no';
$methods[ $instance_id ]->has_settings = $methods[ $instance_id ]->has_settings();
$methods[ $instance_id ]->settings_html = $methods[ $instance_id ]->supports( 'instance-settings-modal' ) ? $methods[ $instance_id ]->get_admin_options_html(): false;
$methods[ $instance_id ]->settings_html = $methods[ $instance_id ]->supports( 'instance-settings-modal' ) ? $methods[ $instance_id ]->get_admin_options_html() : false;
$methods[ $instance_id ]->method_description = wp_kses_post( wpautop( $methods[ $instance_id ]->method_description ) );
}

View File

@ -94,7 +94,7 @@ class WC_Shipping_Zones {
$wc_shipping = WC_Shipping::instance();
$allowed_classes = $wc_shipping->get_shipping_method_class_names();
if ( ! empty( $raw_shipping_method ) && in_array( $raw_shipping_method->method_id, array_keys( $allowed_classes ) ) ) {
if ( ! empty( $raw_shipping_method ) && in_array( $raw_shipping_method->method_id, array_keys( $allowed_classes ), true ) ) {
$class_name = $allowed_classes[ $raw_shipping_method->method_id ];
if ( is_object( $class_name ) ) {
$class_name = get_class( $class_name );

View File

@ -4,11 +4,9 @@
*
* Handles shipping and loads shipping methods via hooks.
*
* @class WC_Shipping
* @version 2.6.0
* @package WooCommerce/Classes/Shipping
* @category Class
* @author WooThemes
* @class WC_Shipping
* @version 2.6.0
* @package WooCommerce/Classes/Shipping
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -20,20 +18,38 @@ if ( ! defined( 'ABSPATH' ) ) {
*/
class WC_Shipping {
/** @var bool True if shipping is enabled. */
public $enabled = false;
/** @var array|null Stores methods loaded into woocommerce. */
public $shipping_methods = null;
/** @var array Stores the shipping classes. */
public $shipping_classes = array();
/** @var array Stores packages to ship and to get quotes for. */
public $packages = array();
/**
* True if shipping is enabled.
*
* @var bool
*/
public $enabled = false;
/**
* @var WC_Shipping The single instance of the class
* Stores methods loaded into woocommerce.
*
* @var array|null
*/
public $shipping_methods = null;
/**
* Stores the shipping classes.
*
* @var array
*/
public $shipping_classes = array();
/**
* Stores packages to ship and to get quotes for.
*
* @var array
*/
public $packages = array();
/**
* The single instance of the class
*
* @var WC_Shipping
* @since 2.1
*/
protected static $_instance = null;
@ -80,10 +96,10 @@ class WC_Shipping {
*/
public function __get( $name ) {
// Grab from cart for backwards compatibility with versions prior to 3.2.
if ( 'shipping_total' === $name ){
if ( 'shipping_total' === $name ) {
return wc()->cart->get_shipping_total();
}
if ( 'shipping_taxes' === $name ){
if ( 'shipping_taxes' === $name ) {
return wc()->cart->get_shipping_taxes();
}
}
@ -108,17 +124,18 @@ class WC_Shipping {
/**
* Shipping methods register themselves by returning their main class name through the woocommerce_shipping_methods filter.
*
* @return array
*/
public function get_shipping_method_class_names() {
// Unique Method ID => Method Class name
// Unique Method ID => Method Class name.
$shipping_methods = array(
'flat_rate' => 'WC_Shipping_Flat_Rate',
'free_shipping' => 'WC_Shipping_Free_Shipping',
'local_pickup' => 'WC_Shipping_Local_Pickup',
);
// For backwards compatibility with 2.5.x we load any ENABLED legacy shipping methods here
// For backwards compatibility with 2.5.x we load any ENABLED legacy shipping methods here.
$maybe_load_legacy_methods = array( 'flat_rate', 'free_shipping', 'international_delivery', 'local_delivery', 'local_pickup' );
foreach ( $maybe_load_legacy_methods as $method ) {
@ -135,7 +152,7 @@ class WC_Shipping {
* Loads all shipping methods which are hooked in.
* If a $package is passed some methods may add themselves conditionally and zones will be used.
*
* @param array $package
* @param array $package Package information.
* @return array
*/
public function load_shipping_methods( $package = array() ) {
@ -144,7 +161,7 @@ class WC_Shipping {
$shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $package );
$this->shipping_methods = $shipping_zone->get_shipping_methods( true );
// Debug output
// Debug output.
if ( $debug_mode && ! defined( 'WOOCOMMERCE_CHECKOUT' ) && ! defined( 'WC_DOING_AJAX' ) && ! wc_has_notice( 'Customer matched zone "' . $shipping_zone->get_zone_name() . '"' ) ) {
wc_add_notice( 'Customer matched zone "' . $shipping_zone->get_zone_name() . '"' );
}
@ -160,7 +177,7 @@ class WC_Shipping {
// Methods can register themselves manually through this hook if necessary.
do_action( 'woocommerce_load_shipping_methods', $package );
// Return loaded methods
// Return loaded methods.
return $this->get_shipping_methods();
}
@ -212,36 +229,17 @@ class WC_Shipping {
*/
public function get_shipping_classes() {
if ( empty( $this->shipping_classes ) ) {
$classes = get_terms( 'product_shipping_class', array( 'hide_empty' => '0', 'orderby' => 'name' ) );
$classes = get_terms(
'product_shipping_class', array(
'hide_empty' => '0',
'orderby' => 'name',
)
);
$this->shipping_classes = ! is_wp_error( $classes ) ? $classes : array();
}
return apply_filters( 'woocommerce_get_shipping_classes', $this->shipping_classes );
}
/**
* Get the default method.
* @param array $available_methods
* @param boolean $current_chosen_method
* @return string
*/
private function get_default_method( $available_methods, $current_chosen_method = false ) {
if ( ! empty( $available_methods ) ) {
if ( ! empty( $current_chosen_method ) ) {
if ( isset( $available_methods[ $current_chosen_method ] ) ) {
return $available_methods[ $current_chosen_method ]->id;
} else {
foreach ( $available_methods as $method_key => $method ) {
if ( strpos( $method->id, $current_chosen_method ) === 0 ) {
return $method->id;
}
}
}
}
return current( $available_methods )->id;
}
return '';
}
/**
* Calculate shipping for (multiple) packages of cart items.
*
@ -292,7 +290,7 @@ class WC_Shipping {
}
$allowed = array_keys( WC()->countries->get_shipping_countries() );
return in_array( $package['destination']['country'], $allowed );
return in_array( $package['destination']['country'], $allowed, true );
}
/**
@ -338,10 +336,12 @@ class WC_Shipping {
$package['rates'] = apply_filters( 'woocommerce_package_rates', $package['rates'], $package );
// Store in session to avoid recalculation.
WC()->session->set( $session_key, array(
'package_hash' => $package_hash,
'rates' => $package['rates'],
) );
WC()->session->set(
$session_key, array(
'package_hash' => $package_hash,
'rates' => $package['rates'],
)
);
} else {
$package['rates'] = $stored_rates['rates'];
}
@ -351,6 +351,7 @@ class WC_Shipping {
/**
* Get packages.
*
* @return array
*/
public function get_packages() {
@ -368,6 +369,8 @@ class WC_Shipping {
}
/**
* Deprecated
*
* @deprecated 2.6.0 Was previously used to determine sort order of methods, but this is now controlled by zones and thus unused.
*/
public function sort_shipping_methods() {

View File

@ -2,8 +2,6 @@
/**
* Shortcodes
*
* @author Automattic
* @category Class
* @package WooCommerce/Classes
* @version 3.2.0
*/

View File

@ -1,7 +1,12 @@
<?php
/**
* Class WC_Validation file
*
* @package WooCommerce\Classes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
/**
@ -10,15 +15,13 @@ if ( ! defined( 'ABSPATH' ) ) {
* @class WC_Validation
* @version 2.4.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
*/
class WC_Validation {
/**
* Validates an email using WordPress native is_email function.
*
* @param string $email Email address to validate.
* @param string $email Email address to validate.
* @return bool
*/
public static function is_email( $email ) {
@ -28,7 +31,7 @@ class WC_Validation {
/**
* Validates a phone number using a regular expression.
*
* @param string $phone Phone number to validate.
* @param string $phone Phone number to validate.
* @return bool
*/
public static function is_phone( $phone ) {
@ -42,8 +45,8 @@ class WC_Validation {
/**
* Checks for a valid postcode.
*
* @param string $postcode Postcode to validate.
* @param string $country Country to validate the postcode for.
* @param string $postcode Postcode to validate.
* @param string $country Country to validate the postcode for.
* @return bool
*/
public static function is_postcode( $postcode, $country ) {
@ -52,36 +55,36 @@ class WC_Validation {
}
switch ( $country ) {
case 'AT' :
case 'AT':
$valid = (bool) preg_match( '/^([0-9]{4})$/', $postcode );
break;
case 'BR' :
case 'BR':
$valid = (bool) preg_match( '/^([0-9]{5})([-])?([0-9]{3})$/', $postcode );
break;
case 'CH' :
case 'CH':
$valid = (bool) preg_match( '/^([0-9]{4})$/i', $postcode );
break;
case 'DE' :
case 'DE':
$valid = (bool) preg_match( '/^([0]{1}[1-9]{1}|[1-9]{1}[0-9]{1})[0-9]{3}$/', $postcode );
break;
case 'ES' :
case 'FR' :
case 'ES':
case 'FR':
$valid = (bool) preg_match( '/^([0-9]{5})$/i', $postcode );
break;
case 'GB' :
$valid = self::is_GB_postcode( $postcode );
case 'GB':
$valid = self::is_gb_postcode( $postcode );
break;
case 'JP' :
case 'JP':
$valid = (bool) preg_match( '/^([0-9]{3})([-])([0-9]{4})$/', $postcode );
break;
case 'PT' :
case 'PT':
$valid = (bool) preg_match( '/^([0-9]{4})([-])([0-9]{3})$/', $postcode );
break;
case 'US' :
case 'US':
$valid = (bool) preg_match( '/^([0-9]{5})(-[0-9]{4})?$/i', $postcode );
break;
case 'CA' :
// CA Postal codes cannot contain D,F,I,O,Q,U and cannot start with W or Z. https://en.wikipedia.org/wiki/Postal_codes_in_Canada#Number_of_possible_postal_codes
case 'CA':
// CA Postal codes cannot contain D,F,I,O,Q,U and cannot start with W or Z. https://en.wikipedia.org/wiki/Postal_codes_in_Canada#Number_of_possible_postal_codes.
$valid = (bool) preg_match( '/^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])([\ ])?(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$/i', $postcode );
break;
case 'PL':
@ -92,7 +95,7 @@ class WC_Validation {
$valid = (bool) preg_match( '/^([0-9]{3})(\s?)([0-9]{2})$/', $postcode );
break;
default :
default:
$valid = true;
break;
}
@ -103,51 +106,50 @@ class WC_Validation {
/**
* Check if is a GB postcode.
*
* @author John Gardner
* @param string $to_check A postcode
* @param string $to_check A postcode.
* @return bool
*/
public static function is_GB_postcode( $to_check ) {
public static function is_gb_postcode( $to_check ) {
// Permitted letters depend upon their position in the postcode.
// https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation
$alpha1 = "[abcdefghijklmnoprstuwyz]"; // Character 1
$alpha2 = "[abcdefghklmnopqrstuvwxy]"; // Character 2
$alpha3 = "[abcdefghjkpstuw]"; // Character 3 == ABCDEFGHJKPSTUW
$alpha4 = "[abehmnprvwxy]"; // Character 4 == ABEHMNPRVWXY
$alpha5 = "[abdefghjlnpqrstuwxyz]"; // Character 5 != CIKMOV
// https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation.
$alpha1 = '[abcdefghijklmnoprstuwyz]'; // Character 1.
$alpha2 = '[abcdefghklmnopqrstuvwxy]'; // Character 2.
$alpha3 = '[abcdefghjkpstuw]'; // Character 3 == ABCDEFGHJKPSTUW.
$alpha4 = '[abehmnprvwxy]'; // Character 4 == ABEHMNPRVWXY.
$alpha5 = '[abdefghjlnpqrstuwxyz]'; // Character 5 != CIKMOV.
$pcexp = array();
// Expression for postcodes: AN NAA, ANN NAA, AAN NAA, and AANN NAA
// Expression for postcodes: AN NAA, ANN NAA, AAN NAA, and AANN NAA.
$pcexp[0] = '/^(' . $alpha1 . '{1}' . $alpha2 . '{0,1}[0-9]{1,2})([0-9]{1}' . $alpha5 . '{2})$/';
// Expression for postcodes: ANA NAA
// Expression for postcodes: ANA NAA.
$pcexp[1] = '/^(' . $alpha1 . '{1}[0-9]{1}' . $alpha3 . '{1})([0-9]{1}' . $alpha5 . '{2})$/';
// Expression for postcodes: AANA NAA
// Expression for postcodes: AANA NAA.
$pcexp[2] = '/^(' . $alpha1 . '{1}' . $alpha2 . '[0-9]{1}' . $alpha4 . ')([0-9]{1}' . $alpha5 . '{2})$/';
// Exception for the special postcode GIR 0AA
// Exception for the special postcode GIR 0AA.
$pcexp[3] = '/^(gir)(0aa)$/';
// Standard BFPO numbers
// Standard BFPO numbers.
$pcexp[4] = '/^(bfpo)([0-9]{1,4})$/';
// c/o BFPO numbers
// c/o BFPO numbers.
$pcexp[5] = '/^(bfpo)(c\/o[0-9]{1,3})$/';
// Load up the string to check, converting into lowercase and removing spaces
// Load up the string to check, converting into lowercase and removing spaces.
$postcode = strtolower( $to_check );
$postcode = str_replace( ' ', '', $postcode );
// Assume we are not going to find a valid postcode
// Assume we are not going to find a valid postcode.
$valid = false;
// Check the string against the six types of postcodes
// Check the string against the six types of postcodes.
foreach ( $pcexp as $regexp ) {
if ( preg_match( $regexp, $postcode, $matches ) ) {
// Remember that we have found that the code is valid and break from loop
// Remember that we have found that the code is valid and break from loop.
$valid = true;
break;
}
@ -159,16 +161,16 @@ class WC_Validation {
/**
* Format the postcode according to the country and length of the postcode.
*
* @param string $postcode Postcode to format.
* @param string $country Country to format the postcode for.
* @return string Formatted postcode.
* @param string $postcode Postcode to format.
* @param string $country Country to format the postcode for.
* @return string Formatted postcode.
*/
public static function format_postcode( $postcode, $country ) {
return wc_format_postcode( $postcode, $country );
}
/**
* format_phone function.
* Format a given phone number.
*
* @param mixed $tel Phone number to format.
* @return string

View File

@ -8,9 +8,7 @@
*
* @version 3.2.0
* @package WooCommerce/Webhooks
* @category Webhooks
* @since 2.2.0
* @author Automattic
*/
if ( ! defined( 'ABSPATH' ) ) {

View File

@ -1,21 +1,18 @@
<?php
/**
* Class WC_Data_Store_WP file.
*
* @package WooCommerce\DataStores
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Shared logic for WP based data.
* Contains functions like meta handling for all default data stores.
* Your own data store doesn't need to use WC_Data_Store_WP -- you can write
* your own meta handling functions.
*
* @version 3.0.0
* @version 3.0.0
* @package WooCommerce/Classes
*/
defined( 'ABSPATH' ) || exit;
/**
* WC_Data_Store_WP class.
*/
class WC_Data_Store_WP {
@ -171,7 +168,6 @@ class WC_Data_Store_WP {
* @since 2.6.0
*
* @param string $key Prefix to be added to meta keys.
*
* @return string
*/
protected function prefix_key( $key ) {
@ -383,7 +379,6 @@ class WC_Data_Store_WP {
'compare' => $operator,
);
break;
case '<':
case '>=':
$wp_query_args['meta_query'][] = array(
@ -392,7 +387,6 @@ class WC_Data_Store_WP {
'compare' => $operator,
);
break;
default:
$wp_query_args['meta_query'][] = array(
'key' => $key,
@ -438,4 +432,61 @@ class WC_Data_Store_WP {
public function get_internal_meta_keys() {
return $this->internal_meta_keys;
}
/**
* Check if the terms are suitable for searching.
*
* Uses an array of stopwords (terms) that are excluded from the separate
* term matching when searching for posts. The list of English stopwords is
* the approximate search engines list, and is translatable.
*
* @since 3.4.0
* @param array $terms Terms to check.
* @return array Terms that are not stopwords.
*/
protected function get_valid_search_terms( $terms ) {
$valid_terms = array();
$stopwords = $this->get_search_stopwords();
foreach ( $terms as $term ) {
// keep before/after spaces when term is for exact match, otherwise trim quotes and spaces.
if ( preg_match( '/^".+"$/', $term ) ) {
$term = trim( $term, "\"'" );
} else {
$term = trim( $term, "\"' " );
}
// Avoid single A-Z and single dashes.
if ( empty( $term ) || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) ) {
continue;
}
if ( in_array( wc_strtolower( $term ), $stopwords, true ) ) {
continue;
}
$valid_terms[] = $term;
}
return $valid_terms;
}
/**
* Retrieve stopwords used when parsing search terms.
*
* @since 3.4.0
* @return array Stopwords.
*/
protected function get_search_stopwords() {
// Translators: This is a comma-separated list of very common words that should be excluded from a search, like a, an, and the. These are usually called "stopwords". You should not simply translate these individual words into your language. Instead, look for and provide commonly accepted stopwords in your language.
$stopwords = array_map( 'wc_strtolower', array_map( 'trim', explode(
',', _x(
'about,an,are,as,at,be,by,com,for,from,how,in,is,it,of,on,or,that,the,this,to,was,what,when,where,who,will,with,www',
'Comma-separated list of search stopwords in your language',
'woocommerce'
)
) ) );
return apply_filters( 'wp_search_stopwords', $stopwords );
}
}

View File

@ -700,6 +700,8 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
foreach ( $attributes as $attribute_key => $attribute ) {
$value = '';
delete_transient( 'wc_layered_nav_counts_' . $attribute_key );
if ( is_null( $attribute ) ) {
if ( taxonomy_exists( $attribute_key ) ) {
// Handle attributes that have been unset.
@ -725,7 +727,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
}
}
update_post_meta( $product->get_id(), '_product_attributes', $meta_values );
delete_transient( 'wc_layered_nav_counts' );
}
}
@ -1326,12 +1327,54 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
public function search_products( $term, $type = '', $include_variations = false, $all_statuses = false ) {
global $wpdb;
$like_term = '%' . $wpdb->esc_like( $term ) . '%';
$post_types = $include_variations ? array( 'product', 'product_variation' ) : array( 'product' );
$post_statuses = current_user_can( 'edit_private_products' ) ? array( 'private', 'publish' ) : array( 'publish' );
$type_join = '';
$type_where = '';
$status_where = '';
$term = wc_strtolower( $term );
// See if search term contains OR keywords.
if ( strstr( $term, ' or ' ) ) {
$term_groups = explode( ' or ', $term );
} else {
$term_groups = array( $term );
}
$search_where = '';
$search_queries = array();
foreach ( $term_groups as $term_group ) {
// Parse search terms.
if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $term_group, $matches ) ) {
$search_terms = $this->get_valid_search_terms( $matches[0] );
$count = count( $search_terms );
// if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence.
if ( 9 < $count || 0 === $count ) {
$search_terms = array( $term_group );
}
} else {
$search_terms = array( $term_group );
}
$term_group_query = '';
$searchand = '';
foreach ( $search_terms as $search_term ) {
$like = '%' . $wpdb->esc_like( $search_term ) . '%';
$term_group_query .= $wpdb->prepare( " {$searchand} ( ( posts.post_title LIKE %s) OR ( posts.post_excerpt LIKE %s) OR ( posts.post_content LIKE %s ) OR ( postmeta.meta_key = '_sku' AND postmeta.meta_value LIKE %s ) )", $like, $like, $like ); // @codingStandardsIgnoreLine.
$searchand = ' AND ';
}
if ( $term_group_query ) {
$search_queries[] = $term_group_query;
}
}
if ( $search_queries ) {
$search_where = 'AND (' . implode( ') OR (', $search_queries ) . ')';
}
if ( $type ) {
if ( in_array( $type, array( 'virtual', 'downloadable' ), true ) ) {
@ -1347,25 +1390,14 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
// phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
$search_results = $wpdb->get_results(
// phpcs:disable
$wpdb->prepare(
"SELECT DISTINCT posts.ID as product_id, posts.post_parent as parent_id FROM {$wpdb->posts} posts
LEFT JOIN {$wpdb->postmeta} postmeta ON posts.ID = postmeta.post_id
$type_join
WHERE (
posts.post_title LIKE %s
OR posts.post_content LIKE %s
OR (
postmeta.meta_key = '_sku' AND postmeta.meta_value LIKE %s
)
)
AND posts.post_type IN ('" . implode( "','", $post_types ) . "')
$status_where
$type_where
ORDER BY posts.post_parent ASC, posts.post_title ASC",
$like_term,
$like_term,
$like_term
)
"SELECT DISTINCT posts.ID as product_id, posts.post_parent as parent_id FROM {$wpdb->posts} posts
LEFT JOIN {$wpdb->postmeta} postmeta ON posts.ID = postmeta.post_id
$type_join
WHERE posts.post_type IN ('" . implode( "','", $post_types ) . "')
$search_where
$status_where
$type_where
ORDER BY posts.post_parent ASC, posts.post_title ASC"
// phpcs:enable
);

View File

@ -197,7 +197,7 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
);
// Empty value indicates that all options for given attribute are available.
if ( in_array( '', $values, true ) || empty( $values ) ) {
if ( in_array( null, $values, true ) || in_array( '', $values, true ) || empty( $values ) ) {
$values = $attribute['is_taxonomy'] ? wc_get_object_terms( $product->get_id(), $attribute['name'], 'slug' ) : wc_get_text_attributes( $attribute['value'] );
// Get custom attributes (non taxonomy) as defined.
} elseif ( ! $attribute['is_taxonomy'] ) {

View File

@ -317,8 +317,9 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
*/
protected function set_product_data( &$product, $data ) {
if ( isset( $data['raw_attributes'] ) ) {
$attributes = array();
$default_attributes = array();
$attributes = array();
$default_attributes = array();
$existing_attributes = $product->get_attributes();
foreach ( $data['raw_attributes'] as $position => $attribute ) {
$attribute_id = 0;
@ -335,12 +336,22 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
$is_visible = 1;
}
// Set if is a variation attribute.
// Get name.
$attribute_name = $attribute_id ? wc_attribute_taxonomy_name_by_id( $attribute_id ) : $attribute['name'];
// Set if is a variation attribute based on existing attributes if possible so updates via CSV do not change this.
$is_variation = 0;
if ( $attribute_id ) {
$attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
if ( $existing_attributes ) {
foreach ( $existing_attributes as $existing_attribute ) {
if ( $existing_attribute->get_name() === $attribute_name ) {
$is_variation = $existing_attribute->get_variation();
break;
}
}
}
if ( $attribute_id ) {
if ( isset( $attribute['value'] ) ) {
$options = array_map( 'wc_sanitize_term_text_based', $attribute['value'] );
$options = array_filter( $options, 'strlen' );

View File

@ -113,7 +113,7 @@ class WC_Shortcode_Products {
$attributes = shortcode_atts(
array(
'limit' => '-1', // Results limit.
'columns' => '3', // Number of columns.
'columns' => '', // Number of columns.
'rows' => '', // Number of rows. If defined, limit will be ignored.
'orderby' => 'title', // menu_order, title, date, rand, price, popularity, rating, or id.
'order' => 'ASC', // ASC or DESC.
@ -134,7 +134,7 @@ class WC_Shortcode_Products {
);
if ( ! absint( $attributes['columns'] ) ) {
$attributes['columns'] = 3;
$attributes['columns'] = wc_get_default_products_per_row();
}
return $attributes;

View File

@ -4,8 +4,6 @@
*
* Functions for determining the current query/page.
*
* @author WooThemes
* @category Core
* @package WooCommerce/Functions
* @version 2.3.0
*/
@ -128,7 +126,7 @@ if ( ! function_exists( 'is_wc_endpoint_url' ) ) {
/**
* Is_wc_endpoint_url - Check if an endpoint is showing.
*
* @param string $endpoint Whether endpoint.
* @param string|false $endpoint Whether endpoint.
* @return bool
*/
function is_wc_endpoint_url( $endpoint = false ) {
@ -272,7 +270,7 @@ if ( ! function_exists( 'is_filtered' ) ) {
* @return bool
*/
function is_filtered() {
return apply_filters( 'woocommerce_is_filtered', ( count( WC_Query::get_layered_nav_chosen_attributes() ) > 0 || isset( $_GET['max_price'] ) || isset( $_GET['min_price'] ) || isset( $_GET['rating_filter'] ) ) );
return apply_filters( 'woocommerce_is_filtered', ( count( WC_Query::get_layered_nav_chosen_attributes() ) > 0 || isset( $_GET['max_price'] ) || isset( $_GET['min_price'] ) || isset( $_GET['rating_filter'] ) ) ); // WPCS: CSRF ok.
}
}
@ -308,7 +306,7 @@ if ( ! function_exists( 'meta_is_product_attribute' ) ) {
if ( $product && method_exists( $product, 'get_variation_attributes' ) ) {
$variation_attributes = $product->get_variation_attributes();
$attributes = $product->get_attributes();
return ( in_array( $name, array_keys( $attributes ) ) && in_array( $value, $variation_attributes[ $attributes[ $name ]['name'] ] ) );
return ( in_array( $name, array_keys( $attributes ), true ) && in_array( $value, $variation_attributes[ $attributes[ $name ]['name'] ], true ) );
} else {
return false;
}

View File

@ -982,7 +982,6 @@ if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
if ( ! wc_get_loop_prop( 'is_paginated' ) || ! woocommerce_products_will_display() ) {
return;
}
$orderby = isset( $_GET['orderby'] ) ? wc_clean( wp_unslash( $_GET['orderby'] ) ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) ); // WPCS: sanitization ok, input var ok, CSRF ok.
$show_default_orderby = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
$catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', array(
'menu_order' => __( 'Default sorting', 'woocommerce' ),
@ -993,12 +992,13 @@ if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
'price-desc' => __( 'Sort by price: high to low', 'woocommerce' ),
) );
$default_orderby = wc_get_loop_prop( 'is_search' ) ? 'relevance' : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby', '' ) );
$orderby = isset( $_GET['orderby'] ) ? wc_clean( wp_unslash( $_GET['orderby'] ) ) : $default_orderby; // WPCS: sanitization ok, input var ok, CSRF ok.
if ( wc_get_loop_prop( 'is_search' ) ) {
$catalog_orderby_options = array_merge( array( 'relevance' => __( 'Relevance', 'woocommerce' ) ), $catalog_orderby_options );
unset( $catalog_orderby_options['menu_order'] );
if ( 'menu_order' === $orderby ) {
$orderby = 'relevance';
}
}
if ( ! $show_default_orderby ) {
@ -1009,6 +1009,10 @@ if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) {
unset( $catalog_orderby_options['rating'] );
}
if ( ! array_key_exists( $orderby, $catalog_orderby_options ) ) {
$orderby = current( array_keys( $catalog_orderby_options ) );
}
wc_get_template( 'loop/orderby.php', array(
'catalog_orderby_options' => $catalog_orderby_options,
'orderby' => $orderby,
@ -1995,7 +1999,7 @@ if ( ! function_exists( 'woocommerce_get_product_subcategories' ) ) {
*/
function woocommerce_get_product_subcategories( $parent_id = 0 ) {
$parent_id = absint( $parent_id );
$product_categories = wp_cache_get( 'product-categories-' . $parent_id, 'product_cat' );
$product_categories = wp_cache_get( 'product-category-hierarchy-' . $parent_id, 'product_cat' );
if ( false === $product_categories ) {
// NOTE: using child_of instead of parent - this is not ideal but due to a WP bug ( https://core.trac.wordpress.org/ticket/15626 ) pad_counts won't work.
@ -2007,7 +2011,8 @@ if ( ! function_exists( 'woocommerce_get_product_subcategories' ) ) {
'taxonomy' => 'product_cat',
'pad_counts' => 1,
) ) );
wp_cache_set( 'product-categories-' . $parent_id, $product_categories, 'product_cat' );
wp_cache_set( 'product-category-hierarchy-' . $parent_id, $product_categories, 'product_cat' );
}
if ( apply_filters( 'woocommerce_product_subcategories_hide_empty', true ) ) {
@ -2326,8 +2331,18 @@ if ( ! function_exists( 'woocommerce_form_field' ) ) {
$field = sprintf( $field_container, $container_class, $container_id, $field_html );
}
/**
* Filter by type.
*/
$field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value );
/**
* General filter on form fields.
*
* @since 3.4.0
*/
$field = apply_filters( 'woocommerce_form_field', $field, $key, $args, $value );
if ( $args['return'] ) {
return $field;
} else {

View File

@ -369,13 +369,22 @@ class WC_Widget_Layered_Nav extends WC_Widget {
// We have a query - let's see if cached results of this query already exist.
$query_hash = md5( $query );
$cached_counts = (array) get_transient( 'wc_layered_nav_counts' );
// Maybe store a transient of the count values.
$cache = apply_filters( 'woocommerce_layered_nav_count_maybe_cache', true );
if ( true === $cache ) {
$cached_counts = (array) get_transient( 'wc_layered_nav_counts_' . $taxonomy );
} else {
$cached_counts = array();
}
if ( ! isset( $cached_counts[ $query_hash ] ) ) {
$results = $wpdb->get_results( $query, ARRAY_A ); // @codingStandardsIgnoreLine
$counts = array_map( 'absint', wp_list_pluck( $results, 'term_count', 'term_count_id' ) );
$cached_counts[ $query_hash ] = $counts;
set_transient( 'wc_layered_nav_counts', $cached_counts, DAY_IN_SECONDS );
if ( true === $cache ) {
set_transient( 'wc_layered_nav_counts_' . $taxonomy, $cached_counts, DAY_IN_SECONDS );
}
}
return array_map( 'absint', (array) $cached_counts[ $query_hash ] );

45
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "woocommerce",
"version": "3.1.0",
"version": "3.3.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1334,9 +1334,9 @@
}
},
"chromedriver": {
"version": "2.33.2",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.33.2.tgz",
"integrity": "sha512-etnQeM8Mqiys50ZB4IiuNqeB1WS2/EKFhVXwkPQ1qjzKMMAJUyrLjaRUcoZoHrbjGscnhBrWkRR+p3zcTGMhDg==",
"version": "2.36.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.36.0.tgz",
"integrity": "sha512-Lq2HrigCJ4RVdIdCmchenv1rVrejNSJ7EUCQojycQo12ww3FedQx4nb+GgTdqMhjbOMTqq5+ziaiZlrEN2z1gQ==",
"dev": true,
"requires": {
"del": "3.0.0",
@ -6032,9 +6032,9 @@
"dev": true
},
"url-join": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.2.tgz",
"integrity": "sha1-wHJ1aWetJLi1nldBVRyqx49QuLc=",
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
"integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
"dev": true
},
"user-home": {
@ -6086,9 +6086,9 @@
}
},
"wc-e2e-page-objects": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/wc-e2e-page-objects/-/wc-e2e-page-objects-0.5.0.tgz",
"integrity": "sha1-7oAQnDRqn9HE4NUbi7h/oeHDcMs=",
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/wc-e2e-page-objects/-/wc-e2e-page-objects-0.9.0.tgz",
"integrity": "sha512-oGOLFAN+lNULLylZkhNIMGT0n5hO+elpcVkpNQcT4HgWfS1yPoGfeWgrfAX33b4ZGVlpViv78Fj3LM5TciXVHw==",
"dev": true,
"requires": {
"lodash": "4.17.4",
@ -6174,7 +6174,22 @@
"selenium-webdriver": "3.6.0",
"slugs": "0.1.3",
"temp": "0.8.3",
"url-join": "2.0.2"
"url-join": "2.0.5"
},
"dependencies": {
"chromedriver": {
"version": "2.33.2",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.33.2.tgz",
"integrity": "sha512-etnQeM8Mqiys50ZB4IiuNqeB1WS2/EKFhVXwkPQ1qjzKMMAJUyrLjaRUcoZoHrbjGscnhBrWkRR+p3zcTGMhDg==",
"dev": true,
"requires": {
"del": "3.0.0",
"extract-zip": "1.6.6",
"kew": "0.7.0",
"mkdirp": "0.5.1",
"request": "2.83.0"
}
}
}
},
"wrap-ansi": {
@ -6209,13 +6224,13 @@
"dev": true,
"requires": {
"sax": "1.2.4",
"xmlbuilder": "9.0.4"
"xmlbuilder": "9.0.7"
}
},
"xmlbuilder": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz",
"integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=",
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
"dev": true
},
"xtend": {

View File

@ -26,7 +26,7 @@
"babel-preset-stage-2": "^6.13.0",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"chromedriver": "^2.33.0",
"chromedriver": "^2.36.0",
"config": "^1.24.0",
"cross-env": "~5.1.1",
"grunt": "~1.0.1",

View File

@ -37,10 +37,11 @@
<exclude name="WordPress.VIP.RestrictedFunctions" />
<exclude name="WordPress.VIP.RestrictedVariables.user_meta__wpdb__usermeta" />
<exclude name="WordPress.VIP.PostsPerPage.posts_per_page_posts_per_page" />
<exclude name="WordPress.VIP.RestrictedVariables.cache_constraints___COOKIE" />
</rule>
<rule ref="WordPress.VIP.ValidatedSanitizedInput">
<properties>
<property name="customSanitizingFunctions" type="array" value="wc_clean,wc_sanitize_tooltip,wc_format_decimal,wc_stock_amount,wc_sanitize_permalink" />
<property name="customSanitizingFunctions" type="array" value="wc_clean,wc_sanitize_tooltip,wc_format_decimal,wc_stock_amount,wc_sanitize_permalink,wc_sanitize_textarea" />
</properties>
</rule>
<rule ref="WordPress.XSS.EscapeOutput">

View File

@ -10,15 +10,12 @@
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
* @version 3.3.0
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce/Templates
* @version 3.4.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
if ( $max_value && $min_value === $max_value ) {
?>
@ -27,10 +24,25 @@ if ( $max_value && $min_value === $max_value ) {
</div>
<?php
} else {
/* translators: %s: Quantity. */
$labelledby = ! empty( $args['product_name'] ) ? sprintf( __( '%s quantity', 'woocommerce' ), strip_tags( $args['product_name'] ) ) : '';
?>
<div class="quantity">
<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php esc_html_e( 'Quantity', 'woocommerce' ); ?></label>
<input type="number" id="<?php echo esc_attr( $input_id ); ?>" class="input-text qty text" step="<?php echo esc_attr( $step ); ?>" min="<?php echo esc_attr( $min_value ); ?>" max="<?php echo esc_attr( 0 < $max_value ? $max_value : '' ); ?>" name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $input_value ); ?>" title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) ?>" size="4" pattern="<?php echo esc_attr( $pattern ); ?>" inputmode="<?php echo esc_attr( $inputmode ); ?>" aria-labelledby="<?php echo ! empty( $args['product_name'] ) ? sprintf( esc_attr__( '%s quantity', 'woocommerce' ), $args['product_name'] ) : ''; ?>" />
<input
type="number"
id="<?php echo esc_attr( $input_id ); ?>"
class="input-text qty text"
step="<?php echo esc_attr( $step ); ?>"
min="<?php echo esc_attr( $min_value ); ?>"
max="<?php echo esc_attr( 0 < $max_value ? $max_value : '' ); ?>"
name="<?php echo esc_attr( $input_name ); ?>"
value="<?php echo esc_attr( $input_value ); ?>"
title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ); ?>"
size="4"
pattern="<?php echo esc_attr( $pattern ); ?>"
inputmode="<?php echo esc_attr( $inputmode ); ?>"
aria-labelledby="<?php echo esc_attr( $labelledby ); ?>" />
</div>
<?php
}

View File

@ -9,7 +9,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
/**
* Test some discount logic which has caused issues in the past.
* Tickets:
* https://github.com/woocommerce/woocommerce/issues/10573
* https://github.com/woocommerce/woocommerce/issues/10573
* https://github.com/woocommerce/woocommerce/issues/10963
*
* Due to discounts being split amongst products in cart.
@ -162,11 +162,11 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
WC()->cart->empty_cart();
WC()->cart->remove_coupons();
$product = new WC_Product_Simple;
$product = new WC_Product_Simple();
$product->set_regular_price( 51.86 );
$product->save();
$coupon = new WC_Coupon;
$coupon = new WC_Coupon();
$coupon->set_code( 'testpercent' );
$coupon->set_discount_type( 'percent' );
$coupon->set_amount( 40 );
@ -263,24 +263,24 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
WC_Tax::_insert_tax_rate( $tax_rate );
// Create product.
$product = new WC_Product_Simple;
$product = new WC_Product_Simple();
$product->set_regular_price( '9.99' );
$product->save();
// Create coupons.
$ten_coupon = new WC_Coupon;
$ten_coupon = new WC_Coupon();
$ten_coupon->set_code( '10off' );
$ten_coupon->set_discount_type( 'percent' );
$ten_coupon->set_amount( 10 );
$ten_coupon->save();
$half_coupon = new WC_Coupon;
$half_coupon = new WC_Coupon();
$half_coupon->set_code( '50off' );
$half_coupon->set_discount_type( 'percent' );
$half_coupon->set_amount( 50 );
$half_coupon->save();
$full_coupon = new WC_Coupon;
$full_coupon = new WC_Coupon();
$full_coupon->set_code( '100off' );
$full_coupon->set_discount_type( 'percent' );
$full_coupon->set_amount( 100 );
@ -374,6 +374,125 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
update_option( 'woocommerce_calc_taxes', 'no' );
}
/**
* Test cart calculations when out of base location with no matching taxes and using inclusive taxes and discounts.
*
* @see GitHub issue #19390.
* @since 3.3
*/
public function test_out_of_base_discounts_inclusive_tax_no_oob_tax() {
global $wpdb;
// Set up tax options.
update_option( 'woocommerce_prices_include_tax', 'yes' );
update_option( 'woocommerce_calc_taxes', 'yes' );
update_option( 'woocommerce_default_country', 'GB' );
update_option( 'woocommerce_default_customer_address', 'base' );
update_option( 'woocommerce_tax_based_on', 'shipping' );
// 20% tax for GB.
$tax_rate = array(
'tax_rate_country' => 'GB',
'tax_rate_state' => '',
'tax_rate' => '20.0000',
'tax_rate_name' => 'VAT',
'tax_rate_priority' => '1',
'tax_rate_compound' => '0',
'tax_rate_shipping' => '0',
'tax_rate_order' => '1',
'tax_rate_class' => '',
);
WC_Tax::_insert_tax_rate( $tax_rate );
// 0% tax everywhere else.
$tax_rate = array(
'tax_rate_country' => '',
'tax_rate_state' => '',
'tax_rate' => '0.0000',
'tax_rate_name' => 'TAX',
'tax_rate_priority' => '1',
'tax_rate_compound' => '0',
'tax_rate_shipping' => '0',
'tax_rate_order' => '1',
'tax_rate_class' => '',
);
WC_Tax::_insert_tax_rate( $tax_rate );
// Create product.
$product = new WC_Product_Simple();
$product->set_regular_price( '24.99' );
$product->save();
// Create coupon.
$ten_coupon = new WC_Coupon();
$ten_coupon->set_code( '10off' );
$ten_coupon->set_discount_type( 'percent' );
$ten_coupon->set_amount( 10 );
$ten_coupon->save();
$half_coupon = new WC_Coupon();
$half_coupon->set_code( '50off' );
$half_coupon->set_discount_type( 'percent' );
$half_coupon->set_amount( 50 );
$half_coupon->save();
$full_coupon = new WC_Coupon();
$full_coupon->set_code( '100off' );
$full_coupon->set_discount_type( 'percent' );
$full_coupon->set_amount( 100 );
$full_coupon->save();
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_shipping' ) );
WC()->cart->add_to_cart( $product->get_id(), 1 );
// Test out of store location with no coupon.
WC()->cart->calculate_totals();
$this->assertEquals( '20.83', wc_format_decimal( WC()->cart->get_subtotal(), 2 ) );
$this->assertEquals( '0.00', wc_format_decimal( WC()->cart->get_discount_total(), 2 ) );
$this->assertEquals( '0.00', wc_format_decimal( WC()->cart->get_total_tax(), 2 ) );
$this->assertEquals( '20.83', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ) );
// Test out of store location with 10% coupon.
WC()->cart->add_discount( $ten_coupon->get_code() );
WC()->cart->calculate_totals();
$this->assertEquals( '20.83', wc_format_decimal( WC()->cart->get_subtotal(), 2 ) );
$this->assertEquals( '2.08', wc_format_decimal( WC()->cart->get_discount_total(), 2 ) );
$this->assertEquals( '0.00', wc_format_decimal( WC()->cart->get_total_tax(), 2 ) );
$this->assertEquals( '18.75', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ) );
WC()->cart->remove_coupons();
// Test out of store location with 50% coupon.
WC()->cart->add_discount( $half_coupon->get_code() );
WC()->cart->calculate_totals();
$this->assertEquals( '20.83', wc_format_decimal( WC()->cart->get_subtotal(), 2 ) );
$this->assertEquals( '10.41', wc_format_decimal( WC()->cart->get_discount_total(), 2 ) );
$this->assertEquals( '0.00', wc_format_decimal( WC()->cart->get_total_tax(), 2 ) );
$this->assertEquals( '10.42', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ) );
WC()->cart->remove_coupons();
// Test out of store location with 100% coupon.
WC()->cart->add_discount( $full_coupon->get_code() );
WC()->cart->calculate_totals();
$this->assertEquals( '20.83', wc_format_decimal( WC()->cart->get_subtotal(), 2 ) );
$this->assertEquals( '20.83', wc_format_decimal( WC()->cart->get_discount_total(), 2 ), 'Discount total out of base' );
$this->assertEquals( '0.00', wc_format_decimal( WC()->cart->get_total_tax(), 2 ) );
$this->assertEquals( '0.00', wc_format_decimal( WC()->cart->get_total( 'edit' ), 2 ) );
// Clean up.
WC()->cart->empty_cart();
WC()->cart->remove_coupons();
remove_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_shipping' ) );
WC_Helper_Product::delete_product( $product->get_id() );
WC_Helper_Coupon::delete_coupon( $ten_coupon->get_id() );
WC_Helper_Coupon::delete_coupon( $half_coupon->get_id() );
WC_Helper_Coupon::delete_coupon( $full_coupon->get_id() );
$wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates" );
$wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations" );
update_option( 'woocommerce_prices_include_tax', 'no' );
update_option( 'woocommerce_calc_taxes', 'no' );
}
/**
* Helper that can be hooked to a filter to force the customer's shipping country to be GB.
*
@ -443,7 +562,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
}
// Create the product and add it to the cart.
$product = new WC_Product_Simple;
$product = new WC_Product_Simple();
$product->set_regular_price( '149.14' );
$product->save();
WC()->cart->add_to_cart( $product->get_id(), 1 );
@ -503,11 +622,11 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
// Add 2 products whose retail prices (inc tax) are: £65, £50.
// Their net prices are therefore: £54.1666667 and £41.6666667.
$product1 = new WC_Product_Simple;
$product1 = new WC_Product_Simple();
$product1->set_regular_price( '54.1666667' );
$product1->save();
$product2 = new WC_Product_Simple;
$product2 = new WC_Product_Simple();
$product2->set_regular_price( '41.6666667' );
$product2->save();
@ -1191,7 +1310,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
*/
public function test_add_discount_code_id() {
$coupon = new WC_Coupon;
$coupon = new WC_Coupon();
$coupon->set_code( 'test' );
$coupon->set_amount( 100 );
$coupon->save();

View File

@ -1,6 +1,7 @@
<?php
/**
* Data Store Tests: Tests WC_Products's WC_Data_Store.
*
* @package WooCommerce\Tests\Product
* @since 3.0.0
*/
@ -11,7 +12,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_product_store_loads() {
public function test_product_store_loads() {
$product_store = new WC_Data_Store( 'product' );
$this->assertTrue( is_callable( array( $product_store, 'read' ) ) );
$this->assertEquals( 'WC_Product_Data_Store_CPT', $product_store->get_current_class_name() );
@ -22,24 +23,24 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_product_create() {
$product = new WC_Product;
$product->set_regular_price( 42 );
$product->set_name( 'My Product' );
$product->save();
public function test_product_create() {
$product = new WC_Product();
$product->set_regular_price( 42 );
$product->set_name( 'My Product' );
$product->save();
$read_product = new WC_Product( $product->get_id() );
$read_product = new WC_Product( $product->get_id() );
$this->assertEquals( '42', $read_product->get_regular_price() );
$this->assertEquals( 'My Product', $read_product->get_name() );
}
$this->assertEquals( '42', $read_product->get_regular_price() );
$this->assertEquals( 'My Product', $read_product->get_name() );
}
/**
* Test reading a product.
*
* @since 3.0.0
*/
function test_product_read() {
public function test_product_read() {
$product = WC_Helper_Product::create_simple_product();
$product = new WC_Product( $product->get_id() );
@ -51,7 +52,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_product_update() {
public function test_product_update() {
$product = WC_Helper_Product::create_simple_product();
$this->assertEquals( '10', $product->get_regular_price() );
@ -70,7 +71,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_product_trash() {
public function test_product_trash() {
$product = WC_Helper_Product::create_simple_product();
$product->delete();
$this->assertEquals( 'trash', $product->get_status() );
@ -81,7 +82,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_product_delete() {
public function test_product_delete() {
$product = WC_Helper_Product::create_simple_product();
$product->delete( true );
$this->assertEquals( 0, $product->get_id() );
@ -92,35 +93,36 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_grouped_product_create() {
public function test_grouped_product_create() {
$simple_product = WC_Helper_Product::create_simple_product();
$product = new WC_Product_Grouped;
$product = new WC_Product_Grouped();
$product->set_children( array( $simple_product->get_id() ) );
$product->set_name( 'My Grouped Product' );
$product->save();
$read_product = new WC_Product_Grouped( $product->get_id() );
$this->assertEquals( 'My Grouped Product', $read_product->get_name() );
$this->assertEquals( array( $simple_product->get_id() ), $read_product->get_children() );
}
}
/**
* Test getting / reading an grouped product.
*
* @since 3.0.0
*/
function test_grouped_product_read() {
$product = WC_Helper_Product::create_grouped_product();
public function test_grouped_product_read() {
$product = WC_Helper_Product::create_grouped_product();
$read_product = new WC_Product_Grouped( $product->get_id() );
$this->assertEquals( 'Dummy Grouped Product', $read_product->get_name() );
$this->assertEquals( 2, count( $read_product->get_children() ) );
}
/**
* Test updating an grouped product.
*
* @since 3.0.0
*/
function test_grouped_product_update() {
$product = WC_Helper_Product::create_grouped_product();
public function test_grouped_product_update() {
$product = WC_Helper_Product::create_grouped_product();
$simple_product = WC_Helper_Product::create_simple_product();
$this->assertEquals( 'Dummy Grouped Product', $product->get_name() );
$this->assertEquals( 2, count( $product->get_children() ) );
@ -140,21 +142,21 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_external_product_create() {
$product = new WC_Product_External;
$product->set_regular_price( 42 );
$product->set_button_text( 'Test CRUD' );
$product->set_product_url( 'http://automattic.com' );
$product->set_name( 'My External Product' );
$product->save();
public function test_external_product_create() {
$product = new WC_Product_External();
$product->set_regular_price( 42 );
$product->set_button_text( 'Test CRUD' );
$product->set_product_url( 'http://automattic.com' );
$product->set_name( 'My External Product' );
$product->save();
$read_product = new WC_Product_External( $product->get_id() );
$read_product = new WC_Product_External( $product->get_id() );
$this->assertEquals( '42', $read_product->get_regular_price() );
$this->assertEquals( 'Test CRUD', $read_product->get_button_text() );
$this->assertEquals( 'http://automattic.com', $read_product->get_product_url() );
$this->assertEquals( 'My External Product', $read_product->get_name() );
}
$this->assertEquals( '42', $read_product->get_regular_price() );
$this->assertEquals( 'Test CRUD', $read_product->get_button_text() );
$this->assertEquals( 'http://automattic.com', $read_product->get_product_url() );
$this->assertEquals( 'My External Product', $read_product->get_name() );
}
/**
* Test getting / reading an external product. Make sure both our external
@ -162,7 +164,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_external_product_read() {
public function test_external_product_read() {
$product = WC_Helper_Product::create_external_product();
$product = new WC_Product_External( $product->get_id() );
@ -176,7 +178,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_external_product_update() {
public function test_external_product_update() {
$product = WC_Helper_Product::create_external_product();
$this->assertEquals( 'Buy external product', $product->get_button_text() );
@ -199,7 +201,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
* @since 3.0.0
*/
public function test_variable_read() {
$product = WC_Helper_Product::create_variation_product();
$product = WC_Helper_Product::create_variation_product();
$children = $product->get_children();
// Test sale prices too
@ -213,8 +215,10 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$expected_prices['price'][ $children[0] ] = 8.00;
$expected_prices['price'][ $children[1] ] = 15.00;
$expected_prices['regular_price'][ $children[0] ] = 10.00;
$expected_prices['regular_price'][ $children[1] ] = 15.00;
$expected_prices['sale_price'][ $children[0] ] = 8.00;
$expected_prices['sale_price'][ $children[1] ] = 15.00;
@ -230,8 +234,8 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_variables_and_variations() {
$product = new WC_Product_Variable;
public function test_variables_and_variations() {
$product = new WC_Product_Variable();
$product->set_name( 'Variable Product' );
$attribute = new WC_Product_Attribute();
@ -246,7 +250,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$this->assertEquals( 'Variable Product', $product->get_name() );
$variation = new WC_Product_Variation;
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_regular_price( 10 );
$variation->set_sku( 'CRUD DUMMY SKU VARIABLE GREEN' );
@ -260,14 +264,14 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$this->assertEquals( 'CRUD DUMMY SKU VARIABLE GREEN', $variation->get_sku() );
$this->assertEquals( 10, $variation->get_price() );
$product = new WC_Product_Variable( $product->get_id() );
$product = new WC_Product_Variable( $product->get_id() );
$children = $product->get_children();
$this->assertEquals( $variation->get_id(), $children[0] );
$expected_attributes = array( 'pa_color' => array( 'green' ) );
$this->assertEquals( $expected_attributes, $product->get_variation_attributes() );
$variation_2 = new WC_Product_Variation;
$variation_2 = new WC_Product_Variation();
$variation_2->set_parent_id( $product->get_id() );
$variation_2->set_regular_price( 10 );
$variation_2->set_sku( 'CRUD DUMMY SKU VARIABLE RED' );
@ -281,7 +285,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$this->assertEquals( 'CRUD DUMMY SKU VARIABLE RED', $variation_2->get_sku() );
$this->assertEquals( 10, $variation_2->get_price() );
$product = new WC_Product_Variable( $product->get_id() );
$product = new WC_Product_Variable( $product->get_id() );
$children = $product->get_children();
$this->assertEquals( $variation_2->get_id(), $children[1] );
$this->assertEquals( 2, count( $children ) );
@ -295,10 +299,13 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$variation_2->save();
$product = new WC_Product_Variable( $product->get_id() );
$expected_prices['price'][ $children[0] ] = 10.00;
$expected_prices['price'][ $children[1] ] = 9.99;
$expected_prices['regular_price'][ $children[0] ] = 10.00;
$expected_prices['regular_price'][ $children[1] ] = 15.00;
$expected_prices['sale_price'][ $children[0] ] = 10.00;
$expected_prices['sale_price'][ $children[1] ] = 9.99;
@ -310,9 +317,9 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$product->delete();
}
function test_variation_save_attributes() {
public function test_variation_save_attributes() {
// Create a variable product with a color attribute.
$product = new WC_Product_Variable;
$product = new WC_Product_Variable();
$attribute = new WC_Product_Attribute();
$attribute->set_id( 0 );
@ -325,7 +332,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$product->save();
// Create a new variation with the color 'green'.
$variation = new WC_Product_Variation;
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_attributes( array( 'color' => 'green' ) );
$variation->set_status( 'private' );
@ -347,46 +354,46 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
public function test_save_default_attributes() {
// Create a variable product with sold individually.
$product = new WC_Product_Variable;
$product = new WC_Product_Variable();
$product->save();
$product_id = $product->get_id();
// Save with a set of FALSE equivalents and some values we expect to come through as true. We should see
// string types with a value of '0' making it through filtration.
$test_object = new stdClass();
$test_object = new stdClass();
$test_object->property = '12345';
$product->set_default_attributes( array(
'sample-attribute-false-0' => 0,
'sample-attribute-false-1' => false,
'sample-attribute-false-2' => '',
'sample-attribute-false-3' => null,
'sample-attribute-true-0' => '0',
'sample-attribute-true-1' => 1,
'sample-attribute-true-2' => 'true',
'sample-attribute-true-3' => 'false',
'sample-attribute-true-4' => array( 'exists' => 'false' ),
'sample-attribute-true-0' => '0',
'sample-attribute-true-1' => 1,
'sample-attribute-true-2' => 'true',
'sample-attribute-true-3' => 'false',
'sample-attribute-true-4' => array( 'exists' => 'false' ),
'sample-attribute-false-4' => $test_object,
));
$product->save();
// Revive the product from the database and analyze results
$product = wc_get_product( $product_id );
$product = wc_get_product( $product_id );
$default_attributes = $product->get_default_attributes();
$this->assertEquals( $default_attributes, array(
'sample-attribute-true-0' => '0',
'sample-attribute-true-1' => 1,
'sample-attribute-true-2' => 'true',
'sample-attribute-true-3' => 'false',
'sample-attribute-true-4' => array( 'exists' => 'false' ),
'sample-attribute-true-0' => '0',
'sample-attribute-true-1' => 1,
'sample-attribute-true-2' => 'true',
'sample-attribute-true-3' => 'false',
'sample-attribute-true-4' => array( 'exists' => 'false' ),
'sample-attribute-false-4' => $test_object,
));
}
function test_variable_child_has_dimensions() {
$product = new WC_Product_Variable;
public function test_variable_child_has_dimensions() {
$product = new WC_Product_Variable();
$product->save();
$variation = new WC_Product_variation;
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_width( 10 );
$variation->save();
@ -398,11 +405,11 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$this->assertTrue( $store->child_has_dimensions( $product ) );
}
function test_variable_child_has_dimensions_no_dimensions() {
$product = new WC_Product_Variable;
public function test_variable_child_has_dimensions_no_dimensions() {
$product = new WC_Product_Variable();
$product->save();
$variation = new WC_Product_variation;
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->save();
@ -413,7 +420,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$this->assertFalse( $store->child_has_dimensions( $product ) );
}
function test_get_on_sale_products() {
public function test_get_on_sale_products() {
$product_store = new WC_Product_Data_Store_CPT();
$sale_product = WC_Helper_Product::create_simple_product();
@ -434,7 +441,7 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$future_sale_product->set_price( $future_sale_product->get_regular_price() );
$future_sale_product->save();
$sale_products = $product_store->get_on_sale_products();
$sale_products = $product_store->get_on_sale_products();
$sale_product_ids = wp_list_pluck( $sale_products, 'id' );
$this->assertContains( $sale_product->get_id(), $sale_product_ids );
@ -442,64 +449,71 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
$this->assertNotContains( $future_sale_product->get_id(), $sale_product_ids );
}
function test_generate_product_title() {
$product = new WC_Product;
public function test_generate_product_title() {
$product = new WC_Product();
$product->set_name( 'Test Product' );
$product->save();
$one_attribute_variation = new WC_Product_Variation;
$one_attribute_variation = new WC_Product_Variation();
$one_attribute_variation->set_parent_id( $product->get_id() );
$one_attribute_variation->set_attributes( array( 'color' => 'Green' ) );
$one_attribute_variation->save();
$two_attribute_variation = new WC_Product_Variation;
$two_attribute_variation = new WC_Product_Variation();
$two_attribute_variation->set_parent_id( $product->get_id() );
$two_attribute_variation->set_attributes( array( 'color' => 'Green', 'size' => 'Large' ) );
$two_attribute_variation->set_attributes( array(
'color' => 'Green',
'size' => 'Large',
) );
$two_attribute_variation->save();
$multiword_attribute_variation = new WC_Product_Variation;
$multiword_attribute_variation = new WC_Product_Variation();
$multiword_attribute_variation->set_parent_id( $product->get_id() );
$multiword_attribute_variation->set_attributes( array( 'color' => 'Green', 'mounting-plate' => 'galaxy-s6', 'support' => 'one-year' ) );
$multiword_attribute_variation->set_attributes( array(
'color' => 'Green',
'mounting-plate' => 'galaxy-s6',
'support' => 'one-year',
) );
$multiword_attribute_variation->save();
// Check the one attribute variation title.
$this->assertEquals( "Test Product - Green", $one_attribute_variation->get_name() );
$this->assertEquals( 'Test Product - Green', $one_attribute_variation->get_name() );
// Check the two attribute variation title.
$this->assertEquals( "Test Product - Green, Large", $two_attribute_variation->get_name() );
$this->assertEquals( 'Test Product - Green, Large', $two_attribute_variation->get_name() );
// Check the variation with a multiword attribute name.
$this->assertEquals( "Test Product", $multiword_attribute_variation->get_name() );
$this->assertEquals( 'Test Product', $multiword_attribute_variation->get_name() );
}
function test_generate_product_title_disable() {
public function test_generate_product_title_disable() {
add_filter( 'woocommerce_product_variation_title_include_attributes', '__return_false' );
$product = new WC_Product;
$product = new WC_Product();
$product->set_name( 'Test Product' );
$product->save();
$variation = new WC_Product_Variation;
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_attributes( array( 'color' => 'green' ) );
$variation->save();
$loaded_variation = wc_get_product( $variation->get_id() );
$this->assertEquals( "Test Product", $loaded_variation->get_name() );
$this->assertEquals( 'Test Product', $loaded_variation->get_name() );
}
function test_generate_product_title_no_attributes() {
$product = new WC_Product;
public function test_generate_product_title_no_attributes() {
$product = new WC_Product();
$product->set_name( 'Test Product' );
$product->save();
$variation = new WC_Product_Variation;
$variation = new WC_Product_Variation();
$variation->set_parent_id( $product->get_id() );
$variation->set_attributes( array() );
$variation->save();
$loaded_variation = wc_get_product( $variation->get_id() );
$this->assertEquals( "Test Product", $loaded_variation->get_name() );
$this->assertEquals( 'Test Product', $loaded_variation->get_name() );
}
/**
@ -507,8 +521,8 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
* https://github.com/woocommerce/woocommerce/issues/13960
* @since 3.0.1
*/
function test_product_meta_save_post() {
$product = new WC_Product;
public function test_product_meta_save_post() {
$product = new WC_Product();
$product->set_name( 'Test Product' );
$product->save();
update_post_meta( $product->get_id(), '_test2', 'default' ); // this is the value we don't want to get back.
@ -530,4 +544,85 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case {
remove_action( 'save_post', array( 'WC_Helper_Product', 'save_post_test_update_meta_data_direct' ) );
}
/**
* Test Product search functionality.
*
* @return void
*/
public function test_search_products() {
// Create some products to search for.
$product = new WC_Product();
$product->set_regular_price( 42 );
$product->set_name( 'Blue widget' );
$product->set_sku( 'blue-widget-1' );
$product->set_description( "You bet I'm agitated! I may be surrounded by insanity, but I am not insane. I suggest you drop it, Mr. Data. Not if I weaken first. Earl Grey tea, watercress sandwiches... and Bularian canapés? Are you up for promotion? and attack the Romulans. Yesterday I did not know how to eat gagh." );
$product->save();
$product2 = new WC_Product();
$product2->set_regular_price( 42 );
$product2->set_name( 'Red widget' );
$product2->set_sku( 'red-widget-1' );
$product2->set_description( "and attack the Romulans. Fear is the true enemy, the only enemy. The game's not big enough unless it scares you a little. What? We're not at all alike! Now, how the hell do we defeat an enemy that knows us better than we know ourselves? Mr. Worf, you do remember how to fire phasers?" );
$product2->save();
$product3 = new WC_Product();
$product3->set_regular_price( 42 );
$product3->set_name( 'Green widget' );
$product3->set_sku( 'green-widget-1' );
$product3->set_description( 'For an android with no feelings, he sure managed to evoke them in others. Then maybe you should consider this: if anything happens to them, Starfleet is going to want a full investigation. We have a saboteur aboard.' );
$product3->save();
$product4 = new WC_Product();
$product4->set_regular_price( 42 );
$product4->set_name( 'Another green widget' );
$product4->set_sku( 'green-widget-2' );
$product4->set_description( 'For an android with no feelings, he sure managed to evoke them in others. Then maybe you should consider this: if anything happens to them, Starfleet is going to want a full investigation. We have a saboteur aboard.' );
$product4->save();
$data_store = WC_Data_Store::load( 'product' );
// Search some things :)
$results = $data_store->search_products( 'green', '', true, true );
$this->assertNotContains( $product->get_id(), $results );
$this->assertNotContains( $product2->get_id(), $results );
$this->assertContains( $product3->get_id(), $results );
$this->assertContains( $product4->get_id(), $results );
$results = $data_store->search_products( 'blue-widget-1', '', true, true );
$this->assertContains( $product->get_id(), $results );
$this->assertNotContains( $product2->get_id(), $results );
$this->assertNotContains( $product3->get_id(), $results );
$this->assertNotContains( $product4->get_id(), $results );
$results = $data_store->search_products( 'blue-widget-1 OR green-widget', '', true, true );
$this->assertContains( $product->get_id(), $results );
$this->assertNotContains( $product2->get_id(), $results );
$this->assertContains( $product3->get_id(), $results );
$this->assertContains( $product4->get_id(), $results );
$results = $data_store->search_products( '"green widget"', '', true, true );
$this->assertNotContains( $product->get_id(), $results );
$this->assertNotContains( $product2->get_id(), $results );
$this->assertContains( $product3->get_id(), $results );
$this->assertContains( $product4->get_id(), $results );
$results = $data_store->search_products( 'Another widget', '', true, true );
$this->assertNotContains( $product->get_id(), $results );
$this->assertNotContains( $product2->get_id(), $results );
$this->assertNotContains( $product3->get_id(), $results );
$this->assertContains( $product4->get_id(), $results );
$results = $data_store->search_products( '"Fear is the true enemy"', '', true, true );
$this->assertNotContains( $product->get_id(), $results );
$this->assertContains( $product2->get_id(), $results );
$this->assertNotContains( $product3->get_id(), $results );
$this->assertNotContains( $product4->get_id(), $results );
// Clean up.
$product->delete();
$product2->delete();
$product3->delete();
$product4->delete();
}
}

View File

@ -14,7 +14,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
$shortcode = new WC_Shortcode_Products();
$expected = array(
'limit' => '-1',
'columns' => '3',
'columns' => '4',
'orderby' => 'title',
'order' => 'ASC',
'ids' => '',
@ -40,7 +40,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
) );
$expected2 = array(
'limit' => '-1',
'columns' => '3',
'columns' => '4',
'orderby' => 'id',
'order' => 'DESC',
'ids' => '',

View File

@ -125,4 +125,25 @@ class WC_Tests_Install extends WC_Unit_Test_Case {
$this->assertEquals( $tables, WC_Install::get_tables() );
}
/**
* Test - get tables should apply the woocommerce_install_get_tables filter.
*/
public function test_get_tables_enables_filter() {
$default = WC_Install::get_tables();
$added = $this->append_table_to_get_tables( array() );
add_filter( 'woocommerce_install_get_tables', array( $this, 'append_table_to_get_tables' ) );
$this->assertEquals( $added, array_values( array_diff( WC_Install::get_tables(), $default ) ) );
}
/**
* Filter callback for test_get_tables_enables_filter().
*/
public function append_table_to_get_tables( $tables ) {
$tables[] = 'some_table_name';
return $tables;
}
}

View File

@ -106,33 +106,33 @@ class WC_Tests_Validation extends WC_Unit_Test_Case {
}
/**
* Data provider for test_is_GB_postcode.
* Data provider for test_is_gb_postcode.
*
* @since 2.4
*/
public function data_provider_test_is_GB_postcode() {
public function data_provider_test_is_gb_postcode() {
return array(
array( true, WC_Validation::is_GB_postcode( 'AA9A 9AA' ) ),
array( true, WC_Validation::is_GB_postcode( 'A9A 9AA' ) ),
array( true, WC_Validation::is_GB_postcode( 'A9 9AA' ) ),
array( true, WC_Validation::is_GB_postcode( 'A99 9AA' ) ),
array( true, WC_Validation::is_GB_postcode( 'AA99 9AA' ) ),
array( true, WC_Validation::is_GB_postcode( 'BFPO 801' ) ),
array( false, WC_Validation::is_GB_postcode( '99999' ) ),
array( false, WC_Validation::is_GB_postcode( '9999 999' ) ),
array( false, WC_Validation::is_GB_postcode( '999 999' ) ),
array( false, WC_Validation::is_GB_postcode( '99 999' ) ),
array( false, WC_Validation::is_GB_postcode( '9A A9A' ) ),
array( true, WC_Validation::is_gb_postcode( 'AA9A 9AA' ) ),
array( true, WC_Validation::is_gb_postcode( 'A9A 9AA' ) ),
array( true, WC_Validation::is_gb_postcode( 'A9 9AA' ) ),
array( true, WC_Validation::is_gb_postcode( 'A99 9AA' ) ),
array( true, WC_Validation::is_gb_postcode( 'AA99 9AA' ) ),
array( true, WC_Validation::is_gb_postcode( 'BFPO 801' ) ),
array( false, WC_Validation::is_gb_postcode( '99999' ) ),
array( false, WC_Validation::is_gb_postcode( '9999 999' ) ),
array( false, WC_Validation::is_gb_postcode( '999 999' ) ),
array( false, WC_Validation::is_gb_postcode( '99 999' ) ),
array( false, WC_Validation::is_gb_postcode( '9A A9A' ) ),
);
}
/**
* Test is_GB_postcode().
* Test is_gb_postcode().
*
* @dataProvider data_provider_test_is_GB_postcode
* @dataProvider data_provider_test_is_gb_postcode
* @since 2.4
*/
public function test_is_GB_postcode( $assert, $values ) {
public function test_is_gb_postcode( $assert, $values ) {
$this->assertEquals( $assert, $values );
}