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 == == 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 = = 2.6.0 - 14/06/16 =
* Feature - Introduced Shipping Zone functionality, and re-usable instance based shipping methods. * Feature - Introduced Shipping Zone functionality, and re-usable instance based shipping methods.
* Feature - Tabbed "My Account" area. * Feature - Tabbed "My Account" area.
@ -25,6 +45,7 @@
* Tweak - Ignore catalog visibility on products shortcode when specifying IDs or SKUs. * Tweak - Ignore catalog visibility on products shortcode when specifying IDs or SKUs.
* Tweak - Added context to checkout error messages. * Tweak - Added context to checkout error messages.
* Tweak - Added SKU field to grouped products. * Tweak - Added SKU field to grouped products.
* Tweak - Moved SKU field to inventory tab.
* Tweak - Support qty display in cart messages. * Tweak - Support qty display in cart messages.
* Tweak - Hide min order amount field when not needed in shipping settings. * 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. * 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 { .wc-backbone-modal .wc-shipping-zone-method-selector {
padding: 2px; p {
margin-top: 0;
}
.wc-shipping-zone-method-description { .wc-shipping-zone-method-description {
margin: 1em 0; margin: .75em 1px 0;
line-height: 1.5em; line-height: 1.5em;
color: #999;
font-style: italic;
} }
select { select {
width: 100%; width: 100%;
cursor: pointer;
} }
} }
@ -4941,7 +4946,7 @@ table.bar_chart {
} }
.wc-backbone-modal-main { .wc-backbone-modal-main {
padding-bottom: 51px; padding-bottom: 55px;
header, header,
article { article {
@ -4950,23 +4955,23 @@ table.bar_chart {
} }
.wc-backbone-modal-header { .wc-backbone-modal-header {
height: 50px; height: auto;
background: #fcfcfc; background: #fcfcfc;
padding: 0 50px 0 16px; padding: 1em 1.5em;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
h1 { h1 {
margin: 0; margin: 0;
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
line-height: 50px; line-height: 1.5em;
} }
.modal-close-link { .modal-close-link {
cursor: pointer; cursor: pointer;
color: #777; color: #777;
height: 50px; height: 54px;
width: 50px; width: 54px;
padding: 0; padding: 0;
position: absolute; position: absolute;
top: 0; top: 0;
@ -5000,8 +5005,18 @@ table.bar_chart {
} }
article { 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 { .pagination {
padding: 10px 0 0; padding: 10px 0 0;
text-align: center; text-align: center;
@ -5014,7 +5029,7 @@ table.bar_chart {
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 100; z-index: 100;
padding: 10px 16px; padding: 1em 1.5em;
background: #fcfcfc; background: #fcfcfc;
border-top: 1px solid #dfdfdf; border-top: 1px solid #dfdfdf;
box-shadow: 0 -4px 4px -4px rgba(0,0,0,0.1); 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>' ); $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 { } 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 ) { onSubmit: function( event ) {

File diff suppressed because one or more lines are too long

View File

@ -85,18 +85,29 @@ jQuery( function( $ ) {
} else { } else {
$( 'table.shop_table.cart' ).closest( 'form' ).replaceWith( $new_form ); $( 'table.shop_table.cart' ).closest( 'form' ).replaceWith( $new_form );
$( 'table.shop_table.cart' ).closest( 'form' ).find( 'input[name="update_cart"]' ).prop( 'disabled', true ); $( 'table.shop_table.cart' ).closest( 'form' ).find( 'input[name="update_cart"]' ).prop( 'disabled', true );
$( '.cart_totals' ).replaceWith( $new_totals );
if ( $error.length > 0 ) { if ( $error.length > 0 ) {
show_notice( $error ); show_notice( $error );
} else if ( $message.length > 0 ) { } else if ( $message.length > 0 ) {
show_notice( $message ); show_notice( $message );
} }
update_cart_totals_div( $new_totals );
} }
$( document.body ).trigger( 'updated_wc_div' ); $( 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. * Clear previous notices and shows new one above form.
* *
@ -158,7 +169,7 @@ jQuery( function( $ ) {
* @param {Object} evt The JQuery event. * @param {Object} evt The JQuery event.
*/ */
shipping_method_selected: function( evt ) { shipping_method_selected: function( evt ) {
var target = evt.target; var target = evt.currentTarget;
var shipping_methods = {}; var shipping_methods = {};
@ -173,9 +184,18 @@ jQuery( function( $ ) {
shipping_method: shipping_methods shipping_method: shipping_methods
}; };
$.post( get_url( 'update_shipping_method' ), data, function( response ) { $.ajax( {
$( 'div.cart_totals' ).replaceWith( response ); type: 'post',
$( document.body ).trigger( 'updated_shipping_method' ); 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 ) { shipping_calculator_submit: function( evt ) {
evt.preventDefault(); evt.preventDefault();
var $form = $( evt.target ); var $form = $( evt.currentTarget );
block( $form ); block( $form );
block( $( 'div.cart_totals' ) ); block( $( 'div.cart_totals' ) );
// Provide the submit button value because wc-form-handler expects it. // Provide the submit button value because wc-form-handler expects it.
$( '<input />' ).attr( 'type', 'hidden' ) $( '<input />' ).attr( 'type', 'hidden' )
.attr( 'name', 'calc_shipping' ) .attr( 'name', 'calc_shipping' )
.attr( 'value', 'x' ) .attr( 'value', 'x' )
.appendTo( $form ); .appendTo( $form );
// Make call to actual form post URL. // Make call to actual form post URL.
$.ajax( { $.ajax( {
@ -300,9 +320,11 @@ jQuery( function( $ ) {
$.ajax( { $.ajax( {
url: get_url( 'get_cart_totals' ), url: get_url( 'get_cart_totals' ),
dataType: 'html', dataType: 'html',
success: function( response ) { success: function( response ) {
$( 'div.cart_totals' ).replaceWith( response ); update_cart_totals_div( response );
$( document.body ).trigger( 'updated_cart_totals' ); },
complete: function() {
unblock( $( 'div.cart_totals' ) );
} }
} ); } );
}, },
@ -313,9 +335,7 @@ jQuery( function( $ ) {
* @param {Object} evt The JQuery event * @param {Object} evt The JQuery event
*/ */
cart_submit: function( evt ) { cart_submit: function( evt ) {
evt.preventDefault(); var $form = $( evt.currentTarget );
var $form = $( evt.target );
var $submit = $( document.activeElement ); var $submit = $( document.activeElement );
var $clicked = $( 'input[type=submit][clicked=true]' ); var $clicked = $( 'input[type=submit][clicked=true]' );
@ -327,9 +347,11 @@ jQuery( function( $ ) {
} }
if ( $clicked.is( '[name="update_cart"]' ) || $submit.is( 'input.qty' ) ) { if ( $clicked.is( '[name="update_cart"]' ) || $submit.is( 'input.qty' ) ) {
evt.preventDefault();
this.quantity_update( $form ); this.quantity_update( $form );
} else if ( $clicked.is( '[name="apply_coupon"]' ) || $submit.is( '#coupon_code' ) ) { } else if ( $clicked.is( '[name="apply_coupon"]' ) || $submit.is( '#coupon_code' ) ) {
evt.preventDefault();
this.apply_coupon( $form ); this.apply_coupon( $form );
} }
}, },
@ -387,8 +409,8 @@ jQuery( function( $ ) {
evt.preventDefault(); evt.preventDefault();
var cart = this; var cart = this;
var $tr = $( evt.target ).parents( 'tr' ); var $tr = $( evt.currentTarget ).parents( 'tr' );
var coupon = $( evt.target ).attr( 'data-coupon' ); var coupon = $( evt.currentTarget ).attr( 'data-coupon' );
block( $tr.parents( 'table' ) ); block( $tr.parents( 'table' ) );
@ -450,7 +472,7 @@ jQuery( function( $ ) {
item_remove_clicked: function( evt ) { item_remove_clicked: function( evt ) {
evt.preventDefault(); evt.preventDefault();
var $a = $( evt.target ); var $a = $( evt.currentTarget );
var $form = $a.parents( 'form' ); var $form = $a.parents( 'form' );
block( $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; return true;
} }
/**
* Get post types.
*
* @return array
*/
protected function get_post_types() {
return array( $post->post_type );
}
/** /**
* Get a single item. * Get a single item.
* *
@ -142,7 +151,7 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
$id = (int) $request['id']; $id = (int) $request['id'];
$post = get_post( $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 ) ); 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']; $id = (int) $request['id'];
$post = get_post( $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 ) ); 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']; $force = (bool) $request['force'];
$post = get_post( $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", __( 'Invalid post id.', 'woocommerce' ), array( 'status' => 404 ) ); 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 ); $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( $params['parent'] = array(
'description' => __( 'Limit result set to those of particular parent ids.', 'woocommerce' ), 'description' => __( 'Limit result set to those of particular parent ids.', 'woocommerce' ),
'type' => 'array', 'type' => 'array',

View File

@ -60,7 +60,7 @@ abstract class WC_Settings_API {
* Set default required properties for each field. * Set default required properties for each field.
* @param array * @param array
*/ */
private function set_defaults( $field ) { protected function set_defaults( $field ) {
if ( ! isset( $field['default'] ) ) { if ( ! isset( $field['default'] ) ) {
$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>'; 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. * Return the name of the option in the WP DB.
* @since 2.6.0 * @since 2.6.0

View File

@ -333,7 +333,7 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
$available = $this->is_enabled(); $available = $this->is_enabled();
// Country availability (legacy, for non-zone based methods) // 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(); $countries = is_array( $this->countries ) ? $this->countries : array();
switch ( $this->availability ) { switch ( $this->availability ) {
@ -453,7 +453,7 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
* @return array * @return array
*/ */
public function get_instance_form_fields() { 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( $url = add_query_arg( array(
'utm_source' => 'product', 'utm_source' => 'addons',
'utm_medium' => 'upsell', 'utm_medium' => 'product',
'utm_campaign' => 'wcaddons', 'utm_campaign' => 'woocommerceplugin',
'utm_content' => $utm_content, 'utm_content' => $utm_content,
), $url ); ), $url );

View File

@ -26,16 +26,15 @@ class WC_Admin_API_Keys {
/** /**
* Check if is API Keys settings page. * Check if is API Keys settings page.
*
* @return bool * @return bool
*/ */
private function is_api_keys_settings_page() { private function is_api_keys_settings_page() {
return isset( $_GET['page'] ) return isset( $_GET['page'] )
&& 'wc-settings' == $_GET['page'] && 'wc-settings' === $_GET['page']
&& isset( $_GET['tab'] ) && isset( $_GET['tab'] )
&& 'api' == $_GET['tab'] && 'api' === $_GET['tab']
&& isset( $_GET['section'] ) && 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 '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, 'rounding_precision' => WC_ROUNDING_PRECISION,
'tax_rounding_mode' => WC_TAX_ROUNDING_MODE, '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_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_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' ), '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' ), 'title' => __( 'Tax Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/qp1v19dwrh?videoFoam=true' '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( 'wc-settings-checkout' => array(
'title' => __( 'Checkout Settings', 'woocommerce' ), 'title' => __( 'Checkout Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/65yjv96z51?videoFoam=true' '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( 'wc-settings-account' => array(
'title' => __( 'Account Settings', 'woocommerce' ), 'title' => __( 'Account Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/35mazq7il2?videoFoam=true' 'url' => '//fast.wistia.net/embed/iframe/35mazq7il2?videoFoam=true'
@ -69,20 +109,12 @@ class WC_Admin_Help {
'title' => __( 'Webhook Settings', 'woocommerce' ), 'title' => __( 'Webhook Settings', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/1q0ny74vvq?videoFoam=true' 'url' => '//fast.wistia.net/embed/iframe/1q0ny74vvq?videoFoam=true'
), ),
'wc-settings-checkout-wc_gateway_paypal' => array( 'product' => array(
'title' => __( 'PayPal Standard', 'woocommerce' ), 'title' => __( 'Simple Products', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/rbl7e7l4k2?videoFoam=true' 'url' => '//fast.wistia.net/embed/iframe/ziyjmd4kut?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'
), ),
'edit-product_cat' => array( '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' 'url' => '//fast.wistia.net/embed/iframe/f0j5gzqigg?videoFoam=true'
), ),
'edit-product_tag' => array( 'edit-product_tag' => array(
@ -93,10 +125,6 @@ class WC_Admin_Help {
'title' => __( 'Product Categories, Tags, Shipping Classes, &amp; Attributes', 'woocommerce' ), 'title' => __( 'Product Categories, Tags, Shipping Classes, &amp; Attributes', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/f0j5gzqigg?videoFoam=true' '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( 'wc-status' => array(
'title' => __( 'System Status', 'woocommerce' ), 'title' => __( 'System Status', 'woocommerce' ),
'url' => '//fast.wistia.net/embed/iframe/xdn733nnhi?videoFoam=true' 'url' => '//fast.wistia.net/embed/iframe/xdn733nnhi?videoFoam=true'
@ -143,7 +171,7 @@ class WC_Admin_Help {
'id' => 'woocommerce_101_tab', 'id' => 'woocommerce_101_tab',
'title' => __( 'WooCommerce 101', 'woocommerce' ), 'title' => __( 'WooCommerce 101', 'woocommerce' ),
'content' => '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>' '<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>' . '<h2>' . __( 'Help &amp; Support', 'woocommerce' ) . '</h2>' .
'<p>' . sprintf( '<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' ), __( '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>' '</a>'
) . '</p>' . ) . '</p>' .
'<p>' . sprintf( '<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' ), __( '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 href="https://wordpress.org/support/plugin/woocommerce">',
'</a>', '</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>' '</a>'
) . '</p>' . ) . '</p>' .
'<p>' . __( 'Before asking for help we recommend checking the system status page to identify any problems with your configuration.', 'woocommerce' ) . '</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( $screen->add_help_tab( array(
@ -185,7 +213,7 @@ class WC_Admin_Help {
'content' => 'content' =>
'<h2>' . __( 'Education', 'woocommerce' ) . '</h2>' . '<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>' . __( '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( $screen->add_help_tab( array(
@ -200,11 +228,11 @@ class WC_Admin_Help {
$screen->set_help_sidebar( $screen->set_help_sidebar(
'<p><strong>' . __( 'For more information:', 'woocommerce' ) . '</strong></p>' . '<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://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://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/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=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/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() { public static function update_notice() {
if ( version_compare( get_option( 'woocommerce_db_version' ), WC_VERSION, '<' ) ) { if ( version_compare( get_option( 'woocommerce_db_version' ), WC_VERSION, '<' ) ) {
$updater = new WC_Background_Updater(); $updater = new WC_Background_Updater();
if ( ! $updater->is_updating() ) { if ( $updater->is_updating() || ! empty( $_GET['do_update_woocommerce'] ) ) {
include( 'views/html-notice-update.php' );
} else {
include( 'views/html-notice-updating.php' ); include( 'views/html-notice-updating.php' );
} else {
include( 'views/html-notice-update.php' );
} }
} else { } else {
include( 'views/html-notice-updated.php' ); include( 'views/html-notice-updated.php' );

View File

@ -1508,80 +1508,22 @@ class WC_Admin_Post_Types {
* @param WP_Query $wp * @param WP_Query $wp
*/ */
public function shop_order_search_custom_fields( $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' ) { if ( 'edit.php' != $pagenow || empty( $wp->query_vars['s'] ) || $wp->query_vars['post_type'] != 'shop_order' ) {
return; return;
} }
$search_fields = array_map( 'wc_clean', apply_filters( 'woocommerce_shop_order_search_fields', array( $post_ids = wc_order_search( $_GET['s'] );
'_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_order_id = str_replace( 'Order #', '', $_GET['s'] ); if ( ! empty( $post_ids ) ) {
// Remove "s" - we don't want to search order name.
// 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
unset( $wp->query_vars['s'] ); 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; $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 ) ); $wp->query_vars['post__in'] = array_merge( $post_ids, array( 0 ) );
} }
} }

View File

@ -7,7 +7,7 @@
* @author WooThemes * @author WooThemes
* @category Admin * @category Admin
* @package WooCommerce/Admin * @package WooCommerce/Admin
* @version 2.4.0 * @version 2.6.0
*/ */
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
@ -600,7 +600,7 @@ class WC_Admin_Setup_Wizard {
), ),
'cheque' => array( 'cheque' => array(
'name' => _x( 'Check Payments', 'Check payment method', 'woocommerce' ), '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' => '', 'image' => '',
'class' => '', 'class' => '',
), ),
@ -770,9 +770,9 @@ class WC_Admin_Setup_Wizard {
<div class="wc-setup-next-steps-last"> <div class="wc-setup-next-steps-last">
<h2><?php _e( 'Learn More', 'woocommerce' ); ?></h2> <h2><?php _e( 'Learn More', 'woocommerce' ); ?></h2>
<ul> <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="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=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="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=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="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> </ul>
</div> </div>
</div> </div>

View File

@ -141,13 +141,23 @@ class WC_Admin {
public function prevent_admin_access() { public function prevent_admin_access() {
$prevent_access = false; $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' ) ) { if ( 'yes' === get_option( 'woocommerce_lock_down_admin', 'yes' ) && ! is_ajax() && basename( $_SERVER["SCRIPT_FILENAME"] ) !== 'admin-post.php' ) {
$prevent_access = true; $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 ( apply_filters( 'woocommerce_prevent_admin_access', $prevent_access ) ) {
if ( $prevent_access ) {
wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) ); wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
exit; exit;
} }

View File

@ -197,11 +197,11 @@ class WC_Meta_Box_Order_Data {
<h3><?php _e( 'General Details', 'woocommerce' ); ?></h3> <h3><?php _e( 'General Details', 'woocommerce' ); ?></h3>
<p class="form-field form-field-wide"><label for="order_date"><?php _e( 'Order date:', 'woocommerce' ) ?></label> <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>
<p class="form-field form-field-wide wc-order-status"><label for="order_status"><?php _e( 'Order status:', 'woocommerce' ) ?> <?php <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>', printf( '<a href="%s">%s &rarr;</a>',
esc_url( $order->get_checkout_payment_url() ), esc_url( $order->get_checkout_payment_url() ),
__( 'Customer payment page', 'woocommerce' ) __( '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 = 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' ) . '">'; $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>'; $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="split-input">
<div class="input"> <div class="input">
<label><?php esc_attr_e( 'Pre-discount:', 'woocommerce' ); ?></label> <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>
<div class="input"> <div class="input">
<label><?php esc_attr_e( 'Total:', 'woocommerce' ); ?></label> <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> </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' ), 'wc_shipping_zones_nonce' => wp_create_nonce( 'wc_shipping_zones_nonce' ),
'strings' => array( 'strings' => array(
'unload_confirmation_msg' => __( 'Your changed data will be lost if you leave this page without saving.', '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' ), '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' ); wp_enqueue_script( 'wc-shipping-zones' );

View File

@ -98,6 +98,8 @@ if ( ! defined( 'ABSPATH' ) ) {
<article> <article>
<form action="" method="post"> <form action="" method="post">
<div class="wc-shipping-zone-method-selector"> <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"> <select name="add_method_id">
<?php <?php
foreach ( WC()->shipping->load_shipping_methods() as $method ) { 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> <a href="admin.php?page=wc-settings&amp;tab=shipping&amp;zone_id={{ data.zone_id }}"><?php _e( 'View', 'woocommerce' ); ?></a>
</div> </div>
</td> </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"> <td class="wc-shipping-zone-methods">
<ul> <ul>
<?php <?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>'; 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 { } 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> <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> <article>
<form action="" method="post"> <form action="" method="post">
<div class="wc-shipping-zone-method-selector"> <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"> <select name="add_method_id">
<?php <?php
foreach ( WC()->shipping->load_shipping_methods() as $method ) { 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' ), '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', 'id' => 'woocommerce_shipping_tax_class',
'css' => 'min-width:150px;', 'css' => 'min-width:150px;',
'default' => 'title', 'default' => '',
'type' => 'select', 'type' => 'select',
'class' => 'wc-enhanced-select', 'class' => 'wc-enhanced-select',
'options' => array( '' => __( 'Shipping tax class based on cart items', 'woocommerce' ), 'standard' => __( 'Standard', 'woocommerce' ) ) + $classes_options, '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><?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"> <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="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', '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="<?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> </p>
</div> </div>

View File

@ -9,5 +9,5 @@ if ( ! defined( 'ABSPATH' ) ) {
?> ?>
<div id="message" class="updated woocommerce-message wc-connect"> <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> </div>

View File

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

View File

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

View File

@ -684,7 +684,7 @@ class WC_REST_Customers_Controller extends WC_REST_Controller {
), ),
'total_spent' => array( 'total_spent' => array(
'description' => __( 'Total amount spent.', 'woocommerce' ), 'description' => __( 'Total amount spent.', 'woocommerce' ),
'type' => 'float', 'type' => 'string',
'context' => array( 'view', 'edit' ), 'context' => array( 'view', 'edit' ),
'readonly' => true, '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'] ) ) { if ( ! empty( $request['product'] ) ) {
$order_ids = $wpdb->get_col( $wpdb->prepare( " $order_ids = $wpdb->get_col( $wpdb->prepare( "
SELECT order_id SELECT order_id
@ -426,6 +427,16 @@ class WC_REST_Orders_Controller extends WC_REST_Posts_Controller {
$args['post__in'] = $order_ids; $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; 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'] ); update_post_meta( $order->id, '_payment_method', $request['payment_method'] );
} }
if ( ! empty( $request['payment_method_title'] ) ) { 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'] ) { if ( true === $request['set_paid'] ) {
$order->payment_complete( $request['transaction_id'] ); $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. * 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_created' => wc_rest_prepare_date_response( $attachment_post->post_date_gmt ),
'date_modified' => wc_rest_prepare_date_response( $attachment_post->post_modified_gmt ), 'date_modified' => wc_rest_prepare_date_response( $attachment_post->post_modified_gmt ),
'src' => current( $attachment ), '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 ), 'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ),
'position' => (int) $position, 'position' => (int) $position,
); );
@ -290,10 +299,10 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
if ( empty( $images ) ) { if ( empty( $images ) ) {
$images[] = array( $images[] = array(
'id' => 0, 'id' => 0,
'date_created' => wc_rest_prepare_date_response( time() ), // Default to now. 'date_created' => wc_rest_prepare_date_response( current_time( 'mysql' ) ), // Default to now.
'date_modified' => wc_rest_prepare_date_response( time() ), 'date_modified' => wc_rest_prepare_date_response( current_time( 'mysql' ) ),
'src' => wc_placeholder_img_src(), 'src' => wc_placeholder_img_src(),
'title' => __( 'Placeholder', 'woocommerce' ), 'name' => __( 'Placeholder', 'woocommerce' ),
'alt' => __( 'Placeholder', 'woocommerce' ), 'alt' => __( 'Placeholder', 'woocommerce' ),
'position' => 0, 'position' => 0,
); );
@ -345,6 +354,23 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
return $default; 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. * Get the attributes for a product or product variation.
* *
@ -376,15 +402,14 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
} }
} else { } else {
foreach ( $product->get_attributes() as $attribute ) { foreach ( $product->get_attributes() as $attribute ) {
// Taxonomy-based attributes are comma-separated, others are pipe (|) separated.
if ( $attribute['is_taxonomy'] ) { if ( $attribute['is_taxonomy'] ) {
$attributes[] = array( $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'] ), 'name' => $this->get_attribute_taxonomy_label( $attribute['name'] ),
'position' => (int) $attribute['position'], 'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'], 'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'], 'variation' => (bool) $attribute['is_variation'],
'options' => array_map( 'trim', explode( ',', $product->get_attribute( $attribute['name'] ) ) ), 'options' => $this->get_attribute_options( $product->id, $attribute ),
); );
} else { } else {
$attributes[] = array( $attributes[] = array(
@ -393,7 +418,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
'position' => (int) $attribute['position'], 'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'], 'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'], '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 ) { if ( $product->is_type( 'variation' ) && $product->parent ) {
$links['up'] = array( $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 ) ) { } elseif ( $product->is_type( 'simple' ) && ! empty( $product->post->post_parent ) ) {
$links['up'] = array( $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'] ) ); update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) );
} }
// Set the image title if present. // Set the image name if present.
if ( ! empty( $image['title'] ) && $attachment_id ) { if ( ! empty( $image['name'] ) && $attachment_id ) {
wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['title'] ) ); 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'] ) ); update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) );
} }
// Set the image title if present. // Set the image name if present.
if ( ! empty( $image['title'] ) ) { if ( ! empty( $image['name'] ) ) {
wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['title'] ) ); wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['name'] ) );
} }
update_post_meta( $variation_id, '_thumbnail_id', $attachment_id ); 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' ), 'description' => __( 'List of grouped products ID.', 'woocommerce' ),
'type' => 'array', 'type' => 'array',
'context' => array( 'view', 'edit' ), 'context' => array( 'view', 'edit' ),

View File

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

View File

@ -470,6 +470,23 @@ class WC_API_Products extends WC_API_Resource {
return $images; 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 * Get the attributes for a product or product variation
* *
@ -496,19 +513,12 @@ class WC_API_Products extends WC_API_Resource {
} else { } else {
foreach ( $product->get_attributes() as $attribute ) { 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( $attributes[] = array(
'name' => ucwords( str_replace( 'pa_', '', $attribute['name'] ) ), 'name' => ucwords( str_replace( 'pa_', '', $attribute['name'] ) ),
'position' => $attribute['position'], 'position' => $attribute['position'],
'visible' => (bool) $attribute['is_visible'], 'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'], '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 'timeout' => 10
) ); ) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { 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 ), 400 ); 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 // Ensure we have a file name and type
@ -1873,6 +1875,23 @@ class WC_API_Products extends WC_API_Resource {
return $attachment_id; 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 * Get the attributes for a product or product variation
* *
@ -1900,21 +1919,13 @@ class WC_API_Products extends WC_API_Resource {
} else { } else {
foreach ( $product->get_attributes() as $attribute ) { 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( $attributes[] = array(
'name' => wc_attribute_label( $attribute['name'] ), 'name' => wc_attribute_label( $attribute['name'] ),
'slug' => str_replace( 'pa_', '', $attribute['name'] ), 'slug' => str_replace( 'pa_', '', $attribute['name'] ),
'position' => (int) $attribute['position'], 'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'], 'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'], '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 'timeout' => 10
) ); ) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { 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 ), 400 ); 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. // Ensure we have a file name and type.
@ -2454,6 +2456,23 @@ class WC_API_Products extends WC_API_Resource {
return $attachment_id; 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 * Get the attributes for a product or product variation
* *
@ -2481,21 +2500,13 @@ class WC_API_Products extends WC_API_Resource {
} else { } else {
foreach ( $product->get_attributes() as $attribute ) { 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( $attributes[] = array(
'name' => wc_attribute_label( $attribute['name'], $product ), 'name' => wc_attribute_label( $attribute['name'], $product ),
'slug' => str_replace( 'pa_', '', $attribute['name'] ), 'slug' => str_replace( 'pa_', '', $attribute['name'] ),
'position' => (int) $attribute['position'], 'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'], 'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'], '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'; protected $action = 'wc_updater';
/**
* @var string
*/
protected $error = '';
/** /**
* Dispatch updater. * Dispatch updater.
* *
@ -41,15 +36,36 @@ class WC_Background_Updater extends WP_Background_Process {
*/ */
public function dispatch() { public function dispatch() {
$dispatched = parent::dispatch(); $dispatched = parent::dispatch();
$logger = new WC_Logger();
if ( is_wp_error( $dispatched ) ) { if ( is_wp_error( $dispatched ) ) {
$this->error = $dispatched->get_error_message(); $logger->add( 'wc_db_updates', sprintf( 'Unable to dispatch WooCommerce updater: %s', $dispatched->get_error_message() ) );
add_action( 'admin_notices', array( $this, 'dispatch_error' ) );
} }
} }
/** /**
* 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() { protected function schedule_event() {
if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) { 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? * Is the updater running?
* @return boolean * @return boolean

View File

@ -405,7 +405,7 @@ class WC_Coupon {
* @throws Exception * @throws Exception
*/ */
private function validate_maximum_amount() { 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 ); 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() ), 'orderNumber' => strval( $order->get_order_number() ),
'priceCurrency' => $order->get_order_currency(), 'priceCurrency' => $order->get_order_currency(),
'price' => $order->get_total(), 'price' => $order->get_total(),
'acceptedOffer' => count( $accepted_offers ) > 1 ? $accepted_offers : $accepted_offers[0], 'acceptedOffer' => $accepted_offers,
'url' => $order->get_view_order_url(), '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 ); $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() { public static function init() {
add_action( 'init', array( __CLASS__, 'check_version' ), 5 ); 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( 'admin_init', array( __CLASS__, 'install_actions' ) );
add_action( 'in_plugin_update_message-woocommerce/woocommerce.php', array( __CLASS__, 'in_plugin_update_message' ) ); 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' ) ); 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( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) );
add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) ); add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) );
add_action( 'woocommerce_plugin_background_installer', array( __CLASS__, 'background_installer' ), 10, 2 ); 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(); self::$background_updater = new WC_Background_Updater();
} }
@ -116,6 +122,10 @@ class WC_Install {
self::update(); self::update();
WC_Admin_Notices::add_notice( '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, meta_value longtext NULL,
PRIMARY KEY (meta_id), PRIMARY KEY (meta_id),
KEY payment_token_id (payment_token_id), KEY payment_token_id (payment_token_id),
KEY meta_key (meta_key) KEY meta_key (meta_key($max_index_length))
) $collate; ) $collate;
"; ";

View File

@ -130,12 +130,34 @@ class WC_Query {
return $title; 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. * Add endpoints for query vars.
*/ */
public function add_endpoints() { public function add_endpoints() {
$mask = $this->get_endpoints_mask();
foreach ( $this->query_vars as $key => $var ) { 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 // 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' ) ) { 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(); $tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
if ( ! empty( $args['taxonomy'] ) && ! empty( $args['term'] ) ) { if ( ! empty( $args['taxonomy'] ) && ! empty( $args['term'] ) ) {
$tax_query[] = array( $tax_query[ $args['taxonomy'] ] = array(
'taxonomy' => $args['taxonomy'], 'taxonomy' => $args['taxonomy'],
'terms' => array( $args['term'] ), 'terms' => array( $args['term'] ),
'field' => 'slug', '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; return $tax_query;
} }

View File

@ -220,8 +220,10 @@ class WC_Shipping_Zone extends WC_Data {
if ( sizeof( $location_parts ) > $max ) { if ( sizeof( $location_parts ) > $max ) {
$remaining = 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 ); 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 ); 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 ) { public function add_location( $code, $type ) {
if ( $this->is_valid_location_type( $type ) ) { if ( $this->is_valid_location_type( $type ) ) {
if ( 'postcode' === $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( $location = array(
'code' => wc_clean( $code ), 'code' => wc_clean( $code ),

View File

@ -133,14 +133,15 @@ class WC_Shipping_Zones {
$criteria = array(); $criteria = array();
$criteria[] = $wpdb->prepare( "( ( location_type = 'country' AND location_code = %s )", $country ); $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 = '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 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';" ); $postcode_locations = $wpdb->get_results( "SELECT zone_id, location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE location_type = 'postcode';" );
if ( $postcode_locations ) { if ( $postcode_locations ) {
$zone_ids_with_postcode_rules = array_map( 'absint', wp_list_pluck( $postcode_locations, 'zone_id' ) ); $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 ) ) ); $do_not_match = array_unique( array_diff( $zone_ids_with_postcode_rules, array_keys( $matches ) ) );
if ( ! empty( $do_not_match ) ) { if ( ! empty( $do_not_match ) ) {
@ -151,7 +152,7 @@ class WC_Shipping_Zones {
// Get matching zones // Get matching zones
$matching_zone_id = $wpdb->get_var( " $matching_zone_id = $wpdb->get_var( "
SELECT zones.zone_id FROM {$wpdb->prefix}woocommerce_shipping_zones as zones 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 ) . " WHERE " . implode( ' ', $criteria ) . "
ORDER BY zone_order ASC LIMIT 1 ORDER BY zone_order ASC LIMIT 1
" ); " );

View File

@ -132,8 +132,14 @@ class WC_Shipping {
*/ */
public function load_shipping_methods( $package = array() ) { public function load_shipping_methods( $package = array() ) {
if ( ! empty( $package ) ) { if ( ! empty( $package ) ) {
$status_options = get_option( 'woocommerce_status_options', array() );
$shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $package ); $shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $package );
$this->shipping_methods = $shipping_zone->get_shipping_methods( true ); $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 { } else {
$this->shipping_methods = array(); $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 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'] ) ) { 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; $chosen_methods[ $i ] = $chosen_method;
$method_counts[ $i ] = sizeof( $package['rates'] ); $method_counts[ $i ] = sizeof( $package['rates'] );
do_action( 'woocommerce_shipping_method_chosen', $chosen_method ); do_action( 'woocommerce_shipping_method_chosen', $chosen_method );

View File

@ -348,14 +348,14 @@ class WC_Shortcodes {
); );
// Ignore catalog visibility // 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'] ) ) { if ( ! empty( $atts['ids'] ) ) {
$query_args['post__in'] = array_map( 'trim', explode( ',', $atts['ids'] ) ); $query_args['post__in'] = array_map( 'trim', explode( ',', $atts['ids'] ) );
// Ignore catalog visibility // 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' ); 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 ) ); $criteria[] = $wpdb->prepare( "tax_rate_class = %s", sanitize_title( $tax_class ) );
// Pre-query postcode ranges for PHP based matching. // 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 '%...%';" ); $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 ) { 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 ) ) { if ( ! empty( $matches ) ) {
foreach ( $matches as $matched_postcodes ) { foreach ( $matches as $matched_postcodes ) {
$postcode_search = array_merge( $postcode_search, $matched_postcodes ); $postcode_search = array_merge( $postcode_search, $matched_postcodes );
@ -818,7 +818,11 @@ class WC_Tax {
if ( ! is_array( $postcodes ) ) { if ( ! is_array( $postcodes ) ) {
$postcodes = explode( ';', $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 'timeout' => 10
) ); ) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { 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 ) ); 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 // 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). // 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 ); $line_item_args['shipping_1'] = $this->number_format( $order->get_total_shipping(), $order );
} elseif ( $order->get_total_shipping() > 0 ) { } 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 ) ); $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() ); $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). // 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 ); $line_item_args['shipping_1'] = $this->number_format( $order->get_total_shipping() + $order->get_shipping_tax(), $order );
} elseif ( $order->get_total_shipping() > 0 ) { } 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 ) ); $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; $calculated_total += $item_line_total;
} else { } else {
$product = $order->get_product_from_item( $item ); $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 ); $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']; $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 ); $payment_response = $this->do_payment( $order, $order->get_total(), $pass_tokens );
if ( is_wp_error( $payment_response ) ) { if ( is_wp_error( $payment_response ) ) {
throw new Exception( $payment_response->get_error_message() ); throw new Simplify_ApiException( $payment_response->get_error_message() );
} else { } else {
// Remove cart // Remove cart
WC()->cart->empty_cart(); WC()->cart->empty_cart();

View File

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

View File

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

View File

@ -4,7 +4,7 @@ if ( ! defined( 'ABSPATH' ) ) {
exit; 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. * Settings for flat rate shipping.
@ -15,7 +15,7 @@ $settings = array(
'type' => 'text', 'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ), 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
'default' => __( 'Flat Rate', 'woocommerce' ), 'default' => __( 'Flat Rate', 'woocommerce' ),
'desc_tip' => true 'desc_tip' => true,
), ),
'tax_status' => array( 'tax_status' => array(
'title' => __( 'Tax Status', 'woocommerce' ), 'title' => __( 'Tax Status', 'woocommerce' ),
@ -24,16 +24,16 @@ $settings = array(
'default' => 'taxable', 'default' => 'taxable',
'options' => array( 'options' => array(
'taxable' => __( 'Taxable', 'woocommerce' ), 'taxable' => __( 'Taxable', 'woocommerce' ),
'none' => _x( 'None', 'Tax status', 'woocommerce' ) 'none' => _x( 'None', 'Tax status', 'woocommerce' ),
) ),
), ),
'cost' => array( 'cost' => array(
'title' => __( 'Cost', 'woocommerce' ), 'title' => __( 'Cost', 'woocommerce' ),
'type' => 'text', 'type' => 'price',
'placeholder' => '', 'placeholder' => '',
'description' => $cost_desc, 'description' => $cost_desc,
'default' => '', 'default' => '0',
'desc_tip' => true 'desc_tip' => true,
) )
); );

View File

@ -46,6 +46,18 @@ class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
* @return array * @return array
*/ */
public function get_instance_form_fields() { 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( return array(
'title' => array( 'title' => array(
'title' => __( 'Title', 'woocommerce' ), 'title' => __( 'Title', 'woocommerce' ),
@ -76,18 +88,6 @@ class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
'desc_tip' => true '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', 'default' => 'taxable',
'options' => array( 'options' => array(
'taxable' => __( 'Taxable', 'woocommerce' ), 'taxable' => __( 'Taxable', 'woocommerce' ),
'none' => _x( 'None', 'Tax status', 'woocommerce' ) 'none' => _x( 'None', 'Tax status', 'woocommerce' ),
) ),
), ),
'cost' => array( 'cost' => array(
'title' => __( 'Cost', 'woocommerce' ), 'title' => __( 'Cost', 'woocommerce' ),
'type' => 'text', 'type' => 'price',
'placeholder' => '0', 'placeholder' => '0',
'description' => __( 'Optional cost for local pickup.', 'woocommerce' ), 'description' => __( 'Optional cost for local pickup.', 'woocommerce' ),
'default' => '', 'default' => '',
'desc_tip' => true 'desc_tip' => true,
) )
); );
} }

View File

@ -62,6 +62,9 @@ class WC_Shortcode_Cart {
// Update Shipping // Update Shipping
if ( ! empty( $_POST['calc_shipping'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) ) { if ( ! empty( $_POST['calc_shipping'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) ) {
self::calculate_shipping(); 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 // Check cart items are valid

View File

@ -47,9 +47,14 @@ class WC_Shortcode_My_Account {
wc_get_template( 'myaccount/form-login.php' ); wc_get_template( 'myaccount/form-login.php' );
} }
} else { } else {
wc_print_notices(); // Start output buffer since the html may need discarding for BW compatibility
ob_start(); ob_start();
self::my_account( $atts );
// 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 * Deprecated my-account.php template handling. This code should be
@ -64,7 +69,9 @@ class WC_Shortcode_My_Account {
continue; continue;
} }
if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) { 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 ); do_action( 'woocommerce_account_' . $key . '_endpoint', $value );
break; 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' ); _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(); 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 { abstract class WP_REST_Controller {
@ -418,7 +418,7 @@ abstract class WP_REST_Controller {
protected function get_object_type() { protected function get_object_type() {
$schema = $this->get_item_schema(); $schema = $this->get_item_schema();
if ( empty( $schema ) || ! isset( $schema['title'] ) ) { if ( ! $schema || ! isset( $schema['title'] ) ) {
return null; return null;
} }

View File

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

View File

@ -93,6 +93,19 @@ function wc_get_account_menu_items() {
unset( $items['downloads'] ); 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 ); 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. * Add to cart messages.
* *
@ -73,7 +95,7 @@ function wc_add_to_cart_message( $products, $show_qty = false ) {
$show_qty = false; $show_qty = false;
} }
if ( ! $show_qty && ! is_array( $products ) ) { if ( ! $show_qty ) {
$products = array_fill_keys( array_values( $products ), 1 ); $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 // Output success messages
if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) { 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 ) ); $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 { } 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 ) ); $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. * Return a list of potential postcodes for wildcard searching.
* @since 2.6.0 * @since 2.6.0
* @param string $postcode * @param string $postcode
* @param string $country to format postcode for matching.
* @return string[] * @return string[]
*/ */
function wc_get_wildcard_postcodes( $postcode ) { function wc_get_wildcard_postcodes( $postcode, $country = '' ) {
$postcodes = array( '*', strtoupper( $postcode ), strtoupper( $postcode ) . '*' ); $postcodes = array( $postcode );
$postcode_length = strlen( $postcode ); $postcode = wc_format_postcode( $postcode, $country );
$wildcard_postcode = strtoupper( $postcode ); $postcodes[] = $postcode;
$postcode_length = strlen( $postcode );
for ( $i = 0; $i < $postcode_length; $i ++ ) { for ( $i = 0; $i < $postcode_length; $i ++ ) {
$wildcard_postcode = substr( $wildcard_postcode, 0, -1 ); $postcodes[] = substr( $postcode, 0, ( $i + 1 ) * -1 ) . '*';
$postcodes[] = $wildcard_postcode . '*';
} }
return $postcodes; return $postcodes;
} }
@ -1248,14 +1250,15 @@ function wc_get_wildcard_postcodes( $postcode ) {
* postcodes to find matches for numerical ranges, and wildcards. * postcodes to find matches for numerical ranges, and wildcards.
* @since 2.6.0 * @since 2.6.0
* @param string $postcode Postcode you want to match against stored postcodes * @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_id_key DB column name for the ID.
* @param string $object_compare_key DB column name for the value. * @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. * @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 ); $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(); $matches = array();
foreach ( $objects as $object ) { foreach ( $objects as $object ) {

View File

@ -680,7 +680,7 @@ function wc_format_postcode( $postcode, $country ) {
* @return string Sanitized postcode. * @return string Sanitized postcode.
*/ */
function wc_normalize_postcode( $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 ); 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. * Unset all notices.
* *
@ -163,10 +176,10 @@ function wc_get_notices( $notice_type = '' ) {
$all_notices = WC()->session->get( 'wc_notices', array() ); $all_notices = WC()->session->get( 'wc_notices', array() );
if ( empty ( $notice_type ) ) { if ( empty( $notice_type ) ) {
$notices = $all_notices; $notices = $all_notices;
} elseif ( isset( $all_notices[$notice_type] ) ) { } elseif ( isset( $all_notices[ $notice_type ] ) ) {
$notices = $all_notices[$notice_type]; $notices = $all_notices[ $notice_type ];
} else { } else {
$notices = array(); $notices = array();
} }

View File

@ -981,3 +981,76 @@ function wc_order_fully_refunded( $order_id ) {
wc_delete_shop_order_transients( $order_id ); wc_delete_shop_order_transients( $order_id );
} }
add_action( 'woocommerce_order_status_refunded', 'wc_order_fully_refunded' ); 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/ * See https://developer.wordpress.org/reference/functions/mysql_to_rfc3339/
* *
* @since 2.6.0 * @since 2.6.0
* @param string $date_gmt * @param string $date
* @param string|null $date
* @return string|null ISO8601/RFC3339 formatted datetime. * @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! // Check if mysql_to_rfc3339 exists first!
if ( ! function_exists( 'mysql_to_rfc3339' ) ) { if ( ! function_exists( 'mysql_to_rfc3339' ) ) {
return null; return null;
} }
// Use the date if passed. // Return null if $date is empty/zeros.
if ( isset( $date ) ) { if ( '0000-00-00 00:00:00' === $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; return null;
} }
// Return the formatted datetime. // 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 '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 ) ); 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' ) ); 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}$#'; $regex = '#^\d{4}-\d{2}-\d{2}$#';
if ( ! preg_match( $regex, $value, $matches ) ) { 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 // 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 ); $product = wc_get_product( $wp_query->post );
if ( $product && $product->is_visible() ) { if ( $product && $product->is_visible() ) {
@ -134,7 +134,7 @@ add_filter( 'loop_end', 'woocommerce_reset_loop' );
/** /**
* Products RSS Feed. * Products RSS Feed.
* * @deprecated 2.6
* @access public * @access public
*/ */
function wc_products_rss_feed() { function wc_products_rss_feed() {

View File

@ -20,10 +20,8 @@ add_filter( 'post_class', 'wc_product_post_class', 20, 3 );
/** /**
* WP Header. * WP Header.
* *
* @see wc_products_rss_feed()
* @see wc_generator_tag() * @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_html', 'wc_generator_tag', 10, 2 );
add_action( 'get_the_generator_xhtml', '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; 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. // Wordpress should give us the taxonomies asked when calling the get_terms function. Only apply to categories and pa_ attributes.
$found = false; $found = false;
foreach ( (array) $taxonomies as $taxonomy ) { foreach ( (array) $taxonomies as $taxonomy ) {
@ -451,9 +456,7 @@ function wc_terms_clauses( $clauses, $taxonomies, $args ) {
} }
// Query fields. // Query fields.
if ( strpos( 'COUNT(*)', $clauses['fields'] ) === false ) { $clauses['fields'] = 'DISTINCT ' . $clauses['fields'];
$clauses['fields'] = 'tm.*, ' . $clauses['fields'];
}
// Query join. // Query join.
if ( get_option( 'db_version' ) < 34370 ) { if ( get_option( 'db_version' ) < 34370 ) {

View File

@ -447,7 +447,7 @@ function wc_update_220_order_status() {
global $wpdb; global $wpdb;
$wpdb->query( " $wpdb->query( "
UPDATE {$wpdb->posts} as posts 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->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id ) LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-pending' SET posts.post_status = 'wc-pending'
@ -459,7 +459,7 @@ function wc_update_220_order_status() {
); );
$wpdb->query( " $wpdb->query( "
UPDATE {$wpdb->posts} as posts 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->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id ) LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-processing' SET posts.post_status = 'wc-processing'
@ -471,7 +471,7 @@ function wc_update_220_order_status() {
); );
$wpdb->query( " $wpdb->query( "
UPDATE {$wpdb->posts} as posts 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->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id ) LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-on-hold' SET posts.post_status = 'wc-on-hold'
@ -483,7 +483,7 @@ function wc_update_220_order_status() {
); );
$wpdb->query( " $wpdb->query( "
UPDATE {$wpdb->posts} as posts 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->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id ) LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-completed' SET posts.post_status = 'wc-completed'
@ -495,7 +495,7 @@ function wc_update_220_order_status() {
); );
$wpdb->query( " $wpdb->query( "
UPDATE {$wpdb->posts} as posts 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->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id ) LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-cancelled' SET posts.post_status = 'wc-cancelled'
@ -507,7 +507,7 @@ function wc_update_220_order_status() {
); );
$wpdb->query( " $wpdb->query( "
UPDATE {$wpdb->posts} as posts 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->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id ) LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-refunded' SET posts.post_status = 'wc-refunded'
@ -519,7 +519,7 @@ function wc_update_220_order_status() {
); );
$wpdb->query( " $wpdb->query( "
UPDATE {$wpdb->posts} as posts 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->term_taxonomy} AS tax USING( term_taxonomy_id )
LEFT JOIN {$wpdb->terms} AS term USING( term_id ) LEFT JOIN {$wpdb->terms} AS term USING( term_id )
SET posts.post_status = 'wc-failed' 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 ( 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;" ) ) { 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" ); $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 ) { protected function get_page_base_url( $taxonomy ) {
if ( defined( 'SHOP_IS_ON_FRONT' ) ) { if ( defined( 'SHOP_IS_ON_FRONT' ) ) {
$link = home_url(); $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' ); $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 { } 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 // Min/Max
@ -343,22 +347,30 @@ class WC_Widget_Layered_Nav extends WC_Widget {
} }
} }
$meta_query = new WP_Meta_Query( $meta_query ); $meta_query = new WP_Meta_Query( $meta_query );
$tax_query = new WP_Tax_Query( $tax_query ); $tax_query = new WP_Tax_Query( $tax_query );
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' ); $meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' ); $tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
$sql = " // Generate query
SELECT COUNT( {$wpdb->posts}.ID ) as term_count, term_count_relationships.term_taxonomy_id as term_count_id FROM {$wpdb->posts} $query = array();
INNER JOIN {$wpdb->term_relationships} AS term_count_relationships ON ({$wpdb->posts}.ID = term_count_relationships.object_id) $query['select'] = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) as term_count, terms.term_id as term_count_id";
" . $tax_query_sql['join'] . $meta_query_sql['join'] . " $query['from'] = "FROM {$wpdb->posts}";
WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish' $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'] . " " . $tax_query_sql['where'] . $meta_query_sql['where'] . "
AND term_count_relationships.term_taxonomy_id IN (" . implode( ',', array_map( 'absint', $term_ids ) ) . ") AND terms.term_id IN (" . implode( ',', array_map( 'absint', $term_ids ) ) . ")
GROUP BY term_count_relationships.term_taxonomy_id;
"; ";
$query['group_by'] = "GROUP BY terms.term_id";
$results = $wpdb->get_results( $sql ); $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' ); return wp_list_pluck( $results, 'term_count', 'term_count_id' );
} }

View File

@ -1,9 +1,9 @@
=== WooCommerce === === 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 Tags: ecommerce, e-commerce, store, sales, sell, shop, cart, checkout, downloadable, downloads, paypal, storefront
Requires at least: 4.4 Requires at least: 4.4
Tested up to: 4.5 Tested up to: 4.5
Stable tag: 2.5.5 Stable tag: 2.6.1
License: GPLv3 License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html 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 == == 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 = = 2.6.0 - 14/06/16 =
* Feature - Introduced Shipping Zone functionality, and re-usable instance based shipping methods. * Feature - Introduced Shipping Zone functionality, and re-usable instance based shipping methods.
* Feature - Tabbed "My Account" area. * 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 - Ignore catalog visibility on products shortcode when specifying IDs or SKUs.
* Tweak - Added context to checkout error messages. * Tweak - Added context to checkout error messages.
* Tweak - Added SKU field to grouped products. * Tweak - Added SKU field to grouped products.
* Tweak - Moved SKU field to inventory tab.
* Tweak - Support qty display in cart messages. * Tweak - Support qty display in cart messages.
* Tweak - Hide min order amount field when not needed in shipping settings. * 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. * 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 == == Upgrade Notice ==
= 2.6.0 = = 2.6 =
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. 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/).
Note: 2.6 includes Shipping Zone functionality. Please ensure shipping method extensions in particular (e.g. Table Rate Shipping) support 2.6 **before** updating.

View File

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

View File

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

View File

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

View File

@ -16,7 +16,6 @@ class WC_Tests_Account_Functions extends WC_Unit_Test_Case {
'dashboard' => __( 'Dashboard', 'woocommerce' ), 'dashboard' => __( 'Dashboard', 'woocommerce' ),
'orders' => __( 'Orders', 'woocommerce' ), 'orders' => __( 'Orders', 'woocommerce' ),
'edit-address' => __( 'Addresses', 'woocommerce' ), 'edit-address' => __( 'Addresses', 'woocommerce' ),
'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
'edit-account' => __( 'Account Details', 'woocommerce' ), 'edit-account' => __( 'Account Details', 'woocommerce' ),
'customer-logout' => __( 'Logout', 'woocommerce' ), 'customer-logout' => __( 'Logout', 'woocommerce' ),
), wc_get_account_menu_items() ); ), 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 Name: WooCommerce
* Plugin URI: https://www.woothemes.com/woocommerce/ * Plugin URI: https://www.woothemes.com/woocommerce/
* Description: An e-commerce toolkit that helps you sell anything. Beautifully. * Description: An e-commerce toolkit that helps you sell anything. Beautifully.
* Version: 2.6.0-RC1 * Version: 2.6.1
* Author: WooThemes * Author: WooThemes
* Author URI: https://woothemes.com * Author URI: https://woothemes.com
* Requires at least: 4.1 * Requires at least: 4.4
* Tested up to: 4.5 * Tested up to: 4.5
* *
* Text Domain: woocommerce * Text Domain: woocommerce
@ -35,7 +35,7 @@ final class WooCommerce {
* *
* @var string * @var string
*/ */
public $version = '2.6.0'; public $version = '2.6.1';
/** /**
* The single instance of the class. * The single instance of the class.