Merge remote-tracking branch 'woothemes/master'

This commit is contained in:
Job 2016-06-21 18:05:34 +02:00
commit b7f72481b6
79 changed files with 1719 additions and 1179 deletions

34
.codeclimate.yml Normal file
View File

@ -0,0 +1,34 @@
engines:
phpcodesniffer:
enabled: true
config:
standard: "WordPress"
eslint:
enabled: true
scss-lint:
enabled: true
duplication:
enabled: true
config:
languages:
- php
- javascript
exclude_paths:
- tests/*
- apigen/*
- dummy-data/*
- i18n/*
- includes/api/legacy/*
- includes/libraries/*
- includes/updates/*
- includes/gateways/simplify-commerce/*
- includes/shipping/legacy-*
- includes/wc-deprecated-functions.php
- includes/class-wc-legacy-api.php
- assets/js/accounting/**
- assets/js/jquery-*
- assets/js/prettyPhoto/*
- assets/js/round/*
- assets/js/select2/*
- assets/js/stupidtable/*
- assets/js/zeroclipboard/*

View File

@ -1,5 +1,25 @@
== Changelog ==
= 2.6.1 - 16/06/16 =
* Fix - Added missing localized format for line taxes in orders screen to prevent total miscalculation in manual orders.
* Fix - Improved the hour and time fields validation pattern on the orders screen.
* Fix - PayPal does not allow free products, but paid shipping. Workaround by sending shipping as a line item if it is the only cost.
* Fix - SKUs prop on products shortcode.
* Fix - Layered nav counts when term_id does not match term_taxonomy_id (before splitting).
* Fix - Fixed referer links from cart messages in WP 4.4.
* Fix - Fix the showing/hiding of panels when terms do not exist by using wc_get_product_types() for retrieving product types.
* Dev - content-product.php and content-product_cat.php contained the wrong version.
* Dev - Show "matching zone" notice on the frontend when shipping debug mode is on.
* Dev - Restored missing WC_Settings_API::init_form_fields() method to prevent potential errors in 3rd party gateways.
* Dev - API - Fixed returned data from product images (changed `title` to `name`).
* Dev - API - Fixed products schema for `grouped_products`.
* Dev - API - Fixed products attribute options when contains `,`.
* Tweak - Hide 'payment methods' screen if no methods support it.
* Tweak - If shipping method count changes, reset to default.
* Tweak - Avoid normalization of zone postcodes so wildcard matching can be performed on postcodes with spaces. E.g. SP1 *
* Tweak - Allow max_fee in addition to min_fee in flat rate costs fields.
* Tweak - Wrap order_schema_markup() output in hidden div in case script tag is stripped.
= 2.6.0 - 14/06/16 =
* Feature - Introduced Shipping Zone functionality, and re-usable instance based shipping methods.
* Feature - Tabbed "My Account" area.
@ -25,6 +45,7 @@
* Tweak - Ignore catalog visibility on products shortcode when specifying IDs or SKUs.
* Tweak - Added context to checkout error messages.
* Tweak - Added SKU field to grouped products.
* Tweak - Moved SKU field to inventory tab.
* Tweak - Support qty display in cart messages.
* Tweak - Hide min order amount field when not needed in shipping settings.
* Tweak - If shipping < 999.99, use 'shipping' arg when passing values to PayPal.

File diff suppressed because one or more lines are too long

View File

@ -2556,13 +2556,18 @@ table.wc-shipping-zones, table.wc-shipping-zone-methods, table.wc-shipping-class
}
.wc-backbone-modal .wc-shipping-zone-method-selector {
padding: 2px;
p {
margin-top: 0;
}
.wc-shipping-zone-method-description {
margin: 1em 0;
margin: .75em 1px 0;
line-height: 1.5em;
color: #999;
font-style: italic;
}
select {
width: 100%;
cursor: pointer;
}
}
@ -4941,7 +4946,7 @@ table.bar_chart {
}
.wc-backbone-modal-main {
padding-bottom: 51px;
padding-bottom: 55px;
header,
article {
@ -4950,23 +4955,23 @@ table.bar_chart {
}
.wc-backbone-modal-header {
height: 50px;
height: auto;
background: #fcfcfc;
padding: 0 50px 0 16px;
padding: 1em 1.5em;
border-bottom: 1px solid #ddd;
h1 {
margin: 0;
font-size: 18px;
font-weight: 700;
line-height: 50px;
line-height: 1.5em;
}
.modal-close-link {
cursor: pointer;
color: #777;
height: 50px;
width: 50px;
height: 54px;
width: 54px;
padding: 0;
position: absolute;
top: 0;
@ -5000,8 +5005,18 @@ table.bar_chart {
}
article {
padding: 10px 16px;
padding: 1.5em;
p {
margin: 1.5em 0;
}
p:first-child {
margin-top: 0;
}
p:last-child {
margin-bottom: 0;
}
.pagination {
padding: 10px 0 0;
text-align: center;
@ -5014,7 +5029,7 @@ table.bar_chart {
right: 0;
bottom: 0;
z-index: 100;
padding: 10px 16px;
padding: 1em 1.5em;
background: #fcfcfc;
border-top: 1px solid #dfdfdf;
box-shadow: 0 -4px 4px -4px rgba(0,0,0,0.1);

View File

@ -219,7 +219,7 @@
$method_list.prepend( '<li class="wc-shipping-zone-method"><a href="admin.php?page=wc-settings&amp;tab=shipping&amp;instance_id=' + instance_id + '" class="' + class_name + '">' + shipping_method.title + '</a></li>' );
} );
} else {
$method_list.prepend( '<li class="wc-shipping-zone-method">&ndash;</li>' );
$method_list.prepend( '<li class="wc-shipping-zone-method">' + data.strings.no_shipping_methods_offered + '</li>' );
}
},
onSubmit: function( event ) {

File diff suppressed because one or more lines are too long

View File

@ -85,18 +85,29 @@ jQuery( function( $ ) {
} else {
$( 'table.shop_table.cart' ).closest( 'form' ).replaceWith( $new_form );
$( 'table.shop_table.cart' ).closest( 'form' ).find( 'input[name="update_cart"]' ).prop( 'disabled', true );
$( '.cart_totals' ).replaceWith( $new_totals );
if ( $error.length > 0 ) {
show_notice( $error );
} else if ( $message.length > 0 ) {
show_notice( $message );
}
update_cart_totals_div( $new_totals );
}
$( document.body ).trigger( 'updated_wc_div' );
};
/**
* Update the .cart_totals div with a string of html.
*
* @param {String} html_str The HTML string with which to replace the div.
*/
var update_cart_totals_div = function( html_str ) {
$( '.cart_totals' ).replaceWith( html_str );
$( document.body ).trigger( 'updated_cart_totals' );
};
/**
* Clear previous notices and shows new one above form.
*
@ -158,7 +169,7 @@ jQuery( function( $ ) {
* @param {Object} evt The JQuery event.
*/
shipping_method_selected: function( evt ) {
var target = evt.target;
var target = evt.currentTarget;
var shipping_methods = {};
@ -173,9 +184,18 @@ jQuery( function( $ ) {
shipping_method: shipping_methods
};
$.post( get_url( 'update_shipping_method' ), data, function( response ) {
$( 'div.cart_totals' ).replaceWith( response );
$( document.body ).trigger( 'updated_shipping_method' );
$.ajax( {
type: 'post',
url: get_url( 'update_shipping_method' ),
data: data,
dataType: 'html',
success: function( response ) {
update_cart_totals_div( response );
},
complete: function() {
unblock( $( 'div.cart_totals' ) );
$( document.body ).trigger( 'updated_shipping_method' );
}
} );
},
@ -187,16 +207,16 @@ jQuery( function( $ ) {
shipping_calculator_submit: function( evt ) {
evt.preventDefault();
var $form = $( evt.target );
var $form = $( evt.currentTarget );
block( $form );
block( $( 'div.cart_totals' ) );
// Provide the submit button value because wc-form-handler expects it.
$( '<input />' ).attr( 'type', 'hidden' )
.attr( 'name', 'calc_shipping' )
.attr( 'value', 'x' )
.appendTo( $form );
.attr( 'name', 'calc_shipping' )
.attr( 'value', 'x' )
.appendTo( $form );
// Make call to actual form post URL.
$.ajax( {
@ -300,9 +320,11 @@ jQuery( function( $ ) {
$.ajax( {
url: get_url( 'get_cart_totals' ),
dataType: 'html',
success: function( response ) {
$( 'div.cart_totals' ).replaceWith( response );
$( document.body ).trigger( 'updated_cart_totals' );
success: function( response ) {
update_cart_totals_div( response );
},
complete: function() {
unblock( $( 'div.cart_totals' ) );
}
} );
},
@ -313,9 +335,7 @@ jQuery( function( $ ) {
* @param {Object} evt The JQuery event
*/
cart_submit: function( evt ) {
evt.preventDefault();
var $form = $( evt.target );
var $form = $( evt.currentTarget );
var $submit = $( document.activeElement );
var $clicked = $( 'input[type=submit][clicked=true]' );
@ -327,9 +347,11 @@ jQuery( function( $ ) {
}
if ( $clicked.is( '[name="update_cart"]' ) || $submit.is( 'input.qty' ) ) {
evt.preventDefault();
this.quantity_update( $form );
} else if ( $clicked.is( '[name="apply_coupon"]' ) || $submit.is( '#coupon_code' ) ) {
evt.preventDefault();
this.apply_coupon( $form );
}
},
@ -387,8 +409,8 @@ jQuery( function( $ ) {
evt.preventDefault();
var cart = this;
var $tr = $( evt.target ).parents( 'tr' );
var coupon = $( evt.target ).attr( 'data-coupon' );
var $tr = $( evt.currentTarget ).parents( 'tr' );
var coupon = $( evt.currentTarget ).attr( 'data-coupon' );
block( $tr.parents( 'table' ) );
@ -450,7 +472,7 @@ jQuery( function( $ ) {
item_remove_clicked: function( evt ) {
evt.preventDefault();
var $a = $( evt.target );
var $a = $( evt.currentTarget );
var $form = $a.parents( 'form' );
block( $form );

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -132,6 +132,15 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
return true;
}
/**
* Get post types.
*
* @return array
*/
protected function get_post_types() {
return array( $post->post_type );
}
/**
* Get a single item.
*
@ -142,7 +151,7 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
$id = (int) $request['id'];
$post = get_post( $id );
if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
if ( empty( $id ) || empty( $post->ID ) || ! in_array( $post->post_type, $this->get_post_types() ) ) {
return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'Invalid id.', 'woocommerce' ), array( 'status' => 404 ) );
}
@ -246,7 +255,7 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
$id = (int) $request['id'];
$post = get_post( $id );
if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
if ( empty( $id ) || empty( $post->ID ) || ! in_array( $post->post_type, $this->get_post_types() ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
}
@ -405,7 +414,7 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
$force = (bool) $request['force'];
$post = get_post( $id );
if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
if ( empty( $id ) || empty( $post->ID ) || ! in_array( $post->post_type, $this->get_post_types() ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post id.', 'woocommerce' ), array( 'status' => 404 ) );
}
@ -648,7 +657,7 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
);
$post_type_obj = get_post_type_object( $this->post_type );
if ( $post_type_obj->hierarchical ) {
if ( isset( $post_type_obj->hierarchical ) && $post_type_obj->hierarchical ) {
$params['parent'] = array(
'description' => __( 'Limit result set to those of particular parent ids.', 'woocommerce' ),
'type' => 'array',

View File

@ -60,7 +60,7 @@ abstract class WC_Settings_API {
* Set default required properties for each field.
* @param array
*/
private function set_defaults( $field ) {
protected function set_defaults( $field ) {
if ( ! isset( $field['default'] ) ) {
$field['default'] = '';
}
@ -74,6 +74,17 @@ abstract class WC_Settings_API {
echo '<table class="form-table">' . $this->generate_settings_html( $this->get_form_fields(), false ) . '</table>';
}
/**
* Initialise settings form fields.
*
* Add an array of fields to be displayed
* on the gateway's settings screen.
*
* @since 1.0.0
* @return string
*/
public function init_form_fields() {}
/**
* Return the name of the option in the WP DB.
* @since 2.6.0

View File

@ -333,7 +333,7 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
$available = $this->is_enabled();
// Country availability (legacy, for non-zone based methods)
if ( ! $this->instance_id ) {
if ( ! $this->instance_id && $available ) {
$countries = is_array( $this->countries ) ? $this->countries : array();
switch ( $this->availability ) {
@ -453,7 +453,7 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
* @return array
*/
public function get_instance_form_fields() {
return apply_filters( 'woocommerce_shipping_instance_form_fields_' . $this->id, $this->instance_form_fields );
return apply_filters( 'woocommerce_shipping_instance_form_fields_' . $this->id, array_map( array( $this, 'set_defaults' ), $this->instance_form_fields ) );
}
/**

View File

@ -116,9 +116,9 @@ class WC_Admin_Addons {
}
$url = add_query_arg( array(
'utm_source' => 'product',
'utm_medium' => 'upsell',
'utm_campaign' => 'wcaddons',
'utm_source' => 'addons',
'utm_medium' => 'product',
'utm_campaign' => 'woocommerceplugin',
'utm_content' => $utm_content,
), $url );

View File

@ -26,16 +26,15 @@ class WC_Admin_API_Keys {
/**
* Check if is API Keys settings page.
*
* @return bool
*/
private function is_api_keys_settings_page() {
return isset( $_GET['page'] )
&& 'wc-settings' == $_GET['page']
&& 'wc-settings' === $_GET['page']
&& isset( $_GET['tab'] )
&& 'api' == $_GET['tab']
&& 'api' === $_GET['tab']
&& isset( $_GET['section'] )
&& 'keys' == isset( $_GET['section'] );
&& 'keys' === $_GET['section'];
}
/**

View File

@ -279,7 +279,7 @@ class WC_Admin_Assets {
'currency_format' => esc_attr( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_price_format() ) ), // For accounting JS
'rounding_precision' => WC_ROUNDING_PRECISION,
'tax_rounding_mode' => WC_TAX_ROUNDING_MODE,
'product_types' => array_map( 'sanitize_title', get_terms( 'product_type', array( 'hide_empty' => false, 'fields' => 'names' ) ) ),
'product_types' => array_unique( array_merge( array( 'simple', 'grouped', 'variable', 'external' ), array_keys( wc_get_product_types() ) ) ),
'i18n_download_permission_fail' => __( 'Could not grant access - the user may already have permission for this file or billing email is not set. Ensure the billing email is set, and the order has been saved.', 'woocommerce' ),
'i18n_permission_revoke' => __( 'Are you sure you want to revoke access to this download?', 'woocommerce' ),
'i18n_tax_rate_already_exists' => __( 'You cannot add the same tax rate twice!', 'woocommerce' ),

View File

@ -53,10 +53,50 @@ class WC_Admin_Help {
'title' => __( 'Tax Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/qp1v19dwrh?videoFoam=true'
),
'wc-settings-shipping' => array(
'title' => __( 'Shipping Zones', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/95yiocro6p?videoFoam=true'
),
'wc-settings-shipping-options' => array(
'title' => __( 'Shipping Options', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/9c9008dxnr?videoFoam=true'
),
'wc-settings-shipping-classes' => array(
'title' => __( 'Shipping Classes', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/tpqg17aq99?videoFoam=true'
),
'wc-settings-checkout' => array(
'title' => __( 'Checkout Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/65yjv96z51?videoFoam=true'
),
'wc-settings-checkout-bacs' => array(
'title' => __( 'Bank Transfer (BACS) Payments', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/dh4piy3sek?videoFoam=true'
),
'wc-settings-checkout-cheque' => array(
'title' => __( 'Check Payments', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/u2m2kcakea?videoFoam=true'
),
'wc-settings-checkout-cod' => array(
'title' => __( 'Cash on Delivery', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/8hyli8wu5f?videoFoam=true'
),
'wc-settings-checkout-paypal' => array(
'title' => __( 'PayPal Standard', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/rbl7e7l4k2?videoFoam=true'
),
'wc-settings-checkout-paypalbraintree_cards' => array(
'title' => __( 'PayPal by Braintree', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/oyksirgn40?videoFoam=true'
),
'wc-settings-checkout-stripe' => array(
'title' => __( 'Stripe', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/mf975hx5de?videoFoam=true'
),
'wc-settings-checkout-simplify_commerce' => array(
'title' => __( 'Simplify Commerce', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/jdfzjiiw61?videoFoam=true'
),
'wc-settings-account' => array(
'title' => __( 'Account Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/35mazq7il2?videoFoam=true'
@ -69,20 +109,12 @@ class WC_Admin_Help {
'title' => __( 'Webhook Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/1q0ny74vvq?videoFoam=true'
),
'wc-settings-checkout-wc_gateway_paypal' => array(
'title' => __( 'PayPal Standard', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/rbl7e7l4k2?videoFoam=true'
),
'wc-settings-shipping' => array(
'title' => __( 'Shipping Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/9c9008dxnr?videoFoam=true'
),
'wc-settings-shipping-classes' => array(
'title' => __( 'Product Categories, Tags, Shipping Classes, &amp; Attributes', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/f0j5gzqigg?videoFoam=true'
'product' => array(
'title' => __( 'Simple Products', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/ziyjmd4kut?videoFoam=true'
),
'edit-product_cat' => array(
'title' => __( 'Product Categories, Tags, Shipping Classes, &amp; Attributes', 'woocommerce' ),
'title' => __( 'Product Categories', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/f0j5gzqigg?videoFoam=true'
),
'edit-product_tag' => array(
@ -93,10 +125,6 @@ class WC_Admin_Help {
'title' => __( 'Product Categories, Tags, Shipping Classes, &amp; Attributes', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/f0j5gzqigg?videoFoam=true'
),
'product' => array(
'title' => __( 'Simple Products', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/ziyjmd4kut?videoFoam=true'
),
'wc-status' => array(
'title' => __( 'System Status', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/xdn733nnhi?videoFoam=true'
@ -143,7 +171,7 @@ class WC_Admin_Help {
'id' => 'woocommerce_101_tab',
'title' => __( 'WooCommerce 101', 'woocommerce' ),
'content' =>
'<h2><a href="https://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Videos&utm_campaign=Onboarding">' . __( 'WooCommerce 101', 'woocommerce' ) . '</a> &ndash; ' . esc_html( $video_map[ $video_key ]['title'] ) . '</h2>' .
'<h2><a href="https://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=helptab&utm_medium=product&utm_content=videos&utm_campaign=woocommerceplugin">' . __( 'WooCommerce 101', 'woocommerce' ) . '</a> &ndash; ' . esc_html( $video_map[ $video_key ]['title'] ) . '</h2>' .
'<iframe data-src="' . esc_url( $video_map[ $video_key ]['url'] ) . '" src="" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" allowfullscreen mozallowfullscreen webkitallowfullscreen oallowfullscreen msallowfullscreen width="480" height="298"></iframe>'
) );
}
@ -155,18 +183,18 @@ class WC_Admin_Help {
'<h2>' . __( 'Help &amp; Support', 'woocommerce' ) . '</h2>' .
'<p>' . sprintf(
__( 'Should you need help understanding, using, or extending WooCommerce, %splease read our documentation%s. You will find all kinds of resources including snippets, tutorials and much more.' , 'woocommerce' ),
'<a href="https://docs.woothemes.com/documentation/plugins/woocommerce/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Docs&utm_campaign=Onboarding">',
'<a href="https://docs.woothemes.com/documentation/plugins/woocommerce/?utm_source=helptab&utm_medium=product&utm_content=docs&utm_campaign=woocommerceplugin">',
'</a>'
) . '</p>' .
'<p>' . sprintf(
__( 'For further assistance with WooCommerce core you can use the %scommunity forum%s. If you need help with premium add-ons sold by WooThemes, please %suse our helpdesk%s.', 'woocommerce' ),
'<a href="https://wordpress.org/support/plugin/woocommerce">',
'</a>',
'<a href="https://www.woothemes.com/my-account/tickets/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Tickets&utm_campaign=Onboarding">',
'<a href="https://www.woothemes.com/my-account/tickets/?utm_source=helptab&utm_medium=product&utm_content=tickets&utm_campaign=woocommerceplugin">',
'</a>'
) . '</p>' .
'<p>' . __( 'Before asking for help we recommend checking the system status page to identify any problems with your configuration.', 'woocommerce' ) . '</p>' .
'<p><a href="' . admin_url( 'admin.php?page=wc-status' ) . '" class="button button-primary">' . __( 'System Status', 'woocommerce' ) . '</a> <a href="' . 'https://wordpress.org/support/plugin/woocommerce' . '" class="button">' . __( 'Community Forum', 'woocommerce' ) . '</a> <a href="' . 'https://www.woothemes.com/my-account/tickets/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=Tickets&utm_campaign=Onboarding' . '" class="button">' . __( 'WooThemes Helpdesk', 'woocommerce' ) . '</a></p>'
'<p><a href="' . admin_url( 'admin.php?page=wc-status' ) . '" class="button button-primary">' . __( 'System Status', 'woocommerce' ) . '</a> <a href="' . 'https://wordpress.org/support/plugin/woocommerce' . '" class="button">' . __( 'Community Forum', 'woocommerce' ) . '</a> <a href="' . 'https://www.woothemes.com/my-account/tickets/?utm_source=helptab&utm_medium=product&utm_content=tickets&utm_campaign=woocommerceplugin' . '" class="button">' . __( 'WooThemes Helpdesk', 'woocommerce' ) . '</a></p>'
) );
$screen->add_help_tab( array(
@ -185,7 +213,7 @@ class WC_Admin_Help {
'content' =>
'<h2>' . __( 'Education', 'woocommerce' ) . '</h2>' .
'<p>' . __( 'If you would like to learn about using WooCommerce from an expert, consider following a WooCommerce course ran by one of our educational partners.', 'woocommerce' ) . '</p>' .
'<p><a href="' . 'https://www.woothemes.com/educational-partners/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=EduPartners&utm_campaign=Onboarding' . '" class="button button-primary">' . __( 'View Education Partners', 'woocommerce' ) . '</a></p>'
'<p><a href="' . 'https://www.woothemes.com/educational-partners/?utm_source=helptab&utm_medium=product&utm_content=edupartners&utm_campaign=woocommerceplugin' . '" class="button button-primary">' . __( 'View Education Partners', 'woocommerce' ) . '</a></p>'
) );
$screen->add_help_tab( array(
@ -200,11 +228,11 @@ class WC_Admin_Help {
$screen->set_help_sidebar(
'<p><strong>' . __( 'For more information:', 'woocommerce' ) . '</strong></p>' .
'<p><a href="' . 'https://www.woothemes.com/woocommerce/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=WooCommerceProductPage&utm_campaign=Onboarding' . '" target="_blank">' . __( 'About WooCommerce', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'https://www.woothemes.com/woocommerce/?utm_source=helptab&utm_medium=product&utm_content=about&utm_campaign=woocommerceplugin' . '" target="_blank">' . __( 'About WooCommerce', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'https://wordpress.org/extend/plugins/woocommerce/' . '" target="_blank">' . __( 'WordPress.org Project', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'https://github.com/woothemes/woocommerce' . '" target="_blank">' . __( 'Github Project', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'https://www.woothemes.com/product-category/themes/woocommerce/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=WCThemes&utm_campaign=Onboarding' . '" target="_blank">' . __( 'Official Themes', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'https://www.woothemes.com/product-category/woocommerce-extensions/?utm_source=WooCommercePlugin&utm_medium=Help&utm_content=WCExtensions&utm_campaign=Onboarding' . '" target="_blank">' . __( 'Official Extensions', 'woocommerce' ) . '</a></p>'
'<p><a href="' . 'https://www.woothemes.com/product-category/themes/woocommerce/?utm_source=helptab&utm_medium=product&utm_content=wcthemes&utm_campaign=woocommerceplugin' . '" target="_blank">' . __( 'Official Themes', 'woocommerce' ) . '</a></p>' .
'<p><a href="' . 'https://www.woothemes.com/product-category/woocommerce-extensions/?utm_source=helptab&utm_medium=product&utm_content=wcextensions&utm_campaign=woocommerceplugin' . '" target="_blank">' . __( 'Official Extensions', 'woocommerce' ) . '</a></p>'
);
}

View File

@ -191,10 +191,10 @@ class WC_Admin_Notices {
public static function update_notice() {
if ( version_compare( get_option( 'woocommerce_db_version' ), WC_VERSION, '<' ) ) {
$updater = new WC_Background_Updater();
if ( ! $updater->is_updating() ) {
include( 'views/html-notice-update.php' );
} else {
if ( $updater->is_updating() || ! empty( $_GET['do_update_woocommerce'] ) ) {
include( 'views/html-notice-updating.php' );
} else {
include( 'views/html-notice-update.php' );
}
} else {
include( 'views/html-notice-updated.php' );

View File

@ -1508,80 +1508,22 @@ class WC_Admin_Post_Types {
* @param WP_Query $wp
*/
public function shop_order_search_custom_fields( $wp ) {
global $pagenow, $wpdb;
global $pagenow;
if ( 'edit.php' != $pagenow || empty( $wp->query_vars['s'] ) || $wp->query_vars['post_type'] != 'shop_order' ) {
return;
}
$search_fields = array_map( 'wc_clean', apply_filters( 'woocommerce_shop_order_search_fields', array(
'_order_key',
'_billing_company',
'_billing_address_1',
'_billing_address_2',
'_billing_city',
'_billing_postcode',
'_billing_country',
'_billing_state',
'_billing_email',
'_billing_phone',
'_shipping_address_1',
'_shipping_address_2',
'_shipping_city',
'_shipping_postcode',
'_shipping_country',
'_shipping_state'
) ) );
$post_ids = wc_order_search( $_GET['s'] );
$search_order_id = str_replace( 'Order #', '', $_GET['s'] );
// Search orders
if ( is_numeric( $search_order_id ) ) {
$post_ids = array_unique( array_merge(
$wpdb->get_col(
$wpdb->prepare( "SELECT DISTINCT p1.post_id FROM {$wpdb->postmeta} p1 WHERE p1.meta_key IN ('" . implode( "','", array_map( 'esc_sql', $search_fields ) ) . "') AND p1.meta_value LIKE '%%%d%%';", absint( $search_order_id ) )
),
array( absint( $search_order_id ) )
) );
} elseif ( ! empty( $search_fields ) ) {
$post_ids = array_unique( array_merge(
$wpdb->get_col(
$wpdb->prepare( "
SELECT DISTINCT p1.post_id
FROM {$wpdb->postmeta} p1
INNER JOIN {$wpdb->postmeta} p2 ON p1.post_id = p2.post_id
WHERE
( p1.meta_key = '_billing_first_name' AND p2.meta_key = '_billing_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
OR
( p1.meta_key = '_shipping_first_name' AND p2.meta_key = '_shipping_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
OR
( p1.meta_key IN ('" . implode( "','", array_map( 'esc_sql', $search_fields ) ) . "') AND p1.meta_value LIKE '%%%s%%' )
",
wc_clean( $_GET['s'] ), wc_clean( $_GET['s'] ), wc_clean( $_GET['s'] )
)
),
$wpdb->get_col(
$wpdb->prepare( "
SELECT order_id
FROM {$wpdb->prefix}woocommerce_order_items as order_items
WHERE order_item_name LIKE '%%%s%%'
",
wc_clean( $_GET['s'] )
)
)
) );
} else {
$post_ids = false;
}
if ( is_array( $post_ids ) ) {
// Remove s - we don't want to search order name
if ( ! empty( $post_ids ) ) {
// Remove "s" - we don't want to search order name.
unset( $wp->query_vars['s'] );
// so we know we're doing this
// so we know we're doing this.
$wp->query_vars['shop_order_search'] = true;
// Search by found posts
// Search by found posts.
$wp->query_vars['post__in'] = array_merge( $post_ids, array( 0 ) );
}
}

View File

@ -7,7 +7,7 @@
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
* @version 2.4.0
* @version 2.6.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
@ -600,7 +600,7 @@ class WC_Admin_Setup_Wizard {
),
'cheque' => array(
'name' => _x( 'Check Payments', 'Check payment method', 'woocommerce' ),
'description' => __( 'An simple offline gateway that lets you accept a check as method of payment.', 'woocommerce' ),
'description' => __( 'A simple offline gateway that lets you accept a check as method of payment.', 'woocommerce' ),
'image' => '',
'class' => '',
),
@ -770,9 +770,9 @@ class WC_Admin_Setup_Wizard {
<div class="wc-setup-next-steps-last">
<h2><?php _e( 'Learn More', 'woocommerce' ); ?></h2>
<ul>
<li class="video-walkthrough"><a href="https://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=WooCommercePlugin&amp;utm_medium=Wizard&amp;utm_content=Videos&amp;utm_campaign=Onboarding"><?php _e( 'Watch the WC 101 video walkthroughs', 'woocommerce' ); ?></a></li>
<li class="newsletter"><a href="https://www.woothemes.com/woocommerce-onboarding-email/?utm_source=WooCommercePlugin&amp;utm_medium=Wizard&amp;utm_content=Newsletter&amp;utm_campaign=Onboarding"><?php _e( 'Get eCommerce advice in your inbox', 'woocommerce' ); ?></a></li>
<li class="learn-more"><a href="https://docs.woothemes.com/documentation/plugins/woocommerce/getting-started/?utm_source=WooCommercePlugin&amp;utm_medium=Wizard&amp;utm_content=Docs&amp;utm_campaign=Onboarding"><?php _e( 'Learn more about getting started', 'woocommerce' ); ?></a></li>
<li class="video-walkthrough"><a href="https://docs.woothemes.com/document/woocommerce-101-video-series/?utm_source=setupwizard&utm_medium=product&utm_content=videos&utm_campaign=woocommerceplugin"><?php _e( 'Watch the WC 101 video walkthroughs', 'woocommerce' ); ?></a></li>
<li class="newsletter"><a href="https://www.woothemes.com/woocommerce-onboarding-email/?utm_source=setupwizard&utm_medium=product&utm_content=newsletter&utm_campaign=woocommerceplugin"><?php _e( 'Get eCommerce advice in your inbox', 'woocommerce' ); ?></a></li>
<li class="learn-more"><a href="https://docs.woothemes.com/documentation/plugins/woocommerce/getting-started/?utm_source=setupwizard&utm_medium=product&utm_content=docs&utm_campaign=woocommerceplugin"><?php _e( 'Learn more about getting started', 'woocommerce' ); ?></a></li>
</ul>
</div>
</div>

View File

@ -141,13 +141,23 @@ class WC_Admin {
public function prevent_admin_access() {
$prevent_access = false;
if ( 'yes' === get_option( 'woocommerce_lock_down_admin', 'yes' ) && ! is_ajax() && basename( $_SERVER["SCRIPT_FILENAME"] ) !== 'admin-post.php' && ! current_user_can( 'edit_posts' ) && ! current_user_can( 'manage_woocommerce' ) ) {
$prevent_access = true;
if ( 'yes' === get_option( 'woocommerce_lock_down_admin', 'yes' ) && ! is_ajax() && basename( $_SERVER["SCRIPT_FILENAME"] ) !== 'admin-post.php' ) {
$has_cap = false;
$access_caps = array( 'edit_posts', 'manage_woocommerce', 'view_admin_dashboard' );
foreach ( $access_caps as $access_cap ) {
if ( current_user_can( $access_cap ) ) {
$has_cap = true;
break;
}
}
if ( ! $has_cap ) {
$prevent_access = true;
}
}
$prevent_access = apply_filters( 'woocommerce_prevent_admin_access', $prevent_access );
if ( $prevent_access ) {
if ( apply_filters( 'woocommerce_prevent_admin_access', $prevent_access ) ) {
wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
exit;
}

View File

@ -197,11 +197,11 @@ class WC_Meta_Box_Order_Data {
<h3><?php _e( 'General Details', 'woocommerce' ); ?></h3>
<p class="form-field form-field-wide"><label for="order_date"><?php _e( 'Order date:', 'woocommerce' ) ?></label>
<input type="text" class="date-picker" name="order_date" id="order_date" maxlength="10" value="<?php echo date_i18n( 'Y-m-d', strtotime( $post->post_date ) ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="text" class="hour" placeholder="<?php esc_attr_e( 'h', 'woocommerce' ) ?>" name="order_date_hour" id="order_date_hour" maxlength="2" size="2" value="<?php echo date_i18n( 'H', strtotime( $post->post_date ) ); ?>" pattern="\-?\d+(\.\d{0,})?" />:<input type="text" class="minute" placeholder="<?php esc_attr_e( 'm', 'woocommerce' ) ?>" name="order_date_minute" id="order_date_minute" maxlength="2" size="2" value="<?php echo date_i18n( 'i', strtotime( $post->post_date ) ); ?>" pattern="\-?\d+(\.\d{0,})?" />
<input type="text" class="date-picker" name="order_date" id="order_date" maxlength="10" value="<?php echo date_i18n( 'Y-m-d', strtotime( $post->post_date ) ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="text" class="hour" placeholder="<?php esc_attr_e( 'h', 'woocommerce' ) ?>" name="order_date_hour" id="order_date_hour" maxlength="2" size="2" value="<?php echo date_i18n( 'H', strtotime( $post->post_date ) ); ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="text" class="minute" placeholder="<?php esc_attr_e( 'm', 'woocommerce' ) ?>" name="order_date_minute" id="order_date_minute" maxlength="2" size="2" value="<?php echo date_i18n( 'i', strtotime( $post->post_date ) ); ?>" pattern="[0-5]{1}[0-9]{1}" />
</p>
<p class="form-field form-field-wide wc-order-status"><label for="order_status"><?php _e( 'Order status:', 'woocommerce' ) ?> <?php
if ( $order->has_status( 'pending' ) ) {
if ( $order->needs_payment() ) {
printf( '<a href="%s">%s &rarr;</a>',
esc_url( $order->get_checkout_payment_url() ),
__( 'Customer payment page', 'woocommerce' )

View File

@ -37,16 +37,9 @@ class WC_Meta_Box_Product_Data {
$product_type = apply_filters( 'default_product_type', 'simple' );
}
$product_type_selector = apply_filters( 'product_type_selector', array(
'simple' => __( 'Simple product', 'woocommerce' ),
'grouped' => __( 'Grouped product', 'woocommerce' ),
'external' => __( 'External/Affiliate product', 'woocommerce' ),
'variable' => __( 'Variable product', 'woocommerce' )
), $product_type );
$type_box = '<label for="product-type"><select id="product-type" name="product-type"><optgroup label="' . esc_attr__( 'Product Type', 'woocommerce' ) . '">';
foreach ( $product_type_selector as $value => $label ) {
foreach ( wc_get_product_types() as $value => $label ) {
$type_box .= '<option value="' . esc_attr( $value ) . '" ' . selected( $product_type, $value, false ) .'>' . esc_html( $label ) . '</option>';
}

View File

@ -142,11 +142,11 @@ $item_subtotal = ( isset( $item['line_subtotal'] ) ) ? esc_attr( wc_format_local
<div class="split-input">
<div class="input">
<label><?php esc_attr_e( 'Pre-discount:', 'woocommerce' ); ?></label>
<input type="text" name="line_subtotal_tax[<?php echo absint( $item_id ); ?>][<?php echo esc_attr( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo $tax_item_subtotal; ?>" class="line_subtotal_tax wc_input_price" data-subtotal_tax="<?php echo $tax_item_subtotal; ?>" data-tax_id="<?php echo esc_attr( $tax_item_id ); ?>" />
<input type="text" name="line_subtotal_tax[<?php echo absint( $item_id ); ?>][<?php echo esc_attr( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $tax_item_subtotal ) ); ?>" class="line_subtotal_tax wc_input_price" data-subtotal_tax="<?php echo esc_attr( wc_format_localized_price( $tax_item_subtotal ) ); ?>" data-tax_id="<?php echo esc_attr( $tax_item_id ); ?>" />
</div>
<div class="input">
<label><?php esc_attr_e( 'Total:', 'woocommerce' ); ?></label>
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>][<?php echo esc_attr( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo $tax_item_total; ?>" class="line_tax wc_input_price" data-total_tax="<?php echo $tax_item_total; ?>" data-tax_id="<?php echo esc_attr( $tax_item_id ); ?>" />
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>][<?php echo esc_attr( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $tax_item_total ) ); ?>" class="line_tax wc_input_price" data-total_tax="<?php echo esc_attr( wc_format_localized_price( $tax_item_total ) ); ?>" data-tax_id="<?php echo esc_attr( $tax_item_id ); ?>" />
</div>
</div>
</div>

View File

@ -239,8 +239,9 @@ class WC_Settings_Shipping extends WC_Settings_Page {
),
'wc_shipping_zones_nonce' => wp_create_nonce( 'wc_shipping_zones_nonce' ),
'strings' => array(
'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', 'woocommerce' ),
'save_failed' => __( 'Your changes were not saved. Please retry.', 'woocommerce' ),
'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', 'woocommerce' ),
'save_failed' => __( 'Your changes were not saved. Please retry.', 'woocommerce' ),
'no_shipping_methods_offered' => __( 'No shipping methods offered to this zone.', 'woocommerce' ),
),
) );
wp_enqueue_script( 'wc-shipping-zones' );

View File

@ -98,6 +98,8 @@ if ( ! defined( 'ABSPATH' ) ) {
<article>
<form action="" method="post">
<div class="wc-shipping-zone-method-selector">
<p><?php esc_html_e( 'Choose the shipping method you wish to add. Only shipping methods which support zones are listed.', 'woocommerce' ); ?></p>
<select name="add_method_id">
<?php
foreach ( WC()->shipping->load_shipping_methods() as $method ) {

View File

@ -36,7 +36,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<a href="admin.php?page=wc-settings&amp;tab=shipping&amp;zone_id={{ data.zone_id }}"><?php _e( 'View', 'woocommerce' ); ?></a>
</div>
</td>
<td class="wc-shipping-zone-region"><?php esc_html_e( 'Shipping Methods added here will apply to shipping addresses that aren&lsquo;t included in any other shipping zone.', 'woocommerce' ); ?></td>
<td class="wc-shipping-zone-region"><?php esc_html_e( 'This zone is used for shipping addresses that aren&lsquo;t included in any other shipping zone. Adding shipping methods to this zone is optional.', 'woocommerce' ); ?></td>
<td class="wc-shipping-zone-methods">
<ul>
<?php
@ -49,7 +49,7 @@ if ( ! defined( 'ABSPATH' ) ) {
echo '<li class="wc-shipping-zone-method"><a href="admin.php?page=wc-settings&amp;tab=shipping&amp;instance_id=' . absint( $method->instance_id ) . '" class="' . esc_attr( $class_name ) . '">' . esc_html( $method->get_title() ) . '</a></li>';
}
} else {
echo '<li class="wc-shipping-zone-method">&ndash;</li>';
echo '<li class="wc-shipping-zone-method">' . __( 'No shipping methods offered to this zone.', 'woocommerce' ) . '</li>';
}
?>
<li class="wc-shipping-zone-methods-add-row"><a href="#" class="add_shipping_method tips" data-tip="<?php esc_attr_e( 'Add shipping method', 'woocommerce' ); ?>" data-disabled-tip="<?php esc_attr_e( 'Save changes to continue adding shipping methods to this zone', 'woocommerce' ); ?>"><?php _e( 'Add shipping method', 'woocommerce' ); ?></a></li>
@ -146,6 +146,8 @@ if ( ! defined( 'ABSPATH' ) ) {
<article>
<form action="" method="post">
<div class="wc-shipping-zone-method-selector">
<p><?php esc_html_e( 'Choose the shipping method you wish to add. Only shipping methods which support zones are listed.', 'woocommerce' ); ?></p>
<select name="add_method_id">
<?php
foreach ( WC()->shipping->load_shipping_methods() as $method ) {

View File

@ -39,7 +39,7 @@ return apply_filters( 'woocommerce_tax_settings', array(
'desc' => __( 'Optionally control which tax class shipping gets, or leave it so shipping tax is based on the cart items themselves.', 'woocommerce' ),
'id' => 'woocommerce_shipping_tax_class',
'css' => 'min-width:150px;',
'default' => 'title',
'default' => '',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => array( '' => __( 'Shipping tax class based on cart items', 'woocommerce' ), 'standard' => __( 'Standard', 'woocommerce' ) ) + $classes_options,

View File

@ -13,7 +13,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<p><?php printf( __( '<strong>Your theme does not declare WooCommerce support</strong> &#8211; Please read our %sintegration%s guide or check out our %sStorefront%s theme which is totally free to download and designed specifically for use with WooCommerce.', 'woocommerce' ), '<a target="_blank" href="' . esc_url( apply_filters( 'woocommerce_docs_url', 'https://docs.woothemes.com/document/third-party-custom-theme-compatibility/', 'theme-compatibility' ) ) . '">', '</a>', '<a target="_blank" href="' . esc_url( admin_url( 'theme-install.php?theme=storefront' ) ) . '">', '</a>' ); ?></p>
<p class="submit">
<a href="https://www.woothemes.com/storefront/?utm_source=wpadmin&amp;utm_medium=notice&amp;utm_campaign=Storefront" class="button-primary" target="_blank"><?php _e( 'Read More About Storefront', 'woocommerce' ); ?></a>
<a href="<?php echo esc_url( apply_filters( 'woocommerce_docs_url', 'https://docs.woothemes.com/document/third-party-custom-theme-compatibility/', 'theme-compatibility' ) ); ?>" class="button-secondary" target="_blank"><?php _e( 'Theme Integration Guide', 'woocommerce' ); ?></a>
<a href="https://www.woothemes.com/storefront/?utm_source=notice&amp;utm_medium=product&amp;utm_content=storefront&amp;utm_campaign=woocommerceplugin" class="button-primary" target="_blank"><?php _e( 'Read More About Storefront', 'woocommerce' ); ?></a>
<a href="<?php echo esc_url( apply_filters( 'woocommerce_docs_url', 'http://docs.woothemes.com/document/third-party-custom-theme-compatibility/?utm_source=notice&utm_medium=product&utm_content=themecompatibility&utm_campaign=woocommerceplugin' ) ); ?>" class="button-secondary" target="_blank"><?php _e( 'Theme Integration Guide', 'woocommerce' ); ?></a>
</p>
</div>

View File

@ -9,5 +9,5 @@ if ( ! defined( 'ABSPATH' ) ) {
?>
<div id="message" class="updated woocommerce-message wc-connect">
<p><strong><?php _e( 'WooCommerce Data Update', 'woocommerce' ); ?></strong> &#8211; <?php _e( 'Your database is being updated in the background.', 'woocommerce' ); ?></p>
<p><strong><?php _e( 'WooCommerce Data Update', 'woocommerce' ); ?></strong> &#8211; <?php _e( 'Your database is being updated in the background.', 'woocommerce' ); ?> <a href="<?php echo esc_url( add_query_arg( 'force_update_woocommerce', 'true', admin_url( 'admin.php?page=wc-settings' ) ) ); ?>"><?php _e( 'Taking a while? Click here to run it now.', 'woocommerce' ); ?></a></p>
</div>

View File

@ -114,8 +114,6 @@ class WC_REST_Authentication {
// Get user data.
$user = $this->get_user_data_by_consumer_key( $consumer_key );
if ( empty( $user ) ) {
$wc_rest_authentication_error = new WP_Error( 'woocommerce_rest_authentication_error', __( 'Consumer Key is invalid.', 'woocommerce' ), array( 'status' => 401 ) );
return false;
}

View File

@ -469,7 +469,7 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
),
'amount' => array(
'description' => __( 'The amount of discount.', 'woocommerce' ),
'type' => 'float',
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'expiry_date' => array(
@ -538,12 +538,12 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
),
'minimum_amount' => array(
'description' => __( 'Minimum order amount that needs to be in the cart before coupon applies.', 'woocommerce' ),
'type' => 'float',
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'maximum_amount' => array(
'description' => __( 'Maximum order amount allowed when using the coupon.', 'woocommerce' ),
'type' => 'float',
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'email_restrictions' => array(

View File

@ -684,7 +684,7 @@ class WC_REST_Customers_Controller extends WC_REST_Controller {
),
'total_spent' => array(
'description' => __( 'Total amount spent.', 'woocommerce' ),
'type' => 'float',
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),

View File

@ -412,6 +412,7 @@ class WC_REST_Orders_Controller extends WC_REST_Posts_Controller {
);
}
// Search by product.
if ( ! empty( $request['product'] ) ) {
$order_ids = $wpdb->get_col( $wpdb->prepare( "
SELECT order_id
@ -426,6 +427,16 @@ class WC_REST_Orders_Controller extends WC_REST_Posts_Controller {
$args['post__in'] = $order_ids;
}
// Search.
if ( ! empty( $args['s'] ) ) {
$order_ids = wc_order_search( $args['s'] );
if ( ! empty( $order_ids ) ) {
unset( $args['s'] );
$args['post__in'] = array_merge( $order_ids, array( 0 ) );
}
}
return $args;
}
@ -530,7 +541,7 @@ class WC_REST_Orders_Controller extends WC_REST_Posts_Controller {
update_post_meta( $order->id, '_payment_method', $request['payment_method'] );
}
if ( ! empty( $request['payment_method_title'] ) ) {
update_post_meta( $order->id, '_payment_method_title', $request['payment_method'] );
update_post_meta( $order->id, '_payment_method_title', $request['payment_method_title'] );
}
if ( true === $request['set_paid'] ) {
$order->payment_complete( $request['transaction_id'] );

View File

@ -112,6 +112,15 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
) );
}
/**
* Get post types.
*
* @return array
*/
protected function get_post_types() {
return array( 'product', 'product_variation' );
}
/**
* Query args.
*
@ -280,7 +289,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
'date_created' => wc_rest_prepare_date_response( $attachment_post->post_date_gmt ),
'date_modified' => wc_rest_prepare_date_response( $attachment_post->post_modified_gmt ),
'src' => current( $attachment ),
'title' => get_the_title( $attachment_id ),
'name' => get_the_title( $attachment_id ),
'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ),
'position' => (int) $position,
);
@ -290,10 +299,10 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
if ( empty( $images ) ) {
$images[] = array(
'id' => 0,
'date_created' => wc_rest_prepare_date_response( time() ), // Default to now.
'date_modified' => wc_rest_prepare_date_response( time() ),
'date_created' => wc_rest_prepare_date_response( current_time( 'mysql' ) ), // Default to now.
'date_modified' => wc_rest_prepare_date_response( current_time( 'mysql' ) ),
'src' => wc_placeholder_img_src(),
'title' => __( 'Placeholder', 'woocommerce' ),
'name' => __( 'Placeholder', 'woocommerce' ),
'alt' => __( 'Placeholder', 'woocommerce' ),
'position' => 0,
);
@ -345,6 +354,23 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
return $default;
}
/**
* Get attribute options.
*
* @param int $product_id
* @param array $attribute
* @return array
*/
protected function get_attribute_options( $product_id, $attribute ) {
if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) {
return wc_get_product_terms( $product_id, $attribute['name'], array( 'fields' => 'names' ) );
} elseif ( isset( $attribute['value'] ) ) {
return array_map( 'trim', explode( '|', $attribute['value'] ) );
}
return array();
}
/**
* Get the attributes for a product or product variation.
*
@ -376,15 +402,14 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
}
} else {
foreach ( $product->get_attributes() as $attribute ) {
// Taxonomy-based attributes are comma-separated, others are pipe (|) separated.
if ( $attribute['is_taxonomy'] ) {
$attributes[] = array(
'id' => $attribute['is_taxonomy'] ? wc_attribute_taxonomy_id_by_name( $attribute['name'] ) : 0,
'id' => wc_attribute_taxonomy_id_by_name( $attribute['name'] ),
'name' => $this->get_attribute_taxonomy_label( $attribute['name'] ),
'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],
'options' => array_map( 'trim', explode( ',', $product->get_attribute( $attribute['name'] ) ) ),
'options' => $this->get_attribute_options( $product->id, $attribute ),
);
} else {
$attributes[] = array(
@ -393,7 +418,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],
'options' => array_map( 'trim', explode( '|', $product->get_attribute( $attribute['name'] ) ) ),
'options' => $this->get_attribute_options( $product->id, $attribute ),
);
}
}
@ -617,7 +642,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
if ( $product->is_type( 'variation' ) && $product->parent ) {
$links['up'] = array(
'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $product->parent ) ),
'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $product->parent->id ) ),
);
} elseif ( $product->is_type( 'simple' ) && ! empty( $product->post->post_parent ) ) {
$links['up'] = array(
@ -746,9 +771,9 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) );
}
// Set the image title if present.
if ( ! empty( $image['title'] ) && $attachment_id ) {
wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['title'] ) );
// Set the image name if present.
if ( ! empty( $image['name'] ) && $attachment_id ) {
wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['name'] ) );
}
}
@ -1366,9 +1391,9 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) );
}
// Set the image title if present.
if ( ! empty( $image['title'] ) ) {
wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['title'] ) );
// Set the image name if present.
if ( ! empty( $image['name'] ) ) {
wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['name'] ) );
}
update_post_meta( $variation_id, '_thumbnail_id', $attachment_id );
@ -2483,7 +2508,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
),
),
),
'grouped_products_ids' => array(
'grouped_products' => array(
'description' => __( 'List of grouped products ID.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),

View File

@ -592,7 +592,7 @@ class WC_REST_Taxes_Controller extends WC_REST_Controller {
),
'rate' => array(
'description' => __( 'Tax rate.', 'woocommerce' ),
'type' => 'float',
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'name' => array(

View File

@ -470,6 +470,23 @@ class WC_API_Products extends WC_API_Resource {
return $images;
}
/**
* Get attribute options.
*
* @param int $product_id
* @param array $attribute
* @return array
*/
protected function get_attribute_options( $product_id, $attribute ) {
if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) {
return wc_get_product_terms( $product_id, $attribute['name'], array( 'fields' => 'names' ) );
} elseif ( isset( $attribute['value'] ) ) {
return array_map( 'trim', explode( '|', $attribute['value'] ) );
}
return array();
}
/**
* Get the attributes for a product or product variation
*
@ -496,19 +513,12 @@ class WC_API_Products extends WC_API_Resource {
} else {
foreach ( $product->get_attributes() as $attribute ) {
// taxonomy-based attributes are comma-separated, others are pipe (|) separated
if ( $attribute['is_taxonomy'] )
$options = explode( ',', $product->get_attribute( $attribute['name'] ) );
else
$options = explode( '|', $product->get_attribute( $attribute['name'] ) );
$attributes[] = array(
'name' => ucwords( str_replace( 'pa_', '', $attribute['name'] ) ),
'position' => $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],
'options' => array_map( 'trim', $options ),
'options' => $this->get_attribute_options( $product->id, $attribute ),
);
}
}

View File

@ -1797,8 +1797,10 @@ class WC_API_Products extends WC_API_Resource {
'timeout' => 10
) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s', 'woocommerce' ), $image_url ), 400 );
if ( is_wp_error( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) . ' ' . sprintf( __( 'Error: %s.', 'woocommerce' ), $response->get_error_message() ), 400 );
} elseif ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ), 400 );
}
// Ensure we have a file name and type
@ -1873,6 +1875,23 @@ class WC_API_Products extends WC_API_Resource {
return $attachment_id;
}
/**
* Get attribute options.
*
* @param int $product_id
* @param array $attribute
* @return array
*/
protected function get_attribute_options( $product_id, $attribute ) {
if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) {
return wc_get_product_terms( $product_id, $attribute['name'], array( 'fields' => 'names' ) );
} elseif ( isset( $attribute['value'] ) ) {
return array_map( 'trim', explode( '|', $attribute['value'] ) );
}
return array();
}
/**
* Get the attributes for a product or product variation
*
@ -1900,21 +1919,13 @@ class WC_API_Products extends WC_API_Resource {
} else {
foreach ( $product->get_attributes() as $attribute ) {
// taxonomy-based attributes are comma-separated, others are pipe (|) separated
if ( $attribute['is_taxonomy'] ) {
$options = explode( ',', $product->get_attribute( $attribute['name'] ) );
} else {
$options = explode( '|', $product->get_attribute( $attribute['name'] ) );
}
$attributes[] = array(
'name' => wc_attribute_label( $attribute['name'] ),
'slug' => str_replace( 'pa_', '', $attribute['name'] ),
'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],
'options' => array_map( 'trim', $options ),
'options' => $this->get_attribute_options( $product->id, $attribute ),
);
}
}

View File

@ -2353,8 +2353,10 @@ class WC_API_Products extends WC_API_Resource {
'timeout' => 10
) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_' . $upload_for, sprintf( __( 'Error getting remote image %s', 'woocommerce' ), $image_url ), 400 );
if ( is_wp_error( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_' . $upload_for, sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) . ' ' . sprintf( __( 'Error: %s.', 'woocommerce' ), $response->get_error_message() ), 400 );
} elseif ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_' . $upload_for, sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ), 400 );
}
// Ensure we have a file name and type.
@ -2454,6 +2456,23 @@ class WC_API_Products extends WC_API_Resource {
return $attachment_id;
}
/**
* Get attribute options.
*
* @param int $product_id
* @param array $attribute
* @return array
*/
protected function get_attribute_options( $product_id, $attribute ) {
if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) {
return wc_get_product_terms( $product_id, $attribute['name'], array( 'fields' => 'names' ) );
} elseif ( isset( $attribute['value'] ) ) {
return array_map( 'trim', explode( '|', $attribute['value'] ) );
}
return array();
}
/**
* Get the attributes for a product or product variation
*
@ -2481,21 +2500,13 @@ class WC_API_Products extends WC_API_Resource {
} else {
foreach ( $product->get_attributes() as $attribute ) {
// taxonomy-based attributes are comma-separated, others are pipe (|) separated
if ( $attribute['is_taxonomy'] ) {
$options = explode( ',', $product->get_attribute( $attribute['name'] ) );
} else {
$options = explode( '|', $product->get_attribute( $attribute['name'] ) );
}
$attributes[] = array(
'name' => wc_attribute_label( $attribute['name'], $product ),
'slug' => str_replace( 'pa_', '', $attribute['name'] ),
'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],
'options' => array_map( 'trim', $options ),
'options' => $this->get_attribute_options( $product->id, $attribute ),
);
}
}

View File

@ -29,11 +29,6 @@ class WC_Background_Updater extends WP_Background_Process {
*/
protected $action = 'wc_updater';
/**
* @var string
*/
protected $error = '';
/**
* Dispatch updater.
*
@ -41,15 +36,36 @@ class WC_Background_Updater extends WP_Background_Process {
*/
public function dispatch() {
$dispatched = parent::dispatch();
$logger = new WC_Logger();
if ( is_wp_error( $dispatched ) ) {
$this->error = $dispatched->get_error_message();
add_action( 'admin_notices', array( $this, 'dispatch_error' ) );
$logger->add( 'wc_db_updates', sprintf( 'Unable to dispatch WooCommerce updater: %s', $dispatched->get_error_message() ) );
}
}
/**
* Schedule event
* Handle cron healthcheck
*
* Restart the background process if not already running
* and data exists in the queue.
*/
public function handle_cron_healthcheck() {
if ( $this->is_process_running() ) {
// Background process already running.
return;
}
if ( $this->is_queue_empty() ) {
// No data to process.
$this->clear_scheduled_event();
return;
}
$this->handle();
}
/**
* Schedule fallback event.
*/
protected function schedule_event() {
if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
@ -57,13 +73,6 @@ class WC_Background_Updater extends WP_Background_Process {
}
}
/**
* Error shown when the updater cannot dispatch.
*/
public function dispatch_error() {
echo '<div class="error"><p>' . __( 'Unable to dispatch WooCommerce updater:', 'woocommerce' ) . ' ' . esc_html( $this->error ) . '</p></div>';
}
/**
* Is the updater running?
* @return boolean

View File

@ -405,7 +405,7 @@ class WC_Coupon {
* @throws Exception
*/
private function validate_maximum_amount() {
if ( $this->maximum_amount > 0 && apply_filters( 'woocommerce_coupon_validate_maximum_amount', wc_format_decimal( $this->maximum_amount ) <= WC()->cart->get_displayed_subtotal(), $this ) ) {
if ( $this->maximum_amount > 0 && apply_filters( 'woocommerce_coupon_validate_maximum_amount', wc_format_decimal( $this->maximum_amount ) < WC()->cart->get_displayed_subtotal(), $this ) ) {
throw new Exception( self::E_WC_COUPON_MAX_SPEND_LIMIT_MET );
}
}

View File

@ -336,7 +336,7 @@ class WC_Emails {
'orderNumber' => strval( $order->get_order_number() ),
'priceCurrency' => $order->get_order_currency(),
'price' => $order->get_total(),
'acceptedOffer' => count( $accepted_offers ) > 1 ? $accepted_offers : $accepted_offers[0],
'acceptedOffer' => $accepted_offers,
'url' => $order->get_view_order_url(),
);
@ -373,7 +373,7 @@ class WC_Emails {
$markup = apply_filters( 'woocommerce_email_order_schema_markup', $markup, $sent_to_admin, $order );
echo '<script type="application/ld+json">' . wp_json_encode( (object) $markup ) . '</script>';
echo '<div style="display:none;"><script type="application/ld+json">' . wp_json_encode( (object) $markup ) . '</script></div>';
}
/**

View File

@ -82,6 +82,7 @@ class WC_Install {
*/
public static function init() {
add_action( 'init', array( __CLASS__, 'check_version' ), 5 );
add_action( 'init', array( __CLASS__, 'init_background_updater' ), 5 );
add_action( 'admin_init', array( __CLASS__, 'install_actions' ) );
add_action( 'in_plugin_update_message-woocommerce/woocommerce.php', array( __CLASS__, 'in_plugin_update_message' ) );
add_filter( 'plugin_action_links_' . WC_PLUGIN_BASENAME, array( __CLASS__, 'plugin_action_links' ) );
@ -89,8 +90,13 @@ class WC_Install {
add_filter( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) );
add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) );
add_action( 'woocommerce_plugin_background_installer', array( __CLASS__, 'background_installer' ), 10, 2 );
}
// Init background updates
/**
* Init background updates
*/
public static function init_background_updater() {
include_once( 'class-wc-background-updater.php' );
self::$background_updater = new WC_Background_Updater();
}
@ -116,6 +122,10 @@ class WC_Install {
self::update();
WC_Admin_Notices::add_notice( 'update' );
}
if ( ! empty( $_GET['force_update_woocommerce'] ) ) {
do_action( 'wp_wc_updater_cron' );
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings' ) );
}
}
/**
@ -550,7 +560,7 @@ CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokenmeta (
meta_value longtext NULL,
PRIMARY KEY (meta_id),
KEY payment_token_id (payment_token_id),
KEY meta_key (meta_key)
KEY meta_key (meta_key($max_index_length))
) $collate;
";

View File

@ -130,12 +130,34 @@ class WC_Query {
return $title;
}
/**
* Endpoint mask describing the places the endpoint should be added.
*
* @since 2.6.2
* @return int
*/
protected function get_endpoints_mask() {
if ( 'page' === get_option( 'show_on_front' ) ) {
$page_on_front = get_option( 'page_on_front' );
$myaccount_page_id = get_option( 'woocommerce_myaccount_page_id' );
$checkout_page_id = get_option( 'woocommerce_checkout_page_id' );
if ( in_array( $page_on_front, array( $myaccount_page_id, $checkout_page_id ) ) ) {
return EP_ROOT | EP_PAGES;
}
}
return EP_PAGES;
}
/**
* Add endpoints for query vars.
*/
public function add_endpoints() {
$mask = $this->get_endpoints_mask();
foreach ( $this->query_vars as $key => $var ) {
add_rewrite_endpoint( $var, EP_ROOT | EP_PAGES );
add_rewrite_endpoint( $var, $mask );
}
}
@ -242,6 +264,11 @@ class WC_Query {
}
}
// Fix product feeds
if ( $q->is_feed() && $q->is_post_type_archive( 'product' ) ) {
$q->is_comment_feed = false;
}
// Special check for shops with the product archive on front
if ( $q->is_page() && 'page' === get_option( 'show_on_front' ) && absint( $q->get( 'page_id' ) ) === wc_get_page_id( 'shop' ) ) {
@ -624,13 +651,29 @@ class WC_Query {
$tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
if ( ! empty( $args['taxonomy'] ) && ! empty( $args['term'] ) ) {
$tax_query[] = array(
$tax_query[ $args['taxonomy'] ] = array(
'taxonomy' => $args['taxonomy'],
'terms' => array( $args['term'] ),
'field' => 'slug',
);
}
if ( ! empty( $args['product_cat'] ) ) {
$tax_query[ 'product_cat' ] = array(
'taxonomy' => 'product_cat',
'terms' => array( $args['product_cat'] ),
'field' => 'slug',
);
}
if ( ! empty( $args['product_tag'] ) ) {
$tax_query[ 'product_tag' ] = array(
'taxonomy' => 'product_tag',
'terms' => array( $args['product_tag'] ),
'field' => 'slug',
);
}
return $tax_query;
}

View File

@ -220,8 +220,10 @@ class WC_Shipping_Zone extends WC_Data {
if ( sizeof( $location_parts ) > $max ) {
$remaining = sizeof( $location_parts ) - $max;
return sprintf( _n( '%s and %d other region', '%s and %d other regions', $remaining, 'woocommerce' ), implode( ', ', array_splice( $location_parts, 0, $max ) ), $remaining );
} else {
} elseif ( ! empty( $location_parts ) ) {
return implode( ', ', $location_parts );
} else {
return __( 'Everywhere', 'woocommerce' );
}
}
@ -349,7 +351,7 @@ class WC_Shipping_Zone extends WC_Data {
public function add_location( $code, $type ) {
if ( $this->is_valid_location_type( $type ) ) {
if ( 'postcode' === $type ) {
$code = wc_normalize_postcode( $code );
$code = trim( strtoupper( str_replace( chr( 226 ) . chr( 128 ) . chr( 166 ), '...', $code ) ) ); // No normalization - postcodes are matched against both normal and formatted versions to support wildcards.
}
$location = array(
'code' => wc_clean( $code ),

View File

@ -133,14 +133,15 @@ class WC_Shipping_Zones {
$criteria = array();
$criteria[] = $wpdb->prepare( "( ( location_type = 'country' AND location_code = %s )", $country );
$criteria[] = $wpdb->prepare( "OR ( location_type = 'state' AND location_code = %s )", $country . ':' . $state );
$criteria[] = $wpdb->prepare( "OR ( location_type = 'continent' AND location_code = %s ) )", $continent );
$criteria[] = $wpdb->prepare( "OR ( location_type = 'continent' AND location_code = %s )", $continent );
$criteria[] = "OR ( location_type IS NULL ) )";
// Postcode range and wildcard matching
$postcode_locations = $wpdb->get_results( "SELECT zone_id, location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE location_type = 'postcode';" );
if ( $postcode_locations ) {
$zone_ids_with_postcode_rules = array_map( 'absint', wp_list_pluck( $postcode_locations, 'zone_id' ) );
$matches = wc_postcode_location_matcher( $postcode, $postcode_locations, 'zone_id', 'location_code' );
$matches = wc_postcode_location_matcher( $postcode, $postcode_locations, 'zone_id', 'location_code', $country );
$do_not_match = array_unique( array_diff( $zone_ids_with_postcode_rules, array_keys( $matches ) ) );
if ( ! empty( $do_not_match ) ) {
@ -151,7 +152,7 @@ class WC_Shipping_Zones {
// Get matching zones
$matching_zone_id = $wpdb->get_var( "
SELECT zones.zone_id FROM {$wpdb->prefix}woocommerce_shipping_zones as zones
LEFT OUTER JOIN {$wpdb->prefix}woocommerce_shipping_zone_locations as locations ON zones.zone_id = locations.zone_id
LEFT OUTER JOIN {$wpdb->prefix}woocommerce_shipping_zone_locations as locations ON zones.zone_id = locations.zone_id AND location_type != 'postcode'
WHERE " . implode( ' ', $criteria ) . "
ORDER BY zone_order ASC LIMIT 1
" );

View File

@ -132,8 +132,14 @@ class WC_Shipping {
*/
public function load_shipping_methods( $package = array() ) {
if ( ! empty( $package ) ) {
$status_options = get_option( 'woocommerce_status_options', array() );
$shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $package );
$this->shipping_methods = $shipping_zone->get_shipping_methods( true );
// Debug output
if ( ! empty( $status_options['shipping_debug_mode'] ) && ! defined( 'WOOCOMMERCE_CHECKOUT' ) && ! wc_has_notice( 'Customer matched zone "' . $shipping_zone->get_zone_name() . '"' ) ) {
wc_add_notice( 'Customer matched zone "' . $shipping_zone->get_zone_name() . '"' );
}
} else {
$this->shipping_methods = array();
}
@ -283,7 +289,7 @@ class WC_Shipping {
// If not set, not available, or available methods have changed, set to the DEFAULT option
if ( empty( $chosen_method ) || ! isset( $package['rates'][ $chosen_method ] ) || $method_count !== sizeof( $package['rates'] ) ) {
$chosen_method = apply_filters( 'woocommerce_shipping_chosen_method', $this->get_default_method( $package['rates'], $chosen_method ), $package['rates'], $chosen_method );
$chosen_method = apply_filters( 'woocommerce_shipping_chosen_method', $this->get_default_method( $package['rates'], false ), $package['rates'], $chosen_method );
$chosen_methods[ $i ] = $chosen_method;
$method_counts[ $i ] = sizeof( $package['rates'] );
do_action( 'woocommerce_shipping_method_chosen', $chosen_method );

View File

@ -348,14 +348,14 @@ class WC_Shortcodes {
);
// Ignore catalog visibility
$query_args['meta_query'] = WC()->query->stock_status_meta_query();
$query_args['meta_query'] = array_merge( $query_args['meta_query'], WC()->query->stock_status_meta_query() );
}
if ( ! empty( $atts['ids'] ) ) {
$query_args['post__in'] = array_map( 'trim', explode( ',', $atts['ids'] ) );
// Ignore catalog visibility
$query_args['meta_query'] = WC()->query->stock_status_meta_query();
$query_args['meta_query'] = array_merge( $query_args['meta_query'], WC()->query->stock_status_meta_query() );
}
return self::product_loop( $query_args, $atts, 'products' );

View File

@ -286,11 +286,11 @@ class WC_Tax {
$criteria[] = $wpdb->prepare( "tax_rate_class = %s", sanitize_title( $tax_class ) );
// Pre-query postcode ranges for PHP based matching.
$postcode_search = wc_get_wildcard_postcodes( $postcode );
$postcode_search = wc_get_wildcard_postcodes( $postcode, $country );
$postcode_ranges = $wpdb->get_results( "SELECT tax_rate_id, location_code FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE location_type = 'postcode' AND location_code LIKE '%...%';" );
if ( $postcode_ranges ) {
$matches = wc_postcode_location_matcher( $postcode, $postcode_ranges, 'tax_rate_id', 'location_code' );
$matches = wc_postcode_location_matcher( $postcode, $postcode_ranges, 'tax_rate_id', 'location_code', $country );
if ( ! empty( $matches ) ) {
foreach ( $matches as $matched_postcodes ) {
$postcode_search = array_merge( $postcode_search, $matched_postcodes );
@ -818,7 +818,11 @@ class WC_Tax {
if ( ! is_array( $postcodes ) ) {
$postcodes = explode( ';', $postcodes );
}
self::_update_tax_rate_locations( $tax_rate_id, array_diff( array_map( 'wc_normalize_postcode', array_filter( $postcodes ) ), array( '*' ) ), 'postcode' );
// No normalization - postcodes are matched against both normal and formatted versions to support wildcards.
foreach ( $postcodes as $key => $postcode ) {
$postcodes[ $key ] = strtoupper( trim( str_replace( chr( 226 ) . chr( 128 ) . chr( 166 ), '...', $postcode ) ) );
}
self::_update_tax_rate_locations( $tax_rate_id, array_diff( array_filter( $postcodes ), array( '*' ) ), 'postcode' );
}
/**

View File

@ -2018,8 +2018,10 @@ class WC_CLI_Product extends WC_CLI_Command {
'timeout' => 10
) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s', 'woocommerce' ), $image_url ) );
if ( is_wp_error( $response ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) . ' ' . sprintf( __( 'Error: %s.', 'woocommerce' ), $response->get_error_message() ) );
} elseif ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_CLI_Exception( 'woocommerce_cli_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) );
}
// Ensure we have a file name and type

View File

@ -171,7 +171,9 @@ class WC_Gateway_Paypal_Request {
}
// Add shipping costs. Paypal ignores anything over 5 digits (999.99 is the max).
if ( $order->get_total_shipping() > 0 && $order->get_total_shipping() < 999.99 ) {
// We also check that shipping is not the **only** cost as PayPal won't allow payment
// if the items have no cost.
if ( $order->get_total_shipping() > 0 && $order->get_total_shipping() < 999.99 && $this->number_format( $order->get_total_shipping() + $order->get_shipping_tax(), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
$line_item_args['shipping_1'] = $this->number_format( $order->get_total_shipping(), $order );
} elseif ( $order->get_total_shipping() > 0 ) {
$this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), $order->get_shipping_method() ), 1, $this->number_format( $order->get_total_shipping(), $order ) );
@ -193,7 +195,9 @@ class WC_Gateway_Paypal_Request {
$this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_total_shipping() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
// Add shipping costs. Paypal ignores anything over 5 digits (999.99 is the max).
if ( $order->get_total_shipping() > 0 && $order->get_total_shipping() < 999.99 ) {
// We also check that shipping is not the **only** cost as PayPal won't allow payment
// if the items have no cost.
if ( $order->get_total_shipping() > 0 && $order->get_total_shipping() < 999.99 && $this->number_format( $order->get_total_shipping() + $order->get_shipping_tax(), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
$line_item_args['shipping_1'] = $this->number_format( $order->get_total_shipping() + $order->get_shipping_tax(), $order );
} elseif ( $order->get_total_shipping() > 0 ) {
$this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), $order->get_shipping_method() ), 1, $this->number_format( $order->get_total_shipping() + $order->get_shipping_tax(), $order ) );
@ -268,8 +272,9 @@ class WC_Gateway_Paypal_Request {
$calculated_total += $item_line_total;
} else {
$product = $order->get_product_from_item( $item );
$sku = $product ? $product->get_sku() : '';
$item_line_total = $this->number_format( $order->get_item_subtotal( $item, false ), $order );
$line_item = $this->add_line_item( $this->get_order_item_name( $order, $item ), $item['qty'], $item_line_total, $product->get_sku() );
$line_item = $this->add_line_item( $this->get_order_item_name( $order, $item ), $item['qty'], $item_line_total, $sku );
$calculated_total += $item_line_total * $item['qty'];
}

View File

@ -452,7 +452,7 @@ class WC_Gateway_Simplify_Commerce extends WC_Payment_Gateway_CC {
$payment_response = $this->do_payment( $order, $order->get_total(), $pass_tokens );
if ( is_wp_error( $payment_response ) ) {
throw new Exception( $payment_response->get_error_message() );
throw new Simplify_ApiException( $payment_response->get_error_message() );
} else {
// Remove cart
WC()->cart->empty_cart();

View File

@ -327,8 +327,6 @@ if ( ! class_exists( 'WP_Background_Process' ) ) {
} else {
$this->complete();
}
wp_die();
}
/**

View File

@ -98,7 +98,8 @@ class WC_Shipping_Flat_Rate extends WC_Shipping_Method {
public function fee( $atts ) {
$atts = shortcode_atts( array(
'percent' => '',
'min_fee' => ''
'min_fee' => '',
'max_fee' => '',
), $atts );
$calculated_fee = 0;
@ -111,6 +112,10 @@ class WC_Shipping_Flat_Rate extends WC_Shipping_Method {
$calculated_fee = $atts['min_fee'];
}
if ( $atts['max_fee'] && $calculated_fee > $atts['max_fee'] ) {
$calculated_fee = $atts['max_fee'];
}
return $calculated_fee;
}

View File

@ -4,7 +4,7 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$cost_desc = __( 'Enter a cost (excl. tax) or sum, e.g. <code>10.00 * [qty]</code>.', 'woocommerce' ) . '<br/>' . __( 'Supports the following placeholders: <code>[qty]</code> = number of items, <code>[cost]</code> = cost of items, <code>[fee percent="10" min_fee="20"]</code> = Percentage based fee.', 'woocommerce' );
$cost_desc = __( 'Enter a cost (excl. tax) or sum, e.g. <code>10.00 * [qty]</code>.', 'woocommerce' ) . '<br/><br/>' . __( 'Use <code>[qty]</code> for the number of items, <br/><code>[cost]</code> for the total cost of items, and <code>[fee percent="10" min_fee="20" max_fee=""]</code> for percentage based fees.', 'woocommerce' );
/**
* Settings for flat rate shipping.
@ -15,7 +15,7 @@ $settings = array(
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
'default' => __( 'Flat Rate', 'woocommerce' ),
'desc_tip' => true
'desc_tip' => true,
),
'tax_status' => array(
'title' => __( 'Tax Status', 'woocommerce' ),
@ -24,16 +24,16 @@ $settings = array(
'default' => 'taxable',
'options' => array(
'taxable' => __( 'Taxable', 'woocommerce' ),
'none' => _x( 'None', 'Tax status', 'woocommerce' )
)
'none' => _x( 'None', 'Tax status', 'woocommerce' ),
),
),
'cost' => array(
'title' => __( 'Cost', 'woocommerce' ),
'type' => 'text',
'type' => 'price',
'placeholder' => '',
'description' => $cost_desc,
'default' => '',
'desc_tip' => true
'default' => '0',
'desc_tip' => true,
)
);

View File

@ -46,6 +46,18 @@ class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
* @return array
*/
public function get_instance_form_fields() {
wc_enqueue_js( "
jQuery( function( $ ) {
$('#woocommerce_free_shipping_requires').change(function(){
if ( $(this).val() === 'coupon' || $(this).val() === '' ) {
$('#woocommerce_free_shipping_min_amount').closest('tr').hide();
} else {
$('#woocommerce_free_shipping_min_amount').closest('tr').show();
}
}).change();
});
" );
return array(
'title' => array(
'title' => __( 'Title', 'woocommerce' ),
@ -76,18 +88,6 @@ class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
'desc_tip' => true
)
);
wc_enqueue_js( "
jQuery( function( $ ) {
$('#woocommerce_free_shipping_requires').change(function(){
if ( $(this).val() === 'coupon' || $(this).val() === '' ) {
$('#woocommerce_free_shipping_min_amount').closest('tr').hide();
} else {
$('#woocommerce_free_shipping_min_amount').closest('tr').show();
}
}).change();
});
" );
}
/**

View File

@ -80,16 +80,16 @@ class WC_Shipping_Local_Pickup extends WC_Shipping_Method {
'default' => 'taxable',
'options' => array(
'taxable' => __( 'Taxable', 'woocommerce' ),
'none' => _x( 'None', 'Tax status', 'woocommerce' )
)
'none' => _x( 'None', 'Tax status', 'woocommerce' ),
),
),
'cost' => array(
'title' => __( 'Cost', 'woocommerce' ),
'type' => 'text',
'type' => 'price',
'placeholder' => '0',
'description' => __( 'Optional cost for local pickup.', 'woocommerce' ),
'default' => '',
'desc_tip' => true
'desc_tip' => true,
)
);
}

View File

@ -62,6 +62,9 @@ class WC_Shortcode_Cart {
// Update Shipping
if ( ! empty( $_POST['calc_shipping'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) ) {
self::calculate_shipping();
// Also calc totals before we check items so subtotals etc are up to date
WC()->cart->calculate_totals();
}
// Check cart items are valid

View File

@ -47,9 +47,14 @@ class WC_Shortcode_My_Account {
wc_get_template( 'myaccount/form-login.php' );
}
} else {
wc_print_notices();
ob_start();
self::my_account( $atts );
// Start output buffer since the html may need discarding for BW compatibility
ob_start();
// Collect notices before output
$notices = wc_get_notices();
// Output the new account page
self::my_account( $atts );
/**
* Deprecated my-account.php template handling. This code should be
@ -64,7 +69,9 @@ class WC_Shortcode_My_Account {
continue;
}
if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) {
ob_clean();
ob_clean(); // Clear previous buffer
wc_set_notices( $notices );
wc_print_notices();
do_action( 'woocommerce_account_' . $key . '_endpoint', $value );
break;
}
@ -73,6 +80,7 @@ class WC_Shortcode_My_Account {
_deprecated_function( 'Your theme version of my-account.php template', '2.6', 'the latest version, which supports multiple account pages and navigation, from WC 2.6.0' );
}
// Send output buffer
ob_end_flush();
}
}

View File

@ -5,7 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* @version 2.0-beta13
* @version 2.0-beta13.1
*/
abstract class WP_REST_Controller {
@ -418,7 +418,7 @@ abstract class WP_REST_Controller {
protected function get_object_type() {
$schema = $this->get_item_schema();
if ( empty( $schema ) || ! isset( $schema['title'] ) ) {
if ( ! $schema || ! isset( $schema['title'] ) ) {
return null;
}

View File

@ -1,6 +1,6 @@
<?php
/**
* @version 2.0-beta12
* @version 2.0-beta13.1
*/
if ( ! defined( 'ABSPATH' ) ) {

View File

@ -93,6 +93,19 @@ function wc_get_account_menu_items() {
unset( $items['downloads'] );
}
// Check if payment gateways support add new payment methods.
$support_payment_methods = false;
foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway ) {
if ( $gateway->supports( 'add_payment_method' ) || $gateway->supports( 'tokenization' ) ) {
$support_payment_methods = true;
break;
}
}
if ( ! $support_payment_methods ) {
unset( $items['payment-methods'] );
}
return apply_filters( 'woocommerce_account_menu_items', $items );
}

View File

@ -57,6 +57,28 @@ function wc_load_persistent_cart( $user_login, $user ) {
}
}
/**
* Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
*
* Do not use for redirects, use {@see wp_get_referer()} instead.
*
* @since 2.6.1
* @return string|false Referer URL on success, false on failure.
*/
function wc_get_raw_referer() {
if ( function_exists( 'wp_get_raw_referer' ) ) {
return wp_get_raw_referer();
}
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
return wp_unslash( $_REQUEST['_wp_http_referer'] );
} else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
return wp_unslash( $_SERVER['HTTP_REFERER'] );
}
return false;
}
/**
* Add to cart messages.
*
@ -73,7 +95,7 @@ function wc_add_to_cart_message( $products, $show_qty = false ) {
$show_qty = false;
}
if ( ! $show_qty && ! is_array( $products ) ) {
if ( ! $show_qty ) {
$products = array_fill_keys( array_values( $products ), 1 );
}
@ -87,7 +109,7 @@ function wc_add_to_cart_message( $products, $show_qty = false ) {
// Output success messages
if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
$return_to = apply_filters( 'woocommerce_continue_shopping_redirect', wp_get_raw_referer() ? wp_validate_redirect( wp_get_raw_referer(), false ) : wc_get_page_permalink( 'shop' ) );
$return_to = apply_filters( 'woocommerce_continue_shopping_redirect', wc_get_raw_referer() ? wp_validate_redirect( wc_get_raw_referer(), false ) : wc_get_page_permalink( 'shop' ) );
$message = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( $return_to ), esc_html__( 'Continue Shopping', 'woocommerce' ), esc_html( $added_text ) );
} else {
$message = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( wc_get_page_permalink( 'cart' ) ), esc_html__( 'View Cart', 'woocommerce' ), esc_html( $added_text ) );

View File

@ -1229,17 +1229,19 @@ function wc_help_tip( $tip, $allow_html = false ) {
* Return a list of potential postcodes for wildcard searching.
* @since 2.6.0
* @param string $postcode
* @param string $country to format postcode for matching.
* @return string[]
*/
function wc_get_wildcard_postcodes( $postcode ) {
$postcodes = array( '*', strtoupper( $postcode ), strtoupper( $postcode ) . '*' );
$postcode_length = strlen( $postcode );
$wildcard_postcode = strtoupper( $postcode );
function wc_get_wildcard_postcodes( $postcode, $country = '' ) {
$postcodes = array( $postcode );
$postcode = wc_format_postcode( $postcode, $country );
$postcodes[] = $postcode;
$postcode_length = strlen( $postcode );
for ( $i = 0; $i < $postcode_length; $i ++ ) {
$wildcard_postcode = substr( $wildcard_postcode, 0, -1 );
$postcodes[] = $wildcard_postcode . '*';
$postcodes[] = substr( $postcode, 0, ( $i + 1 ) * -1 ) . '*';
}
return $postcodes;
}
@ -1248,14 +1250,15 @@ function wc_get_wildcard_postcodes( $postcode ) {
* postcodes to find matches for numerical ranges, and wildcards.
* @since 2.6.0
* @param string $postcode Postcode you want to match against stored postcodes
* @param array $objects Array of postcode objects from Database
* @param array $objects Array of postcode objects from Database
* @param string $object_id_key DB column name for the ID.
* @param string $object_compare_key DB column name for the value.
* @param string $country Country from which this postcode belongs. Allows for formatting.
* @return array Array of matching object ID and matching values.
*/
function wc_postcode_location_matcher( $postcode, $objects, $object_id_key, $object_compare_key ) {
function wc_postcode_location_matcher( $postcode, $objects, $object_id_key, $object_compare_key, $country = '' ) {
$postcode = wc_normalize_postcode( $postcode );
$wildcard_postcodes = array_map( 'wc_clean', wc_get_wildcard_postcodes( $postcode ) );
$wildcard_postcodes = array_map( 'wc_clean', wc_get_wildcard_postcodes( $postcode, $country ) );
$matches = array();
foreach ( $objects as $object ) {

View File

@ -680,7 +680,7 @@ function wc_format_postcode( $postcode, $country ) {
* @return string Sanitized postcode.
*/
function wc_normalize_postcode( $postcode ) {
return trim( preg_replace( '/[\s\-]/', '', strtoupper( $postcode ) ) );
return preg_replace( '/[\s\-]/', '', trim( strtoupper( $postcode ) ) );
}
/**

View File

@ -90,6 +90,19 @@ function wc_add_notice( $message, $notice_type = 'success' ) {
WC()->session->set( 'wc_notices', $notices );
}
/**
* Set all notices at once.
* @since 2.6.0
*/
function wc_set_notices( $notices ) {
if ( ! did_action( 'woocommerce_init' ) ) {
_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before woocommerce_init.', 'woocommerce' ), '2.6' );
return;
}
WC()->session->set( 'wc_notices', $notices );
}
/**
* Unset all notices.
*
@ -163,10 +176,10 @@ function wc_get_notices( $notice_type = '' ) {
$all_notices = WC()->session->get( 'wc_notices', array() );
if ( empty ( $notice_type ) ) {
if ( empty( $notice_type ) ) {
$notices = $all_notices;
} elseif ( isset( $all_notices[$notice_type] ) ) {
$notices = $all_notices[$notice_type];
} elseif ( isset( $all_notices[ $notice_type ] ) ) {
$notices = $all_notices[ $notice_type ];
} else {
$notices = array();
}

View File

@ -981,3 +981,76 @@ function wc_order_fully_refunded( $order_id ) {
wc_delete_shop_order_transients( $order_id );
}
add_action( 'woocommerce_order_status_refunded', 'wc_order_fully_refunded' );
/**
* Search in orders.
*
* @since 2.6.0
* @param string $term Term to search.
* @return array List of orders ID.
*/
function wc_order_search( $term ) {
global $wpdb;
$term = str_replace( 'Order #', '', wc_clean( $term ) );
$post_ids = array();
// Search fields.
$search_fields = array_map( 'wc_clean', apply_filters( 'woocommerce_shop_order_search_fields', array(
'_order_key',
'_billing_company',
'_billing_address_1',
'_billing_address_2',
'_billing_city',
'_billing_postcode',
'_billing_country',
'_billing_state',
'_billing_email',
'_billing_phone',
'_shipping_address_1',
'_shipping_address_2',
'_shipping_city',
'_shipping_postcode',
'_shipping_country',
'_shipping_state'
) ) );
// Search orders.
if ( is_numeric( $term ) ) {
$post_ids = array_unique( array_merge(
$wpdb->get_col(
$wpdb->prepare( "SELECT DISTINCT p1.post_id FROM {$wpdb->postmeta} p1 WHERE p1.meta_key IN ('" . implode( "','", array_map( 'esc_sql', $search_fields ) ) . "') AND p1.meta_value LIKE '%%%d%%';", absint( $term ) )
),
array( absint( $term ) )
) );
} elseif ( ! empty( $search_fields ) ) {
$post_ids = array_unique( array_merge(
$wpdb->get_col(
$wpdb->prepare( "
SELECT DISTINCT p1.post_id
FROM {$wpdb->postmeta} p1
INNER JOIN {$wpdb->postmeta} p2 ON p1.post_id = p2.post_id
WHERE
( p1.meta_key = '_billing_first_name' AND p2.meta_key = '_billing_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
OR
( p1.meta_key = '_shipping_first_name' AND p2.meta_key = '_shipping_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
OR
( p1.meta_key IN ('" . implode( "','", array_map( 'esc_sql', $search_fields ) ) . "') AND p1.meta_value LIKE '%%%s%%' )
",
$term, $term, $term
)
),
$wpdb->get_col(
$wpdb->prepare( "
SELECT order_id
FROM {$wpdb->prefix}woocommerce_order_items as order_items
WHERE order_item_name LIKE '%%%s%%'
",
$term
)
)
) );
}
return $post_ids;
}

View File

@ -21,28 +21,22 @@ if ( ! defined( 'ABSPATH' ) ) {
* See https://developer.wordpress.org/reference/functions/mysql_to_rfc3339/
*
* @since 2.6.0
* @param string $date_gmt
* @param string|null $date
* @param string $date
* @return string|null ISO8601/RFC3339 formatted datetime.
*/
function wc_rest_prepare_date_response( $date_gmt, $date = null ) {
function wc_rest_prepare_date_response( $date ) {
// Check if mysql_to_rfc3339 exists first!
if ( ! function_exists( 'mysql_to_rfc3339' ) ) {
return null;
}
// Use the date if passed.
if ( isset( $date ) ) {
return mysql_to_rfc3339( $date );
}
// Return null if $date_gmt is empty/zeros.
if ( '0000-00-00 00:00:00' === $date_gmt ) {
// Return null if $date is empty/zeros.
if ( '0000-00-00 00:00:00' === $date ) {
return null;
}
// Return the formatted datetime.
return mysql_to_rfc3339( $date_gmt );
return mysql_to_rfc3339( $date );
}
/**
@ -70,7 +64,9 @@ function wc_rest_upload_image_from_url( $image_url ) {
'timeout' => 10
) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
if ( is_wp_error( $response ) ) {
return new WP_Error( 'woocommerce_rest_invalid_remote_image_url', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) . ' ' . sprintf( __( 'Error: %s.', 'woocommerce' ), $response->get_error_message() ), array( 'status' => 400 ) );
} elseif ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
return new WP_Error( 'woocommerce_rest_invalid_remote_image_url', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ), array( 'status' => 400 ) );
}
@ -172,7 +168,7 @@ function wc_rest_validate_reports_request_arg( $value, $request, $param ) {
return new WP_Error( 'woocommerce_rest_invalid_param', sprintf( __( '%1$s is not of type %2$s', 'woocommerce' ), $param, 'string' ) );
}
if ( 'data' === $args['format'] ) {
if ( 'date' === $args['format'] ) {
$regex = '#^\d{4}-\d{2}-\d{2}$#';
if ( ! preg_match( $regex, $value, $matches ) ) {

View File

@ -40,7 +40,7 @@ function wc_template_redirect() {
}
// Redirect to the product page if we have a single product
elseif ( is_search() && is_post_type_archive( 'product' ) && apply_filters( 'woocommerce_redirect_single_search_result', true ) && 1 === $wp_query->found_posts ) {
elseif ( is_search() && is_post_type_archive( 'product' ) && apply_filters( 'woocommerce_redirect_single_search_result', true ) && 1 === absint( $wp_query->found_posts ) ) {
$product = wc_get_product( $wp_query->post );
if ( $product && $product->is_visible() ) {
@ -134,7 +134,7 @@ add_filter( 'loop_end', 'woocommerce_reset_loop' );
/**
* Products RSS Feed.
*
* @deprecated 2.6
* @access public
*/
function wc_products_rss_feed() {

View File

@ -20,10 +20,8 @@ add_filter( 'post_class', 'wc_product_post_class', 20, 3 );
/**
* WP Header.
*
* @see wc_products_rss_feed()
* @see wc_generator_tag()
*/
add_action( 'wp_head', 'wc_products_rss_feed' );
add_action( 'get_the_generator_html', 'wc_generator_tag', 10, 2 );
add_action( 'get_the_generator_xhtml', 'wc_generator_tag', 10, 2 );

View File

@ -431,6 +431,11 @@ function wc_terms_clauses( $clauses, $taxonomies, $args ) {
return $clauses;
}
// No need to filter counts
if ( strpos( 'COUNT(*)', $clauses['fields'] ) !== false ) {
return $clauses;
}
// Wordpress should give us the taxonomies asked when calling the get_terms function. Only apply to categories and pa_ attributes.
$found = false;
foreach ( (array) $taxonomies as $taxonomy ) {
@ -451,9 +456,7 @@ function wc_terms_clauses( $clauses, $taxonomies, $args ) {
}
// Query fields.
if ( strpos( 'COUNT(*)', $clauses['fields'] ) === false ) {
$clauses['fields'] = 'tm.*, ' . $clauses['fields'];
}
$clauses['fields'] = 'DISTINCT ' . $clauses['fields'];
// Query join.
if ( get_option( 'db_version' ) < 34370 ) {

View File

@ -447,7 +447,7 @@ function wc_update_220_order_status() {
global $wpdb;
$wpdb->query( "
UPDATE {$wpdb->posts} as posts
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-pending'
@ -459,7 +459,7 @@ function wc_update_220_order_status() {
);
$wpdb->query( "
UPDATE {$wpdb->posts} as posts
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-processing'
@ -471,7 +471,7 @@ function wc_update_220_order_status() {
);
$wpdb->query( "
UPDATE {$wpdb->posts} as posts
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-on-hold'
@ -483,7 +483,7 @@ function wc_update_220_order_status() {
);
$wpdb->query( "
UPDATE {$wpdb->posts} as posts
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-completed'
@ -495,7 +495,7 @@ function wc_update_220_order_status() {
);
$wpdb->query( "
UPDATE {$wpdb->posts} as posts
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-cancelled'
@ -507,7 +507,7 @@ function wc_update_220_order_status() {
);
$wpdb->query( "
UPDATE {$wpdb->posts} as posts
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-refunded'
@ -519,7 +519,7 @@ function wc_update_220_order_status() {
);
$wpdb->query( "
UPDATE {$wpdb->posts} as posts
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-failed'
@ -859,6 +859,7 @@ function wc_update_260_termmeta() {
if ( get_option( 'db_version' ) >= 34370 && $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_termmeta';" ) ) {
if ( $wpdb->query( "INSERT INTO {$wpdb->termmeta} ( term_id, meta_key, meta_value ) SELECT woocommerce_term_id, meta_key, meta_value FROM {$wpdb->prefix}woocommerce_termmeta;" ) ) {
$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}woocommerce_termmeta" );
wp_cache_flush();
}
}
}

View File

@ -265,10 +265,14 @@ class WC_Widget_Layered_Nav extends WC_Widget {
protected function get_page_base_url( $taxonomy ) {
if ( defined( 'SHOP_IS_ON_FRONT' ) ) {
$link = home_url();
} elseif ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id('shop') ) ) {
} elseif ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id( 'shop' ) ) ) {
$link = get_post_type_archive_link( 'product' );
} elseif ( is_product_category() ) {
$link = get_term_link( get_query_var( 'product_cat' ), 'product_cat' );
} elseif ( is_product_tag() ) {
$link = get_term_link( get_query_var( 'product_tag' ), 'product_tag' );
} else {
$link = get_term_link( get_query_var('term'), get_query_var('taxonomy') );
$link = get_term_link( get_query_var( 'term' ), get_query_var( 'taxonomy' ) );
}
// Min/Max
@ -343,22 +347,30 @@ class WC_Widget_Layered_Nav extends WC_Widget {
}
}
$meta_query = new WP_Meta_Query( $meta_query );
$tax_query = new WP_Tax_Query( $tax_query );
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
$meta_query = new WP_Meta_Query( $meta_query );
$tax_query = new WP_Tax_Query( $tax_query );
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
$sql = "
SELECT COUNT( {$wpdb->posts}.ID ) as term_count, term_count_relationships.term_taxonomy_id as term_count_id FROM {$wpdb->posts}
INNER JOIN {$wpdb->term_relationships} AS term_count_relationships ON ({$wpdb->posts}.ID = term_count_relationships.object_id)
" . $tax_query_sql['join'] . $meta_query_sql['join'] . "
WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish'
// Generate query
$query = array();
$query['select'] = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) as term_count, terms.term_id as term_count_id";
$query['from'] = "FROM {$wpdb->posts}";
$query['join'] = "
INNER JOIN {$wpdb->term_relationships} AS term_relationships ON {$wpdb->posts}.ID = term_relationships.object_id
INNER JOIN {$wpdb->term_taxonomy} AS term_taxonomy USING( term_taxonomy_id )
INNER JOIN {$wpdb->terms} AS terms USING( term_id )
" . $tax_query_sql['join'] . $meta_query_sql['join'];
$query['where'] = "
WHERE {$wpdb->posts}.post_type IN ( 'product' )
AND {$wpdb->posts}.post_status = 'publish'
" . $tax_query_sql['where'] . $meta_query_sql['where'] . "
AND term_count_relationships.term_taxonomy_id IN (" . implode( ',', array_map( 'absint', $term_ids ) ) . ")
GROUP BY term_count_relationships.term_taxonomy_id;
AND terms.term_id IN (" . implode( ',', array_map( 'absint', $term_ids ) ) . ")
";
$results = $wpdb->get_results( $sql );
$query['group_by'] = "GROUP BY terms.term_id";
$query = apply_filters( 'woocommerce_get_filtered_term_product_counts_query', $query );
$query = implode( ' ', $query );
$results = $wpdb->get_results( $query );
return wp_list_pluck( $results, 'term_count', 'term_count_id' );
}

View File

@ -1,9 +1,9 @@
=== WooCommerce ===
Contributors: automattic, mikejolley, jameskoster, claudiosanches, jshreve, coderkevin, woothemes
Contributors: automattic, mikejolley, jameskoster, claudiosanches, jshreve, coderkevin, woothemes, BFTrick
Tags: ecommerce, e-commerce, store, sales, sell, shop, cart, checkout, downloadable, downloads, paypal, storefront
Requires at least: 4.4
Tested up to: 4.5
Stable tag: 2.5.5
Stable tag: 2.6.1
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@ -158,6 +158,45 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
== Changelog ==
= 2.6.2 - xx/xx/16 =
* Fix - Set max index length on woocommerce_payment_tokenmeta table for utf8mb4 support.
* Fix - is_available check for legacy shipping methods.
* Fix - wc_add_to_cart_message() when non-array is passed.
* Fix - Maximum coupon check should allow the 'maximum' value.
* Fix - Potential notices when leaving out 'default' field for shipping instances.
* Fix - wp_cache_flush after term meta migration/update.
* Fix - wc_add_to_cart_message() when non-array is passed.
* Fix - woocommerce_redirect_single_search_result type check was incorrect.
* Fix - Javascript show/hide of option in free shipping method.
* Fix - Convert ellipsis to three periods when saving postcodes.
* Fix - Prevent get_terms returning duplicates.
* Tweak - Made customer pay link display if order needs_payment() rather than checking pending status.
* Tweak - Zones - Wording clarifications.
* Tweak - Zones - Match zones with postcodes but no country.
* Tweak - Zones - Match zones with no regions as 'everywhere'.
* Tweak - Validate price format for Flat Rate and Local Pickup.
* Tweak - Added view_admin_dashboard cap for disabling the admin access restriction in custom roles.
= 2.6.1 - 16/06/16 =
* Fix - Added missing localized format for line taxes in orders screen to prevent total miscalculation in manual orders.
* Fix - Improved the hour and time fields validation pattern on the orders screen.
* Fix - PayPal does not allow free products, but paid shipping. Workaround by sending shipping as a line item if it is the only cost.
* Fix - SKUs prop on products shortcode.
* Fix - Layered nav counts when term_id does not match term_taxonomy_id (before splitting).
* Fix - Fixed referer links from cart messages in WP 4.4.
* Fix - Fix the showing/hiding of panels when terms do not exist by using wc_get_product_types() for retrieving product types.
* Dev - content-product.php and content-product_cat.php contained the wrong version.
* Dev - Show "matching zone" notice on the frontend when shipping debug mode is on.
* Dev - Restored missing WC_Settings_API::init_form_fields() method to prevent potential errors in 3rd party gateways.
* Dev - API - Fixed returned data from product images (changed `title` to `name`).
* Dev - API - Fixed products schema for `grouped_products`.
* Dev - API - Fixed products attribute options when contains `,`.
* Tweak - Hide 'payment methods' screen if no methods support it.
* Tweak - If shipping method count changes, reset to default.
* Tweak - Avoid normalization of zone postcodes so wildcard matching can be performed on postcodes with spaces. E.g. SP1 *
* Tweak - Allow max_fee in addition to min_fee in flat rate costs fields.
* Tweak - Wrap order_schema_markup() output in hidden div in case script tag is stripped.
= 2.6.0 - 14/06/16 =
* Feature - Introduced Shipping Zone functionality, and re-usable instance based shipping methods.
* Feature - Tabbed "My Account" area.
@ -183,6 +222,7 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
* Tweak - Ignore catalog visibility on products shortcode when specifying IDs or SKUs.
* Tweak - Added context to checkout error messages.
* Tweak - Added SKU field to grouped products.
* Tweak - Moved SKU field to inventory tab.
* Tweak - Support qty display in cart messages.
* Tweak - Hide min order amount field when not needed in shipping settings.
* Tweak - If shipping < 999.99, use 'shipping' arg when passing values to PayPal.
@ -208,7 +248,5 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
== Upgrade Notice ==
= 2.6.0 =
2.6 is a major update so it is important that you make backups, and ensure themes and extensions are 2.6 compatible before upgrading. Developers should catch up with [the development blog](https://woocommerce.wordpress.com/) to see what has been happening in core.
Note: 2.6 includes Shipping Zone functionality. Please ensure shipping method extensions in particular (e.g. Table Rate Shipping) support 2.6 **before** updating.
= 2.6 =
2.6 is a major update. It is important that you make backups and ensure themes and extensions are 2.6 compatible before upgrading, in particular shipping method extensions (e.g. Table Rate Shipping) since 2.6 introduces Shipping Zone functionality. [Read more here](https://woocommerce.wordpress.com/2016/06/14/say-hello-to-woocommerce-2-6-zipping-zebra/).

View File

@ -13,7 +13,7 @@
* @see https://docs.woothemes.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
* @version 2.5.0
* @version 2.6.1
*/
if ( ! defined( 'ABSPATH' ) ) {

View File

@ -13,7 +13,7 @@
* @see https://docs.woothemes.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
* @version 2.5.2
* @version 2.6.1
*/
if ( ! defined( 'ABSPATH' ) ) {

View File

@ -17,6 +17,10 @@
* @package WooCommerce/Templates
* @version 2.6.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<p>

View File

@ -16,7 +16,6 @@ class WC_Tests_Account_Functions extends WC_Unit_Test_Case {
'dashboard' => __( 'Dashboard', 'woocommerce' ),
'orders' => __( 'Orders', 'woocommerce' ),
'edit-address' => __( 'Addresses', 'woocommerce' ),
'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
'edit-account' => __( 'Account Details', 'woocommerce' ),
'customer-logout' => __( 'Logout', 'woocommerce' ),
), wc_get_account_menu_items() );

View File

@ -0,0 +1,105 @@
<?php
/**
* REST API Functions.
* @package WooCommerce\Tests\API
* @since 2.6.0
*/
class WC_Tests_API_Functions extends WC_Unit_Test_Case {
/**
* Test wc_rest_prepare_date_response().
*
* @since 2.6.0
*/
public function test_wc_rest_prepare_date_response() {
$this->assertEquals( '2016-06-06T06:06:06', wc_rest_prepare_date_response( '2016-06-06 06:06:06' ) );
}
/**
* Test wc_rest_upload_image_from_url().
*
* @since 2.6.0
*/
public function test_wc_rest_upload_image_from_url() {
// Only test the error, no need to upload images.
$this->assertIsWPError( wc_rest_upload_image_from_url( 'thing' ) );
}
/**
* Test wc_rest_set_uploaded_image_as_attachment().
*
* @since 2.6.0
*/
public function test_wc_rest_set_uploaded_image_as_attachment() {
$this->assertInternalType( 'int', wc_rest_set_uploaded_image_as_attachment( array( 'file' => '', 'url' => '' ) ) );
}
/**
* Test wc_rest_validate_reports_request_arg().
*
* @since 2.6.0
*/
public function test_wc_rest_validate_reports_request_arg() {
$request = new WP_REST_Request( 'GET', '/wc/v1/foo', array(
'args' => array(
'date' => array(
'type' => 'string',
'format' => 'date',
),
),
) );
// Success.
$this->assertTrue( wc_rest_validate_reports_request_arg( '2016-06-06', $request, 'date' ) );
// Error.
$error = wc_rest_validate_reports_request_arg( 'foo', $request, 'date' );
$this->assertEquals( 'The date you provided is invalid.', $error->get_error_message() );
}
/**
* Test wc_rest_urlencode_rfc3986().
*
* @since 2.6.0
*/
public function test_wc_rest_urlencode_rfc3986() {
$this->assertEquals( 'https%253A%252F%252Fwoocommerce.com%252F', wc_rest_urlencode_rfc3986( 'https://woocommerce.com/' ) );
}
/**
* Test wc_rest_check_post_permissions().
*
* @since 2.6.0
*/
public function test_wc_rest_check_post_permissions() {
$this->isFalse( wc_rest_check_post_permissions( 'shop_order' ) );
}
/**
* Test wc_rest_check_user_permissions().
*
* @since 2.6.0
*/
public function test_wc_rest_check_user_permissions() {
$this->isFalse( wc_rest_check_user_permissions() );
}
/**
* Test wc_rest_check_product_term_permissions().
*
* @since 2.6.0
*/
public function test_wc_rest_check_product_term_permissions() {
$this->isFalse( wc_rest_check_product_term_permissions( 'product_cat' ) );
}
/**
* Test wc_rest_check_manager_permissions().
*
* @since 2.6.0
*/
public function test_wc_rest_check_manager_permissions() {
$this->isFalse( wc_rest_check_manager_permissions( 'reports' ) );
}
}

View File

@ -3,10 +3,10 @@
* Plugin Name: WooCommerce
* Plugin URI: https://www.woothemes.com/woocommerce/
* Description: An e-commerce toolkit that helps you sell anything. Beautifully.
* Version: 2.6.0-RC1
* Version: 2.6.1
* Author: WooThemes
* Author URI: https://woothemes.com
* Requires at least: 4.1
* Requires at least: 4.4
* Tested up to: 4.5
*
* Text Domain: woocommerce
@ -35,7 +35,7 @@ final class WooCommerce {
*
* @var string
*/
public $version = '2.6.0';
public $version = '2.6.1';
/**
* The single instance of the class.