Merge remote-tracking branch 'woothemes/master'

This commit is contained in:
Job 2016-08-08 15:31:55 +02:00
commit 44ab9bde0d
151 changed files with 13912 additions and 4198 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,7 +146,18 @@ 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() {
@ -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

View File

@ -152,7 +152,7 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
$post = get_post( $id );
if ( empty( $id ) || empty( $post->ID ) || ! in_array( $post->post_type, $this->get_post_types() ) ) {
return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'Invalid id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$data = $this->prepare_item_for_response( $post, $request );
@ -521,6 +521,8 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
if ( 'include' === $query_args['orderby'] ) {
$query_args['orderby'] = 'post__in';
} elseif ( 'id' === $query_args['orderby'] ) {
$query_args['orderby'] = 'ID'; // ID must be capitalized
}
return $query_args;
@ -622,7 +624,7 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
'validate_callback' => 'rest_validate_request_arg',
);
$params['exclude'] = array(
'description' => __( 'Ensure result set excludes specific ids.', 'woocommerce' ),
'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
@ -663,13 +665,13 @@ abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
$post_type_obj = get_post_type_object( $this->post_type );
if ( isset( $post_type_obj->hierarchical ) && $post_type_obj->hierarchical ) {
$params['parent'] = array(
'description' => __( 'Limit result set to those of particular parent ids.', 'woocommerce' ),
'description' => __( 'Limit result set to those of particular parent IDs.', 'woocommerce' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'default' => array(),
);
$params['parent_exclude'] = array(
'description' => __( 'Limit result set to all items except those of a particular parent id.', 'woocommerce' ),
'description' => __( 'Limit result set to all items except those of a particular parent ID.', 'woocommerce' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'default' => array(),

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

@ -133,6 +133,6 @@ class WC_Admin_Addons {
$theme = wp_get_theme();
$section_keys = array_keys( $sections );
$current_section = isset( $_GET['section'] ) ? sanitize_text_field( $_GET['section'] ) : current( $section_keys );
include_once( 'views/html-admin-page-addons.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-addons.php' );
}
}

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

@ -46,8 +46,8 @@ class WC_Admin_Dashboard {
public function status_widget() {
global $wpdb;
include_once( 'reports/class-wc-admin-report.php' );
include_once( 'reports/class-wc-report-sales-by-date.php' );
include_once( dirname( __FILE__ ) . '/reports/class-wc-admin-report.php' );
include_once( dirname( __FILE__ ) . '/reports/class-wc-report-sales-by-date.php' );
$reports = new WC_Admin_Report();
$sales_by_date = new WC_Report_Sales_By_Date();

View File

@ -212,7 +212,7 @@ class WC_Admin_Help {
'title' => __( 'Education', 'woocommerce' ),
'content' =>
'<h2>' . __( 'Education', 'woocommerce' ) . '</h2>' .
'<p>' . __( 'If you would like to learn about using WooCommerce from an expert, consider following a WooCommerce course ran by one of our educational partners.', 'woocommerce' ) . '</p>' .
'<p>' . __( 'If you would like to learn about using WooCommerce from an expert, consider following a WooCommerce course offered by one of our educational partners.', 'woocommerce' ) . '</p>' .
'<p><a href="' . 'https://woocommerce.com/educational-partners/?utm_source=helptab&utm_medium=product&utm_content=edupartners&utm_campaign=woocommerceplugin' . '" class="button button-primary">' . __( 'View Education Partners', 'woocommerce' ) . '</a></p>'
) );

View File

@ -50,7 +50,7 @@ class WC_Admin_Importers {
}
// includes
require 'importers/class-wc-tax-rate-importer.php';
require( dirname( __FILE__ ) . '/importers/class-wc-tax-rate-importer.php' );
// Dispatch
$importer = new WC_Tax_Rate_Importer();

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

@ -93,7 +93,7 @@ class WC_Admin_Post_Types {
}
// Meta-Box Class
include_once( 'class-wc-admin-meta-boxes.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-meta-boxes.php' );
// Download permissions
add_action( 'woocommerce_process_product_file_download_paths', array( $this, 'process_product_file_download_paths' ), 10, 3 );

View File

@ -30,8 +30,8 @@ class WC_Admin_Reports {
$current_tab = ! empty( $_GET['tab'] ) ? sanitize_title( $_GET['tab'] ) : $first_tab[0];
$current_report = isset( $_GET['report'] ) ? sanitize_title( $_GET['report'] ) : current( array_keys( $reports[ $current_tab ]['reports'] ) );
include_once( 'reports/class-wc-admin-report.php' );
include_once( 'views/html-admin-page-reports.php' );
include_once( dirname( __FILE__ ) . '/reports/class-wc-admin-report.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-reports.php' );
}
/**

View File

@ -47,7 +47,7 @@ class WC_Admin_Settings {
if ( empty( self::$settings ) ) {
$settings = array();
include_once( 'settings/class-wc-settings-page.php' );
include_once( dirname( __FILE__ ) . '/settings/class-wc-settings-page.php' );
$settings[] = include( 'settings/class-wc-settings-general.php' );
$settings[] = include( 'settings/class-wc-settings-products.php' );
@ -166,7 +166,7 @@ class WC_Admin_Settings {
// Get tabs for the settings page
$tabs = apply_filters( 'woocommerce_settings_tabs_array', array() );
include 'views/html-admin-settings.php';
include( dirname( __FILE__ ) . '/views/html-admin-settings.php' );
}
/**
@ -662,10 +662,14 @@ class WC_Admin_Settings {
* Loops though the woocommerce options array and outputs each field.
*
* @param array $options Options array to output
* @param array $data Optional. Data to use for saving. Defaults to $_POST.
* @return bool
*/
public static function save_fields( $options ) {
if ( empty( $_POST ) ) {
public static function save_fields( $options, $data = null ) {
if ( is_null( $data ) ) {
$data = $_POST;
}
if ( empty( $data ) ) {
return false;
}
@ -683,17 +687,17 @@ class WC_Admin_Settings {
parse_str( $option['id'], $option_name_array );
$option_name = current( array_keys( $option_name_array ) );
$setting_name = key( $option_name_array[ $option_name ] );
$raw_value = isset( $_POST[ $option_name ][ $setting_name ] ) ? wp_unslash( $_POST[ $option_name ][ $setting_name ] ) : null;
$raw_value = isset( $data[ $option_name ][ $setting_name ] ) ? wp_unslash( $data[ $option_name ][ $setting_name ] ) : null;
} else {
$option_name = $option['id'];
$setting_name = '';
$raw_value = isset( $_POST[ $option['id'] ] ) ? wp_unslash( $_POST[ $option['id'] ] ) : null;
$raw_value = isset( $data[ $option['id'] ] ) ? wp_unslash( $data[ $option['id'] ] ) : null;
}
// Format the value based on option type.
switch ( $option['type'] ) {
case 'checkbox' :
$value = is_null( $raw_value ) ? 'no' : 'yes';
$value = '1' === $raw_value || 'yes' === $raw_value ? 'yes' : 'no';
break;
case 'textarea' :
$value = wp_kses_post( trim( $raw_value ) );
@ -714,6 +718,15 @@ class WC_Admin_Settings {
$value['crop'] = $option['default']['crop'];
}
break;
case 'select':
$allowed_values = empty( $option['options'] ) ? array() : array_keys( $option['options'] );
if ( empty( $option['default'] ) && empty( $allowed_values ) ) {
$value = null;
break;
}
$default = ( empty( $option['default'] ) ? $allowed_values[0] : $option['default'] );
$value = in_array( $raw_value, $allowed_values ) ? $raw_value : $default;
break;
default :
$value = wc_clean( $raw_value );
break;

View File

@ -483,7 +483,7 @@ class WC_Admin_Setup_Wizard {
</tbody>
</table>
</div>
<p class="description"><?php printf( __( 'You may you need to add/edit rates based on your products or business location which can be done from the %1$stax settings%2$s screen. If in doubt, speak to an accountant.', 'woocommerce' ), '<a href="' . admin_url( 'admin.php?page=wc-settings&tab=tax' ) . '" target="_blank">', '</a>' ); ?></p>
<p class="description"><?php printf( __( 'You may need to add/edit rates based on your products or business location which can be done from the %1$stax settings%2$s screen. If in doubt, speak to an accountant.', 'woocommerce' ), '<a href="' . admin_url( 'admin.php?page=wc-settings&tab=tax' ) . '" target="_blank">', '</a>' ); ?></p>
</td>
</tr>
<?php
@ -606,13 +606,13 @@ class WC_Admin_Setup_Wizard {
),
'bacs' => array(
'name' => __( 'Bank Transfer (BACS) Payments', 'woocommerce' ),
'description' => __( 'An simple offline gateway that lets you accept BACS payment.', 'woocommerce' ),
'description' => __( 'A simple offline gateway that lets you accept BACS payment.', 'woocommerce' ),
'image' => '',
'class' => '',
),
'cod' => array(
'name' => __( 'Cash on Delivery', 'woocommerce' ),
'description' => __( 'An simple offline gateway that lets you accept cash on delivery.', 'woocommerce' ),
'description' => __( 'A simple offline gateway that lets you accept cash on delivery.', 'woocommerce' ),
'image' => '',
'class' => '',
)

View File

@ -21,14 +21,14 @@ class WC_Admin_Status {
* Handles output of the reports page in admin.
*/
public static function output() {
include_once( 'views/html-admin-page-status.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-status.php' );
}
/**
* Handles output of report.
*/
public static function status_report() {
include_once( 'views/html-admin-page-status-report.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-status-report.php' );
}
/**
@ -138,7 +138,7 @@ class WC_Admin_Status {
echo '<div class="updated inline"><p>' . __( 'Your changes have been saved.', 'woocommerce' ) . '</p></div>';
}
include_once( 'views/html-admin-page-status-tools.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-status-tools.php' );
}
/**
@ -205,6 +205,12 @@ class WC_Admin_Status {
$viewed_log = current( $logs );
}
$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 = wc_get_logger();
$logger->remove( $_REQUEST[ 'handle' ] );
}
wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
exit();
}
}

View File

@ -357,11 +357,9 @@ class WC_Admin_Taxonomies {
* @return array
*/
public function disable_checked_ontop( $args ) {
if ( 'product_cat' == $args['taxonomy'] ) {
if ( ! empty( $args['taxonomy'] ) && 'product_cat' === $args['taxonomy'] ) {
$args['checked_ontop'] = false;
}
return $args;
}
}

View File

@ -442,7 +442,7 @@ class WC_Admin_Webhooks {
add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_webhook_comments' ), 10, 1 );
if ( $logs ) {
include_once( 'settings/views/html-webhook-logs.php' );
include_once( dirname( __FILE__ ) . '/settings/views/html-webhook-logs.php' );
} else {
echo '<p>' . __( 'This Webhook has no log yet.', 'woocommerce' ) . '</p>';
}

View File

@ -43,34 +43,34 @@ class WC_Admin {
* Include any classes we need within admin.
*/
public function includes() {
include_once( 'wc-admin-functions.php' );
include_once( 'wc-meta-box-functions.php' );
include_once( 'class-wc-admin-post-types.php' );
include_once( 'class-wc-admin-taxonomies.php' );
include_once( 'class-wc-admin-menus.php' );
include_once( 'class-wc-admin-notices.php' );
include_once( 'class-wc-admin-assets.php' );
include_once( 'class-wc-admin-api-keys.php' );
include_once( 'class-wc-admin-webhooks.php' );
include_once( 'class-wc-admin-pointers.php' );
include_once( dirname( __FILE__ ) . '/wc-admin-functions.php' );
include_once( dirname( __FILE__ ) . '/wc-meta-box-functions.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-post-types.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-taxonomies.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-menus.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-notices.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-assets.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-api-keys.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-webhooks.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-pointers.php' );
// Help Tabs
if ( apply_filters( 'woocommerce_enable_admin_help_tab', true ) ) {
include_once( 'class-wc-admin-help.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-help.php' );
}
// Setup/welcome
if ( ! empty( $_GET['page'] ) ) {
switch ( $_GET['page'] ) {
case 'wc-setup' :
include_once( 'class-wc-admin-setup-wizard.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-setup-wizard.php' );
break;
}
}
// Importers
if ( defined( 'WP_LOAD_IMPORTERS' ) ) {
include_once( 'class-wc-admin-importers.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-importers.php' );
}
}

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

@ -5,7 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( ! class_exists( 'WC_Report_Stock' ) ) {
require_once( 'class-wc-report-stock.php' );
require_once( dirname( __FILE__ ) . '/class-wc-report-stock.php' );
}
/**

View File

@ -5,7 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( ! class_exists( 'WC_Report_Stock' ) ) {
require_once( 'class-wc-report-stock.php' );
require_once( dirname( __FILE__ ) . '/class-wc-report-stock.php' );
}
/**

View File

@ -5,7 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( ! class_exists( 'WC_Report_Stock' ) ) {
require_once( 'class-wc-report-stock.php' );
require_once( dirname( __FILE__ ) . '/class-wc-report-stock.php' );
}
/**

View File

@ -111,7 +111,7 @@ class WC_Settings_Accounts extends WC_Settings_Page {
array(
'title' => __( 'Orders', 'woocommerce' ),
'desc' => __( 'Endpoint for the My Account &rarr; Orders page', 'woocommerce' ),
'desc' => sprintf( __( 'Endpoint for the My Account &rarr; %s page', 'woocommerce' ), __( 'Orders', 'woocommerce' ) ),
'id' => 'woocommerce_myaccount_orders_endpoint',
'type' => 'text',
'default' => 'orders',
@ -120,7 +120,7 @@ class WC_Settings_Accounts extends WC_Settings_Page {
array(
'title' => __( 'View Order', 'woocommerce' ),
'desc' => __( 'Endpoint for the My Account &rarr; View Order page', 'woocommerce' ),
'desc' => sprintf( __( 'Endpoint for the My Account &rarr; %s page', 'woocommerce' ), __( 'View Order', 'woocommerce' ) ),
'id' => 'woocommerce_myaccount_view_order_endpoint',
'type' => 'text',
'default' => 'view-order',
@ -129,7 +129,7 @@ class WC_Settings_Accounts extends WC_Settings_Page {
array(
'title' => __( 'Downloads', 'woocommerce' ),
'desc' => __( 'Endpoint for the My Account &rarr; Downloads page', 'woocommerce' ),
'desc' => sprintf( __( 'Endpoint for the My Account &rarr; %s page', 'woocommerce' ), __( 'Downloads', 'woocommerce' ) ),
'id' => 'woocommerce_myaccount_downloads_endpoint',
'type' => 'text',
'default' => 'downloads',
@ -138,7 +138,7 @@ class WC_Settings_Accounts extends WC_Settings_Page {
array(
'title' => __( 'Edit Account', 'woocommerce' ),
'desc' => __( 'Endpoint for the My Account &rarr; Edit Account page', 'woocommerce' ),
'desc' => sprintf( __( 'Endpoint for the My Account &rarr; %s page', 'woocommerce' ), __( 'Edit Account', 'woocommerce' ) ),
'id' => 'woocommerce_myaccount_edit_account_endpoint',
'type' => 'text',
'default' => 'edit-account',
@ -147,7 +147,7 @@ class WC_Settings_Accounts extends WC_Settings_Page {
array(
'title' => __( 'Addresses', 'woocommerce' ),
'desc' => __( 'Endpoint for the My Account &rarr; Addresses page', 'woocommerce' ),
'desc' => sprintf( __( 'Endpoint for the My Account &rarr; %s page', 'woocommerce' ), __( 'Addresses', 'woocommerce' ) ),
'id' => 'woocommerce_myaccount_edit_address_endpoint',
'type' => 'text',
'default' => 'edit-address',
@ -156,7 +156,7 @@ class WC_Settings_Accounts extends WC_Settings_Page {
array(
'title' => __( 'Payment Methods', 'woocommerce' ),
'desc' => __( 'Endpoint for the My Account &rarr; Payment Methods page', 'woocommerce' ),
'desc' => sprintf( __( 'Endpoint for the My Account &rarr; %s page', 'woocommerce' ), __( 'Payment Methods', 'woocommerce' ) ),
'id' => 'woocommerce_myaccount_payment_methods_endpoint',
'type' => 'text',
'default' => 'payment-methods',
@ -165,7 +165,7 @@ class WC_Settings_Accounts extends WC_Settings_Page {
array(
'title' => __( 'Lost Password', 'woocommerce' ),
'desc' => __( 'Endpoint for the My Account &rarr; Lost Password page', 'woocommerce' ),
'desc' => sprintf( __( 'Endpoint for the My Account &rarr; %s page', 'woocommerce' ), __( 'Lost Password', 'woocommerce' ) ),
'id' => 'woocommerce_myaccount_lost_password_endpoint',
'type' => 'text',
'default' => 'lost-password',

View File

@ -43,6 +43,24 @@ abstract class WC_Settings_Page {
add_action( 'woocommerce_settings_save_' . $this->id, array( $this, 'save' ) );
}
/**
* Get settings page ID.
* @since 2.7.0
* @return string
*/
public function get_id() {
return $this->id;
}
/**
* Get settings page label.
* @since 2.7.0
* @return string
*/
public function get_label() {
return $this->label;
}
/**
* Add this page to settings.
*/

View File

@ -217,7 +217,7 @@ class WC_Settings_Shipping extends WC_Settings_Page {
) );
wp_enqueue_script( 'wc-shipping-zone-methods' );
include_once( 'views/html-admin-page-shipping-zone-methods.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-shipping-zone-methods.php' );
}
/**
@ -246,7 +246,7 @@ class WC_Settings_Shipping extends WC_Settings_Page {
) );
wp_enqueue_script( 'wc-shipping-zones' );
include_once( 'views/html-admin-page-shipping-zones.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-shipping-zones.php' );
}
/**
@ -277,7 +277,7 @@ class WC_Settings_Shipping extends WC_Settings_Page {
$shipping_method->display_errors();
}
include_once( 'views/html-admin-page-shipping-zones-instance.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-shipping-zones-instance.php' );
}
/**
@ -308,7 +308,7 @@ class WC_Settings_Shipping extends WC_Settings_Page {
'wc-shipping-class-count' => __( 'Product Count', 'woocommerce' ),
) );
include_once( 'views/html-admin-page-shipping-classes.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-shipping-classes.php' );
}
}

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>';
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 {
echo '<mark class="yes">' . esc_html( $php_version ) . '</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; ?>
<?php
<?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, 'MySQL' ) ) : ?>
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() ) );
} 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() ) );
} 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 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 {
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 {
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>
<?php
}
?>
</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 ) {
foreach ( $database['database_tables'] as $table => $table_exists ) {
?>
<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>
<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 ( in_array( get_option( 'woocommerce_default_customer_address' ), array( 'geolocation_ajax', 'geolocation' ) ) ) {
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( 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> ';
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\"', 'woocommerce' ), make_clickable( 'http://dev.maxmind.com/geoip/legacy/geolite/' ), '<code class="private">' . WC_Geolocation::get_local_database_path() . '</code>' ) . '</mark>', WC_LOG_DIR );
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
}
?>
</tr>
</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">
<?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

@ -62,9 +62,7 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
$option_value = get_option( $option );
if ( $option_value > 0 ) {
$page_object = get_post( $option_value );
if ( $option_value > 0 && ( $page_object = get_post( $option_value ) ) ) {
if ( 'page' === $page_object->post_type && ! in_array( $page_object->post_status, array( 'pending', 'trash', 'future', 'auto-draft' ) ) ) {
// Valid page is already in place
return $page_object->ID;
@ -135,7 +133,7 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
function woocommerce_admin_fields( $options ) {
if ( ! class_exists( 'WC_Admin_Settings' ) ) {
include 'class-wc-admin-settings.php';
include( dirname( __FILE__ ) . '/class-wc-admin-settings.php' );
}
WC_Admin_Settings::output_fields( $options );
@ -145,14 +143,15 @@ function woocommerce_admin_fields( $options ) {
* Update all settings which are passed.
*
* @param array $options
* @param array $data
*/
function woocommerce_update_options( $options ) {
function woocommerce_update_options( $options, $data = null ) {
if ( ! class_exists( 'WC_Admin_Settings' ) ) {
include 'class-wc-admin-settings.php';
include( dirname( __FILE__ ) . '/class-wc-admin-settings.php' );
}
WC_Admin_Settings::save_fields( $options );
WC_Admin_Settings::save_fields( $options, $data );
}
/**
@ -165,7 +164,7 @@ function woocommerce_update_options( $options ) {
function woocommerce_settings_get_option( $option_name, $default = '' ) {
if ( ! class_exists( 'WC_Admin_Settings' ) ) {
include 'class-wc-admin-settings.php';
include( dirname( __FILE__ ) . '/class-wc-admin-settings.php' );
}
return WC_Admin_Settings::get_option( $option_name, $default );

View File

@ -246,8 +246,8 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
// Content.
$data->post_content = '';
// Excerpt.
if ( ! empty( $schema['properties']['excerpt'] ) && isset( $request['description'] ) ) {
// Coupon description (excerpt).
if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) {
$data->post_excerpt = wp_filter_post_kses( $request['description'] );
}

View File

@ -353,7 +353,7 @@ class WC_REST_Customers_Controller extends WC_REST_Controller {
$customer = get_userdata( $id );
if ( empty( $id ) || empty( $customer->ID ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$customer = $this->prepare_item_for_response( $customer, $request );
@ -373,7 +373,7 @@ class WC_REST_Customers_Controller extends WC_REST_Controller {
$customer = get_userdata( $id );
if ( ! $customer ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 400 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 400 ) );
}
if ( ! empty( $request['email'] ) && email_exists( $request['email'] ) && $request['email'] !== $customer->user_email ) {
@ -837,13 +837,13 @@ class WC_REST_Customers_Controller extends WC_REST_Controller {
$params['context']['default'] = 'view';
$params['exclude'] = array(
'description' => __( 'Ensure result set excludes specific ids.', 'woocommerce' ),
'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['include'] = array(
'description' => __( 'Limit result set to specific ids.', 'woocommerce' ),
'description' => __( 'Limit result set to specific IDs.', 'woocommerce' ),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',

View File

@ -161,7 +161,7 @@ class WC_REST_Order_Notes_Controller extends WC_REST_Controller {
$order = get_post( (int) $request['order_id'] );
if ( empty( $order->post_type ) || $this->post_type !== $order->post_type ) {
return new WP_Error( 'woocommerce_rest_{$this->post_type}_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_{$this->post_type}_invalid_id', __( 'Invalid order ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$args = array(
@ -200,7 +200,7 @@ class WC_REST_Order_Notes_Controller extends WC_REST_Controller {
$order = get_post( (int) $request['order_id'] );
if ( empty( $order->post_type ) || $this->post_type !== $order->post_type ) {
return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$order = wc_get_order( $order );
@ -244,13 +244,13 @@ class WC_REST_Order_Notes_Controller extends WC_REST_Controller {
$order = get_post( (int) $request['order_id'] );
if ( empty( $order->post_type ) || $this->post_type !== $order->post_type ) {
return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$note = get_comment( $id );
if ( empty( $id ) || empty( $note ) || intval( $note->comment_post_ID ) !== intval( $order->ID ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$order_note = $this->prepare_item_for_response( $note, $request );
@ -277,13 +277,13 @@ class WC_REST_Order_Notes_Controller extends WC_REST_Controller {
$order = get_post( (int) $request['order_id'] );
if ( empty( $order->post_type ) || $this->post_type !== $order->post_type ) {
return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$note = get_comment( $id );
if ( empty( $id ) || empty( $note ) || intval( $note->comment_post_ID ) !== intval( $order->ID ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$request->set_param( 'context', 'edit' );

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

@ -182,7 +182,7 @@ class WC_REST_Product_Categories_Controller extends WC_REST_Terms_Controller {
),
),
'parent' => array(
'description' => __( 'The id for the parent of the resource.', 'woocommerce' ),
'description' => __( 'The ID for the parent of the resource.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),

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 ) {
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product id.', 'woocommerce' ), array( 'status' => 404 ) );
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 );
@ -125,16 +223,16 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
*/
public function get_item( $request ) {
$id = (int) $request['id'];
$product = get_post( (int) $request['product_id'] );
$product_id = (int) $request['product_id'];
if ( empty( $product->post_type ) || 'product' !== $product->post_type ) {
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product id.', 'woocommerce' ), array( 'status' => 404 ) );
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 ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
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 ) );
}
$delivery = $this->prepare_item_for_response( $review, $request );
@ -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

@ -1732,7 +1732,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
$post = get_post( $id );
if ( empty( $id ) || empty( $post->ID ) || ! in_array( $post->post_type, $this->get_post_types() ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$supports_trash = EMPTY_TRASH_DAYS > 0;

View File

@ -0,0 +1,231 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* REST API Settings Groups Controller.
* Handles requests to the /settings and /settings/<group> endpoints.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @version 2.7.0
* @since 2.7.0
*/
class WC_REST_Settings_Controller extends WC_REST_Controller {
/**
* WP REST API namespace/version.
*/
protected $namespace = 'wc/v1';
/**
* Route base.
*
* @var string
*/
protected $rest_base = 'settings';
/**
* Register routes.
*
* @since 2.7.0
*/
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' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
}
/**
* Get all settings groups items.
*
* @since 2.7.0
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public function get_items( $request ) {
$groups = apply_filters( 'woocommerce_settings_groups', array() );
if ( empty( $groups ) ) {
return new WP_Error( 'rest_setting_groups_empty', __( 'No setting groups have been registered.', 'woocommerce' ), array( 'status' => 500 ) );
}
$defaults = $this->group_defaults();
$filtered_groups = array();
foreach ( $groups as $group ) {
$sub_groups = array();
foreach ( $groups as $_group ) {
if ( ! empty( $_group['parent_id'] ) && $group['id'] === $_group['parent_id'] ) {
$sub_groups[] = $_group['id'];
}
}
$group['sub_groups'] = $sub_groups;
$group = wp_parse_args( $group, $defaults );
if ( ! is_null( $group['id'] ) && ! is_null( $group['label'] ) ) {
$group_obj = $this->filter_group( $group );
$group_data = $this->prepare_item_for_response( $group_obj, $request );
$group_data = $this->prepare_response_for_collection( $group_data );
$filtered_groups[] = $group_data;
}
}
$response = rest_ensure_response( $filtered_groups );
return $response;
}
/**
* Prepare links for the request.
*
* @param string $group_id Group ID.
* @return array Links for the given group.
*/
protected function prepare_links( $group_id ) {
$base = '/' . $this->namespace . '/' . $this->rest_base;
$links = array(
'item' => array(
'href' => rest_url( trailingslashit( $base ) . $group_id ),
'embeddable' => true,
),
);
return $links;
}
/**
* Prepare a report sales object for serialization.
*
* @since 2.7.0
* @param array $item Group object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response Response data.
*/
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 );
$response = rest_ensure_response( $data );
$response->add_links( $this->prepare_links( $item['id'] ) );
return $response;
}
/**
* Filters out bad values from the groups array/filter so we
* only return known values via the API.
*
* @since 2.7.0
* @param array $group
* @return array
*/
public function filter_group( $group ) {
return array_intersect_key(
$group,
array_flip( array_filter( array_keys( $group ), array( $this, 'allowed_group_keys' ) ) )
);
}
/**
* Callback for allowed keys for each group response.
*
* @since 2.7.0
* @param string $key Key to check
* @return boolean
*/
public function allowed_group_keys( $key ) {
return in_array( $key, array( 'id', 'label', 'description', 'parent_id', 'sub_groups' ) );
}
/**
* Returns default settings for groups. null means the field is required.
*
* @since 2.7.0
* @return array
*/
protected function group_defaults() {
return array(
'id' => null,
'label' => null,
'description' => '',
'parent_id' => '',
'sub_groups' => array(),
);
}
/**
* Makes sure the current user has access to READ the settings APIs.
*
* @since 2.7.0
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
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;
}
/**
* Get the groups schema, conforming to JSON Schema.
*
* @since 2.7.0
* @return array
*/
public function get_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'settings-group',
'type' => 'object',
'properties' => array(
'id' => array(
'description' => __( 'A unique identifier that can be used to link settings together.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_title',
),
),
'label' => array(
'description' => __( 'A human readable translation wrapped label. Meant to be used in interfaces.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'description' => array(
'description' => __( 'A human readable translation wrapped description. Meant to be used in interfaces', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'parent_id' => array(
'description' => __( 'ID of parent grouping.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'sub_groups' => array(
'description' => __( 'IDs for settings sub groups.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
),
);
return $this->add_additional_fields_schema( $schema );
}
}

View File

@ -0,0 +1,423 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* REST API Settings Controller.
* Handles requests to the /settings/$group/$setting endpoints.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @version 2.7.0
* @since 2.7.0
*/
class WC_REST_Settings_Options_Controller extends WC_REST_Controller {
/**
* WP REST API namespace/version.
*/
protected $namespace = 'wc/v1';
/**
* Route base.
*
* @var string
*/
protected $rest_base = 'settings';
/**
* Register routes.
*
* @since 2.7.0
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<group>[\w-]+)', 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<group>[\w-]+)/batch', array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'batch_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_batch_schema' ),
) );
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<group>[\w-]+)/(?P<id>[\w-]+)', 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' ),
) );
}
/**
* Return a single setting.
*
* @since 2.7.0
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public function get_item( $request ) {
$setting = $this->get_setting( $request['group'], $request['id'] );
if ( is_wp_error( $setting ) ) {
return $setting;
}
$response = $this->prepare_item_for_response( $setting, $request );
return rest_ensure_response( $response );
}
/**
* Return all settings in a group.
*
* @since 2.7.0
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public function get_items( $request ) {
$settings = $this->get_group_settings( $request['group'] );
if ( is_wp_error( $settings ) ) {
return $settings;
}
$data = array();
foreach ( $settings as $setting_obj ) {
$setting = $this->prepare_item_for_response( $setting_obj, $request );
$setting = $this->prepare_response_for_collection( $setting );
$data[] = $setting;
}
return rest_ensure_response( $data );
}
/**
* Get all settings in a group.
*
* @since 2.7.0
* @param string $group_id Group ID.
* @return array|WP_Error
*/
public function get_group_settings( $group_id ) {
if ( empty( $group_id ) ) {
return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'woocommerce' ), array( 'status' => 404 ) );
}
$settings = apply_filters( 'woocommerce_settings-' . $group_id, array() );
if ( empty( $settings ) ) {
return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'woocommerce' ), array( 'status' => 404 ) );
}
$filtered_settings = array();
foreach ( $settings as $setting ) {
$setting = $this->filter_setting( $setting );
if ( $this->is_setting_type_valid( $setting['type'] ) ) {
$setting['value'] = WC_Admin_Settings::get_option( $setting['id'] );
$filtered_settings[] = $setting;
}
}
return $filtered_settings;
}
/**
* Get setting data.
*
* @since 2.7.0
* @param string $group_id Group ID.
* @param string $setting_id Setting ID.
* @return stdClass|WP_Error
*/
public function get_setting( $group_id, $setting_id ) {
if ( empty( $setting_id ) ) {
return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'woocommerce' ), array( 'status' => 404 ) );
}
$settings = $this->get_group_settings( $group_id );
if ( is_wp_error( $settings ) ) {
return $settings;
}
$array_key = array_keys( wp_list_pluck( $settings, 'id' ), $setting_id );
if ( empty( $array_key ) ) {
return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'woocommerce' ), array( 'status' => 404 ) );
}
$setting = $settings[ $array_key[0] ];
if ( ! $this->is_setting_type_valid( $setting['type'] ) ) {
return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'woocommerce' ), array( 'status' => 404 ) );
}
return $setting;
}
/**
* 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 ) {
// Get the request params.
$items = array_filter( $request->get_params() );
/*
* Since our batch settings update is group-specific and matches based on the route,
* we inject the URL parameters (containing group) into the batch items
*/
if ( ! empty( $items['update'] ) ) {
$to_update = array();
foreach ( $items['update'] as $item ) {
$to_update[] = array_merge( $request->get_url_params(), $item );
}
$request = new WP_REST_Request( $request->get_method() );
$request->set_body_params( array( 'update' => $to_update ) );
}
return parent::batch_items( $request );
}
/**
* Update a single setting in a group.
* @since 2.7.0
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public function update_item( $request ) {
$setting = $this->get_setting( $request['group'], $request['id'] );
if ( is_wp_error( $setting ) ) {
return $setting;
}
$update_data = array();
$update_data[ $setting['id'] ] = $request['value'];
WC_Admin_Settings::save_fields( array( $setting ), $update_data );
$response = $this->prepare_item_for_response( $setting, $request );
return rest_ensure_response( $response );
}
/**
* Prepare a single setting object for response.
*
* @since 2.7.0
* @param object $item Setting object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response Response data.
*/
public function prepare_item_for_response( $item, $request ) {
$data = $this->filter_setting( $item );
$data['value'] = WC_Admin_Settings::get_option( $data['id'] );
$context = empty( $request['context'] ) ? 'view' : $request['context'];
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );
$response = rest_ensure_response( $data );
$response->add_links( $this->prepare_links( $data['id'], $request['group'] ) );
return $response;
}
/**
* Prepare links for the request.
*
* @since 2.7.0
* @param string $setting_id Setting ID.
* @param string $group_id Group ID.
* @return array Links for the given setting.
*/
protected function prepare_links( $setting_id, $group_id ) {
$base = '/' . $this->namespace . '/' . $this->rest_base . '/' . $group_id;
$links = array(
'self' => array(
'href' => rest_url( trailingslashit( $base ) . $setting_id ),
),
'collection' => array(
'href' => rest_url( $base ),
),
);
return $links;
}
/**
* Makes sure the current user has access to READ the settings APIs.
*
* @since 2.7.0
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
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;
}
/**
* Makes sure the current user has access to WRITE the settings APIs.
*
* @since 2.7.0
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean
*/
public function update_items_permissions_check( $request ) {
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;
}
/**
* Filters out bad values from the settings array/filter so we
* only return known values via the API.
*
* @since 2.7.0
* @param array $setting
* @return array
*/
public function filter_setting( $setting ) {
$setting = array_intersect_key(
$setting,
array_flip( array_filter( array_keys( $setting ), array( $this, 'allowed_setting_keys' ) ) )
);
if ( empty( $setting['options'] ) ) {
unset( $setting['options'] );
}
return $setting;
}
/**
* Callback for allowed keys for each setting response.
*
* @since 2.7.0
* @param string $key Key to check
* @return boolean
*/
public function allowed_setting_keys( $key ) {
return in_array( $key, array(
'id', 'label', 'description', 'default', 'tip',
'placeholder', 'type', 'options', 'value',
) );
}
/**
* Boolean for if a setting type is a valid supported setting type.
*
* @since 2.7.0
* @param string $type
* @return boolean
*/
public function is_setting_type_valid( $type ) {
return in_array( $type, array(
'text', 'email', 'number', 'color', 'password',
'textarea', 'select', 'multiselect', 'radio', 'checkbox',
'multi_select_countries', 'image_width',
) );
}
/**
* Get the settings schema, conforming to JSON Schema.
*
* @since 2.7.0
* @return array
*/
public function get_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'settings',
'type' => 'object',
'properties' => array(
'id' => array(
'description' => __( 'A unique identifier for the setting.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_title',
),
),
'label' => array(
'description' => __( 'A human readable translation wrapped label. Meant to be used in interfaces.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'description' => array(
'description' => __( 'A human readable translation wrapped description. Meant to be used in interfaces.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'default' => array(
'description' => __( 'Default value for the setting.', 'woocommerce' ),
'type' => 'mixed',
),
'tip' => array(
'description' => __( 'Extra help text explaining the setting.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'placeholder' => array(
'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'type' => array(
'description' => __( 'Type of setting. Allowed values: text, email, number, color, password, textarea, select, multiselect, radio, image_width, checkbox.', 'woocommerce' ),
'type' => 'string',
'arg_options' => array(
'sanitize_callback' => 'sanitize_text_field',
),
),
'options' => array(
'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'woocommerce' ),
'type' => 'array',
),
),
);
return $this->add_additional_fields_schema( $schema );
}
}

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

@ -389,7 +389,7 @@ class WC_REST_Taxes_Controller extends WC_REST_Controller {
$tax_obj = WC_Tax::_get_tax_rate( $id, OBJECT );
if ( empty( $id ) || empty( $tax_obj ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$tax = $this->prepare_item_for_response( $tax_obj, $request );
@ -409,7 +409,7 @@ class WC_REST_Taxes_Controller extends WC_REST_Controller {
$tax_obj = WC_Tax::_get_tax_rate( $id, OBJECT );
if ( empty( $id ) || empty( $tax_obj ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$tax = $this->create_or_update_tax( $request, $tax_obj );
@ -452,7 +452,7 @@ class WC_REST_Taxes_Controller extends WC_REST_Controller {
$tax = WC_Tax::_get_tax_rate( $id, OBJECT );
if ( empty( $id ) || empty( $tax ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 400 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 400 ) );
}
$request->set_param( 'context', 'edit' );
@ -647,13 +647,13 @@ class WC_REST_Taxes_Controller extends WC_REST_Controller {
$params['context']['default'] = 'view';
$params['exclude'] = array(
'description' => __( 'Ensure result set excludes specific ids.', 'woocommerce' ),
'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['include'] = array(
'description' => __( 'Limit result set to specific ids.', 'woocommerce' ),
'description' => __( 'Limit result set to specific IDs.', 'woocommerce' ),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',

View File

@ -103,7 +103,7 @@ class WC_REST_Webhook_Deliveries_Controller extends WC_REST_Controller {
$webhook = new WC_Webhook( (int) $request['webhook_id'] );
if ( empty( $webhook->post_data->post_type ) || 'shop_webhook' !== $webhook->post_data->post_type ) {
return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$logs = $webhook->get_delivery_logs();
@ -129,13 +129,13 @@ class WC_REST_Webhook_Deliveries_Controller extends WC_REST_Controller {
$webhook = new WC_Webhook( (int) $request['webhook_id'] );
if ( empty( $webhook->post_data->post_type ) || 'shop_webhook' !== $webhook->post_data->post_type ) {
return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$log = $webhook->get_delivery_log( $id );
if ( empty( $id ) || empty( $log ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$delivery = $this->prepare_item_for_response( (object) $log, $request );

View File

@ -302,7 +302,7 @@ class WC_REST_Webhooks_Controller extends WC_REST_Posts_Controller {
$post = get_post( $id );
if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post id.', 'woocommerce' ), array( 'status' => 404 ) );
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$request->set_param( 'context', 'edit' );

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

@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( ! class_exists( 'WC_Legacy_API' ) ) {
include_once( 'class-wc-legacy-api.php' );
include_once( dirname( __FILE__ ) . '/class-wc-legacy-api.php' );
}
class WC_API extends WC_Legacy_API {
@ -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;
}
@ -129,43 +127,52 @@ class WC_API extends WC_Legacy_API {
*/
private function rest_api_includes() {
// Exception handler.
include_once( 'api/class-wc-rest-exception.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-exception.php' );
// Authentication.
include_once( 'api/class-wc-rest-authentication.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-authentication.php' );
// WP-API classes and functions.
include_once( 'vendor/wp-rest-functions.php' );
include_once( dirname( __FILE__ ) . '/vendor/wp-rest-functions.php' );
if ( ! class_exists( 'WP_REST_Controller' ) ) {
include_once( 'vendor/class-wp-rest-controller.php' );
include_once( dirname( __FILE__ ) . '/vendor/class-wp-rest-controller.php' );
}
// Abstract controllers.
include_once( 'abstracts/abstract-wc-rest-controller.php' );
include_once( 'abstracts/abstract-wc-rest-posts-controller.php' );
include_once( 'abstracts/abstract-wc-rest-terms-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-posts-controller.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-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( 'api/class-wc-rest-coupons-controller.php' );
include_once( 'api/class-wc-rest-customer-downloads-controller.php' );
include_once( 'api/class-wc-rest-customers-controller.php' );
include_once( 'api/class-wc-rest-order-notes-controller.php' );
include_once( 'api/class-wc-rest-order-refunds-controller.php' );
include_once( 'api/class-wc-rest-orders-controller.php' );
include_once( 'api/class-wc-rest-product-attribute-terms-controller.php' );
include_once( 'api/class-wc-rest-product-attributes-controller.php' );
include_once( 'api/class-wc-rest-product-categories-controller.php' );
include_once( 'api/class-wc-rest-product-reviews-controller.php' );
include_once( 'api/class-wc-rest-product-shipping-classes-controller.php' );
include_once( 'api/class-wc-rest-product-tags-controller.php' );
include_once( 'api/class-wc-rest-products-controller.php' );
include_once( 'api/class-wc-rest-report-sales-controller.php' );
include_once( 'api/class-wc-rest-report-top-sellers-controller.php' );
include_once( 'api/class-wc-rest-reports-controller.php' );
include_once( 'api/class-wc-rest-tax-classes-controller.php' );
include_once( 'api/class-wc-rest-taxes-controller.php' );
include_once( 'api/class-wc-rest-webhook-deliveries.php' );
include_once( 'api/class-wc-rest-webhooks-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-coupons-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-customer-downloads-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-customers-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-order-notes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-order-refunds-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-orders-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-attribute-terms-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-attributes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-categories-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-reviews-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-shipping-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-product-tags-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-products-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-report-sales-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-report-top-sellers-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-reports-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-settings-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-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' );
}
/**
@ -173,6 +180,9 @@ class WC_API extends WC_Legacy_API {
* @since 2.6.0
*/
public function register_rest_routes() {
// Register settings to the REST API.
$this->register_wp_admin_settings();
$controllers = array(
'WC_REST_Coupons_Controller',
'WC_REST_Customer_Downloads_Controller',
@ -190,10 +200,16 @@ class WC_API extends WC_Legacy_API {
'WC_REST_Report_Sales_Controller',
'WC_REST_Report_Top_Sellers_Controller',
'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 ) {
@ -201,4 +217,16 @@ class WC_API extends WC_Legacy_API {
$this->$controller->register_routes();
}
}
/**
* Register WC settings from WP-API to the REST API.
* @since 2.7.0
*/
public function register_wp_admin_settings() {
$pages = WC_Admin_Settings::get_settings_pages();
foreach ( $pages as $page ) {
new WC_Register_WP_Admin_Settings( $page );
}
}
}

View File

@ -16,8 +16,8 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
include_once( 'libraries/wp-async-request.php' );
include_once( 'libraries/wp-background-process.php' );
include_once( dirname( __FILE__ ) . '/libraries/wp-async-request.php' );
include_once( dirname( __FILE__ ) . '/libraries/wp-background-process.php' );
/**
* WC_Background_Updater Class.
@ -36,7 +36,7 @@ class WC_Background_Updater extends WP_Background_Process {
*/
public function dispatch() {
$dispatched = parent::dispatch();
$logger = new WC_Logger();
$logger = wc_get_logger();
if ( is_wp_error( $dispatched ) ) {
$logger->add( 'wc_db_updates', sprintf( 'Unable to dispatch WooCommerce updater: %s', $dispatched->get_error_message() ) );
@ -97,9 +97,9 @@ class WC_Background_Updater extends WP_Background_Process {
define( 'WC_UPDATING', true );
}
$logger = new WC_Logger();
$logger = wc_get_logger();
include_once( 'wc-update-functions.php' );
include_once( dirname( __FILE__ ) . '/wc-update-functions.php' );
if ( is_callable( $callback ) ) {
$logger->add( 'wc_db_updates', sprintf( 'Running %s callback', $callback ) );
@ -119,7 +119,7 @@ class WC_Background_Updater extends WP_Background_Process {
* performed, or, call parent::complete().
*/
protected function complete() {
$logger = new WC_Logger();
$logger = wc_get_logger();
$logger->add( 'wc_db_updates', 'Data update complete' );
WC_Install::update_db_version();
parent::complete();

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

@ -1289,8 +1289,8 @@ class WC_Cart {
// Apply discounts and get the discounted price FOR A SINGLE ITEM
$discounted_price = $this->get_discounted_price( $values, $adjusted_price, true );
// Convert back to line price and round nicely
$discounted_line_price = round( $discounted_price * $values['quantity'], $this->dp );
// Convert back to line price
$discounted_line_price = $discounted_price * $values['quantity'];
// Now use rounded line price to get taxes.
$discounted_taxes = WC_Tax::calc_tax( $discounted_line_price, $item_tax_rates, true );
@ -1312,8 +1312,8 @@ class WC_Cart {
// Calc prices and tax (discounted)
$discounted_price = $this->get_discounted_price( $values, $base_price, true );
// Convert back to line price and round nicely
$discounted_line_price = round( $discounted_price * $values['quantity'], $this->dp );
// Convert back to line price
$discounted_line_price = $discounted_price * $values['quantity'];
// Now use rounded line price to get taxes.
$discounted_taxes = WC_Tax::calc_tax( $discounted_line_price, $item_tax_rates, true );
@ -1356,15 +1356,27 @@ class WC_Cart {
// Cart contents total is based on discounted prices and is used for the final total calculation
$this->cart_contents_total += $line_total;
// Store costs + taxes for lines
/**
* Store costs + taxes for lines. For tax inclusive prices, we do some extra rounding logic so the stored
* values "add up" when viewing the order in admin. This does have the disadvatage of not being able to
* recalculate the tax total/subtotal accurately in the future, but it does ensure the data looks correct.
*
* Tax exclusive prices are not affected.
*/
if ( ! $_product->is_taxable() || $this->prices_include_tax ) {
$this->cart_contents[ $cart_item_key ]['line_total'] = round( $line_total + $line_tax - wc_round_tax_total( $line_tax ), $this->dp );
$this->cart_contents[ $cart_item_key ]['line_subtotal'] = round( $line_subtotal + $line_subtotal_tax - wc_round_tax_total( $line_subtotal_tax ), $this->dp );
$this->cart_contents[ $cart_item_key ]['line_tax'] = wc_round_tax_total( $line_tax );
$this->cart_contents[ $cart_item_key ]['line_subtotal_tax'] = wc_round_tax_total( $line_subtotal_tax );
$this->cart_contents[ $cart_item_key ]['line_tax_data'] = array( 'total' => array_map( 'wc_round_tax_total', $discounted_taxes ), 'subtotal' => array_map( 'wc_round_tax_total', $taxes ) );
} else {
$this->cart_contents[ $cart_item_key ]['line_total'] = $line_total;
$this->cart_contents[ $cart_item_key ]['line_tax'] = $line_tax;
$this->cart_contents[ $cart_item_key ]['line_subtotal'] = $line_subtotal;
$this->cart_contents[ $cart_item_key ]['line_tax'] = $line_tax;
$this->cart_contents[ $cart_item_key ]['line_subtotal_tax'] = $line_subtotal_tax;
// Store rates ID and costs - Since 2.2
$this->cart_contents[ $cart_item_key ]['line_tax_data'] = array( 'total' => $discounted_taxes, 'subtotal' => $taxes );
}
}
// Only calculate the grand total + shipping if on the cart/checkout
if ( is_checkout() || is_cart() || defined('WOOCOMMERCE_CHECKOUT') || defined('WOOCOMMERCE_CART') ) {

View File

@ -129,7 +129,7 @@ class WC_Emails {
*/
public function init() {
// Include email classes
include_once( 'emails/class-wc-email.php' );
include_once( dirname( __FILE__ ) . '/emails/class-wc-email.php' );
$this->emails['WC_Email_New_Order'] = include( 'emails/class-wc-email-new-order.php' );
$this->emails['WC_Email_Cancelled_Order'] = include( 'emails/class-wc-email-cancelled-order.php' );
@ -147,7 +147,7 @@ class WC_Emails {
// include css inliner
if ( ! class_exists( 'Emogrifier' ) && class_exists( 'DOMDocument' ) ) {
include_once( 'libraries/class-emogrifier.php' );
include_once( dirname( __FILE__ ) . '/libraries/class-emogrifier.php' );
}
}

View File

@ -146,7 +146,7 @@ class WC_Form_Handler {
do_action( 'woocommerce_customer_save_address', $user_id, $load_address );
wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
wp_safe_redirect( wc_get_endpoint_url( 'edit-address', '', wc_get_page_permalink( 'myaccount' ) ) );
exit;
}
}
@ -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

@ -1168,12 +1168,8 @@ class WC_Geo_IP {
* @param string $message
*/
public static function log( $message ) {
if ( ! class_exists( 'WC_Logger' ) ) {
include_once( 'class-wc-logger.php' );
}
if ( empty( self::$log ) ) {
self::$log = new WC_Logger();
self::$log = wc_get_logger();
}
self::$log->add( 'geoip', $message );
}

View File

@ -176,7 +176,7 @@ class WC_Geolocation {
* Update geoip database. Adapted from https://wordpress.org/plugins/geoip-detect/.
*/
public static function update_database() {
$logger = new WC_Logger();
$logger = wc_get_logger();
if ( ! is_callable( 'gzopen' ) ) {
$logger->add( 'geolocation', 'Server does not support gzopen' );
@ -218,7 +218,7 @@ class WC_Geolocation {
*/
private static function geolocate_via_db( $ip_address ) {
if ( ! class_exists( 'WC_Geo_IP' ) ) {
include_once( 'class-wc-geo-ip.php' );
include_once( dirname( __FILE__ ) . '/class-wc-geo-ip.php' );
}
$gi = new WC_Geo_IP();

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 */
@ -96,7 +99,7 @@ class WC_Install {
* Init background updates
*/
public static function init_background_updater() {
include_once( 'class-wc-background-updater.php' );
include_once( dirname( __FILE__ ) . '/class-wc-background-updater.php' );
self::$background_updater = new WC_Background_Updater();
}
@ -139,7 +142,7 @@ class WC_Install {
}
// Ensure needed classes are loaded
include_once( 'admin/class-wc-admin-notices.php' );
include_once( dirname( __FILE__ ) . '/admin/class-wc-admin-notices.php' );
self::create_options();
self::create_tables();
@ -218,7 +221,7 @@ class WC_Install {
*/
private static function update() {
$current_db_version = get_option( 'woocommerce_db_version' );
$logger = new WC_Logger();
$logger = wc_get_logger();
$update_queued = false;
foreach ( self::$db_updates as $version => $update_callbacks ) {
@ -287,7 +290,7 @@ class WC_Install {
* Create pages that the plugin relies on, storing page id's in variables.
*/
public static function create_pages() {
include_once( 'admin/wc-admin-functions.php' );
include_once( dirname( __FILE__ ) . '/admin/wc-admin-functions.php' );
$pages = apply_filters( 'woocommerce_create_pages', array(
'shop' => array(
@ -326,7 +329,7 @@ class WC_Install {
*/
private static function create_options() {
// Include settings so that we can run through defaults
include_once( 'admin/class-wc-admin-settings.php' );
include_once( dirname( __FILE__ ) . '/admin/class-wc-admin-settings.php' );
$settings = WC_Admin_Settings::get_settings_pages();

View File

@ -124,23 +124,23 @@ class WC_Legacy_API {
public function includes() {
// API server / response handlers.
include_once( 'api/legacy/v3/class-wc-api-exception.php' );
include_once( 'api/legacy/v3/class-wc-api-server.php' );
include_once( 'api/legacy/v3/interface-wc-api-handler.php' );
include_once( 'api/legacy/v3/class-wc-api-json-handler.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-exception.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-server.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/interface-wc-api-handler.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-json-handler.php' );
// Authentication.
include_once( 'api/legacy/v3/class-wc-api-authentication.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-authentication.php' );
$this->authentication = new WC_API_Authentication();
include_once( 'api/legacy/v3/class-wc-api-resource.php' );
include_once( 'api/legacy/v3/class-wc-api-coupons.php' );
include_once( 'api/legacy/v3/class-wc-api-customers.php' );
include_once( 'api/legacy/v3/class-wc-api-orders.php' );
include_once( 'api/legacy/v3/class-wc-api-products.php' );
include_once( 'api/legacy/v3/class-wc-api-reports.php' );
include_once( 'api/legacy/v3/class-wc-api-taxes.php' );
include_once( 'api/legacy/v3/class-wc-api-webhooks.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-resource.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-coupons.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-customers.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-orders.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-products.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-reports.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-taxes.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v3/class-wc-api-webhooks.php' );
// Allow plugins to load other response handlers or resource classes.
do_action( 'woocommerce_api_loaded' );
@ -182,20 +182,20 @@ class WC_Legacy_API {
private function handle_v1_rest_api_request() {
// Include legacy required files for v1 REST API request.
include_once( 'api/legacy/v1/class-wc-api-server.php' );
include_once( 'api/legacy/v1/interface-wc-api-handler.php' );
include_once( 'api/legacy/v1/class-wc-api-json-handler.php' );
include_once( 'api/legacy/v1/class-wc-api-xml-handler.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-server.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/interface-wc-api-handler.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-json-handler.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-xml-handler.php' );
include_once( 'api/legacy/v1/class-wc-api-authentication.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-authentication.php' );
$this->authentication = new WC_API_Authentication();
include_once( 'api/legacy/v1/class-wc-api-resource.php' );
include_once( 'api/legacy/v1/class-wc-api-coupons.php' );
include_once( 'api/legacy/v1/class-wc-api-customers.php' );
include_once( 'api/legacy/v1/class-wc-api-orders.php' );
include_once( 'api/legacy/v1/class-wc-api-products.php' );
include_once( 'api/legacy/v1/class-wc-api-reports.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-resource.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-coupons.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-customers.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-orders.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-products.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v1/class-wc-api-reports.php' );
// Allow plugins to load other response handlers or resource classes.
do_action( 'woocommerce_api_loaded' );
@ -228,21 +228,21 @@ class WC_Legacy_API {
* @deprecated 2.6.0
*/
private function handle_v2_rest_api_request() {
include_once( 'api/legacy/v2/class-wc-api-exception.php' );
include_once( 'api/legacy/v2/class-wc-api-server.php' );
include_once( 'api/legacy/v2/interface-wc-api-handler.php' );
include_once( 'api/legacy/v2/class-wc-api-json-handler.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-exception.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-server.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/interface-wc-api-handler.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-json-handler.php' );
include_once( 'api/legacy/v2/class-wc-api-authentication.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-authentication.php' );
$this->authentication = new WC_API_Authentication();
include_once( 'api/legacy/v2/class-wc-api-resource.php' );
include_once( 'api/legacy/v2/class-wc-api-coupons.php' );
include_once( 'api/legacy/v2/class-wc-api-customers.php' );
include_once( 'api/legacy/v2/class-wc-api-orders.php' );
include_once( 'api/legacy/v2/class-wc-api-products.php' );
include_once( 'api/legacy/v2/class-wc-api-reports.php' );
include_once( 'api/legacy/v2/class-wc-api-webhooks.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-resource.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-coupons.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-customers.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-orders.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-products.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-reports.php' );
include_once( dirname( __FILE__ ) . '/api/legacy/v2/class-wc-api-webhooks.php' );
// allow plugins to load other response handlers or resource classes.
do_action( 'woocommerce_api_loaded' );

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

@ -60,20 +60,20 @@ class WC_Post_types {
apply_filters( 'woocommerce_taxonomy_args_product_cat', array(
'hierarchical' => true,
'update_count_callback' => '_wc_term_recount',
'label' => __( 'Product Categories', 'woocommerce' ),
'label' => __( 'Categories', 'woocommerce' ),
'labels' => array(
'name' => __( 'Product Categories', 'woocommerce' ),
'singular_name' => __( 'Product Category', 'woocommerce' ),
'name' => __( 'Categories', 'woocommerce' ),
'singular_name' => __( 'Category', 'woocommerce' ),
'menu_name' => _x( 'Categories', 'Admin menu name', 'woocommerce' ),
'search_items' => __( 'Search Product Categories', 'woocommerce' ),
'all_items' => __( 'All Product Categories', 'woocommerce' ),
'parent_item' => __( 'Parent Product Category', 'woocommerce' ),
'parent_item_colon' => __( 'Parent Product Category:', 'woocommerce' ),
'edit_item' => __( 'Edit Product Category', 'woocommerce' ),
'update_item' => __( 'Update Product Category', 'woocommerce' ),
'add_new_item' => __( 'Add New Product Category', 'woocommerce' ),
'new_item_name' => __( 'New Product Category Name', 'woocommerce' ),
'not_found' => __( 'No Product Category found', 'woocommerce' ),
'search_items' => __( 'Search Categories', 'woocommerce' ),
'all_items' => __( 'All Categories', 'woocommerce' ),
'parent_item' => __( 'Parent Category', 'woocommerce' ),
'parent_item_colon' => __( 'Parent Category:', 'woocommerce' ),
'edit_item' => __( 'Edit Category', 'woocommerce' ),
'update_item' => __( 'Update Category', 'woocommerce' ),
'add_new_item' => __( 'Add New Category', 'woocommerce' ),
'new_item_name' => __( 'New Category Name', 'woocommerce' ),
'not_found' => __( 'No categories found', 'woocommerce' ),
),
'show_ui' => true,
'query_var' => true,
@ -98,20 +98,20 @@ class WC_Post_types {
'update_count_callback' => '_wc_term_recount',
'label' => __( 'Product Tags', 'woocommerce' ),
'labels' => array(
'name' => __( 'Product Tags', 'woocommerce' ),
'singular_name' => __( 'Product Tag', 'woocommerce' ),
'name' => __( 'Tags', 'woocommerce' ),
'singular_name' => __( 'Tag', 'woocommerce' ),
'menu_name' => _x( 'Tags', 'Admin menu name', 'woocommerce' ),
'search_items' => __( 'Search Product Tags', 'woocommerce' ),
'all_items' => __( 'All Product Tags', 'woocommerce' ),
'edit_item' => __( 'Edit Product Tag', 'woocommerce' ),
'update_item' => __( 'Update Product Tag', 'woocommerce' ),
'add_new_item' => __( 'Add New Product Tag', 'woocommerce' ),
'new_item_name' => __( 'New Product Tag Name', 'woocommerce' ),
'popular_items' => __( 'Popular Product Tags', 'woocommerce' ),
'separate_items_with_commas' => __( 'Separate Product Tags with commas', 'woocommerce' ),
'add_or_remove_items' => __( 'Add or remove Product Tags', 'woocommerce' ),
'choose_from_most_used' => __( 'Choose from the most used Product tags', 'woocommerce' ),
'not_found' => __( 'No Product Tags found', 'woocommerce' ),
'search_items' => __( 'Search Tags', 'woocommerce' ),
'all_items' => __( 'All Tags', 'woocommerce' ),
'edit_item' => __( 'Edit Tag', 'woocommerce' ),
'update_item' => __( 'Update Tag', 'woocommerce' ),
'add_new_item' => __( 'Add New Tag', 'woocommerce' ),
'new_item_name' => __( 'New Tag Name', 'woocommerce' ),
'popular_items' => __( 'Popular Tags', 'woocommerce' ),
'separate_items_with_commas' => __( 'Separate Tags with commas', 'woocommerce' ),
'add_or_remove_items' => __( 'Add or remove Tags', 'woocommerce' ),
'choose_from_most_used' => __( 'Choose from the most used tags', 'woocommerce' ),
'not_found' => __( 'No tags found', 'woocommerce' ),
),
'show_ui' => true,
'query_var' => true,

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

@ -219,6 +219,22 @@ class WC_Query {
}
}
/**
* Are we currently on the front page?
* @return boolean
*/
private function is_showing_page_on_front( $q ) {
return $q->is_home() && 'page' === get_option( 'show_on_front' );
}
/**
* Is the front page a page we define?
* @return boolean
*/
private function page_on_front_is( $page_id ) {
return absint( get_option( 'page_on_front' ) ) === absint( $page_id );
}
/**
* Hook into pre_get_posts to do the main product query.
*
@ -230,21 +246,8 @@ class WC_Query {
return;
}
// Fix for verbose page rules
if ( $GLOBALS['wp_rewrite']->use_verbose_page_rules && isset( $q->queried_object->ID ) && $q->queried_object->ID === wc_get_page_id( 'shop' ) ) {
$q->set( 'post_type', 'product' );
$q->set( 'page', '' );
$q->set( 'pagename', '' );
// Fix conditional Functions
$q->is_archive = true;
$q->is_post_type_archive = true;
$q->is_singular = false;
$q->is_page = false;
}
// Fix for endpoints on the homepage
if ( $q->is_home() && 'page' === get_option( 'show_on_front' ) && absint( get_option( 'page_on_front' ) ) !== absint( $q->get( 'page_id' ) ) ) {
if ( $this->is_showing_page_on_front( $q ) && ! $this->page_on_front_is( $q->get( 'page_id' ) ) ) {
$_query = wp_parse_args( $q->query );
if ( ! empty( $_query ) && array_intersect( array_keys( $_query ), array_keys( $this->query_vars ) ) ) {
$q->is_page = true;
@ -256,7 +259,7 @@ class WC_Query {
}
// When orderby is set, WordPress shows posts. Get around that here.
if ( $q->is_home() && 'page' === get_option( 'show_on_front' ) && absint( get_option( 'page_on_front' ) ) === wc_get_page_id( 'shop' ) ) {
if ( $this->is_showing_page_on_front( $q ) && $this->page_on_front_is( wc_get_page_id( 'shop' ) ) ) {
$_query = wp_parse_args( $q->query );
if ( empty( $_query ) || ! array_diff( array_keys( $_query ), array( 'preview', 'page', 'paged', 'cpage', 'orderby' ) ) ) {
$q->is_page = true;
@ -273,7 +276,6 @@ class WC_Query {
// Special check for shops with the product archive on front
if ( $q->is_page() && 'page' === get_option( 'show_on_front' ) && absint( $q->get( 'page_id' ) ) === wc_get_page_id( 'shop' ) ) {
// This is a front-page shop
$q->set( 'post_type', 'product' );
$q->set( 'page_id', '' );

View File

@ -0,0 +1,111 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Take settings registered for WP-Admin and hooks them up to the REST API.
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @category Class
*/
class WC_Register_WP_Admin_Settings {
/** @var class Current settings class. Used to pull settings. */
protected $page;
/**
* Hooks into the settings API and starts registering our settings.
*
* @since 2.7.0
*/
public function __construct( $page ) {
$this->page = $page;
add_filter( 'woocommerce_settings_groups', array( $this, 'register_group' ) );
add_filter( 'woocommerce_settings-' . $this->page->get_id(), array( $this, 'register_settings' ) );
}
/**
* Registers a setting group, based on admin page ID & label as parent group.
*
* @since 2.7.0
* @param array $groups Array of previously registered groups.
* @return array
*/
public function register_group( $groups ) {
$groups[] = array(
'id' => $this->page->get_id(),
'label' => $this->page->get_label(),
);
return $groups;
}
/**
* Registers settings to a specific group.
*
* @since 2.7.0
* @param array $settings Existing registered settings
* @return array
*/
public function register_settings( $settings ) {
/**
* wp-admin settings can be broken down into separate sections from
* a UI standpoint. This will grab all the sections associated with
* a particular setting group (like 'products') and register them
* to the REST API.
*/
$sections = $this->page->get_sections();
if ( empty( $sections ) ) {
// Default section is just an empty string, per admin page classes
$sections = array( '' );
}
foreach ( $sections as $section => $section_label ) {
$settings_from_section = $this->page->get_settings( $section );
foreach ( $settings_from_section as $setting ) {
$new_setting = $this->register_setting( $setting );
if ( $new_setting ) {
$settings[] = $new_setting;
}
}
}
return $settings;
}
/**
* Register's a specific setting (from WC_Settings_Page::get_settings() )
* into the format expected for the REST API Settings Controller.
*
* @since 2.7.0
* @param array $setting Settings array, as produced by a subclass of WC_Settings_Page.
* @return array|bool boolean False if setting has no ID or converted array.
*/
public function register_setting( $setting ) {
if ( ! isset( $setting['id'] ) ) {
return false;
}
$new_setting = array(
'id' => $setting['id'],
'label' => ( ! empty( $setting['title'] ) ? $setting['title'] : '' ),
'description' => ( ! empty( $setting['desc'] ) ? $setting['desc'] : '' ),
'type' => $setting['type'],
);
if ( isset( $setting['default'] ) ) {
$new_setting['default'] = $setting['default'];
}
if ( isset( $setting['options'] ) ) {
$new_setting['options'] = $setting['options'];
}
if ( isset( $setting['desc_tip'] ) ) {
if ( true === $setting['desc_tip'] ) {
$new_setting['tip'] = $setting['desc'];
} else if ( ! empty( $setting['desc_tip'] ) ) {
$new_setting['tip'] = $setting['desc_tip'];
}
}
return $new_setting;
}
}

View File

@ -4,7 +4,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( ! class_exists( 'WC_Session' ) ) {
include_once( 'abstracts/abstract-wc-session.php' );
include_once( dirname( __FILE__ ) . '/abstracts/abstract-wc-session.php' );
}
/**

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

@ -411,7 +411,7 @@ class WC_Email extends WC_Settings_API {
$emogrifier = new Emogrifier( $content, $css );
$content = $emogrifier->emogrify();
} catch ( Exception $e ) {
$logger = new WC_Logger();
$logger = wc_get_logger();
$logger->add( 'emogrifier', $e->getMessage() );
}
}

View File

@ -56,15 +56,17 @@ 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';
} else {
include_once( 'includes/class-wc-gateway-paypal-ipn-handler.php' );
include_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-ipn-handler.php' );
new WC_Gateway_Paypal_IPN_Handler( $this->testmode, $this->receiver_email );
if ( $this->identity_token ) {
include_once( 'includes/class-wc-gateway-paypal-pdt-handler.php' );
include_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-pdt-handler.php' );
new WC_Gateway_Paypal_PDT_Handler( $this->testmode, $this->identity_token );
}
}
@ -77,7 +79,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
public static function log( $message ) {
if ( self::$log_enabled ) {
if ( empty( self::$log ) ) {
self::$log = new WC_Logger();
self::$log = wc_get_logger();
}
self::$log->add( 'paypal', $message );
}
@ -236,7 +238,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
* @return array
*/
public function process_payment( $order_id ) {
include_once( 'includes/class-wc-gateway-paypal-request.php' );
include_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-request.php' );
$order = wc_get_order( $order_id );
$paypal_request = new WC_Gateway_Paypal_Request( $this );
@ -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( '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;
}
}
}
}
}

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