improved structured data - added div into short description template

This commit is contained in:
opportus 2016-08-06 00:49:31 +02:00
commit 79ef06b6ad
101 changed files with 11644 additions and 3770 deletions

2
.gitignore vendored
View File

@ -28,3 +28,5 @@ Thumbs.db
# Logs
/logs
/vendor/

File diff suppressed because one or more lines are too long

View File

@ -306,7 +306,12 @@ table.wc_status_table {
#log-viewer-select {
padding: 10px 0 8px;
line-height: 180%;
line-height: 28px;
h2 {
a {
vertical-align: middle;
}
}
}
#log-viewer {
@ -585,7 +590,7 @@ ul.wc_coupon_list_block {
.hour,
.minute {
width: 3em;
width: 3.5em;
}
small {
@ -2037,20 +2042,32 @@ table.wc_input_table {
color: $blue;
}
th {
white-space: nowrap;
padding: 10px;
}
td {
padding: 0;
border-right: 1px solid #DFDFDF;
border-bottom: 1px solid #DFDFDF;
border-top: 0;
background: #fff;
cursor: default;
input[type="text"],
input[type="number"] {
width: 100%;
padding: 5px 7px;
padding: 8px 10px;
margin: 0;
border: 0;
outline: 0;
background: transparent none;
&:focus {
outline: 0;
box-shadow: none;
}
}
&.compound,
@ -2149,13 +2166,6 @@ table.wc_input_table {
}
}
tfoot {
th {
padding-left: 20px;
padding-right: 20px;
}
}
tr {
&:last-child {
td {

File diff suppressed because one or more lines are too long

View File

@ -547,6 +547,11 @@ html[dir="rtl"] .select2-container-multi .select2-choices li
background-color: #e4e4e4;
}
.select2-container-multi .ui-sortable .select2-search-choice {
cursor: move;
}
html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice
{
margin: 3px 5px 3px 0;

View File

@ -41,7 +41,7 @@
text-align: right !important; // Important to overwrite order status inline styling
&.order-actions {
text-align: left !important;
text-align: left !important; // This must always align left on handheld
}
&:before {
@ -109,7 +109,7 @@
&:nth-child(2n) {
float: right;
clear: none !important;
clear: none !important; // This should never clear.
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -69,13 +69,13 @@ p.demo_store {
text-align: center;
line-height: 1;
border-radius: 100%;
color: red !important;
color: red !important; // Required for default theme compatibility
text-decoration: none;
font-weight: 700;
border: 0;
&:hover {
color: #fff !important;
color: #fff !important; // Required for default theme compatibility
background: red;
}
}
@ -1140,6 +1140,10 @@ p.demo_store {
.buttons {
@include clearfix();
a {
margin-right: 5px;
margin-bottom: 5px;
}
}
}
@ -1492,13 +1496,13 @@ p.demo_store {
.woocommerce-message,
.woocommerce-error,
.woocommerce-info {
padding: 1em 2em 1em 3.5em !important;
margin: 0 0 2em !important;
padding: 1em 2em 1em 3.5em;
margin: 0 0 2em;
position: relative;
background-color: lighten($secondary,5%);
color: $secondarytext;
border-top: 3px solid $primary;
list-style: none outside !important;
list-style: none outside;
@include clearfix();
width: auto;
word-wrap: break-word;
@ -1517,9 +1521,9 @@ p.demo_store {
}
li {
list-style: none outside !important;
padding-left: 0 !important;
margin-left: 0 !important;
list-style: none outside !important; // Required for default theme compatibility
padding-left: 0 !important; // Required for default theme compatibility
margin-left: 0 !important; // Required for default theme compatibility
}
}

View File

@ -88,6 +88,8 @@
}).append( this.$el );
this.resizeContent();
this.$el.focus();
$( document.body ).trigger( 'init_tooltips' );
$( document.body ).trigger( 'wc_backbone_modal_loaded', this._target );
},

View File

@ -120,7 +120,6 @@
this.listenTo( this.model, 'change:rates', this.setUnloadConfirmation );
this.listenTo( this.model, 'saved:rates', this.clearUnloadConfirmation );
$tbody.on( 'change autocompletechange', ':input', { view: this }, this.updateModelOnChange );
$tbody.on( 'sortupdate', { view: this }, this.updateModelOnSort );
$search_field.on( 'keyup search', { view: this }, this.onSearchField );
$pagination.on( 'click', 'a', { view: this }, this.onPageChange );
$pagination.on( 'change', 'input', { view: this }, this.onPageChange );
@ -182,13 +181,6 @@
$pagination.empty();
view.page = 1;
}
// Disable sorting if there is a search term filtering the items.
if ( $search_field.val() ) {
$tbody.sortable( 'disable' );
} else {
$tbody.sortable( 'enable' );
}
},
updateUrl: function() {
if ( ! window.history.replaceState ) {
@ -364,31 +356,6 @@
model.setRateAttribute( id, attribute, val );
},
updateModelOnSort: function( event ) {
var view = event.data.view,
model = view.model,
rates = _.indexBy( model.get( 'rates' ), 'tax_rate_id' ),
changes = {};
_.each( rates, function( rate ) {
var new_position = 0;
var old_position = parseInt( rate.tax_rate_order, 10 );
if ( $table.find( 'tr[data-id="' + rate.tax_rate_id + '"]').length ) {
new_position = parseInt( $table.find( 'tr[data-id="' + rate.tax_rate_id + '"]').index(), 10 ) + parseInt( ( view.page - 1 ) * view.per_page, 10 );
} else {
new_position = old_position;
}
if ( old_position !== new_position ) {
changes[ rate.tax_rate_id ] = _.extend( changes[ rate.tax_rate_id ] || {}, { tax_rate_order : new_position } );
}
} );
if ( _.size( changes ) ) {
model.logChanges( changes );
}
},
sanitizePage: function( page_num ) {
page_num = parseInt( page_num, 10 );
if ( page_num < 1 ) {

File diff suppressed because one or more lines are too long

View File

@ -146,8 +146,19 @@ jQuery( function( $ ) {
select2_args = $.extend( select2_args, getEnhancedSelectFormatString() );
$( this ).select2( select2_args ).addClass( 'enhanced' );
if ( $( this ).data( 'sortable' ) ) {
$( this ).select2( 'container' ).find( 'ul.select2-choices' ).sortable({
containment: 'parent',
start: function() { $( this ).select2( 'onSortStart' ); },
update: function() { $( this ).select2( 'onSortEnd' ); }
});
}
});
// Ajax customer search boxes
$( ':input.wc-customer-search' ).filter( ':not(.enhanced)' ).each( function() {
var select2_args = {
@ -215,6 +226,15 @@ jQuery( function( $ ) {
select2_args = $.extend( select2_args, getEnhancedSelectFormatString() );
$( this ).select2( select2_args ).addClass( 'enhanced' );
if ( $( this ).data( 'sortable' ) ) {
$( this ).select2( 'container' ).find( 'ul.select2-choices' ).sortable({
containment: 'parent',
start: function() { $( this ).select2( 'onSortStart' ); },
update: function() { $( this ).select2( 'onSortEnd' ); }
});
}
});
})

View File

@ -1 +1 @@
jQuery(function(a){function b(){var a={formatMatches:function(a){return 1===a?wc_enhanced_select_params.i18n_matches_1:wc_enhanced_select_params.i18n_matches_n.replace("%qty%",a)},formatNoMatches:function(){return wc_enhanced_select_params.i18n_no_matches},formatAjaxError:function(){return wc_enhanced_select_params.i18n_ajax_error},formatInputTooShort:function(a,b){var c=b-a.length;return 1===c?wc_enhanced_select_params.i18n_input_too_short_1:wc_enhanced_select_params.i18n_input_too_short_n.replace("%qty%",c)},formatInputTooLong:function(a,b){var c=a.length-b;return 1===c?wc_enhanced_select_params.i18n_input_too_long_1:wc_enhanced_select_params.i18n_input_too_long_n.replace("%qty%",c)},formatSelectionTooBig:function(a){return 1===a?wc_enhanced_select_params.i18n_selection_too_long_1:wc_enhanced_select_params.i18n_selection_too_long_n.replace("%qty%",a)},formatLoadMore:function(){return wc_enhanced_select_params.i18n_load_more},formatSearching:function(){return wc_enhanced_select_params.i18n_searching}};return a}a(document.body).on("wc-enhanced-select-init",function(){a(":input.wc-enhanced-select, :input.chosen_select").filter(":not(.enhanced)").each(function(){var c=a.extend({minimumResultsForSearch:10,allowClear:!!a(this).data("allow_clear"),placeholder:a(this).data("placeholder")},b());a(this).select2(c).addClass("enhanced")}),a(":input.wc-enhanced-select-nostd, :input.chosen_select_nostd").filter(":not(.enhanced)").each(function(){var c=a.extend({minimumResultsForSearch:10,allowClear:!0,placeholder:a(this).data("placeholder")},b());a(this).select2(c).addClass("enhanced")}),a(":input.wc-product-search").filter(":not(.enhanced)").each(function(){var c={allowClear:!!a(this).data("allow_clear"),placeholder:a(this).data("placeholder"),minimumInputLength:a(this).data("minimum_input_length")?a(this).data("minimum_input_length"):"3",escapeMarkup:function(a){return a},ajax:{url:wc_enhanced_select_params.ajax_url,dataType:"json",quietMillis:250,data:function(b){return{term:b,action:a(this).data("action")||"woocommerce_json_search_products_and_variations",security:wc_enhanced_select_params.search_products_nonce,exclude:a(this).data("exclude"),include:a(this).data("include"),limit:a(this).data("limit")}},results:function(b){var c=[];return b&&a.each(b,function(a,b){c.push({id:a,text:b})}),{results:c}},cache:!0}};a(this).data("multiple")===!0?(c.multiple=!0,c.initSelection=function(b,c){var d=a.parseJSON(b.attr("data-selected")),e=[];return a(b.val().split(",")).each(function(a,b){e.push({id:b,text:d[b]})}),c(e)},c.formatSelection=function(a){return'<div class="selected-option" data-id="'+a.id+'">'+a.text+"</div>"}):(c.multiple=!1,c.initSelection=function(a,b){var c={id:a.val(),text:a.attr("data-selected")};return b(c)}),c=a.extend(c,b()),a(this).select2(c).addClass("enhanced")}),a(":input.wc-customer-search").filter(":not(.enhanced)").each(function(){var c={allowClear:!!a(this).data("allow_clear"),placeholder:a(this).data("placeholder"),minimumInputLength:a(this).data("minimum_input_length")?a(this).data("minimum_input_length"):"3",escapeMarkup:function(a){return a},ajax:{url:wc_enhanced_select_params.ajax_url,dataType:"json",quietMillis:250,data:function(b){return{term:b,action:"woocommerce_json_search_customers",security:wc_enhanced_select_params.search_customers_nonce,exclude:a(this).data("exclude")}},results:function(b){var c=[];return b&&a.each(b,function(a,b){c.push({id:a,text:b})}),{results:c}},cache:!0}};a(this).data("multiple")===!0?(c.multiple=!0,c.initSelection=function(b,c){var d=a.parseJSON(b.attr("data-selected")),e=[];return a(b.val().split(",")).each(function(a,b){e.push({id:b,text:d[b]})}),c(e)},c.formatSelection=function(a){return'<div class="selected-option" data-id="'+a.id+'">'+a.text+"</div>"}):(c.multiple=!1,c.initSelection=function(a,b){var c={id:a.val(),text:a.attr("data-selected")};return b(c)}),c=a.extend(c,b()),a(this).select2(c).addClass("enhanced")})}).on("wc_backbone_modal_before_remove",function(){a(":input.wc-enhanced-select, :input.wc-product-search, :input.wc-customer-search").select2("close")}).trigger("wc-enhanced-select-init")});
jQuery(function(a){function b(){var a={formatMatches:function(a){return 1===a?wc_enhanced_select_params.i18n_matches_1:wc_enhanced_select_params.i18n_matches_n.replace("%qty%",a)},formatNoMatches:function(){return wc_enhanced_select_params.i18n_no_matches},formatAjaxError:function(){return wc_enhanced_select_params.i18n_ajax_error},formatInputTooShort:function(a,b){var c=b-a.length;return 1===c?wc_enhanced_select_params.i18n_input_too_short_1:wc_enhanced_select_params.i18n_input_too_short_n.replace("%qty%",c)},formatInputTooLong:function(a,b){var c=a.length-b;return 1===c?wc_enhanced_select_params.i18n_input_too_long_1:wc_enhanced_select_params.i18n_input_too_long_n.replace("%qty%",c)},formatSelectionTooBig:function(a){return 1===a?wc_enhanced_select_params.i18n_selection_too_long_1:wc_enhanced_select_params.i18n_selection_too_long_n.replace("%qty%",a)},formatLoadMore:function(){return wc_enhanced_select_params.i18n_load_more},formatSearching:function(){return wc_enhanced_select_params.i18n_searching}};return a}a(document.body).on("wc-enhanced-select-init",function(){a(":input.wc-enhanced-select, :input.chosen_select").filter(":not(.enhanced)").each(function(){var c=a.extend({minimumResultsForSearch:10,allowClear:!!a(this).data("allow_clear"),placeholder:a(this).data("placeholder")},b());a(this).select2(c).addClass("enhanced")}),a(":input.wc-enhanced-select-nostd, :input.chosen_select_nostd").filter(":not(.enhanced)").each(function(){var c=a.extend({minimumResultsForSearch:10,allowClear:!0,placeholder:a(this).data("placeholder")},b());a(this).select2(c).addClass("enhanced")}),a(":input.wc-product-search").filter(":not(.enhanced)").each(function(){var c={allowClear:!!a(this).data("allow_clear"),placeholder:a(this).data("placeholder"),minimumInputLength:a(this).data("minimum_input_length")?a(this).data("minimum_input_length"):"3",escapeMarkup:function(a){return a},ajax:{url:wc_enhanced_select_params.ajax_url,dataType:"json",quietMillis:250,data:function(b){return{term:b,action:a(this).data("action")||"woocommerce_json_search_products_and_variations",security:wc_enhanced_select_params.search_products_nonce,exclude:a(this).data("exclude"),include:a(this).data("include"),limit:a(this).data("limit")}},results:function(b){var c=[];return b&&a.each(b,function(a,b){c.push({id:a,text:b})}),{results:c}},cache:!0}};a(this).data("multiple")===!0?(c.multiple=!0,c.initSelection=function(b,c){var d=a.parseJSON(b.attr("data-selected")),e=[];return a(b.val().split(",")).each(function(a,b){e.push({id:b,text:d[b]})}),c(e)},c.formatSelection=function(a){return'<div class="selected-option" data-id="'+a.id+'">'+a.text+"</div>"}):(c.multiple=!1,c.initSelection=function(a,b){var c={id:a.val(),text:a.attr("data-selected")};return b(c)}),c=a.extend(c,b()),a(this).select2(c).addClass("enhanced"),a(this).data("sortable")===!0&&a(this).select2("container").find("ul.select2-choices").sortable({containment:"parent",start:function(){a(this).select2("onSortStart")},update:function(){a(this).select2("onSortEnd")}})}),a(":input.wc-customer-search").filter(":not(.enhanced)").each(function(){var c={allowClear:!!a(this).data("allow_clear"),placeholder:a(this).data("placeholder"),minimumInputLength:a(this).data("minimum_input_length")?a(this).data("minimum_input_length"):"3",escapeMarkup:function(a){return a},ajax:{url:wc_enhanced_select_params.ajax_url,dataType:"json",quietMillis:250,data:function(b){return{term:b,action:"woocommerce_json_search_customers",security:wc_enhanced_select_params.search_customers_nonce,exclude:a(this).data("exclude")}},results:function(b){var c=[];return b&&a.each(b,function(a,b){c.push({id:a,text:b})}),{results:c}},cache:!0}};a(this).data("multiple")===!0?(c.multiple=!0,c.initSelection=function(b,c){var d=a.parseJSON(b.attr("data-selected")),e=[];return a(b.val().split(",")).each(function(a,b){e.push({id:b,text:d[b]})}),c(e)},c.formatSelection=function(a){return'<div class="selected-option" data-id="'+a.id+'">'+a.text+"</div>"}):(c.multiple=!1,c.initSelection=function(a,b){var c={id:a.val(),text:a.attr("data-selected")};return b(c)}),c=a.extend(c,b()),a(this).select2(c).addClass("enhanced"),a(this).data("sortable")===!0&&a(this).select2("container").find("ul.select2-choices").sortable({containment:"parent",start:function(){a(this).select2("onSortStart")},update:function(){a(this).select2("onSortEnd")}})})}).on("wc_backbone_modal_before_remove",function(){a(":input.wc-enhanced-select, :input.wc-product-search, :input.wc-customer-search").select2("close")}).trigger("wc-enhanced-select-init")});

View File

@ -213,14 +213,14 @@
return parseInt( method.method_order, 10 );
} );
_.each( shipping_methods, function( shipping_method, instance_id ) {
_.each( shipping_methods, function( shipping_method ) {
var class_name = 'method_disabled';
if ( 'yes' === shipping_method.enabled ) {
class_name = 'method_enabled';
}
$method_list.append( '<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.append( '<li class="wc-shipping-zone-method"><a href="admin.php?page=wc-settings&amp;tab=shipping&amp;instance_id=' + shipping_method.instance_id + '" class="' + class_name + '">' + shipping_method.title + '</a></li>' );
} );
} else {
$method_list.append( '<li class="wc-shipping-zone-method">' + data.strings.no_shipping_methods_offered + '</li>' );

File diff suppressed because one or more lines are too long

View File

@ -354,8 +354,9 @@ jQuery( function( $ ) {
var $clicked = $( 'input[type=submit][clicked=true]' );
if ( 0 === $form.find( '.shop_table.cart' ).length ) {
return false;
return;
}
if ( is_blocked( $form ) ) {
return false;
}

File diff suppressed because one or more lines are too long

View File

@ -55,7 +55,7 @@ jQuery( function( $ ) {
$( 'input#createaccount' ).change( this.toggle_create_account ).change();
}
},
init_payment_methods: function() {
init_payment_methods: function( selectedPaymentMethod ) {
var $payment_methods = $( '.woocommerce-checkout' ).find( 'input[name="payment_method"]' );
// If there is one method, we can hide the radio input
@ -63,6 +63,11 @@ jQuery( function( $ ) {
$payment_methods.eq(0).hide();
}
// If there was a previously selected method, check that one.
if ( selectedPaymentMethod ) {
$( '#' + selectedPaymentMethod ).prop( 'checked', true );
}
// If there are none selected, select the first.
if ( 0 === $payment_methods.filter( ':checked' ).length ) {
$payment_methods.eq(0).prop( 'checked', true );
@ -271,6 +276,9 @@ jQuery( function( $ ) {
url: wc_checkout_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'update_order_review' ),
data: data,
success: function( data ) {
var selectedPaymentMethod = $( '.woocommerce-checkout input[name="payment_method"]:checked' ).attr( 'id' );
// Reload the page if requested
if ( 'true' === data.reload ) {
window.location.reload();
@ -321,7 +329,7 @@ jQuery( function( $ ) {
}
// Re-init methods
wc_checkout_form.init_payment_methods();
wc_checkout_form.init_payment_methods( selectedPaymentMethod );
// Fire updated_checkout e
$( document.body ).trigger( 'updated_checkout' );

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,595 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Legacy Abstract Order
*
* Legacy and deprecated functions are here to keep the WC_Abstract_Order clean.
* This class will be removed in future versions.
*
* @version 2.7.0
* @package WooCommerce/Abstracts
* @category Abstract Class
* @author WooThemes
*/
abstract class WC_Abstract_Legacy_Order extends WC_Data {
/**
* Update a line item for the order.
*
* Note this does not update order totals.
*
* @param object|int $item order item ID or item object.
* @param WC_Product $product
* @param array $args data to update.
* @return int updated order item ID
*/
public function update_product( $item, $product, $args ) {
_deprecated_function( 'WC_Order::update_product', '2.7', 'Interact with WC_Order_Item_Product class' );
if ( is_numeric( $item ) ) {
$item = $this->get_item( $item );
}
if ( ! is_object( $item ) || ! $item->is_type( 'line_item' ) ) {
return false;
}
if ( ! $this->get_id() ) {
$this->save(); // Order must exist
}
// BW compatibility with old args
if ( isset( $args['totals'] ) ) {
foreach ( $args['totals'] as $key => $value ) {
if ( 'tax' === $key ) {
$args['total_tax'] = $value;
} elseif ( 'tax_data' === $key ) {
$args['taxes'] = $value;
} else {
$args[ $key ] = $value;
}
}
}
// Handly qty if set
if ( isset( $args['qty'] ) ) {
if ( $product->backorders_require_notification() && $product->is_on_backorder( $args['qty'] ) ) {
$item->add_meta_data( apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $args['qty'] - max( 0, $product->get_total_stock() ), true );
}
$args['subtotal'] = $args['subtotal'] ? $args['subtotal'] : $product->get_price_excluding_tax( $args['qty'] );
$args['total'] = $args['total'] ? $args['total'] : $product->get_price_excluding_tax( $args['qty'] );
}
$item->set_order_id( $this->get_id() );
$item->set_all( $args );
$item->save();
do_action( 'woocommerce_order_edit_product', $this->get_id(), $item->get_id(), $args, $product );
return $item->get_id();
}
/**
* Update coupon for order. Note this does not update order totals.
* @param object|int $item
* @param array $args
* @return int updated order item ID
*/
public function update_coupon( $item, $args ) {
_deprecated_function( 'WC_Order::update_coupon', '2.7', 'Interact with WC_Order_Item_Coupon class' );
if ( is_numeric( $item ) ) {
$item = $this->get_item( $item );
}
if ( ! is_object( $item ) || ! $item->is_type( 'coupon' ) ) {
return false;
}
if ( ! $this->get_id() ) {
$this->save(); // Order must exist
}
// BW compatibility for old args
if ( isset( $args['discount_amount'] ) ) {
$args['discount'] = $args['discount_amount'];
}
if ( isset( $args['discount_amount_tax'] ) ) {
$args['discount_tax'] = $args['discount_amount_tax'];
}
$item->set_order_id( $this->get_id() );
$item->set_all( $args );
$item->save();
do_action( 'woocommerce_order_update_coupon', $this->get_id(), $item->get_id(), $args );
return $item->get_id();
}
/**
* Update shipping method for order.
*
* Note this does not update the order total.
*
* @param object|int $item
* @param array $args
* @return int updated order item ID
*/
public function update_shipping( $item, $args ) {
_deprecated_function( 'WC_Order::update_shipping', '2.7', 'Interact with WC_Order_Item_Shipping class' );
if ( is_numeric( $item ) ) {
$item = $this->get_item( $item );
}
if ( ! is_object( $item ) || ! $item->is_type( 'shipping' ) ) {
return false;
}
if ( ! $this->get_id() ) {
$this->save(); // Order must exist
}
// BW compatibility for old args
if ( isset( $args['cost'] ) ) {
$args['total'] = $args['cost'];
}
$item->set_order_id( $this->get_id() );
$item->set_all( $args );
$item->save();
$this->calculate_shipping();
do_action( 'woocommerce_order_update_shipping', $this->get_id(), $item->get_id(), $args );
return $item->get_id();
}
/**
* Update fee for order.
*
* Note this does not update order totals.
*
* @param object|int $item
* @param array $args
* @return int updated order item ID
*/
public function update_fee( $item, $args ) {
_deprecated_function( 'WC_Order::update_fee', '2.7', 'Interact with WC_Order_Item_Fee class' );
if ( is_numeric( $item ) ) {
$item = $this->get_item( $item );
}
if ( ! is_object( $item ) || ! $item->is_type( 'fee' ) ) {
return false;
}
if ( ! $this->get_id() ) {
$this->save(); // Order must exist
}
$item->set_order_id( $this->get_id() );
$item->set_all( $args );
$item->save();
do_action( 'woocommerce_order_update_fee', $this->get_id(), $item->get_id(), $args );
return $item->get_id();
}
/**
* Update tax line on order.
* Note this does not update order totals.
*
* @since 2.7
* @param object|int $item
* @param array $args
* @return int updated order item ID
*/
public function update_tax( $item, $args ) {
_deprecated_function( 'WC_Order::update_tax', '2.7', 'Interact with WC_Order_Item_Tax class' );
if ( is_numeric( $item ) ) {
$item = $this->get_item( $item );
}
if ( ! is_object( $item ) || ! $item->is_type( 'tax' ) ) {
return false;
}
if ( ! $this->get_id() ) {
$this->save(); // Order must exist
}
$item->set_order_id( $this->get_id() );
$item->set_all( $args );
$item->save();
do_action( 'woocommerce_order_update_tax', $this->get_id(), $item->get_id(), $args );
return $item->get_id();
}
/**
* Get a product (either product or variation).
* @deprecated Add deprecation notices in future release. Replaced with $item->get_product()
* @param object $item
* @return WC_Product|bool
*/
public function get_product_from_item( $item ) {
if ( is_callable( array( $item, 'get_product' ) ) ) {
$product = $item->get_product();
} else {
$product = false;
}
return apply_filters( 'woocommerce_get_product_from_item', $product, $item, $this );
}
/**
* Set the customer address.
* @param array $address Address data.
* @param string $type billing or shipping.
*/
public function set_address( $address, $type = 'billing' ) {
foreach ( $address as $key => $value ) {
update_post_meta( $this->get_id(), "_{$type}_" . $key, $value );
if ( is_callable( array( $this, "set_{$type}_{$key}" ) ) ) {
$this->{"set_{$type}_{$key}"}( $value );
}
}
}
/**
* Set an order total.
* @param float $amount
* @param string $total_type
* @return bool
*/
public function legacy_set_total( $amount, $total_type = 'total' ) {
if ( ! in_array( $total_type, array( 'shipping', 'tax', 'shipping_tax', 'total', 'cart_discount', 'cart_discount_tax' ) ) ) {
return false;
}
switch ( $total_type ) {
case 'total' :
$amount = wc_format_decimal( $amount, wc_get_price_decimals() );
$this->set_total( $amount );
update_post_meta( $this->get_id(), '_order_total', $amount );
break;
case 'cart_discount' :
$amount = wc_format_decimal( $amount );
$this->set_discount_total( $amount );
update_post_meta( $this->get_id(), '_cart_discount', $amount );
break;
case 'cart_discount_tax' :
$amount = wc_format_decimal( $amount );
$this->set_discount_tax( $amount );
update_post_meta( $this->get_id(), '_cart_discount_tax', $amount );
break;
case 'shipping' :
$amount = wc_format_decimal( $amount );
$this->set_shipping_total( $amount );
update_post_meta( $this->get_id(), '_order_shipping', $amount );
break;
case 'shipping_tax' :
$amount = wc_format_decimal( $amount );
$this->set_shipping_tax( $amount );
update_post_meta( $this->get_id(), '_order_shipping_tax', $amount );
break;
case 'tax' :
$amount = wc_format_decimal( $amount );
$this->set_cart_tax( $amount );
update_post_meta( $this->get_id(), '_order_tax', $amount );
break;
}
return true;
}
/**
* Magic __isset method for backwards compatibility.
* @param string $key
* @return bool
*/
public function __isset( $key ) {
// Legacy properties which could be accessed directly in the past.
$legacy_props = array( 'completed_date', 'id', 'order_type', 'post', 'status', 'post_status', 'customer_note', 'customer_message', 'user_id', 'customer_user', 'prices_include_tax', 'tax_display_cart', 'display_totals_ex_tax', 'display_cart_ex_tax', 'order_date', 'modified_date', 'cart_discount', 'cart_discount_tax', 'order_shipping', 'order_shipping_tax', 'order_total', 'order_tax', 'billing_first_name', 'billing_last_name', 'billing_company', 'billing_address_1', 'billing_address_2', 'billing_city', 'billing_state', 'billing_postcode', 'billing_country', 'billing_phone', 'billing_email', 'shipping_first_name', 'shipping_last_name', 'shipping_company', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode', 'shipping_country', 'customer_ip_address', 'customer_user_agent', 'payment_method_title', 'payment_method', 'order_currency' );
return $this->get_id() ? ( in_array( $key, $legacy_props ) || metadata_exists( 'post', $this->get_id(), '_' . $key ) ) : false;
}
/**
* Magic __get method for backwards compatibility.
* @param string $key
* @return mixed
*/
public function __get( $key ) {
_doing_it_wrong( $key, 'Order properties should not be accessed directly.', '2.7' );
if ( 'completed_date' === $key ) {
return $this->get_date_completed();
} elseif ( 'paid_date' === $key ) {
return $this->get_date_paid();
} elseif ( 'modified_date' === $key ) {
return $this->get_date_modified();
} elseif ( 'order_date' === $key ) {
return $this->get_date_created();
} elseif ( 'id' === $key ) {
return $this->get_id();
} elseif ( 'post' === $key ) {
return get_post( $this->get_id() );
} elseif ( 'status' === $key || 'post_status' === $key ) {
return $this->get_status();
} elseif ( 'customer_message' === $key || 'customer_note' === $key ) {
return $this->get_customer_note();
} elseif ( in_array( $key, array( 'user_id', 'customer_user' ) ) ) {
return $this->get_customer_id();
} elseif ( 'tax_display_cart' === $key ) {
return get_option( 'woocommerce_tax_display_cart' );
} elseif ( 'display_totals_ex_tax' === $key ) {
return 'excl' === get_option( 'woocommerce_tax_display_cart' );
} elseif ( 'display_cart_ex_tax' === $key ) {
return 'excl' === get_option( 'woocommerce_tax_display_cart' );
} elseif ( 'cart_discount' === $key ) {
return $this->get_discount();
} elseif ( 'cart_discount_tax' === $key ) {
return $this->get_discount_tax();
} elseif ( 'order_tax' === $key ) {
return $this->get_cart_tax();
} elseif ( 'order_shipping_tax' === $key ) {
return $this->get_shipping_tax();
} elseif ( 'order_shipping' === $key ) {
return $this->get_shipping_total();
} elseif ( 'order_total' === $key ) {
return $this->get_total();
} elseif ( 'order_type' === $key ) {
return $this->get_type();
} elseif ( 'order_currency' === $key ) {
return $this->get_currency();
} elseif ( 'order_version' === $key ) {
return $this->get_version();
} elseif ( is_callable( array( $this, "get_{$key}" ) ) ) {
return $this->{"get_{$key}"}();
} else {
return get_post_meta( $this->get_id(), '_' . $key, true );
}
}
/**
* has_meta function for order items.
*
* @param string $order_item_id
* @return array of meta data.
*/
public function has_meta( $order_item_id ) {
global $wpdb;
_deprecated_function( 'has_meta', '2.7', 'WC_Order_item::get_meta_data' );
return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id
FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A );
}
/**
* Display meta data belonging to an item.
* @param array $item
*/
public function display_item_meta( $item ) {
_deprecated_function( 'get_item_meta', '2.7', 'wc_display_item_meta' );
$product = $item->get_product();
$item_meta = new WC_Order_Item_Meta( $item, $product );
$item_meta->display();
}
/**
* Display download links for an order item.
* @param array $item
*/
public function display_item_downloads( $item ) {
_deprecated_function( 'display_item_downloads', '2.7', 'wc_display_item_downloads' );
$product = $item->get_product();
if ( $product && $product->exists() && $product->is_downloadable() && $this->is_download_permitted() ) {
$download_files = $this->get_item_downloads( $item );
$i = 0;
$links = array();
foreach ( $download_files as $download_id => $file ) {
$i++;
$prefix = count( $download_files ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
$links[] = '<small class="download-url">' . $prefix . ': <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a></small>' . "\n";
}
echo '<br/>' . implode( '<br/>', $links );
}
}
/**
* Get the Download URL.
*
* @param int $product_id
* @param int $download_id
* @return string
*/
public function get_download_url( $product_id, $download_id ) {
_deprecated_function( 'get_download_url', '2.7', 'WC_Order_Item_Product::get_item_download_url' );
return add_query_arg( array(
'download_file' => $product_id,
'order' => $this->get_order_key(),
'email' => urlencode( $this->get_billing_email() ),
'key' => $download_id,
), trailingslashit( home_url() ) );
}
/**
* Get the downloadable files for an item in this order.
*
* @param array $item
* @return array
*/
public function get_item_downloads( $item ) {
_deprecated_function( 'get_item_downloads', '2.7', 'WC_Order_Item_Product::get_item_downloads' );
return $item->get_item_downloads();
}
/**
* Gets shipping total. Alias of WC_Order::get_shipping_total().
* @deprecated 2.7.0 since this is an alias only.
* @return float
*/
public function get_total_shipping() {
return $this->get_shipping_total();
}
/**
* Get order item meta.
* @deprecated 2.7.0
* @param mixed $order_item_id
* @param string $key (default: '')
* @param bool $single (default: false)
* @return array|string
*/
public function get_item_meta( $order_item_id, $key = '', $single = false ) {
_deprecated_function( 'get_item_meta', '2.7', 'wc_get_order_item_meta' );
return get_metadata( 'order_item', $order_item_id, $key, $single );
}
/**
* Get all item meta data in array format in the order it was saved. Does not group meta by key like get_item_meta().
*
* @param mixed $order_item_id
* @return array of objects
*/
public function get_item_meta_array( $order_item_id ) {
_deprecated_function( 'get_item_meta_array', '2.7', 'WC_Order_Item::get_meta_data() (note the format has changed)' );
$item = $this->get_item( $order_item_id );
$meta_data = $item->get_meta_data();
$item_meta_array = array();
foreach ( $meta_data as $meta ) {
$item_meta_array[ $meta->meta_id ] = $meta;
}
return $item_meta_array;
}
/**
* Expand item meta into the $item array.
* @deprecated 2.7.0 Item meta no longer expanded due to new order item
* classes. This function now does nothing to avoid data breakage.
* @param array $item before expansion.
* @return array
*/
public function expand_item_meta( $item ) {
_deprecated_function( 'expand_item_meta', '2.7', '' );
return $item;
}
/**
* Load the order object. Called from the constructor.
* @deprecated 2.7.0 Logic moved to constructor
* @param int|object|WC_Order $order Order to init.
*/
protected function init( $order ) {
_deprecated_function( 'init', '2.7', 'Logic moved to constructor' );
if ( is_numeric( $order ) ) {
$this->read( $order );
} elseif ( $order instanceof WC_Order ) {
$this->read( absint( $order->get_id() ) );
} elseif ( isset( $order->ID ) ) {
$this->read( absint( $order->ID ) );
}
}
/**
* Gets an order from the database.
* @deprecated 2.7
* @param int $id (default: 0).
* @return bool
*/
public function get_order( $id = 0 ) {
_deprecated_function( 'get_order', '2.7', 'read' );
if ( ! $id ) {
return false;
}
if ( $result = get_post( $id ) ) {
$this->populate( $result );
return true;
}
return false;
}
/**
* Populates an order from the loaded post data.
* @deprecated 2.7
* @param mixed $result
*/
public function populate( $result ) {
_deprecated_function( 'populate', '2.7', 'read' );
$this->read( $result->ID );
}
/**
* Cancel the order and restore the cart (before payment).
* @deprecated 2.7.0 Moved to event handler.
* @param string $note (default: '') Optional note to add.
*/
public function cancel_order( $note = '' ) {
_deprecated_function( 'cancel_order', '2.7', 'update_status' );
WC()->session->set( 'order_awaiting_payment', false );
$this->update_status( 'cancelled', $note );
}
/**
* Record sales.
* @deprecated 2.7.0
*/
public function record_product_sales() {
_deprecated_function( 'record_product_sales', '2.7', 'wc_update_total_sales_counts' );
wc_update_total_sales_counts( $this->get_id() );
}
/**
* Increase applied coupon counts.
* @deprecated 2.7.0
*/
public function increase_coupon_usage_counts() {
_deprecated_function( 'increase_coupon_usage_counts', '2.7', 'wc_update_coupon_usage_counts' );
wc_update_coupon_usage_counts( $this->get_id() );
}
/**
* Decrease applied coupon counts.
* @deprecated 2.7.0
*/
public function decrease_coupon_usage_counts() {
_deprecated_function( 'decrease_coupon_usage_counts', '2.7', 'wc_update_coupon_usage_counts' );
wc_update_coupon_usage_counts( $this->get_id() );
}
/**
* Reduce stock levels for all line items in the order.
* @deprecated 2.7.0
*/
public function reduce_order_stock() {
_deprecated_function( 'reduce_order_stock', '2.7', 'wc_reduce_stock_levels' );
wc_reduce_stock_levels( $this->get_id() );
}
/**
* Send the stock notifications.
* @deprecated 2.7.0 No longer needs to be called directly.
*/
public function send_stock_notifications( $product, $new_stock, $qty_ordered ) {
_deprecated_function( 'send_stock_notifications', '2.7' );
}
/**
* Output items for display in html emails.
* @deprecated 2.7.0 Moved to template functions.
* @param array $args Items args.
* @return string
*/
public function email_order_items_table( $args = array() ) {
_deprecated_function( 'email_order_items_table', '2.7', 'wc_get_email_order_items' );
return wc_get_email_order_items( $this, $args );
}
/**
* Get currency.
* @deprecated 2.7.0
*/
public function get_order_currency() {
_deprecated_function( 'get_order_currency', '2.7', 'get_currency' );
return apply_filters( 'woocommerce_get_order_currency', $this->get_currency(), $this );
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1429,7 +1429,7 @@ class WC_Product {
* @return bool
*/
public function enable_dimensions_display() {
return apply_filters( 'wc_product_enable_dimensions_display', true );
return apply_filters( 'wc_product_enable_dimensions_display', true ) && ( $this->has_dimensions() || $this->has_weight() );
}
/**
@ -1441,6 +1441,15 @@ class WC_Product {
return $this->get_dimensions() ? true : false;
}
/**
* Does a child have dimensions set?
* @since 2.7.0
* @return boolean
*/
public function child_has_dimensions() {
return false;
}
/**
* Returns the product length.
* @return string
@ -1483,6 +1492,15 @@ class WC_Product {
return $this->get_weight() ? true : false;
}
/**
* Does a child have a weight set?
* @since 2.7.0
* @return boolean
*/
public function child_has_weight() {
return false;
}
/**
* Returns formatted dimensions.
* @return string
@ -1498,7 +1516,7 @@ class WC_Product {
$dimensions .= ' ' . get_option( 'woocommerce_dimension_unit' );
}
return apply_filters( 'woocommerce_product_dimensions', $dimensions, $this );
return apply_filters( 'woocommerce_product_dimensions', $dimensions, $this );
}
/**

View File

@ -0,0 +1,108 @@
<?php
/**
* REST API Shipping Zones Controller base
*
* Houses common functionality between Shipping Zones and Locations.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.7.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* REST API Shipping Zones base class.
*
* @package WooCommerce/API
* @extends WC_REST_Controller
*/
abstract class WC_REST_Shipping_Zones_Controller_Base extends WC_REST_Controller {
/**
* Endpoint namespace.
*
* @var string
*/
protected $namespace = 'wc/v1';
/**
* Route base.
*
* @var string
*/
protected $rest_base = 'shipping/zones';
/**
* Retrieve a Shipping Zone by it's ID.
*
* @param int $zone_id Shipping Zone ID.
* @return WC_Shipping_Zone|WP_Error
*/
protected function get_zone( $zone_id ) {
$zone = WC_Shipping_Zones::get_zone_by( 'zone_id', $zone_id );
if ( false === $zone ) {
return new WP_Error( 'woocommerce_rest_shipping_zone_invalid', __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) );
}
return $zone;
}
/**
* Check whether a given request has permission to read Shipping Zones.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! wc_shipping_enabled() ) {
return new WP_Error( 'rest_no_route', __( 'Shipping is disabled.', 'woocommerce' ), array( 'status' => 404 ) );
}
if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to create Shipping Zones.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function create_item_permissions_check( $request ) {
if ( ! wc_shipping_enabled() ) {
return new WP_Error( 'rest_no_route', __( 'Shipping is disabled.', 'woocommerce' ), array( 'status' => 404 ) );
}
if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you cannot create new resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check whether a given request has permission to edit Shipping Zones.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function update_items_permissions_check( $request ) {
if ( ! wc_shipping_enabled() ) {
return new WP_Error( 'rest_no_route', __( 'Shipping is disabled.', 'woocommerce' ), array( 'status' => 404 ) );
}
if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot update resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
}

View File

@ -271,6 +271,7 @@ class WC_Admin_Attributes {
<form action="edit.php?post_type=product&amp;page=product_attributes&amp;edit=<?php echo absint( $edit ); ?>" method="post">
<table class="form-table">
<tbody>
<?php do_action( 'woocommerce_before_edit_attribute_fields' ); ?>
<tr class="form-field form-required">
<th scope="row" valign="top">
<label for="attribute_label"><?php _e( 'Name', 'woocommerce' ); ?></label>
@ -309,7 +310,6 @@ class WC_Admin_Attributes {
<?php endforeach; ?>
<?php
/**
* Deprecated action in favor of product_attributes_type_selector filter.
*
@ -335,6 +335,7 @@ class WC_Admin_Attributes {
<p class="description"><?php _e( 'Determines the sort order of the terms on the frontend shop product pages. If using custom ordering, you can drag and drop the terms in this attribute.', 'woocommerce' ); ?></p>
</td>
</tr>
<?php do_action( 'woocommerce_after_edit_attribute_fields' ) ?>
</tbody>
</table>
<p class="submit"><input type="submit" name="save_attribute" id="submit" class="button-primary" value="<?php esc_attr_e( 'Update', 'woocommerce' ); ?>"></p>
@ -374,7 +375,6 @@ class WC_Admin_Attributes {
if ( $attribute_taxonomies = wc_get_attribute_taxonomies() ) :
foreach ( $attribute_taxonomies as $tax ) :
?><tr>
<td>
<strong><a href="edit-tags.php?taxonomy=<?php echo esc_html( wc_attribute_taxonomy_name( $tax->attribute_name ) ); ?>&amp;post_type=product"><?php echo esc_html( $tax->attribute_label ); ?></a></strong>
@ -440,6 +440,8 @@ class WC_Admin_Attributes {
<h2><?php _e( 'Add New Attribute', 'woocommerce' ); ?></h2>
<p><?php _e( 'Attributes let you define extra product data, such as size or colour. You can use these attributes in the shop sidebar using the "layered nav" widgets. Please note: you cannot rename an attribute later on.', 'woocommerce' ); ?></p>
<form action="edit.php?post_type=product&amp;page=product_attributes" method="post">
<?php do_action( 'woocommerce_before_add_attribute_fields' ) ?>
<div class="form-field">
<label for="attribute_label"><?php _e( 'Name', 'woocommerce' ); ?></label>
<input name="attribute_label" id="attribute_label" type="text" value="" />
@ -489,6 +491,8 @@ class WC_Admin_Attributes {
<p class="description"><?php _e( 'Determines the sort order of the terms on the frontend shop product pages. If using custom ordering, you can drag and drop the terms in this attribute.', 'woocommerce' ); ?></p>
</div>
<?php do_action( 'woocommerce_after_add_attribute_fields' ) ?>
<p class="submit"><input type="submit" name="add_new_attribute" id="submit" class="button button-primary" value="<?php esc_attr_e( 'Add Attribute', 'woocommerce' ); ?>"></p>
<?php wp_nonce_field( 'woocommerce-add-new_attribute' ); ?>
</form>

View File

@ -190,8 +190,8 @@ class WC_Admin_Permalink_Settings {
}
// This is an invalid base structure and breaks pages.
if ( '%product_cat%' == $product_permalink ) {
$product_permalink = '/' . _x( 'product', 'slug', 'woocommerce' ) . '/' . $product_permalink;
if ( '/%product_cat%' === $product_permalink ) {
$product_permalink = '/' . _x( 'product', 'slug', 'woocommerce' ) . $product_permalink;
}
} elseif ( empty( $product_permalink ) ) {
$product_permalink = false;

View File

@ -697,7 +697,7 @@ class WC_Admin_Settings {
// Format the value based on option type.
switch ( $option['type'] ) {
case 'checkbox' :
$value = in_array( $raw_value, array( 'yes', 'no' ) ) ? $raw_value : 'no';
$value = '1' === $raw_value || 'yes' === $raw_value ? 'yes' : 'no';
break;
case 'textarea' :
$value = wp_kses_post( trim( $raw_value ) );

View File

@ -205,7 +205,13 @@ class WC_Admin_Status {
$viewed_log = current( $logs );
}
include_once( dirname( __FILE__ ) . '/views/html-admin-page-status-logs.php' );
$handle = ! empty( $viewed_log ) ? self::get_log_file_handle( $viewed_log ) : '';
if ( ! empty( $_REQUEST[ 'handle' ] ) ) {
self::remove_log();
}
include_once( 'views/html-admin-page-status-logs.php' );
}
/**
@ -240,6 +246,16 @@ class WC_Admin_Status {
return $version ;
}
/**
* Return the log file handle.
*
* @param string $filename
* @return string
*/
public static function get_log_file_handle( $filename ) {
return substr( $filename, 0, strlen( $filename ) > 37 ? strlen( $filename ) - 37 : strlen( $filename ) - 4 );
}
/**
* Scan the template files.
* @param string $template_path
@ -342,4 +358,21 @@ class WC_Admin_Status {
return $update_theme_version;
}
/**
* Remove/delete the chosen file.
*/
public static function remove_log() {
if ( empty( $_REQUEST[ '_wpnonce' ] ) || ! wp_verify_nonce( $_REQUEST[ '_wpnonce' ], 'remove_log' ) ) {
wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
}
if ( ! empty( $_REQUEST[ 'handle' ] ) ) {
$logger = new WC_Logger();
$logger->remove( $_REQUEST[ 'handle' ] );
}
wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
exit();
}
}

View File

@ -242,14 +242,14 @@ class WC_Admin_Report {
$key = is_array( $value['meta_key'] ) ? $value['meta_key'][0] . '_array' : $value['meta_key'];
if ( strtolower( $value['operator'] ) == 'in' ) {
if ( strtolower( $value['operator'] ) == 'in' || strtolower( $value['operator'] ) == 'not in' ) {
if ( is_array( $value['meta_value'] ) ) {
$value['meta_value'] = implode( "','", $value['meta_value'] );
}
if ( ! empty( $value['meta_value'] ) ) {
$where_value = "IN ('{$value['meta_value']}')";
$where_value = "{$value['operator']} ('{$value['meta_value']}')";
}
} else {
$where_value = "{$value['operator']} '{$value['meta_value']}'";
@ -289,14 +289,14 @@ class WC_Admin_Report {
foreach ( $where as $value ) {
if ( strtolower( $value['operator'] ) == 'in' ) {
if ( strtolower( $value['operator'] ) == 'in' || strtolower( $value['operator'] ) == 'not in' ) {
if ( is_array( $value['value'] ) ) {
$value['value'] = implode( "','", $value['value'] );
}
if ( ! empty( $value['value'] ) ) {
$where_value = "IN ('{$value['value']}')";
$where_value = "{$value['operator']} ('{$value['value']}')";
}
} else {
$where_value = "{$value['operator']} '{$value['value']}'";

View File

@ -12,10 +12,9 @@ if ( ! defined( 'ABSPATH' ) ) {
<h3><?php printf( __( '"%s" Tax Rates', 'woocommerce' ), $current_class ? esc_html( $current_class ) : __( 'Standard', 'woocommerce' ) ); ?></h3>
<table class="wc_tax_rates wc_input_table sortable widefat">
<table class="wc_tax_rates wc_input_table widefat">
<thead>
<tr>
<th class="sort">&nbsp;</th>
<th width="8%"><a href="https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes" target="_blank"><?php _e( 'Country&nbsp;Code', 'woocommerce' ); ?></a>&nbsp;<?php echo wc_help_tip( __( 'A 2 digit country code, e.g. US. Leave blank to apply to all.', 'woocommerce' ) ); ?></th>
<th width="8%"><?php _e( 'State&nbsp;Code', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'A 2 digit state code, e.g. AL. Leave blank to apply to all.', 'woocommerce' ) ); ?></th>
<th><?php _e( 'ZIP/Postcode', 'woocommerce' ); ?>&nbsp;<?php echo wc_help_tip( __( 'Postcode for this rule. Semi-colon (;) separate multiple values. Leave blank to apply to all areas. Wildcards (*) and ranges for numeric postcodes (e.g. 12345...12350) can also be used.', 'woocommerce' ) ); ?></th>
@ -29,7 +28,7 @@ if ( ! defined( 'ABSPATH' ) ) {
</thead>
<tfoot>
<tr>
<th colspan="10">
<th colspan="9">
<a href="#" class="button plus insert"><?php _e( 'Insert row', 'woocommerce' ); ?></a>
<a href="#" class="button minus remove_tax_rates"><?php _e( 'Remove selected row(s)', 'woocommerce' ); ?></a>
<a href="#" download="tax_rates.csv" class="button export"><?php _e( 'Export CSV', 'woocommerce' ); ?></a>
@ -39,15 +38,13 @@ if ( ! defined( 'ABSPATH' ) ) {
</tfoot>
<tbody id="rates">
<tr>
<th colspan="10" style="text-align: center;"><?php esc_html_e( 'Loading&hellip;', 'woocommerce' ); ?></th>
<th colspan="9" style="text-align: center;"><?php esc_html_e( 'Loading&hellip;', 'woocommerce' ); ?></th>
</tr>
</tbody>
</table>
<script type="text/html" id="tmpl-wc-tax-table-row">
<tr class="tips" data-tip="<?php echo esc_attr( sprintf( __( 'Tax rate ID: %s', 'woocommerce' ), '{{ data.tax_rate_id }}' ) ); ?>" data-id="{{ data.tax_rate_id }}">
<td class="sort"></td>
<td class="country">
<input type="text" value="{{ data.tax_rate_country }}" placeholder="*" name="tax_rate_country[{{ data.tax_rate_id }}]" class="wc_input_country_iso" data-attribute="tax_rate_country" style="text-transform:uppercase" />
</td>
@ -88,7 +85,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<script type="text/html" id="tmpl-wc-tax-table-row-empty">
<tr>
<th colspan="10" style="text-align:center"><?php esc_html_e( 'No Matching Tax Rates Found.', 'woocommerce' ); ?></th>
<th colspan="9" style="text-align:center"><?php esc_html_e( 'No Matching Tax Rates Found.', 'woocommerce' ); ?></th>
</tr>
</script>

View File

@ -11,7 +11,12 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php if ( $logs ) : ?>
<div id="log-viewer-select">
<div class="alignleft">
<h2><?php printf( __( 'Log file: %s (%s)', 'woocommerce' ), esc_html( $viewed_log ), date_i18n( get_option( 'date_format') . ' ' . get_option( 'time_format'), filemtime( WC_LOG_DIR . $viewed_log ) ) ); ?></h2>
<h2>
<?php echo esc_html( $viewed_log ); ?>
<?php if ( ! empty( $handle ) ) : ?>
<a class="page-title-action" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'handle' => $handle ), admin_url( 'admin.php?page=wc-status&tab=logs' ) ), 'remove_log' ) ); ?>" class="button"><?php esc_html_e( 'Delete Log', 'woocommerce');?></a>
<?php endif; ?>
</h2>
</div>
<div class="alignright">
<form action="<?php echo admin_url( 'admin.php?page=wc-status&tab=logs' ); ?>" method="post">
@ -26,7 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="clear"></div>
</div>
<div id="log-viewer">
<textarea cols="70" rows="25"><?php echo esc_textarea( file_get_contents( WC_LOG_DIR . $viewed_log ) ); ?></textarea>
<textarea cols="70" rows="40"><?php echo esc_textarea( file_get_contents( WC_LOG_DIR . $viewed_log ) ); ?></textarea>
</div>
<?php else : ?>
<div class="updated woocommerce-message inline"><p><?php _e( 'There are currently no logs to view.', 'woocommerce' ); ?></p></div>

View File

@ -6,8 +6,15 @@
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
global $wpdb;
global $wpdb;
$system_status = new WC_REST_System_Status_Controller;
$environment = $system_status->get_environment_info();
$database = $system_status->get_database_info();
$active_plugins = $system_status->get_active_plugins();
$theme = $system_status->get_theme_info();
$settings = $system_status->get_settings();
$pages = $system_status->get_pages();
?>
<div class="updated woocommerce-message inline">
<p><?php _e( 'Please copy and paste this information in your ticket when contacting support:', 'woocommerce' ); ?> </p>
@ -29,54 +36,47 @@ global $wpdb;
<tr>
<td data-export-label="Home URL"><?php _e( 'Home URL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The URL of your site\'s homepage.', 'woocommerce' ) ); ?></td>
<td><?php form_option( 'home' ); ?></td>
<td><?php echo esc_html( $environment['home_url'] ) ?></td>
</tr>
<tr>
<td data-export-label="Site URL"><?php _e( 'Site URL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The root URL of your site.', 'woocommerce' ) ); ?></td>
<td><?php form_option( 'siteurl' ); ?></td>
<td><?php echo esc_html( $environment['site_url'] ) ?></td>
</tr>
<tr>
<td data-export-label="WC Version"><?php _e( 'WC Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The version of WooCommerce installed on your site.', 'woocommerce' ) ); ?></td>
<td><?php echo esc_html( WC()->version ); ?></td>
<td><?php echo esc_html( $environment['version'] ) ?></td>
</tr>
<tr>
<td data-export-label="Log Directory Writable"><?php _e( 'Log Directory Writable', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Several WooCommerce extensions can write logs which makes debugging problems easier. The directory must be writable for this to happen.', 'woocommerce' ) ); ?></td>
<td><?php
if ( @fopen( WC_LOG_DIR . 'test-log.log', 'a' ) ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> <code class="private">' . WC_LOG_DIR . '</code></mark> ';
if ( $environment['log_directory_writable'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> <code class="private">' . esc_html( $environment['log_directory'] ) . '</code></mark> ';
} else {
printf( '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'To allow logging, make <code>%s</code> writable or define a custom <code>WC_LOG_DIR</code>.', 'woocommerce' ) . '</mark>', WC_LOG_DIR );
printf( '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'To allow logging, make <code>%s</code> writable or define a custom <code>WC_LOG_DIR</code>.', 'woocommerce' ) . '</mark>', $environment['log_directory'] );
}
?></td>
</tr>
<tr>
<td data-export-label="WP Version"><?php _e( 'WP Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The version of WordPress installed on your site.', 'woocommerce' ) ); ?></td>
<td><?php bloginfo('version'); ?></td>
<td><?php echo esc_html( $environment['wp_version'] ) ?></td>
</tr>
<tr>
<td data-export-label="WP Multisite"><?php _e( 'WP Multisite', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Whether or not you have WordPress Multisite enabled.', 'woocommerce' ) ); ?></td>
<td><?php if ( is_multisite() ) echo '<span class="dashicons dashicons-yes"></span>'; else echo '&ndash;'; ?></td>
<td><?php if ( $environment['wp_multisite'] ) echo '<span class="dashicons dashicons-yes"></span>'; else echo '&ndash;'; ?></td>
</tr>
<tr>
<td data-export-label="WP Memory Limit"><?php _e( 'WP Memory Limit', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The maximum amount of memory (RAM) that your site can use at one time.', 'woocommerce' ) ); ?></td>
<td><?php
$memory = wc_let_to_num( WP_MEMORY_LIMIT );
if ( function_exists( 'memory_get_usage' ) ) {
$system_memory = wc_let_to_num( @ini_get( 'memory_limit' ) );
$memory = max( $memory, $system_memory );
}
if ( $memory < 67108864 ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend setting memory to at least 64MB. See: %s', 'woocommerce' ), size_format( $memory ), '<a href="https://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP" target="_blank">' . __( 'Increasing memory allocated to PHP', 'woocommerce' ) . '</a>' ) . '</mark>';
if ( $environment['wp_memory_limit'] < 67108864 ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend setting memory to at least 64MB. See: %s', 'woocommerce' ), size_format( $environment['wp_memory_limit'] ), '<a href="https://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP" target="_blank">' . __( 'Increasing memory allocated to PHP', 'woocommerce' ) . '</a>' ) . '</mark>';
} else {
echo '<mark class="yes">' . size_format( $memory ) . '</mark>';
echo '<mark class="yes">' . size_format( $environment['wp_memory_limit'] ) . '</mark>';
}
?></td>
</tr>
@ -84,7 +84,7 @@ global $wpdb;
<td data-export-label="WP Debug Mode"><?php _e( 'WP Debug Mode', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Displays whether or not WordPress is in Debug Mode.', 'woocommerce' ) ); ?></td>
<td>
<?php if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) : ?>
<?php if ( $environment['wp_debug_mode'] ) : ?>
<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>
<?php else : ?>
<mark class="no">&ndash;</mark>
@ -95,17 +95,17 @@ global $wpdb;
<td data-export-label="WP Cron"><?php _e( 'WP Cron', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Displays whether or not WP Cron Jobs are enabled.', 'woocommerce' ) ); ?></td>
<td>
<?php if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) : ?>
<mark class="no">&ndash;</mark>
<?php else : ?>
<?php if ( $environment['wp_cron'] ) : ?>
<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>
<?php else : ?>
<mark class="no">&ndash;</mark>
<?php endif; ?>
</td>
</tr>
<tr>
<td data-export-label="Language"><?php _e( 'Language', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The current language used by WordPress. Default = English', 'woocommerce' ) ); ?></td>
<td><?php echo get_locale(); ?></td>
<td><?php echo esc_html( $environment['language'] ) ?></td>
</tr>
</tbody>
</table>
@ -119,23 +119,16 @@ global $wpdb;
<tr>
<td data-export-label="Server Info"><?php _e( 'Server Info', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Information about the web server that is currently hosting your site.', 'woocommerce' ) ); ?></td>
<td><?php echo esc_html( $_SERVER['SERVER_SOFTWARE'] ); ?></td>
<td><?php echo esc_html( $environment['server_info'] ); ?></td>
</tr>
<tr>
<td data-export-label="PHP Version"><?php _e( 'PHP Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The version of PHP installed on your hosting server.', 'woocommerce' ) ); ?></td>
<td><?php
// Check if phpversion function exists.
if ( function_exists( 'phpversion' ) ) {
$php_version = phpversion();
if ( version_compare( $php_version, '5.6', '<' ) ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend a minimum PHP version of 5.6. See: %s', 'woocommerce' ), esc_html( $php_version ), '<a href="https://docs.woocommerce.com/document/how-to-update-your-php-version/" target="_blank">' . __( 'How to update your PHP version', 'woocommerce' ) . '</a>' ) . '</mark>';
} else {
echo '<mark class="yes">' . esc_html( $php_version ) . '</mark>';
}
if ( version_compare( $environment['php_version'], '5.6', '<' ) ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend a minimum PHP version of 5.6. See: %s', 'woocommerce' ), esc_html( $environment['php_version'] ), '<a href="https://docs.woocommerce.com/document/how-to-update-your-php-version/" target="_blank">' . __( 'How to update your PHP version', 'woocommerce' ) . '</a>' ) . '</mark>';
} else {
_e( "Couldn't determine PHP version because phpversion() doesn't exist.", 'woocommerce' );
echo '<mark class="yes">' . esc_html( $environment['php_version'] ) . '</mark>';
}
?></td>
</tr>
@ -143,55 +136,44 @@ global $wpdb;
<tr>
<td data-export-label="PHP Post Max Size"><?php _e( 'PHP Post Max Size', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The largest filesize that can be contained in one post.', 'woocommerce' ) ); ?></td>
<td><?php echo size_format( wc_let_to_num( ini_get( 'post_max_size' ) ) ); ?></td>
<td><?php echo esc_html( size_format( $environment['php_post_max_size'] ) ) ?></td>
</tr>
<tr>
<td data-export-label="PHP Time Limit"><?php _e( 'PHP Time Limit', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The amount of time (in seconds) that your site will spend on a single operation before timing out (to avoid server lockups)', 'woocommerce' ) ); ?></td>
<td><?php echo ini_get( 'max_execution_time' ); ?></td>
<td><?php echo esc_html( $environment['php_max_execution_time'] ) ?></td>
</tr>
<tr>
<td data-export-label="PHP Max Input Vars"><?php _e( 'PHP Max Input Vars', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The maximum number of variables your server can use for a single function to avoid overloads.', 'woocommerce' ) ); ?></td>
<td><?php echo ini_get( 'max_input_vars' ); ?></td>
<td><?php echo esc_html( $environment['php_max_input_vars'] ) ?></td>
</tr>
<tr>
<td data-export-label="cURL Version"><?php _e( 'cURL Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The version of cURL installed on your server.', 'woocommerce' ) ); ?></td>
<td><?php
if ( function_exists( 'curl_version' ) ) {
$curl_version = curl_version();
echo $curl_version['version'] . ', ' . $curl_version['ssl_version'];
} else {
_e( 'N/A', 'woocommerce' );
}
?></td>
<td><?php echo esc_html( $environment['curl_version'] ) ?></td>
</tr>
<tr>
<td data-export-label="SUHOSIN Installed"><?php _e( 'SUHOSIN Installed', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Suhosin is an advanced protection system for PHP installations. It was designed to protect your servers on the one hand against a number of well known problems in PHP applications and on the other hand against potential unknown vulnerabilities within these applications or the PHP core itself. If enabled on your server, Suhosin may need to be configured to increase its data submission limits.', 'woocommerce' ) ); ?></td>
<td><?php echo extension_loaded( 'suhosin' ) ? '<span class="dashicons dashicons-yes"></span>' : '&ndash;'; ?></td>
<td><?php echo $environment['suhosin_installed'] ? '<span class="dashicons dashicons-yes"></span>' : '&ndash;'; ?></td>
</tr>
<?php endif;
if ( $wpdb->use_mysqli ) {
$ver = mysqli_get_server_info( $wpdb->dbh );
} else {
$ver = mysql_get_server_info();
}
if ( ! empty( $wpdb->is_mysql ) && ! stristr( $ver, 'MariaDB' ) ) : ?>
<tr>
<td data-export-label="MySQL Version"><?php _e( 'MySQL Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The version of MySQL installed on your hosting server.', 'woocommerce' ) ); ?></td>
<td>
<?php
$mysql_version = $wpdb->db_version();
if ( version_compare( $mysql_version, '5.6', '<' ) ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend a minimum MySQL version of 5.6. See: %s', 'woocommerce' ), esc_html( $mysql_version ), '<a href="https://wordpress.org/about/requirements/" target="_blank">' . __( 'WordPress Requirements', 'woocommerce' ) . '</a>' ) . '</mark>';
if ( version_compare( $environment['mysql_version'], '5.6', '<' ) ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend a minimum MySQL version of 5.6. See: %s', 'woocommerce' ), esc_html( $environment['mysql_version'] ), '<a href="https://wordpress.org/about/requirements/" target="_blank">' . __( 'WordPress Requirements', 'woocommerce' ) . '</a>' ) . '</mark>';
} else {
echo '<mark class="yes">' . esc_html( $mysql_version ) . '</mark>';
echo '<mark class="yes">' . esc_html( $environment['mysql_version'] ) . '</mark>';
}
?>
</td>
@ -200,138 +182,96 @@ global $wpdb;
<tr>
<td data-export-label="Max Upload Size"><?php _e( 'Max Upload Size', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The largest filesize that can be uploaded to your WordPress installation.', 'woocommerce' ) ); ?></td>
<td><?php echo size_format( wp_max_upload_size() ); ?></td>
<td><?php echo size_format( $environment['max_upload_size'] ) ?></td>
</tr>
<tr>
<td data-export-label="Default Timezone is UTC"><?php _e( 'Default Timezone is UTC', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The default timezone for your server.', 'woocommerce' ) ); ?></td>
<td><?php
$default_timezone = date_default_timezone_get();
if ( 'UTC' !== $default_timezone ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Default timezone is %s - it should be UTC', 'woocommerce' ), $default_timezone ) . '</mark>';
if ( 'UTC' !== $environment['default_timezone'] ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Default timezone is %s - it should be UTC', 'woocommerce' ), $environment['default_timezone'] ) . '</mark>';
} else {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} ?>
</td>
</tr>
<?php
$posting = array();
// fsockopen/cURL.
$posting['fsockopen_curl']['name'] = 'fsockopen/cURL';
$posting['fsockopen_curl']['help'] = wc_help_tip( __( 'Payment gateways can use cURL to communicate with remote servers to authorize payments, other plugins may also use it when communicating with remote services.', 'woocommerce' ) );
if ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ) {
$posting['fsockopen_curl']['success'] = true;
} else {
$posting['fsockopen_curl']['success'] = false;
$posting['fsockopen_curl']['note'] = __( 'Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider.', 'woocommerce' );
}
// SOAP.
$posting['soap_client']['name'] = 'SoapClient';
$posting['soap_client']['help'] = wc_help_tip( __( 'Some webservices like shipping use SOAP to get information from remote servers, for example, live shipping quotes from FedEx require SOAP to be installed.', 'woocommerce' ) );
if ( class_exists( 'SoapClient' ) ) {
$posting['soap_client']['success'] = true;
} else {
$posting['soap_client']['success'] = false;
$posting['soap_client']['note'] = sprintf( __( 'Your server does not have the %s class enabled - some gateway plugins which use SOAP may not work as expected.', 'woocommerce' ), '<a href="https://php.net/manual/en/class.soapclient.php">SoapClient</a>' );
}
// DOMDocument.
$posting['dom_document']['name'] = 'DOMDocument';
$posting['dom_document']['help'] = wc_help_tip( __( 'HTML/Multipart emails use DOMDocument to generate inline CSS in templates.', 'woocommerce' ) );
if ( class_exists( 'DOMDocument' ) ) {
$posting['dom_document']['success'] = true;
} else {
$posting['dom_document']['success'] = false;
$posting['dom_document']['note'] = sprintf( __( 'Your server does not have the %s class enabled - HTML/Multipart emails, and also some extensions, will not work without DOMDocument.', 'woocommerce' ), '<a href="https://php.net/manual/en/class.domdocument.php">DOMDocument</a>' );
}
// GZIP.
$posting['gzip']['name'] = 'GZip';
$posting['gzip']['help'] = wc_help_tip( __( 'GZip (gzopen) is used to open the GEOIP database from MaxMind.', 'woocommerce' ) );
if ( is_callable( 'gzopen' ) ) {
$posting['gzip']['success'] = true;
} else {
$posting['gzip']['success'] = false;
$posting['gzip']['note'] = sprintf( __( 'Your server does not support the %s function - this is required to use the GeoIP database from MaxMind.', 'woocommerce' ), '<a href="https://php.net/manual/en/zlib.installation.php">gzopen</a>' );
}
// Multibyte String.
$posting['mbstring']['name'] = 'Multibyte String';
$posting['mbstring']['help'] = wc_help_tip( __( 'Multibyte String (mbstring) is used to convert character encoding, like for emails or converting characters to lowercase.', 'woocommerce' ) );
if ( extension_loaded( 'mbstring' ) ) {
$posting['mbstring']['success'] = true;
} else {
$posting['mbstring']['success'] = false;
$posting['mbstring']['note'] = sprintf( __( 'Your server does not support the %s functions - this is required for better character encoding. Some fallbacks will be used instead for it.', 'woocommerce' ), '<a href="https://php.net/manual/en/mbstring.installation.php">mbstring</a>' );
}
// WP Remote Post Check.
$posting['wp_remote_post']['name'] = __( 'Remote Post', 'woocommerce');
$posting['wp_remote_post']['help'] = wc_help_tip( __( 'PayPal uses this method of communicating when sending back transaction information.', 'woocommerce' ) );
$response = wp_safe_remote_post( 'https://www.paypal.com/cgi-bin/webscr', array(
'timeout' => 60,
'user-agent' => 'WooCommerce/' . WC()->version,
'httpversion' => '1.1',
'body' => array(
'cmd' => '_notify-validate'
)
) );
if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 ) {
$posting['wp_remote_post']['success'] = true;
} else {
$posting['wp_remote_post']['note'] = __( 'wp_remote_post() failed. PayPal IPN won\'t work with your server. Contact your hosting provider.', 'woocommerce' );
if ( is_wp_error( $response ) ) {
$posting['wp_remote_post']['note'] .= ' ' . sprintf( __( 'Error: %s', 'woocommerce' ), wc_clean( $response->get_error_message() ) );
<tr>
<td data-export-label="fsockopen/cURL"><?php _e( 'fsockopen/cURL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Payment gateways can use cURL to communicate with remote servers to authorize payments, other plugins may also use it when communicating with remote services.', 'woocommerce' ) ); ?></td>
<td><?php
if ( $environment['fsockopen_or_curl_enabled'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} else {
$posting['wp_remote_post']['note'] .= ' ' . sprintf( __( 'Status code: %s', 'woocommerce' ), wc_clean( $response['response']['code'] ) );
}
$posting['wp_remote_post']['success'] = false;
}
// WP Remote Get Check.
$posting['wp_remote_get']['name'] = __( 'Remote Get', 'woocommerce');
$posting['wp_remote_get']['help'] = wc_help_tip( __( 'WooCommerce plugins may use this method of communication when checking for plugin updates.', 'woocommerce' ) );
$response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) );
if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 ) {
$posting['wp_remote_get']['success'] = true;
} else {
$posting['wp_remote_get']['note'] = __( 'wp_remote_get() failed. The WooCommerce plugin updater won\'t work with your server. Contact your hosting provider.', 'woocommerce' );
if ( is_wp_error( $response ) ) {
$posting['wp_remote_get']['note'] .= ' ' . sprintf( __( 'Error: %s', 'woocommerce' ), wc_clean( $response->get_error_message() ) );
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider.', 'woocommerce' ) . '</mark>';
} ?>
</td>
</tr>
<tr>
<td data-export-label="SoapClient"><?php _e( 'SoapClient', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Some webservices like shipping use SOAP to get information from remote servers, for example, live shipping quotes from FedEx require SOAP to be installed.', 'woocommerce' ) ); ?></td>
<td><?php
if ( $environment['soapclient_enabled'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} else {
$posting['wp_remote_get']['note'] .= ' ' . sprintf( __( 'Status code: %s', 'woocommerce' ), wc_clean( $response['response']['code'] ) );
}
$posting['wp_remote_get']['success'] = false;
}
$posting = apply_filters( 'woocommerce_debug_posting', $posting );
foreach ( $posting as $post ) {
$mark = ! empty( $post['success'] ) ? 'yes' : 'error';
?>
<tr>
<td data-export-label="<?php echo esc_html( $post['name'] ); ?>"><?php echo esc_html( $post['name'] ); ?>:</td>
<td class="help"><?php echo isset( $post['help'] ) ? $post['help'] : ''; ?></td>
<td>
<mark class="<?php echo $mark; ?>">
<?php echo ! empty( $post['success'] ) ? '<span class="dashicons dashicons-yes"></span>' : '<span class="dashicons dashicons-no-alt"></span>'; ?> <?php echo ! empty( $post['note'] ) ? wp_kses_data( $post['note'] ) : ''; ?>
</mark>
</td>
</tr>
<?php
}
?>
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Your server does not have the %s class enabled - some gateway plugins which use SOAP may not work as expected.', 'woocommerce' ), '<a href="https://php.net/manual/en/class.soapclient.php">SoapClient</a>' ) . '</mark>';
} ?>
</td>
</tr>
<tr>
<td data-export-label="DOMDocument"><?php _e( 'DOMDocument', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'HTML/Multipart emails use DOMDocument to generate inline CSS in templates.', 'woocommerce' ) ); ?></td>
<td><?php
if ( $environment['domdocument_enabled'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} else {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Your server does not have the %s class enabled - HTML/Multipart emails, and also some extensions, will not work without DOMDocument.', 'woocommerce' ), '<a href="https://php.net/manual/en/class.domdocument.php">DOMDocument</a>' ) . '</mark>';
} ?>
</td>
</tr>
<tr>
<td data-export-label="GZip"><?php _e( 'GZip', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'GZip (gzopen) is used to open the GEOIP database from MaxMind.', 'woocommerce' ) ); ?></td>
<td><?php
if ( $environment['gzip_enabled'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} else {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Your server does not support the %s function - this is required to use the GeoIP database from MaxMind.', 'woocommerce' ), '<a href="https://php.net/manual/en/zlib.installation.php">gzopen</a>' ) . '</mark>';
} ?>
</td>
</tr>
<tr>
<td data-export-label="Multibyte String"><?php _e( 'Multibyte String', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Multibyte String (mbstring) is used to convert character encoding, like for emails or converting characters to lowercase.', 'woocommerce' ) ); ?></td>
<td><?php
if ( $environment['mbstring_enabled'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} else {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Your server does not support the %s functions - this is required for better character encoding. Some fallbacks will be used instead for it.', 'woocommerce' ), '<a href="https://php.net/manual/en/mbstring.installation.php">mbstring</a>' ) . '</mark>';
} ?>
</td>
</tr>
<tr>
<td data-export-label="Remote Post"><?php _e( 'Remote Post', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'PayPal uses this method of communicating when sending back transaction information.', 'woocommerce' ) ); ?></td>
<td><?php
if ( $environment['remote_post_successful'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} else {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'wp_remote_post() failed. Contact your hosting provider.', 'woocommerce' ) . ' ' . esc_html( $environment['remote_post_response'] ) . '</mark>';
} ?>
</td>
</tr>
<tr>
<td data-export-label="Remote Get"><?php _e( 'Remote Get', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'WooCommerce plugins may use this method of communication when checking for plugin updates.', 'woocommerce' ) ); ?></td>
<td><?php
if ( $environment['remote_get_successful'] ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
} else {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'wp_remote_get() failed. Contact your hosting provider.', 'woocommerce' ) . ' ' . esc_html( $environment['remote_get_response'] ) . '</mark>';
} ?>
</td>
</tr>
</tbody>
</table>
<table class="wc_status_table widefat" cellspacing="0">
@ -344,137 +284,83 @@ global $wpdb;
<tr>
<td data-export-label="WC Database Version"><?php _e( 'WC Database Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The version of WooCommerce that the database is formatted for. This should be the same as your WooCommerce Version.', 'woocommerce' ) ); ?></td>
<td><?php echo esc_html( get_option( 'woocommerce_db_version' ) ); ?></td>
<td><?php echo esc_html( $database['wc_database_version'] ); ?></td>
</tr>
<tr>
<td data-export-label="WC Database Prefix"><?php _e( 'Database Prefix', 'woocommerce' ); ?></td>
<td class="help">&nbsp;</td>
<td><?php
if ( strlen( $wpdb->prefix ) > 20 ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend using a prefix with less than 20 characters. See: %s', 'woocommerce' ), esc_html( $wpdb->prefix ), '<a href="https://docs.woocommerce.com/document/completed-order-email-doesnt-contain-download-links/#section-2" target="_blank">' . __( 'How to update your database table prefix', 'woocommerce' ) . '</a>' ) . '</mark>';
if ( strlen( $database['database_prefix'] ) > 20 ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '%s - We recommend using a prefix with less than 20 characters. See: %s', 'woocommerce' ), esc_html( $database['database_prefix'] ), '<a href="https://docs.woocommerce.com/document/completed-order-email-doesnt-contain-download-links/#section-2" target="_blank">' . __( 'How to update your database table prefix', 'woocommerce' ) . '</a>' ) . '</mark>';
} else {
echo '<mark class="yes">' . esc_html( $wpdb->prefix ) . '</mark>';
echo '<mark class="yes">' . esc_html( $database['database_prefix'] ) . '</mark>';
}
?>
</td>
</tr>
<tr>
<?php
$tables = array(
'woocommerce_sessions',
'woocommerce_api_keys',
'woocommerce_attribute_taxonomies',
'woocommerce_downloadable_product_permissions',
'woocommerce_order_items',
'woocommerce_order_itemmeta',
'woocommerce_tax_rates',
'woocommerce_tax_rate_locations',
'woocommerce_shipping_zones',
'woocommerce_shipping_zone_locations',
'woocommerce_shipping_zone_methods',
'woocommerce_payment_tokens',
'woocommerce_payment_tokenmeta',
);
if ( get_option( 'db_version' ) < 34370 ) {
$tables[] = 'woocommerce_termmeta';
}
foreach ( $tables as $table ) {
?>
<tr>
<td><?php echo esc_html( $table ); ?></td>
<td class="help">&nbsp;</td>
<td><?php echo $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s;", $wpdb->prefix . $table ) ) !== $wpdb->prefix . $table ? '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'Table does not exist', 'woocommerce' ) . '</mark>' : '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>'; ?></td>
</tr>
<?php
}
if ( in_array( get_option( 'woocommerce_default_customer_address' ), array( 'geolocation_ajax', 'geolocation' ) ) ) {
?>
<tr>
<td data-export-label="MaxMind GeoIP Database"><?php _e( 'MaxMind GeoIP Database', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The GeoIP database from MaxMind is used to geolocate customers.', 'woocommerce' ) ); ?></td>
<td><?php
if ( file_exists( WC_Geolocation::get_local_database_path() ) ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> <code class="private">' . esc_html( WC_Geolocation::get_local_database_path() ) . '</code></mark> ';
} else {
printf( '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'The MaxMind GeoIP Database does not exist - Geolocation will not function. You can download and install it manually from %1$s to the path: %2$s. Scroll down to \"Downloads\" and download the \"Binary / gzip\" file next to \"GeoLite Country\"', 'woocommerce' ), make_clickable( 'http://dev.maxmind.com/geoip/legacy/geolite/' ), '<code class="private">' . WC_Geolocation::get_local_database_path() . '</code>' ) . '</mark>', WC_LOG_DIR );
}
?></td>
</tr>
<?php
}
<?php
foreach ( $database['database_tables'] as $table => $table_exists ) {
?>
</tr>
<tr>
<td><?php echo esc_html( $table ); ?></td>
<td class="help">&nbsp;</td>
<td><?php echo ! $table_exists ? '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'Table does not exist', 'woocommerce' ) . '</mark>' : '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>'; ?></td>
</tr>
<?php
}
if ( $settings['geolocation_enabled'] ) {
?>
<tr>
<td data-export-label="MaxMind GeoIP Database"><?php _e( 'MaxMind GeoIP Database', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The GeoIP database from MaxMind is used to geolocate customers.', 'woocommerce' ) ); ?></td>
<td><?php
if ( file_exists( $database['maxmind_geoip_database'] ) ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> <code class="private">' . esc_html( $database['maxmind_geoip_database'] ) . '</code></mark> ';
} else {
printf( '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'The MaxMind GeoIP Database does not exist - Geolocation will not function. You can download and install it manually from %1$s to the path: %2$s. Scroll down to \"Downloads\" and download the \"Binary / gzip\" file next to \"GeoLite Country\". Please remember to uncompress GeoIP.dat.gz and upload the GeoIP.dat file only.', 'woocommerce' ), make_clickable( 'http://dev.maxmind.com/geoip/legacy/geolite/' ), '<code class="private">' . $database['maxmind_geoip_database'] . '</code>' ) . '</mark>', WC_LOG_DIR );
}
?></td>
</tr>
<?php
}
?>
</tbody>
</table>
<table class="wc_status_table widefat" cellspacing="0">
<thead>
<tr>
<th colspan="3" data-export-label="Active Plugins (<?php echo count( (array) get_option( 'active_plugins' ) ); ?>)"><h2><?php _e( 'Active Plugins', 'woocommerce' ); ?> (<?php echo count( (array) get_option( 'active_plugins' ) ); ?>)</h2></th>
<th colspan="3" data-export-label="Active Plugins (<?php echo count( $active_plugins ) ?>)"><h2><?php _e( 'Active Plugins', 'woocommerce' ); ?> (<?php echo count( $active_plugins ) ?>)</h2></th>
</tr>
</thead>
<tbody>
<?php
$active_plugins = (array) get_option( 'active_plugins', array() );
if ( is_multisite() ) {
$network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
$active_plugins = array_merge( $active_plugins, $network_activated_plugins );
}
foreach ( $active_plugins as $plugin ) {
$plugin_data = @get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
$dirname = dirname( $plugin );
$version_string = '';
$network_string = '';
if ( ! empty( $plugin_data['Name'] ) ) {
if ( ! empty( $plugin['name'] ) ) {
$dirname = dirname( $plugin['plugin'] );
// Link the plugin name to the plugin url if available.
$plugin_name = esc_html( $plugin_data['Name'] );
if ( ! empty( $plugin_data['PluginURI'] ) ) {
$plugin_name = '<a href="' . esc_url( $plugin_data['PluginURI'] ) . '" title="' . esc_attr__( 'Visit plugin homepage' , 'woocommerce' ) . '" target="_blank">' . $plugin_name . '</a>';
$plugin_name = esc_html( $plugin['name'] );
if ( ! empty( $plugin['url'] ) ) {
$plugin_name = '<a href="' . esc_url( $plugin['url'] ) . '" title="' . esc_attr__( 'Visit plugin homepage' , 'woocommerce' ) . '" target="_blank">' . $plugin_name . '</a>';
}
if ( strstr( $dirname, 'woocommerce-' ) && strstr( $plugin_data['PluginURI'], 'woothemes.com' ) ) {
if ( false === ( $version_data = get_transient( md5( $plugin ) . '_version_data' ) ) ) {
$changelog = wp_safe_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $dirname . '/changelog.txt' );
$cl_lines = explode( "\n", wp_remote_retrieve_body( $changelog ) );
if ( ! empty( $cl_lines ) ) {
foreach ( $cl_lines as $line_num => $cl_line ) {
if ( preg_match( '/^[0-9]/', $cl_line ) ) {
$date = str_replace( '.' , '-' , trim( substr( $cl_line , 0 , strpos( $cl_line , '-' ) ) ) );
$version = preg_replace( '~[^0-9,.]~' , '' ,stristr( $cl_line , "version" ) );
$update = trim( str_replace( "*" , "" , $cl_lines[ $line_num + 1 ] ) );
$version_data = array( 'date' => $date , 'version' => $version , 'update' => $update , 'changelog' => $changelog );
set_transient( md5( $plugin ) . '_version_data', $version_data, DAY_IN_SECONDS );
break;
}
}
}
$version_string = '';
$network_string = '';
if ( strstr( $plugin['url'], 'woothemes.com' ) ) {
if ( ! empty( $plugin['version_latest'] ) && version_compare( $plugin['version_latest'], $plugin['version'], '>' ) ) {
$version_string = ' &ndash; <strong style="color:red;">' . esc_html( sprintf( _x( '%s is available', 'Version info', 'woocommerce' ), $plugin['version_latest'] ) ) . '</strong>';
}
if ( ! empty( $version_data['version'] ) && version_compare( $version_data['version'], $plugin_data['Version'], '>' ) ) {
$version_string = ' &ndash; <strong style="color:red;">' . esc_html( sprintf( _x( '%s is available', 'Version info', 'woocommerce' ), $version_data['version'] ) ) . '</strong>';
}
if ( $plugin_data['Network'] != false ) {
if ( $plugin['network_activated'] != false ) {
$network_string = ' &ndash; <strong style="color:black;">' . __( 'Network enabled', 'woocommerce' ) . '</strong>';
}
}
?>
<tr>
<td><?php echo $plugin_name; ?></td>
<td class="help">&nbsp;</td>
<td><?php echo sprintf( _x( 'by %s', 'by author', 'woocommerce' ), $plugin_data['Author'] ) . ' &ndash; ' . esc_html( $plugin_data['Version'] ) . $version_string . $network_string; ?></td>
<td><?php echo sprintf( _x( 'by %s', 'by author', 'woocommerce' ), $plugin['author_name'] ) . ' &ndash; ' . esc_html( $plugin['version'] ) . $version_string . $network_string; ?></td>
</tr>
<?php
}
@ -489,49 +375,51 @@ global $wpdb;
</tr>
</thead>
<tbody>
<tr>
<td data-export-label="API Enabled"><?php _e( 'API Enabled', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Does your site have REST API enabled?', 'woocommerce' ) ); ?></td>
<td><?php echo $settings['api_enabled'] ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<mark class="no">&ndash;</mark>'; ?></td>
</tr>
<tr>
<td data-export-label="Force SSL"><?php _e( 'Force SSL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Does your site force a SSL Certificate for transactions?', 'woocommerce' ) ); ?></td>
<td><?php echo 'yes' === get_option( 'woocommerce_force_ssl_checkout' ) ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<mark class="no">&ndash;</mark>'; ?></td>
<td><?php echo $settings['force_ssl'] ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<mark class="no">&ndash;</mark>'; ?></td>
</tr>
<tr>
<td data-export-label="Currency"><?php _e( 'Currency', 'woocommerce' ) ?></td>
<td class="help"><?php echo wc_help_tip( __( 'What currency prices are listed at in the catalog and which currency gateways will take payments in.', 'woocommerce' ) ); ?></td>
<td><?php echo get_woocommerce_currency(); ?> (<?php echo get_woocommerce_currency_symbol() ?>)</td>
<td><?php echo esc_html( $settings['currency'] ) ?> (<?php echo esc_html( $settings['currency_symbol'] ) ?>)</td>
</tr>
<tr>
<td data-export-label="Currency Position"><?php _e( 'Currency Position', 'woocommerce' ) ?></td>
<td class="help"><?php echo wc_help_tip( __( 'The position of the currency symbol.', 'woocommerce' ) ); ?></td>
<td><?php echo get_option( 'woocommerce_currency_pos' ); ?></td>
<td><?php echo esc_html( $settings['currency_position'] ) ?></td>
</tr>
<tr>
<td data-export-label="Thousand Separator"><?php _e( 'Thousand Separator', 'woocommerce' ) ?></td>
<td class="help"><?php echo wc_help_tip( __( 'The thousand separator of displayed prices.', 'woocommerce' ) ); ?></td>
<td><?php echo wc_get_price_thousand_separator(); ?></td>
<td><?php echo esc_html( $settings['thousand_separator'] ) ?></td>
</tr>
<tr>
<td data-export-label="Decimal Separator"><?php _e( 'Decimal Separator', 'woocommerce' ) ?></td>
<td class="help"><?php echo wc_help_tip( __( 'The decimal separator of displayed prices.', 'woocommerce' ) ); ?></td>
<td><?php echo wc_get_price_decimal_separator(); ?></td>
<td><?php echo esc_html( $settings['decimal_separator'] ) ?></td>
</tr>
<tr>
<td data-export-label="Number of Decimals"><?php _e( 'Number of Decimals', 'woocommerce' ) ?></td>
<td class="help"><?php echo wc_help_tip( __( 'The number of decimal points shown in displayed prices.', 'woocommerce' ) ); ?></td>
<td><?php echo wc_get_price_decimals(); ?></td>
<td><?php echo esc_html( $settings['number_of_decimals'] ) ?></td>
</tr>
</tbody>
</table>
<table class="wc_status_table widefat" cellspacing="0">
<thead>
<tr>
<th colspan="3" data-export-label="API"><h2><?php _e( 'API', 'woocommerce' ); ?></h2></th>
</tr>
</thead>
<tbody>
<tr>
<td data-export-label="API Enabled"><?php _e( 'API Enabled', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Does your site have REST API enabled?', 'woocommerce' ) ); ?></td>
<td><?php echo 'yes' === get_option( 'woocommerce_api_enabled' ) ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<mark class="no">&ndash;</mark>'; ?></td>
<td data-export-label="Taxonomies: Product Types"><?php _e( 'Taxonomies: Product Types', 'woocommerce' ); ?></th>
<td class="help"><?php echo wc_help_tip( __( 'A list of taxonomy terms that can be used in regard to order/product statuses.', 'woocommerce' ) ); ?></td>
<td><?php
$display_terms = array();
foreach ( $settings['taxonomies'] as $slug => $name ) {
$display_terms[] = strtolower( $name ) . ' (' . $slug . ')';
}
echo implode( ', ', array_map( 'esc_html', $display_terms ) );
?></td>
</tr>
</tbody>
</table>
@ -543,177 +431,109 @@ global $wpdb;
</thead>
<tbody>
<?php
$check_pages = array(
_x( 'Shop Base', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_shop_page_id',
'shortcode' => '',
'help' => __( 'The URL of your WooCommerce shop\'s homepage (along with the Page ID).', 'woocommerce' ),
),
_x( 'Cart', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_cart_page_id',
'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
'help' => __( 'The URL of your WooCommerce shop\'s cart (along with the page ID).', 'woocommerce' ),
),
_x( 'Checkout', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_checkout_page_id',
'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
'help' => __( 'The URL of your WooCommerce shop\'s checkout (along with the page ID).', 'woocommerce' ),
),
_x( 'My Account', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_myaccount_page_id',
'shortcode' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
'help' => __( 'The URL of your WooCommerce shop\'s “My Account” Page (along with the page ID).', 'woocommerce' ),
)
);
$alt = 1;
foreach ( $check_pages as $page_name => $values ) {
foreach ( $pages as $page ) {
$error = false;
$page_id = get_option( $values['option'] );
if ( $page_id ) {
$page_name = '<a href="' . get_edit_post_link( $page_id ) . '" title="' . sprintf( _x( 'Edit %s page', 'WC Pages links in the System Status', 'woocommerce' ), esc_html( $page_name ) ) . '">' . esc_html( $page_name ) . '</a>';
if ( $page['page_id'] ) {
$page_name = '<a href="' . get_edit_post_link( $page['page_id'] ) . '" title="' . sprintf( _x( 'Edit %s page', 'WC Pages links in the System Status', 'woocommerce' ), esc_html( $page['page_name'] ) ) . '">' . esc_html( $page['page_name'] ) . '</a>';
} else {
$page_name = esc_html( $page_name );
$page_name = esc_html( $page['page_name'] );
}
echo '<tr><td data-export-label="' . esc_attr( $page_name ) . '">' . $page_name . ':</td>';
echo '<td class="help">' . wc_help_tip( $values['help'] ) . '</td><td>';
echo '<td class="help">' . wc_help_tip( sprintf( __( 'The URL of your WooCommerce shop\'s %s (along with the Page ID).', 'woocommerce' ), $page_name ) ) . '</td><td>';
// Page ID check.
if ( ! $page_id ) {
if ( ! $page['page_set'] ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'Page not set', 'woocommerce' ) . '</mark>';
$error = true;
} else if ( ! get_post( $page_id ) ) {
} else if ( ! $page['page_exists'] ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'Page ID is set, but the page does not exist', 'woocommerce' ) . '</mark>';
$error = true;
} else if ( get_post_status( $page_id ) !== 'publish' ) {
} else if ( ! $page['page_visible'] ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Page visibility should be %spublic%s', 'woocommerce' ), '<a href="https://codex.wordpress.org/Content_Visibility" target="_blank">', '</a>' ) . '</mark>';
$error = true;
} else {
// Shortcode check
if ( $values['shortcode'] ) {
$page = get_post( $page_id );
if ( empty( $page ) ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Page does not exist', 'woocommerce' ) ) . '</mark>';
if ( $page['shortcode_required'] ) {
if ( ! $page['shortcode_present'] ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Page does not contain the shortcode.', 'woocommerce' ), $page['shortcode'] ) . '</mark>';
$error = true;
} else if ( ! strstr( $page->post_content, $values['shortcode'] ) ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Page does not contain the shortcode: %s', 'woocommerce' ), $values['shortcode'] ) . '</mark>';
$error = true;
}
}
}
if ( ! $error ) echo '<mark class="yes">#' . absint( $page_id ) . ' - ' . str_replace( home_url(), '', get_permalink( $page_id ) ) . '</mark>';
if ( ! $error ) echo '<mark class="yes">#' . absint( $page['page_id'] ) . ' - ' . str_replace( home_url(), '', get_permalink( $page['page_id'] ) ) . '</mark>';
echo '</td></tr>';
}
?>
</tbody>
</table>
<table class="wc_status_table widefat" cellspacing="0">
<thead>
<tr>
<th colspan="3" data-export-label="Taxonomies"><h2><?php _e( 'Taxonomies', 'woocommerce' ); ?><?php echo wc_help_tip( __( 'A list of taxonomy terms that can be used in regard to order/product statuses.', 'woocommerce' ) ); ?></h2></th>
</tr>
</thead>
<tbody>
<tr>
<td data-export-label="Product Types"><?php _e( 'Product Types', 'woocommerce' ); ?>:</td>
<td class="help">&nbsp;</td>
<td><?php
$display_terms = array();
$terms = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
foreach ( $terms as $term ) {
$display_terms[] = strtolower( $term->name ) . ' (' . $term->slug . ')';
}
echo implode( ', ', array_map( 'esc_html', $display_terms ) );
?></td>
</tr>
</tbody>
</table>
<table class="wc_status_table widefat" cellspacing="0">
<thead>
<tr>
<th colspan="3" data-export-label="Theme"><h2><?php _e( 'Theme', 'woocommerce' ); ?></h2></th>
</tr>
</thead>
<?php
include_once( ABSPATH . 'wp-admin/includes/theme-install.php' );
$active_theme = wp_get_theme();
$theme_version = $active_theme->Version;
$update_theme_version = WC_Admin_Status::get_latest_theme_version( $active_theme );
?>
<tbody>
<tr>
<td data-export-label="Name"><?php _e( 'Name', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The name of the current active theme.', 'woocommerce' ) ); ?></td>
<td><?php echo esc_html( $active_theme->Name ); ?></td>
<td><?php echo esc_html( $theme['name'] ) ?></td>
</tr>
<tr>
<td data-export-label="Version"><?php _e( 'Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The installed version of the current active theme.', 'woocommerce' ) ); ?></td>
<td><?php
echo esc_html( $theme_version );
if ( version_compare( $theme_version, $update_theme_version, '<' ) ) {
echo ' &ndash; <strong style="color:red;">' . sprintf( __( '%s is available', 'woocommerce' ), esc_html( $update_theme_version ) ) . '</strong>';
echo esc_html( $theme['version'] );
if ( version_compare( $theme['version'], $theme['version_latest'], '<' ) ) {
echo ' &ndash; <strong style="color:red;">' . sprintf( __( '%s is available', 'woocommerce' ), esc_html( $theme['version_latest'] ) ) . '</strong>';
}
?></td>
</tr>
<tr>
<td data-export-label="Author URL"><?php _e( 'Author URL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The theme developers URL.', 'woocommerce' ) ); ?></td>
<td><?php echo $active_theme->{'Author URI'}; ?></td>
<td><?php echo esc_html( $theme['author_url'] ) ?></td>
</tr>
<tr>
<td data-export-label="Child Theme"><?php _e( 'Child Theme', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Displays whether or not the current theme is a child theme.', 'woocommerce' ) ); ?></td>
<td><?php
echo is_child_theme() ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<span class="dashicons dashicons-no-alt"></span> &ndash; ' . sprintf( __( 'If you\'re modifying WooCommerce on a parent theme you didn\'t build personally, then we recommend using a child theme. See: <a href="%s" target="_blank">How to create a child theme</a>', 'woocommerce' ), 'https://codex.wordpress.org/Child_Themes' );
echo $theme['is_child_theme'] ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<span class="dashicons dashicons-no-alt"></span> &ndash; ' . sprintf( __( 'If you\'re modifying WooCommerce on a parent theme you didn\'t build personally, then we recommend using a child theme. See: <a href="%s" target="_blank">How to create a child theme</a>', 'woocommerce' ), 'https://codex.wordpress.org/Child_Themes' );
?></td>
</tr>
<?php
if( is_child_theme() ) :
$parent_theme = wp_get_theme( $active_theme->Template );
$update_theme_version = WC_Admin_Status::get_latest_theme_version( $parent_theme );
if( $theme['is_child_theme'] ) :
?>
<tr>
<td data-export-label="Parent Theme Name"><?php _e( 'Parent Theme Name', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The name of the parent theme.', 'woocommerce' ) ); ?></td>
<td><?php echo esc_html( $parent_theme->Name ); ?></td>
<td><?php echo esc_html( $theme['parent_name'] ); ?></td>
</tr>
<tr>
<td data-export-label="Parent Theme Version"><?php _e( 'Parent Theme Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The installed version of the parent theme.', 'woocommerce' ) ); ?></td>
<td><?php
echo esc_html( $parent_theme->Version );
if ( version_compare( $parent_theme->Version, $update_theme_version, '<' ) ) {
echo ' &ndash; <strong style="color:red;">' . sprintf( __( '%s is available', 'woocommerce' ), esc_html( $update_theme_version ) ) . '</strong>';
echo esc_html( $theme['parent_version'] );
if ( version_compare( $theme['parent_version'], $theme['parent_version_latest'], '<' ) ) {
echo ' &ndash; <strong style="color:red;">' . sprintf( __( '%s is available', 'woocommerce' ), esc_html( $theme['parent_version_latest'] ) ) . '</strong>';
}
?></td>
</tr>
<tr>
<td data-export-label="Parent Theme Author URL"><?php _e( 'Parent Theme Author URL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'The parent theme developers URL.', 'woocommerce' ) ); ?></td>
<td><?php echo $parent_theme->{'Author URI'}; ?></td>
<td><?php echo esc_html( $theme['parent_author_url'] ) ?></td>
</tr>
<?php endif ?>
<tr>
<td data-export-label="WooCommerce Support"><?php _e( 'WooCommerce Support', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( __( 'Displays whether or not the current active theme declares WooCommerce support.', 'woocommerce' ) ); ?></td>
<td><?php
if ( ! current_theme_supports( 'woocommerce' ) && ! in_array( $active_theme->template, wc_get_core_supported_themes() ) ) {
if ( ! $theme['has_woocommerce_support'] ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . __( 'Not Declared', 'woocommerce' ) . '</mark>';
} else {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
@ -729,62 +549,36 @@ global $wpdb;
</tr>
</thead>
<tbody>
<?php if ( file_exists( get_stylesheet_directory() . '/woocommerce.php' ) || file_exists( get_template_directory() . '/woocommerce.php' ) ) : ?>
<?php if ( $theme['has_woocommerce_file'] ) : ?>
<tr>
<td data-export-label="Overrides"><?php _e( 'Archive Template', 'woocommerce' ); ?>:</td>
<td data-export-label="Archive Template"><?php _e( 'Archive Template', 'woocommerce' ); ?>:</td>
<td class="help">&nbsp;</td>
<td><?php _e( 'Your theme has a woocommerce.php file, you will not be able to override the woocommerce/archive-product.php custom template since woocommerce.php has priority over archive-product.php. This is intended to prevent display issues.', 'woocommerce' ); ?></td>
</tr>
<?php endif ?>
<?php
$template_paths = apply_filters( 'woocommerce_template_overrides_scan_paths', array( 'WooCommerce' => WC()->plugin_path() . '/templates/' ) );
$scanned_files = array();
$found_files = array();
$outdated_templates = false;
foreach ( $template_paths as $plugin_name => $template_path ) {
$scanned_files = WC_Admin_Status::scan_template_files( $template_path );
foreach ( $scanned_files as $file ) {
if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/' . $file;
} elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/woocommerce/' . $file;
} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
$theme_file = get_template_directory() . '/' . $file;
} elseif( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_template_directory() . '/woocommerce/' . $file;
} else {
$theme_file = false;
}
if ( ! empty( $theme_file ) ) {
$core_version = WC_Admin_Status::get_file_version( $template_path . $file );
$theme_version = WC_Admin_Status::get_file_version( $theme_file );
if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
if ( ! $outdated_templates ) {
$outdated_templates = true;
}
$found_files[ $plugin_name ][] = sprintf( __( '<code>%s</code> version <strong style="color:red">%s</strong> is out of date. The core version is %s', 'woocommerce' ), str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ), $theme_version ? $theme_version : '-', $core_version );
} else {
$found_files[ $plugin_name ][] = sprintf( '<code>%s</code>', str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ) );
}
}
}
}
if ( ! empty( $found_files ) ) {
foreach ( $found_files as $plugin_name => $found_plugin_files ) {
?>
if ( ! empty( $theme['overrides'] ) ) { ?>
<tr>
<td data-export-label="Overrides"><?php _e( 'Overrides', 'woocommerce' ); ?> (<?php echo $plugin_name; ?>):</td>
<td data-export-label="Overrides"><?php _e( 'Overrides', 'woocommerce' ); ?></td>
<td class="help">&nbsp;</td>
<td><?php echo implode( ', <br/>', $found_plugin_files ); ?></td>
<td>
<?php
for ( $i = 0; $i < count( $theme['overrides'] ); $i++ ) {
$override = $theme['overrides'][ $i ];
if ( $override['core_version'] && ( empty( $override['version'] ) || version_compare( $override['version'], $override['core_version'], '<' ) ) ) {
printf( __( '<code>%s</code> version <strong style="color:red">%s</strong> is out of date. The core version is %s', 'woocommerce' ), $override['file'], $override['version'] ? $override['version'] : '-', $override['core_version'] );
} else {
echo esc_html( $override['file'] );
}
if ( $i !== ( count( $theme['overrides'] ) - 1 ) ) {
echo ', ';
}
echo '<br />';
}
?>
</td>
</tr>
<?php
}
} else {
?>
<tr>
@ -795,12 +589,12 @@ global $wpdb;
<?php
}
if ( true === $outdated_templates ) {
if ( true === $theme['has_outdated_templates'] ) {
?>
<tr>
<td>&nbsp;</td>
<td data-export-label="Outdated Templates"><?php _e( 'Outdated Templates', 'woocommerce' ); ?>:</td>
<td class="help">&nbsp;</td>
<td><a href="https://docs.woocommerce.com/document/fix-outdated-templates-woocommerce/" target="_blank"><?php _e( 'Learn how to update outdated templates', 'woocommerce' ) ?></a></td>
<td><mark class="error"><span class="dashicons dashicons-warning"></span></mark><a href="https://docs.woocommerce.com/document/fix-outdated-templates-woocommerce/" target="_blank"><?php _e( 'Learn how to update', 'woocommerce' ) ?></a></td>
</tr>
<?php
}

View File

@ -12,7 +12,11 @@ if ( ! defined( 'ABSPATH' ) ) {
<div id="poststuff" class="woocommerce-reports-wide">
<div class="postbox">
<h3 class="screen-reader-text"><?php echo esc_html( $ranges[ $current_range ] ); ?></h3>
<?php if ( 'custom' === $current_range && isset( $_GET['start_date'], $_GET['end_date'] ) ) : ?>
<h3 class="screen-reader-text"><?php echo esc_html( sprintf( _x( 'From %s to %s', 'start date and end date', 'woocommerce' ), wc_clean( $_GET['start_date'] ), wc_clean( $_GET['end_date'] ) ) ); ?></h3>
<?php else : ?>
<h3 class="screen-reader-text"><?php echo esc_html( $ranges[ $current_range ] ); ?></h3>
<?php endif; ?>
<div class="stats_range">
<?php $this->get_export_button(); ?>

View File

@ -1019,7 +1019,7 @@ class WC_REST_Orders_Controller extends WC_REST_Posts_Controller {
// Create item.
if ( is_null( $item['id'] ) ) {
$this->set_item( $order, $line_type, $item, 'create' );
} elseif ( $this->item_is_null( $item ) ) {
} elseif ( $this->item_is_null( $item ) || 0 === $item['quantity'] ) {
// Delete item.
wc_delete_order_item( $item['id'] );
} else {

View File

@ -1,8 +1,8 @@
<?php
/**
* REST API Product Reviews controller
* REST API Product Reviews Controller.
*
* Handles requests to the /products/<product_id>/reviews endpoint.
* Handles requests to /products/<product_id>/reviews.
*
* @author WooThemes
* @category API
@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* REST API Products controller class.
* REST API Product Reviews Controller Class.
*
* @package WooCommerce/API
* @extends WC_REST_Controller
@ -47,6 +47,22 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
'review' => array(
'required' => true,
),
'name' => array(
'required' => true,
),
'email' => array(
'required' => true,
),
) ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
@ -59,8 +75,35 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_item' ),
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
'args' => array(
'force' => array(
'default' => false,
'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce' ),
),
),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'batch_items' ),
'permission_callback' => array( $this, 'batch_items_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
'schema' => array( $this, 'get_public_batch_schema' ),
) );
}
/**
@ -78,7 +121,7 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
}
/**
* Check if a given request has access to read a webhook develivery.
* Check if a given request has access to read a product review.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
@ -93,6 +136,61 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
return true;
}
/**
* Check if a given request has access to create a new product review.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function create_item_permissions_check( $request ) {
$post = get_post( (int) $request['product_id'] );
if ( $post && ! wc_rest_check_post_permissions( 'product', 'create', $post->ID ) ) {
return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you cannot create new resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to update a product review.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$post = get_post( (int) $request['product_id'] );
if ( $post && ! wc_rest_check_post_permissions( 'product', 'edit', $post->ID ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to delete a product review.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function delete_item_permissions_check( $request ) {
$post = get_post( (int) $request['product_id'] );
if ( $post && ! wc_rest_check_post_permissions( 'product', 'delete', $post->ID ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot delete product reviews.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to batch manage product reviews.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function batch_items_permissions_check( $request ) {
if ( ! wc_rest_check_post_permissions( 'product', 'batch' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot batch manipulate product reviews.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Get all reviews from a product.
*
@ -100,13 +198,13 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
* @return array
*/
public function get_items( $request ) {
$product = get_post( (int) $request['product_id'] );
$product_id = (int) $request['product_id'];
if ( empty( $product->post_type ) || 'product' !== $product->post_type ) {
if ( 'product' !== get_post_type( $product_id ) ) {
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$reviews = get_approved_comments( $product->ID );
$reviews = get_approved_comments( $product_id );
$data = array();
foreach ( $reviews as $review_data ) {
$review = $this->prepare_item_for_response( $review_data, $request );
@ -124,16 +222,16 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
* @return WP_Error|WP_REST_Response
*/
public function get_item( $request ) {
$id = (int) $request['id'];
$product = get_post( (int) $request['product_id'] );
$id = (int) $request['id'];
$product_id = (int) $request['product_id'];
if ( empty( $product->post_type ) || 'product' !== $product->post_type ) {
if ( 'product' !== get_post_type( $product_id ) ) {
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$review = get_comment( $id );
if ( empty( $id ) || empty( $review ) || intval( $review->comment_post_ID ) !== intval( $product->ID ) ) {
if ( empty( $id ) || empty( $review ) || intval( $review->comment_post_ID ) !== $product_id ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
@ -143,6 +241,197 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
return $response;
}
/**
* Create a product review.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|WP_REST_Response
*/
public function create_item( $request ) {
$product_id = (int) $request['product_id'];
if ( 'product' !== get_post_type( $product_id ) ) {
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$prepared_review = $this->prepare_item_for_database( $request );
/**
* Filter a product review (comment) before it is inserted via the REST API.
*
* Allows modification of the comment right before it is inserted via `wp_insert_comment`.
*
* @param array $prepared_review The prepared comment data for `wp_insert_comment`.
* @param WP_REST_Request $request Request used to insert the comment.
*/
$prepared_review = apply_filters( 'rest_pre_insert_product_review', $prepared_review, $request );
$product_review_id = wp_insert_comment( $prepared_review );
if ( ! $product_review_id ) {
return new WP_Error( 'rest_product_review_failed_create', __( 'Creating product review failed.' ), array( 'status' => 500 ) );
}
update_comment_meta( $product_review_id, 'rating', ( ! empty( $request['rating'] ) ? $request['rating'] : '0' ) );
$product_review = get_comment( $product_review_id );
$this->update_additional_fields_for_object( $product_review, $request );
/**
* Fires after a single item is created or updated via the REST API.
*
* @param WP_Comment $product_review Inserted object.
* @param WP_REST_Request $request Request object.
* @param boolean $creating True when creating item, false when updating.
*/
do_action( "woocommerce_rest_insert_product_review", $product_review, $request, true );
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $product_review, $request );
$response = rest_ensure_response( $response );
$response->set_status( 201 );
$base = str_replace( '(?P<product_id>[\d]+)', $product_id, $this->rest_base );
$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $product_review_id ) ) );
return $response;
}
/**
* Update a single product review.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|WP_REST_Response
*/
public function update_item( $request ) {
$product_review_id = (int) $request['id'];
$product_id = (int) $request['product_id'];
if ( 'product' !== get_post_type( $product_id ) ) {
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$review = get_comment( $product_review_id );
if ( empty( $product_review_id ) || empty( $review ) || intval( $review->comment_post_ID ) !== $product_id ) {
return new WP_Error( 'woocommerce_rest_product_review_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$prepared_review = $this->prepare_item_for_database( $request );
$updated = wp_update_comment( $prepared_review );
if ( 0 === $updated ) {
return new WP_Error( 'rest_product_review_failed_edit', __( 'Updating product review failed.' ), array( 'status' => 500 ) );
}
if ( ! empty( $request['rating'] ) ) {
update_comment_meta( $product_review_id, 'rating', $request['rating'] );
}
$product_review = get_comment( $product_review_id );
$this->update_additional_fields_for_object( $product_review, $request );
/**
* Fires after a single item is created or updated via the REST API.
*
* @param WP_Comment $comment Inserted object.
* @param WP_REST_Request $request Request object.
* @param boolean $creating True when creating item, false when updating.
*/
do_action( "woocommerce_rest_insert_product_review", $product_review, $request, true );
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $product_review, $request );
return rest_ensure_response( $response );
}
/**
* Delete a product review.
*
* @param WP_REST_Request $request Full details about the request
* @return WP_Error|boolean
*/
public function delete_item( $request ) {
$product_review_id = is_array( $request['id'] ) ? $request['id']['id'] : $request['id'];
$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
$product_review = get_comment( $product_review_id );
if ( empty( $product_review_id ) || empty( $product_review->comment_ID ) || empty( $product_review->comment_post_ID ) ) {
return new WP_Error( 'woocommerce_rest_product_review_invalid_id', __( 'Invalid product review ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
/**
* Filter whether a product review is trashable.
*
* Return false to disable trash support for the product review.
*
* @param boolean $supports_trash Whether the object supports trashing.
* @param WP_Post $product_review The object being considered for trashing support.
*/
$supports_trash = apply_filters( 'rest_product_review_trashable', ( EMPTY_TRASH_DAYS > 0 ), $product_review );
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $product_review, $request );
if ( $force ) {
$result = wp_delete_comment( $product_review_id, true );
} else {
if ( ! $supports_trash ) {
return new WP_Error( 'rest_trash_not_supported', __( 'The product review does not support trashing.' ), array( 'status' => 501 ) );
}
if ( 'trash' === $product_review->comment_approved ) {
return new WP_Error( 'rest_already_trashed', __( 'The comment has already been trashed.' ), array( 'status' => 410 ) );
}
$result = wp_trash_comment( $product_review->comment_ID );
}
if ( ! $result ) {
return new WP_Error( 'rest_cannot_delete', __( 'The product review cannot be deleted.' ), array( 'status' => 500 ) );
}
/**
* Fires after a product review is deleted via the REST API.
*
* @param object $product_review The deleted item.
* @param WP_REST_Response $response The response data.
* @param WP_REST_Request $request The request sent to the API.
*/
do_action( 'rest_delete_product_review', $product_review, $response, $request );
return $response;
}
/**
* Bulk create, update and delete items.
*
* @since 2.7.0
* @param WP_REST_Request $request Full details about the request.
* @return array Of WP_Error or WP_REST_Response.
*/
public function batch_items( $request ) {
$items = array_filter( $request->get_params() );
$params = $request->get_url_params();
$product_id = $params['product_id'];
$body_params = array();
foreach ( array( 'update', 'create', 'delete' ) as $batch_type ) {
if ( ! empty( $items[ $batch_type ] ) ) {
$injected_items = array();
foreach ( $items[ $batch_type ] as $item ) {
$injected_items[] = array_merge( array( 'product_id' => $product_id ), $item );
}
$body_params[ $batch_type ] = $injected_items;
}
}
$request = new WP_REST_Request( $request->get_method() );
$request->set_body_params( $body_params );
return parent::batch_items( $request );
}
/**
* Prepare a single product review output for response.
*
@ -180,6 +469,38 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
return apply_filters( 'woocommerce_rest_prepare_product_review', $response, $review, $request );
}
/**
* Prepare a single product review to be inserted into the database.
*
* @param WP_REST_Request $request Request object.
* @return array|WP_Error $prepared_review
*/
protected function prepare_item_for_database( $request ) {
$prepared_review = array( 'comment_approved' => 1, 'comment_type' => 'review' );
if ( isset( $request['id'] ) ) {
$prepared_review['comment_ID'] = (int) $request['id'];
}
if ( isset( $request['review'] ) ) {
$prepared_review['comment_content'] = $request['review'];
}
if ( isset( $request['product_id'] ) ) {
$prepared_review['comment_post_ID'] = (int) $request['product_id'];
}
if ( isset( $request['name'] ) ) {
$prepared_review['comment_author'] = $request['name'];
}
if ( isset( $request['email'] ) ) {
$prepared_review['comment_author_email'] = $request['email'];
}
return apply_filters( 'rest_preprocess_product_review', $prepared_review, $request );
}
/**
* Prepare links for the request.
*
@ -219,37 +540,38 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'review' => array(
'description' => __( 'The content of the review.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'date_created' => array(
'description' => __( "The date the review was created, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'rating' => array(
'description' => __( 'Review rating (0 to 5).', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'readonly' => true,
'context' => array( 'view', 'edit' ),
),
'name' => array(
'description' => __( 'Reviewer name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
'context' => array( 'view', 'edit' ),
),
'email' => array(
'description' => __( 'Reviewer email.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
'context' => array( 'view', 'edit' ),
),
'verified' => array(
'description' => __( 'Shows if the reviewer bought the product or not.', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
),

View File

@ -0,0 +1,179 @@
<?php
/**
* REST API Shipping Zone Locations controller
*
* Handles requests to the /shipping/zones/<id>/locations endpoint.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.7.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* REST API Shipping Zone Locations class.
*
* @package WooCommerce/API
* @extends WC_REST_Shipping_Zones_Controller_Base
*/
class WC_REST_Shipping_Zone_Locations_Controller extends WC_REST_Shipping_Zones_Controller_Base {
/**
* Register the routes for Shipping Zone Locations.
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d-]+)/locations', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_items' ),
'permission_callback' => array( $this, 'update_items_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
}
/**
* Get all Shipping Zone Locations.
*
* @param WP_REST_Request $request
* @return WP_REST_Response|WP_Error
*/
public function get_items( $request ) {
$zone = $this->get_zone( $request['id'] );
if ( is_wp_error( $zone ) ) {
return $zone;
}
$locations = $zone->get_zone_locations();
$data = array();
foreach ( $locations as $location_obj ) {
$location = $this->prepare_item_for_response( $location_obj, $request );
$location = $this->prepare_response_for_collection( $location );
$data[] = $location;
}
return rest_ensure_response( $data );
}
/**
* Update all Shipping Zone Locations.
*
* @param WP_REST_Request $request
* @return WP_REST_Response|WP_Error
*/
public function update_items( $request ) {
$zone = $this->get_zone( $request['id'] );
if ( is_wp_error( $zone ) ) {
return $zone;
}
$raw_locations = $request->get_json_params();
$locations = array();
foreach ( (array) $raw_locations as $raw_location ) {
if ( empty( $raw_location['code'] ) || empty( $raw_location['type'] ) ) {
continue;
}
$locations[] = $raw_location;
}
$zone->set_locations( $locations );
$zone->save();
return $this->get_items( $request );
}
/**
* Prepare the Shipping Zone Location for the REST response.
*
* @param array $item Shipping Zone Location.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response
*/
public function prepare_item_for_response( $item, $request ) {
$context = empty( $request['context'] ) ? 'view' : $request['context'];
$data = $this->add_additional_fields_to_object( $item, $request );
$data = $this->filter_response_by_context( $data, $context );
// Wrap the data in a response object.
$response = rest_ensure_response( $data );
$response->add_links( $this->prepare_links( $request['id'] ) );
return $response;
}
/**
* Prepare links for the request.
*
* @param int $zone_id Given Shipping Zone ID.
* @return array Links for the given Shipping Zone Location.
*/
protected function prepare_links( $zone_id ) {
$base = '/' . $this->namespace . '/' . $this->rest_base . '/' . $zone_id;
$links = array(
'collection' => array(
'href' => rest_url( $base . '/locations' ),
),
'describes' => array(
'href' => rest_url( $base ),
),
);
return $links;
}
/**
* Get the Shipping Zone Locations schema, conforming to JSON Schema
*
* @return array
*/
public function get_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'shipping_zone_location',
'type' => 'object',
'properties' => array(
'code' => array(
'description' => __( 'Shipping zone location code.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'required' => true,
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'type' => array(
'description' => __( 'Shipping zone location type.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'required' => true,
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
'enum' => array(
'postcode',
'state',
'country',
'continent',
),
),
),
);
return $this->add_additional_fields_schema( $schema );
}
}

View File

@ -0,0 +1,217 @@
<?php
/**
* REST API Shipping Zone Methods controller
*
* Handles requests to the /shipping/zones/<id>/methods endpoint.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.7.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* REST API Shipping Zone Methods class.
*
* @package WooCommerce/API
* @extends WC_REST_Shipping_Zones_Controller_Base
*/
class WC_REST_Shipping_Zone_Methods_Controller extends WC_REST_Shipping_Zones_Controller_Base {
/**
* Register the routes for Shipping Zone Methods.
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<zone_id>[\d-]+)/methods', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<zone_id>[\d-]+)/methods/(?P<instance_id>[\d-]+)', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
}
/**
* Get a single Shipping Zone Method.
*
* @param WP_REST_Request $request
* @return WP_REST_Response|WP_Error
*/
public function get_item( $request ) {
$zone = $this->get_zone( $request['zone_id'] );
if ( is_wp_error( $zone ) ) {
return $zone;
}
$instance_id = (int) $request['instance_id'];
$methods = $zone->get_shipping_methods();
$method = false;
foreach ( $methods as $method_obj ) {
if ( $instance_id === $method_obj->instance_id ) {
$method = $method_obj;
break;
}
}
if ( false === $method ) {
return new WP_Error( 'woocommerce_rest_shipping_zone_method_invalid', __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) );
}
$data = $this->prepare_item_for_response( $method, $request );
return rest_ensure_response( $data );
}
/**
* Get all Shipping Zone Methods.
*
* @param WP_REST_Request $request
* @return WP_REST_Response|WP_Error
*/
public function get_items( $request ) {
$zone = $this->get_zone( $request['zone_id'] );
if ( is_wp_error( $zone ) ) {
return $zone;
}
$methods = $zone->get_shipping_methods();
$data = array();
foreach ( $methods as $method_obj ) {
$method = $this->prepare_item_for_response( $method_obj, $request );
$data[] = $method;
}
return rest_ensure_response( $data );
}
/**
* Prepare the Shipping Zone Method for the REST response.
*
* @param array $item Shipping Zone Method.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response
*/
public function prepare_item_for_response( $item, $request ) {
$method = array(
'instance_id' => $item->instance_id,
'title' => $item->instance_settings['title'],
'order' => $item->method_order,
'enabled' => ( 'yes' === $item->enabled ),
'method_id' => $item->id,
'method_title' => $item->method_title,
'method_description' => $item->method_description,
);
$context = empty( $request['context'] ) ? 'view' : $request['context'];
$data = $this->add_additional_fields_to_object( $method, $request );
$data = $this->filter_response_by_context( $data, $context );
// Wrap the data in a response object.
$response = rest_ensure_response( $data );
$response->add_links( $this->prepare_links( $request['zone_id'], $item->instance_id ) );
$response = $this->prepare_response_for_collection( $response );
return $response;
}
/**
* Prepare links for the request.
*
* @param int $zone_id Given Shipping Zone ID.
* @param int $instance_id Given Shipping Zone Method Instance ID.
* @return array Links for the given Shipping Zone Method.
*/
protected function prepare_links( $zone_id, $instance_id ) {
$base = '/' . $this->namespace . '/' . $this->rest_base . '/' . $zone_id;
$links = array(
'self' => array(
'href' => rest_url( $base . '/methods/' . $instance_id ),
),
'collection' => array(
'href' => rest_url( $base . '/methods' ),
),
'describes' => array(
'href' => rest_url( $base ),
),
);
return $links;
}
/**
* Get the Shipping Zone Methods schema, conforming to JSON Schema
*
* @return array
*/
public function get_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'shipping_zone_method',
'type' => 'object',
'properties' => array(
'instance_id' => array(
'description' => __( 'Shipping method instance ID.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
),
'title' => array(
'description' => __( 'Shipping method customer facing title.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
),
'order' => array(
'description' => __( 'Shipping method sort order.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'required' => false,
'arg_options' => array(
'sanitize_callback' => 'absint',
),
),
'enabled' => array(
'description' => __( 'Shipping method enabled status.', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
'required' => false,
),
'method_id' => array(
'description' => __( 'Shipping method ID.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
),
'method_title' => array(
'description' => __( 'Shipping method title.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
),
'method_description' => array(
'description' => __( 'Shipping method description.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
),
),
);
return $this->add_additional_fields_schema( $schema );
}
}

View File

@ -0,0 +1,253 @@
<?php
/**
* REST API Shipping Zones controller
*
* Handles requests to the /shipping/zones endpoint.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.7.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* REST API Shipping Zones class.
*
* @package WooCommerce/API
* @extends WC_REST_Shipping_Zones_Controller_Base
*/
class WC_REST_Shipping_Zones_Controller extends WC_REST_Shipping_Zones_Controller_Base {
/**
* Register the routes for Shipping Zones.
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d-]+)', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_items_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
}
/**
* Get a single Shipping Zone.
*
* @param WP_REST_Request $request
* @return WP_REST_Response
*/
public function get_item( $request ) {
$zone = $this->get_zone( $request->get_param( 'id' ) );
if ( is_wp_error( $zone ) ) {
return $zone;
}
$data = $zone->get_data();
$data = $this->prepare_item_for_response( $data, $request );
$data = $this->prepare_response_for_collection( $data );
return rest_ensure_response( $data );
}
/**
* Get all Shipping Zones.
*
* @param WP_REST_Request $request
* @return WP_REST_Response
*/
public function get_items( $request ) {
$rest_of_the_world = WC_Shipping_Zones::get_zone_by( 'zone_id', 0 );
$zones = WC_Shipping_Zones::get_zones();
array_unshift( $zones, $rest_of_the_world->get_data() );
$data = array();
foreach ( $zones as $zone_obj ) {
$zone = $this->prepare_item_for_response( $zone_obj, $request );
$zone = $this->prepare_response_for_collection( $zone );
$data[] = $zone;
}
return rest_ensure_response( $data );
}
/**
* Create a single Shipping Zone.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Request|WP_Error
*/
public function create_item( $request ) {
$zone = new WC_Shipping_Zone( null );
if ( ! is_null( $request->get_param( 'name' ) ) ) {
$zone->set_zone_name( $request->get_param( 'name' ) );
}
if ( ! is_null( $request->get_param( 'order' ) ) ) {
$zone->set_zone_order( $request->get_param( 'order' ) );
}
$zone->create();
if ( $zone->get_id() !== 0 ) {
$request->set_param( 'id', $zone->get_id() );
$response = $this->get_item( $request );
$response->set_status( 201 );
$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $zone->get_id() ) ) );
return $response;
} else {
return new WP_Error( 'woocommerce_rest_shipping_zone_not_created', __( "Resource cannot be created. Check to make sure 'order' and 'name' are present.", 'woocommerce' ), array( 'status' => 500 ) );
}
}
/**
* Update a single Shipping Zone.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Request|WP_Error
*/
public function update_item( $request ) {
$zone = $this->get_zone( $request->get_param( 'id' ) );
if ( is_wp_error( $zone ) ) {
return $zone;
}
$zone_changed = false;
if ( ! is_null( $request->get_param( 'name' ) ) ) {
$zone->set_zone_name( $request->get_param( 'name' ) );
$zone_changed = true;
}
if ( ! is_null( $request->get_param( 'order' ) ) ) {
$zone->set_zone_order( $request->get_param( 'order' ) );
$zone_changed = true;
}
if ( $zone_changed ) {
$zone->save();
}
return $this->get_item( $request );
}
/**
* Prepare the Shipping Zone for the REST response.
*
* @param array $item Shipping Zone.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response
*/
public function prepare_item_for_response( $item, $request ) {
$data = array(
'id' => (int) $item['zone_id'],
'name' => $item['zone_name'],
'order' => (int) $item['zone_order'],
);
$context = empty( $request['context'] ) ? 'view' : $request['context'];
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );
// Wrap the data in a response object.
$response = rest_ensure_response( $data );
$response->add_links( $this->prepare_links( $data['id'] ) );
return $response;
}
/**
* Prepare links for the request.
*
* @param int $zone_id Given Shipping Zone ID.
* @return array Links for the given Shipping Zone.
*/
protected function prepare_links( $zone_id ) {
$base = '/' . $this->namespace . '/' . $this->rest_base;
$links = array(
'self' => array(
'href' => rest_url( trailingslashit( $base ) . $zone_id ),
),
'collection' => array(
'href' => rest_url( $base ),
),
'describedby' => array(
'href' => rest_url( trailingslashit( $base ) . $zone_id . '/locations' ),
),
);
return $links;
}
/**
* Get the Shipping Zones schema, conforming to JSON Schema
*
* @return array
*/
public function get_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'shipping_zone',
'type' => 'object',
'properties' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'name' => array(
'description' => __( 'Shipping zone name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'required' => true,
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'order' => array(
'description' => __( 'Shipping zone order.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'required' => false,
'arg_options' => array(
'sanitize_callback' => 'absint',
),
),
),
);
return $this->add_additional_fields_schema( $schema );
}
}

View File

@ -0,0 +1,821 @@
<?php
/**
* REST API WC System Status controller
*
* Handles requests to the /system_status endpoint.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.7.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* @package WooCommerce/API
* @extends WC_REST_Controller
*/
class WC_REST_System_Status_Controller extends WC_REST_Controller {
/**
* Endpoint namespace.
*
* @var string
*/
protected $namespace = 'wc/v1';
/**
* Route base.
*
* @var string
*/
protected $rest_base = 'system_status';
/**
* Register the routes for coupons.
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
}
/**
* Check whether a given request has permission to view system status.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Get a system status info, by section.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|WP_REST_Response
*/
public function get_items( $request ) {
$schema = $this->get_item_schema();
$mappings = $this->get_item_mappings();
$response = array();
foreach ( $mappings as $section => $values ) {
settype( $values, $schema['properties'][ $section ]['type'] );
foreach ( $values as $key => $value ) {
if ( isset( $schema['properties'][ $section ]['properties'][ $key ]['type'] ) ) {
settype( $values[ $key ], $schema['properties'][ $section ]['properties'][ $key ]['type'] );
}
}
$response[ $section ] = $values;
}
return rest_ensure_response( $response );
}
/**
* Get the system status schema, conforming to JSON Schema.
*
* @return array
*/
public function get_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'system_status',
'type' => 'object',
'properties' => array(
'environment' => array(
'description' => __( 'Environment', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
'properties' => array(
'home_url' => array(
'description' => __( 'Home URL', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
'site_url' => array(
'description' => __( 'Site URL', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
'wc_version' => array(
'description' => __( 'WooCommerce Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'log_directory' => array(
'description' => __( 'Log Directory', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'log_directory_writable' => array(
'description' => __( 'Is Log Directory Writable?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'wp_version' => array(
'description' => __( 'WordPress Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'wp_multisite' => array(
'description' => __( 'Is WordPress Multisite?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'wp_memory_limit' => array(
'description' => __( 'WordPress Memory Limit', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'wp_debug_mode' => array(
'description' => __( 'Is WordPress Debug Mode Active?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'wp_cron' => array(
'description' => __( 'Are WordPress Cron Jobs Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'language' => array(
'description' => __( 'WordPress Language', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'server_info' => array(
'description' => __( 'Server Info', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'php_version' => array(
'description' => __( 'PHP Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'php_post_max_size' => array(
'description' => __( 'PHP Post Max Size', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'php_max_execution_time' => array(
'description' => __( 'PHP Max Execution Time', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'php_max_input_vars' => array(
'description' => __( 'PHP Max Input Vars', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'curl_version' => array(
'description' => __( 'cURL Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'suhosin_installed' => array(
'description' => __( 'Is SUHOSIN Installed?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'max_upload_size' => array(
'description' => __( 'Max Upload Size', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'mysql_version' => array(
'description' => __( 'MySQL Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'default_timezone' => array(
'description' => __( 'Default Timezone', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'fsockopen_or_curl_enabled' => array(
'description' => __( 'Is fsockopen/cURL Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'soapclient_enabled' => array(
'description' => __( 'Is SoapClient Class Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'domdocument_enabled' => array(
'description' => __( 'Is DomDocument Class Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'gzip_enabled' => array(
'description' => __( 'Is GZip Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'mbstring_enabled' => array(
'description' => __( 'Is mbstring Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'remote_post_successful' => array(
'description' => __( 'Remote POST Successful?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'remote_post_response' => array(
'description' => __( 'Remote POST Response', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'remote_get_successful' => array(
'description' => __( 'Remote GET Successful?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'remote_get_response' => array(
'description' => __( 'Remote GET Response', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
),
),
'database' => array(
'description' => __( 'Database', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
'properties' => array(
'wc_database_version' => array(
'description' => __( 'WC Database Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'database_prefix' => array(
'description' => __( 'Database Prefix', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'maxmind_geoip_database' => array(
'description' => __( 'MaxMind GeoIP Database', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'database_tables' => array(
'description' => __( 'Database Tables', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
),
)
),
'active_plugins' => array(
'description' => __( 'Active Plugins', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
),
'theme' => array(
'description' => __( 'Theme', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
'properties' => array(
'name' => array(
'description' => __( 'Theme Name', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'version' => array(
'description' => __( 'Theme Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'version_latest' => array(
'description' => __( 'Latest Version Of Theme', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'author_url' => array(
'description' => __( 'Theme Author URL', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
'is_child_theme' => array(
'description' => __( 'Is this theme a child theme?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'has_woocommerce_support' => array(
'description' => __( 'Does the theme declare WooCommerce support?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'has_woocommerce_file' => array(
'description' => __( 'Does the theme have a woocommerce.php file?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'has_outdated_templates' => array(
'description' => __( 'Does this theme have outdated templates?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'overrides' => array(
'description' => __( 'Template Overrides', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
),
'parent_name' => array(
'description' => __( 'Parent Theme Name', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'parent_version' => array(
'description' => __( 'Parent Theme Version', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'parent_author_url' => array(
'description' => __( 'Parent Theme Author URL', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
)
),
'settings' => array(
'description' => __( 'Settings', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
'properties' => array(
'api_enabled' => array(
'description' => __( 'REST API Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'force_ssl' => array(
'description' => __( 'SSL Forced?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'currency' => array(
'description' => __( 'Currency', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'currency_symbol' => array(
'description' => __( 'Currency Symbol', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'currency_position' => array(
'description' => __( 'Currency Position', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'thousand_separator' => array(
'description' => __( 'Thousand Separator', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'decimal_separator' => array(
'description' => __( 'Decimal Separator', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'number_of_decimals' => array(
'description' => __( 'Number of Decimals', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'geolocation_enabled' => array(
'description' => __( 'Geolocation Enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'taxonomies' => array(
'description' => __( 'Taxonomy Terms for Product/Order Statuses', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
),
)
),
'pages' => array(
'description' => __( 'WooCommerce Pages', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
),
)
);
return $this->add_additional_fields_schema( $schema );
}
/**
* Return an array of sections and the data associated with each.
*
* @return array
*/
public function get_item_mappings() {
return array(
'environment' => $this->get_environment_info(),
'database' => $this->get_database_info(),
'active_plugins' => $this->get_active_plugins(),
'theme' => $this->get_theme_info(),
'settings' => $this->get_settings(),
'pages' => $this->get_pages(),
);
}
/**
* Get array of environment information. Includes thing like software
* versions, and various server settings.
*
* @return array
*/
public function get_environment_info() {
global $wpdb;
// Figure out cURL version, if installed.
$curl_version = '';
if ( function_exists( 'curl_version' ) ) {
$curl_version = curl_version();
$curl_version = $curl_version['version'] . ', ' . $curl_version['ssl_version'];
}
// WP memory limit
$wp_memory_limit = wc_let_to_num( WP_MEMORY_LIMIT );
if ( function_exists( 'memory_get_usage' ) ) {
$wp_memory_limit = max( $wp_memory_limit, wc_let_to_num( @ini_get( 'memory_limit' ) ) );
}
// Test POST requests
$post_response = wp_safe_remote_post( 'https://www.paypal.com/cgi-bin/webscr', array(
'timeout' => 60,
'user-agent' => 'WooCommerce/' . WC()->version,
'httpversion' => '1.1',
'body' => array(
'cmd' => '_notify-validate'
)
) );
$post_response_successful = false;
if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) {
$post_response_successful = true;
}
// Test GET requests
$get_response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) );
$get_response_successful = false;
if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) {
$get_response_successful = true;
}
// Return all environment info. Described by JSON Schema.
return array(
'home_url' => get_option( 'home' ),
'site_url' => get_option( 'siteurl' ),
'version' => WC()->version,
'log_directory' => WC_LOG_DIR,
'log_directory_writable' => ( @fopen( WC_LOG_DIR . 'test-log.log', 'a' ) ? true : false ),
'wp_version' => get_bloginfo('version'),
'wp_multisite' => is_multisite(),
'wp_memory_limit' => $wp_memory_limit,
'wp_debug_mode' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
'wp_cron' => ! ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ),
'language' => get_locale(),
'server_info' => $_SERVER['SERVER_SOFTWARE'],
'php_version' => phpversion(),
'php_post_max_size' => wc_let_to_num( ini_get( 'post_max_size' ) ),
'php_max_execution_time' => ini_get( 'max_execution_time' ),
'php_max_input_vars' => ini_get( 'max_input_vars' ),
'curl_version' => $curl_version,
'suhosin_installed' => extension_loaded( 'suhosin' ),
'max_upload_size' => wp_max_upload_size(),
'mysql_version' => ( ! empty( $wpdb->is_mysql ) ? $wpdb->db_version() : '' ),
'default_timezone' => date_default_timezone_get(),
'fsockopen_or_curl_enabled' => ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ),
'soapclient_enabled' => class_exists( 'SoapClient' ),
'domdocument_enabled' => class_exists( 'DOMDocument' ),
'gzip_enabled' => is_callable( 'gzopen' ),
'mbstring_enabled' => extension_loaded( 'mbstring' ),
'remote_post_successful' => $post_response_successful,
'remote_post_response' => ( is_wp_error( $post_response ) ? $post_response->get_error_message() : $post_response['response']['code'] ),
'remote_get_successful' => $get_response_successful,
'remote_get_response' => ( is_wp_error( $get_response ) ? $get_response->get_error_message() : $get_response['response']['code'] ),
);
}
/**
* Get array of database information. Version, prefix, and table existence.
*
* @return array
*/
public function get_database_info() {
global $wpdb;
// WC Core tables to check existence of
$tables = array(
'woocommerce_sessions',
'woocommerce_api_keys',
'woocommerce_attribute_taxonomies',
'woocommerce_downloadable_product_permissions',
'woocommerce_order_items',
'woocommerce_order_itemmeta',
'woocommerce_tax_rates',
'woocommerce_tax_rate_locations',
'woocommerce_shipping_zones',
'woocommerce_shipping_zone_locations',
'woocommerce_shipping_zone_methods',
'woocommerce_payment_tokens',
'woocommerce_payment_tokenmeta',
);
if ( get_option( 'db_version' ) < 34370 ) {
$tables[] = 'woocommerce_termmeta';
}
$table_exists = array();
foreach ( $tables as $table ) {
$table_exists[ $table ] = ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s;", $wpdb->prefix . $table ) ) === $wpdb->prefix . $table );
}
// Return all database info. Described by JSON Schema.
return array(
'wc_database_version' => get_option( 'woocommerce_db_version' ),
'database_prefix' => $wpdb->prefix,
'maxmind_geoip_database' => WC_Geolocation::get_local_database_path(),
'database_tables' => $table_exists,
);
}
/**
* Get a list of plugins active on the site.
*
* @return array
*/
public function get_active_plugins() {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
// Get both site plugins and network plugins
$active_plugins = (array) get_option( 'active_plugins', array() );
if ( is_multisite() ) {
$network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
$active_plugins = array_merge( $active_plugins, $network_activated_plugins );
}
$active_plugins_data = array();
foreach ( $active_plugins as $plugin ) {
$data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
$dirname = dirname( $plugin );
$theme_version_latest = '';
if ( strstr( $data['PluginURI'], 'woothemes.com' ) ) {
if ( false === ( $version_data = get_transient( md5( $plugin ) . '_version_data' ) ) ) {
$changelog = wp_safe_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $dirname . '/changelog.txt' );
$cl_lines = explode( "\n", wp_remote_retrieve_body( $changelog ) );
if ( ! empty( $cl_lines ) ) {
foreach ( $cl_lines as $line_num => $cl_line ) {
if ( preg_match( '/^[0-9]/', $cl_line ) ) {
$date = str_replace( '.' , '-' , trim( substr( $cl_line , 0 , strpos( $cl_line , '-' ) ) ) );
$version = preg_replace( '~[^0-9,.]~' , '' ,stristr( $cl_line , "version" ) );
$update = trim( str_replace( "*" , "" , $cl_lines[ $line_num + 1 ] ) );
$version_data = array( 'date' => $date , 'version' => $version , 'update' => $update , 'changelog' => $changelog );
set_transient( md5( $plugin ) . '_version_data', $version_data, DAY_IN_SECONDS );
break;
}
}
}
}
$theme_version_latest = $version_data['version'];
} else {
include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
$slug = explode( '/', $plugin );
$slug = explode( '.', end( $slug ) );
$slug = $slug[0];
$api = plugins_api( 'plugin_information', array(
'slug' => $slug,
'fields' => array(
'sections' => false,
'tags' => false,
)
) );
if ( is_object( $api ) && ! is_wp_error( $api ) ) {
$theme_version_latest = $api->version;
}
}
// convert plugin data to json response format.
$active_plugins_data[] = array(
'plugin' => $plugin,
'name' => $data['Name'],
'version' => $data['Version'],
'version_latest' => $theme_version_latest,
'url' => $data['PluginURI'],
'author_name' => $data['AuthorName'],
'author_url' => esc_url_raw( $data['AuthorURI'] ),
'network_activated' => $data['Network'],
);
}
return $active_plugins_data;
}
/**
* Get info on the current active theme, info on parent theme (if presnet)
* and a list of template overrides.
*
* @return array
*/
public function get_theme_info() {
$active_theme = wp_get_theme();
// Get parent theme info if this theme is a child theme, otherwise
// pass empty info in the response.
if ( is_child_theme() ) {
$parent_theme = wp_get_theme( $active_theme->Template );
$parent_theme_info = array(
'parent_name' => $parent_theme->Name,
'parent_version' => $parent_theme->Version,
'parent_version_latest' => WC_Admin_Status::get_latest_theme_version( $parent_theme ),
'parent_author_url' => $parent_theme->{'Author URI'},
);
} else {
$parent_theme_info = array( 'parent_name' => '', 'parent_version' => '', 'parent_version_latest' => '', 'parent_author_url' => '' );
}
/**
* Scan the theme directory for all WC templates to see if our theme
* overrides any of them.
*/
$override_files = array();
$outdated_templates = false;
$scan_files = WC_Admin_Status::scan_template_files( WC()->plugin_path() . '/templates/' );
foreach ( $scan_files as $file ) {
if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/' . $file;
} elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/woocommerce/' . $file;
} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
$theme_file = get_template_directory() . '/' . $file;
} elseif ( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_template_directory() . '/woocommerce/' . $file;
} else {
$theme_file = false;
}
if ( ! empty( $theme_file ) ) {
$core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file );
$theme_version = WC_Admin_Status::get_file_version( $theme_file );
if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
if ( ! $outdated_templates ) {
$outdated_templates = true;
}
}
$override_files[] = array(
'file' => str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ),
'version' => $theme_version,
'core_version' => $core_version,
);
}
}
$active_theme_info = array(
'name' => $active_theme->Name,
'version' => $active_theme->Version,
'version_latest' => WC_Admin_Status::get_latest_theme_version( $active_theme ),
'author_url' => esc_url_raw( $active_theme->{'Author URI'} ),
'is_child_theme' => is_child_theme(),
'has_woocommerce_support' => ( current_theme_supports( 'woocommerce' ) || in_array( $active_theme->template, wc_get_core_supported_themes() ) ),
'has_woocommerce_file' => ( file_exists( get_stylesheet_directory() . '/woocommerce.php' ) || file_exists( get_template_directory() . '/woocommerce.php' ) ),
'has_outdated_templates' => $outdated_templates,
'overrides' => $override_files,
);
return array_merge( $active_theme_info, $parent_theme_info );
}
/**
* Get some setting values for the site that are useful for debugging
* purposes. For full settings access, use the settings api.
*
* @return array
*/
public function get_settings() {
// Get a list of terms used for product/order taxonomies
$term_response = array();
$terms = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
foreach ( $terms as $term ) {
$term_response[ $term->slug ] = strtolower( $term->name );
}
// Return array of useful settings for debugging.
return array(
'api_enabled' => 'yes' === get_option( 'woocommerce_api_enabled' ),
'force_ssl' => 'yes' === get_option( 'woocommerce_force_ssl_checkout' ),
'currency' => get_woocommerce_currency(),
'currency_symbol' => get_woocommerce_currency_symbol(),
'currency_position' => get_option( 'woocommerce_currency_pos' ),
'thousand_separator' => wc_get_price_thousand_separator(),
'decimal_separator' => wc_get_price_decimal_separator(),
'number_of_decimals' => wc_get_price_decimals(),
'geolocation_enabled' => in_array( get_option( 'woocommerce_default_customer_address' ), array( 'geolocation_ajax', 'geolocation' ) ),
'taxonomies' => $term_response,
);
}
/**
* Returns a mini-report on WC pages and if they are configured correctly:
* Present, visible, and including the correct shortcode.
*
* @return array
*/
public function get_pages() {
// WC pages to check against
$check_pages = array(
_x( 'Shop Base', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_shop_page_id',
'shortcode' => '',
),
_x( 'Cart', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_cart_page_id',
'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
),
_x( 'Checkout', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_checkout_page_id',
'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
),
_x( 'My Account', 'Page setting', 'woocommerce' ) => array(
'option' => 'woocommerce_myaccount_page_id',
'shortcode' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
),
);
$pages_output = array();
foreach ( $check_pages as $page_name => $values ) {
$errors = array();
$page_id = get_option( $values['option'] );
$page_set = $page_exists = $page_visible = false;
$shortcode_present = $shortcode_required = false;
// Page checks
if ( $page_id ) {
$page_set = true;
}
if ( get_post( $page_id ) ) {
$page_exists = true;
}
if ( 'publish' === get_post_status( $page_id ) ) {
$page_visible = true;
}
// Shortcode checks
if ( $values['shortcode'] && get_post( $page_id ) ) {
$shortcode_required = true;
$page = get_post( $page_id );
if ( strstr( $page->post_content, $values['shortcode'] ) ) {
$shortcode_present = true;
}
}
// Wrap up our findings into an output array
$pages_output[] = array(
'page_name' => $page_name,
'page_id' => $page_id,
'page_set' => $page_set,
'page_exists' => $page_exists,
'page_visible' => $page_visible,
'shortcode' => $values['shortcode'],
'shortcode_required' => $shortcode_required,
'shortcode_present' => $shortcode_present,
);
}
return $pages_output;
}
/**
* Get any query params needed.
*
* @return array
*/
public function get_collection_params() {
return array(
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
);
}
}

View File

@ -3243,7 +3243,10 @@ class WC_AJAX {
$method_id = $wpdb->get_var( $wpdb->prepare( "SELECT method_id FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE instance_id = %d", $instance_id ) );
if ( isset( $data['deleted'] ) ) {
$shipping_method = WC_Shipping_Zones::get_shipping_method( $instance_id );
$option_key = $shipping_method->get_instance_option_key();
if ( $wpdb->delete( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'instance_id' => $instance_id ) ) ) {
delete_option( $option_key );
do_action( 'woocommerce_shipping_zone_method_deleted', $instance_id, $method_id, $zone_id );
}
continue;

View File

@ -110,10 +110,8 @@ class WC_API extends WC_Legacy_API {
* @since 2.6.0
*/
private function rest_api_init() {
global $wp_version;
// REST API was included starting WordPress 4.4.
if ( version_compare( $wp_version, 4.4, '<' ) ) {
if ( ! class_exists( 'WP_REST_Server' ) ) {
return;
}
@ -143,9 +141,11 @@ class WC_API extends WC_Legacy_API {
// Abstract controllers.
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-posts-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-shipping-zones-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-terms-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-settings-api.php' );
// REST API controllers.
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-coupons-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-customer-downloads-controller.php' );
@ -165,10 +165,14 @@ class WC_API extends WC_Legacy_API {
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-reports-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-settings-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-settings-options-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zones-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zone-locations-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zone-methods-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-tax-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-taxes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-webhook-deliveries.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-webhooks-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-system-status-controller.php' );
}
/**
@ -198,10 +202,14 @@ class WC_API extends WC_Legacy_API {
'WC_REST_Reports_Controller',
'WC_REST_Settings_Controller',
'WC_REST_Settings_Options_Controller',
'WC_REST_Shipping_Zones_Controller',
'WC_REST_Shipping_Zone_Locations_Controller',
'WC_REST_Shipping_Zone_Methods_Controller',
'WC_REST_Tax_Classes_Controller',
'WC_REST_Taxes_Controller',
'WC_REST_Webhook_Deliveries_Controller',
'WC_REST_Webhooks_Controller',
'WC_REST_System_Status_Controller',
);
foreach ( $controllers as $controller ) {

View File

@ -74,7 +74,7 @@ class WC_Breadcrumb {
'is_tax'
);
if ( ( ! is_front_page() && ! ( is_post_type_archive() && get_option( 'page_on_front' ) == wc_get_page_id( 'shop' ) ) ) || is_paged() ) {
if ( ( ! is_front_page() && ! ( is_post_type_archive() && intval( get_option( 'page_on_front' ) ) === wc_get_page_id( 'shop' ) ) ) || is_paged() ) {
foreach ( $conditionals as $conditional ) {
if ( call_user_func( $conditional ) ) {
call_user_func( array( $this, 'add_crumbs_' . substr( $conditional, 3 ) ) );

View File

@ -211,11 +211,6 @@ class WC_Form_Handler {
$user->user_email = $account_email;
}
if ( ! empty( $pass1 ) && ! wp_check_password( $pass_cur, $current_user->user_pass, $current_user->ID ) ) {
wc_add_notice( __( 'Your current password is incorrect.', 'woocommerce' ), 'error' );
$save_pass = false;
}
if ( ! empty( $pass_cur ) && empty( $pass1 ) && empty( $pass2 ) ) {
wc_add_notice( __( 'Please fill out all password fields.', 'woocommerce' ), 'error' );
$save_pass = false;
@ -228,6 +223,9 @@ class WC_Form_Handler {
} elseif ( ( ! empty( $pass1 ) || ! empty( $pass2 ) ) && $pass1 !== $pass2 ) {
wc_add_notice( __( 'New passwords do not match.', 'woocommerce' ), 'error' );
$save_pass = false;
} elseif ( ! empty( $pass1 ) && ! wp_check_password( $pass_cur, $current_user->user_pass, $current_user->ID ) ) {
wc_add_notice( __( 'Your current password is incorrect.', 'woocommerce' ), 'error' );
$save_pass = false;
}
if ( $pass1 && $save_pass ) {
@ -873,9 +871,12 @@ class WC_Form_Handler {
if ( ! empty( $_POST['login'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-login' ) ) {
try {
$creds = array();
$username = trim( $_POST['username'] );
$creds = array(
'user_password' => $_POST['password'],
'remember' => isset( $_POST['rememberme'] ),
);
$username = trim( $_POST['username'] );
$validation_error = new WP_Error();
$validation_error = apply_filters( 'woocommerce_process_login_errors', $validation_error, $_POST['username'], $_POST['password'] );
@ -904,10 +905,17 @@ class WC_Form_Handler {
$creds['user_login'] = $username;
}
$creds['user_password'] = $_POST['password'];
$creds['remember'] = isset( $_POST['rememberme'] );
$secure_cookie = is_ssl() ? true : false;
$user = wp_signon( apply_filters( 'woocommerce_login_credentials', $creds ), $secure_cookie );
// On multisite, ensure user exists on current site, if not add them before allowing login.
if ( is_multisite() ) {
$user_data = get_user_by( 'login', $username );
if ( $user_data && ! is_user_member_of_blog( $user_data->ID, get_current_blog_id() ) ) {
add_user_to_blog( get_current_blog_id(), $user_data->ID, 'customer' );
}
}
// Perform the login
$user = wp_signon( apply_filters( 'woocommerce_login_credentials', $creds ), is_ssl() );
if ( is_wp_error( $user ) ) {
$message = $user->get_error_message();
@ -987,7 +995,7 @@ class WC_Form_Handler {
do_action( 'woocommerce_customer_reset_password', $user );
wp_redirect( add_query_arg( 'reset', 'true', remove_query_arg( array( 'key', 'login', 'reset-link-sent' ) ) ) );
wp_redirect( add_query_arg( 'password-reset', 'true', wc_get_page_permalink( 'myaccount' ) ) );
exit;
}
}

View File

@ -72,6 +72,9 @@ class WC_Install {
'wc_update_260_refunds',
'wc_update_260_db_version',
),
'2.7.0' => array(
'wc_update_270_webhooks',
),
);
/** @var object Background update class */

View File

@ -124,4 +124,29 @@ class WC_Logger {
return $result;
}
/**
* Remove/delete the chosen file.
*
* @param string $handle
*
* @return bool
*/
public function remove( $handle ) {
$removed = false;
$file = wc_get_log_file_path( $handle );
if ( is_file( $file ) && is_writable( $file ) ) {
// Close first to be certain no processes keep it alive after it is unlinked.
$this->close( $handle );
$removed = unlink( $file );
} elseif ( is_file( trailingslashit( WC_LOG_DIR ) . $handle . '.log' ) && is_writable( trailingslashit( WC_LOG_DIR ) . $handle . '.log' ) ) {
$this->close( $handle );
$removed = unlink( trailingslashit( WC_LOG_DIR ) . $handle . '.log' );
}
do_action( 'woocommerce_log_remove', $handle, $removed );
return $removed;
}
}

View File

@ -10,7 +10,7 @@ if ( ! defined( 'ABSPATH' ) ) {
* The WooCommerce order factory creating the right order objects.
*
* @class WC_Order_Factory
* @version 2.2.0
* @version 2.7.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
@ -23,7 +23,7 @@ class WC_Order_Factory {
* @param bool $the_order (default: false)
* @return WC_Order|bool
*/
public function get_order( $the_order = false ) {
public static function get_order( $the_order = false ) {
global $post;
if ( false === $the_order ) {
@ -31,7 +31,7 @@ class WC_Order_Factory {
} elseif ( is_numeric( $the_order ) ) {
$the_order = get_post( $the_order );
} elseif ( $the_order instanceof WC_Order ) {
$the_order = get_post( $the_order->id );
$the_order = get_post( $the_order->get_id() );
}
if ( ! $the_order || ! is_object( $the_order ) ) {
@ -56,4 +56,49 @@ class WC_Order_Factory {
return new $classname( $the_order );
}
/**
* Get order item.
* @param int
* @return WC_Order_Item
*/
public static function get_order_item( $item_id = 0 ) {
global $wpdb;
if ( is_numeric( $item_id ) ) {
$item_data = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d LIMIT 1;", $item_id ) );
$item_type = $item_data->order_item_type;
} elseif ( $item_id instanceof WC_Order_Item ) {
$item_data = $item_id->get_data();
$item_type = $item_data->get_type();
} elseif( is_object( $item_id ) && ! empty( $item_id->order_item_type ) ) {
$item_data = $item_id;
$item_type = $item_id->order_item_type;
} else {
$item_data = false;
$item_type = false;
}
if ( $item_data && $item_type ) {
switch ( $item_type ) {
case 'line_item' :
case 'product' :
return new WC_Order_Item_Product( $item_data );
break;
case 'coupon' :
return new WC_Order_Item_Coupon( $item_data );
break;
case 'fee' :
return new WC_Order_Item_Fee( $item_data );
break;
case 'shipping' :
return new WC_Order_Item_Shipping( $item_data );
break;
case 'tax' :
return new WC_Order_Item_Tax( $item_data );
break;
}
}
return new WC_Order_Item();
}
}

View File

@ -0,0 +1,187 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Order Line Item (coupon).
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @author WooThemes
*/
class WC_Order_Item_Coupon extends WC_Order_Item {
/**
* Data properties of this order item object.
* @since 2.7.0
* @var array
*/
protected $_data = array(
'order_id' => 0,
'order_item_id' => 0,
'code' => '',
'discount' => 0,
'discount_tax' => 0,
);
/**
* offsetGet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @return mixed
*/
public function offsetGet( $offset ) {
if ( 'discount_amount' === $offset ) {
$offset = 'discount';
} elseif ( 'discount_amount_tax' === $offset ) {
$offset = 'discount_tax';
}
return parent::offsetGet( $offset );
}
/**
* offsetSet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @param mixed $value
*/
public function offsetSet( $offset, $value ) {
if ( 'discount_amount' === $offset ) {
$offset = 'discount';
} elseif ( 'discount_amount_tax' === $offset ) {
$offset = 'discount_tax';
}
parent::offsetSet( $offset, $value );
}
/**
* offsetExists for ArrayAccess
* @param string $offset
* @return bool
*/
public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'discount_amount', 'discount_amount_tax' ) ) ) {
return true;
}
return parent::offsetExists( $offset );
}
/**
* Read/populate data properties specific to this order item.
*/
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->set_discount( get_metadata( 'order_item', $this->get_id(), 'discount_amount', true ) );
$this->set_discount_tax( get_metadata( 'order_item', $this->get_id(), 'discount_amount_tax', true ) );
}
}
/**
* Save properties specific to this order item.
* @return int Item ID
*/
public function save() {
parent::save();
if ( $this->get_id() ) {
wc_update_order_item_meta( $this->get_id(), 'discount_amount', $this->get_discount() );
wc_update_order_item_meta( $this->get_id(), 'discount_amount_tax', $this->get_discount_tax() );
}
return $this->get_id();
}
/**
* Internal meta keys we don't want exposed as part of meta_data.
* @return array()
*/
protected function get_internal_meta_keys() {
return array( 'discount_amount', 'discount_amount_tax' );
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* Set order item name.
* @param string $value
*/
public function set_name( $value ) {
$this->set_code( $value );
}
/**
* Set code.
* @param string $value
*/
public function set_code( $value ) {
$this->_data['code'] = wc_clean( $value );
}
/**
* Set discount amount.
* @param string $value
*/
public function set_discount( $value ) {
$this->_data['discount'] = wc_format_decimal( $value );
}
/**
* Set discounted tax amount.
* @param string $value
*/
public function set_discount_tax( $value ) {
$this->_data['discount_tax'] = wc_format_decimal( $value );
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* Get order item type.
* @return string
*/
public function get_type() {
return 'coupon';
}
/**
* Get order item name.
* @return string
*/
public function get_name() {
return $this->get_code();
}
/**
* Get coupon code.
* @return string
*/
public function get_code() {
return $this->_data['code'];
}
/**
* Get discount amount.
* @return string
*/
public function get_discount() {
return wc_format_decimal( $this->_data['discount'] );
}
/**
* Get discounted tax amount.
* @return string
*/
public function get_discount_tax() {
return wc_format_decimal( $this->_data['discount_tax'] );
}
}

View File

@ -0,0 +1,231 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Order Line Item (fee).
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @author WooThemes
*/
class WC_Order_Item_Fee extends WC_Order_Item {
/**
* Data properties of this order item object.
* @since 2.7.0
* @var array
*/
protected $_data = array(
'order_id' => 0,
'order_item_id' => 0,
'name' => '',
'tax_class' => '',
'tax_status' => 'taxable',
'total' => '',
'total_tax' => '',
'taxes' => array(
'total' => array()
)
);
/**
* offsetGet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @return mixed
*/
public function offsetGet( $offset ) {
if ( 'line_total' === $offset ) {
$offset = 'total';
} elseif ( 'line_tax' === $offset ) {
$offset = 'total_tax';
} elseif ( 'line_tax_data' === $offset ) {
$offset = 'taxes';
}
return parent::offsetGet( $offset );
}
/**
* offsetSet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @param mixed $value
*/
public function offsetSet( $offset, $value ) {
if ( 'line_total' === $offset ) {
$offset = 'total';
} elseif ( 'line_tax' === $offset ) {
$offset = 'total_tax';
} elseif ( 'line_tax_data' === $offset ) {
$offset = 'taxes';
}
parent::offsetSet( $offset, $value );
}
/**
* offsetExists for ArrayAccess
* @param string $offset
* @return bool
*/
public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'line_total', 'line_tax', 'line_tax_data' ) ) ) {
return true;
}
return parent::offsetExists( $offset );
}
/**
* Read/populate data properties specific to this order item.
*/
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->set_tax_class( get_metadata( 'order_item', $this->get_id(), '_tax_class', true ) );
$this->set_tax_status( get_metadata( 'order_item', $this->get_id(), '_tax_status', true ) );
$this->set_total( get_metadata( 'order_item', $this->get_id(), '_line_total', true ) );
$this->set_total_tax( get_metadata( 'order_item', $this->get_id(), '_line_tax', true ) );
$this->set_taxes( get_metadata( 'order_item', $this->get_id(), '_line_tax_data', true ) );
}
}
/**
* Save properties specific to this order item.
* @return int Item ID
*/
public function save() {
parent::save();
if ( $this->get_id() ) {
wc_update_order_item_meta( $this->get_id(), '_tax_class', $this->get_tax_class() );
wc_update_order_item_meta( $this->get_id(), '_tax_status', $this->get_tax_status() );
wc_update_order_item_meta( $this->get_id(), '_line_total', $this->get_total() );
wc_update_order_item_meta( $this->get_id(), '_line_tax', $this->get_total_tax() );
wc_update_order_item_meta( $this->get_id(), '_line_tax_data', $this->get_taxes() );
}
return $this->get_id();
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* Set tax class.
* @param string $value
*/
public function set_tax_class( $value ) {
$this->_data['tax_class'] = $value;
}
/**
* Set tax_status.
* @param string $value
*/
public function set_tax_status( $value ) {
if ( in_array( $value, array( 'taxable', 'none' ) ) ) {
$this->_data['tax_status'] = $value;
} else {
$this->_data['tax_status'] = 'taxable';
}
}
/**
* Set total.
* @param string $value
*/
public function set_total( $value ) {
$this->_data['total'] = wc_format_decimal( $value );
}
/**
* Set total tax.
* @param string $value
*/
public function set_total_tax( $value ) {
$this->_data['total_tax'] = wc_format_decimal( $value );
}
/**
* Set taxes.
*
* This is an array of tax ID keys with total amount values.
* @param array $raw_tax_data
*/
public function set_taxes( $raw_tax_data ) {
$raw_tax_data = maybe_unserialize( $raw_tax_data );
$tax_data = array(
'total' => array(),
);
if ( ! empty( $raw_tax_data['total'] ) ) {
$tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data['total'] );
}
$this->_data['taxes'] = $tax_data;
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* Get order item name.
* @return string
*/
public function get_name() {
return $this->_data['name'] ? $this->_data['name'] : __( 'Fee', 'woocommerce' );
}
/**
* Get order item type.
* @return string
*/
public function get_type() {
return 'fee';
}
/**
* Get tax class.
* @return string
*/
public function get_tax_class() {
return $this->_data['tax_class'];
}
/**
* Get tax status.
* @return string
*/
public function get_tax_status() {
return $this->_data['tax_status'];
}
/**
* Get total fee.
* @return string
*/
public function get_total() {
return wc_format_decimal( $this->_data['total'] );
}
/**
* Get total tax.
* @return string
*/
public function get_total_tax() {
return wc_format_decimal( $this->_data['total_tax'] );
}
/**
* Get fee taxes.
* @return array
*/
public function get_taxes() {
return $this->_data['taxes'];
}
}

View File

@ -1,7 +1,6 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit;
}
/**
@ -9,6 +8,7 @@ if ( ! defined( 'ABSPATH' ) ) {
*
* A Simple class for managing order item meta so plugins add it in the correct format.
*
* @deprecated 2.7.0 wc_display_item_meta function is used instead.
* @class order_item_meta
* @version 2.4
* @package WooCommerce/Classes
@ -41,7 +41,6 @@ class WC_Order_Item_Meta {
$this->meta = array_filter( (array) $item );
return;
}
$this->item = $item;
$this->meta = array_filter( (array) $item['item_meta'] );
$this->product = $product;

View File

@ -0,0 +1,412 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Order Line Item (product).
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @author WooThemes
*/
class WC_Order_Item_Product extends WC_Order_Item {
/**
* Data properties of this order item object.
* @since 2.7.0
* @var array
*/
protected $_data = array(
'order_id' => 0,
'order_item_id' => 0,
'name' => '',
'product_id' => 0,
'variation_id' => 0,
'qty' => 0,
'tax_class' => '',
'subtotal' => 0,
'subtotal_tax' => 0,
'total' => 0,
'total_tax' => 0,
'taxes' => array(
'subtotal' => array(),
'total' => array()
),
);
/**
* offsetGet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @return mixed
*/
public function offsetGet( $offset ) {
if ( 'line_subtotal' === $offset ) {
$offset = 'subtotal';
} elseif ( 'line_subtotal_tax' === $offset ) {
$offset = 'subtotal_tax';
} elseif ( 'line_total' === $offset ) {
$offset = 'total';
} elseif ( 'line_tax' === $offset ) {
$offset = 'total_tax';
} elseif ( 'line_tax_data' === $offset ) {
$offset = 'taxes';
}
return parent::offsetGet( $offset );
}
/**
* offsetSet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @param mixed $value
*/
public function offsetSet( $offset, $value ) {
if ( 'line_subtotal' === $offset ) {
$offset = 'subtotal';
} elseif ( 'line_subtotal_tax' === $offset ) {
$offset = 'subtotal_tax';
} elseif ( 'line_total' === $offset ) {
$offset = 'total';
} elseif ( 'line_tax' === $offset ) {
$offset = 'total_tax';
} elseif ( 'line_tax_data' === $offset ) {
$offset = 'taxes';
}
parent::offsetSet( $offset, $value );
}
/**
* offsetExists for ArrayAccess
* @param string $offset
* @return bool
*/
public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', 'line_tax_data', 'item_meta_array', 'item_meta' ) ) ) {
return true;
}
return parent::offsetExists( $offset );
}
/**
* Read/populate data properties specific to this order item.
*/
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->set_product_id( get_metadata( 'order_item', $this->get_id(), '_product_id', true ) );
$this->set_variation_id( get_metadata( 'order_item', $this->get_id(), '_variation_id', true ) );
$this->set_qty( get_metadata( 'order_item', $this->get_id(), '_qty', true ) );
$this->set_tax_class( get_metadata( 'order_item', $this->get_id(), '_tax_class', true ) );
$this->set_subtotal( get_metadata( 'order_item', $this->get_id(), '_line_subtotal', true ) );
$this->set_subtotal_tax( get_metadata( 'order_item', $this->get_id(), '_line_subtotal_tax', true ) );
$this->set_total( get_metadata( 'order_item', $this->get_id(), '_line_total', true ) );
$this->set_total_tax( get_metadata( 'order_item', $this->get_id(), '_line_tax', true ) );
$this->set_taxes( get_metadata( 'order_item', $this->get_id(), '_line_tax_data', true ) );
}
}
/**
* Save properties specific to this order item.
* @return int Item ID
*/
public function save() {
parent::save();
if ( $this->get_id() ) {
wc_update_order_item_meta( $this->get_id(), '_product_id', $this->get_product_id() );
wc_update_order_item_meta( $this->get_id(), '_variation_id', $this->get_variation_id() );
wc_update_order_item_meta( $this->get_id(), '_qty', $this->get_qty() );
wc_update_order_item_meta( $this->get_id(), '_tax_class', $this->get_tax_class() );
wc_update_order_item_meta( $this->get_id(), '_line_subtotal', $this->get_subtotal() );
wc_update_order_item_meta( $this->get_id(), '_line_subtotal_tax', $this->get_subtotal_tax() );
wc_update_order_item_meta( $this->get_id(), '_line_total', $this->get_total() );
wc_update_order_item_meta( $this->get_id(), '_line_tax', $this->get_total_tax() );
wc_update_order_item_meta( $this->get_id(), '_line_tax_data', $this->get_taxes() );
}
return $this->get_id();
}
/**
* Internal meta keys we don't want exposed as part of meta_data.
* @return array()
*/
protected function get_internal_meta_keys() {
return array( '_product_id', '_variation_id', '_qty', '_tax_class', '_line_subtotal', '_line_subtotal_tax', '_line_total', '_line_tax', '_line_tax_data' );
}
/**
* Get the associated product.
* @return WC_Product|bool
*/
public function get_product() {
if ( $this->get_variation_id() ) {
$product = wc_get_product( $this->get_variation_id() );
} else {
$product = wc_get_product( $this->get_product_id() );
}
// Backwards compatible filter from WC_Order::get_product_from_item()
if ( has_filter( 'woocommerce_get_product_from_item' ) ) {
$product = apply_filters( 'woocommerce_get_product_from_item', $product, $this, wc_get_order( $this->get_order_id() ) );
}
return apply_filters( 'woocommerce_order_item_product', $product, $this );
}
/**
* Get the Download URL.
* @param int $download_id
* @return string
*/
public function get_item_download_url( $download_id ) {
$order = $this->get_order();
return $order ? add_query_arg( array(
'download_file' => $this->get_variation_id() ? $this->get_variation_id() : $this->get_product_id(),
'order' => $order->get_order_key(),
'email' => urlencode( $order->get_billing_email() ),
'key' => $download_id
), trailingslashit( home_url() ) ) : '';
}
/**
* Get any associated downloadable files.
* @return array
*/
public function get_item_downloads() {
global $wpdb;
$files = array();
$product = $this->get_product();
$order = $this->get_order();
if ( $product && $order && $product->is_downloadable() && $order->is_download_permitted() ) {
$download_ids = $wpdb->get_col(
$wpdb->prepare(
"SELECT download_id FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE user_email = %s AND order_key = %s AND product_id = %d ORDER BY permission_id",
$order->get_billing_email(),
$order->get_order_key(),
$this->get_variation_id() ? $this->get_variation_id() : $this->get_product_id()
)
);
foreach ( $download_ids as $download_id ) {
if ( $product->has_file( $download_id ) ) {
$files[ $download_id ] = $product->get_file( $download_id );
$files[ $download_id ]['download_url'] = $this->get_item_download_url( $download_id );
}
}
}
return apply_filters( 'woocommerce_get_item_downloads', $files, $this, $order );
}
/**
* Get tax status.
* @return string
*/
public function get_tax_status() {
$product = $this->get_product();
return $product ? $product->get_tax_status() : 'taxable';
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* Set qty.
* @param int $value
*/
public function set_qty( $value ) {
$this->_data['qty'] = wc_stock_amount( $value );
}
/**
* Set tax class.
* @param string $value
*/
public function set_tax_class( $value ) {
$this->_data['tax_class'] = $value;
}
/**
* Set Product ID
* @param int $value
*/
public function set_product_id( $value ) {
$this->_data['product_id'] = absint( $value );
}
/**
* Set variation ID.
* @param int $value
*/
public function set_variation_id( $value ) {
$this->_data['variation_id'] = absint( $value );
}
/**
* Line subtotal (before discounts).
* @param string $value
*/
public function set_subtotal( $value ) {
$this->_data['subtotal'] = wc_format_decimal( $value );
}
/**
* Line total (after discounts).
* @param string $value
*/
public function set_total( $value ) {
$this->_data['total'] = wc_format_decimal( $value );
}
/**
* Line subtotal tax (before discounts).
* @param string $value
*/
public function set_subtotal_tax( $value ) {
$this->_data['subtotal_tax'] = wc_format_decimal( $value );
}
/**
* Line total tax (after discounts).
* @param string $value
*/
public function set_total_tax( $value ) {
$this->_data['total_tax'] = wc_format_decimal( $value );
}
/**
* Set line taxes.
* @param array $raw_tax_data
*/
public function set_taxes( $raw_tax_data ) {
$raw_tax_data = maybe_unserialize( $raw_tax_data );
$tax_data = array(
'total' => array(),
'subtotal' => array()
);
if ( ! empty( $raw_tax_data['total'] ) && ! empty( $raw_tax_data['subtotal'] ) ) {
$tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data['total'] );
$tax_data['subtotal'] = array_map( 'wc_format_decimal', $raw_tax_data['subtotal'] );
}
$this->_data['taxes'] = $tax_data;
}
/**
* Set variation data (stored as meta data - write only).
* @param array $data Key/Value pairs
*/
public function set_variation( $data ) {
foreach ( $data as $key => $value ) {
$this->_meta_data[ str_replace( 'attribute_', '', $key ) ] = $value;
}
}
/**
* Set properties based on passed in product object.
* @param WC_Product $product
*/
public function set_product( $product ) {
if ( $product ) {
$this->set_product_id( $product->get_id() );
$this->set_name( $product->get_title() );
$this->set_tax_class( $product->get_tax_class() );
$this->set_variation_id( is_callable( array( $product, 'get_variation_id' ) ) ? $product->get_variation_id() : 0 );
$this->set_variation( is_callable( array( $product, 'get_variation_attributes' ) ) ? $product->get_variation_attributes() : array() );
}
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* Get order item type.
* @return string
*/
public function get_type() {
return 'line_item';
}
/**
* Get product ID.
* @return int
*/
public function get_product_id() {
return absint( $this->_data['product_id'] );
}
/**
* Get variation ID.
* @return int
*/
public function get_variation_id() {
return absint( $this->_data['variation_id'] );
}
/**
* Get qty.
* @return int
*/
public function get_qty() {
return wc_stock_amount( $this->_data['qty'] );
}
/**
* Get tax class.
* @return string
*/
public function get_tax_class() {
return $this->_data['tax_class'];
}
/**
* Get subtotal.
* @return string
*/
public function get_subtotal() {
return wc_format_decimal( $this->_data['subtotal'] );
}
/**
* Get subtotal tax.
* @return string
*/
public function get_subtotal_tax() {
return wc_format_decimal( $this->_data['subtotal_tax'] );
}
/**
* Get total.
* @return string
*/
public function get_total() {
return wc_format_decimal( $this->_data['total'] );
}
/**
* Get total tax.
* @return string
*/
public function get_total_tax() {
return wc_format_decimal( $this->_data['total_tax'] );
}
/**
* Get fee taxes.
* @return array
*/
public function get_taxes() {
return $this->_data['taxes'];
}
}

View File

@ -0,0 +1,233 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Order Line Item (shipping).
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @author WooThemes
*/
class WC_Order_Item_Shipping extends WC_Order_Item {
/**
* Data properties of this order item object.
* @since 2.7.0
* @var array
*/
protected $_data = array(
'order_id' => 0,
'order_item_id' => 0,
'method_title' => '',
'method_id' => '',
'total' => 0,
'total_tax' => 0,
'taxes' => array(
'total' => array()
),
);
/**
* offsetGet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @return mixed
*/
public function offsetGet( $offset ) {
if ( 'cost' === $offset ) {
$offset = 'total';
}
return parent::offsetGet( $offset );
}
/**
* offsetSet for ArrayAccess/Backwards compatibility.
* @deprecated Add deprecation notices in future release.
* @param string $offset
* @param mixed $value
*/
public function offsetSet( $offset, $value ) {
if ( 'cost' === $offset ) {
$offset = 'total';
}
parent::offsetSet( $offset, $value );
}
/**
* offsetExists for ArrayAccess
* @param string $offset
* @return bool
*/
public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'cost' ) ) ) {
return true;
}
return parent::offsetExists( $offset );
}
/**
* Read/populate data properties specific to this order item.
*/
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->set_method_id( get_metadata( 'order_item', $this->get_id(), 'method_id', true ) );
$this->set_total( get_metadata( 'order_item', $this->get_id(), 'cost', true ) );
$this->set_total_tax( get_metadata( 'order_item', $this->get_id(), 'total_tax', true ) );
$this->set_taxes( get_metadata( 'order_item', $this->get_id(), 'taxes', true ) );
}
}
/**
* Save properties specific to this order item.
* @return int Item ID
*/
public function save() {
parent::save();
if ( $this->get_id() ) {
wc_update_order_item_meta( $this->get_id(), 'method_id', $this->get_method_id() );
wc_update_order_item_meta( $this->get_id(), 'cost', $this->get_total() );
wc_update_order_item_meta( $this->get_id(), 'total_tax', $this->get_total_tax() );
wc_update_order_item_meta( $this->get_id(), 'taxes', $this->get_taxes() );
}
return $this->get_id();
}
/**
* Internal meta keys we don't want exposed as part of meta_data.
* @return array()
*/
protected function get_internal_meta_keys() {
return array( 'method_id', 'cost', 'total_tax', 'taxes' );
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* Set order item name.
* @param string $value
*/
public function set_name( $value ) {
$this->set_method_title( $value );
}
/**
* Set code.
* @param string $value
*/
public function set_method_title( $value ) {
$this->_data['method_title'] = wc_clean( $value );
}
/**
* Set shipping method id.
* @param string $value
*/
public function set_method_id( $value ) {
$this->_data['method_id'] = wc_clean( $value );
}
/**
* Set total.
* @param string $value
*/
public function set_total( $value ) {
$this->_data['total'] = wc_format_decimal( $value );
}
/**
* Set total tax.
* @param string $value
*/
public function set_total_tax( $value ) {
$this->_data['total_tax'] = wc_format_decimal( $value );
}
/**
* Set taxes.
*
* This is an array of tax ID keys with total amount values.
* @param array $raw_tax_data
*/
public function set_taxes( $raw_tax_data ) {
$raw_tax_data = maybe_unserialize( $raw_tax_data );
$tax_data = array(
'total' => array()
);
if ( ! empty( $raw_tax_data['total'] ) ) {
$tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data['total'] );
}
$this->_data['taxes'] = $tax_data;
$this->set_total_tax( array_sum( $tax_data['total'] ) );
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* Get order item type.
* @return string
*/
public function get_type() {
return 'shipping';
}
/**
* Get order item name.
* @return string
*/
public function get_name() {
return $this->get_method_title();
}
/**
* Get title.
* @return string
*/
public function get_method_title() {
return $this->_data['method_title'] ? $this->_data['method_title'] : __( 'Shipping', 'woocommerce' );
}
/**
* Get method ID.
* @return string
*/
public function get_method_id() {
return $this->_data['method_id'];
}
/**
* Get total cost.
* @return string
*/
public function get_total() {
return wc_format_decimal( $this->_data['total'] );
}
/**
* Get total tax.
* @return string
*/
public function get_total_tax() {
return wc_format_decimal( $this->_data['total_tax'] );
}
/**
* Get taxes.
* @return array
*/
public function get_taxes() {
return $this->_data['taxes'];
}
}

View File

@ -0,0 +1,210 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Order Line Item (tax).
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @author WooThemes
*/
class WC_Order_Item_Tax extends WC_Order_Item {
/**
* Data properties of this order item object.
* @since 2.7.0
* @var array
*/
protected $_data = array(
'order_id' => 0,
'order_item_id' => 0,
'rate_code' => '',
'rate_id' => 0,
'label' => '',
'compound' => false,
'tax_total' => 0,
'shipping_tax_total' => 0
);
/**
* Read/populate data properties specific to this order item.
*/
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->set_rate_id( get_metadata( 'order_item', $this->get_id(), 'rate_id', true ) );
$this->set_label( get_metadata( 'order_item', $this->get_id(), 'label', true ) );
$this->set_compound( get_metadata( 'order_item', $this->get_id(), 'compound', true ) );
$this->set_tax_total( get_metadata( 'order_item', $this->get_id(), 'tax_amount', true ) );
$this->set_shipping_tax_total( get_metadata( 'order_item', $this->get_id(), 'shipping_tax_amount', true ) );
}
}
/**
* Save properties specific to this order item.
* @return int Item ID
*/
public function save() {
parent::save();
if ( $this->get_id() ) {
wc_update_order_item_meta( $this->get_id(), 'rate_id', $this->get_rate_id() );
wc_update_order_item_meta( $this->get_id(), 'label', $this->get_label() );
wc_update_order_item_meta( $this->get_id(), 'compound', $this->get_compound() );
wc_update_order_item_meta( $this->get_id(), 'tax_amount', $this->get_tax_total() );
wc_update_order_item_meta( $this->get_id(), 'shipping_tax_amount', $this->get_shipping_tax_total() );
}
return $this->get_id();
}
/**
* Internal meta keys we don't want exposed as part of meta_data.
* @return array()
*/
protected function get_internal_meta_keys() {
return array( 'rate_id', 'label', 'compound', 'tax_amount', 'shipping_tax_amount' );
}
/**
* Is this a compound tax rate?
* @return boolean
*/
public function is_compound() {
return $this->get_compound();
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* Set order item name.
* @param string $value
*/
public function set_name( $value ) {
$this->set_rate_code( $value );
}
/**
* Set item name.
* @param string $value
*/
public function set_rate_code( $value ) {
$this->_data['rate_code'] = wc_clean( $value );
}
/**
* Set item name.
* @param string $value
*/
public function set_label( $value ) {
$this->_data['label'] = wc_clean( $value );
}
/**
* Set tax rate id.
* @param int $value
*/
public function set_rate_id( $value ) {
$this->_data['rate_id'] = absint( $value );
}
/**
* Set tax total.
* @param string $value
*/
public function set_tax_total( $value ) {
$this->_data['tax_total'] = wc_format_decimal( $value );
}
/**
* Set shipping_tax_total
* @param string $value
*/
public function set_shipping_tax_total( $value ) {
$this->_data['shipping_tax_total'] = wc_format_decimal( $value );
}
/**
* Set compound
* @param bool $value
*/
public function set_compound( $value ) {
$this->_data['compound'] = (bool) $value;
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* Get order item type.
* @return string
*/
public function get_type() {
return 'tax';
}
/**
* Get rate code/name.
* @return string
*/
public function get_name() {
return $this->get_rate_code();
}
/**
* Get rate code/name.
* @return string
*/
public function get_rate_code() {
return $this->_data['rate_code'];
}
/**
* Get label.
* @return string
*/
public function get_label() {
return $this->_data['label'] ? $this->_data['label'] : __( 'Tax', 'woocommerce' );
}
/**
* Get tax rate ID.
* @return int
*/
public function get_rate_id() {
return absint( $this->_data['rate_id'] );
}
/**
* Get tax_total
* @return string
*/
public function get_tax_total() {
return wc_format_decimal( $this->_data['tax_total'] );
}
/**
* Get shipping_tax_total
* @return string
*/
public function get_shipping_tax_total() {
return wc_format_decimal( $this->_data['shipping_tax_total'] );
}
/**
* Get compound.
* @return bool
*/
public function get_compound() {
return (bool) $this->_data['compound'];
}
}

View File

@ -0,0 +1,428 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Order Item
*
* A class which represents an item within an order and handles CRUD.
* Uses ArrayAccess to be BW compatible with WC_Orders::get_items().
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @author WooThemes
*/
class WC_Order_Item extends WC_Data implements ArrayAccess {
/**
* Data array, with defaults.
* @since 2.7.0
* @var array
*/
protected $_data = array(
'order_id' => 0,
'order_item_id' => 0,
'name' => '',
'type' => '',
);
/**
* May store an order to prevent retriving it multiple times.
* @var object
*/
protected $_order;
/**
* Stores meta in cache for future reads.
* A group must be set to to enable caching.
* @var string
*/
protected $_cache_group = 'order_itemmeta';
/**
* Meta type. This should match up with
* the types avaiable at https://codex.wordpress.org/Function_Reference/add_metadata.
* WP defines 'post', 'user', 'comment', and 'term'.
*/
protected $_meta_type = 'order_item';
/**
* Constructor.
* @param int|object|array $order_item ID to load from the DB (optional) or already queried data.
*/
public function __construct( $item = 0 ) {
if ( $item instanceof WC_Order_Item ) {
if ( $this->is_type( $item->get_type() ) ) {
$this->set_all( $item->get_data() );
}
} elseif ( is_array( $item ) ) {
$this->set_all( $item );
} else {
$this->read( $item );
}
}
/**
* Set all data based on input array.
* @param array $data
* @access private
*/
public function set_all( $data ) {
foreach ( $data as $key => $value ) {
if ( is_callable( array( $this, "set_$key" ) ) ) {
$this->{"set_$key"}( $value );
} else {
$this->_data[ $key ] = $value;
}
}
}
/**
* Type checking
* @param string|array $Type
* @return boolean
*/
public function is_type( $type ) {
return is_array( $type ) ? in_array( $this->get_type(), $type ) : $type === $this->get_type();
}
/**
* Get qty.
* @return int
*/
public function get_qty() {
return 1;
}
/**
* Get parent order object.
* @return int
*/
public function get_order() {
if ( ! $this->_order ) {
$this->_order = wc_get_order( $this->get_order_id() );
}
return $this->_order;
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* Get order item ID.
* @return int
*/
public function get_id() {
return $this->get_order_item_id();
}
/**
* Get order ID this meta belongs to.
* @return int
*/
public function get_order_id() {
return absint( $this->_data['order_id'] );
}
/**
* Get order item ID this meta belongs to.
* @return int
*/
protected function get_order_item_id() {
return absint( $this->_data['order_item_id'] );
}
/**
* Get order item name.
* @return string
*/
public function get_name() {
return $this->_data['name'];
}
/**
* Get order item type.
* @return string
*/
public function get_type() {
return $this->_data['type'];
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* Set ID
* @param int $value
*/
public function set_id( $value ) {
$this->set_order_item_id( $value );
}
/**
* Set order ID.
* @param int $value
*/
public function set_order_id( $value ) {
$this->_data['order_id'] = absint( $value );
}
/**
* Set order item ID.
* @param int $value
*/
protected function set_order_item_id( $value ) {
$this->_data['order_item_id'] = absint( $value );
}
/**
* Set order item name.
* @param string $value
*/
public function set_name( $value ) {
$this->_data['name'] = wc_clean( $value );
}
/**
* Set order item type.
* @param string $value
*/
protected function set_type( $value ) {
$this->_data['type'] = wc_clean( $value );
}
/*
|--------------------------------------------------------------------------
| CRUD methods
|--------------------------------------------------------------------------
|
| Methods which create, read, update and delete data from the database.
|
*/
/**
* Insert data into the database.
* @since 2.7.0
*/
public function create() {
global $wpdb;
$wpdb->insert( $wpdb->prefix . 'woocommerce_order_items', array(
'order_item_name' => $this->get_name(),
'order_item_type' => $this->get_type(),
'order_id' => $this->get_order_id()
) );
$this->set_id( $wpdb->insert_id );
do_action( 'woocommerce_new_order_item', $this->get_id(), $this, $this->get_order_id() );
}
/**
* Update data in the database.
* @since 2.7.0
*/
public function update() {
global $wpdb;
$wpdb->update( $wpdb->prefix . 'woocommerce_order_items', array(
'order_item_name' => $this->get_name(),
'order_item_type' => $this->get_type(),
'order_id' => $this->get_order_id()
), array( 'order_item_id' => $this->get_id() ) );
do_action( 'woocommerce_update_order_item', $this->get_id(), $this, $this->get_order_id() );
}
/**
* Read from the database.
* @since 2.7.0
* @param int|object $item ID of object to read, or already queried object.
*/
public function read( $item ) {
global $wpdb;
if ( is_numeric( $item ) && ! empty( $item ) ) {
$data = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d LIMIT 1;", $item ) );
} elseif ( ! empty( $item->order_item_id ) ) {
$data = $item;
} else {
$data = false;
}
if ( $data ) {
$this->set_order_id( $data->order_id );
$this->set_id( $data->order_item_id );
$this->set_name( $data->order_item_name );
$this->set_type( $data->order_item_type );
$this->read_meta_data();
}
}
/**
* Save data to the database.
* @since 2.7.0
* @return int Item ID
*/
public function save() {
if ( ! $this->get_id() ) {
$this->create();
} else {
$this->update();
}
$this->save_meta_data();
return $this->get_id();
}
/**
* Delete data from the database.
* @since 2.7.0
*/
public function delete() {
if ( $this->get_id() ) {
global $wpdb;
do_action( 'woocommerce_before_delete_order_item', $this->get_id() );
$wpdb->delete( $wpdb->prefix . 'woocommerce_order_items', array( 'order_item_id' => $this->get_id() ) );
$wpdb->delete( $wpdb->prefix . 'woocommerce_order_itemmeta', array( 'order_item_id' => $this->get_id() ) );
do_action( 'woocommerce_delete_order_item', $this->get_id() );
}
}
/*
|--------------------------------------------------------------------------
| Meta Data Handling
|--------------------------------------------------------------------------
*/
/**
* Expands things like term slugs before return.
* @param string $hideprefix (default: _)
* @return array
*/
public function get_formatted_meta_data( $hideprefix = '_' ) {
$formatted_meta = array();
$meta_data = $this->get_meta_data();
foreach ( $meta_data as $meta ) {
if ( "" === $meta->value || is_serialized( $meta->value ) || ( ! empty( $hideprefix ) && substr( $meta->key, 0, 1 ) === $hideprefix ) ) {
continue;
}
$attribute_key = urldecode( str_replace( 'attribute_', '', $meta->key ) );
$display_key = wc_attribute_label( $attribute_key, is_callable( array( $this, 'get_product' ) ) ? $this->get_product() : false );
$display_value = $meta->value;
if ( taxonomy_exists( $attribute_key ) ) {
$term = get_term_by( 'slug', $meta->value, $attribute_key );
if ( ! is_wp_error( $term ) && is_object( $term ) && $term->name ) {
$display_value = $term->name;
}
}
$formatted_meta[ $meta->meta_id ] = (object) array(
'key' => $meta->key,
'value' => $meta->key,
'display_key' => apply_filters( 'woocommerce_order_item_display_meta_key', $display_key ),
'display_value' => apply_filters( 'woocommerce_order_item_display_meta_value', $display_value ),
);
}
return $formatted_meta;
}
/*
|--------------------------------------------------------------------------
| Array Access Methods
|--------------------------------------------------------------------------
|
| For backwards compat with legacy arrays.
|
*/
/**
* offsetSet for ArrayAccess
* @param string $offset
* @param mixed $value
*/
public function offsetSet( $offset, $value ) {
if ( 'item_meta_array' === $offset ) {
foreach ( $value as $meta_id => $meta ) {
$this->update_meta_data( $meta->key, $meta->value, $meta_id );
}
return;
}
if ( array_key_exists( $offset, $this->_data ) ) {
$this->_data[ $offset ] = $value;
}
$this->update_meta_data( '_' . $offset, $value );
}
/**
* offsetUnset for ArrayAccess
* @param string $offset
*/
public function offsetUnset( $offset ) {
if ( 'item_meta_array' === $offset || 'item_meta' === $offset ) {
$this->_meta_data = array();
return;
}
if ( array_key_exists( $offset, $this->_data ) ) {
unset( $this->_data[ $offset ] );
}
$this->delete_meta_data( '_' . $offset );
}
/**
* offsetExists for ArrayAccess
* @param string $offset
* @return bool
*/
public function offsetExists( $offset ) {
if ( 'item_meta_array' === $offset || 'item_meta' === $offset || array_key_exists( $offset, $this->_data ) ) {
return true;
}
return array_key_exists( '_' . $offset, wp_list_pluck( $this->_meta_data, 'value', 'key' ) );
}
/**
* offsetGet for ArrayAccess
* @param string $offset
* @return mixed
*/
public function offsetGet( $offset ) {
if ( 'item_meta_array' === $offset ) {
$return = array();
foreach ( $this->_meta_data as $meta ) {
$return[ $meta->meta_id ] = $meta;
}
return $return;
}
$meta_values = wp_list_pluck( $this->_meta_data, 'value', 'key' );
if ( 'item_meta' === $offset ) {
return $meta_values;
} elseif ( array_key_exists( $offset, $this->_data ) ) {
return $this->_data[ $offset ];
} elseif ( array_key_exists( '_' . $offset, $meta_values ) ) {
// Item meta was expanded in previous versions, with prefixes removed. This maintains support.
return $meta_values[ '_' . $offset ];
}
return null;
}
}

View File

@ -1,113 +1,191 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit;
}
/**
* Order refund
* Order refund. Refunds are based on orders (essentially negative orders) and
* contain much of the same data.
*
* @class WC_Order_Refund
* @version 2.2.0
* @version 2.7.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
*/
class WC_Order_Refund extends WC_Abstract_Order {
/** @public string Order type */
public $order_type = 'refund';
/** @var string Date */
public $date;
/** @var string Refund reason */
public $reason;
/**
* Extend the abstract _data properties and then read the order object.
*
* @param int|object|WC_Order $order Order to init.
*/
public function __construct( $order = 0 ) {
$this->_data = array_merge( $this->_data, array(
'refund_amount' => '',
'refund_reason' => '',
'refunded_by' => 0,
) );
parent::__construct( $order );
}
/**
* Init/load the refund object. Called from the constructor.
*
* @param string|int|object|WC_Order_Refund $refund Refund to init
* @uses WP_POST
* Insert data into the database.
* @since 2.7.0
*/
protected function init( $refund ) {
if ( is_numeric( $refund ) ) {
$this->id = absint( $refund );
$this->post = get_post( $refund );
$this->get_refund( $this->id );
} elseif ( $refund instanceof WC_Order_Refund ) {
$this->id = absint( $refund->id );
$this->post = $refund->post;
$this->get_refund( $this->id );
} elseif ( isset( $refund->ID ) ) {
$this->id = absint( $refund->ID );
$this->post = $refund;
$this->get_refund( $this->id );
public function create() {
parent::create();
// Store additonal order data
if ( $this->get_id() ) {
$this->update_post_meta( '_refund_amount', $this->get_refund_amount() );
$this->update_post_meta( '_refunded_by', $this->get_refunded_by() );
$this->update_post_meta( '_refund_reason', $this->get_refund_reason() );
}
}
/**
* Gets an refund from the database.
*
* @since 2.2
* @param int $id
* @return bool
* Read from the database.
* @since 2.7.0
* @param int $id ID of object to read.
*/
public function get_refund( $id = 0 ) {
if ( ! $id ) {
return false;
public function read( $id ) {
parent::read( $id );
// Read additonal order data
if ( $this->get_id() ) {
$post_object = get_post( $id );
$this->set_refund_amount( get_post_meta( $this->get_id(), '_refund_amount', true ) );
// post_author was used before refunded_by meta.
$this->set_refunded_by( metadata_exists( 'post', $this->get_id(), '_refunded_by' ) ? get_post_meta( $this->get_id(), '_refunded_by', true ) : absint( $post_object->post_author ) );
// post_excerpt was used before refund_reason meta.
$this->set_refund_reason( metadata_exists( 'post', $this->get_id(), '_refund_reason' ) ? get_post_meta( $this->get_id(), '_refund_reason', true ) : absint( $post_object->post_excerpt ) );
}
if ( $result = get_post( $id ) ) {
$this->populate( $result );
return true;
}
return false;
}
/**
* Populates an refund from the loaded post data.
*
* @param mixed $result
* Update data in the database.
* @since 2.7.0
*/
public function populate( $result ) {
// Standard post data
$this->id = $result->ID;
$this->date = $result->post_date;
$this->modified_date = $result->post_modified;
$this->reason = $result->post_excerpt;
public function update() {
parent::update();
// Store additonal order data
$this->update_post_meta( '_refund_amount', $this->get_refund_amount() );
$this->update_post_meta( '_refunded_by', $this->get_refunded_by() );
$this->update_post_meta( '_refund_reason', $this->get_refund_reason() );
}
/**
* Get internal type (post type.)
* @return string
*/
public function get_type() {
return 'shop_order_refund';
}
/**
* Get a title for the new post type.
*/
protected function get_post_title() {
return sprintf( __( 'Refund &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) );
}
/**
* Set refunded amount.
* @param string $value
*/
public function set_refund_amount( $value ) {
$this->_data['refund_amount'] = wc_format_decimal( $value );
}
/**
* Get refunded amount.
*
* @since 2.2
* @return int|float
*/
public function get_refund_amount() {
return apply_filters( 'woocommerce_refund_amount', (double) $this->refund_amount, $this );
return apply_filters( 'woocommerce_refund_amount', (double) $this->_data['refund_amount'], $this );
}
/**
* Get formatted refunded amount.
*
* @since 2.4
* @return string
*/
public function get_formatted_refund_amount() {
return apply_filters( 'woocommerce_formatted_refund_amount', wc_price( $this->refund_amount, array('currency' => $this->get_order_currency()) ), $this );
return apply_filters( 'woocommerce_formatted_refund_amount', wc_price( $this->get_refund_amount(), array( 'currency' => $this->get_currency() ) ), $this );
}
/**
* Set refund reason.
* @param string $value
*/
public function set_refund_reason( $value ) {
$this->_data['refund_reason'] = $value;
}
/**
* Get refunded amount.
*
* Get refund reason.
* @since 2.2
* @return int|float
*/
public function get_refund_reason() {
return apply_filters( 'woocommerce_refund_reason', $this->reason, $this );
return apply_filters( 'woocommerce_refund_reason', $this->_data['refund_reason'], $this );
}
/**
* Set refunded by.
* @param int $value
*/
public function set_refunded_by( $value ) {
$this->_data['refunded_by'] = absint( $value );
}
/**
* Get ID of user who did the refund.
* @since 2.7
* @return int
*/
public function get_refunded_by() {
return absint( $this->_data['refunded_by'] );
}
/**
* Magic __get method for backwards compatibility.
* @param string $key
* @return mixed
*/
public function __get( $key ) {
_doing_it_wrong( $key, 'Refund properties should not be accessed directly.', '2.7' );
/**
* Maps legacy vars to new getters.
*/
if ( 'reason' === $key ) {
return $this->get_refund_reason();
} elseif ( 'refund_amount' === $key ) {
return $this->get_refund_amount();
}
return parent::__get( $key );
}
/**
* Gets an refund from the database.
* @deprecated 2.7
* @param int $id (default: 0).
* @return bool
*/
public function get_refund( $id = 0 ) {
_deprecated_function( 'get_refund', '2.7', 'read' );
if ( ! $id ) {
return false;
}
if ( $result = get_post( $id ) ) {
$this->populate( $result );
return true;
}
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -610,7 +610,7 @@ class WC_Product_Variable extends WC_Product {
'price_html' => apply_filters( 'woocommerce_show_variation_price', $variation->get_price() === "" || $this->get_variation_price( 'min' ) !== $this->get_variation_price( 'max' ), $this, $variation ) ? '<span class="price">' . $variation->get_price_html() . '</span>' : '',
'availability_html' => $availability_html,
'sku' => $variation->get_sku(),
'weight' => $variation->get_weight() . ' ' . esc_attr( get_option('woocommerce_weight_unit' ) ),
'weight' => $variation->get_weight() ? $variation->get_weight() . ' ' . esc_attr( get_option('woocommerce_weight_unit' ) ) : '',
'dimensions' => $variation->get_dimensions(),
'min_qty' => 1,
'max_qty' => $variation->backorders_allowed() ? '' : $variation->get_stock_quantity(),
@ -723,6 +723,33 @@ class WC_Product_Variable extends WC_Product {
}
}
/**
* Does a child have a weight set?
* @since 2.7.0
* @return boolean
*/
public function child_has_weight() {
return (bool) get_post_meta( $this->id, '_child_has_weight', true );
}
/**
* Does a child have dimensions set?
* @since 2.7.0
* @return boolean
*/
public function child_has_dimensions() {
return (bool) get_post_meta( $this->id, '_child_has_dimensions', true );
}
/**
* Returns whether or not we are showing dimensions on the product page.
*
* @return bool
*/
public function enable_dimensions_display() {
return apply_filters( 'wc_product_enable_dimensions_display', true ) && ( $this->has_dimensions() || $this->has_weight() || $this->child_has_weight() || $this->child_has_dimensions() );
}
/**
* Sync the variable product with it's children.
*/
@ -740,6 +767,8 @@ class WC_Product_Variable extends WC_Product {
// No published variations - product won't be purchasable.
if ( ! $children ) {
update_post_meta( $product_id, '_price', '' );
delete_post_meta( $product_id, '_child_has_weight' );
delete_post_meta( $product_id, '_child_has_dimensions' );
delete_transient( 'wc_products_onsale' );
if ( is_admin() && 'publish' === get_post_status( $product_id ) ) {
@ -826,6 +855,22 @@ class WC_Product_Variable extends WC_Product {
add_post_meta( $product_id, '_price', $max_price, false );
delete_transient( 'wc_products_onsale' );
// Sync weights
foreach ( $children as $child_id ) {
if ( get_post_meta( $child_id, '_weight', true ) ) {
update_post_meta( $product_id, '_child_has_weight', true );
break;
}
}
// Sync dimensions
foreach ( $children as $child_id ) {
if ( get_post_meta( $child_id, '_height', true ) || get_post_meta( $child_id, '_width', true ) || get_post_meta( $child_id, '_length', true ) ) {
update_post_meta( $product_id, '_child_has_dimensions', true );
break;
}
}
// Sync attributes
self::sync_attributes( $product_id, $children );

View File

@ -88,6 +88,11 @@ class WC_Product_Variation extends WC_Product {
$this->product_type = 'variation';
$this->parent = ! empty( $args['parent'] ) ? $args['parent'] : wc_get_product( $this->id );
$this->post = ! empty( $this->parent->post ) ? $this->parent->post : array();
// The post parent is not a valid variable product so we should prevent this being created.
if ( ! is_a( $this->parent, 'WC_Product' ) ) {
throw new Exception( sprintf( 'Invalid parent for variation #%d', $this->variation_id ), 422 );
}
}
/**

View File

@ -275,7 +275,7 @@ class WC_Query {
}
// Special check for shops with the product archive on front
if ( $this->is_showing_page_on_front( $q ) && 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' ) ) {
// This is a front-page shop
$q->set( 'post_type', 'product' );
$q->set( 'page_id', '' );

View File

@ -331,7 +331,14 @@ class WC_Shipping {
}
// Check if we need to recalculate shipping for this package
$package_hash = 'wc_ship_' . md5( json_encode( $package ) . WC_Cache_Helper::get_transient_version( 'shipping' ) );
$package_to_hash = $package;
// Remove data objects so hashes are consistent
foreach ( $package_to_hash['contents'] as $item_id => $item ) {
unset( $package_to_hash['contents'][ $item_id ]['data'] );
}
$package_hash = 'wc_ship_' . md5( json_encode( $package_to_hash ) . WC_Cache_Helper::get_transient_version( 'shipping' ) );
$status_options = get_option( 'woocommerce_status_options', array() );
$session_key = 'shipping_for_package_' . $package_key;
$stored_rates = WC()->session->get( $session_key );

View File

@ -266,6 +266,51 @@ class WC_Tax {
return $shipping_rates;
}
/**
* Does the sort comparison.
*/
private static function sort_rates_callback( $rate1, $rate2 ) {
if ( $rate1->tax_rate_priority !== $rate2->tax_rate_priority ) {
return $rate1->tax_rate_priority < $rate2->tax_rate_priority ? -1 : 1; // ASC
} elseif ( $rate1->tax_rate_country !== $rate2->tax_rate_country ) {
if ( '' === $rate1->tax_rate_country ) {
return 1;
}
if ( '' === $rate2->tax_rate_country ) {
return -1;
}
return strcmp( $rate1->tax_rate_country, $rate2->tax_rate_country ) > 0 ? 1 : -1;
} elseif ( $rate1->tax_rate_state !== $rate2->tax_rate_state ) {
if ( '' === $rate1->tax_rate_state ) {
return 1;
}
if ( '' === $rate2->tax_rate_state ) {
return -1;
}
return strcmp( $rate1->tax_rate_state, $rate2->tax_rate_state ) > 0 ? 1 : -1;
} else {
return $rate1->tax_rate_id < $rate2->tax_rate_id ? -1 : 1; // Identical - use ID
}
}
/**
* Logical sort order for tax rates based on the following in order of priority:
* - Priority
* - County code
* - State code
* @param array $rates
* @return array
* @todo remove tax_rate_order column
*/
private static function sort_rates( $rates ) {
uasort( $rates, __CLASS__ . '::sort_rates_callback' );
$i = 0;
foreach ( $rates as $key => $rate ) {
$rates[ $key ]->tax_rate_order = $i++;
}
return $rates;
}
/**
* Loop through a set of tax rates and get the matching rates (1 per priority).
*
@ -338,9 +383,10 @@ class WC_Tax {
LEFT OUTER JOIN {$wpdb->prefix}woocommerce_tax_rate_locations as locations2 ON tax_rates.tax_rate_id = locations2.tax_rate_id
WHERE 1=1 AND " . implode( ' AND ', $criteria ) . "
GROUP BY tax_rate_id
ORDER BY tax_rate_priority, tax_rate_order
ORDER BY tax_rate_priority
" );
$found_rates = self::sort_rates( $found_rates );
$matched_tax_rates = array();
$found_priority = array();
@ -892,7 +938,7 @@ class WC_Tax {
global $wpdb;
// Get all the rates and locations. Snagging all at once should significantly cut down on the number of queries.
$rates = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->prefix}woocommerce_tax_rates` WHERE `tax_rate_class` = %s ORDER BY `tax_rate_order`;", sanitize_title( $tax_class ) ) );
$rates = self::sort_rates( $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->prefix}woocommerce_tax_rates` WHERE `tax_rate_class` = %s;", sanitize_title( $tax_class ) ) ) );
$locations = $wpdb->get_results( "SELECT * FROM `{$wpdb->prefix}woocommerce_tax_rate_locations`" );
if ( ! empty( $rates ) ) {

View File

@ -270,6 +270,10 @@ class WC_Webhook {
break;
case 'product':
// bulk and quick edit action hooks return a product object instead of an ID
if ( 'updated' === $event && is_a( $resource_id, 'WC_Product' ) ) {
$resource_id = $resource_id->get_id();
}
$payload = WC()->api->WC_API_Products->get_product( $resource_id );
break;
@ -581,6 +585,8 @@ class WC_Webhook {
'product.updated' => array(
'woocommerce_process_product_meta',
'woocommerce_api_edit_product',
'woocommerce_product_quick_edit_save',
'woocommerce_product_bulk_edit_save',
),
'product.deleted' => array(
'wp_trash_post',

View File

@ -56,6 +56,8 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
self::$log_enabled = $this->debug;
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'woocommerce_order_status_on-hold_to_processing', array( $this, 'capture_payment' ) );
add_action( 'woocommerce_order_status_on-hold_to_completed', array( $this, 'capture_payment' ) );
if ( ! $this->is_valid_for_use() ) {
$this->enabled = 'no';
@ -256,6 +258,18 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
return $order && $order->get_transaction_id();
}
/**
* Init the API class and set the username/password etc.
*/
protected function init_api() {
include_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-api-handler.php' );
WC_Gateway_Paypal_API_Handler::$api_username = $this->get_option( 'api_username' );
WC_Gateway_Paypal_API_Handler::$api_password = $this->get_option( 'api_password' );
WC_Gateway_Paypal_API_Handler::$api_signature = $this->get_option( 'api_signature' );
WC_Gateway_Paypal_API_Handler::$sandbox = $this->testmode;
}
/**
* Process a refund if supported.
* @param int $order_id
@ -271,13 +285,9 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
return new WP_Error( 'error', __( 'Refund Failed: No transaction ID', 'woocommerce' ) );
}
include_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-refund.php' );
$this->init_api();
WC_Gateway_Paypal_Refund::$api_username = $this->get_option( 'api_username' );
WC_Gateway_Paypal_Refund::$api_password = $this->get_option( 'api_password' );
WC_Gateway_Paypal_Refund::$api_signature = $this->get_option( 'api_signature' );
$result = WC_Gateway_Paypal_Refund::refund_order( $order, $amount, $reason, $this->testmode );
$result = WC_Gateway_Paypal_API_Handler::refund_transaction( $order, $amount, $reason );
if ( is_wp_error( $result ) ) {
$this->log( 'Refund Failed: ' . $result->get_error_message() );
@ -286,14 +296,49 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
$this->log( 'Refund Result: ' . print_r( $result, true ) );
switch ( strtolower( $result['ACK'] ) ) {
switch ( strtolower( $result->ACK ) ) {
case 'success':
case 'successwithwarning':
$order->add_order_note( sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $result['GROSSREFUNDAMT'], $result['REFUNDTRANSACTIONID'] ) );
$order->add_order_note( sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $result->GROSSREFUNDAMT, $result->REFUNDTRANSACTIONID ) );
return true;
break;
}
return isset( $result['L_LONGMESSAGE0'] ) ? new WP_Error( 'error', $result['L_LONGMESSAGE0'] ) : false;
return isset( $result->L_LONGMESSAGE0 ) ? new WP_Error( 'error', $result->L_LONGMESSAGE0 ) : false;
}
/**
* Capture payment when the order is changed from on-hold to complete or processing
*
* @param int $order_id
*/
public function capture_payment( $order_id ) {
$order = wc_get_order( $order_id );
if ( 'paypal' === $order->payment_method && 'pending' === get_post_meta( $order->id, '_paypal_status', true ) && $order->get_transaction_id() ) {
$this->init_api();
$result = WC_Gateway_Paypal_API_Handler::do_capture( $order );
if ( is_wp_error( $result ) ) {
$this->log( 'Capture Failed: ' . $result->get_error_message() );
$order->add_order_note( sprintf( __( 'Payment could not captured: %s', 'woocommerce' ), $result->get_error_message() ) );
return;
}
$this->log( 'Capture Result: ' . print_r( $result, true ) );
if ( ! empty( $result->PAYMENTSTATUS ) ) {
switch ( $result->PAYMENTSTATUS ) {
case 'Completed' :
$order->add_order_note( sprintf( __( 'Payment of %s was captured - Auth ID: %s, Transaction ID: %s', 'woocommerce' ), $result->AMT, $result->AUTHORIZATIONID, $result->TRANSACTIONID ) );
update_post_meta( $order->id, '_paypal_status', $result->PAYMENTSTATUS );
update_post_meta( $order->id, '_transaction_id', $result->TRANSACTIONID );
break;
default :
$order->add_order_note( sprintf( __( 'Payment could not captured - Auth ID: %s, Status: %s', 'woocommerce' ), $result->AUTHORIZATIONID, $result->PAYMENTSTATUS ) );
break;
}
}
}
}
}

View File

@ -0,0 +1,156 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles Refunds and other API requests such as capture.
* @since 2.7.0
*/
class WC_Gateway_Paypal_API_Handler {
/** @var string API Username */
public static $api_username;
/** @var string API Password */
public static $api_password;
/** @var string API Signature */
public static $api_signature;
/** @var bool Sandbox */
public static $sandbox = false;
/**
* Get capture request args.
* See https://developer.paypal.com/docs/classic/api/merchant/DoCapture_API_Operation_NVP/.
* @param WC_Order $order
* @param float $amount
* @return array
*/
public static function get_capture_request( $order, $amount = null ) {
$request = array(
'VERSION' => '84.0',
'SIGNATURE' => self::$api_signature,
'USER' => self::$api_username,
'PWD' => self::$api_password,
'METHOD' => 'DoCapture',
'AUTHORIZATIONID' => $order->get_transaction_id(),
'AMT' => number_format( is_null( $amount ) ? $order->get_total() : $amount, 2, '.', '' ),
'CURRENCYCODE' => $order->get_order_currency(),
'COMPLETETYPE' => 'Complete',
);
return apply_filters( 'woocommerce_paypal_capture_request', $request, $order, $amount );
}
/**
* Get refund request args.
* @param WC_Order $order
* @param float $amount
* @param string $reason
* @return array
*/
public static function get_refund_request( $order, $amount = null, $reason = '' ) {
$request = array(
'VERSION' => '84.0',
'SIGNATURE' => self::$api_signature,
'USER' => self::$api_username,
'PWD' => self::$api_password,
'METHOD' => 'RefundTransaction',
'TRANSACTIONID' => $order->get_transaction_id(),
'NOTE' => html_entity_decode( wc_trim_string( $reason, 255 ), ENT_NOQUOTES, 'UTF-8' ),
'REFUNDTYPE' => 'Full',
);
if ( ! is_null( $amount ) ) {
$request['AMT'] = number_format( $amount, 2, '.', '' );
$request['CURRENCYCODE'] = $order->get_order_currency();
$request['REFUNDTYPE'] = 'Partial';
}
return apply_filters( 'woocommerce_paypal_refund_request', $request, $order, $amount, $reason );
}
/**
* Capture an authorization.
* @param WC_Order $order
* @param float $amount
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
*/
public static function do_capture( $order, $amount = null ) {
$raw_response = wp_safe_remote_post(
self::$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
array(
'method' => 'POST',
'body' => self::get_capture_request( $order, $amount ),
'timeout' => 70,
'user-agent' => 'WooCommerce/' . WC()->version,
'httpversion' => '1.1',
)
);
WC_Gateway_Paypal::log( 'DoCapture Response: ' . print_r( $raw_response, true ) );
if ( empty( $raw_response['body'] ) ) {
return new WP_Error( 'paypal-api', 'Empty Response' );
} elseif ( is_wp_error( $raw_response ) ) {
return $raw_response;
}
parse_str( $raw_response['body'], $response );
return (object) $response;
}
/**
* Refund an order via PayPal.
* @param WC_Order $order
* @param float $amount
* @param string $reason
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
*/
public static function refund_transaction( $order, $amount = null, $reason = '' ) {
$raw_response = wp_safe_remote_post(
self::$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
array(
'method' => 'POST',
'body' => self::get_refund_request( $order, $amount, $reason ),
'timeout' => 70,
'user-agent' => 'WooCommerce/' . WC()->version,
'httpversion' => '1.1',
)
);
WC_Gateway_Paypal::log( 'Refund Response: ' . print_r( $raw_response, true ) );
if ( empty( $raw_response['body'] ) ) {
return new WP_Error( 'paypal-api', 'Empty Response' );
} elseif ( is_wp_error( $raw_response ) ) {
return $raw_response;
}
parse_str( $raw_response['body'], $response );
return (object) $response;
}
}
/**
* Here for backwards compatibility.
* @since 2.7.0
*/
class WC_Gateway_Paypal_Refund extends WC_Gateway_Paypal_API_Handler {
public static function get_request( $order, $amount = null, $reason = '' ) {
return self::get_refund_request( $order, $amount, $reason );
}
public static function refund_order( $order, $amount = null, $reason = '', $sandbox = false ) {
if ( $sandbox ) {
self::$sandbox = $sandbox;
}
$result = self::refund_transaction( $order, $amount, $reason );
if ( is_wp_error( $result ) ) {
return $result;
} else {
return (array) $result;
}
}
}

View File

@ -172,7 +172,7 @@ class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response {
* @param array $posted
*/
protected function payment_status_completed( $order, $posted ) {
if ( $order->has_status( 'completed' ) ) {
if ( $order->has_status( array( 'processing', 'completed' ) ) ) {
WC_Gateway_Paypal::log( 'Aborting, Order #' . $order->id . ' is already complete.' );
exit;
}
@ -192,7 +192,11 @@ class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response {
}
} else {
$this->payment_on_hold( $order, sprintf( __( 'Payment pending: %s', 'woocommerce' ), $posted['pending_reason'] ) );
if ( 'authorization' === $posted['pending_reason'] ) {
$this->payment_on_hold( $order, __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce' ) );
} else {
$this->payment_on_hold( $order, sprintf( __( 'Payment pending (%s).', 'woocommerce' ), $posted['pending_reason'] ) );
}
}
}
@ -304,6 +308,12 @@ class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response {
if ( ! empty( $posted['payment_type'] ) ) {
update_post_meta( $order->id, 'Payment type', wc_clean( $posted['payment_type'] ) );
}
if ( ! empty( $posted['txn_id'] ) ) {
update_post_meta( $order->id, '_transaction_id', wc_clean( $posted['txn_id'] ) );
}
if ( ! empty( $posted['payment_status'] ) ) {
update_post_meta( $order->id, '_paypal_status', wc_clean( $posted['payment_status'] ) );
}
}
/**

View File

@ -88,28 +88,41 @@ class WC_Gateway_Paypal_PDT_Handler extends WC_Gateway_Paypal_Response {
$transaction_result = $this->validate_transaction( $transaction );
if ( $transaction_result && 'completed' === $status ) {
if ( $order->get_total() != $amount ) {
WC_Gateway_Paypal::log( 'Payment error: Amounts do not match (amt ' . $amount . ')' );
$this->payment_on_hold( $order, sprintf( __( 'Validation error: PayPal amounts do not match (amt %s).', 'woocommerce' ), $amount ) );
} else {
$this->payment_complete( $order, $transaction, __( 'PDT payment completed', 'woocommerce' ) );
WC_Gateway_Paypal::log( 'PDT Transaction Result: ' . print_r( $transaction_result, true ) );
// Log paypal transaction fee and other meta data.
if ( ! empty( $transaction_result['mc_fee'] ) ) {
update_post_meta( $order->id, 'PayPal Transaction Fee', $transaction_result['mc_fee'] );
update_post_meta( $order->id, '_paypal_status', $status );
update_post_meta( $order->id, '_transaction_id', $transaction );
if ( $transaction_result ) {
if ( 'completed' === $status ) {
if ( $order->get_total() != $amount ) {
WC_Gateway_Paypal::log( 'Payment error: Amounts do not match (amt ' . $amount . ')' );
$this->payment_on_hold( $order, sprintf( __( 'Validation error: PayPal amounts do not match (amt %s).', 'woocommerce' ), $amount ) );
} else {
$this->payment_complete( $order, $transaction, __( 'PDT payment completed', 'woocommerce' ) );
// Log paypal transaction fee and other meta data.
if ( ! empty( $transaction_result['mc_fee'] ) ) {
update_post_meta( $order->id, 'PayPal Transaction Fee', $transaction_result['mc_fee'] );
}
if ( ! empty( $transaction_result['payer_email'] ) ) {
update_post_meta( $order->id, 'Payer PayPal address', $transaction_result['payer_email'] );
}
if ( ! empty( $transaction_result['first_name'] ) ) {
update_post_meta( $order->id, 'Payer first name', $transaction_result['first_name'] );
}
if ( ! empty( $transaction_result['last_name'] ) ) {
update_post_meta( $order->id, 'Payer last name', $transaction_result['last_name'] );
}
if ( ! empty( $transaction_result['payment_type'] ) ) {
update_post_meta( $order->id, 'Payment type', $transaction_result['payment_type'] );
}
}
if ( ! empty( $transaction_result['payer_email'] ) ) {
update_post_meta( $order->id, 'Payer PayPal address', $transaction_result['payer_email'] );
}
if ( ! empty( $transaction_result['first_name'] ) ) {
update_post_meta( $order->id, 'Payer first name', $transaction_result['first_name'] );
}
if ( ! empty( $transaction_result['last_name'] ) ) {
update_post_meta( $order->id, 'Payer last name', $transaction_result['last_name'] );
}
if ( ! empty( $transaction_result['payment_type'] ) ) {
update_post_meta( $order->id, 'Payment type', $transaction_result['payment_type'] );
} else {
if ( 'authorization' === $transaction_result['pending_reason'] ) {
$this->payment_on_hold( $order, __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce' ) );
} else {
$this->payment_on_hold( $order, sprintf( __( 'Payment pending (%s).', 'woocommerce' ), $transaction_result['pending_reason'] ) );
}
}
}

View File

@ -1,81 +0,0 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles Refunds.
*/
class WC_Gateway_Paypal_Refund {
/** @var string API Username for refunds */
public static $api_username;
/** @var string API Password for refunds */
public static $api_password;
/** @var string API Signature for refunds */
public static $api_signature;
/**
* Get refund request args.
* @param WC_Order $order
* @param float $amount
* @param string $reason
* @return array
*/
public static function get_request( $order, $amount = null, $reason = '' ) {
$request = array(
'VERSION' => '84.0',
'SIGNATURE' => self::$api_signature,
'USER' => self::$api_username,
'PWD' => self::$api_password,
'METHOD' => 'RefundTransaction',
'TRANSACTIONID' => $order->get_transaction_id(),
'NOTE' => html_entity_decode( wc_trim_string( $reason, 255 ), ENT_NOQUOTES, 'UTF-8' ),
'REFUNDTYPE' => 'Full'
);
if ( ! is_null( $amount ) ) {
$request['AMT'] = number_format( $amount, 2, '.', '' );
$request['CURRENCYCODE'] = $order->get_order_currency();
$request['REFUNDTYPE'] = 'Partial';
}
return apply_filters( 'woocommerce_paypal_refund_request', $request, $order, $amount, $reason );
}
/**
* Refund an order via PayPal.
* @param WC_Order $order
* @param float $amount
* @param string $reason
* @param bool $sandbox
* @return array|wp_error The parsed response from paypal, or a WP_Error object
*/
public static function refund_order( $order, $amount = null, $reason = '', $sandbox = false ) {
$response = wp_safe_remote_post(
$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
array(
'method' => 'POST',
'body' => self::get_request( $order, $amount, $reason ),
'timeout' => 70,
'user-agent' => 'WooCommerce',
'httpversion' => '1.1'
)
);
WC_Gateway_Paypal::log( 'Refund Response: ' . print_r( $response, true ) );
if ( is_wp_error( $response ) ) {
return $response;
}
if ( empty( $response['body'] ) ) {
return new WP_Error( 'paypal-refunds', 'Empty Response' );
}
parse_str( $response['body'], $response_array );
return $response_array;
}
}

View File

@ -44,7 +44,7 @@ if ( ! empty( $shipping_classes ) ) {
'title' => __( 'Shipping Class Costs', 'woocommerce' ),
'type' => 'title',
'default' => '',
'description' => sprintf( __( 'These costs can optionally be added based on the %sproduct shipping class%s.', 'woocommerce' ), '<a href="' . admin_url( 'edit-tags.php?taxonomy=product_shipping_class&post_type=product' ) . '">', '</a>' )
'description' => sprintf( __( 'These costs can optionally be added based on the %sproduct shipping class%s.', 'woocommerce' ), '<a href="' . admin_url( 'admin.php?page=wc-settings&tab=shipping&section=classes' ) . '">', '</a>' )
);
foreach ( $shipping_classes as $shipping_class ) {
if ( ! isset( $shipping_class->term_id ) ) {

View File

@ -71,7 +71,7 @@ if ( ! empty( $shipping_classes ) ) {
'title' => __( 'Shipping Class Costs', 'woocommerce' ),
'type' => 'title',
'default' => '',
'description' => sprintf( __( 'These costs can optionally be added based on the %sproduct shipping class%s.', 'woocommerce' ), '<a href="' . admin_url( 'edit-tags.php?taxonomy=product_shipping_class&post_type=product' ) . '">', '</a>' )
'description' => sprintf( __( 'These costs can optionally be added based on the %sproduct shipping class%s.', 'woocommerce' ), '<a href="' . admin_url( 'admin.php?page=wc-settings&tab=shipping&section=classes' ) . '">', '</a>' )
);
foreach ( $shipping_classes as $shipping_class ) {
if ( ! isset( $shipping_class->term_id ) ) {

View File

@ -41,6 +41,11 @@ class WC_Shortcode_My_Account {
wc_add_notice( $message );
}
// After password reset, add confirmation message.
if ( ! empty( $_GET['password-reset'] ) ) {
wc_add_notice( __( 'Your password has been reset successfully.', 'woocommerce' ) );
}
if ( isset( $wp->query_vars['lost-password'] ) ) {
self::lost_password();
} else {
@ -188,12 +193,6 @@ class WC_Shortcode_My_Account {
if ( ! empty( $_GET['reset-link-sent'] ) ) {
return wc_get_template( 'myaccount/lost-password-confirmation.php' );
/**
* After reset, show confirmation message.
*/
} elseif ( ! empty( $_GET['reset'] ) ) {
wc_add_notice( __( 'Your password has been reset.', 'woocommerce' ) . ' <a class="button" href="' . esc_url( wc_get_page_permalink( 'myaccount' ) ) . '">' . __( 'Log in', 'woocommerce' ) . '</a>' );
/**
* Process reset key / login from email confirmation link
*/

View File

@ -47,26 +47,26 @@ class WC_Product_Cat_Dropdown_Walker extends Walker {
*/
public function start_el( &$output, $cat, $depth = 0, $args = array(), $current_object_id = 0 ) {
if ( ! empty( $args['hierarchical'] ) )
if ( ! empty( $args['hierarchical'] ) ) {
$pad = str_repeat('&nbsp;', $depth * 3);
else
} else {
$pad = '';
}
$cat_name = apply_filters( 'list_product_cats', $cat->name, $cat );
$value = isset( $args['value'] ) && $args['value'] == 'id' ? $cat->term_id : $cat->slug;
$output .= "\t<option class=\"level-$depth\" value=\"" . esc_attr( $value ) . "\"";
$value = isset( $args['value'] ) && $args['value'] == 'id' ? $cat->term_id : $cat->slug;
$output .= "\t<option class=\"level-$depth\" value=\"" . $value . "\"";
if ( $value == $args['selected'] || ( is_array( $args['selected'] ) && in_array( $value, $args['selected'] ) ) )
if ( $value === $args['selected'] || ( is_array( $args['selected'] ) && in_array( $value, $args['selected'] ) ) ) {
$output .= ' selected="selected"';
}
$output .= '>';
$output .= esc_html( $pad . _x( $cat_name, 'product category name', 'woocommerce' ) );
$output .= $pad . _x( $cat_name, 'product category name', 'woocommerce' );
if ( ! empty( $args['show_count'] ) )
$output .= '&nbsp;(' . $cat->count . ')';
if ( ! empty( $args['show_count'] ) ) {
$output .= '&nbsp;(' . absint( $cat->count ) . ')';
}
$output .= "</option>\n";
}

View File

@ -85,13 +85,14 @@ function wc_get_raw_referer() {
* @access public
* @param int|array $products
* @param bool $show_qty Should qty's be shown? Added in 2.6.0
* @param bool $return Return message rather than add it.
*/
function wc_add_to_cart_message( $products, $show_qty = false ) {
function wc_add_to_cart_message( $products, $show_qty = false, $return = false ) {
$titles = array();
$count = 0;
if ( ! is_array( $products ) ) {
$products = array( $products );
$products = array( $products => 1 );
$show_qty = false;
}
@ -115,7 +116,13 @@ function wc_add_to_cart_message( $products, $show_qty = false ) {
$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 ) );
}
wc_add_notice( apply_filters( 'wc_add_to_cart_message', $message, $product_id ) );
$message = apply_filters( 'wc_add_to_cart_message', $message, $product_id );
if ( $return ) {
return $message;
} else {
wc_add_notice( $message );
}
}
/**

View File

@ -668,6 +668,9 @@ function wc_format_postcode( $postcode, $country ) {
case 'JP' :
$postcode = trim( substr_replace( $postcode, '-', 3, 0 ) );
break;
case 'PL' :
$postcode = trim( substr_replace( $postcode, '-', -3, 0 ) );
break;
case 'PT' :
$postcode = trim( substr_replace( $postcode, '-', 4, 0 ) );
break;

View File

@ -860,7 +860,7 @@ function wc_create_refund( $args = array() ) {
$order = wc_get_order( $args['order_id'] );
// Refund currency is the same used for the parent order
update_post_meta( $refund_id, '_order_currency', $order->get_order_currency() );
update_post_meta( $refund_id, '_order_currency', $order->get_currency() );
// Negative line items
if ( sizeof( $args['line_items'] ) > 0 ) {
@ -917,7 +917,7 @@ function wc_create_refund( $args = array() ) {
$refund->calculate_totals( false );
// Set total to total refunded which may vary from order items
$refund->set_total( wc_format_decimal( $args['amount'] ) * -1, 'total' );
$refund->set_total( wc_format_decimal( $args['amount'] ) * -1 );
do_action( 'woocommerce_refund_created', $refund_id, $args );
}
@ -1065,3 +1065,134 @@ function wc_order_search( $term ) {
return $post_ids;
}
/**
* Update total sales amount for each product within a paid order.
*
* @since 2.7.0
* @param int $order_id
*/
function wc_update_total_sales_counts( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order || 'yes' === get_post_meta( $order_id, '_recorded_sales', true ) ) {
return;
}
if ( sizeof( $order->get_items() ) > 0 ) {
foreach ( $order->get_items() as $item ) {
if ( $item['product_id'] > 0 ) {
update_post_meta( $item['product_id'], 'total_sales', absint( get_post_meta( $item['product_id'], 'total_sales', true ) ) + absint( $item['qty'] ) );
}
}
}
update_post_meta( $order_id, '_recorded_sales', 'yes' );
/**
* Called when sales for an order are recorded
*
* @param int $order_id order id
*/
do_action( 'woocommerce_recorded_sales', $order_id );
}
add_action( 'woocommerce_order_status_completed', 'wc_update_total_sales_counts' );
add_action( 'woocommerce_order_status_processing', 'wc_update_total_sales_counts' );
add_action( 'woocommerce_order_status_on-hold', 'wc_update_total_sales_counts' );
/**
* Update used coupon amount for each coupon within an order.
*
* @since 2.7.0
* @param int $order_id
*/
function wc_update_coupon_usage_counts( $order_id ) {
$order = wc_get_order( $order_id );
$has_recorded = get_post_meta( $order_id, '_recorded_coupon_usage_counts', true );
if ( ! $order ) {
return;
}
if ( $order->has_status( 'cancelled' ) && 'yes' === $has_recorded ) {
$action = 'reduce';
delete_post_meta( $order_id, '_recorded_coupon_usage_counts' );
} elseif ( ! $order->has_status( 'cancelled' ) && 'yes' !== $has_recorded ) {
$action = 'increase';
update_post_meta( $order_id, '_recorded_coupon_usage_counts', 'yes' );
} else {
return;
}
if ( sizeof( $order->get_used_coupons() ) > 0 ) {
foreach ( $order->get_used_coupons() as $code ) {
if ( ! $code ) {
continue;
}
$coupon = new WC_Coupon( $code );
if ( ! $used_by = $order->get_user_id() ) {
$used_by = $order->get_billing_email();
}
switch ( $action ) {
case 'reduce' :
$coupon->dcr_usage_count( $used_by );
break;
case 'increase' :
$coupon->inc_usage_count( $used_by );
break;
}
}
}
}
add_action( 'woocommerce_order_status_completed', 'wc_update_total_sales_counts' );
add_action( 'woocommerce_order_status_processing', 'wc_update_total_sales_counts' );
add_action( 'woocommerce_order_status_on-hold', 'wc_update_total_sales_counts' );
add_action( 'woocommerce_order_status_cancelled', 'wc_update_total_sales_counts' );
/**
* When a payment is complete, we can reduce stock levels for items within an order.
* @since 2.7.0
* @param int $order_id
*/
function wc_maybe_reduce_stock_levels( $order_id ) {
if ( apply_filters( 'woocommerce_payment_complete_reduce_order_stock', ! get_post_meta( $order_id, '_order_stock_reduced', true ), $order_id ) ) {
wc_reduce_stock_levels( $order_id );
add_post_meta( $order_id, '_order_stock_reduced', '1', true );
}
}
add_action( 'woocommerce_payment_complete', 'wc_maybe_reduce_stock_levels' );
/**
* Reduce stock levels for items within an order.
* @since 2.7.0
* @param int $order_id
*/
function wc_reduce_stock_levels( $order_id ) {
$order = wc_get_order( $order_id );
if ( 'yes' === get_option( 'woocommerce_manage_stock' ) && $order && apply_filters( 'woocommerce_can_reduce_order_stock', true, $order ) && sizeof( $order->get_items() ) > 0 ) {
foreach ( $order->get_items() as $item ) {
if ( $item->is_type( 'line_item' ) && ( $product = $item->get_product() ) && $product->managing_stock() ) {
$qty = apply_filters( 'woocommerce_order_item_quantity', $item['qty'], $order, $item );
$new_stock = $product->reduce_stock( $qty );
$item_name = $product->get_sku() ? $product->get_sku(): $item['product_id'];
if ( ! empty( $item['variation_id'] ) ) {
$order->add_order_note( sprintf( __( 'Item %s variation #%s stock reduced from %s to %s.', 'woocommerce' ), $item_name, $item['variation_id'], $new_stock + $qty, $new_stock ) );
} else {
$order->add_order_note( sprintf( __( 'Item %s stock reduced from %s to %s.', 'woocommerce' ), $item_name, $new_stock + $qty, $new_stock ) );
}
if ( $new_stock < 0 ) {
do_action( 'woocommerce_product_on_backorder', array( 'product' => $product, 'order_id' => $order_id, 'quantity' => $qty_ordered ) );
}
}
}
do_action( 'woocommerce_reduce_order_stock', $order );
}
}

View File

@ -306,9 +306,10 @@ function wc_rest_check_product_term_permissions( $taxonomy, $context = 'read', $
*/
function wc_rest_check_manager_permissions( $object, $context = 'read' ) {
$objects = array(
'reports' => 'view_woocommerce_reports',
'settings' => 'manage_woocommerce',
'attributes' => 'manage_product_terms',
'reports' => 'view_woocommerce_reports',
'settings' => 'manage_woocommerce',
'system_status' => 'manage_woocommerce',
'attributes' => 'manage_product_terms',
);
$permission = current_user_can( $objects[ $object ] );

View File

@ -27,7 +27,7 @@ function wc_template_redirect() {
}
// When on the checkout with an empty cart, redirect to cart page
elseif ( is_page( wc_get_page_id( 'checkout' ) ) && WC()->cart->is_empty() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ) {
elseif ( is_page( wc_get_page_id( 'checkout' ) ) && wc_get_page_id( 'checkout' ) !== wc_get_page_id( 'cart' ) && WC()->cart->is_empty() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ) {
wc_add_notice( __( 'Checkout is not available whilst your cart is empty.', 'woocommerce' ), 'notice' );
wp_redirect( wc_get_page_permalink( 'cart' ) );
exit;
@ -337,6 +337,40 @@ function wc_product_post_class( $classes, $class = '', $post_id = '' ) {
return $classes;
}
/**
* Outputs hidden form inputs for each query string variable.
* @since 2.7.0
* @param array $values Name value pairs.
* @param array $exclude Keys to exclude.
* @param string $current_key Current key we are outputting.
*/
function wc_query_string_form_fields( $values = null, $exclude = array(), $current_key = '', $return = false ) {
if ( is_null( $values ) ) {
$values = $_GET;
}
$html = '';
foreach ( $values as $key => $value ) {
if ( in_array( $key, $exclude, true ) ) {
continue;
}
if ( $current_key ) {
$key = $current_key . '[' . $key . ']';
}
if ( is_array( $value ) ) {
$html .= wc_query_string_form_fields( $value, $exclude, $key, true );
} else {
$html .= '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
}
}
if ( $return ) {
return $html;
} else {
echo $html;
}
}
/** Template pages ********************************************************/
if ( ! function_exists( 'woocommerce_content' ) ) {
@ -606,7 +640,7 @@ if ( ! function_exists( 'woocommerce_product_archive_description' ) ) {
if ( is_search() ) {
return;
}
if ( is_post_type_archive( 'product' ) && 0 === absint( get_query_var( 'paged' ) ) ) {
$shop_page = get_post( wc_get_page_id( 'shop' ) );
if ( $shop_page ) {
@ -1085,7 +1119,7 @@ if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
}
// Additional information tab - shows attributes
if ( $product && ( $product->has_attributes() || ( $product->enable_dimensions_display() && ( $product->has_dimensions() || $product->has_weight() ) ) ) ) {
if ( $product && ( $product->has_attributes() || $product->enable_dimensions_display() ) ) {
$tabs['additional_information'] = array(
'title' => __( 'Additional Information', 'woocommerce' ),
'priority' => 20,
@ -1334,7 +1368,29 @@ if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
}
}
if ( ! function_exists( 'woocommerce_widget_shopping_cart_button_view_cart' ) ) {
/**
* Output the proceed to checkout button.
*
* @subpackage Cart
*/
function woocommerce_widget_shopping_cart_button_view_cart() {
echo '<a href="' . esc_url( wc_get_cart_url() ) . '" class="button wc-forward">' . __( 'View Cart', 'woocommerce' ) . '</a>';
}
}
if ( ! function_exists( 'woocommerce_widget_shopping_cart_proceed_to_checkout' ) ) {
/**
* Output the proceed to checkout button.
*
* @subpackage Cart
*/
function woocommerce_widget_shopping_cart_proceed_to_checkout() {
echo '<a href="' . esc_url( wc_get_checkout_url() ) . '" class="button checkout wc-forward">' . __( 'Checkout', 'woocommerce' ) . '</a>';
}
}
/** Mini-Cart *************************************************************/
@ -1672,10 +1728,13 @@ if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
$thumbnail_id = get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true );
if ( $thumbnail_id ) {
$image = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size );
$image = $image[0];
$image = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size );
$image = $image[0];
$image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false;
$image_sizes = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false;
} else {
$image = wc_placeholder_img_src();
$image = wc_placeholder_img_src();
$image_srcset = $image_sizes = false;
}
if ( $image ) {
@ -1683,7 +1742,12 @@ if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
// Ref: https://core.trac.wordpress.org/ticket/23605
$image = str_replace( ' ', '%20', $image );
echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
// Add responsive image markup if available
if ( $image_srcset && $image_sizes ) {
echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" srcset="' . esc_attr( $image_srcset ) . '" sizes="' . esc_attr( $image_sizes ) . '" />';
} else {
echo '<img src="' . esc_url( $image ) . '" alt="' . esc_attr( $category->name ) . '" width="' . esc_attr( $dimensions['width'] ) . '" height="' . esc_attr( $dimensions['height'] ) . '" />';
}
}
}
}
@ -1961,11 +2025,19 @@ if ( ! function_exists( 'get_product_search_form' ) ) {
* @return string
*/
function get_product_search_form( $echo = true ) {
global $product_search_form_index;
ob_start();
if ( empty( $product_search_form_index ) ) {
$product_search_form_index = 0;
}
do_action( 'pre_get_product_search_form' );
wc_get_template( 'product-searchform.php' );
wc_get_template( 'product-searchform.php', array(
'index' => $product_search_form_index++,
) );
$form = apply_filters( 'get_product_search_form', ob_get_clean() );
@ -2204,3 +2276,126 @@ if ( ! function_exists( 'woocommerce_account_edit_account' ) ) {
WC_Shortcode_My_Account::edit_account();
}
}
if ( ! function_exists( 'wc_get_email_order_items' ) ) {
/**
* Get HTML for the order items to be shown in emails.
* @param WC_Order $order
* @param array $args
* @since 2.7.0
*/
function wc_get_email_order_items( $order, $args = array() ) {
ob_start();
$defaults = array(
'show_sku' => false,
'show_image' => false,
'image_size' => array( 32, 32 ),
'plain_text' => false
);
$args = wp_parse_args( $args, $defaults );
$template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
wc_get_template( $template, array(
'order' => $order,
'items' => $order->get_items(),
'show_download_links' => $order->is_download_permitted(),
'show_sku' => $args['show_sku'],
'show_purchase_note' => $order->is_paid(),
'show_image' => $args['show_image'],
'image_size' => $args['image_size'],
) );
return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order );
}
}
if ( ! function_exists( 'wc_display_item_meta' ) ) {
/**
* Display item meta data.
* @since 2.7.0
* @param WC_Item $item
* @param array $args
* @return string|void
*/
function wc_display_item_meta( $item, $args = array() ) {
$strings = array();
$html = '';
$args = wp_parse_args( $args, array(
'before' => '<ul class="wc-item-meta"><li>',
'after' => '</li></ul>',
'separator' => '</li><li>',
'echo' => true,
'autop' => false,
) );
foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) {
if ( '_' === substr( $meta->key, 0, 1 ) ) {
continue;
}
$value = $args['autop'] ? wp_kses_post( wpautop( make_clickable( $meta->display_value ) ) ) : wp_kses_post( make_clickable( $meta->display_value ) );
$strings[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $value;
}
if ( $strings ) {
$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
}
$html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args );
if ( $args['echo'] ) {
echo $html;
} else {
return $html;
}
}
}
if ( ! function_exists( 'wc_display_item_downloads' ) ) {
/**
* Display item download links.
* @since 2.7.0
* @param WC_Item $item
* @param array $args
* @return string|void
*/
function wc_display_item_downloads( $item, $args = array() ) {
$strings = array();
$html = '';
$args = wp_parse_args( $args, array(
'before' => '<ul class ="wc-item-downloads"><li>',
'after' => '</li></ul>',
'separator' => '</li><li>',
'echo' => true,
'show_url' => false,
) );
if ( is_object( $item ) && $item->is_type( 'line_item' ) && ( $downloads = $item->get_item_downloads() ) ) {
$i = 0;
foreach ( $downloads as $file ) {
$i ++;
if ( $args['show_url'] ) {
$strings[] = '<strong class="wc-item-download-label">' . esc_html( $file['name'] ) . ':</strong> ' . esc_html( $file['download_url'] );
} else {
$prefix = sizeof( $downloads ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
$strings[] = '<strong class="wc-item-download-label">' . $prefix . ':</strong> <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a>';
}
}
}
if ( $strings ) {
$html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
}
$html = apply_filters( 'woocommerce_display_item_downloads', $html, $item, $args );
if ( $args['echo'] ) {
echo $html;
} else {
return $html;
}
}
}

View File

@ -204,6 +204,11 @@ add_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_for
add_action( 'woocommerce_checkout_order_review', 'woocommerce_order_review', 10 );
add_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 );
/**
* Cart widget
*/
add_action( 'woocommerce_widget_shopping_cart_buttons', 'woocommerce_widget_shopping_cart_button_view_cart', 10 );
add_action( 'woocommerce_widget_shopping_cart_buttons', 'woocommerce_widget_shopping_cart_proceed_to_checkout', 20 );
/**
* Cart.

View File

@ -970,3 +970,20 @@ function wc_update_260_refunds() {
function wc_update_260_db_version() {
WC_Install::update_db_version( '2.6.0' );
}
function wc_update_270_webhooks() {
/**
* Make sure product.update webhooks get the woocommerce_product_quick_edit_save
* and woocommerce_product_bulk_edit_save hooks.
*/
$product_update_webhooks = get_posts( array(
'posts_per_page' => -1,
'post_type' => 'shop_webhook',
'meta_key' => '_topic',
'meta_value' => 'product.updated'
) );
foreach ( $product_update_webhooks as $product_update_webhook ) {
$webhook = new WC_Webhook( $product_update_webhook->ID );
$webhook->set_topic( 'product.updated' );
}
}

View File

@ -176,17 +176,18 @@ function wc_update_new_customer_past_orders( $customer_id ) {
* @param int $order_id
*/
function wc_paying_customer( $order_id ) {
$order = wc_get_order( $order_id );
$order = wc_get_order( $order_id );
$customer_id = $order->get_customer_id();
if ( $order->user_id > 0 && 'refund' !== $order->order_type ) {
update_user_meta( $order->user_id, 'paying_customer', 1 );
if ( $customer_id > 0 && 'refund' !== $order->get_type() ) {
update_user_meta( $customer_id, 'paying_customer', 1 );
$old_spent = absint( get_user_meta( $order->user_id, '_money_spent', true ) );
update_user_meta( $order->user_id, '_money_spent', $old_spent + $order->order_total );
$old_spent = absint( get_user_meta( $customer_id, '_money_spent', true ) );
update_user_meta( $customer_id, '_money_spent', $old_spent + $order->order_total );
}
if ( $order->user_id > 0 && 'simple' === $order->order_type ) {
$old_count = absint( get_user_meta( $order->user_id, '_order_count', true ) );
update_user_meta( $order->user_id, '_order_count', $old_count + 1 );
if ( $customer_id > 0 && 'shop_order' === $order->get_type() ) {
$old_count = absint( get_user_meta( $customer_id, '_order_count', true ) );
update_user_meta( $customer_id, '_order_count', $old_count + 1 );
}
}
add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' );
@ -446,7 +447,7 @@ function wc_get_customer_available_downloads( $customer_id ) {
array(
'download_file' => $product_id,
'order' => $result->order_key,
'email' => $result->user_email,
'email' => urlencode( $result->user_email ),
'key' => $result->download_id
),
home_url( '/' )

View File

@ -68,45 +68,6 @@ class WC_Widget_Price_Filter extends WC_Widget {
wp_enqueue_script( 'wc-price-slider' );
// Remember current filters/search
$fields = '';
if ( get_search_query() ) {
$fields .= '<input type="hidden" name="s" value="' . get_search_query() . '" />';
}
if ( ! empty( $_GET['post_type'] ) ) {
$fields .= '<input type="hidden" name="post_type" value="' . esc_attr( $_GET['post_type'] ) . '" />';
}
if ( ! empty ( $_GET['product_cat'] ) ) {
$fields .= '<input type="hidden" name="product_cat" value="' . esc_attr( $_GET['product_cat'] ) . '" />';
}
if ( ! empty( $_GET['product_tag'] ) ) {
$fields .= '<input type="hidden" name="product_tag" value="' . esc_attr( $_GET['product_tag'] ) . '" />';
}
if ( ! empty( $_GET['orderby'] ) ) {
$fields .= '<input type="hidden" name="orderby" value="' . esc_attr( $_GET['orderby'] ) . '" />';
}
if ( ! empty( $_GET['min_rating'] ) ) {
$fields .= '<input type="hidden" name="min_rating" value="' . esc_attr( $_GET['min_rating'] ) . '" />';
}
if ( $_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes() ) {
foreach ( $_chosen_attributes as $attribute => $data ) {
$taxonomy_filter = 'filter_' . str_replace( 'pa_', '', $attribute );
$fields .= '<input type="hidden" name="' . esc_attr( $taxonomy_filter ) . '" value="' . esc_attr( implode( ',', $data['terms'] ) ) . '" />';
if ( 'or' == $data['query_type'] ) {
$fields .= '<input type="hidden" name="' . esc_attr( str_replace( 'pa_', 'query_type_', $attribute ) ) . '" value="or" />';
}
}
}
// Find min and max price in current result set
$prices = $this->get_filtered_price();
$min = floor( $prices->min_price );
@ -152,7 +113,7 @@ class WC_Widget_Price_Filter extends WC_Widget {
<div class="price_label" style="display:none;">
' . __( 'Price:', 'woocommerce' ) . ' <span class="from"></span> &mdash; <span class="to"></span>
</div>
' . $fields . '
' . wc_query_string_form_fields( null, array( 'min_price', 'max_price' ), '', true ) . '
<div class="clear"></div>
</div>
</div>

View File

@ -75,14 +75,14 @@ class WC_Widget_Recently_Viewed extends WC_Widget {
$this->widget_start( $args, $instance );
echo '<ul class="product_list_widget">';
echo apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' );
while ( $r->have_posts() ) {
$r->the_post();
wc_get_template( 'content-widget-product.php' );
}
echo '</ul>';
echo apply_filters( 'woocommerce_after_widget_product_list', '</ul>' );
$this->widget_end( $args );
}

View File

@ -74,14 +74,14 @@ class WC_Widget_Top_Rated_Products extends WC_Widget {
$this->widget_start( $args, $instance );
echo '<ul class="product_list_widget">';
echo apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' );
while ( $r->have_posts() ) {
$r->the_post();
wc_get_template( 'content-widget-product.php', array( 'show_rating' => true ) );
}
echo '</ul>';
echo apply_filters( 'woocommerce_after_widget_product_list', '</ul>' );
$this->widget_end( $args );
}

View File

@ -1,5 +1,5 @@
=== WooCommerce ===
Contributors: automattic, mikejolley, jameskoster, claudiosanches, jshreve, coderkevin, woothemes, BFTrick
Contributors: automattic, mikejolley, jameskoster, claudiosanches, jshreve, coderkevin, woothemes, BFTrick, iCaleb
Tags: ecommerce, e-commerce, store, sales, sell, shop, cart, checkout, downloadable, downloads, paypal, storefront
Requires at least: 4.4
Tested up to: 4.5
@ -162,6 +162,11 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
* Respect stock status and prevent the "out of stock threshold" setting affecting existing in-stock products.
* Added Nigerian Provinces to i18n/state.
* Improved handling of shop page rewrite rules to allow subpages.
* Redirect to login after password reset.
* When using authorizations in PayPal standard, automatically capture funds when the order goes processing/completed.
* On multisite, when a user logs into a store with an account on a site, but not the current site, rather than error, add the user to the current site as a customer.
* Show variable weights/dimensions even when parent values are not set.
* Automatically sort tax rates rather than allow clunky manual sorting.
[See changelog for all versions](https://raw.githubusercontent.com/woothemes/woocommerce/master/CHANGELOG.txt).

View File

@ -31,7 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php if ( ! WC()->cart->is_empty() ) : ?>
<?php do_action( 'woocommerce_before_mini_cart_contents' ); ?>
<?php
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
@ -70,7 +70,7 @@ if ( ! defined( 'ABSPATH' ) ) {
?>
<?php do_action( 'woocommerce_mini_cart_contents' ); ?>
<?php else : ?>
<li class="empty"><?php _e( 'No products in the cart.', 'woocommerce' ); ?></li>
@ -86,8 +86,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php do_action( 'woocommerce_widget_shopping_cart_before_buttons' ); ?>
<p class="buttons">
<a href="<?php echo esc_url( wc_get_cart_url() ); ?>" class="button wc-forward"><?php _e( 'View Cart', 'woocommerce' ); ?></a>
<a href="<?php echo esc_url( wc_get_checkout_url() ); ?>" class="button checkout wc-forward"><?php _e( 'Checkout', 'woocommerce' ); ?></a>
<?php do_action( 'woocommerce_widget_shopping_cart_buttons' ); ?>
</p>
<?php endif; ?>

View File

@ -27,19 +27,5 @@ if ( ! defined( 'ABSPATH' ) ) {
<option value="<?php echo esc_attr( $id ); ?>" <?php selected( $orderby, $id ); ?>><?php echo esc_html( $name ); ?></option>
<?php endforeach; ?>
</select>
<?php
// Keep query string vars intact
foreach ( $_GET as $key => $val ) {
if ( 'orderby' === $key || 'submit' === $key ) {
continue;
}
if ( is_array( $val ) ) {
foreach( $val as $innerVal ) {
echo '<input type="hidden" name="' . esc_attr( $key ) . '[]" value="' . esc_attr( $innerVal ) . '" />';
}
} else {
echo '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $val ) . '" />';
}
}
?>
<?php wc_query_string_form_fields( null, array( 'orderby', 'submit' ) ); ?>
</form>

View File

@ -16,16 +16,14 @@
* @version 2.5.0
*/
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<form role="search" method="get" class="woocommerce-product-search" action="<?php echo esc_url( home_url( '/' ) ); ?>">
<label class="screen-reader-text" for="woocommerce-product-search-field"><?php _e( 'Search for:', 'woocommerce' ); ?></label>
<input type="search" id="woocommerce-product-search-field" class="search-field" placeholder="<?php echo esc_attr_x( 'Search Products&hellip;', 'placeholder', 'woocommerce' ); ?>" value="<?php echo get_search_query(); ?>" name="s" title="<?php echo esc_attr_x( 'Search for:', 'label', 'woocommerce' ); ?>" />
<label class="screen-reader-text" for="woocommerce-product-search-field-<?php echo isset( $index ) ? absint( $index ) : 0; ?>"><?php _e( 'Search for:', 'woocommerce' ); ?></label>
<input type="search" id="woocommerce-product-search-field-<?php echo isset( $index ) ? absint( $index ) : 0; ?>" class="search-field" placeholder="<?php echo esc_attr_x( 'Search Products&hellip;', 'placeholder', 'woocommerce' ); ?>" value="<?php echo get_search_query(); ?>" name="s" title="<?php echo esc_attr_x( 'Search for:', 'label', 'woocommerce' ); ?>" />
<input type="submit" value="<?php echo esc_attr_x( 'Search', 'submit button', 'woocommerce' ); ?>" />
<input type="hidden" name="post_type" value="product" />
</form>

View File

@ -33,17 +33,17 @@ ob_start();
<?php if ( $product->enable_dimensions_display() ) : ?>
<?php if ( $product->has_weight() ) : $has_row = true; ?>
<?php if ( $product->has_weight() || get_post_meta( $product->id, '_child_has_weight', true ) ) : $has_row = true; ?>
<tr class="<?php if ( ( $alt = $alt * -1 ) === 1 ) echo 'alt'; ?>">
<th><?php _e( 'Weight', 'woocommerce' ) ?></th>
<td class="product_weight"><?php echo wc_format_localized_decimal( $product->get_weight() ) . ' ' . esc_attr( get_option( 'woocommerce_weight_unit' ) ); ?></td>
<td class="product_weight"><?php echo $product->get_weight() ? wc_format_localized_decimal( $product->get_weight() ) . ' ' . esc_attr( get_option( 'woocommerce_weight_unit' ) ) : __( 'N/A', 'woocommerce' ); ?></td>
</tr>
<?php endif; ?>
<?php if ( $product->has_dimensions() ) : $has_row = true; ?>
<?php if ( $product->has_dimensions() || get_post_meta( $product->id, '_child_has_dimensions', true ) ) : $has_row = true; ?>
<tr class="<?php if ( ( $alt = $alt * -1 ) === 1 ) echo 'alt'; ?>">
<th><?php _e( 'Dimensions', 'woocommerce' ) ?></th>
<td class="product_dimensions"><?php echo $product->get_dimensions(); ?></td>
<td class="product_dimensions"><?php echo $product->get_dimensions() ? $product->get_dimensions() : __( 'N/A', 'woocommerce' ); ?></td>
</tr>
<?php endif; ?>

View File

@ -13,11 +13,11 @@
* @see https://docs.woocommerce.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
* @version 2.6.0
* @version 2.7.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
global $comment;
@ -25,18 +25,18 @@ $verified = wc_review_is_from_verified_owner( $comment->comment_ID );
if ( '0' === $comment->comment_approved ) { ?>
<p class="meta"><em><?php esc_attr_e( 'Your comment is awaiting approval', 'woocommerce' ); ?></em></p>
<p class="meta"><em class="woocommerce-review__awaiting-approval"><?php esc_attr_e( 'Your review is awaiting approval', 'woocommerce' ); ?></em></p>
<?php } else { ?>
<p class="meta">
<strong><?php comment_author(); ?></strong> <?php
<strong class="woocommerce-review__author" itemprop="author"><?php comment_author(); ?></strong> <?php
if ( 'yes' === get_option( 'woocommerce_review_rating_verification_label' ) && $verified ) {
echo '<em class="verified">(' . esc_attr__( 'verified owner', 'woocommerce' ) . ')</em> ';
echo '<em class="woocommerce-review__verified verified">(' . esc_attr__( 'verified owner', 'woocommerce' ) . ')</em> ';
}
?>&ndash; <time datetime="<?php echo get_comment_date( 'c' ); ?>"><?php echo get_comment_date( wc_date_format() ); ?></time>:
?><span class="woocommerce-review__dash">&ndash;</span> <time class="woocommerce-review__published-date" itemprop="datePublished" datetime="<?php echo get_comment_date( 'c' ); ?>"><?php echo get_comment_date( wc_date_format() ); ?></time>
</p>
<?php }

View File

@ -26,4 +26,7 @@ if ( ! $post->post_excerpt ) {
return;
}
echo apply_filters( 'woocommerce_short_description', $post->post_excerpt );
?>
<div class="woocommerce-product-details__short-description">
<?php echo apply_filters( 'woocommerce_short_description', $post->post_excerpt ); ?>
</div>

View File

@ -51,7 +51,7 @@ class WC_Helper_Order {
$order = wc_create_order( $order_data );
// Add order products
$item_id = $order->add_product( $product, 4 );
$item_id = $order->add_product( $product, array( 'qty' => 4 ) );
// Set billing address
$billing_address = array(
@ -78,13 +78,13 @@ class WC_Helper_Order {
$order->set_payment_method( $payment_gateways['bacs'] );
// Set totals
$order->set_total( 10, 'shipping' );
$order->set_total( 0, 'cart_discount' );
$order->set_total( 0, 'cart_discount_tax' );
$order->set_total( 0, 'tax' );
$order->set_total( 0, 'shipping_tax' );
$order->set_total( 40, 'total' ); // 4 x $10 simple helper product
$order->set_shipping_total( 10 );
$order->set_discount_total( 0 );
$order->set_discount_tax( 0 );
$order->set_cart_tax( 0 );
$order->set_shipping_tax( 0 );
$order->set_total( 40 ); // 4 x $10 simple helper product
return wc_get_order( $order->id );
return wc_get_order( $order->get_id() );
}
}

View File

@ -239,4 +239,27 @@ class WC_Helper_Product {
$wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_id = $attribute_id" );
}
/**
* Creates a new product review on a specific product.
*
* @since 2.7
* @param $product_id integer Product ID that the review is for
* @param $revieww_content string Content to use for the product review
* @return integer Product Review ID
*/
public static function create_product_review( $product_id, $review_content = 'Review content here' ) {
$data = array(
'comment_post_ID' => $product_id,
'comment_author' => 'admin',
'comment_author_email' => 'woo@woo.local',
'comment_author_url' => '',
'comment_date' => '2016-01-01T11:11:11',
'comment_content' => $review_content,
'comment_approved' => 1,
'comment_type' => 'review',
);
return wp_insert_comment( $data );
}
}

View File

@ -0,0 +1,423 @@
<?php
/**
* Tests for the product reviews REST API.
*
* @package WooCommerce\Tests\API
* @since 2.7.0
*/
class Product_Reviews extends WC_REST_Unit_Test_Case {
/**
* Setup our test server, endpoints, and user info.
*/
public function setUp() {
parent::setUp();
$this->endpoint = new WC_REST_Product_Reviews_Controller();
$this->user = $this->factory->user->create( array(
'role' => 'administrator',
) );
}
/**
* Test route registration.
*
* @since 2.7.0
*/
public function test_register_routes() {
$routes = $this->server->get_routes();
$this->assertArrayHasKey( '/wc/v1/products/(?P<product_id>[\d]+)/reviews', $routes );
$this->assertArrayHasKey( '/wc/v1/products/(?P<product_id>[\d]+)/reviews/(?P<id>[\d]+)', $routes );
}
/**
* Test getting all product reviews.
*
* @since 2.7.0
*/
public function test_get_product_reviews() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
// Create 10 products reviews for the product
for ( $i = 0; $i < 10; $i++ ) {
WC_Helper_Product::create_product_review( $product->id );
}
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/products/' . $product->id . '/reviews' ) );
$product_reviews = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 10, count( $product_reviews ) );
$this->assertContains( array(
'id' => 2,
'date_created' => '2016-01-01T11:11:11',
'review' => 'Review content here',
'rating' => 0,
'name' => 'admin',
'email' => 'woo@woo.local',
'verified' => false,
'_links' => array(
'self' => array(
array(
'href' => rest_url( '/wc/v1/products/' . $product->id . '/reviews/2' ),
),
),
'collection' => array(
array(
'href' => rest_url( '/wc/v1/products/' . $product->id . '/reviews' ),
),
),
'up' => array(
array(
'href' => rest_url( '/wc/v1/products/' . $product->id ),
),
),
),
), $product_reviews );
}
/**
* Tests to make sure product reviews cannot be viewed without valid permissions.
*
* @since 2.7.0
*/
public function test_get_product_reviews_without_permission() {
wp_set_current_user( 0 );
$product = WC_Helper_Product::create_simple_product();
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/products/' . $product->id . '/reviews' ) );
$this->assertEquals( 401, $response->get_status() );
}
/**
* Tests to make sure an error is returned when an invalid product is loaded.
*
* @since 2.7.0
*/
public function test_get_product_reviews_invalid_product() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/products/0/reviews' ) );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Tests getting a single product review.
*
* @since 2.7.0
*/
public function test_get_product_review() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$product_review_id = WC_Helper_Product::create_product_review( $product->id );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/products/' . $product->id . '/reviews/' . $product_review_id ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( array(
'id' => $product_review_id ,
'date_created' => '2016-01-01T11:11:11',
'review' => 'Review content here',
'rating' => 0,
'name' => 'admin',
'email' => 'woo@woo.local',
'verified' => false,
), $data );
}
/**
* Tests getting a single product review without the correct permissions.
*
* @since 2.7.0
*/
public function test_get_product_review_without_permission() {
wp_set_current_user( 0 );
$product = WC_Helper_Product::create_simple_product();
$product_review_id = WC_Helper_Product::create_product_review( $product->id );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/products/' . $product->id . '/reviews/' . $product_review_id ) );
$this->assertEquals( 401, $response->get_status() );
}
/**
* Tests getting a product review with an invalid ID.
*
* @since 2.7.0
*/
public function test_get_product_review_invalid_id() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/products/' . $product->id . '/reviews/0' ) );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Tests creating a product review.
*
* @since 2.7.0
*/
public function test_create_product_review() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$request = new WP_REST_Request( 'POST', '/wc/v1/products/' . $product->id . '/reviews' );
$request->set_body_params( array(
'review' => 'Hello world.',
'name' => 'Admin',
'email' => 'woo@woo.local',
'rating' => '5',
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 201, $response->get_status() );
$this->assertEquals( array(
'id' => $data['id'],
'date_created' => $data['date_created'],
'review' => 'Hello world.',
'rating' => 5,
'name' => 'Admin',
'email' => 'woo@woo.local',
'verified' => false,
), $data );
}
/**
* Tests creating a product review without required fields.
*
* @since 2.7.0
*/
public function test_create_product_review_invalid_fields() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
// missing review
$request = new WP_REST_Request( 'POST', '/wc/v1/products/' . $product->id . '/reviews' );
$request->set_body_params( array(
'name' => 'Admin',
'email' => 'woo@woo.local',
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 400, $response->get_status() );
// missing name
$request = new WP_REST_Request( 'POST', '/wc/v1/products/' . $product->id . '/reviews' );
$request->set_body_params( array(
'review' => 'Hello world.',
'email' => 'woo@woo.local',
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 400, $response->get_status() );
// missing email
$request = new WP_REST_Request( 'POST', '/wc/v1/products/' . $product->id . '/reviews' );
$request->set_body_params( array(
'review' => 'Hello world.',
'name' => 'Admin',
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 400, $response->get_status() );
}
/**
* Tests updating a product review.
*
* @since 2.7.0
*/
public function test_update_product_review() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$product_review_id = WC_Helper_Product::create_product_review( $product->id );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/products/' . $product->id . '/reviews/' . $product_review_id ) );
$data = $response->get_data();
$this->assertEquals( 'Review content here', $data['review'] );
$this->assertEquals( 'admin', $data['name'] );
$this->assertEquals( 'woo@woo.local', $data['email'] );
$this->assertEquals( 0, $data['rating'] );
$request = new WP_REST_Request( 'PUT', '/wc/v1/products/' . $product->id . '/reviews/' . $product_review_id );
$request->set_body_params( array(
'review' => 'Hello world - updated.',
'name' => 'Justin',
'email' => 'woo2@woo.local',
'rating' => 3,
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 'Hello world - updated.', $data['review'] );
$this->assertEquals( 'Justin', $data['name'] );
$this->assertEquals( 'woo2@woo.local', $data['email'] );
$this->assertEquals( 3, $data['rating'] );
}
/**
* Tests updating a product review without the correct permissions.
*
* @since 2.7.0
*/
public function test_update_product_review_without_permission() {
wp_set_current_user( 0 );
$product = WC_Helper_Product::create_simple_product();
$product_review_id = WC_Helper_Product::create_product_review( $product->id );
$request = new WP_REST_Request( 'PUT', '/wc/v1/products/' . $product->id . '/reviews/' . $product_review_id );
$request->set_body_params( array(
'review' => 'Hello world.',
'name' => 'Admin',
'email' => 'woo@woo.dev',
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 401, $response->get_status() );
}
/**
* Tests that updating a product review with an invalid id fails.
*
* @since 2.7.0
*/
public function test_update_product_review_invalid_id() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$request = new WP_REST_Request( 'PUT', '/wc/v1/products/' . $product->id . '/reviews/0' );
$request->set_body_params( array(
'review' => 'Hello world.',
'name' => 'Admin',
'email' => 'woo@woo.dev',
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 404, $response->get_status() );
}
/**
* Test deleting a product review.
*
* @since 2.7.0
*/
public function test_delete_product_review() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$product_review_id = WC_Helper_Product::create_product_review( $product->id );
$request = new WP_REST_Request( 'DELETE', '/wc/v1/products/' . $product->id . '/reviews/' . $product_review_id );
$request->set_param( 'force', true );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
}
/**
* Test deleting a product review without permission/creds.
*
* @since 2.7.0
*/
public function test_delete_product_without_permission() {
wp_set_current_user( 0 );
$product = WC_Helper_Product::create_simple_product();
$product_review_id = WC_Helper_Product::create_product_review( $product->id );
$request = new WP_REST_Request( 'DELETE', '/wc/v1/products/' . $product->id . '/reviews/' . $product_review_id );
$response = $this->server->dispatch( $request );
$this->assertEquals( 401, $response->get_status() );
}
/**
* Test deleting a product review with an invalid id.
*
* @since 2.7.0
*/
public function test_delete_product_review_invalid_id() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$product_review_id = WC_Helper_Product::create_product_review( $product->id );
$request = new WP_REST_Request( 'DELETE', '/wc/v1/products/' . $product->id . '/reviews/0' );
$request->set_param( 'force', true );
$response = $this->server->dispatch( $request );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Test batch managing product reviews.
*/
public function test_product_reviews_batch() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$review_1_id = WC_Helper_Product::create_product_review( $product->id );
$review_2_id = WC_Helper_Product::create_product_review( $product->id );
$review_3_id = WC_Helper_Product::create_product_review( $product->id );
$review_4_id = WC_Helper_Product::create_product_review( $product->id );
$request = new WP_REST_Request( 'POST', '/wc/v1/products/' . $product->id . '/reviews/batch' );
$request->set_body_params( array(
'update' => array(
array(
'id' => $review_1_id,
'review' => 'Updated review.',
),
),
'delete' => array(
array(
'id' => $review_2_id,
),
array(
'id' => $review_3_id,
),
),
'create' => array(
array(
'review' => 'New review.',
'name' => 'Justin',
'email' => 'woo3@woo.local',
),
),
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 'Updated review.', $data['update'][0]['review'] );
$this->assertEquals( 'New review.', $data['create'][0]['review'] );
$this->assertEquals( $review_2_id, $data['delete'][0]['id'] );
$this->assertEquals( $review_3_id, $data['delete'][1]['id'] );
$request = new WP_REST_Request( 'GET', '/wc/v1/products/' . $product->id . '/reviews' );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 3, count( $data ) );
}
/**
* Test the product review schema.
*
* @since 2.7.0
*/
public function test_product_review_schema() {
wp_set_current_user( $this->user );
$product = WC_Helper_Product::create_simple_product();
$request = new WP_REST_Request( 'OPTIONS', '/wc/v1/products/' . $product->id . '/reviews' );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$properties = $data['schema']['properties'];
$this->assertEquals( 7, count( $properties ) );
$this->assertArrayHasKey( 'id', $properties );
$this->assertArrayHasKey( 'review', $properties );
$this->assertArrayHasKey( 'date_created', $properties );
$this->assertArrayHasKey( 'rating', $properties );
$this->assertArrayHasKey( 'name', $properties );
$this->assertArrayHasKey( 'email', $properties );
$this->assertArrayHasKey( 'verified', $properties );
}
}

View File

@ -0,0 +1,559 @@
<?php
/**
* Shipping Zones API Tests
* @package WooCommerce\Tests\API
* @since 2.7.0
*/
class WC_Tests_API_Shipping_Zones extends WC_REST_Unit_Test_Case {
protected $server;
protected $endpoint;
protected $user;
protected $zones;
/**
* Setup our test server, endpoints, and user info.
*/
public function setUp() {
parent::setUp();
$this->endpoint = new WC_REST_Shipping_Zones_Controller();
$this->user = $this->factory->user->create( array(
'role' => 'administrator',
) );
$this->zones = array();
}
/**
* Delete zones.
*/
public function tearDown() {
parent::tearDown();
foreach( $this->zones as $zone ) {
$zone->delete();
}
}
/**
* Helper method to create a Shipping Zone.
*
* @param string $name Zone name.
* @param int $order Optional. Zone sort order.
* @return WC_Shipping_Zone
*/
protected function create_shipping_zone( $name, $order = 0, $locations = array() ) {
$zone = new WC_Shipping_Zone( null );
$zone->set_zone_name( $name );
$zone->set_zone_order( $order );
$zone->set_locations( $locations );
$zone->save();
$this->zones[] = $zone;
return $zone;
}
/**
* Test route registration.
* @since 2.7.0
*/
public function test_register_routes() {
$routes = $this->server->get_routes();
$this->assertArrayHasKey( '/wc/v1/shipping/zones', $routes );
$this->assertArrayHasKey( '/wc/v1/shipping/zones/(?P<id>[\d-]+)', $routes );
$this->assertArrayHasKey( '/wc/v1/shipping/zones/(?P<id>[\d-]+)/locations', $routes );
$this->assertArrayHasKey( '/wc/v1/shipping/zones/(?P<zone_id>[\d-]+)/methods', $routes );
$this->assertArrayHasKey( '/wc/v1/shipping/zones/(?P<zone_id>[\d-]+)/methods/(?P<instance_id>[\d-]+)', $routes );
}
/**
* Test getting all Shipping Zones.
* @since 2.7.0
*/
public function test_get_zones() {
wp_set_current_user( $this->user );
// "Rest of the World" zone exists by default
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones' ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 1 );
$this->assertContains( array(
'id' => 0,
'name' => 'Rest of the World',
'order' => 0,
'_links' => array(
'self' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/0' ),
),
),
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones' ),
),
),
'describedby' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/0/locations' ),
),
),
),
), $data );
// Create a zone and make sure it's in the response
$this->create_shipping_zone( 'Zone 1' );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones' ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 2 );
$this->assertContains( array(
'id' => 1,
'name' => 'Zone 1',
'order' => 0,
'_links' => array(
'self' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/1' ),
),
),
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones' ),
),
),
'describedby' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/1/locations' ),
),
),
),
), $data );
}
/**
* Test /shipping/zones without valid permissions/creds.
* @since 2.7.0
*/
public function test_get_shipping_zones_without_permission() {
wp_set_current_user( 0 );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones' ) );
$this->assertEquals( 401, $response->get_status() );
}
/**
* Test /shipping/zones while Shipping is disabled in WooCommerce.
* @since 2.7.0
*/
public function test_get_shipping_zones_disabled_shipping() {
wp_set_current_user( $this->user );
add_filter( 'wc_shipping_enabled', '__return_false' );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones' ) );
$this->assertEquals( 404, $response->get_status() );
remove_filter( 'wc_shipping_enabled', '__return_false' );
}
/**
* Test Shipping Zone schema.
* @since 2.7.0
*/
public function test_get_shipping_zone_schema() {
$request = new WP_REST_Request( 'OPTIONS', '/wc/v1/shipping/zones' );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$properties = $data['schema']['properties'];
$this->assertEquals( 3, count( $properties ) );
$this->assertArrayHasKey( 'id', $properties );
$this->assertTrue( $properties['id']['readonly'] );
$this->assertArrayHasKey( 'name', $properties );
$this->assertTrue( $properties['name']['required'] );
$this->assertArrayHasKey( 'order', $properties );
$this->assertFalse( $properties['order']['required'] );
}
/**
* Test Shipping Zone create endpoint.
* @since 2.7.0
*/
public function test_create_shipping_zone() {
wp_set_current_user( $this->user );
$request = new WP_REST_Request( 'POST', '/wc/v1/shipping/zones' );
$request->set_body_params( array(
'name' => 'Test Zone',
'order' => 1,
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 201, $response->get_status() );
$this->assertEquals( array(
'id' => $data['id'],
'name' => 'Test Zone',
'order' => 1,
'_links' => array(
'self' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $data['id'] ),
),
),
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones' ),
),
),
'describedby' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $data['id'] . '/locations' ),
),
),
),
), $data );
}
/**
* Test Shipping Zone create endpoint.
* @since 2.7.0
*/
public function test_create_shipping_zone_without_permission() {
wp_set_current_user( 0 );
$request = new WP_REST_Request( 'POST', '/wc/v1/shipping/zones' );
$request->set_body_params( array(
'name' => 'Test Zone',
'order' => 1,
) );
$response = $this->server->dispatch( $request );
$this->assertEquals( 401, $response->get_status() );
}
/**
* Test Shipping Zone update endpoint.
* @since 2.7.0
*/
public function test_update_shipping_zone() {
wp_set_current_user( $this->user );
$zone = $this->create_shipping_zone( 'Test Zone' );
$request = new WP_REST_Request( 'PUT', '/wc/v1/shipping/zones/' . $zone->get_id() );
$request->set_body_params( array(
'name' => 'Zone Test',
'order' => 2,
) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( array(
'id' => $zone->get_id(),
'name' => 'Zone Test',
'order' => 2,
'_links' => array(
'self' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() ),
),
),
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones' ),
),
),
'describedby' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() . '/locations' ),
),
),
),
), $data );
}
/**
* Test Shipping Zone update endpoint with a bad zone ID.
* @since 2.7.0
*/
public function test_update_shipping_zone_invalid_id() {
wp_set_current_user( $this->user );
$request = new WP_REST_Request( 'PUT', '/wc/v1/shipping/zones/1' );
$request->set_body_params( array(
'name' => 'Zone Test',
'order' => 2,
) );
$response = $this->server->dispatch( $request );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Test getting a single Shipping Zone.
* @since 2.7.0
*/
public function test_get_single_shipping_zone() {
wp_set_current_user( $this->user );
$zone = $this->create_shipping_zone( 'Test Zone' );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/' . $zone->get_id() ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( array(
'id' => $zone->get_id(),
'name' => 'Test Zone',
'order' => 0,
'_links' => array(
'self' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() ),
),
),
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones' ),
),
),
'describedby' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() . '/locations' ),
),
),
),
), $data );
}
/**
* Test getting a single Shipping Zone with a bad zone ID.
* @since 2.7.0
*/
public function test_get_single_shipping_zone_invalid_id() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/1' ) );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Test getting Shipping Zone Locations.
* @since 2.7.0
*/
public function test_get_locations() {
wp_set_current_user( $this->user );
// Create a zone
$zone = $this->create_shipping_zone( 'Zone 1', 0, array(
array(
'code' => 'US',
'type' => 'country',
),
) );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/' . $zone->get_id() . '/locations' ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 1 );
$this->assertEquals( array(
array(
'code' => 'US',
'type' => 'country',
'_links' => array(
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() . '/locations' ),
),
),
'describes' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() ),
),
),
),
),
), $data );
}
/**
* Test getting Shipping Zone Locations with a bad zone ID.
* @since 2.7.0
*/
public function test_get_locations_invalid_id() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/1/locations' ) );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Test Shipping Zone Locations update endpoint.
* @since 2.7.0
*/
public function test_update_locations() {
wp_set_current_user( $this->user );
$zone = $this->create_shipping_zone( 'Test Zone' );
$request = new WP_REST_Request( 'PUT', '/wc/v1/shipping/zones/' . $zone->get_id() . '/locations' );
$request->add_header( 'Content-Type', 'application/json' );
$request->set_body( json_encode( array(
array(
'code' => 'UK',
'type' => 'country',
),
array(
'code' => 'US', // test that locations missing "type" aren't saved
),
array(
'code' => 'SW1A0AA',
'type' => 'postcode',
),
array(
'type' => 'continent', // test that locations missing "code" aren't saved
),
) ) );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( count( $data ), 2 );
$this->assertEquals( array(
array(
'code' => 'UK',
'type' => 'country',
'_links' => array(
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() . '/locations' ),
),
),
'describes' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() ),
),
),
),
),
array(
'code' => 'SW1A0AA',
'type' => 'postcode',
'_links' => array(
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() . '/locations' ),
),
),
'describes' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() ),
),
),
),
),
), $data );
}
/**
* Test updating Shipping Zone Locations with a bad zone ID.
* @since 2.7.0
*/
public function test_update_locations_invalid_id() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'PUT', '/wc/v1/shipping/zones/1/locations' ) );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Test getting all Shipping Zone Methods and getting a single Shipping Zone Method.
* @since 2.7.0
*/
public function test_get_methods() {
wp_set_current_user( $this->user );
// Create a shipping method and make sure it's in the response
$zone = $this->create_shipping_zone( 'Zone 1' );
$instance_id = $zone->add_shipping_method( 'flat_rate' );
$methods = $zone->get_shipping_methods();
$method = $methods[ $instance_id ];
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/' . $zone->get_id() . '/methods' ) );
$data = $response->get_data();
$expected = array(
'instance_id' => $instance_id,
'title' => $method->instance_settings['title'],
'order' => $method->method_order,
'enabled' => ( 'yes' === $method->enabled ),
'method_id' => $method->id,
'method_title' => $method->method_title,
'method_description' => $method->method_description,
'_links' => array(
'self' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() . '/methods/' . $instance_id ),
),
),
'collection' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() . '/methods' ),
),
),
'describes' => array(
array(
'href' => rest_url( '/wc/v1/shipping/zones/' . $zone->get_id() ),
),
),
),
);
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 1 );
$this->assertContains( $expected, $data );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/' . $zone->get_id() . '/methods/' . $instance_id ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( $expected, $data );
}
/**
* Test getting all Shipping Zone Methods with a bad zone ID.
* @since 2.7.0
*/
public function test_get_methods_invalid_zone_id() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/1/methods' ) );
$this->assertEquals( 404, $response->get_status() );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/1/methods/1' ) );
$this->assertEquals( 404, $response->get_status() );
}
/**
* Test getting a single Shipping Zone Method with a bad ID.
* @since 2.7.0
*/
public function test_get_methods_invalid_method_id() {
wp_set_current_user( $this->user );
$zone = $this->create_shipping_zone( 'Zone 1' );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/shipping/zones/' . $zone->get_id() . '/methods/1' ) );
$this->assertEquals( 404, $response->get_status() );
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
* System Status REST Tests
* @package WooCommerce\Tests\API
* @since 2.7
*/
class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case {
/**
* Setup our test server.
*/
public function setUp() {
parent::setUp();
$this->endpoint = new WC_REST_System_Status_Controller();
$this->user = $this->factory->user->create( array(
'role' => 'administrator',
) );
}
/**
* Test route registration.
*/
public function test_register_routes() {
$routes = $this->server->get_routes();
$this->assertArrayHasKey( '/wc/v1/system_status', $routes );
}
/**
* Test to make sure system status cannot be accessed without valid creds
*
* @since 2.7.0
*/
public function test_get_system_status_info_without_permission() {
wp_set_current_user( 0 );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
$this->assertEquals( 401, $response->get_status() );
}
/**
* Test to make sure root properties are present.
* (environment, theme, database, etc).
*
* @since 2.7.0
*/
public function test_get_system_status_info_returns_root_properties() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
$data = $response->get_data();
$this->assertArrayHasKey( 'environment', $data );
$this->assertArrayHasKey( 'database', $data );
$this->assertArrayHasKey( 'active_plugins', $data );
$this->assertArrayHasKey( 'theme', $data );
$this->assertArrayHasKey( 'settings', $data );
$this->assertArrayHasKey( 'pages', $data );
}
/**
* Test to make sure environment response is correct.
*
* @since 2.7.0
*/
public function test_get_system_status_info_environment() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
$data = $response->get_data();
$environment = $data['environment'];
// Make sure all expected data is present
$this->assertEquals( 30, count( $environment ) );
// Test some responses to make sure they match up
$this->assertEquals( get_option( 'home' ), $environment['home_url'] );
$this->assertEquals( get_option( 'siteurl' ), $environment['site_url'] );
$this->assertEquals( WC()->version, $environment['version'] );
}
/**
* Test to make sure database response is correct.
*
* @since 2.7.0
*/
public function test_get_system_status_info_database() {
global $wpdb;
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
$data = $response->get_data();
$database = $data['database'];
$this->assertEquals( get_option( 'woocommerce_db_version' ), $database['wc_database_version'] );
$this->assertEquals( $wpdb->prefix, $database['database_prefix'] );
$this->assertEquals( WC_Geolocation::get_local_database_path(), $database['maxmind_geoip_database'] );
$this->assertArrayHasKey( 'woocommerce_payment_tokens', $database['database_tables'] );
}
/**
* Test to make sure active plugins response is correct.
*
* @since 2.7.0
*/
public function test_get_system_status_info_active_plugins() {
wp_set_current_user( $this->user );
$actual_plugins = array( 'hello.php' );
update_option( 'active_plugins', $actual_plugins );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
update_option( 'active_plugins', array() );
$data = $response->get_data();
$plugins = $data['active_plugins'];
$this->assertEquals( 1, count( $plugins ) );
$this->assertEquals( 'Hello Dolly', $plugins[0]['name'] );
}
/**
* Test to make sure theme response is correct.
*
* @since 2.7.0
*/
public function test_get_system_status_info_theme() {
wp_set_current_user( $this->user );
$active_theme = wp_get_theme();
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
$data = $response->get_data();
$theme = $data['theme'];
$this->assertEquals( 13, count( $theme ) );
$this->assertEquals( $active_theme->Name, $theme['name'] );
}
/**
* Test to make sure settings response is correct.
*
* @since 2.7.0
*/
public function test_get_system_status_info_settings() {
wp_set_current_user( $this->user );
$term_response = array();
$terms = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
foreach ( $terms as $term ) {
$term_response[ $term->slug ] = strtolower( $term->name );
}
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
$data = $response->get_data();
$settings = $data['settings'];
$this->assertEquals( 10, count( $settings ) );
$this->assertEquals( ( 'yes' === get_option( 'woocommerce_api_enabled' ) ), $settings['api_enabled'] );
$this->assertEquals( get_woocommerce_currency(), $settings['currency'] );
$this->assertEquals( $term_response, $settings['taxonomies'] );
}
/**
* Test to make sure pages response is correct.
*
* @since 2.7.0
*/
public function test_get_system_status_info_pages() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v1/system_status' ) );
$data = $response->get_data();
$pages = $data['pages'];
$this->assertEquals( 4, count( $pages ) );
}
/**
* Test system status schema.
*
* @since 2.7.0
*/
public function test_system_status_schema() {
$request = new WP_REST_Request( 'OPTIONS', '/wc/v1/system_status' );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$properties = $data['schema']['properties'];
$this->assertEquals( 6, count( $properties ) );
$this->assertArrayHasKey( 'environment', $properties );
$this->assertArrayHasKey( 'database', $properties );
$this->assertArrayHasKey( 'active_plugins', $properties );
$this->assertArrayHasKey( 'theme', $properties );
$this->assertArrayHasKey( 'settings', $properties );
$this->assertArrayHasKey( 'pages', $properties );
}
}

View File

@ -88,14 +88,59 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
$wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations" );
WC()->cart->empty_cart();
WC()->cart->remove_coupons();
WC_Helper_Product::delete_product( $product->id );
# Test case 3 #11626
update_post_meta( $coupon->id, 'discount_type', 'percent' );
update_post_meta( $coupon->id, 'coupon_amount', '50' );
update_option( 'woocommerce_prices_include_tax', 'yes' );
update_option( 'woocommerce_calc_taxes', 'yes' );
$tax_rate = array(
'tax_rate_country' => '',
'tax_rate_state' => '',
'tax_rate' => '19.0000',
'tax_rate_name' => 'TAX',
'tax_rate_priority' => '1',
'tax_rate_compound' => '0',
'tax_rate_shipping' => '1',
'tax_rate_order' => '1',
'tax_rate_class' => ''
);
WC_Tax::_insert_tax_rate( $tax_rate );
$product_ids = array();
$products_data = array(
'5.17', '3.32', '1.25', '3.50', '5.01', '3.34', '5.99', '5.51'
);
foreach ( $products_data as $price ) {
$loop_product = WC_Helper_Product::create_simple_product();
$product_ids[] = $loop_product->id;
update_post_meta( $loop_product->id, '_regular_price', $price );
update_post_meta( $loop_product->id, '_price', $price );
WC()->cart->add_to_cart( $loop_product->id, 1 );
}
WC()->cart->add_discount( $coupon->code );
WC()->cart->calculate_totals();
$cart_item = current( WC()->cart->get_cart() );
$this->assertEquals( '16.55', WC()->cart->total );
// Cleanup
WC()->cart->empty_cart();
WC()->cart->remove_coupons();
foreach ( $product_ids as $product_id ) {
WC_Helper_Product::delete_product( $product_id );
}
$wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates" );
$wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations" );
update_option( 'woocommerce_prices_include_tax', 'no' );
update_option( 'woocommerce_calc_taxes', 'no' );
// Delete coupon
WC_Helper_Coupon::delete_coupon( $coupon->id );
// Clean up product
WC_Helper_Product::delete_product( $product->id );
}
/**
@ -124,6 +169,8 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
// Create dummy product
$product = WC_Helper_Product::create_simple_product();
WC()->cart->empty_cart();
// Add the product to the cart. Methods returns boolean on failure, string on success.
$this->assertNotFalse( WC()->cart->add_to_cart( $product->id, 1 ) );

View File

@ -46,7 +46,7 @@ class WC_Tests_Cart_Functions extends WC_Unit_Test_Case {
public function test_get_checkout_url_regular() {
// Make sure pages exist
WC_Install::create_pages();
// Get the original setting
$o_setting = get_option( 'woocommerce_force_ssl_checkout' );
@ -154,4 +154,29 @@ class WC_Tests_Cart_Functions extends WC_Unit_Test_Case {
$this->assertEquals( apply_filters( 'woocommerce_get_cart_url', $cart_page_url ? $cart_page_url : '' ), wc_get_cart_url() );
}
/**
* Test wc_add_to_cart_message
*/
public function test_wc_add_to_cart_message() {
$product = WC_Helper_Product::create_simple_product();
$message = wc_add_to_cart_message( array( $product->id => 1 ), false, true );
$this->assertEquals( '<a href="http://example.org" class="button wc-forward">View Cart</a> &ldquo;Dummy Product&rdquo; has been added to your cart.', $message );
$message = wc_add_to_cart_message( array( $product->id => 3 ), false, true );
$this->assertEquals( '<a href="http://example.org" class="button wc-forward">View Cart</a> &ldquo;Dummy Product&rdquo; has been added to your cart.', $message );
$message = wc_add_to_cart_message( array( $product->id => 1 ), true, true );
$this->assertEquals( '<a href="http://example.org" class="button wc-forward">View Cart</a> &ldquo;Dummy Product&rdquo; has been added to your cart.', $message );
$message = wc_add_to_cart_message( array( $product->id => 3 ), true, true );
$this->assertEquals( '<a href="http://example.org" class="button wc-forward">View Cart</a> 3 &times; &ldquo;Dummy Product&rdquo; have been added to your cart.', $message );
$message = wc_add_to_cart_message( $product->id, false, true );
$this->assertEquals( '<a href="http://example.org" class="button wc-forward">View Cart</a> &ldquo;Dummy Product&rdquo; has been added to your cart.', $message );
$message = wc_add_to_cart_message( $product->id, true, true );
$this->assertEquals( '<a href="http://example.org" class="button wc-forward">View Cart</a> &ldquo;Dummy Product&rdquo; has been added to your cart.', $message );
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
<?php
/**
* Meta
* @package WooCommerce\Tests\CRUD
*/
class WC_Tests_CRUD_Refunds extends WC_Unit_Test_Case {
/**
* Test: get_type
*/
function test_get_type() {
$object = new WC_Order_Refund();
$this->assertEquals( 'shop_order_refund', $object->get_type() );
}
/**
* Test: get_refund_amount
*/
function test_get_refund_amount() {
$object = new WC_Order_Refund();
$object->set_refund_amount( 20 );
$this->assertEquals( '20.00', $object->get_refund_amount() );
}
/**
* Test: get_refund_reason
*/
function test_get_refund_reason() {
$object = new WC_Order_Refund();
$object->set_refund_reason( 'Customer is an idiot' );
$this->assertEquals( 'Customer is an idiot', $object->get_refund_reason() );
}
/**
* Test: get_refunded_by
*/
function test_get_refunded_by() {
$object = new WC_Order_Refund();
$object->set_refunded_by( 1 );
$this->assertEquals( 1, $object->get_refunded_by() );
}
}

View File

@ -109,7 +109,7 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case {
$this->assertInstanceOf( 'WC_Order', wc_get_order( $order ) );
// Assert that wc_get_order() accepts a order post id.
$this->assertInstanceOf( 'WC_Order', wc_get_order( $order->id ) );
$this->assertInstanceOf( 'WC_Order', wc_get_order( $order->get_id() ) );
// Assert that a non-shop_order post returns false
$post = $this->factory->post->create_and_get( array( 'post_type' => 'post' ) );
@ -132,7 +132,7 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case {
$this->assertEmpty( $order->get_payment_tokens() );
$token = WC_Helper_Payment_Token::create_cc_token();
update_post_meta( $order->id, '_payment_tokens', array( $token->get_id() ) );
update_post_meta( $order->get_id(), '_payment_tokens', array( $token->get_id() ) );
$this->assertCount( 1, $order->get_payment_tokens() );
}

View File

@ -18,12 +18,12 @@ class WC_Tests_Payment_Tokens extends WC_Unit_Test_Case {
*/
function test_wc_payment_tokens_get_order_tokens() {
$order = WC_Helper_Order::create_order();
$this->assertEmpty( WC_Payment_Tokens::get_order_tokens( $order->id ) );
$this->assertEmpty( WC_Payment_Tokens::get_order_tokens( $order->get_id() ) );
$token = WC_Helper_Payment_Token::create_cc_token();
update_post_meta( $order->id, '_payment_tokens', array( $token->get_id() ) );
update_post_meta( $order->get_id(), '_payment_tokens', array( $token->get_id() ) );
$this->assertCount( 1, WC_Payment_Tokens::get_order_tokens( $order->id ) );
$this->assertCount( 1, WC_Payment_Tokens::get_order_tokens( $order->get_id() ) );
}

View File

@ -97,6 +97,26 @@ class WC_Tests_Conditional_Functions extends WC_Unit_Test_Case {
);
}
/**
* Test wc_site_is_https().
*/
public function test_wc_site_is_https() {
$this->assertFalse( wc_site_is_https() );
add_filter( 'pre_option_home', array( $this, '_https_url' ) );
$this->assertTrue( wc_site_is_https() );
}
/**
* Callback for chaning home url to https.
*
* @return string
*/
public function _https_url() {
return 'https://example.org';
}
/**
* Test wc_is_valid_url().
*

Some files were not shown because too many files have changed in this diff Show More