Update from master

This commit is contained in:
Mike Jolley 2019-02-18 15:04:58 +00:00
commit 4fd2a9f77e
229 changed files with 15465 additions and 13452 deletions

View File

@ -24,7 +24,6 @@ exclude_paths:
- "includes/api/legacy/"
- "includes/libraries/"
- "includes/updates/"
- "includes/gateways/simplify-commerce/"
- "includes/shipping/legacy-*"
- "includes/wc-deprecated-functions.php"
- "assets/js/accounting/"

View File

@ -7,12 +7,16 @@
"globals": {
"wp": true,
"wpApiSettings": true,
"wcSettings": true
"wcSettings": true,
"es6": true
},
"rules": {
"camelcase": 0,
"indent": 0,
"max-len": [ 2, { "code": 140 } ],
"no-console": 1
},
"parserOptions": {
"ecmaVersion": 6
}
}

View File

@ -27,7 +27,6 @@ filter:
- sample-data/
- i18n/
- includes/api/legacy/
- includes/gateways/simplify-commerce/includes/
- includes/legacy/
- includes/libraries/
- includes/shipping/legacy-*

View File

@ -1,60 +1,3 @@
{
"rules": {
"indentation": "tab",
"color-hex-case": "lower",
"color-no-invalid-hex": true,
"function-calc-no-unspaced-operator": true,
"function-comma-space-after": "always-single-line",
"function-comma-space-before": "never",
"function-name-case": "lower",
"function-url-quotes": "always",
"function-whitespace-after": "always",
"number-leading-zero": "always",
"number-no-trailing-zeros": true,
"length-zero-no-unit": true,
"string-no-newline": true,
"string-quotes": "single",
"unit-case": "lower",
"unit-no-unknown": true,
"unit-whitelist": ["px", "%", "deg", "ms", "em", "vh", "vw", "rem", "s", "ex", "pt", "cm"],
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
"shorthand-property-no-redundant-values": true,
"property-case": "lower",
"declaration-block-no-duplicate-properties": [true, { "severity": "warning" } ],
"declaration-block-no-ignored-properties": [true, { "severity": "warning" } ],
"declaration-block-trailing-semicolon": "always",
"declaration-block-single-line-max-declarations": 0,
"declaration-block-semicolon-space-before": "never",
"declaration-block-semicolon-space-after": "always-single-line",
"declaration-block-semicolon-newline-before": "never-multi-line",
"declaration-block-semicolon-newline-after": "always-multi-line",
"block-closing-brace-newline-after": "always",
"block-closing-brace-newline-before": "always-multi-line",
"block-no-empty": true,
"block-opening-brace-newline-after": "always-multi-line",
"block-opening-brace-space-before": "always",
"selector-attribute-brackets-space-inside": "never",
"selector-attribute-operator-space-after": "never",
"selector-attribute-operator-space-before": "never",
"selector-combinator-space-after": "always",
"selector-combinator-space-before": "always",
"selector-pseudo-class-case": "lower",
"selector-pseudo-class-parentheses-space-inside": "always",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-colon-notation": "double",
"selector-pseudo-element-no-unknown": true,
"selector-type-case": "lower",
"selector-no-id": [true, { "severity": "warning" } ]
}
"extends": "stylelint-config-wordpress",
}

View File

@ -1,6 +1,7 @@
/* jshint node:true */
module.exports = function( grunt ) {
'use strict';
const sass = require( 'node-sass' );
grunt.initConfig({
@ -22,9 +23,7 @@ module.exports = function( grunt ) {
'<%= dirs.js %>/admin/*.js',
'!<%= dirs.js %>/admin/*.min.js',
'<%= dirs.js %>/frontend/*.js',
'!<%= dirs.js %>/frontend/*.min.js',
'includes/gateways/simplify-commerce/assets/js/*.js',
'!includes/gateways/simplify-commerce/assets/js/*.min.js'
'!<%= dirs.js %>/frontend/*.min.js'
]
},
@ -75,9 +74,13 @@ module.exports = function( grunt ) {
'<%= dirs.js %>/jquery-flot/jquery.flot.time.min.js': ['<%= dirs.js %>/jquery-flot/jquery.flot.time.js'],
'<%= dirs.js %>/jquery-payment/jquery.payment.min.js': ['<%= dirs.js %>/jquery-payment/jquery.payment.js'],
'<%= dirs.js %>/jquery-qrcode/jquery.qrcode.min.js': ['<%= dirs.js %>/jquery-qrcode/jquery.qrcode.js'],
'<%= dirs.js %>/jquery-serializejson/jquery.serializejson.min.js': ['<%= dirs.js %>/jquery-serializejson/jquery.serializejson.js'],
'<%= dirs.js %>/jquery-serializejson/jquery.serializejson.min.js': [
'<%= dirs.js %>/jquery-serializejson/jquery.serializejson.js'
],
'<%= dirs.js %>/jquery-tiptip/jquery.tipTip.min.js': ['<%= dirs.js %>/jquery-tiptip/jquery.tipTip.js'],
'<%= dirs.js %>/jquery-ui-touch-punch/jquery-ui-touch-punch.min.js': ['<%= dirs.js %>/jquery-ui-touch-punch/jquery-ui-touch-punch.js'],
'<%= dirs.js %>/jquery-ui-touch-punch/jquery-ui-touch-punch.min.js': [
'<%= dirs.js %>/jquery-ui-touch-punch/jquery-ui-touch-punch.js'
],
'<%= dirs.js %>/prettyPhoto/jquery.prettyPhoto.init.min.js': ['<%= dirs.js %>/prettyPhoto/jquery.prettyPhoto.init.js'],
'<%= dirs.js %>/prettyPhoto/jquery.prettyPhoto.min.js': ['<%= dirs.js %>/prettyPhoto/jquery.prettyPhoto.js'],
'<%= dirs.js %>/flexslider/jquery.flexslider.min.js': ['<%= dirs.js %>/flexslider/jquery.flexslider.js'],
@ -112,6 +115,7 @@ module.exports = function( grunt ) {
sass: {
compile: {
options: {
implementation: sass,
sourceMap: 'none'
},
files: [{
@ -260,7 +264,9 @@ module.exports = function( grunt ) {
contributors: {
command: [
'echo "Generating contributor list since <%= fromDate %>"',
'./node_modules/.bin/githubcontrib --owner woocommerce --repo woocommerce --fromDate <%= fromDate %> --authToken <%= authToken %> --cols 6 --sortBy contributions --format md --sortOrder desc --showlogin true > contributors.md'
'./node_modules/.bin/githubcontrib --owner woocommerce --repo woocommerce --fromDate <%= fromDate %>' +
' --authToken <%= authToken %> --cols 6 --sortBy contributions --format md --sortOrder desc' +
' --showlogin true > contributors.md'
].join( '&&' )
}
},
@ -277,7 +283,8 @@ module.exports = function( grunt ) {
{
config: 'authToken',
type: 'input',
message: '(optional) Provide a personal access token. This will allow 5000 requests per hour rather than 60 - use if nothing is generated.'
message: '(optional) Provide a personal access token.' +
' This will allow 5000 requests per hour rather than 60 - use if nothing is generated.'
}
]
}
@ -298,15 +305,14 @@ module.exports = function( grunt ) {
},
dist: {
src: [
'**/*.php', // Include all files
'!apigen/**', // Exclude apigen/
'!includes/api/legacy/**', // Exclude legacy REST API
'!includes/gateways/simplify-commerce/includes/Simplify/**', // Exclude simplify commerce SDK
'!includes/libraries/**', // Exclude libraries/
'!node_modules/**', // Exclude node_modules/
'!tests/cli/**', // Exclude tests/cli/
'!tmp/**', // Exclude tmp/
'!vendor/**' // Exclude vendor/
'**/*.php', // Include all php files.
'!apigen/**',
'!includes/api/legacy/**',
'!includes/libraries/**',
'!node_modules/**',
'!tests/cli/**',
'!tmp/**',
'!vendor/**'
]
}
},

View File

@ -10,12 +10,6 @@ div.woocommerce-message {
overflow: hidden;
position: relative;
border-left-color: #cc99c2 !important;
p {
max-width: 700px;
}
p:last-child {
max-width: inherit;
}
}
p.woocommerce-actions,
@ -76,7 +70,6 @@ div.woocommerce-no-shipping-methods-notice {
p {
position: relative;
z-index: 1;
max-width: 700px;
line-height: 1.5em;
margin: 12px 0;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -583,17 +583,6 @@
color: inherit;
}
.simplify-commerce-banner {
overflow: hidden;
img {
float: right;
padding: 15px 0;
margin-left: 1em;
width: 200px;
}
}
/**
* Help Tip
*/
@ -3686,15 +3675,15 @@
padding: 0 15px 10px 0;
}
}
.wc-shipping-zone-settings {
td.forminp {
input, textarea {
width: 448px;
padding: 6px 11px;
}
.select2-search input {
padding: 6px;
}
@ -4797,8 +4786,20 @@
float: right;
}
input[type=text],
input[type=number],
input[type="text"],
input[type="number"],
input[type="password"],
input[type="color"],
input[type="date"],
input[type="datetime"],
input[type="datetime-local"],
input[type="email"],
input[type="month"],
input[type="search"],
input[type="tel"],
input[type="time"],
input[type="url"],
input[type="week"],
select,
textarea {
width: 100%;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -80,6 +80,17 @@
visibility: visible;
}
}
.woocommerce-form-login {
.woocommerce-form-login__submit {
float: left;
margin-right: 1em;
}
.woocommerce-form-login__rememberme {
display: inline-block;
line-height: 3em;
}
}
}
.woocommerce-breadcrumb {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1670,6 +1670,16 @@ p.demo_store,
color: $red;
}
}
.woocommerce-form-login {
.woocommerce-form-login__submit {
float: left;
margin-right: 1em;
}
.woocommerce-form-login__rememberme {
display: inline-block;
}
}
}
.woocommerce-no-js {

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

View File

@ -1,7 +1,8 @@
/*global woocommerce_admin_meta_boxes */
jQuery( function( $ ) {
// Scroll to first checked category - https://github.com/scribu/wp-category-checklist-tree/blob/d1c3c1f449e1144542efa17dde84a9f52ade1739/category-checklist-tree.php
// Scroll to first checked category
// https://github.com/scribu/wp-category-checklist-tree/blob/d1c3c1f449e1144542efa17dde84a9f52ade1739/category-checklist-tree.php
$( function() {
$( '[id$="-all"] > ul.categorychecklist' ).each( function() {
var $list = $( this );
@ -422,7 +423,8 @@ jQuery( function( $ ) {
window.alert( response.error );
} else if ( response.slug ) {
// Success.
$wrapper.find( 'select.attribute_values' ).append( '<option value="' + response.term_id + '" selected="selected">' + response.name + '</option>' );
$wrapper.find( 'select.attribute_values' )
.append( '<option value="' + response.term_id + '" selected="selected">' + response.name + '</option>' );
$wrapper.find( 'select.attribute_values' ).change();
}
@ -464,11 +466,15 @@ jQuery( function( $ ) {
$( '.product_attributes' ).html( response.data.html );
$( '.product_attributes' ).unblock();
// Hide the 'Used for variations' checkbox if not viewing a variable product
show_and_hide_panels();
// Make sure the dropdown is not disabled for empty value attributes.
var nr_elements = original_data.length / 6;
for ( var i = 0; i < nr_elements; i++ ) {
if ( typeof( original_data ) !== 'undefined' && original_data[ i * 6 + 2 ].value === '' ) {
$( 'select.attribute_taxonomy' ).find( 'option[value="' + original_data[ i * 6 ].value + '"]' ).removeAttr( 'disabled' );
$( 'select.attribute_taxonomy' )
.find( 'option[value="' + original_data[ i * 6 ].value + '"]' ).removeAttr( 'disabled' );
}
}
@ -607,7 +613,11 @@ jQuery( function( $ ) {
attachment_ids = attachment_ids ? attachment_ids + ',' + attachment.id : attachment.id;
var attachment_image = attachment.sizes && attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.url;
$product_images.append( '<li class="image" data-attachment_id="' + attachment.id + '"><img src="' + attachment_image + '" /><ul class="actions"><li><a href="#" class="delete" title="' + $el.data('delete') + '">' + $el.data('text') + '</a></li></ul></li>' );
$product_images.append(
'<li class="image" data-attachment_id="' + attachment.id + '"><img src="' + attachment_image +
'" /><ul class="actions"><li><a href="#" class="delete" title="' + $el.data('delete') + '">' +
$el.data('text') + '</a></li></ul></li>'
);
}
});

View File

@ -95,6 +95,7 @@ jQuery( function( $ ) {
description.find( '.shipping-method-description' ).addClass( 'hide' );
description.find( '.' + selectedMethod ).removeClass( 'hide' );
var $checkbox = zone.parent().find( 'input[type="checkbox"]' );
var settings = zone.find( '.shipping-method-settings' );
settings
.find( '.shipping-method-setting' )
@ -105,7 +106,7 @@ jQuery( function( $ ) {
.find( '.' + selectedMethod )
.removeClass( 'hide' )
.find( '.shipping-method-required-field' )
.prop( 'required', true );
.prop( 'required', $checkbox.prop( 'checked' ) );
} ).find( '.wc-wizard-shipping-method-select .method' ).change();
$( '.wc-wizard-services' ).on( 'change', '.wc-wizard-shipping-method-enable', function() {

View File

@ -111,8 +111,8 @@
VariationForm.prototype.onResetDisplayedVariation = function( event ) {
var form = event.data.variationForm;
form.$product.find( '.product_meta' ).find( '.sku' ).wc_reset_content();
form.$product.find( '.product_weight' ).wc_reset_content();
form.$product.find( '.product_dimensions' ).wc_reset_content();
form.$product.find( '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' ).wc_reset_content();
form.$product.find( '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' ).wc_reset_content();
form.$form.trigger( 'reset_image' );
form.$singleVariation.slideUp( 200 ).trigger( 'hide_variation' );
};
@ -194,8 +194,8 @@
VariationForm.prototype.onFoundVariation = function( event, variation ) {
var form = event.data.variationForm,
$sku = form.$product.find( '.product_meta' ).find( '.sku' ),
$weight = form.$product.find( '.product_weight' ),
$dimensions = form.$product.find( '.product_dimensions' ),
$weight = form.$product.find( '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' ),
$dimensions = form.$product.find( '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' ),
$qty = form.$singleVariationWrap.find( '.quantity' ),
purchasable = true,
variation_id = '',
@ -352,11 +352,19 @@
}
if ( attr_val ) {
// Decode entities and add slashes.
// Decode entities.
attr_val = $( '<div/>' ).html( attr_val ).text();
// Attach.
new_attr_select.find( 'option[value="' + form.addSlashes( attr_val ) + '"]' ).addClass( 'attached ' + variation_active );
// Attach to matching options by value. This is done to compare
// TEXT values rather than any HTML entities.
new_attr_select.find( 'option' ).each( function( index, el ) {
var option_value = $( this ).val();
if ( attr_val === option_value ) {
$( this ).addClass( 'attached ' + variation_active );
return false; // break.
}
});
} else {
// Attach all apart from placeholder.
new_attr_select.find( 'option:gt(0)' ).addClass( 'attached ' + variation_active );
@ -371,8 +379,19 @@
attached_options_count = new_attr_select.find( 'option.attached' ).length;
// Check if current selection is in attached options.
if ( selected_attr_val && ( attached_options_count === 0 || new_attr_select.find( 'option.attached.enabled[value="' + form.addSlashes( selected_attr_val ) + '"]' ).length === 0 ) ) {
if ( selected_attr_val ) {
selected_attr_val_valid = false;
if ( 0 !== attached_options_count ) {
new_attr_select.find( 'option.attached.enabled' ).each( function( index, el ) {
var option_value = $( this ).val();
if ( selected_attr_val === option_value ) {
selected_attr_val_valid = true;
return false; // break.
}
});
}
}
// Detach the placeholder if:

View File

@ -119,15 +119,13 @@ jQuery( function( $ ) {
AddToCartHandler.prototype.updateCartPage = function() {
var page = window.location.toString().replace( 'add-to-cart', 'added-to-cart' );
$( '.shop_table.cart' ).load( page + ' .shop_table.cart:eq(0) > *', function() {
$( '.shop_table.cart' ).stop( true ).css( 'opacity', '1' ).unblock();
$.get( page, function( data ) {
$( '.shop_table.cart:eq(0)' ).replaceWith( $( data ).find( '.shop_table.cart:eq(0)' ) );
$( '.cart_totals:eq(0)' ).replaceWith( $( data ).find( '.cart_totals:eq(0)' ) );
$( '.cart_totals, .shop_table.cart' ).stop( true ).css( 'opacity', '1' ).unblock();
$( document.body ).trigger( 'cart_page_refreshed' );
});
$( '.cart_totals' ).load( page + ' .cart_totals:eq(0) > *', function() {
$( '.cart_totals' ).stop( true ).css( 'opacity', '1' ).unblock();
$( document.body ).trigger( 'cart_totals_refreshed' );
});
} );
};
/**

View File

@ -38,6 +38,7 @@ jQuery( function( $ ) {
var $fragment_refresh = {
url: wc_cart_fragments_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_refreshed_fragments' ),
type: 'POST',
timeout: wc_cart_fragments_params.request_timeout,
success: function( data ) {
if ( data && data.fragments ) {
@ -56,6 +57,9 @@ jQuery( function( $ ) {
$( document.body ).trigger( 'wc_fragments_refreshed' );
}
},
error: function() {
$( document.body ).trigger( 'wc_fragments_ajax_error' );
}
};
@ -161,4 +165,18 @@ jQuery( function( $ ) {
$( document.body ).on( 'adding_to_cart', function() {
$( '.hide_cart_widget_if_empty' ).closest( '.widget_shopping_cart' ).show();
});
// Customiser support.
var hasSelectiveRefresh = (
'undefined' !== typeof wp &&
wp.customize &&
wp.customize.selectiveRefresh &&
wp.customize.widgetsPreview &&
wp.customize.widgetsPreview.WidgetPartial
);
if ( hasSelectiveRefresh ) {
wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function() {
refresh_cart_fragment();
} );
}
});

View File

@ -24,6 +24,8 @@ jQuery( function( $ ) {
if ( $( document.body ).hasClass( 'woocommerce-order-pay' ) ) {
this.$order_review.on( 'click', 'input[name="payment_method"]', this.payment_method_selected );
this.$order_review.on( 'submit', this.submitOrder );
this.$order_review.attr( 'novalidate', 'novalidate' );
}
// Prevent HTML5 validation which can conflict.
@ -77,10 +79,12 @@ jQuery( function( $ ) {
$payment_methods.eq(0).prop( 'checked', true );
}
if ( $payment_methods.length > 1 ) {
// Get name of new selected method.
var checkedPaymentMethod = $payment_methods.filter( ':checked' ).eq(0).prop( 'id' );
if ( $payment_methods.length > 1 ) {
// Hide open descriptions.
$( 'div.payment_box' ).filter( ':visible' ).slideUp( 0 );
$( 'div.payment_box:not(".' + checkedPaymentMethod + '")' ).filter( ':visible' ).slideUp( 0 );
}
// Trigger click event for selected method
@ -411,6 +415,22 @@ jQuery( function( $ ) {
});
},
blockOnSubmit: function( $form ) {
var form_data = $form.data();
if ( 1 !== form_data['blockUI.isBlocked'] ) {
$form.block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
}
},
submitOrder: function() {
wc_checkout_form.blockOnSubmit( $( this ) );
},
submit: function() {
wc_checkout_form.reset_update_checkout_timer();
var $form = $( this );
@ -424,17 +444,7 @@ jQuery( function( $ ) {
$form.addClass( 'processing' );
var form_data = $form.data();
if ( 1 !== form_data['blockUI.isBlocked'] ) {
$form.block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
}
wc_checkout_form.blockOnSubmit( $form );
// ajaxSetup is global, but we use it to ensure JSON is valid once returned.
$.ajaxSetup( {

View File

@ -115,7 +115,7 @@ jQuery( function( $ ) {
this.openPhotoswipe = this.openPhotoswipe.bind( this );
if ( this.flexslider_enabled ) {
this.initFlexslider();
this.initFlexslider( args.flexslider );
$target.on( 'woocommerce_gallery_reset_slide_position', this.onResetSlidePosition );
} else {
this.$target.css( 'opacity', 1 );
@ -134,7 +134,7 @@ jQuery( function( $ ) {
/**
* Initialize flexSlider.
*/
ProductGallery.prototype.initFlexslider = function() {
ProductGallery.prototype.initFlexslider = function( args ) {
var $target = this.$target,
gallery = this;
@ -146,7 +146,7 @@ jQuery( function( $ ) {
after: function( slider ) {
gallery.initZoomForTarget( gallery.$images.eq( slider.currentSlide ) );
}
}, wc_single_product_params.flexslider );
}, args );
$target.flexslider( options );
@ -307,6 +307,12 @@ jQuery( function( $ ) {
* Initialize all galleries on page.
*/
$( '.woocommerce-product-gallery' ).each( function() {
$( this ).wc_product_gallery();
$( this ).trigger( 'wc-product-gallery-before-init', [ this, wc_single_product_params ] );
$( this ).wc_product_gallery( wc_single_product_params );
$( this ).trigger( 'wc-product-gallery-after-init', [ this, wc_single_product_params ] );
} );
} );

File diff suppressed because one or more lines are too long

View File

@ -14,19 +14,22 @@ jQuery( function( $ ) {
}
});
// Set a cookie and hide the store notice when the dismiss button is clicked
$( '.woocommerce-store-notice__dismiss-link' ).click( function() {
Cookies.set( 'store_notice', 'hidden', { path: '/' } );
$( '.woocommerce-store-notice' ).hide();
});
var noticeID = $( '.woocommerce-store-notice' ).data( 'notice-id' ) || '',
cookieName = 'store_notice' + noticeID;
// Check the value of that cookie and show/hide the notice accordingly
if ( 'hidden' === Cookies.get( 'store_notice' ) ) {
if ( 'hidden' === Cookies.get( cookieName ) ) {
$( '.woocommerce-store-notice' ).hide();
} else {
$( '.woocommerce-store-notice' ).show();
}
// Set a cookie and hide the store notice when the dismiss button is clicked
$( '.woocommerce-store-notice__dismiss-link' ).click( function() {
Cookies.set( cookieName, 'hidden', { path: '/' } );
$( '.woocommerce-store-notice' ).hide();
});
// Make form field descriptions toggle on focus.
$( document.body ).on( 'click', function() {
$( '.woocommerce-input-wrapper span.description:visible' ).prop( 'aria-hidden', true ).slideUp( 250 );

View File

@ -12,29 +12,19 @@
"require-dev": {
"apigen/apigen": "4.1.2",
"nette/utils": "2.5.3",
"phpunit/phpunit": "6.5.13",
"woocommerce/woocommerce-git-hooks": "*",
"phpunit/phpunit": "6.5.14",
"woocommerce/woocommerce-sniffs": "0.0.5"
},
"scripts": {
"pre-update-cmd": [
"WooCommerce\\GitHooks\\Hooks::preHooks"
],
"pre-install-cmd": [
"WooCommerce\\GitHooks\\Hooks::preHooks"
],
"post-install-cmd": [
"WooCommerce\\GitHooks\\Hooks::postHooks"
],
"post-update-cmd": [
"WooCommerce\\GitHooks\\Hooks::postHooks"
],
"test": [
"phpunit"
],
"phpcs": [
"phpcs -s -p"
],
"phpcs-pre-commit": [
"phpcs -s -p -n"
],
"phpcbf": [
"phpcbf -p"
]

747
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8830,7 +8830,7 @@ msgstr ""
#: includes/admin/class-wc-admin-setup-wizard.php:1872
msgid ""
"Select from the list below to enable automated taxes and MailChimps "
"Select from the list below to enable automated taxes and Mailchimps "
"best-in-class email services — and design your store with our official, "
"free WooCommerce theme."
msgstr ""
@ -8870,22 +8870,22 @@ msgid "automated taxes icon"
msgstr ""
#: includes/admin/class-wc-admin-setup-wizard.php:1909
msgid "MailChimp"
msgid "Mailchimp"
msgstr ""
#: includes/admin/class-wc-admin-setup-wizard.php:1910
msgid ""
"Join the 16 million customers who use MailChimp. Sync list and store data "
"Join the 16 million customers who use Mailchimp. Sync list and store data "
"to send automated emails, and targeted campaigns."
msgstr ""
#: includes/admin/class-wc-admin-setup-wizard.php:1912
msgid "MailChimp icon"
msgid "Mailchimp icon"
msgstr ""
#: includes/admin/class-wc-admin-setup-wizard.php:1913
#: includes/admin/class-wc-admin-setup-wizard.php:1955
msgid "MailChimp for WooCommerce"
msgid "Mailchimp for WooCommerce"
msgstr ""
#: includes/admin/class-wc-admin-setup-wizard.php:2006
@ -27268,4 +27268,4 @@ msgstr[1] ""
#: templates/product-searchform.php:27
msgctxt "submit button"
msgid "Search"
msgstr ""
msgstr ""

View File

@ -243,6 +243,26 @@ return array(
),
),
),
'DK' => array(
'currency_code' => 'DKK',
'currency_pos' => 'left_space',
'thousand_sep' => '.',
'decimal_sep' => ',',
'num_decimals' => 2,
'weight_unit' => 'kg',
'dimension_unit' => 'cm',
'tax_rates' => array(
'' => array(
array(
'country' => '*',
'state' => '',
'rate' => '25.0000',
'name' => 'Moms',
'shipping' => true,
),
),
),
),
'ES' => array(
'currency_code' => 'EUR',
'currency_pos' => 'right',

1348
i18n/states.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -220,7 +220,7 @@ abstract class WC_Data {
* @return string Data in JSON format.
*/
public function __toString() {
return json_encode( $this->get_data() );
return wp_json_encode( $this->get_data() );
}
/**
@ -283,7 +283,7 @@ abstract class WC_Data {
* @return bool true if it's an internal key, false otherwise
*/
protected function is_internal_meta_key( $key ) {
$internal_meta_key = ! empty( $key ) && $this->data_store && in_array( $key, $this->data_store->get_internal_meta_keys() );
$internal_meta_key = ! empty( $key ) && $this->data_store && in_array( $key, $this->data_store->get_internal_meta_keys(), true );
if ( ! $internal_meta_key ) {
return false;
@ -320,7 +320,7 @@ abstract class WC_Data {
$this->maybe_read_meta_data();
$meta_data = $this->get_meta_data();
$array_keys = array_keys( wp_list_pluck( $meta_data, 'key' ), $key );
$array_keys = array_keys( wp_list_pluck( $meta_data, 'key' ), $key, true );
$value = $single ? '' : array();
if ( ! empty( $array_keys ) ) {
@ -349,7 +349,7 @@ abstract class WC_Data {
public function meta_exists( $key = '' ) {
$this->maybe_read_meta_data();
$array_keys = wp_list_pluck( $this->get_meta_data(), 'key' );
return in_array( $key, $array_keys );
return in_array( $key, $array_keys, true );
}
/**
@ -364,11 +364,13 @@ abstract class WC_Data {
foreach ( $data as $meta ) {
$meta = (array) $meta;
if ( isset( $meta['key'], $meta['value'], $meta['id'] ) ) {
$this->meta_data[] = new WC_Meta_Data( array(
'id' => $meta['id'],
'key' => $meta['key'],
'value' => $meta['value'],
) );
$this->meta_data[] = new WC_Meta_Data(
array(
'id' => $meta['id'],
'key' => $meta['key'],
'value' => $meta['value'],
)
);
}
}
}
@ -379,9 +381,9 @@ abstract class WC_Data {
*
* @since 2.6.0
*
* @param string $key Meta key.
* @param string|array $value Meta value.
* @param bool $unique Should this be a unique key?.
* @param string $key Meta key.
* @param string|array $value Meta value.
* @param bool $unique Should this be a unique key?.
*/
public function add_meta_data( $key, $value, $unique = false ) {
if ( $this->is_internal_meta_key( $key ) ) {
@ -396,10 +398,12 @@ abstract class WC_Data {
if ( $unique ) {
$this->delete_meta_data( $key );
}
$this->meta_data[] = new WC_Meta_Data( array(
'key' => $key,
'value' => $value,
) );
$this->meta_data[] = new WC_Meta_Data(
array(
'key' => $key,
'value' => $value,
)
);
}
/**
@ -462,7 +466,7 @@ abstract class WC_Data {
*/
public function delete_meta_data( $key ) {
$this->maybe_read_meta_data();
$array_keys = array_keys( wp_list_pluck( $this->meta_data, 'key' ), $key );
$array_keys = array_keys( wp_list_pluck( $this->meta_data, 'key' ), $key, true );
if ( $array_keys ) {
foreach ( $array_keys as $array_key ) {
@ -479,7 +483,7 @@ abstract class WC_Data {
*/
public function delete_meta_data_by_mid( $mid ) {
$this->maybe_read_meta_data();
$array_keys = array_keys( wp_list_pluck( $this->meta_data, 'id' ), $mid );
$array_keys = array_keys( wp_list_pluck( $this->meta_data, 'id' ), (int) $mid, true );
if ( $array_keys ) {
foreach ( $array_keys as $array_key ) {
@ -507,8 +511,8 @@ abstract class WC_Data {
* @param bool $force_read True to force a new DB read (and update cache).
*/
public function read_meta_data( $force_read = false ) {
$this->meta_data = array();
$cache_loaded = false;
$this->meta_data = array();
$cache_loaded = false;
if ( ! $this->get_id() ) {
return;
@ -533,11 +537,13 @@ abstract class WC_Data {
$raw_meta_data = $cache_loaded ? $cached_meta : $this->data_store->read_meta( $this );
if ( $raw_meta_data ) {
foreach ( $raw_meta_data as $meta ) {
$this->meta_data[] = new WC_Meta_Data( array(
'id' => (int) $meta->meta_id,
'key' => $meta->meta_key,
'value' => maybe_unserialize( $meta->meta_value ),
) );
$this->meta_data[] = new WC_Meta_Data(
array(
'id' => (int) $meta->meta_id,
'key' => $meta->meta_key,
'value' => maybe_unserialize( $meta->meta_value ),
)
);
}
if ( ! $cache_loaded && ! empty( $this->cache_group ) ) {
@ -593,8 +599,8 @@ abstract class WC_Data {
* @since 3.0.0
*/
public function set_defaults() {
$this->data = $this->default_data;
$this->changes = array();
$this->data = $this->default_data;
$this->changes = array();
$this->set_object_read( false );
}
@ -630,27 +636,30 @@ abstract class WC_Data {
* @return bool|WP_Error
*/
public function set_props( $props, $context = 'set' ) {
$errors = new WP_Error();
$errors = false;
foreach ( $props as $prop => $value ) {
try {
if ( 'meta_data' === $prop ) {
/**
* Checks if the prop being set is allowed, and the value is not null.
*/
if ( is_null( $value ) || in_array( $prop, array( 'prop', 'date_prop', 'meta_data' ), true ) ) {
continue;
}
$setter = "set_$prop";
if ( ! is_null( $value ) && is_callable( array( $this, $setter ) ) ) {
$reflection = new ReflectionMethod( $this, $setter );
if ( $reflection->isPublic() ) {
$this->{$setter}( $value );
}
if ( is_callable( array( $this, $setter ) ) ) {
$this->{$setter}( $value );
}
} catch ( WC_Data_Exception $e ) {
if ( ! $errors ) {
$errors = new WP_Error();
}
$errors->add( $e->getErrorCode(), $e->getMessage() );
}
}
return count( $errors->get_error_codes() ) ? $errors : true;
return $errors && count( $errors->get_error_codes() ) ? $errors : true;
}
/**
@ -757,7 +766,7 @@ abstract class WC_Data {
} else {
$timestamp = wc_string_to_timestamp( get_gmt_from_date( gmdate( 'Y-m-d H:i:s', wc_string_to_timestamp( $value ) ) ) );
}
$datetime = new WC_DateTime( "@{$timestamp}", new DateTimeZone( 'UTC' ) );
$datetime = new WC_DateTime( "@{$timestamp}", new DateTimeZone( 'UTC' ) );
}
// Set local timezone or offset.

View File

@ -403,7 +403,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$subtotal += $item->get_subtotal();
}
return apply_filters( 'woocommerce_order_get_subtotal', (double) $subtotal, $this );
return apply_filters( 'woocommerce_order_get_subtotal', (float) $subtotal, $this );
}
/**
@ -692,13 +692,16 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* @return string
*/
protected function type_to_group( $type ) {
$type_to_group = apply_filters( 'woocommerce_order_type_to_group', array(
'line_item' => 'line_items',
'tax' => 'tax_lines',
'shipping' => 'shipping_lines',
'fee' => 'fee_lines',
'coupon' => 'coupon_lines',
) );
$type_to_group = apply_filters(
'woocommerce_order_type_to_group',
array(
'line_item' => 'line_items',
'tax' => 'tax_lines',
'shipping' => 'shipping_lines',
'fee' => 'fee_lines',
'coupon' => 'coupon_lines',
)
);
return isset( $type_to_group[ $type ] ) ? $type_to_group[ $type ] : '';
}
@ -952,10 +955,10 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
}
$this->set_coupon_discount_amounts( $discounts );
$this->set_item_discount_amounts( $discounts );
$this->save();
// Recalculate totals and taxes.
$this->calculate_totals( true );
$this->recalculate_coupons();
// Record usage so counts and validation is correct.
$used_by = $this->get_user_id();
@ -1076,9 +1079,14 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
// If the prices include tax, discounts should be taken off the tax inclusive prices like in the cart.
if ( $this->get_prices_include_tax() && wc_tax_enabled() ) {
$amount_tax = WC_Tax::get_tax_total( WC_Tax::calc_tax( $amount, WC_Tax::get_rates( $item->get_tax_class() ), true ) );
$amount -= $amount_tax;
$item->set_total( max( 0, $item->get_total() - $amount ) );
$taxes = WC_Tax::calc_tax( $amount, WC_Tax::get_rates( $item->get_tax_class() ), true );
if ( 'yes' !== get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
$taxes = array_map( 'wc_round_tax_total', $taxes );
}
$amount = $amount - array_sum( $taxes );
$item->set_total( max( 0, round( $item->get_total() - $amount, wc_get_price_decimals() ) ) );
} else {
$item->set_total( max( 0, $item->get_total() - $amount ) );
}
@ -1116,11 +1124,22 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$item = $this->get_item( $item_id, false );
if ( $this->get_prices_include_tax() && wc_tax_enabled() ) {
$amount_tax = array_sum( WC_Tax::calc_tax( $item_discount_amount, WC_Tax::get_rates( $item->get_tax_class() ), true ) );
$discount_tax += $amount_tax;
$amount = $amount - $amount_tax;
$taxes = WC_Tax::calc_tax( $item_discount_amount, WC_Tax::get_rates( $item->get_tax_class() ), true );
if ( 'yes' !== get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
$taxes = array_map( 'wc_round_tax_total', $taxes );
}
$discount_tax += array_sum( $taxes );
$amount = $amount - array_sum( $taxes );
} else {
$discount_tax += array_sum( WC_Tax::calc_tax( $item_discount_amount, WC_Tax::get_rates( $item->get_tax_class() ) ) );
$taxes = WC_Tax::calc_tax( $item_discount_amount, WC_Tax::get_rates( $item->get_tax_class() ) );
if ( 'yes' !== get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
$taxes = array_map( 'wc_round_tax_total', $taxes );
}
$discount_tax += array_sum( $taxes );
}
}
@ -1285,12 +1304,15 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$tax_based_on = 'billing';
}
$args = wp_parse_args( $args, array(
'country' => 'billing' === $tax_based_on ? $this->get_billing_country() : $this->get_shipping_country(),
'state' => 'billing' === $tax_based_on ? $this->get_billing_state() : $this->get_shipping_state(),
'postcode' => 'billing' === $tax_based_on ? $this->get_billing_postcode() : $this->get_shipping_postcode(),
'city' => 'billing' === $tax_based_on ? $this->get_billing_city() : $this->get_shipping_city(),
) );
$args = wp_parse_args(
$args,
array(
'country' => 'billing' === $tax_based_on ? $this->get_billing_country() : $this->get_shipping_country(),
'state' => 'billing' === $tax_based_on ? $this->get_billing_state() : $this->get_shipping_state(),
'postcode' => 'billing' === $tax_based_on ? $this->get_billing_postcode() : $this->get_shipping_postcode(),
'city' => 'billing' === $tax_based_on ? $this->get_billing_city() : $this->get_shipping_city(),
)
);
// Default to base.
if ( 'base' === $tax_based_on || empty( $args['country'] ) ) {
@ -1405,14 +1427,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$this->add_item( $item );
}
if ( 'yes' !== get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
$this->set_shipping_tax( wc_round_tax_total( array_sum( array_map( 'wc_round_tax_total', $shipping_taxes ) ) ) );
$this->set_cart_tax( wc_round_tax_total( array_sum( array_map( 'wc_round_tax_total', $cart_taxes ) ) ) );
} else {
$this->set_shipping_tax( wc_round_tax_total( array_sum( $shipping_taxes ) ) );
$this->set_cart_tax( wc_round_tax_total( array_sum( $cart_taxes ) ) );
}
$this->set_shipping_tax( wc_round_tax_total( array_sum( $shipping_taxes ) ) );
$this->set_cart_tax( wc_round_tax_total( array_sum( $cart_taxes ) ) );
$this->save();
}
@ -1467,14 +1483,21 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$this->calculate_taxes();
}
// Sum taxes.
// Sum taxes again so we can work out how much tax was discounted. This uses original values, not those possibly rounded to 2dp.
foreach ( $this->get_items() as $item ) {
$cart_subtotal_tax += $item->get_subtotal_tax();
$cart_total_tax += $item->get_total_tax();
$taxes = $item->get_taxes();
foreach ( $taxes['total'] as $tax_rate_id => $tax ) {
$cart_total_tax += (float) $tax;
}
foreach ( $taxes['subtotal'] as $tax_rate_id => $tax ) {
$cart_subtotal_tax += (float) $tax;
}
}
$this->set_discount_total( $cart_subtotal - $cart_total );
$this->set_discount_tax( $cart_subtotal_tax - $cart_total_tax );
$this->set_discount_tax( wc_round_tax_total( $cart_subtotal_tax - $cart_total_tax ) );
$this->set_total( round( $cart_total + $fee_total + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() ) );
do_action( 'woocommerce_order_after_calculate_totals', $and_taxes, $this );
@ -1619,10 +1642,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( 'excl' === $tax_display ) {
$ex_tax_label = $this->get_prices_include_tax() ? 1 : 0;
$subtotal = wc_price( $this->get_line_subtotal( $item ), array(
'ex_tax_label' => $ex_tax_label,
'currency' => $this->get_currency(),
) );
$subtotal = wc_price(
$this->get_line_subtotal( $item ),
array(
'ex_tax_label' => $ex_tax_label,
'currency' => $this->get_currency(),
)
);
} else {
$subtotal = wc_price( $this->get_line_subtotal( $item, true ), array( 'currency' => $this->get_currency() ) );
}

View File

@ -516,7 +516,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
* @since 2.6.0
*/
public function save_payment_method_checkbox() {
printf(
$html = sprintf(
'<p class="form-row woocommerce-SavedPaymentMethods-saveNew">
<input id="wc-%1$s-new-payment-method" name="wc-%1$s-new-payment-method" type="checkbox" value="true" style="width:auto;" />
<label for="wc-%1$s-new-payment-method" style="display:inline;">%2$s</label>
@ -524,6 +524,8 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
esc_attr( $this->id ),
esc_html__( 'Save to account', 'woocommerce' )
);
echo apply_filters( 'woocommerce_payment_gateway_save_new_payment_method_option_html', $html, $this );
}
/**

View File

@ -88,6 +88,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
'attributes' => array(),
'default_attributes' => array(),
'menu_order' => 0,
'post_password' => '',
'virtual' => false,
'downloadable' => false,
'category_ids' => array(),
@ -549,6 +550,17 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return $this->get_prop( 'menu_order', $context );
}
/**
* Get post password.
*
* @since 3.6.0
* @param string $context What the value is for. Valid values are view and edit.
* @return int
*/
public function get_post_password( $context = 'view' ) {
return $this->get_prop( 'post_password', $context );
}
/**
* Get category ids.
*
@ -1124,6 +1136,16 @@ class WC_Product extends WC_Abstract_Legacy_Product {
$this->set_prop( 'menu_order', intval( $menu_order ) );
}
/**
* Set post password.
*
* @since 3.6.0
* @param int $post_password Post password.
*/
public function set_post_password( $post_password ) {
$this->set_prop( 'post_password', $post_password );
}
/**
* Set the product categories.
*
@ -1257,10 +1279,6 @@ class WC_Product extends WC_Abstract_Legacy_Product {
public function set_gallery_image_ids( $image_ids ) {
$image_ids = wp_parse_id_list( $image_ids );
if ( $this->get_object_read() ) {
$image_ids = array_filter( $image_ids, 'wp_attachment_is_image' );
}
$this->set_prop( 'gallery_image_ids', $image_ids );
}

View File

@ -122,6 +122,24 @@ abstract class WC_Widget extends WP_Widget {
}
}
/**
* Get this widgets title.
*
* @param array $instance Array of instance options.
* @return string
*/
protected function get_instance_title( $instance ) {
if ( isset( $instance['title'] ) ) {
return $instance['title'];
}
if ( isset( $this->settings, $this->settings['title'], $this->settings['title']['std'] ) ) {
return $this->settings['title']['std'];
}
return '';
}
/**
* Output the html at the start of a widget.
*
@ -131,7 +149,9 @@ abstract class WC_Widget extends WP_Widget {
public function widget_start( $args, $instance ) {
echo $args['before_widget']; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
if ( $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base ) ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found, WordPress.CodeAnalysis.AssignmentInCondition.Found
$title = apply_filters( 'widget_title', $this->get_instance_title( $instance ), $instance, $this->id_base );
if ( $title ) {
echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
}
}
@ -225,7 +245,7 @@ abstract class WC_Widget extends WP_Widget {
case 'text':
?>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; ?></label><?php // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
<label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo wp_kses_post( $setting['label'] ); ?></label><?php // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
<input class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="text" value="<?php echo esc_attr( $value ); ?>" />
</p>
<?php
@ -327,6 +347,11 @@ abstract class WC_Widget extends WP_Widget {
// Post Type Arg.
if ( isset( $_GET['post_type'] ) ) {
$link = add_query_arg( 'post_type', wc_clean( wp_unslash( $_GET['post_type'] ) ), $link );
// Prevent post type and page id when pretty permalinks are disabled.
if ( is_shop() ) {
$link = remove_query_arg( 'page_id', $link );
}
}
// Min Rating Arg.
@ -337,7 +362,7 @@ abstract class WC_Widget extends WP_Widget {
// All current filters.
if ( $_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes() ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found, WordPress.CodeAnalysis.AssignmentInCondition.Found
foreach ( $_chosen_attributes as $name => $data ) {
$filter_name = sanitize_title( str_replace( 'pa_', '', $name ) );
$filter_name = wc_attribute_taxonomy_slug( $name );
if ( ! empty( $data['terms'] ) ) {
$link = add_query_arg( 'filter_' . $filter_name, implode( ',', $data['terms'] ), $link );
}

View File

@ -336,7 +336,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
'i18n_permission_revoke' => __( 'Are you sure you want to revoke access to this download?', 'woocommerce' ),
'i18n_tax_rate_already_exists' => __( 'You cannot add the same tax rate twice!', 'woocommerce' ),
'i18n_delete_note' => __( 'Are you sure you wish to delete this note? This action cannot be undone.', 'woocommerce' ),
'i18n_apply_coupon' => __( 'Enter a coupon code to apply to this order.', 'woocommerce' ),
'i18n_apply_coupon' => __( 'Enter a coupon code to apply. Discounts are applied to line totals, before taxes.', 'woocommerce' ),
'i18n_add_fee' => __( 'Enter a fixed amount or percentage to apply as a fee.', 'woocommerce' ),
);

View File

@ -2,14 +2,12 @@
/**
* Admin Dashboard
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
* @version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
@ -23,7 +21,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
* Hook in tabs.
*/
public function __construct() {
// Only hook in admin parts if the user has admin access
// Only hook in admin parts if the user has admin access.
if ( current_user_can( 'view_woocommerce_reports' ) || current_user_can( 'manage_woocommerce' ) || current_user_can( 'publish_shop_orders' ) ) {
// If on network admin, only load the widget that works in that context and skip the rest.
if ( is_multisite() && is_network_admin() ) {
@ -44,7 +42,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
wp_add_dashboard_widget( 'woocommerce_dashboard_status', __( 'WooCommerce Status', 'woocommerce' ), array( $this, 'status_widget' ) );
// Network Order Widget.
if ( is_multisite() ) {
if ( is_multisite() && is_main_site() ) {
$this->register_network_order_widget();
}
}
@ -110,39 +108,43 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
echo '<ul class="wc_status_list">';
if ( current_user_can( 'view_woocommerce_reports' ) && ( $report_data = $this->get_sales_report_data() ) ) {
?>
if ( current_user_can( 'view_woocommerce_reports' ) ) {
$report_data = $this->get_sales_report_data();
if ( $report_data ) {
?>
<li class="sales-this-month">
<a href="<?php echo admin_url( 'admin.php?page=wc-reports&tab=orders&range=month' ); ?>">
<?php echo $reports->sales_sparkline( '', max( 7, date( 'd', current_time( 'timestamp' ) ) ) ); ?>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=orders&range=month' ) ); ?>">
<?php echo $reports->sales_sparkline( '', max( 7, date( 'd', current_time( 'timestamp' ) ) ) ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
<?php
/* translators: %s: net sales */
printf(
__( '%s net sales this month', 'woocommerce' ),
/* translators: %s: net sales */
esc_html__( '%s net sales this month', 'woocommerce' ),
'<strong>' . wc_price( $report_data->net_sales ) . '</strong>'
);
?>
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
?>
</a>
</li>
<?php
}
if ( current_user_can( 'view_woocommerce_reports' ) && ( $top_seller = $this->get_top_seller() ) && $top_seller->qty ) {
?>
<li class="best-seller-this-month">
<a href="<?php echo admin_url( 'admin.php?page=wc-reports&tab=orders&report=sales_by_product&range=month&product_ids=' . $top_seller->product_id ); ?>">
<?php echo $reports->sales_sparkline( $top_seller->product_id, max( 7, date( 'd', current_time( 'timestamp' ) ) ), 'count' ); ?>
<?php
/* translators: 1: top seller product title 2: top seller quantity */
}
$top_seller = $this->get_top_seller();
if ( $top_seller && $top_seller->qty ) {
?>
<li class="best-seller-this-month">
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=orders&report=sales_by_product&range=month&product_ids=' . $top_seller->product_id ) ); ?>">
<?php echo $reports->sales_sparkline( $top_seller->product_id, max( 7, date( 'd', current_time( 'timestamp' ) ) ), 'count' ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
<?php
printf(
__( '%1$s top seller this month (sold %2$d)', 'woocommerce' ),
/* translators: 1: top seller product title 2: top seller quantity */
esc_html__( '%1$s top seller this month (sold %2$d)', 'woocommerce' ),
'<strong>' . get_the_title( $top_seller->product_id ) . '</strong>',
$top_seller->qty
);
?>
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
?>
</a>
</li>
<?php
<?php
}
}
$this->status_widget_order_rows();
@ -169,24 +171,24 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
}
?>
<li class="processing-orders">
<a href="<?php echo admin_url( 'edit.php?post_status=wc-processing&post_type=shop_order' ); ?>">
<a href="<?php echo esc_url( admin_url( 'edit.php?post_status=wc-processing&post_type=shop_order' ) ); ?>">
<?php
/* translators: %s: order count */
printf(
/* translators: %s: order count */
_n( '<strong>%s order</strong> awaiting processing', '<strong>%s orders</strong> awaiting processing', $processing_count, 'woocommerce' ),
$processing_count
);
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
?>
</a>
</li>
<li class="on-hold-orders">
<a href="<?php echo admin_url( 'edit.php?post_status=wc-on-hold&post_type=shop_order' ); ?>">
<a href="<?php echo esc_url( admin_url( 'edit.php?post_status=wc-on-hold&post_type=shop_order' ) ); ?>">
<?php
/* translators: %s: order count */
printf(
/* translators: %s: order count */
_n( '<strong>%s order</strong> on-hold', '<strong>%s orders</strong> on-hold', $on_hold_count, 'woocommerce' ),
$on_hold_count
);
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
?>
</a>
</li>
@ -199,12 +201,13 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
private function status_widget_stock_rows() {
global $wpdb;
// Get products using a query - this is too advanced for get_posts :(
// Get products using a query - this is too advanced for get_posts.
$stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) );
$nostock = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) );
$transient_name = 'wc_low_stock_count';
if ( false === ( $lowinstock_count = get_transient( $transient_name ) ) ) {
$lowinstock_count = get_transient( $transient_name );
if ( false === $lowinstock_count ) {
$query_from = apply_filters(
'woocommerce_report_low_in_stock_query_from',
"FROM {$wpdb->posts} as posts
@ -223,7 +226,8 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
$transient_name = 'wc_outofstock_count';
if ( false === ( $outofstock_count = get_transient( $transient_name ) ) ) {
$outofstock_count = get_transient( $transient_name );
if ( false === $outofstock_count ) {
$query_from = apply_filters(
'woocommerce_report_out_of_stock_query_from',
"FROM {$wpdb->posts} as posts
@ -240,24 +244,24 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
}
?>
<li class="low-in-stock">
<a href="<?php echo admin_url( 'admin.php?page=wc-reports&tab=stock&report=low_in_stock' ); ?>">
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=stock&report=low_in_stock' ) ); ?>">
<?php
/* translators: %s: order count */
printf(
/* translators: %s: order count */
_n( '<strong>%s product</strong> low in stock', '<strong>%s products</strong> low in stock', $lowinstock_count, 'woocommerce' ),
$lowinstock_count
);
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
?>
</a>
</li>
<li class="out-of-stock">
<a href="<?php echo admin_url( 'admin.php?page=wc-reports&tab=stock&report=out_of_stock' ); ?>">
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=stock&report=out_of_stock' ) ); ?>">
<?php
/* translators: %s: order count */
printf(
/* translators: %s: order count */
_n( '<strong>%s product</strong> out of stock', '<strong>%s products</strong> out of stock', $outofstock_count, 'woocommerce' ),
$outofstock_count
);
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
?>
</a>
</li>
@ -298,16 +302,16 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
$rating = intval( get_comment_meta( $comment->comment_ID, 'rating', true ) );
/* translators: %s: rating */
echo '<div class="star-rating"><span style="width:' . ( $rating * 20 ) . '%">' . sprintf( __( '%s out of 5', 'woocommerce' ), $rating ) . '</span></div>';
echo '<div class="star-rating"><span style="width:' . esc_html( $rating * 20 ) . '%">' . sprintf( esc_html__( '%s out of 5', 'woocommerce' ), esc_html( $rating ) ) . '</span></div>';
/* translators: %s: review author */
echo '<h4 class="meta"><a href="' . get_permalink( $comment->ID ) . '#comment-' . absint( $comment->comment_ID ) . '">' . esc_html( apply_filters( 'woocommerce_admin_dashboard_recent_reviews', $comment->post_title, $comment ) ) . '</a> ' . sprintf( __( 'reviewed by %s', 'woocommerce' ), esc_html( $comment->comment_author ) ) . '</h4>';
echo '<h4 class="meta"><a href="' . esc_url( get_permalink( $comment->ID ) ) . '#comment-' . esc_html( absint( $comment->comment_ID ) ) . '">' . esc_html( apply_filters( 'woocommerce_admin_dashboard_recent_reviews', $comment->post_title, $comment ) ) . '</a> ' . sprintf( esc_html__( 'reviewed by %s', 'woocommerce' ), esc_html( $comment->comment_author ) ) . '</h4>';
echo '<blockquote>' . wp_kses_data( $comment->comment_content ) . '</blockquote></li>';
}
echo '</ul>';
} else {
echo '<p>' . __( 'There are no product reviews yet.', 'woocommerce' ) . '</p>';
echo '<p>' . esc_html__( 'There are no product reviews yet.', 'woocommerce' ) . '</p>';
}
}
@ -326,7 +330,9 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
$blog_ids = wp_list_pluck( $blogs, 'userblog_id' );
wp_localize_script(
'wc-network-orders', 'woocommerce_network_orders', array(
'wc-network-orders',
'woocommerce_network_orders',
array(
'nonce' => wp_create_nonce( 'wp_rest' ),
'sites' => array_values( $blog_ids ),
'order_endpoint' => get_rest_url( null, 'wc/v3/orders/network' ),
@ -357,6 +363,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
<?php esc_html_e( 'No orders found', 'woocommerce' ); ?>
</p>
</div>
<?php // @codingStandardsIgnoreStart ?>
<script type="text/template" id="network-orders-row-template">
<tr>
<td>
@ -374,8 +381,9 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
</td>
</tr>
</script>
<?php // @codingStandardsIgnoreEnd ?>
</div>
<?php
<?php
}
}

View File

@ -82,7 +82,7 @@ class WC_Admin_Importers {
*/
public function admin_scripts() {
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_register_script( 'wc-product-import', WC()->plugin_url() . '/assets/js/admin/wc-product-import' . $suffix . '.js', array( 'jquery' ), WC_VERSION );
wp_register_script( 'wc-product-import', WC()->plugin_url() . '/assets/js/admin/wc-product-import' . $suffix . '.js', array( 'jquery' ), WC_VERSION, true );
}
/**
@ -159,7 +159,7 @@ class WC_Admin_Importers {
foreach ( $post['terms'] as $term ) {
if ( strstr( $term['domain'], 'pa_' ) ) {
if ( ! taxonomy_exists( $term['domain'] ) ) {
$attribute_name = wc_sanitize_taxonomy_name( str_replace( 'pa_', '', $term['domain'] ) );
$attribute_name = wc_attribute_taxonomy_slug( $term['domain'] );
// Create the taxonomy.
if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies(), true ) ) {
@ -179,7 +179,8 @@ class WC_Admin_Importers {
$term['domain'],
apply_filters( 'woocommerce_taxonomy_objects_' . $term['domain'], array( 'product' ) ),
apply_filters(
'woocommerce_taxonomy_args_' . $term['domain'], array(
'woocommerce_taxonomy_args_' . $term['domain'],
array(
'hierarchical' => true,
'show_ui' => false,
'query_var' => true,
@ -248,16 +249,20 @@ class WC_Admin_Importers {
// @codingStandardsIgnoreEnd.
// Clean up orphaned data.
$wpdb->query( "
$wpdb->query(
"
DELETE {$wpdb->posts}.* FROM {$wpdb->posts}
LEFT JOIN {$wpdb->posts} wp ON wp.ID = {$wpdb->posts}.post_parent
WHERE wp.ID IS NULL AND {$wpdb->posts}.post_type = 'product_variation'
" );
$wpdb->query( "
"
);
$wpdb->query(
"
DELETE {$wpdb->postmeta}.* FROM {$wpdb->postmeta}
LEFT JOIN {$wpdb->posts} wp ON wp.ID = {$wpdb->postmeta}.post_id
WHERE wp.ID IS NULL
" );
"
);
// @codingStandardsIgnoreStart.
$wpdb->query( "
DELETE tr.* FROM {$wpdb->term_relationships} tr

View File

@ -98,9 +98,9 @@ class WC_Admin_Menus {
$current_section = empty( $_REQUEST['section'] ) ? '' : sanitize_title( wp_unslash( $_REQUEST['section'] ) ); // WPCS: input var okay, CSRF ok.
// Save settings if data has been posted.
if ( '' !== $current_section && apply_filters( "woocommerce_save_settings_{$current_tab}_{$current_section}", ! empty( $_POST ) ) ) { // WPCS: input var okay, CSRF ok.
if ( '' !== $current_section && apply_filters( "woocommerce_save_settings_{$current_tab}_{$current_section}", ! empty( $_POST['save'] ) ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::save();
} elseif ( '' === $current_section && apply_filters( "woocommerce_save_settings_{$current_tab}", ! empty( $_POST ) ) ) { // WPCS: input var okay, CSRF ok.
} elseif ( '' === $current_section && apply_filters( "woocommerce_save_settings_{$current_tab}", ! empty( $_POST['save'] ) ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::save();
}

View File

@ -31,7 +31,6 @@ class WC_Admin_Notices {
'template_files' => 'template_file_check_notice',
'legacy_shipping' => 'legacy_shipping_notice',
'no_shipping_methods' => 'no_shipping_methods_notice',
'simplify_commerce' => 'simplify_commerce_notice',
'regenerating_thumbnails' => 'regenerating_thumbnails_notice',
'no_secure_connection' => 'secure_connection_notice',
'wootenberg' => 'wootenberg_feature_plugin_notice',
@ -81,17 +80,9 @@ class WC_Admin_Notices {
* Reset notices for themes when switched or a new version of WC is installed.
*/
public static function reset_admin_notices() {
$simplify_options = get_option( 'woocommerce_simplify_commerce_settings', array() );
$location = wc_get_base_location();
if ( ! class_exists( 'WC_Gateway_Simplify_Commerce_Loader' ) && ! empty( $simplify_options['enabled'] ) && 'yes' === $simplify_options['enabled'] && in_array( $location['country'], apply_filters( 'woocommerce_gateway_simplify_commerce_supported_countries', array( 'US', 'IE' ) ), true ) ) {
self::add_notice( 'simplify_commerce' );
}
if ( ! self::is_ssl() ) {
self::add_notice( 'no_secure_connection' );
}
self::add_wootenberg_feature_plugin_notice();
self::add_notice( 'template_files' );
}
@ -329,18 +320,10 @@ class WC_Admin_Notices {
}
/**
* Simplify Commerce is being removed from core.
* Simplify Commerce is no longer in core.
*/
public static function simplify_commerce_notice() {
$location = wc_get_base_location();
if ( class_exists( 'WC_Gateway_Simplify_Commerce_Loader' ) || ! in_array( $location['country'], apply_filters( 'woocommerce_gateway_simplify_commerce_supported_countries', array( 'US', 'IE' ) ), true ) ) {
self::remove_notice( 'simplify_commerce' );
return;
}
if ( empty( $_GET['action'] ) ) { // WPCS: input var ok, CSRF ok.
include dirname( __FILE__ ) . '/views/html-notice-simplify-commerce.php';
}
wc_deprecated_function( 'WC_Admin_Notices::simplify_commerce_notice', '3.6.0' );
}
/**
@ -404,7 +387,7 @@ class WC_Admin_Notices {
* @since 3.5.1
*/
protected static function is_ssl() {
$shop_page = 0 < wc_get_page_id( 'shop' ) ? get_permalink( wc_get_page_id( 'shop' ) ) : get_home_url();
$shop_page = wc_get_page_permalink( 'shop' );
return ( is_ssl() && 'https' === substr( $shop_page, 0, 5 ) );
}

View File

@ -132,7 +132,8 @@ class WC_Admin_Post_Types {
9 => sprintf(
/* translators: 1: date 2: product url */
__( 'Product scheduled for: %1$s. <a target="_blank" href="%2$s">Preview product</a>', 'woocommerce' ),
'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post->ID ) ) . '</strong>'
'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $post->post_date ) ),
esc_url( get_permalink( $post->ID ) ) . '</strong>'
),
/* translators: %s: product url */
10 => sprintf( __( 'Product draft updated. <a target="_blank" href="%s">Preview product</a>', 'woocommerce' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
@ -240,7 +241,8 @@ class WC_Admin_Post_Types {
}
$shipping_class = get_terms(
'product_shipping_class', array(
'product_shipping_class',
array(
'hide_empty' => false,
)
);
@ -260,7 +262,8 @@ class WC_Admin_Post_Types {
}
$shipping_class = get_terms(
'product_shipping_class', array(
'product_shipping_class',
array(
'hide_empty' => false,
)
);
@ -627,7 +630,18 @@ class WC_Admin_Post_Types {
$product->set_backorders( $backorders );
if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
$product->set_stock_quantity( $stock_amount );
$change_stock = absint( $_REQUEST['change_stock'] );
switch ( $change_stock ) {
case 2:
wc_update_product_stock( $product, $stock_amount, 'increase' );
break;
case 3:
wc_update_product_stock( $product, $stock_amount, 'decrease' );
break;
default:
wc_update_product_stock( $product, $stock_amount, 'set' );
break;
}
}
// Apply product type constraints to stock status.

View File

@ -186,8 +186,7 @@ if ( ! class_exists( 'WC_Admin_Profile', false ) ) :
<?php else : ?>
<input type="text" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $this->get_user_meta( $user->ID, $key ) ); ?>" class="<?php echo ( ! empty( $field['class'] ) ? esc_attr( $field['class'] ) : 'regular-text' ); ?>" />
<?php endif; ?>
<br/>
<span class="description"><?php echo wp_kses_post( $field['description'] ); ?></span>
<p class="description"><?php echo wp_kses_post( $field['description'] ); ?></p>
</td>
</tr>
<?php endforeach; ?>

View File

@ -91,6 +91,7 @@ class WC_Admin_Setup_Wizard {
protected function is_default_theme() {
return wc_is_active_theme(
array(
'twentynineteen',
'twentyseventeen',
'twentysixteen',
'twentyfifteen',
@ -1055,6 +1056,10 @@ class WC_Admin_Setup_Wizard {
public function wc_setup_shipping_save() {
check_admin_referer( 'wc-setup' );
if ( ! did_action( 'rest_api_init' ) ) {
WC()->api->rest_api_includes();
}
// @codingStandardsIgnoreStart
$setup_domestic = isset( $_POST['shipping_zones']['domestic']['enabled'] ) && ( 'yes' === $_POST['shipping_zones']['domestic']['enabled'] );
$domestic_method = isset( $_POST['shipping_zones']['domestic']['method'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_zones']['domestic']['method'] ) ) : '';
@ -1909,11 +1914,11 @@ class WC_Admin_Setup_Wizard {
if ( $this->should_show_mailchimp() ) :
$this->display_recommended_item( array(
'type' => 'mailchimp',
'title' => __( 'MailChimp', 'woocommerce' ),
'description' => __( 'Join the 16 million customers who use MailChimp. Sync list and store data to send automated emails, and targeted campaigns.', 'woocommerce' ),
'title' => __( 'Mailchimp', 'woocommerce' ),
'description' => __( 'Join the 16 million customers who use Mailchimp. Sync list and store data to send automated emails, and targeted campaigns.', 'woocommerce' ),
'img_url' => WC()->plugin_url() . '/assets/images/obw-mailchimp-icon.svg',
'img_alt' => __( 'MailChimp icon', 'woocommerce' ),
'plugins' => array( array( 'name' => __( 'MailChimp for WooCommerce', 'woocommerce' ), 'slug' => 'mailchimp-for-woocommerce' ) ),
'img_alt' => __( 'Mailchimp icon', 'woocommerce' ),
'plugins' => array( array( 'name' => __( 'Mailchimp for WooCommerce', 'woocommerce' ), 'slug' => 'mailchimp-for-woocommerce' ) ),
) );
endif;
?>

View File

@ -31,6 +31,15 @@ class WC_Admin_Status {
* Handles output of tools.
*/
public static function status_tools() {
// This screen requires classes from the REST API.
if ( ! did_action( 'rest_api_init' ) ) {
WC()->api->rest_api_includes();
}
if ( ! class_exists( 'WC_REST_System_Status_Tools_Controller', false ) ) {
wp_die( 'Cannot load the REST API to access WC_REST_System_Status_Tools_Controller.' );
}
$tools = self::get_tools();
if ( ! empty( $_GET['action'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'debug_action' ) ) { // WPCS: input var ok, sanitization ok.

View File

@ -5,12 +5,10 @@
* @class WC_Admin_Taxonomies
* @version 2.3.10
* @package WooCommerce/Admin
* @category Class
* @author WooThemes
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
/**
@ -18,6 +16,13 @@ if ( ! defined( 'ABSPATH' ) ) {
*/
class WC_Admin_Taxonomies {
/**
* Class instance.
*
* @var WC_Admin_Taxonomies instance
*/
protected static $instance = false;
/**
* Default category ID.
*
@ -25,6 +30,16 @@ class WC_Admin_Taxonomies {
*/
private $default_cat_id = 0;
/**
* Get class instance
*/
public static function get_instance() {
if ( ! self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
@ -32,17 +47,17 @@ class WC_Admin_Taxonomies {
// Default category ID.
$this->default_cat_id = get_option( 'default_product_cat', 0 );
// Category/term ordering
// Category/term ordering.
add_action( 'create_term', array( $this, 'create_term' ), 5, 3 );
add_action( 'delete_term', array( $this, 'delete_term' ), 5 );
// Add form
// Add form.
add_action( 'product_cat_add_form_fields', array( $this, 'add_category_fields' ) );
add_action( 'product_cat_edit_form_fields', array( $this, 'edit_category_fields' ), 10 );
add_action( 'created_term', array( $this, 'save_category_fields' ), 10, 3 );
add_action( 'edit_term', array( $this, 'save_category_fields' ), 10, 3 );
// Add columns
// Add columns.
add_filter( 'manage_edit-product_cat_columns', array( $this, 'product_cat_columns' ) );
add_filter( 'manage_product_cat_custom_column', array( $this, 'product_cat_column' ), 10, 3 );
@ -50,7 +65,7 @@ class WC_Admin_Taxonomies {
add_filter( 'product_cat_row_actions', array( $this, 'product_cat_row_actions' ), 10, 2 );
add_filter( 'admin_init', array( $this, 'handle_product_cat_row_actions' ) );
// Taxonomy page descriptions
// Taxonomy page descriptions.
add_action( 'product_cat_pre_add_form', array( $this, 'product_cat_description' ) );
add_action( 'after-product_cat-table', array( $this, 'product_cat_notes' ) );
@ -62,19 +77,19 @@ class WC_Admin_Taxonomies {
}
}
// Maintain hierarchy of terms
// Maintain hierarchy of terms.
add_filter( 'wp_terms_checklist_args', array( $this, 'disable_checked_ontop' ) );
// Admin footer scripts for this product categories admin screen
// Admin footer scripts for this product categories admin screen.
add_action( 'admin_footer', array( $this, 'scripts_at_product_cat_screen_footer' ) );
}
/**
* Order term when created (put in position 0).
*
* @param mixed $term_id
* @param mixed $tt_id
* @param string $taxonomy
* @param mixed $term_id Term ID.
* @param mixed $tt_id Term taxonomy ID.
* @param string $taxonomy Taxonomy slug.
*/
public function create_term( $term_id, $tt_id = '', $taxonomy = '' ) {
if ( 'product_cat' != $taxonomy && ! taxonomy_is_product_attribute( $taxonomy ) ) {
@ -89,7 +104,7 @@ class WC_Admin_Taxonomies {
/**
* When a term is deleted, delete its meta.
*
* @param mixed $term_id
* @param mixed $term_id Term ID.
*/
public function delete_term( $term_id ) {
global $wpdb;
@ -107,21 +122,21 @@ class WC_Admin_Taxonomies {
public function add_category_fields() {
?>
<div class="form-field term-display-type-wrap">
<label for="display_type"><?php _e( 'Display type', 'woocommerce' ); ?></label>
<label for="display_type"><?php esc_html_e( 'Display type', 'woocommerce' ); ?></label>
<select id="display_type" name="display_type" class="postform">
<option value=""><?php _e( 'Default', 'woocommerce' ); ?></option>
<option value="products"><?php _e( 'Products', 'woocommerce' ); ?></option>
<option value="subcategories"><?php _e( 'Subcategories', 'woocommerce' ); ?></option>
<option value="both"><?php _e( 'Both', 'woocommerce' ); ?></option>
<option value=""><?php esc_html_e( 'Default', 'woocommerce' ); ?></option>
<option value="products"><?php esc_html_e( 'Products', 'woocommerce' ); ?></option>
<option value="subcategories"><?php esc_html_e( 'Subcategories', 'woocommerce' ); ?></option>
<option value="both"><?php esc_html_e( 'Both', 'woocommerce' ); ?></option>
</select>
</div>
<div class="form-field term-thumbnail-wrap">
<label><?php _e( 'Thumbnail', 'woocommerce' ); ?></label>
<label><?php esc_html_e( 'Thumbnail', 'woocommerce' ); ?></label>
<div id="product_cat_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( wc_placeholder_img_src() ); ?>" width="60px" height="60px" /></div>
<div style="line-height: 60px;">
<input type="hidden" id="product_cat_thumbnail_id" name="product_cat_thumbnail_id" />
<button type="button" class="upload_image_button button"><?php _e( 'Upload/Add image', 'woocommerce' ); ?></button>
<button type="button" class="remove_image_button button"><?php _e( 'Remove image', 'woocommerce' ); ?></button>
<button type="button" class="upload_image_button button"><?php esc_html_e( 'Upload/Add image', 'woocommerce' ); ?></button>
<button type="button" class="remove_image_button button"><?php esc_html_e( 'Remove image', 'woocommerce' ); ?></button>
</div>
<script type="text/javascript">
@ -145,9 +160,9 @@ class WC_Admin_Taxonomies {
// Create the media frame.
file_frame = wp.media.frames.downloadable_file = wp.media({
title: '<?php _e( 'Choose an image', 'woocommerce' ); ?>',
title: '<?php esc_html_e( 'Choose an image', 'woocommerce' ); ?>',
button: {
text: '<?php _e( 'Use image', 'woocommerce' ); ?>'
text: '<?php esc_html_e( 'Use image', 'woocommerce' ); ?>'
},
multiple: false
});
@ -200,7 +215,7 @@ class WC_Admin_Taxonomies {
/**
* Edit category thumbnail field.
*
* @param mixed $term Term (category) being edited
* @param mixed $term Term (category) being edited.
*/
public function edit_category_fields( $term ) {
@ -214,24 +229,24 @@ class WC_Admin_Taxonomies {
}
?>
<tr class="form-field term-display-type-wrap">
<th scope="row" valign="top"><label><?php _e( 'Display type', 'woocommerce' ); ?></label></th>
<th scope="row" valign="top"><label><?php esc_html_e( 'Display type', 'woocommerce' ); ?></label></th>
<td>
<select id="display_type" name="display_type" class="postform">
<option value="" <?php selected( '', $display_type ); ?>><?php _e( 'Default', 'woocommerce' ); ?></option>
<option value="products" <?php selected( 'products', $display_type ); ?>><?php _e( 'Products', 'woocommerce' ); ?></option>
<option value="subcategories" <?php selected( 'subcategories', $display_type ); ?>><?php _e( 'Subcategories', 'woocommerce' ); ?></option>
<option value="both" <?php selected( 'both', $display_type ); ?>><?php _e( 'Both', 'woocommerce' ); ?></option>
<option value="" <?php selected( '', $display_type ); ?>><?php esc_html_e( 'Default', 'woocommerce' ); ?></option>
<option value="products" <?php selected( 'products', $display_type ); ?>><?php esc_html_e( 'Products', 'woocommerce' ); ?></option>
<option value="subcategories" <?php selected( 'subcategories', $display_type ); ?>><?php esc_html_e( 'Subcategories', 'woocommerce' ); ?></option>
<option value="both" <?php selected( 'both', $display_type ); ?>><?php esc_html_e( 'Both', 'woocommerce' ); ?></option>
</select>
</td>
</tr>
<tr class="form-field term-thumbnail-wrap">
<th scope="row" valign="top"><label><?php _e( 'Thumbnail', 'woocommerce' ); ?></label></th>
<th scope="row" valign="top"><label><?php esc_html_e( 'Thumbnail', 'woocommerce' ); ?></label></th>
<td>
<div id="product_cat_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( $image ); ?>" width="60px" height="60px" /></div>
<div style="line-height: 60px;">
<input type="hidden" id="product_cat_thumbnail_id" name="product_cat_thumbnail_id" value="<?php echo $thumbnail_id; ?>" />
<button type="button" class="upload_image_button button"><?php _e( 'Upload/Add image', 'woocommerce' ); ?></button>
<button type="button" class="remove_image_button button"><?php _e( 'Remove image', 'woocommerce' ); ?></button>
<input type="hidden" id="product_cat_thumbnail_id" name="product_cat_thumbnail_id" value="<?php echo esc_attr( $thumbnail_id ); ?>" />
<button type="button" class="upload_image_button button"><?php esc_html_e( 'Upload/Add image', 'woocommerce' ); ?></button>
<button type="button" class="remove_image_button button"><?php esc_html_e( 'Remove image', 'woocommerce' ); ?></button>
</div>
<script type="text/javascript">
@ -255,9 +270,9 @@ class WC_Admin_Taxonomies {
// Create the media frame.
file_frame = wp.media.frames.downloadable_file = wp.media({
title: '<?php _e( 'Choose an image', 'woocommerce' ); ?>',
title: '<?php esc_html_e( 'Choose an image', 'woocommerce' ); ?>',
button: {
text: '<?php _e( 'Use image', 'woocommerce' ); ?>'
text: '<?php esc_html_e( 'Use image', 'woocommerce' ); ?>'
},
multiple: false
});
@ -291,18 +306,18 @@ class WC_Admin_Taxonomies {
}
/**
* save_category_fields function.
* Save category fields
*
* @param mixed $term_id Term ID being saved
* @param mixed $tt_id
* @param string $taxonomy
* @param mixed $term_id Term ID being saved.
* @param mixed $tt_id Term taxonomy ID.
* @param string $taxonomy Taxonomy slug.
*/
public function save_category_fields( $term_id, $tt_id = '', $taxonomy = '' ) {
if ( isset( $_POST['display_type'] ) && 'product_cat' === $taxonomy ) {
update_woocommerce_term_meta( $term_id, 'display_type', esc_attr( $_POST['display_type'] ) );
if ( isset( $_POST['display_type'] ) && 'product_cat' === $taxonomy ) { // WPCS: CSRF ok, input var ok.
update_woocommerce_term_meta( $term_id, 'display_type', esc_attr( $_POST['display_type'] ) ); // WPCS: CSRF ok, sanitization ok, input var ok.
}
if ( isset( $_POST['product_cat_thumbnail_id'] ) && 'product_cat' === $taxonomy ) {
update_woocommerce_term_meta( $term_id, 'thumbnail_id', absint( $_POST['product_cat_thumbnail_id'] ) );
if ( isset( $_POST['product_cat_thumbnail_id'] ) && 'product_cat' === $taxonomy ) { // WPCS: CSRF ok, input var ok.
update_woocommerce_term_meta( $term_id, 'thumbnail_id', absint( $_POST['product_cat_thumbnail_id'] ) ); // WPCS: CSRF ok, input var ok.
}
}
@ -310,7 +325,10 @@ class WC_Admin_Taxonomies {
* Description for product_cat page to aid users.
*/
public function product_cat_description() {
echo wpautop( __( 'Product categories for your store can be managed here. To change the order of categories on the front-end you can drag and drop to sort them. To see more categories listed click the "screen options" link at the top-right of this page.', 'woocommerce' ) );
echo wp_kses(
wpautop( __( 'Product categories for your store can be managed here. To change the order of categories on the front-end you can drag and drop to sort them. To see more categories listed click the "screen options" link at the top-right of this page.', 'woocommerce' ) ),
array( 'p' => array() )
);
}
/**
@ -323,11 +341,11 @@ class WC_Admin_Taxonomies {
?>
<div class="form-wrap edit-term-notes">
<p>
<strong><?php _e( 'Note:', 'woocommerce' ); ?></strong><br>
<strong><?php esc_html_e( 'Note:', 'woocommerce' ); ?></strong><br>
<?php
printf(
/* translators: %s: default category */
__( 'Deleting a category does not delete the products in that category. Instead, products that were only assigned to the deleted category are set to the category %s.', 'woocommerce' ),
esc_html__( 'Deleting a category does not delete the products in that category. Instead, products that were only assigned to the deleted category are set to the category %s.', 'woocommerce' ),
'<strong>' . esc_html( $category_name ) . '</strong>'
);
?>
@ -340,13 +358,16 @@ class WC_Admin_Taxonomies {
* Description for shipping class page to aid users.
*/
public function product_attribute_description() {
echo wpautop( __( 'Attribute terms can be assigned to products and variations.<br/><br/><b>Note</b>: Deleting a term will remove it from all products and variations to which it has been assigned. Recreating a term will not automatically assign it back to products.', 'woocommerce' ) );
echo wp_kses(
wpautop( __( 'Attribute terms can be assigned to products and variations.<br/><br/><b>Note</b>: Deleting a term will remove it from all products and variations to which it has been assigned. Recreating a term will not automatically assign it back to products.', 'woocommerce' ) ),
array( 'p' => array() )
);
}
/**
* Thumbnail column added to category admin.
*
* @param mixed $columns
* @param mixed $columns Columns array.
* @return array
*/
public function product_cat_columns( $columns ) {
@ -392,10 +413,10 @@ class WC_Admin_Taxonomies {
* Handle custom row actions.
*/
public function handle_product_cat_row_actions() {
if ( isset( $_GET['action'], $_GET['tag_ID'], $_GET['_wpnonce'] ) && 'make_default' === $_GET['action'] ) {
$make_default_id = absint( $_GET['tag_ID'] );
if ( isset( $_GET['action'], $_GET['tag_ID'], $_GET['_wpnonce'] ) && 'make_default' === $_GET['action'] ) { // WPCS: CSRF ok, input var ok.
$make_default_id = absint( $_GET['tag_ID'] ); // WPCS: Input var ok.
if ( wp_verify_nonce( $_GET['_wpnonce'], 'make_default_' . $make_default_id ) && current_user_can( 'edit_term', $make_default_id ) ) {
if ( wp_verify_nonce( $_GET['_wpnonce'], 'make_default_' . $make_default_id ) && current_user_can( 'edit_term', $make_default_id ) ) { // WPCS: Sanitization ok, input var ok, CSRF ok.
update_option( 'default_product_cat', $make_default_id );
}
}
@ -404,9 +425,9 @@ class WC_Admin_Taxonomies {
/**
* Thumbnail column value added to category admin.
*
* @param string $columns
* @param string $column
* @param int $id
* @param string $columns Column HTML output.
* @param string $column Column name.
* @param int $id Product ID.
*
* @return string
*/
@ -427,7 +448,7 @@ class WC_Admin_Taxonomies {
$image = wc_placeholder_img_src();
}
// Prevent esc_url from breaking spaces in urls for image embeds. Ref: https://core.trac.wordpress.org/ticket/23605
// Prevent esc_url from breaking spaces in urls for image embeds. Ref: https://core.trac.wordpress.org/ticket/23605 .
$image = str_replace( ' ', '%20', $image );
$columns .= '<img src="' . esc_url( $image ) . '" alt="' . esc_attr__( 'Thumbnail', 'woocommerce' ) . '" class="wp-post-image" height="48" width="48" />';
}
@ -440,7 +461,7 @@ class WC_Admin_Taxonomies {
/**
* Maintain term hierarchy when editing a product.
*
* @param array $args
* @param array $args Term checklist args.
* @return array
*/
public function disable_checked_ontop( $args ) {
@ -456,10 +477,10 @@ class WC_Admin_Taxonomies {
* @return void
*/
public function scripts_at_product_cat_screen_footer() {
if ( ! isset( $_GET['taxonomy'] ) || 'product_cat' !== $_GET['taxonomy'] ) {
if ( ! isset( $_GET['taxonomy'] ) || 'product_cat' !== $_GET['taxonomy'] ) { // WPCS: CSRF ok, input var ok.
return;
}
// Ensure the tooltip is displayed when the image column is disabled on product categories
// Ensure the tooltip is displayed when the image column is disabled on product categories.
wc_enqueue_js("
(function( $ ) {
'use strict';
@ -471,4 +492,4 @@ class WC_Admin_Taxonomies {
}
}
new WC_Admin_Taxonomies();
$wc_admin_taxonomies = WC_Admin_Taxonomies::get_instance();

View File

@ -168,7 +168,7 @@ class WC_Admin {
public function prevent_admin_access() {
$prevent_access = false;
if ( 'yes' === get_option( 'woocommerce_lock_down_admin', 'yes' ) && ! is_ajax() && basename( $_SERVER['SCRIPT_FILENAME'] ) !== 'admin-post.php' ) {
if ( apply_filters( 'woocommerce_disable_admin_bar', true ) && ! is_ajax() && basename( $_SERVER["SCRIPT_FILENAME"] ) !== 'admin-post.php' ) {
$has_cap = false;
$access_caps = array( 'edit_posts', 'manage_woocommerce', 'view_admin_dashboard' );

View File

@ -535,7 +535,7 @@ class WC_Meta_Box_Order_Data {
// Create order key.
if ( ! $order->get_order_key() ) {
$props['order_key'] = 'wc_' . apply_filters( 'woocommerce_generate_order_key', uniqid( 'order_' ) );
$props['order_key'] = wc_generate_order_key();
}
// Update customer.

View File

@ -228,7 +228,7 @@ class WC_Meta_Box_Product_Data {
$attributes = array();
if ( ! $data ) {
$data = $_POST;
$data = stripslashes_deep( $_POST );
}
if ( isset( $data['attribute_names'], $data['attribute_values'] ) ) {
@ -365,7 +365,7 @@ class WC_Meta_Box_Product_Data {
'backorders' => isset( $_POST['_backorders'] ) ? wc_clean( wp_unslash( $_POST['_backorders'] ) ) : null,
'stock_status' => wc_clean( wp_unslash( $_POST['_stock_status'] ) ),
'stock_quantity' => $stock,
'low_stock_amount' => wc_stock_amount( wp_unslash( $_POST['_low_stock_amount'] ) ),
'low_stock_amount' => isset( $_POST['_low_stock_amount'] ) ? wc_stock_amount( wp_unslash( $_POST['_low_stock_amount'] ) ) : null,
'download_limit' => '' === $_POST['_download_limit'] ? '' : absint( wp_unslash( $_POST['_download_limit'] ) ),
'download_expiry' => '' === $_POST['_download_expiry'] ? '' : absint( wp_unslash( $_POST['_download_expiry'] ) ),
'downloads' => self::prepare_downloads(

View File

@ -59,7 +59,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php
}
do_action( 'woocommerce_product_option_terms', $attribute_taxonomy, $i );
do_action( 'woocommerce_product_option_terms', $attribute_taxonomy, $i, $attribute );
} else {
/* translators: %s: WC_DELIMITER */
?>

View File

@ -28,8 +28,8 @@ if ( ! defined( 'ABSPATH' ) ) {
<label for="product_length"><?php printf( __( 'Dimensions (%s)', 'woocommerce' ), get_option( 'woocommerce_dimension_unit' ) ); ?></label>
<span class="wrap">
<input id="product_length" placeholder="<?php esc_attr_e( 'Length', 'woocommerce' ); ?>" class="input-text wc_input_decimal" size="6" type="text" name="_length" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_length( 'edit' ) ) ); ?>" />
<input placeholder="<?php esc_attr_e( 'Width', 'woocommerce' ); ?>" class="input-text wc_input_decimal" size="6" type="text" name="_width" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_width( 'edit' ) ) ); ?>" />
<input placeholder="<?php esc_attr_e( 'Height', 'woocommerce' ); ?>" class="input-text wc_input_decimal last" size="6" type="text" name="_height" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_height( 'edit' ) ) ); ?>" />
<input id="product_width" placeholder="<?php esc_attr_e( 'Width', 'woocommerce' ); ?>" class="input-text wc_input_decimal" size="6" type="text" name="_width" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_width( 'edit' ) ) ); ?>" />
<input id="product_height" placeholder="<?php esc_attr_e( 'Height', 'woocommerce' ); ?>" class="input-text wc_input_decimal last" size="6" type="text" name="_height" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_height( 'edit' ) ) ); ?>" />
</span>
<?php echo wc_help_tip( __( 'LxWxH in decimal form', 'woocommerce' ) ); ?>
</p>

View File

@ -48,6 +48,17 @@ if ( ! defined( 'ABSPATH' ) ) {
?>
<input type="hidden" name="variable_post_id[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( $variation_id ); ?>" />
<input type="hidden" class="variation_menu_order" name="variation_menu_order[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( $variation_object->get_menu_order( 'edit' ) ); ?>" />
<?php
/**
* woocommerce_variation_header action.
*
* @since 3.6.0
*
* @param WP_Post $variation .
*/
do_action( 'woocommerce_variation_header', $variation );
?>
</h3>
<div class="woocommerce_variable_attributes wc-metabox-content" style="display: none;">
<div class="data">

View File

@ -1,7 +1,12 @@
<?php
/**
* Class WC_Report_Customer_List file.
*
* @package WooCommerce\Reports
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'WP_List_Table' ) ) {
@ -11,8 +16,6 @@ if ( ! class_exists( 'WP_List_Table' ) ) {
/**
* WC_Report_Customer_List.
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin/Reports
* @version 2.1.0
*/
@ -36,7 +39,7 @@ class WC_Report_Customer_List extends WP_List_Table {
* No items found text.
*/
public function no_items() {
_e( 'No customers found.', 'woocommerce' );
esc_html_e( 'No customers found.', 'woocommerce' );
}
/**
@ -47,20 +50,20 @@ class WC_Report_Customer_List extends WP_List_Table {
echo '<div id="poststuff" class="woocommerce-reports-wide">';
if ( ! empty( $_GET['link_orders'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'link_orders' ) ) {
if ( ! empty( $_GET['link_orders'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'link_orders' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
$linked = wc_update_new_customer_past_orders( absint( $_GET['link_orders'] ) );
echo '<div class="updated"><p>' . sprintf( _n( '%s previous order linked', '%s previous orders linked', $linked, 'woocommerce' ), $linked ) . '</p></div>';
/* translators: single or plural number of orders */
echo '<div class="updated"><p>' . sprintf( esc_html( _n( '%s previous order linked', '%s previous orders linked', $linked, 'woocommerce' ), $linked ) ) . '</p></div>';
}
if ( ! empty( $_GET['refresh'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'refresh' ) ) {
if ( ! empty( $_GET['refresh'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'refresh' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
$user_id = absint( $_GET['refresh'] );
$user = get_user_by( 'id', $user_id );
delete_user_meta( $user_id, '_money_spent' );
delete_user_meta( $user_id, '_order_count' );
echo '<div class="updated"><p>' . sprintf( __( 'Refreshed stats for %s', 'woocommerce' ), $user->display_name ) . '</p></div>';
/* translators: User display name */
echo '<div class="updated"><p>' . sprintf( esc_html__( 'Refreshed stats for %s', 'woocommerce' ), esc_html( $user->display_name ) ) . '</p></div>';
}
echo '<form method="post" id="woocommerce_customers">';
@ -75,8 +78,8 @@ class WC_Report_Customer_List extends WP_List_Table {
/**
* Get column value.
*
* @param WP_User $user
* @param string $column_name
* @param WP_User $user WP User object.
* @param string $column_name Column name.
* @return string
*/
public function column_default( $user, $column_name ) {
@ -224,14 +227,13 @@ class WC_Report_Customer_List extends WP_List_Table {
/**
* Order users by name.
*
* @param WP_User_Query $query
*
* @param WP_User_Query $query Query that gets passed through.
* @return WP_User_Query
*/
public function order_by_last_name( $query ) {
global $wpdb;
$s = ! empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : '';
$s = ! empty( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$query->query_from .= " LEFT JOIN {$wpdb->usermeta} as meta2 ON ({$wpdb->users}.ID = meta2.user_id) ";
$query->query_where .= " AND meta2.meta_key = 'last_name' ";
@ -278,10 +280,13 @@ class WC_Report_Customer_List extends WP_List_Table {
);
$query = new WP_User_Query(
array(
'exclude' => array_merge( $admin_users->get_results(), $manager_users->get_results() ),
'number' => $per_page,
'offset' => ( $current_page - 1 ) * $per_page,
apply_filters(
'woocommerce_admin_report_customer_list_user_query_args',
array(
'exclude' => array_merge( $admin_users->get_results(), $manager_users->get_results() ),
'number' => $per_page,
'offset' => ( $current_page - 1 ) * $per_page,
)
)
);

View File

@ -203,9 +203,12 @@ class WC_Report_Customers extends WC_Admin_Report {
);
$users_query = new WP_User_Query(
array(
'fields' => array( 'user_registered' ),
'exclude' => array_merge( $admin_users->get_results(), $manager_users->get_results() ),
apply_filters(
'woocommerce_admin_report_customers_user_query_args',
array(
'fields' => array( 'user_registered' ),
'exclude' => array_merge( $admin_users->get_results(), $manager_users->get_results() ),
)
)
);

View File

@ -1,16 +1,17 @@
<?php
/**
* WC_Report_Sales_By_Date
*
* @package WooCommerce/Admin/Reports
* @version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
/**
* WC_Report_Sales_By_Date
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin/Reports
* @version 2.1.0
*/
class WC_Report_Sales_By_Date extends WC_Admin_Report {
@ -106,7 +107,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
)
);
// All items from orders - even those refunded
// All items from orders - even those refunded.
$this->report_data->order_items = (array) $this->get_order_report_data(
array(
'data' => array(
@ -249,6 +250,10 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
)
);
foreach ( $this->report_data->full_refunds as $key => $order ) {
$this->report_data->full_refunds[ $key ]->net_refund = $order->total_refund - ( $order->total_shipping + $order->total_tax + $order->total_shipping_tax );
}
/**
* Partial refunds. This includes line items, shipping and taxes. Not grouped by date.
*/
@ -315,6 +320,10 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
)
);
foreach ( $this->report_data->partial_refunds as $key => $order ) {
$this->report_data->partial_refunds[ $key ]->net_refund = $order->total_refund - ( $order->total_shipping + $order->total_tax + $order->total_shipping_tax );
}
/**
* Refund lines - all partial refunds on all order types so we can plot full AND partial refunds on the chart.
*/
@ -389,9 +398,9 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
$this->report_data->total_shipping_tax_refunded = 0;
$this->report_data->total_refunds = 0;
$refunded_orders = array_merge( $this->report_data->partial_refunds, $this->report_data->full_refunds );
$this->report_data->refunded_orders = array_merge( $this->report_data->partial_refunds, $this->report_data->full_refunds );
foreach ( $refunded_orders as $key => $value ) {
foreach ( $this->report_data->refunded_orders as $key => $value ) {
$this->report_data->total_tax_refunded += floatval( $value->total_tax < 0 ? $value->total_tax * -1 : $value->total_tax );
$this->report_data->total_refunds += floatval( $value->total_refund );
$this->report_data->total_shipping_tax_refunded += floatval( $value->total_shipping_tax < 0 ? $value->total_shipping_tax * -1 : $value->total_shipping_tax );
@ -412,11 +421,11 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
$this->report_data->total_sales = wc_format_decimal( array_sum( wp_list_pluck( $this->report_data->orders, 'total_sales' ) ) - $this->report_data->total_refunds, 2 );
$this->report_data->net_sales = wc_format_decimal( $this->report_data->total_sales - $this->report_data->total_shipping - max( 0, $this->report_data->total_tax ) - max( 0, $this->report_data->total_shipping_tax ), 2 );
// Calculate average based on net
// Calculate average based on net.
$this->report_data->average_sales = wc_format_decimal( $this->report_data->net_sales / ( $this->chart_interval + 1 ), 2 );
$this->report_data->average_total_sales = wc_format_decimal( $this->report_data->total_sales / ( $this->chart_interval + 1 ), 2 );
// Total orders and discounts also includes those which have been refunded at some point
// Total orders and discounts also includes those which have been refunded at some point.
$this->report_data->total_coupons = number_format( array_sum( wp_list_pluck( $this->report_data->coupons, 'discount_amount' ) ), 2, '.', '' );
$this->report_data->total_refunded_orders = absint( count( $this->report_data->full_refunds ) );
@ -441,26 +450,26 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
switch ( $this->chart_groupby ) {
case 'day':
/* translators: %s: average total sales */
$average_total_sales_title = sprintf(
/* translators: %s: average total sales */
__( '%s average gross daily sales', 'woocommerce' ),
'<strong>' . wc_price( $data->average_total_sales ) . '</strong>'
);
/* translators: %s: average sales */
$average_sales_title = sprintf(
/* translators: %s: average sales */
__( '%s average net daily sales', 'woocommerce' ),
'<strong>' . wc_price( $data->average_sales ) . '</strong>'
);
break;
case 'month':
default:
/* translators: %s: average total sales */
$average_total_sales_title = sprintf(
/* translators: %s: average total sales */
__( '%s average gross monthly sales', 'woocommerce' ),
'<strong>' . wc_price( $data->average_total_sales ) . '</strong>'
);
/* translators: %s: average sales */
$average_sales_title = sprintf(
/* translators: %s: average sales */
__( '%s average net monthly sales', 'woocommerce' ),
'<strong>' . wc_price( $data->average_sales ) . '</strong>'
);
@ -468,8 +477,8 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
}
$legend[] = array(
/* translators: %s: total sales */
'title' => sprintf(
/* translators: %s: total sales */
__( '%s gross sales in this period', 'woocommerce' ),
'<strong>' . wc_price( $data->total_sales ) . '</strong>'
),
@ -486,8 +495,8 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
}
$legend[] = array(
/* translators: %s: net sales */
'title' => sprintf(
/* translators: %s: net sales */
__( '%s net sales in this period', 'woocommerce' ),
'<strong>' . wc_price( $data->net_sales ) . '</strong>'
),
@ -504,8 +513,8 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
}
$legend[] = array(
/* translators: %s: total orders */
'title' => sprintf(
/* translators: %s: total orders */
__( '%s orders placed', 'woocommerce' ),
'<strong>' . $data->total_orders . '</strong>'
),
@ -514,8 +523,8 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
);
$legend[] = array(
/* translators: %s: total items */
'title' => sprintf(
/* translators: %s: total items */
__( '%s items purchased', 'woocommerce' ),
'<strong>' . $data->total_items . '</strong>'
),
@ -523,8 +532,8 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
'highlight_series' => 0,
);
$legend[] = array(
/* translators: 1: total refunds 2: total refunded orders 3: refunded items */
'title' => sprintf(
/* translators: 1: total refunds 2: total refunded orders 3: refunded items */
_n( '%1$s refunded %2$d order (%3$d item)', '%1$s refunded %2$d orders (%3$d items)', $this->report_data->total_refunded_orders, 'woocommerce' ),
'<strong>' . wc_price( $data->total_refunds ) . '</strong>',
$this->report_data->total_refunded_orders,
@ -534,8 +543,8 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
'highlight_series' => 8,
);
$legend[] = array(
/* translators: %s: total shipping */
'title' => sprintf(
/* translators: %s: total shipping */
__( '%s charged for shipping', 'woocommerce' ),
'<strong>' . wc_price( $data->total_shipping ) . '</strong>'
),
@ -543,8 +552,8 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
'highlight_series' => 5,
);
$legend[] = array(
/* translators: %s: total coupons */
'title' => sprintf(
/* translators: %s: total coupons */
__( '%s worth of coupons used', 'woocommerce' ),
'<strong>' . wc_price( $data->total_coupons ) . '</strong>'
),
@ -578,9 +587,9 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
'refund_amount' => '#e74c3c',
);
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : '7day';
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.NoNonceVerification
if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) {
if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ), true ) ) {
$current_range = '7day';
}
@ -594,18 +603,18 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
* Output an export link.
*/
public function get_export_button() {
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : '7day';
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.NoNonceVerification
?>
<a
href="#"
download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo date_i18n( 'Y-m-d', current_time( 'timestamp' ) ); ?>.csv"
download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_attr( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv"
class="export_csv"
data-export="chart"
data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>"
data-exclude_series="2"
data-groupby="<?php echo $this->chart_groupby; ?>"
data-groupby="<?php echo esc_attr( $this->chart_groupby ); ?>"
>
<?php _e( 'Export CSV', 'woocommerce' ); ?>
<?php esc_html_e( 'Export CSV', 'woocommerce' ); ?>
</a>
<?php
}
@ -613,7 +622,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
/**
* Round our totals correctly.
*
* @param array|string $amount
* @param array|string $amount Chart total.
*
* @return array|string
*/
@ -631,7 +640,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
public function get_main_chart() {
global $wp_locale;
// Prepare data for report
// Prepare data for report.
$data = array(
'order_counts' => $this->prepare_chart_data( $this->report_data->order_counts, 'post_date', 'count', $this->chart_interval, $this->start_date, $this->chart_groupby ),
'order_item_counts' => $this->prepare_chart_data( $this->report_data->order_items, 'post_date', 'order_item_count', $this->chart_interval, $this->start_date, $this->chart_groupby ),
@ -639,6 +648,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
'coupon_amounts' => $this->prepare_chart_data( $this->report_data->coupons, 'post_date', 'discount_amount', $this->chart_interval, $this->start_date, $this->chart_groupby ),
'shipping_amounts' => $this->prepare_chart_data( $this->report_data->orders, 'post_date', 'total_shipping', $this->chart_interval, $this->start_date, $this->chart_groupby ),
'refund_amounts' => $this->prepare_chart_data( $this->report_data->refund_lines, 'post_date', 'total_refund', $this->chart_interval, $this->start_date, $this->chart_groupby ),
'net_refund_amounts' => $this->prepare_chart_data( $this->report_data->refunded_orders, 'post_date', 'net_refund', $this->chart_interval, $this->start_date, $this->chart_groupby ),
'shipping_tax_amounts' => $this->prepare_chart_data( $this->report_data->orders, 'post_date', 'total_shipping_tax', $this->chart_interval, $this->start_date, $this->chart_groupby ),
'tax_amounts' => $this->prepare_chart_data( $this->report_data->orders, 'post_date', 'total_tax', $this->chart_interval, $this->start_date, $this->chart_groupby ),
'net_order_amounts' => array(),
@ -650,19 +660,19 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
$data['gross_order_amounts'][ $order_amount_key ][1] -= $data['refund_amounts'][ $order_amount_key ][1];
$data['net_order_amounts'][ $order_amount_key ] = $order_amount_value;
// subtract the sum of the values from net order amounts
// Subtract the sum of the values from net order amounts.
$data['net_order_amounts'][ $order_amount_key ][1] -=
$data['refund_amounts'][ $order_amount_key ][1] +
$data['net_refund_amounts'][ $order_amount_key ][1] +
$data['shipping_amounts'][ $order_amount_key ][1] +
$data['shipping_tax_amounts'][ $order_amount_key ][1] +
$data['tax_amounts'][ $order_amount_key ][1];
}
// 3rd party filtering of report data
// 3rd party filtering of report data.
$data = apply_filters( 'woocommerce_admin_report_chart_data', $data );
// Encode in json format
$chart_data = json_encode(
// Encode in json format.
$chart_data = wp_json_encode(
array(
'order_counts' => array_values( $data['order_counts'] ),
'order_item_counts' => array_values( $data['order_item_counts'] ),
@ -683,30 +693,30 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
var main_chart;
jQuery(function(){
var order_data = jQuery.parseJSON( '<?php echo $chart_data; ?>' );
var order_data = jQuery.parseJSON( '<?php echo $chart_data; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>' );
var drawGraph = function( highlight ) {
var series = [
{
label: "<?php echo esc_js( __( 'Number of items sold', 'woocommerce' ) ); ?>",
data: order_data.order_item_counts,
color: '<?php echo $this->chart_colours['item_count']; ?>',
bars: { fillColor: '<?php echo $this->chart_colours['item_count']; ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo $this->barwidth; ?> * 0.5, align: 'center' },
color: '<?php echo esc_js( $this->chart_colours['item_count'] ); ?>',
bars: { fillColor: '<?php echo esc_js( $this->chart_colours['item_count'] ); ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo esc_js( $this->barwidth ); ?> * 0.5, align: 'center' },
shadowSize: 0,
hoverable: false
},
{
label: "<?php echo esc_js( __( 'Number of orders', 'woocommerce' ) ); ?>",
data: order_data.order_counts,
color: '<?php echo $this->chart_colours['order_count']; ?>',
bars: { fillColor: '<?php echo $this->chart_colours['order_count']; ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo $this->barwidth; ?> * 0.5, align: 'center' },
color: '<?php echo esc_js( $this->chart_colours['order_count'] ); ?>',
bars: { fillColor: '<?php echo esc_js( $this->chart_colours['order_count'] ); ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo esc_js( $this->barwidth ); ?> * 0.5, align: 'center' },
shadowSize: 0,
hoverable: false
},
{
label: "<?php echo esc_js( __( 'Average gross sales amount', 'woocommerce' ) ); ?>",
data: [ [ <?php echo min( array_keys( $data['order_amounts'] ) ); ?>, <?php echo $this->report_data->average_total_sales; ?> ], [ <?php echo max( array_keys( $data['order_amounts'] ) ); ?>, <?php echo $this->report_data->average_total_sales; ?> ] ],
data: [ [ <?php echo esc_js( min( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_total_sales ); ?> ], [ <?php echo esc_js( max( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_total_sales ); ?> ] ],
yaxis: 2,
color: '<?php echo $this->chart_colours['average']; ?>',
color: '<?php echo esc_js( $this->chart_colours['average'] ); ?>',
points: { show: false },
lines: { show: true, lineWidth: 2, fill: false },
shadowSize: 0,
@ -714,9 +724,9 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
},
{
label: "<?php echo esc_js( __( 'Average net sales amount', 'woocommerce' ) ); ?>",
data: [ [ <?php echo min( array_keys( $data['order_amounts'] ) ); ?>, <?php echo $this->report_data->average_sales; ?> ], [ <?php echo max( array_keys( $data['order_amounts'] ) ); ?>, <?php echo $this->report_data->average_sales; ?> ] ],
data: [ [ <?php echo esc_js( min( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_sales ); ?> ], [ <?php echo esc_js( max( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_sales ); ?> ] ],
yaxis: 2,
color: '<?php echo $this->chart_colours['net_average']; ?>',
color: '<?php echo esc_js( $this->chart_colours['net_average'] ); ?>',
points: { show: false },
lines: { show: true, lineWidth: 2, fill: false },
shadowSize: 0,
@ -726,51 +736,51 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
label: "<?php echo esc_js( __( 'Coupon amount', 'woocommerce' ) ); ?>",
data: order_data.coupon_amounts,
yaxis: 2,
color: '<?php echo $this->chart_colours['coupon_amount']; ?>',
color: '<?php echo esc_js( $this->chart_colours['coupon_amount'] ); ?>',
points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true },
lines: { show: true, lineWidth: 2, fill: false },
shadowSize: 0,
<?php echo $this->get_currency_tooltip(); ?>
<?php echo $this->get_currency_tooltip(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
},
{
label: "<?php echo esc_js( __( 'Shipping amount', 'woocommerce' ) ); ?>",
data: order_data.shipping_amounts,
yaxis: 2,
color: '<?php echo $this->chart_colours['shipping_amount']; ?>',
color: '<?php echo esc_js( $this->chart_colours['shipping_amount'] ); ?>',
points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true },
lines: { show: true, lineWidth: 2, fill: false },
shadowSize: 0,
prepend_tooltip: "<?php echo get_woocommerce_currency_symbol(); ?>"
prepend_tooltip: "<?php echo get_woocommerce_currency_symbol(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>"
},
{
label: "<?php echo esc_js( __( 'Gross sales amount', 'woocommerce' ) ); ?>",
data: order_data.gross_order_amounts,
yaxis: 2,
color: '<?php echo $this->chart_colours['sales_amount']; ?>',
color: '<?php echo esc_js( $this->chart_colours['sales_amount'] ); ?>',
points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true },
lines: { show: true, lineWidth: 2, fill: false },
shadowSize: 0,
<?php echo $this->get_currency_tooltip(); ?>
<?php echo $this->get_currency_tooltip(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
},
{
label: "<?php echo esc_js( __( 'Net sales amount', 'woocommerce' ) ); ?>",
data: order_data.net_order_amounts,
yaxis: 2,
color: '<?php echo $this->chart_colours['net_sales_amount']; ?>',
color: '<?php echo esc_js( $this->chart_colours['net_sales_amount'] ); ?>',
points: { show: true, radius: 6, lineWidth: 4, fillColor: '#fff', fill: true },
lines: { show: true, lineWidth: 5, fill: false },
shadowSize: 0,
<?php echo $this->get_currency_tooltip(); ?>
<?php echo $this->get_currency_tooltip(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
},
{
label: "<?php echo esc_js( __( 'Refund amount', 'woocommerce' ) ); ?>",
data: order_data.refund_amounts,
yaxis: 2,
color: '<?php echo $this->chart_colours['refund_amount']; ?>',
color: '<?php echo esc_js( $this->chart_colours['refund_amount'] ); ?>',
points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true },
lines: { show: true, lineWidth: 2, fill: false },
shadowSize: 0,
prepend_tooltip: "<?php echo get_woocommerce_currency_symbol(); ?>"
prepend_tooltip: "<?php echo get_woocommerce_currency_symbol(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>"
},
];
@ -807,9 +817,9 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
tickColor: 'transparent',
mode: "time",
timeformat: "<?php echo ( 'day' === $this->chart_groupby ) ? '%d %b' : '%b'; ?>",
monthNames: <?php echo json_encode( array_values( $wp_locale->month_abbrev ) ); ?>,
monthNames: <?php echo wp_json_encode( array_values( $wp_locale->month_abbrev ) ); ?>,
tickLength: 1,
minTickSize: [1, "<?php echo $this->chart_groupby; ?>"],
minTickSize: [1, "<?php echo esc_js( $this->chart_groupby ); ?>"],
font: {
color: "#aaa"
}

View File

@ -12,8 +12,6 @@ if ( ! defined( 'ABSPATH' ) ) {
/**
* WC_Report_Sales_By_Product
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin/Reports
* @version 2.1.0
*/
@ -44,11 +42,13 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
* Constructor.
*/
public function __construct() {
// @codingStandardsIgnoreStart
if ( isset( $_GET['product_ids'] ) && is_array( $_GET['product_ids'] ) ) {
$this->product_ids = array_filter( array_map( 'absint', $_GET['product_ids'] ) );
} elseif ( isset( $_GET['product_ids'] ) ) {
$this->product_ids = array_filter( array( absint( $_GET['product_ids'] ) ) );
}
// @codingStandardsIgnoreEnd
}
/**
@ -78,13 +78,14 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'relation' => 'OR',
array(
'type' => 'order_item_meta',
'meta_key' => array( '_product_id', '_variation_id' ),
'meta_value' => $this->product_ids,
'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_key
'meta_value' => $this->product_ids, // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_value
'operator' => 'IN',
),
),
'query_type' => 'get_var',
'filter_range' => true,
'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ),
)
);
@ -103,13 +104,14 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'relation' => 'OR',
array(
'type' => 'order_item_meta',
'meta_key' => array( '_product_id', '_variation_id' ),
'meta_value' => $this->product_ids,
'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_key
'meta_value' => $this->product_ids, // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_value
'operator' => 'IN',
),
),
'query_type' => 'get_var',
'filter_range' => true,
'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ),
)
)
);
@ -148,9 +150,9 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'item_count' => '#d4d9dc',
);
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day';
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) {
if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ), true ) ) {
$current_range = '7day';
}
@ -254,6 +256,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'limit' => 12,
'query_type' => 'get_results',
'filter_range' => true,
'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ),
)
);
@ -296,8 +299,8 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'where_meta' => array(
array(
'type' => 'order_item_meta',
'meta_key' => '_line_subtotal',
'meta_value' => '0',
'meta_key' => '_line_subtotal', // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_key
'meta_value' => '0', // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_value
'operator' => '=',
),
),
@ -350,6 +353,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'limit' => 12,
'query_type' => 'get_results',
'filter_range' => true,
'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ),
)
);
@ -396,7 +400,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
*/
public function get_export_button() {
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day';
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
?>
<a
href="#"
@ -450,8 +454,8 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'relation' => 'OR',
array(
'type' => 'order_item_meta',
'meta_key' => array( '_product_id', '_variation_id' ),
'meta_value' => $this->product_ids,
'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_key
'meta_value' => $this->product_ids, // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_value
'operator' => 'IN',
),
),
@ -459,6 +463,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'order_by' => 'post_date ASC',
'query_type' => 'get_results',
'filter_range' => true,
'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ),
)
);
@ -487,8 +492,8 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'relation' => 'OR',
array(
'type' => 'order_item_meta',
'meta_key' => array( '_product_id', '_variation_id' ),
'meta_value' => $this->product_ids,
'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_key
'meta_value' => $this->product_ids, // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_value
'operator' => 'IN',
),
),
@ -496,6 +501,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'order_by' => 'post_date ASC',
'query_type' => 'get_results',
'filter_range' => true,
'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ),
)
);
@ -504,7 +510,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
$order_item_amounts = $this->prepare_chart_data( $order_item_amounts, 'post_date', 'order_item_amount', $this->chart_interval, $this->start_date, $this->chart_groupby );
// Encode in json format.
$chart_data = json_encode(
$chart_data = wp_json_encode(
array(
'order_item_counts' => array_values( $order_item_counts ),
'order_item_amounts' => array_values( $order_item_amounts ),

View File

@ -1,14 +1,17 @@
<?php
/**
* Taxes by tax code report.
*
* @package WooCommerce/Admin/Reports
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
/**
* WC_Report_Taxes_By_Code
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin/Reports
* @version 2.1.0
*/
@ -28,15 +31,15 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
*/
public function get_export_button() {
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : 'last_month';
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : 'last_month';
?>
<a
href="#"
download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo date_i18n( 'Y-m-d', current_time( 'timestamp' ) ); ?>.csv"
download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_attr( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv"
class="export_csv"
data-export="table"
>
<?php _e( 'Export CSV', 'woocommerce' ); ?>
<?php esc_html_e( 'Export CSV', 'woocommerce' ); ?>
</a>
<?php
}
@ -52,7 +55,7 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
'month' => __( 'This month', 'woocommerce' ),
);
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : 'last_month';
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : 'last_month';
if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) {
$current_range = 'last_month';
@ -124,27 +127,58 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
'order_by' => 'posts.post_date ASC',
'query_type' => 'get_results',
'filter_range' => true,
'order_types' => array_merge( wc_get_order_types( 'sales-reports' ), array( 'shop_order_refund' ) ),
'order_status' => array( 'completed', 'processing' ),
'parent_order_status' => array( 'completed', 'processing' ), // Partial refunds inside refunded orders should be ignored
'order_types' => wc_get_order_types( 'sales-reports' ),
'order_status' => array( 'completed', 'processing', 'refunded' ),
)
);
// Merge
$tax_rows_partial_refunds = $this->get_order_report_data(
array(
'data' => $query_data,
'where' => $query_where,
'order_by' => 'posts.post_date ASC',
'query_type' => 'get_results',
'filter_range' => true,
'order_types' => array( 'shop_order_refund' ),
'parent_order_status' => array( 'completed', 'processing' ), // Partial refunds inside refunded orders should be ignored.
)
);
$tax_rows_full_refunds = $this->get_order_report_data(
array(
'data' => $query_data,
'where' => $query_where,
'order_by' => 'posts.post_date ASC',
'query_type' => 'get_results',
'filter_range' => true,
'order_types' => array( 'shop_order_refund' ),
'parent_order_status' => array( 'refunded' ),
)
);
// Merge.
$tax_rows = array();
foreach ( $tax_rows_orders as $tax_row ) {
foreach ( $tax_rows_orders + $tax_rows_partial_refunds as $tax_row ) {
$key = $tax_row->rate_id;
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array(
'tax_amount' => 0,
'shipping_tax_amount' => 0,
'total_orders' => 0,
);
$tax_rows[ $key ]->total_orders += 1;
$tax_rows[ $key ]->tax_rate = $tax_row->tax_rate;
$tax_rows[ $key ]->tax_amount += wc_round_tax_total( $tax_row->tax_amount );
$tax_rows[ $key ]->shipping_tax_amount += wc_round_tax_total( $tax_row->shipping_tax_amount );
}
if ( 'shop_order_refund' !== get_post_type( $tax_row->post_id ) ) {
$tax_rows[ $key ]->total_orders += 1;
}
foreach ( $tax_rows_full_refunds as $tax_row ) {
$key = $tax_row->rate_id;
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array(
'tax_amount' => 0,
'shipping_tax_amount' => 0,
'total_orders' => 0,
);
$tax_rows[ $key ]->tax_rate = $tax_row->tax_rate;
$tax_rows[ $key ]->tax_amount += wc_round_tax_total( $tax_row->tax_amount );
$tax_rows[ $key ]->shipping_tax_amount += wc_round_tax_total( $tax_row->shipping_tax_amount );
@ -153,12 +187,12 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
<table class="widefat">
<thead>
<tr>
<th><?php _e( 'Tax', 'woocommerce' ); ?></th>
<th><?php _e( 'Rate', 'woocommerce' ); ?></th>
<th class="total_row"><?php _e( 'Number of orders', 'woocommerce' ); ?></th>
<th class="total_row"><?php _e( 'Tax amount', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the sum of the "Tax rows" tax amount within your orders.', 'woocommerce' ) ); ?></th>
<th class="total_row"><?php _e( 'Shipping tax amount', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the sum of the "Tax rows" shipping tax amount within your orders.', 'woocommerce' ) ); ?></th>
<th class="total_row"><?php _e( 'Total tax', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the total tax for the rate (shipping tax + product tax).', 'woocommerce' ) ); ?></th>
<th><?php esc_html_e( 'Tax', 'woocommerce' ); ?></th>
<th><?php esc_html_e( 'Rate', 'woocommerce' ); ?></th>
<th class="total_row"><?php esc_html_e( 'Number of orders', 'woocommerce' ); ?></th>
<th class="total_row"><?php esc_html_e( 'Tax amount', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the sum of the "Tax rows" tax amount within your orders.', 'woocommerce' ) ); ?></th>
<th class="total_row"><?php esc_html_e( 'Shipping tax amount', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the sum of the "Tax rows" shipping tax amount within your orders.', 'woocommerce' ) ); ?></th>
<th class="total_row"><?php esc_html_e( 'Total tax', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the total tax for the rate (shipping tax + product tax).', 'woocommerce' ) ); ?></th>
</tr>
</thead>
<?php if ( ! empty( $tax_rows ) ) : ?>
@ -168,12 +202,12 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
$rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $rate_id ) );
?>
<tr>
<th scope="row"><?php echo apply_filters( 'woocommerce_reports_taxes_tax_rate', $tax_row->tax_rate, $rate_id, $tax_row ); ?></th>
<td><?php echo apply_filters( 'woocommerce_reports_taxes_rate', $rate, $rate_id, $tax_row ); ?>%</td>
<td class="total_row"><?php echo $tax_row->total_orders; ?></td>
<td class="total_row"><?php echo wc_price( $tax_row->tax_amount ); ?></td>
<td class="total_row"><?php echo wc_price( $tax_row->shipping_tax_amount ); ?></td>
<td class="total_row"><?php echo wc_price( $tax_row->tax_amount + $tax_row->shipping_tax_amount ); ?></td>
<th scope="row"><?php echo wp_kses_post( apply_filters( 'woocommerce_reports_taxes_tax_rate', $tax_row->tax_rate, $rate_id, $tax_row ) ); ?></th>
<td><?php echo wp_kses_post( apply_filters( 'woocommerce_reports_taxes_rate', $rate, $rate_id, $tax_row ) ); ?>%</td>
<td class="total_row"><?php echo esc_html( $tax_row->total_orders ); ?></td>
<td class="total_row"><?php echo wc_price( $tax_row->tax_amount ); // phpcs:ignore ?></td>
<td class="total_row"><?php echo wc_price( $tax_row->shipping_tax_amount ); // phpcs:ignore ?></td>
<td class="total_row"><?php echo wc_price( $tax_row->tax_amount + $tax_row->shipping_tax_amount ); // phpcs:ignore ?></td>
</tr>
<?php
}
@ -181,16 +215,16 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
</tbody>
<tfoot>
<tr>
<th scope="row" colspan="3"><?php _e( 'Total', 'woocommerce' ); ?></th>
<th class="total_row"><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) ) ); ?></th>
<th class="total_row"><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) ) ) ); ?></th>
<th class="total_row"><strong><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) + array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) ) ) ); ?></strong></th>
<th scope="row" colspan="3"><?php esc_html_e( 'Total', 'woocommerce' ); ?></th>
<th class="total_row"><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) ) ); // phpcs:ignore ?></th>
<th class="total_row"><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) ) ) ); // phpcs:ignore ?></th>
<th class="total_row"><strong><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) + array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) ) ) ); // phpcs:ignore ?></strong></th>
</tr>
</tfoot>
<?php else : ?>
<tbody>
<tr>
<td><?php _e( 'No taxes found in this period', 'woocommerce' ); ?></td>
<td><?php esc_html_e( 'No taxes found in this period', 'woocommerce' ); ?></td>
</tr>
</tbody>
<?php endif; ?>

View File

@ -133,7 +133,7 @@ class WC_Settings_Emails extends WC_Settings_Page {
'css' => 'width:300px; height: 75px;',
'placeholder' => __( 'N/A', 'woocommerce' ),
'type' => 'textarea',
'default' => '{site_title}<br/>Powered by <a href="https://woocommerce.com/">WooCommerce</a>',
'default' => '{site_title}<br/>Built with <a href="https://woocommerce.com/">WooCommerce</a>',
'autoload' => false,
'desc_tip' => true,
),

View File

@ -50,7 +50,8 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
if ( '' === $current_section ) {
$settings = apply_filters(
'woocommerce_payment_gateways_settings', array(
'woocommerce_payment_gateways_settings',
array(
array(
'title' => __( 'Payment methods', 'woocommerce' ),
'desc' => __( 'Installed payment methods are listed below and can be sorted to control their display order on the frontend.', 'woocommerce' ),
@ -94,10 +95,9 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
break;
}
}
} else {
$settings = $this->get_settings();
WC_Admin_Settings::output_fields( $settings );
}
$settings = $this->get_settings( $current_section );
WC_Admin_Settings::output_fields( $settings );
}
/**

View File

@ -76,8 +76,8 @@ class WC_Settings_Shipping extends WC_Settings_Page {
if ( '' === $current_section ) {
$settings = apply_filters(
'woocommerce_shipping_settings', array(
'woocommerce_shipping_settings',
array(
array(
'title' => __( 'Shipping options', 'woocommerce' ),
'type' => 'title',
@ -157,11 +157,18 @@ class WC_Settings_Shipping extends WC_Settings_Page {
$hide_save_button = true;
$this->output_shipping_class_screen();
} else {
$is_shipping_method = false;
foreach ( $shipping_methods as $method ) {
if ( in_array( $current_section, array( $method->id, sanitize_title( get_class( $method ) ) ), true ) && $method->has_settings() ) {
$is_shipping_method = true;
$method->admin_options();
}
}
if ( ! $is_shipping_method ) {
$settings = $this->get_settings();
$settings = apply_filters( 'woocommerce_get_settings_' . $this->id, $settings, $current_section );
WC_Admin_Settings::output_fields( $settings );
}
}
}
@ -182,13 +189,18 @@ class WC_Settings_Shipping extends WC_Settings_Page {
case '':
break;
default:
$wc_shipping = WC_Shipping::instance();
$wc_shipping = WC_Shipping::instance();
$is_shipping_method = false;
foreach ( $wc_shipping->get_shipping_methods() as $method_id => $method ) {
if ( in_array( $current_section, array( $method->id, sanitize_title( get_class( $method ) ) ), true ) ) {
$is_shipping_method = true;
do_action( 'woocommerce_update_options_' . $this->id . '_' . $method->id );
}
}
if ( ! $is_shipping_method ) {
WC_Admin_Settings::save_fields( $this->get_settings( $current_section ) );
}
break;
}
@ -229,10 +241,8 @@ class WC_Settings_Shipping extends WC_Settings_Page {
wp_die( esc_html__( 'Zone does not exist!', 'woocommerce' ) );
}
$allowed_countries = WC()->countries->get_allowed_countries();
$wc_shipping = WC_Shipping::instance();
$shipping_methods = $wc_shipping->get_shipping_methods();
$continents = WC()->countries->get_continents();
$allowed_countries = WC()->countries->get_shipping_countries();
$shipping_continents = WC()->countries->get_shipping_continents();
// Prepare locations.
$locations = array();
@ -247,7 +257,9 @@ class WC_Settings_Shipping extends WC_Settings_Page {
}
wp_localize_script(
'wc-shipping-zone-methods', 'shippingZoneMethodsLocalizeScript', array(
'wc-shipping-zone-methods',
'shippingZoneMethodsLocalizeScript',
array(
'methods' => $zone->get_shipping_methods( false, 'json' ),
'zone_name' => $zone->get_zone_name(),
'zone_id' => $zone->get_id(),
@ -272,12 +284,12 @@ class WC_Settings_Shipping extends WC_Settings_Page {
* Show zones
*/
protected function zones_screen() {
$allowed_countries = WC()->countries->get_allowed_countries();
$continents = WC()->countries->get_continents();
$method_count = wc_get_shipping_method_count();
$method_count = wc_get_shipping_method_count();
wp_localize_script(
'wc-shipping-zones', 'shippingZonesLocalizeScript', array(
'wc-shipping-zones',
'shippingZonesLocalizeScript',
array(
'zones' => WC_Shipping_Zones::get_zones( 'json' ),
'default_zone' => array(
'zone_id' => 0,
@ -336,7 +348,9 @@ class WC_Settings_Shipping extends WC_Settings_Page {
protected function output_shipping_class_screen() {
$wc_shipping = WC_Shipping::instance();
wp_localize_script(
'wc-shipping-classes', 'shippingClassesLocalizeScript', array(
'wc-shipping-classes',
'shippingClassesLocalizeScript',
array(
'classes' => $wc_shipping->get_shipping_classes(),
'default_shipping_class' => array(
'term_id' => 0,
@ -354,7 +368,8 @@ class WC_Settings_Shipping extends WC_Settings_Page {
// Extendable columns to show on the shipping classes screen.
$shipping_class_columns = apply_filters(
'woocommerce_shipping_classes_columns', array(
'woocommerce_shipping_classes_columns',
array(
'wc-shipping-class-name' => __( 'Shipping class', 'woocommerce' ),
'wc-shipping-class-slug' => __( 'Slug', 'woocommerce' ),
'wc-shipping-class-description' => __( 'Description', 'woocommerce' ),

View File

@ -41,17 +41,19 @@ if ( ! defined( 'ABSPATH' ) ) {
<td class="forminp">
<select multiple="multiple" data-attribute="zone_locations" id="zone_locations" name="zone_locations" data-placeholder="<?php esc_html_e( 'Select regions within this zone', 'woocommerce' ); ?>" class="wc-shipping-zone-region-select chosen_select">
<?php
foreach ( $continents as $continent_code => $continent ) {
echo '<option value="continent:' . esc_attr( $continent_code ) . '"' . wc_selected( "continent:$continent_code", $locations ) . ' alt="">' . esc_html( $continent['name'] ) . '</option>';
foreach ( $shipping_continents as $continent_code => $continent ) {
echo '<option value="continent:' . esc_attr( $continent_code ) . '"' . wc_selected( "continent:$continent_code", $locations ) . '>' . esc_html( $continent['name'] ) . '</option>';
$countries = array_intersect( array_keys( $allowed_countries ), $continent['countries'] );
foreach ( $countries as $country_code ) {
echo '<option value="country:' . esc_attr( $country_code ) . '"' . wc_selected( "country:$country_code", $locations ) . ' alt="' . esc_attr( $continent['name'] ) . '">' . esc_html( '&nbsp;&nbsp; ' . $allowed_countries[ $country_code ] ) . '</option>';
echo '<option value="country:' . esc_attr( $country_code ) . '"' . wc_selected( "country:$country_code", $locations ) . '>' . esc_html( '&nbsp;&nbsp; ' . $allowed_countries[ $country_code ] ) . '</option>';
if ( $states = WC()->countries->get_states( $country_code ) ) {
$states = WC()->countries->get_states( $country_code );
if ( $states ) {
foreach ( $states as $state_code => $state_name ) {
echo '<option value="state:' . esc_attr( $country_code . ':' . $state_code ) . '"' . wc_selected( "state:$country_code:$state_code", $locations ) . ' alt="' . esc_attr( $continent['name'] . ' ' . $allowed_countries[ $country_code ] ) . '">' . esc_html( '&nbsp;&nbsp;&nbsp;&nbsp; ' . $state_name ) . '</option>';
echo '<option value="state:' . esc_attr( $country_code . ':' . $state_code ) . '"' . wc_selected( "state:$country_code:$state_code", $locations ) . '>' . esc_html( '&nbsp;&nbsp;&nbsp;&nbsp; ' . $state_name . ', ' . $allowed_countries[ $country_code ] ) . '</option>';
}
}
}
@ -138,8 +140,8 @@ if ( ! defined( 'ABSPATH' ) ) {
<header class="wc-backbone-modal-header">
<h1>
<?php
/* translators: %s: shipping method title */
printf(
/* translators: %s: shipping method title */
esc_html__( '%s Settings', 'woocommerce' ),
'{{{ data.method.method_title }}}'
);

View File

@ -9,6 +9,11 @@ defined( 'ABSPATH' ) || exit;
global $wpdb;
// This screen requires classes from the REST API.
if ( ! did_action( 'rest_api_init' ) ) {
WC()->api->rest_api_includes();
}
if ( ! class_exists( 'WC_REST_System_Status_Controller', false ) ) {
wp_die( 'Cannot load the REST API to access WC_REST_System_Status_Controller.' );
}
@ -55,15 +60,15 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'minor
</thead>
<tbody>
<tr>
<td data-export-label="Home URL"><?php esc_html_e( 'Home URL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( esc_html__( 'The homepage URL of your site.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
<td><?php echo esc_html( $environment['home_url'] ); ?></td>
</tr>
<tr>
<td data-export-label="Site URL"><?php esc_html_e( 'Site URL', 'woocommerce' ); ?>:</td>
<td data-export-label="WordPress address (URL)"><?php esc_html_e( 'WordPress address (URL)', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( esc_html__( 'The root URL of your site.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
<td><?php echo esc_html( $environment['site_url'] ); ?></td>
</tr>
<tr>
<td data-export-label="Site address (URL)"><?php esc_html_e( 'Site address (URL)', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( esc_html__( 'The homepage URL of your site.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
<td><?php echo esc_html( $environment['home_url'] ); ?></td>
</tr>
<tr>
<td data-export-label="WC Version"><?php esc_html_e( 'WooCommerce version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( esc_html__( 'The version of WooCommerce installed on your site.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>

View File

@ -257,6 +257,8 @@ if ( ! defined( 'ABSPATH' ) ) {
$options = array(
'' => __( '— No change —', 'woocommerce' ),
'1' => __( 'Change to:', 'woocommerce' ),
'2' => __( 'Increase existing stock by:', 'woocommerce' ),
'3' => __( 'Decrease existing stock by:', 'woocommerce' ),
);
foreach ( $options as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '">' . $value . '</option>';

View File

@ -1,24 +0,0 @@
<?php
/**
* Admin View: Notice - Simplify Commerce.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$plugin_slug = 'woocommerce-gateway-simplify-commerce';
if ( current_user_can( 'install_plugins' ) ) {
$url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug );
} else {
$url = 'https://wordpress.org/plugins/' . $plugin_slug;
}
?>
<div id="message" class="updated woocommerce-message">
<a class="woocommerce-message-close notice-dismiss" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc-hide-notice', 'simplify_commerce' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>"><?php _e( 'Dismiss', 'woocommerce' ); ?></a>
<p><?php _e( '<strong>The Simplify Commerce payment gateway is deprecated</strong> &#8211; Please install our new free Simplify Commerce plugin from WordPress.org. Simplify Commerce will be removed from WooCommerce core in a future update.', 'woocommerce' ); ?></p>
<p class="submit"><a href="<?php echo esc_url( $url ); ?>" class="wc-update-now button-primary"><?php _e( 'Install our new Simplify Commerce plugin', 'woocommerce' ); ?></a></p>
</div>

View File

@ -78,8 +78,9 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
}
if ( strlen( $page_content ) > 0 ) {
// Search for an existing page with the specified page content (typically a shortcode)
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$page_content}%" ) );
// Search for an existing page with the specified page content (typically a shortcode).
$shortcode = str_replace( array( '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ), '', $page_content );
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) );
} else {
// Search for an existing page with the specified page slug
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_name = %s LIMIT 1;", $slug ) );

View File

@ -28,8 +28,9 @@ class WC_REST_Customers_Controller extends WC_REST_Customers_V2_Controller {
/**
* Get formatted item data.
*
* @param WC_Data $object WC_Data instance.
*
* @since 3.0.0
* @param WC_Data $object WC_Data instance.
* @return array
*/
protected function get_formatted_item_data( $object ) {
@ -38,7 +39,8 @@ class WC_REST_Customers_Controller extends WC_REST_Customers_V2_Controller {
// Format date values.
foreach ( $format_date as $key ) {
$datetime = $data[ $key ];
// Date created is stored UTC, date modified is stored WP local time.
$datetime = 'date_created' === $key ? get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $data[ $key ]->getTimestamp() ) ) : $data[ $key ];
$data[ $key ] = wc_rest_prepare_date_response( $datetime, false );
$data[ $key . '_gmt' ] = wc_rest_prepare_date_response( $datetime );
}

View File

@ -162,7 +162,7 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller {
// Make sure customer is part of blog.
if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) {
throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id_network', __( 'Customer ID does not belong to this site.', 'woocommerce' ), 400 );
add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' );
}
}

View File

@ -181,7 +181,7 @@ class WC_REST_Product_Categories_Controller extends WC_REST_Product_Categories_V
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
'name' => array(
'name' => array(
'description' => __( 'Image name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
@ -209,4 +209,63 @@ class WC_REST_Product_Categories_Controller extends WC_REST_Product_Categories_V
return $this->add_additional_fields_schema( $schema );
}
/**
* Update term meta fields.
*
* @param WP_Term $term Term object.
* @param WP_REST_Request $request Request instance.
* @return bool|WP_Error
*
* @since 3.5.5
*/
protected function update_term_meta_fields( $term, $request ) {
$id = (int) $term->term_id;
if ( isset( $request['display'] ) ) {
update_woocommerce_term_meta( $id, 'display_type', 'default' === $request['display'] ? '' : $request['display'] );
}
if ( isset( $request['menu_order'] ) ) {
update_woocommerce_term_meta( $id, 'order', $request['menu_order'] );
}
if ( isset( $request['image'] ) ) {
if ( empty( $request['image']['id'] ) && ! empty( $request['image']['src'] ) ) {
$upload = wc_rest_upload_image_from_url( esc_url_raw( $request['image']['src'] ) );
if ( is_wp_error( $upload ) ) {
return $upload;
}
$image_id = wc_rest_set_uploaded_image_as_attachment( $upload );
} else {
$image_id = isset( $request['image']['id'] ) ? absint( $request['image']['id'] ) : 0;
}
// Check if image_id is a valid image attachment before updating the term meta.
if ( $image_id && wp_attachment_is_image( $image_id ) ) {
update_woocommerce_term_meta( $id, 'thumbnail_id', $image_id );
// Set the image alt.
if ( ! empty( $request['image']['alt'] ) ) {
update_post_meta( $image_id, '_wp_attachment_image_alt', wc_clean( $request['image']['alt'] ) );
}
// Set the image title.
if ( ! empty( $request['image']['name'] ) ) {
wp_update_post(
array(
'ID' => $image_id,
'post_title' => wc_clean( $request['image']['name'] ),
)
);
}
} else {
delete_woocommerce_term_meta( $id, 'thumbnail_id' );
}
}
return true;
}
}

View File

@ -251,7 +251,7 @@ class WC_REST_Legacy_Orders_Controller extends WC_REST_CRUD_Controller {
// Make sure customer is part of blog.
if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) {
throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id_network',__( 'Customer ID does not belong to this site.', 'woocommerce' ), 400 );
add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' );
}
$order = $this->prepare_item_for_database( $request );

View File

@ -500,7 +500,7 @@ class WC_API_Products extends WC_API_Resource {
// taxonomy-based attributes are prefixed with `pa_`, otherwise simply `attribute_`
$attributes[] = array(
'name' => ucwords( str_replace( 'attribute_', '', str_replace( 'pa_', '', $attribute_name ) ) ),
'name' => ucwords( str_replace( 'attribute_', '', wc_attribute_taxonomy_slug( $attribute_name ) ) ),
'option' => $attribute,
);
}
@ -508,7 +508,7 @@ class WC_API_Products extends WC_API_Resource {
foreach ( $product->get_attributes() as $attribute ) {
$attributes[] = array(
'name' => ucwords( str_replace( 'pa_', '', $attribute['name'] ) ),
'name' => ucwords( wc_attribute_taxonomy_slug( $attribute['name'] ) ),
'position' => $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],

View File

@ -973,7 +973,7 @@ class WC_API_Orders extends WC_API_Resource {
if ( isset( $variations ) && is_array( $variations ) ) {
// start by normalizing the passed variations
foreach ( $variations as $key => $value ) {
$key = str_replace( 'attribute_', '', str_replace( 'pa_', '', $key ) ); // from get_attributes in class-wc-api-products.php
$key = str_replace( 'attribute_', '', wc_attribute_taxonomy_slug( $key ) ); // from get_attributes in class-wc-api-products.php
$variations_normalized[ $key ] = strtolower( $value );
}
// now search through each product child and see if our passed variations match anything
@ -981,7 +981,7 @@ class WC_API_Orders extends WC_API_Resource {
$meta = array();
foreach ( get_post_meta( $variation ) as $key => $value ) {
$value = $value[0];
$key = str_replace( 'attribute_', '', str_replace( 'pa_', '', $key ) );
$key = str_replace( 'attribute_', '', wc_attribute_taxonomy_slug( $key ) );
$meta[ $key ] = strtolower( $value );
}
// if the variation array is a part of the $meta array, we found our match

View File

@ -1691,73 +1691,16 @@ class WC_API_Products extends WC_API_Resource {
*
* @param string $image_url
*
* @return array|WP_Error
* @return array
*
* @throws WC_API_Exception
*/
public function upload_product_image( $image_url ) {
$file_name = basename( current( explode( '?', $image_url ) ) );
$parsed_url = @parse_url( $image_url );
// Check parsed URL
if ( ! $parsed_url || ! is_array( $parsed_url ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_image', sprintf( __( 'Invalid URL %s.', 'woocommerce' ), $image_url ), 400 );
$upload = wc_rest_upload_image_from_url( $image_url );
if ( is_wp_error( $upload ) ) {
throw new WC_API_Exception( 'woocommerce_api_product_image_upload_error', $upload->get_error_message(), 400 );
}
// Ensure url is valid
$image_url = str_replace( ' ', '%20', $image_url );
// Get the file
$response = wp_safe_remote_get( $image_url, array(
'timeout' => 10,
) );
if ( is_wp_error( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) . ' ' . sprintf( __( 'Error: %s.', 'woocommerce' ), $response->get_error_message() ), 400 );
} elseif ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ), 400 );
}
// Ensure we have a file name and type
$wp_filetype = wp_check_filetype( $file_name, wc_rest_allowed_image_mime_types() );
if ( ! $wp_filetype['type'] ) {
$headers = wp_remote_retrieve_headers( $response );
if ( isset( $headers['content-disposition'] ) && strstr( $headers['content-disposition'], 'filename=' ) ) {
$disposition = end( explode( 'filename=', $headers['content-disposition'] ) );
$disposition = sanitize_file_name( $disposition );
$file_name = $disposition;
} elseif ( isset( $headers['content-type'] ) && strstr( $headers['content-type'], 'image/' ) ) {
$file_name = 'image.' . str_replace( 'image/', '', $headers['content-type'] );
}
unset( $headers );
// Recheck filetype
$wp_filetype = wp_check_filetype( $file_name, wc_rest_allowed_image_mime_types() );
if ( ! $wp_filetype['type'] ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_product_image', __( 'Invalid image type.', 'woocommerce' ), 400 );
}
}
// Upload the file
$upload = wp_upload_bits( $file_name, '', wp_remote_retrieve_body( $response ) );
if ( $upload['error'] ) {
throw new WC_API_Exception( 'woocommerce_api_product_image_upload_error', $upload['error'], 400 );
}
// Get filesize
$filesize = filesize( $upload['file'] );
if ( 0 == $filesize ) {
@unlink( $upload['file'] );
unset( $upload );
throw new WC_API_Exception( 'woocommerce_api_product_image_upload_file_error', __( 'Zero size file downloaded.', 'woocommerce' ), 400 );
}
unset( $response );
return $upload;
}
@ -1835,7 +1778,7 @@ class WC_API_Products extends WC_API_Resource {
// taxonomy-based attributes are prefixed with `pa_`, otherwise simply `attribute_`
$attributes[] = array(
'name' => wc_attribute_label( str_replace( 'attribute_', '', $attribute_name ) ),
'slug' => str_replace( 'attribute_', '', str_replace( 'pa_', '', $attribute_name ) ),
'slug' => str_replace( 'attribute_', '', wc_attribute_taxonomy_slug( $attribute_name ) ),
'option' => $attribute,
);
}
@ -1844,7 +1787,7 @@ class WC_API_Products extends WC_API_Resource {
foreach ( $product->get_attributes() as $attribute ) {
$attributes[] = array(
'name' => wc_attribute_label( $attribute['name'] ),
'slug' => str_replace( 'pa_', '', $attribute['name'] ),
'slug' => wc_attribute_taxonomy_slug( $attribute['name'] ),
'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],

View File

@ -195,7 +195,7 @@ class WC_API_Webhooks extends WC_API_Resource {
'post_status' => 'publish',
'ping_status' => 'closed',
'post_author' => get_current_user_id(),
'post_password' => strlen( ( $password = uniqid( 'webhook_' ) ) ) > 20 ? substr( $password, 0, 20 ) : $password,
'post_password' => 'webhook_' . wp_generate_password(),
'post_title' => ! empty( $data['name'] ) ? $data['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ),
), $data, $this );

View File

@ -1018,7 +1018,7 @@ class WC_API_Orders extends WC_API_Resource {
if ( isset( $variations ) && is_array( $variations ) ) {
// start by normalizing the passed variations
foreach ( $variations as $key => $value ) {
$key = str_replace( 'attribute_', '', str_replace( 'pa_', '', $key ) ); // from get_attributes in class-wc-api-products.php
$key = str_replace( 'attribute_', '', wc_attribute_taxonomy_slug( $key ) ); // from get_attributes in class-wc-api-products.php
$variations_normalized[ $key ] = strtolower( $value );
}
// now search through each product child and see if our passed variations match anything
@ -1026,7 +1026,7 @@ class WC_API_Orders extends WC_API_Resource {
$meta = array();
foreach ( get_post_meta( $variation ) as $key => $value ) {
$value = $value[0];
$key = str_replace( 'attribute_', '', str_replace( 'pa_', '', $key ) );
$key = str_replace( 'attribute_', '', wc_attribute_taxonomy_slug( $key ) );
$meta[ $key ] = strtolower( $value );
}
// if the variation array is a part of the $meta array, we found our match

View File

@ -2226,71 +2226,14 @@ class WC_API_Products extends WC_API_Resource {
* @since 2.5.0
* @param string $image_url
* @param string $upload_for
* @return array|WP_Error
* @return array
*/
protected function upload_image_from_url( $image_url, $upload_for = 'product_image' ) {
$file_name = basename( current( explode( '?', $image_url ) ) );
$parsed_url = @parse_url( $image_url );
// Check parsed URL.
if ( ! $parsed_url || ! is_array( $parsed_url ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_' . $upload_for, sprintf( __( 'Invalid URL %s.', 'woocommerce' ), $image_url ), 400 );
$upload = wc_rest_upload_image_from_url( $image_url );
if ( is_wp_error( $upload ) ) {
throw new WC_API_Exception( 'woocommerce_api_' . $upload_for . '_upload_error', $upload->get_error_message(), 400 );
}
// Ensure url is valid.
$image_url = str_replace( ' ', '%20', $image_url );
// Get the file.
$response = wp_safe_remote_get( $image_url, array(
'timeout' => 10,
) );
if ( is_wp_error( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_' . $upload_for, sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) . ' ' . sprintf( __( 'Error: %s.', 'woocommerce' ), $response->get_error_message() ), 400 );
} elseif ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_remote_' . $upload_for, sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ), 400 );
}
// Ensure we have a file name and type.
$wp_filetype = wp_check_filetype( $file_name, wc_rest_allowed_image_mime_types() );
if ( ! $wp_filetype['type'] ) {
$headers = wp_remote_retrieve_headers( $response );
if ( isset( $headers['content-disposition'] ) && strstr( $headers['content-disposition'], 'filename=' ) ) {
$disposition = end( explode( 'filename=', $headers['content-disposition'] ) );
$disposition = sanitize_file_name( $disposition );
$file_name = $disposition;
} elseif ( isset( $headers['content-type'] ) && strstr( $headers['content-type'], 'image/' ) ) {
$file_name = 'image.' . str_replace( 'image/', '', $headers['content-type'] );
}
unset( $headers );
// Recheck filetype
$wp_filetype = wp_check_filetype( $file_name, wc_rest_allowed_image_mime_types() );
if ( ! $wp_filetype['type'] ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_' . $upload_for, __( 'Invalid image type.', 'woocommerce' ), 400 );
}
}
// Upload the file.
$upload = wp_upload_bits( $file_name, '', wp_remote_retrieve_body( $response ) );
if ( $upload['error'] ) {
throw new WC_API_Exception( 'woocommerce_api_' . $upload_for . '_upload_error', $upload['error'], 400 );
}
// Get filesize.
$filesize = filesize( $upload['file'] );
if ( 0 == $filesize ) {
@unlink( $upload['file'] );
unset( $upload );
throw new WC_API_Exception( 'woocommerce_api_' . $upload_for . '_upload_file_error', __( 'Zero size file downloaded.', 'woocommerce' ), 400 );
}
unset( $response );
do_action( 'woocommerce_api_uploaded_image_from_url', $upload, $image_url, $upload_for );
return $upload;
@ -2393,7 +2336,7 @@ class WC_API_Products extends WC_API_Resource {
// taxonomy-based attributes are prefixed with `pa_`, otherwise simply `attribute_`
$attributes[] = array(
'name' => wc_attribute_label( str_replace( 'attribute_', '', $attribute_name ), $product ),
'slug' => str_replace( 'attribute_', '', str_replace( 'pa_', '', $attribute_name ) ),
'slug' => str_replace( 'attribute_', '', wc_attribute_taxonomy_slug( $attribute_name ) ),
'option' => $attribute,
);
}
@ -2402,7 +2345,7 @@ class WC_API_Products extends WC_API_Resource {
foreach ( $product->get_attributes() as $attribute ) {
$attributes[] = array(
'name' => wc_attribute_label( $attribute['name'], $product ),
'slug' => str_replace( 'pa_', '', $attribute['name'] ),
'slug' => wc_attribute_taxonomy_slug( $attribute['name'] ),
'position' => (int) $attribute['position'],
'visible' => (bool) $attribute['is_visible'],
'variation' => (bool) $attribute['is_variation'],

View File

@ -195,7 +195,7 @@ class WC_API_Webhooks extends WC_API_Resource {
'post_status' => 'publish',
'ping_status' => 'closed',
'post_author' => get_current_user_id(),
'post_password' => strlen( ( $password = uniqid( 'webhook_' ) ) ) > 20 ? substr( $password, 0, 20 ) : $password,
'post_password' => 'webhook_' . wp_generate_password(),
'post_title' => ! empty( $data['name'] ) ? $data['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ),
), $data, $this );

View File

@ -536,7 +536,7 @@ class WC_REST_Orders_V1_Controller extends WC_REST_Posts_Controller {
// Make sure customer is part of blog.
if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) {
throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id_network',__( 'Customer ID does not belong to this site.', 'woocommerce' ), 400 );
add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' );
}
$order = $this->prepare_item_for_database( $request );

View File

@ -352,7 +352,7 @@ class WC_REST_Products_V1_Controller extends WC_REST_Posts_Controller {
} else {
$default[] = array(
'id' => 0,
'name' => str_replace( 'pa_', '', $key ),
'name' => wc_attribute_taxonomy_slug( $key ),
'option' => $value,
);
}

View File

@ -504,8 +504,7 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
$data->post_author = get_current_user_id();
// Post password.
$password = strlen( uniqid( 'webhook_' ) );
$data->post_password = $password > 20 ? substr( $password, 0, 20 ) : $password;
$data->post_password = 'webhook_' . wp_generate_password();
// Post status.
$data->post_status = 'publish';

View File

@ -58,7 +58,9 @@ class WC_REST_Orders_V2_Controller extends WC_REST_Legacy_Orders_Controller {
*/
public function register_routes() {
register_rest_route(
$this->namespace, '/' . $this->rest_base, array(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
@ -76,7 +78,9 @@ class WC_REST_Orders_V2_Controller extends WC_REST_Legacy_Orders_Controller {
);
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
$this->namespace,
'/' . $this->rest_base . '/(?P<id>[\d]+)',
array(
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
@ -114,7 +118,9 @@ class WC_REST_Orders_V2_Controller extends WC_REST_Legacy_Orders_Controller {
);
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/batch', array(
$this->namespace,
'/' . $this->rest_base . '/batch',
array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'batch_items' ),
@ -382,12 +388,11 @@ class WC_REST_Orders_V2_Controller extends WC_REST_Legacy_Orders_Controller {
if ( ! empty( $request['product'] ) ) {
$order_ids = $wpdb->get_col(
$wpdb->prepare(
"
SELECT order_id
FROM {$wpdb->prefix}woocommerce_order_items
WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = %d )
AND order_item_type = 'line_item'
", $request['product']
"SELECT order_id
FROM {$wpdb->prefix}woocommerce_order_items
WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = %d )
AND order_item_type = 'line_item'",
$request['product']
)
);
@ -529,7 +534,7 @@ class WC_REST_Orders_V2_Controller extends WC_REST_Legacy_Orders_Controller {
// Make sure customer is part of blog.
if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) {
throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id_network', __( 'Customer ID does not belong to this site.', 'woocommerce' ), 400 );
add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' );
}
}

View File

@ -58,7 +58,8 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
*/
public function register_routes() {
register_rest_route(
$this->namespace, '/' . $this->rest_base, // @codingStandardsIgnoreLine.
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
@ -77,7 +78,8 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
);
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', // @codingStandardsIgnoreLine.
$this->namespace,
'/' . $this->rest_base . '/(?P<id>[\d]+)',
array(
'args' => array(
'id' => array(
@ -120,7 +122,8 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
);
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/batch', // @codingStandardsIgnoreLine.
$this->namespace,
'/' . $this->rest_base . '/batch',
array(
array(
'methods' => WP_REST_Server::EDITABLE,
@ -265,7 +268,8 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
}
$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
$args, array(
$args,
array(
'key' => '_sku',
'value' => $skus,
'compare' => 'IN',
@ -276,7 +280,8 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
// Filter by tax class.
if ( ! empty( $request['tax_class'] ) ) {
$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
$args, array(
$args,
array(
'key' => '_tax_class',
'value' => 'standard' !== $request['tax_class'] ? $request['tax_class'] : '',
)
@ -291,7 +296,8 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
// Filter product in stock or out of stock.
if ( is_bool( $request['in_stock'] ) ) {
$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
$args, array(
$args,
array(
'key' => '_stock_status',
'value' => true === $request['in_stock'] ? 'instock' : 'outofstock',
)
@ -454,7 +460,7 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
$attributes = $product->get_attributes();
if ( ! isset( $attributes[ $slug ] ) ) {
return str_replace( 'pa_', '', $slug );
return wc_attribute_taxonomy_slug( $slug );
}
$attribute = $attributes[ $slug ];
@ -511,7 +517,9 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
protected function get_attribute_options( $product_id, $attribute ) {
if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) {
return wc_get_product_terms(
$product_id, $attribute['name'], array(
$product_id,
$attribute['name'],
array(
'fields' => 'names',
)
);
@ -713,7 +721,9 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
if ( 'variation' === $product->get_type() ) {
return new WP_Error(
"woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ), array(
"woocommerce_rest_invalid_{$this->post_type}_id",
__( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ),
array(
'status' => 404,
)
);
@ -1199,7 +1209,7 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
*
* @param WC_Product $product Product instance.
* @param array $downloads Downloads data.
* @param int $deprecated Deprecated since 3.0
* @param int $deprecated Deprecated since 3.0.
*
* @return WC_Product
*/
@ -1332,7 +1342,9 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
if ( ! $object || 0 === $object->get_id() ) {
return new WP_Error(
"woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array(
"woocommerce_rest_{$this->post_type}_invalid_id",
__( 'Invalid ID.', 'woocommerce' ),
array(
'status' => 404,
)
);
@ -1340,7 +1352,9 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
if ( 'variation' === $object->get_type() ) {
return new WP_Error(
"woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ), array(
"woocommerce_rest_invalid_{$this->post_type}_id",
__( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ),
array(
'status' => 404,
)
);
@ -1360,8 +1374,10 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) {
return new WP_Error(
"woocommerce_rest_user_cannot_delete_{$this->post_type}",
/* translators: %s: post type */
"woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array(
sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ),
array(
'status' => rest_authorization_required_code(),
)
);
@ -1396,8 +1412,10 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
// If we don't support trashing for this type, error out.
if ( ! $supports_trash ) {
return new WP_Error(
'woocommerce_rest_trash_not_supported',
/* translators: %s: post type */
'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ), array(
sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ),
array(
'status' => 501,
)
);
@ -1407,8 +1425,10 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
if ( is_callable( array( $object, 'get_status' ) ) ) {
if ( 'trash' === $object->get_status() ) {
return new WP_Error(
'woocommerce_rest_already_trashed',
/* translators: %s: post type */
'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ), array(
sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ),
array(
'status' => 410,
)
);
@ -1421,8 +1441,10 @@ class WC_REST_Products_V2_Controller extends WC_REST_Legacy_Products_Controller
if ( ! $result ) {
return new WP_Error(
'woocommerce_rest_cannot_delete',
/* translators: %s: post type */
'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array(
sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ),
array(
'status' => 500,
)
);

View File

@ -37,7 +37,9 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
*/
public function register_routes() {
register_rest_route(
$this->namespace, '/' . $this->rest_base, array(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
@ -49,7 +51,9 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
);
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/(?P<id>[\w-]+)', array(
$this->namespace,
'/' . $this->rest_base . '/(?P<id>[\w-]+)',
array(
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
@ -199,7 +203,7 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
__( 'Note:', 'woocommerce' ),
__( 'This tool will update your WooCommerce database to the latest version. Please ensure you make sufficient backups before proceeding.', 'woocommerce' )
),
)
),
);
// Jetpack does the image resizing heavy lifting so you don't have to.
@ -226,7 +230,8 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
'name' => $tool['name'],
'action' => $tool['button'],
'description' => $tool['desc'],
), $request
),
$request
)
);
}
@ -254,7 +259,8 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
'name' => $tool['name'],
'action' => $tool['button'],
'description' => $tool['desc'],
), $request
),
$request
)
);
}
@ -418,6 +424,7 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
case 'clear_transients':
wc_delete_product_transients();
wc_delete_shop_order_transients();
delete_transient( 'wc_count_comments' );
$attribute_taxonomies = wc_get_attribute_taxonomies();
@ -494,14 +501,16 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
case 'recount_terms':
$product_cats = get_terms(
'product_cat', array(
'product_cat',
array(
'hide_empty' => false,
'fields' => 'id=>parent',
)
);
_wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), true, false );
$product_tags = get_terms(
'product_tag', array(
'product_tag',
array(
'hide_empty' => false,
'fields' => 'id=>parent',
)

View File

@ -572,6 +572,8 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
if ( function_exists( 'curl_version' ) ) {
$curl_version = curl_version();
$curl_version = $curl_version['version'] . ', ' . $curl_version['ssl_version'];
} elseif ( extension_loaded( 'curl' ) ) {
$curl_version = __( 'cURL installed but unable to retrieve version.', 'woocommerce' );
}
// WP memory limit.
@ -600,7 +602,7 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
// 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 ) {
if ( ! is_wp_error( $get_response ) && $get_response['response']['code'] >= 200 && $get_response['response']['code'] < 300 ) {
$get_response_successful = true;
}
@ -987,7 +989,7 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
* @return array
*/
public function get_security_info() {
$check_page = 0 < wc_get_page_id( 'shop' ) ? get_permalink( wc_get_page_id( 'shop' ) ) : get_home_url();
$check_page = wc_get_page_permalink( 'shop' );
return array(
'secure_connection' => 'https' === substr( $check_page, 0, 5 ),
'hide_errors' => ! ( defined( 'WP_DEBUG' ) && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG && WP_DEBUG_DISPLAY ) || 0 === intval( ini_get( 'display_errors' ) ),

View File

@ -2,8 +2,8 @@
/**
* WooCommerce WC_AJAX. AJAX Event Handlers.
*
* @class WC_AJAX
* @package WooCommerce/Classes
* @class WC_AJAX
* @package WooCommerce/Classes
*/
defined( 'ABSPATH' ) || exit;
@ -25,7 +25,8 @@ class WC_AJAX {
/**
* Get WC Ajax Endpoint.
*
* @param string $request Optional.
* @param string $request Optional.
*
* @return string
*/
public static function get_endpoint( $request = '' ) {
@ -178,7 +179,7 @@ class WC_AJAX {
'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>',
)
),
'cart_hash' => apply_filters( 'woocommerce_add_to_cart_hash', WC()->cart->get_cart_for_session() ? md5( json_encode( WC()->cart->get_cart_for_session() ) ) : '', WC()->cart->get_cart_for_session() ),
'cart_hash' => WC()->cart->get_cart_hash(),
);
wp_send_json( $data );
@ -334,18 +335,19 @@ class WC_AJAX {
WC()->customer->save();
WC()->cart->calculate_totals();
// Get order review fragment
// Get order review fragment.
ob_start();
woocommerce_order_review();
$woocommerce_order_review = ob_get_clean();
// Get checkout payment fragment
// Get checkout payment fragment.
ob_start();
woocommerce_checkout_payment();
$woocommerce_checkout_payment = ob_get_clean();
// Get messages if reload checkout is not true
if ( ! isset( WC()->session->reload_checkout ) ) {
// Get messages if reload checkout is not true.
$reload_checkout = isset( WC()->session->reload_checkout ) ? true : false;
if ( ! $reload_checkout ) {
$messages = wc_print_notices( true );
} else {
$messages = '';
@ -357,9 +359,10 @@ class WC_AJAX {
array(
'result' => empty( $messages ) ? 'success' : 'failure',
'messages' => $messages,
'reload' => isset( WC()->session->reload_checkout ) ? 'true' : 'false',
'reload' => $reload_checkout ? 'true' : 'false',
'fragments' => apply_filters(
'woocommerce_update_order_review_fragments', array(
'woocommerce_update_order_review_fragments',
array(
'.woocommerce-checkout-review-order-table' => $woocommerce_order_review,
'.woocommerce-checkout-payment' => $woocommerce_checkout_payment,
)
@ -615,7 +618,7 @@ class WC_AJAX {
$response = array();
try {
parse_str( $_POST['data'], $data );
parse_str( wp_unslash( $_POST['data'] ), $data );
$attributes = WC_Meta_Box_Product_Data::prepare_attributes( $data );
$product_id = absint( $_POST['post_id'] );
@ -676,7 +679,7 @@ class WC_AJAX {
$variation_object->set_attributes( array_fill_keys( array_map( 'sanitize_title', array_keys( $product_object->get_variation_attributes() ) ), '' ) );
$variation_id = $variation_object->save();
$variation = get_post( $variation_id );
$variation_data = array_merge( array_map( 'maybe_unserialize', get_post_custom( $variation_id ) ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility.
$variation_data = array_merge( get_post_custom( $variation_id ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility.
include 'admin/meta-boxes/views/html-variation-admin.php';
wp_die();
}
@ -802,6 +805,7 @@ class WC_AJAX {
if ( $file->get_name() ) {
$file_count = $file->get_name();
} else {
/* translators: %d file count */
$file_count = sprintf( __( 'File %d', 'woocommerce' ), $file_counter );
}
include 'admin/meta-boxes/views/html-order-download-permission.php';
@ -947,6 +951,7 @@ class WC_AJAX {
$fee = new WC_Order_Item_Fee();
$fee->set_amount( $amount );
$fee->set_total( $amount );
/* translators: %s fee amount */
$fee->set_name( sprintf( __( '%s fee', 'woocommerce' ), wc_clean( $formatted_amount ) ) );
$order->add_item( $fee );
@ -1053,7 +1058,7 @@ class WC_AJAX {
$result = $order->apply_coupon( wc_clean( $_POST['coupon'] ) );
if ( is_wp_error( $result ) ) {
throw new Exception( $result->get_error_message() );
throw new Exception( html_entity_decode( wp_strip_all_tags( $result->get_error_message() ) ) );
}
ob_start();
@ -1292,7 +1297,10 @@ class WC_AJAX {
</div>
<p class="meta">
<abbr class="exact-date" title="<?php echo $note->date_created->date( 'y-m-d h:i:s' ); ?>">
<?php printf( __( 'added on %1$s at %2$s', 'woocommerce' ), $note->date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) ); ?>
<?php
/* translators: $1: Date created, $2 Time created */
printf( __( 'added on %1$s at %2$s', 'woocommerce' ), $note->date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) );
?>
</abbr>
<?php
if ( 'system' !== $note->added_by ) :
@ -1470,6 +1478,7 @@ class WC_AJAX {
$customer = new WC_Customer( $id );
/* translators: 1: user display name 2: user ID 3: user email */
$found_customers[ $id ] = sprintf(
/* translators: $1: customer name, $2 customer id, $3: customer email */
esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
$customer->get_first_name() . ' ' . $customer->get_last_name(),
$customer->get_id(),
@ -1872,7 +1881,7 @@ class WC_AJAX {
foreach ( $variations as $variation_object ) {
$variation_id = $variation_object->get_id();
$variation = get_post( $variation_id );
$variation_data = array_merge( array_map( 'maybe_unserialize', get_post_custom( $variation_id ) ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility.
$variation_data = array_merge( get_post_custom( $variation_id ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility.
include 'admin/meta-boxes/views/html-variation-admin.php';
$loop++;
}
@ -1918,10 +1927,10 @@ class WC_AJAX {
/**
* Bulk action - Toggle Enabled.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_toggle_enabled( $variations, $data ) {
foreach ( $variations as $variation_id ) {
@ -1934,10 +1943,10 @@ class WC_AJAX {
/**
* Bulk action - Toggle Downloadable Checkbox.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_toggle_downloadable( $variations, $data ) {
self::variation_bulk_toggle( $variations, 'downloadable' );
@ -1946,10 +1955,10 @@ class WC_AJAX {
/**
* Bulk action - Toggle Virtual Checkbox.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_toggle_virtual( $variations, $data ) {
self::variation_bulk_toggle( $variations, 'virtual' );
@ -1958,10 +1967,10 @@ class WC_AJAX {
/**
* Bulk action - Toggle Manage Stock Checkbox.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_toggle_manage_stock( $variations, $data ) {
self::variation_bulk_toggle( $variations, 'manage_stock' );
@ -1970,10 +1979,10 @@ class WC_AJAX {
/**
* Bulk action - Set Regular Prices.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_regular_price( $variations, $data ) {
self::variation_bulk_set( $variations, 'regular_price', $data['value'] );
@ -1982,10 +1991,10 @@ class WC_AJAX {
/**
* Bulk action - Set Sale Prices.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_sale_price( $variations, $data ) {
self::variation_bulk_set( $variations, 'sale_price', $data['value'] );
@ -1994,10 +2003,10 @@ class WC_AJAX {
/**
* Bulk action - Set Stock Status as In Stock.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_stock_status_instock( $variations, $data ) {
self::variation_bulk_set( $variations, 'stock_status', 'instock' );
@ -2006,10 +2015,10 @@ class WC_AJAX {
/**
* Bulk action - Set Stock Status as Out of Stock.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_stock_status_outofstock( $variations, $data ) {
self::variation_bulk_set( $variations, 'stock_status', 'outofstock' );
@ -2018,10 +2027,10 @@ class WC_AJAX {
/**
* Bulk action - Set Stock Status as On Backorder.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_stock_status_onbackorder( $variations, $data ) {
self::variation_bulk_set( $variations, 'stock_status', 'onbackorder' );
@ -2030,10 +2039,10 @@ class WC_AJAX {
/**
* Bulk action - Set Stock.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_stock( $variations, $data ) {
if ( ! isset( $data['value'] ) ) {
@ -2056,10 +2065,10 @@ class WC_AJAX {
/**
* Bulk action - Set Weight.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_weight( $variations, $data ) {
self::variation_bulk_set( $variations, 'weight', $data['value'] );
@ -2068,10 +2077,10 @@ class WC_AJAX {
/**
* Bulk action - Set Length.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_length( $variations, $data ) {
self::variation_bulk_set( $variations, 'length', $data['value'] );
@ -2080,10 +2089,10 @@ class WC_AJAX {
/**
* Bulk action - Set Width.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_width( $variations, $data ) {
self::variation_bulk_set( $variations, 'width', $data['value'] );
@ -2092,10 +2101,10 @@ class WC_AJAX {
/**
* Bulk action - Set Height.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_height( $variations, $data ) {
self::variation_bulk_set( $variations, 'height', $data['value'] );
@ -2104,10 +2113,10 @@ class WC_AJAX {
/**
* Bulk action - Set Download Limit.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_download_limit( $variations, $data ) {
self::variation_bulk_set( $variations, 'download_limit', $data['value'] );
@ -2116,10 +2125,10 @@ class WC_AJAX {
/**
* Bulk action - Set Download Expiry.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_download_expiry( $variations, $data ) {
self::variation_bulk_set( $variations, 'download_expiry', $data['value'] );
@ -2128,10 +2137,10 @@ class WC_AJAX {
/**
* Bulk action - Delete all.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_delete_all( $variations, $data ) {
if ( isset( $data['allowed'] ) && 'true' === $data['allowed'] ) {
@ -2145,10 +2154,10 @@ class WC_AJAX {
/**
* Bulk action - Sale Schedule.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_sale_schedule( $variations, $data ) {
if ( ! isset( $data['date_from'] ) && ! isset( $data['date_to'] ) ) {
@ -2173,10 +2182,10 @@ class WC_AJAX {
/**
* Bulk action - Increase Regular Prices.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_regular_price_increase( $variations, $data ) {
self::variation_bulk_adjust_price( $variations, 'regular_price', '+', wc_clean( $data['value'] ) );
@ -2185,10 +2194,10 @@ class WC_AJAX {
/**
* Bulk action - Decrease Regular Prices.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_regular_price_decrease( $variations, $data ) {
self::variation_bulk_adjust_price( $variations, 'regular_price', '-', wc_clean( $data['value'] ) );
@ -2197,10 +2206,10 @@ class WC_AJAX {
/**
* Bulk action - Increase Sale Prices.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_sale_price_increase( $variations, $data ) {
self::variation_bulk_adjust_price( $variations, 'sale_price', '+', wc_clean( $data['value'] ) );
@ -2209,10 +2218,10 @@ class WC_AJAX {
/**
* Bulk action - Decrease Sale Prices.
*
* @access private
* @param array $variations
* @param array $data
*
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_sale_price_decrease( $variations, $data ) {
self::variation_bulk_adjust_price( $variations, 'sale_price', '-', wc_clean( $data['value'] ) );
@ -2221,12 +2230,12 @@ class WC_AJAX {
/**
* Bulk action - Set Price.
*
* @access private
* @used-by bulk_edit_variations
* @param array $variations
* @param string $operator + or -
* @param string $field price being adjusted _regular_price or _sale_price
* @param string $value Price or Percent
*
* @used-by bulk_edit_variations
*/
private static function variation_bulk_adjust_price( $variations, $field, $operator, $value ) {
foreach ( $variations as $variation_id ) {
@ -2235,7 +2244,7 @@ class WC_AJAX {
if ( '%' === substr( $value, -1 ) ) {
$percent = wc_format_decimal( substr( $value, 0, -1 ) );
$field_value += ( ( $field_value / 100 ) * $percent ) * "{$operator}1";
$field_value += round( ( $field_value / 100 ) * $percent, wc_get_price_decimals() ) * "{$operator}1";
} else {
$field_value += $value * "{$operator}1";
}
@ -2248,7 +2257,6 @@ class WC_AJAX {
/**
* Bulk set convenience function.
*
* @access private
* @param array $variations
* @param string $field
* @param string $value
@ -2264,7 +2272,6 @@ class WC_AJAX {
/**
* Bulk toggle convenience function.
*
* @access private
* @param array $variations
* @param string $field
*/

View File

@ -1,8 +1,11 @@
<?php
/**
* WooCommerce API
* WooCommerce API class loader.
*
* Handles WC-API endpoint requests.
* This handles APIs in WooCommerce. These include:
* - wc-api endpoint - Commonly used by Payment gateways for callbacks.
* - Legacy REST API - Deprecated in 2.6.0. @see class-wc-legacy-api.php
* - WP REST API - The main REST API in WooCommerce which is built on top of the WP REST API.
*
* @package WooCommerce/API
* @since 2.0.0
@ -11,7 +14,7 @@
defined( 'ABSPATH' ) || exit;
/**
* API class.
* WC_API class.
*/
class WC_API extends WC_Legacy_API {
@ -23,22 +26,32 @@ class WC_API extends WC_Legacy_API {
public function __construct() {
parent::__construct();
// Add query vars.
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Register API endpoints.
add_action( 'init', array( $this, 'add_endpoint' ), 0 );
// Handle wc-api endpoint requests.
add_action( 'parse_request', array( $this, 'handle_api_requests' ), 0 );
// Ensure payment gateways are initialized in time for API requests.
add_action( 'woocommerce_api_request', array( 'WC_Payment_Gateways', 'instance' ), 0 );
// WP REST API.
$this->wc_api_init();
$this->rest_api_init();
}
/**
* Init the WC API by adding endpoints for those requests.
*/
private function wc_api_init() {
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
add_action( 'init', array( $this, 'add_endpoint' ), 0 );
add_action( 'parse_request', array( $this, 'handle_api_requests' ), 0 );
}
/**
* Init WP REST API by hooking into `rest_api_init`.
*
* @since 2.6.0
*/
private function rest_api_init() {
// Authentication needs to run early to handle basic auth.
include_once dirname( __FILE__ ) . '/api/class-wc-rest-authentication.php';
add_action( 'rest_api_init', array( $this, 'rest_api_includes' ), 5 );
add_action( 'rest_api_init', array( $this, 'register_rest_routes' ), 10 );
}
/**
* Add new query vars.
*
@ -87,6 +100,9 @@ class WC_API extends WC_Legacy_API {
// Clean the API request.
$api_request = strtolower( wc_clean( $wp->query_vars['wc-api'] ) );
// Make sure gateways are available for request.
WC()->payment_gateways();
// Trigger generic action before request hook.
do_action( 'woocommerce_api_request', $api_request );
@ -102,35 +118,15 @@ class WC_API extends WC_Legacy_API {
}
}
/**
* Init WP REST API.
*
* @since 2.6.0
*/
private function rest_api_init() {
// REST API was included starting WordPress 4.4.
if ( ! class_exists( 'WP_REST_Server' ) ) {
return;
}
$this->rest_api_includes();
// Init REST API routes.
add_action( 'rest_api_init', array( $this, 'register_rest_routes' ), 10 );
}
/**
* Include REST API classes.
*
* @since 2.6.0
*/
private function rest_api_includes() {
public function rest_api_includes() {
// Exception handler.
include_once dirname( __FILE__ ) . '/api/class-wc-rest-exception.php';
// Authentication.
include_once dirname( __FILE__ ) . '/api/class-wc-rest-authentication.php';
// Abstract controllers.
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-controller.php';
include_once dirname( __FILE__ ) . '/abstracts/abstract-wc-rest-posts-controller.php';
@ -370,5 +366,4 @@ class WC_API extends WC_Legacy_API {
new WC_Register_WP_Admin_Settings( $email, 'email' );
}
}
}

View File

@ -28,7 +28,7 @@ class WC_Breadcrumb {
*/
public function add_crumb( $name, $link = '' ) {
$this->crumbs[] = array(
strip_tags( $name ),
wp_strip_all_tags( $name ),
$link,
);
}
@ -148,8 +148,11 @@ class WC_Breadcrumb {
$this->prepend_shop_page();
$terms = wc_get_product_terms(
$post->ID, 'product_cat', apply_filters(
'woocommerce_breadcrumb_product_terms_args', array(
$post->ID,
'product_cat',
apply_filters(
'woocommerce_breadcrumb_product_terms_args',
array(
'orderby' => 'parent',
'order' => 'DESC',
)
@ -240,7 +243,7 @@ class WC_Breadcrumb {
if ( ! $_name ) {
$product_post_type = get_post_type_object( 'product' );
$_name = $product_post_type->labels->singular_name;
$_name = $product_post_type->labels->name;
}
$this->add_crumb( $_name, get_post_type_archive_link( 'product' ) );
@ -253,7 +256,7 @@ class WC_Breadcrumb {
$post_type = get_post_type_object( get_post_type() );
if ( $post_type ) {
$this->add_crumb( $post_type->labels->singular_name, get_post_type_archive_link( get_post_type() ) );
$this->add_crumb( $post_type->labels->name, get_post_type_archive_link( get_post_type() ) );
}
}
@ -368,7 +371,7 @@ class WC_Breadcrumb {
* Add a breadcrumb for pagination.
*/
private function paged_trail() {
if ( get_query_var( 'paged' ) ) {
if ( get_query_var( 'paged' ) && 'subcategories' !== woocommerce_get_loop_display_mode() ) {
/* translators: %d: page number */
$this->add_crumb( sprintf( __( 'Page %d', 'woocommerce' ), get_query_var( 'paged' ) ) );
}

View File

@ -12,18 +12,64 @@ defined( 'ABSPATH' ) || exit;
*/
class WC_Cache_Helper {
/**
* Transients to delete on shutdown.
*
* @var array Array of transient keys.
*/
private static $delete_transients = array();
/**
* Hook in methods.
*/
public static function init() {
add_action( 'shutdown', array( __CLASS__, 'delete_transients_on_shutdown' ), 10 );
add_action( 'template_redirect', array( __CLASS__, 'geolocation_ajax_redirect' ) );
add_action( 'admin_notices', array( __CLASS__, 'notices' ) );
add_action( 'delete_version_transients', array( __CLASS__, 'delete_version_transients' ) );
add_action( 'delete_version_transients', array( __CLASS__, 'delete_version_transients' ), 10 );
add_action( 'wp', array( __CLASS__, 'prevent_caching' ) );
add_action( 'clean_term_cache', array( __CLASS__, 'clean_term_cache' ), 10, 2 );
add_action( 'edit_terms', array( __CLASS__, 'clean_term_cache' ), 10, 2 );
}
/**
* Add a transient to delete on shutdown.
*
* @since 3.6.0
* @param string|array $keys Transient key or keys.
*/
public static function queue_delete_transient( $keys ) {
self::$delete_transients = array_unique( array_merge( is_array( $keys ) ? $keys : array( $keys ), self::$delete_transients ) );
}
/**
* Transients that don't need to be cleaned right away can be deleted on shutdown to avoid repetition.
*
* @since 3.6.0
*/
public static function delete_transients_on_shutdown() {
if ( self::$delete_transients ) {
foreach ( self::$delete_transients as $key ) {
delete_transient( $key );
}
self::$delete_transients = array();
}
}
/**
* Used to clear layered nav counts based on passed attribute names.
*
* @since 3.6.0
* @param array $attribute_keys Attribute keys.
*/
public static function invalidate_attribute_count( $attribute_keys ) {
if ( $attribute_keys ) {
foreach ( $attribute_keys as $attribute_key ) {
self::queue_delete_transient( 'wc_layered_nav_counts_' . $attribute_key );
}
}
}
/**
* Get prefix for use with wp_cache_set. Allows all cache in a group to be invalidated at once.
*
@ -134,62 +180,16 @@ class WC_Cache_Helper {
public static function get_transient_version( $group, $refresh = false ) {
$transient_name = $group . '-transient-version';
$transient_value = get_transient( $transient_name );
$transient_value = strval( $transient_value ? $transient_value : '' );
if ( '' === $transient_value || true === $refresh ) {
$old_transient_value = $transient_value;
$transient_value = (string) time();
if ( $old_transient_value === $transient_value ) {
// Time did not change but transient needs flushing now.
self::delete_version_transients( $transient_value );
} else {
self::queue_delete_version_transients( $transient_value );
}
if ( false === $transient_value || true === $refresh ) {
$transient_value = (string) time();
set_transient( $transient_name, $transient_value );
}
return $transient_value;
}
/**
* Queues a cleanup event for version transients.
*
* @param string $version Version of the transient to remove.
*/
protected static function queue_delete_version_transients( $version = '' ) {
if ( ! wp_using_ext_object_cache() && ! empty( $version ) ) {
wp_schedule_single_event( time() + 30, 'delete_version_transients', array( $version ) );
}
}
/**
* When the transient version increases, this is used to remove all past transients to avoid filling the DB.
*
* Note; this only works on transients appended with the transient version, and when object caching is not being used.
*
* @since 2.3.10
* @param string $version Version of the transient to remove.
*/
public static function delete_version_transients( $version = '' ) {
if ( ! wp_using_ext_object_cache() && ! empty( $version ) ) {
global $wpdb;
$limit = apply_filters( 'woocommerce_delete_version_transients_limit', 1000 );
if ( ! $limit ) {
return;
}
$affected = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s LIMIT %d;", '\_transient\_%' . $version, $limit ) ); // WPCS: cache ok, db call ok.
// If affected rows is equal to limit, there are more rows to delete. Delete in 30 secs.
if ( $affected === $limit ) {
self::queue_delete_version_transients( $version );
}
}
}
/**
* Set constants to prevent caching by some plugins.
*
@ -254,6 +254,34 @@ class WC_Cache_Helper {
}
}
}
/**
* When the transient version increases, this is used to remove all past transients to avoid filling the DB.
*
* Note; this only works on transients appended with the transient version, and when object caching is not being used.
*
* @deprecated 3.6.0 Adjusted transient usage to include versions within the transient values, making this cleanup obsolete.
* @since 2.3.10
* @param string $version Version of the transient to remove.
*/
public static function delete_version_transients( $version = '' ) {
if ( ! wp_using_ext_object_cache() && ! empty( $version ) ) {
global $wpdb;
$limit = apply_filters( 'woocommerce_delete_version_transients_limit', 1000 );
if ( ! $limit ) {
return;
}
$affected = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s LIMIT %d;", '\_transient\_%' . $version, $limit ) ); // WPCS: cache ok, db call ok.
// If affected rows is equal to limit, there are more rows to delete. Delete in 30 secs.
if ( $affected === $limit ) {
wp_schedule_single_event( time() + 30, 'delete_version_transients', array( $version ) );
}
}
}
}
WC_Cache_Helper::init();

View File

@ -30,6 +30,7 @@ final class WC_Cart_Session {
*
* @since 3.2.0
* @throws Exception If missing WC_Cart object.
*
* @param WC_Cart $cart Cart object to calculate totals for.
*/
public function __construct( &$cart ) {
@ -46,13 +47,19 @@ final class WC_Cart_Session {
public function init() {
add_action( 'wp_loaded', array( $this, 'get_cart_from_session' ) );
add_action( 'woocommerce_cart_emptied', array( $this, 'destroy_cart_session' ) );
add_action( 'wp', array( $this, 'maybe_set_cart_cookies' ), 99 );
add_action( 'woocommerce_add_to_cart', array( $this, 'maybe_set_cart_cookies' ) );
add_action( 'woocommerce_after_calculate_totals', array( $this, 'set_session' ) );
add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'set_session' ) );
add_action( 'woocommerce_removed_coupon', array( $this, 'set_session' ) );
add_action( 'shutdown', array( $this, 'maybe_set_cart_cookies' ), 0 );
add_action( 'woocommerce_cart_updated', array( $this, 'persistent_cart_update' ) );
// Cookie events - cart cookies need to be set before headers are sent.
if ( function_exists( 'header_register_callback' ) ) {
header_register_callback( array( $this, 'maybe_set_cart_cookies' ) ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.header_register_callbackFound
} else {
add_action( 'woocommerce_add_to_cart', array( $this, 'maybe_set_cart_cookies' ) );
add_action( 'wp', array( $this, 'maybe_set_cart_cookies' ), 99 );
add_action( 'shutdown', array( $this, 'maybe_set_cart_cookies' ), 0 );
}
}
/**
@ -97,40 +104,54 @@ final class WC_Cart_Session {
$cart_contents = array();
foreach ( $cart as $key => $values ) {
$product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] );
if ( ! is_customize_preview() && 'customize-preview' === $key ) {
continue;
}
if ( ! empty( $product ) && $product->exists() && $values['quantity'] > 0 ) {
$product = wc_get_product( $values['variation_id'] ? $values['variation_id'] : $values['product_id'] );
if ( ! $product->is_purchasable() ) {
$update_cart_session = true;
/* translators: %s: product name */
wc_add_notice( sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce' ), $product->get_name() ), 'error' );
do_action( 'woocommerce_remove_cart_item_from_session', $key, $values );
if ( empty( $product ) || ! $product->exists() || 0 >= $values['quantity'] ) {
continue;
}
} elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound
$update_cart_session = true;
/* translators: %1$s: product name. %2$s product permalink */
wc_add_notice( sprintf( __( '%1$s has been removed from your cart because it has since been modified. You can add it back to your cart <a href="%2$s">here</a>.', 'woocommerce' ), $product->get_name(), $product->get_permalink() ), 'notice' );
do_action( 'woocommerce_remove_cart_item_from_session', $key, $values );
/**
* Allow 3rd parties to validate this item before it's added to cart and add their own notices.
*
* @since 3.6.0
*
* @param bool $remove_cart_item_from_session If true, the item will not be added to the cart. Default: false.
* @param string $key Cart item key.
* @param array $values Cart item values e.g. quantity and product_id.
*/
if ( apply_filters( 'woocommerce_pre_remove_cart_item_from_session', false, $key, $values ) ) {
$update_cart_session = true;
do_action( 'woocommerce_remove_cart_item_from_session', $key, $values );
} else {
// Put session data into array. Run through filter so other plugins can load their own session data.
$session_data = array_merge(
$values,
array(
'data' => $product,
)
);
} elseif ( ! $product->is_purchasable() ) {
$update_cart_session = true;
/* translators: %s: product name */
wc_add_notice( sprintf( __( '%s has been removed from your cart because it can no longer be purchased. Please contact us if you need assistance.', 'woocommerce' ), $product->get_name() ), 'error' );
do_action( 'woocommerce_remove_cart_item_from_session', $key, $values );
$cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key );
} elseif ( ! empty( $values['data_hash'] ) && ! hash_equals( $values['data_hash'], wc_get_cart_item_data_hash( $product ) ) ) { // phpcs:ignore PHPCompatibility.PHP.NewFunctions.hash_equalsFound
$update_cart_session = true;
/* translators: %1$s: product name. %2$s product permalink */
wc_add_notice( sprintf( __( '%1$s has been removed from your cart because it has since been modified. You can add it back to your cart <a href="%2$s">here</a>.', 'woocommerce' ), $product->get_name(), $product->get_permalink() ), 'notice' );
do_action( 'woocommerce_remove_cart_item_from_session', $key, $values );
// Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook.
$this->cart->set_cart_contents( $cart_contents );
}
} else {
// Put session data into array. Run through filter so other plugins can load their own session data.
$session_data = array_merge(
$values,
array(
'data' => $product,
)
);
$cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key );
// Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook.
$this->cart->set_cart_contents( $cart_contents );
}
}
@ -238,18 +259,34 @@ final class WC_Cart_Session {
}
/**
* Set cart hash cookie and items in cart.
* Set cart hash cookie and items in cart if not already set.
*
* @param bool $set Should cookies be set (true) or unset.
*/
private function set_cart_cookies( $set = true ) {
if ( $set ) {
wc_setcookie( 'woocommerce_items_in_cart', 1 );
wc_setcookie( 'woocommerce_cart_hash', md5( wp_json_encode( $this->get_cart_for_session() ) ) );
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) { // WPCS: input var ok.
wc_setcookie( 'woocommerce_items_in_cart', 0, time() - HOUR_IN_SECONDS );
wc_setcookie( 'woocommerce_cart_hash', '', time() - HOUR_IN_SECONDS );
$setcookies = array(
'woocommerce_items_in_cart' => '1',
'woocommerce_cart_hash' => WC()->cart->get_cart_hash(),
);
foreach ( $setcookies as $name => $value ) {
if ( ! isset( $_COOKIE[ $name ] ) || $_COOKIE[ $name ] !== $value ) {
wc_setcookie( $name, $value );
}
}
} else {
$unsetcookies = array(
'woocommerce_items_in_cart',
'woocommerce_cart_hash',
);
foreach ( $unsetcookies as $name ) {
if ( isset( $_COOKIE[ $name ] ) ) {
wc_setcookie( $name, 0, time() - HOUR_IN_SECONDS );
unset( $_COOKIE[ $name ] );
}
}
}
do_action( 'woocommerce_set_cart_cookies', $set );
}
@ -277,8 +314,10 @@ final class WC_Cart_Session {
* Get a cart from an order, if user has permission.
*
* @since 3.5.0
*
* @param int $order_id Order ID to try to load.
* @param array $cart Current cart array.
*
* @return array
*/
private function populate_cart_from_order( $order_id, $cart ) {
@ -351,7 +390,7 @@ final class WC_Cart_Session {
);
}
do_action( 'woocommerce_ordered_again', $order->get_id(), $order_items, $cart );
do_action_ref_array( 'woocommerce_ordered_again', array( $order->get_id(), $order_items, &$cart ) );
$num_items_in_cart = count( $cart );
$num_items_in_original_order = count( $order_items );

View File

@ -159,6 +159,7 @@ final class WC_Cart_Totals {
'price_includes_tax' => false,
'subtotal' => 0,
'subtotal_tax' => 0,
'subtotal_taxes' => array(),
'total' => 0,
'total_tax' => 0,
'taxes' => array(),
@ -421,7 +422,15 @@ final class WC_Cart_Totals {
*/
protected function remove_item_base_taxes( $item ) {
if ( $item->price_includes_tax && $item->taxable ) {
$base_tax_rates = WC_Tax::get_base_tax_rates( $item->product->get_tax_class( 'unfiltered' ) );
if ( apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ) {
$base_tax_rates = WC_Tax::get_base_tax_rates( $item->product->get_tax_class( 'unfiltered' ) );
} else {
/**
* If we want all customers to pay the same price on this store, we should not remove base taxes from a VAT exempt user's price,
* but just the relevent tax rate. See issue #20911.
*/
$base_tax_rates = $item->tax_rates;
}
// Work out a new base price without the shop's base tax.
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
@ -484,8 +493,11 @@ final class WC_Cart_Totals {
if ( ! wc_tax_enabled() ) {
return array();
}
$tax_class = $item->product->get_tax_class();
return isset( $this->item_tax_rates[ $tax_class ] ) ? $this->item_tax_rates[ $tax_class ] : $this->item_tax_rates[ $tax_class ] = WC_Tax::get_rates( $item->product->get_tax_class(), $this->cart->get_customer() );
$tax_class = $item->product->get_tax_class();
$item_tax_rates = isset( $this->item_tax_rates[ $tax_class ] ) ? $this->item_tax_rates[ $tax_class ] : $this->item_tax_rates[ $tax_class ] = WC_Tax::get_rates( $item->product->get_tax_class(), $this->cart->get_customer() );
// Allow plugins to filter item tax rates.
return apply_filters( 'woocommerce_cart_totals_get_item_tax_rates', $item_tax_rates, $item, $this->cart );
}
/**
@ -693,6 +705,8 @@ final class WC_Cart_Totals {
* @since 3.2.0
*/
protected function calculate_item_subtotals() {
$merged_subtotal_taxes = array(); // Taxes indexed by tax rate ID for storage later.
foreach ( $this->items as $item_key => $item ) {
if ( $item->price_includes_tax ) {
if ( $this->cart->get_customer()->get_is_vat_exempt() ) {
@ -703,24 +717,31 @@ final class WC_Cart_Totals {
}
$item->subtotal = $item->price;
$subtotal_taxes = array();
if ( $this->calculate_tax && $item->product->is_taxable() ) {
$subtotal_taxes = WC_Tax::calc_tax( $item->subtotal, $item->tax_rates, $item->price_includes_tax );
$item->subtotal_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $subtotal_taxes ) );
$item->subtotal_taxes = WC_Tax::calc_tax( $item->subtotal, $item->tax_rates, $item->price_includes_tax );
$item->subtotal_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $item->subtotal_taxes ) );
if ( $item->price_includes_tax ) {
// Use unrounded taxes so we can re-calculate from the orders screen accurately later.
$item->subtotal = $item->subtotal - array_sum( $subtotal_taxes );
$item->subtotal = $item->subtotal - array_sum( $item->subtotal_taxes );
}
foreach ( $item->subtotal_taxes as $rate_id => $rate ) {
if ( ! isset( $merged_subtotal_taxes[ $rate_id ] ) ) {
$merged_subtotal_taxes[ $rate_id ] = 0;
}
$merged_subtotal_taxes[ $rate_id ] += $this->round_line_tax( $rate );
}
}
$this->cart->cart_contents[ $item_key ]['line_tax_data'] = array( 'subtotal' => wc_remove_number_precision_deep( $subtotal_taxes ) );
$this->cart->cart_contents[ $item_key ]['line_tax_data'] = array( 'subtotal' => wc_remove_number_precision_deep( $item->subtotal_taxes ) );
$this->cart->cart_contents[ $item_key ]['line_subtotal'] = wc_remove_number_precision( $item->subtotal );
$this->cart->cart_contents[ $item_key ]['line_subtotal_tax'] = wc_remove_number_precision( $item->subtotal_tax );
}
$this->set_total( 'items_subtotal', array_sum( array_map( 'round', array_values( wp_list_pluck( $this->items, 'subtotal' ) ) ) ) );
$this->set_total( 'items_subtotal_tax', array_sum( array_values( wp_list_pluck( $this->items, 'subtotal_tax' ) ) ) );
$this->set_total( 'items_subtotal_tax', array_sum( $this->round_merged_taxes( $merged_subtotal_taxes ) ) );
$this->cart->set_subtotal( $this->get_total( 'items_subtotal' ) );
$this->cart->set_subtotal_tax( $this->get_total( 'items_subtotal_tax' ) );

View File

@ -869,7 +869,7 @@ class WC_Cart extends WC_Legacy_Cart {
$tax_totals[ $code ]->is_compound = WC_Tax::is_compound( $key );
$tax_totals[ $code ]->label = WC_Tax::get_rate_label( $key );
$tax_totals[ $code ]->amount += wc_round_tax_total( $tax );
$tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ) );
$tax_totals[ $code ]->formatted_amount = wc_price( $tax_totals[ $code ]->amount );
}
}
@ -1425,7 +1425,7 @@ class WC_Cart extends WC_Legacy_Cart {
if ( $coupon->is_valid() ) {
// Get user and posted emails to compare.
$current_user = wp_get_current_user();
$current_user = wp_get_current_user();
$billing_email = isset( $posted['billing_email'] ) ? $posted['billing_email'] : '';
$check_emails = array_unique(
array_filter(
@ -1916,10 +1916,10 @@ class WC_Cart extends WC_Legacy_Cart {
if ( ! $compound && WC_Tax::is_compound( $key ) ) {
continue;
}
$total += $tax;
$total += wc_round_tax_total( $tax );
}
if ( $display ) {
$total = wc_round_tax_total( $total );
$total = wc_format_decimal( $total, wc_get_price_decimals() );
}
return apply_filters( 'woocommerce_cart_taxes_total', $total, $compound, $display, $this );
}
@ -1954,4 +1954,18 @@ class WC_Cart extends WC_Legacy_Cart {
return get_option( 'woocommerce_tax_display_cart' );
}
/**
* Returns the hash based on cart contents.
*
* @since 3.6.0
* @return string hash for cart content
*/
public function get_cart_hash() {
$cart_session = $this->session->get_cart_for_session();
$hash = $cart_session ? md5( wp_json_encode( $cart_session ) . $this->get_total( 'edit' ) ) : '';
$hash = apply_filters_deprecated( 'woocommerce_add_to_cart_hash', array( $hash, $cart_session ), '3.6.0', 'woocommerce_cart_hash' );
return apply_filters( 'woocommerce_cart_hash', $hash, $cart_session );
}
}

View File

@ -36,6 +36,13 @@ class WC_Checkout {
*/
protected $legacy_posted_data = array();
/**
* Caches customer object. @see get_value.
*
* @var WC_Customer
*/
private $logged_in_customer = null;
/**
* Gets the main WC_Checkout Instance.
*
@ -293,7 +300,7 @@ class WC_Checkout {
try {
$order_id = absint( WC()->session->get( 'order_awaiting_payment' ) );
$cart_hash = md5( wp_json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total );
$cart_hash = WC()->cart->get_cart_hash();
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
$order = $order_id ? wc_get_order( $order_id ) : null;
@ -314,13 +321,14 @@ class WC_Checkout {
}
$fields_prefix = array(
'shipping' => true,
'billing' => true,
'shipping' => true,
'billing' => true,
);
$shipping_fields = array(
'shipping_method' => true,
'shipping_total' => true,
'shipping_tax' => true,
'shipping_method' => true,
'shipping_total' => true,
'shipping_tax' => true,
);
foreach ( $data as $key => $value ) {
if ( is_callable( array( $order, "set_{$key}" ) ) ) {
@ -336,6 +344,8 @@ class WC_Checkout {
$order->set_created_via( 'checkout' );
$order->set_cart_hash( $cart_hash );
$order->set_customer_id( apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() ) );
$order_vat_exempt = WC()->cart->get_customer()->get_is_vat_exempt() ? 'yes' : 'no';
$order->add_meta_data( 'is_vat_exempt', $order_vat_exempt );
$order->set_currency( get_woocommerce_currency() );
$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
@ -711,7 +721,7 @@ class WC_Checkout {
if ( in_array( 'email', $format, true ) && '' !== $data[ $key ] ) {
$email_is_valid = is_email( $data[ $key ] );
$data[ $key ] = sanitize_email( $data[ $key ] );
$data[ $key ] = sanitize_email( $data[ $key ] );
if ( $validate_fieldset && ! $email_is_valid ) {
/* translators: %s: email address */
@ -944,7 +954,6 @@ class WC_Checkout {
throw new Exception( $customer_id->get_error_message() );
}
wp_set_current_user( $customer_id );
wc_set_customer_auth_cookie( $customer_id );
// As we are now logged in, checkout will need to refresh to show logged in data.
@ -1106,29 +1115,52 @@ class WC_Checkout {
}
/**
* Gets the value either from the posted data, or from the users meta data.
* Gets the value either from POST, or from the customer object. Sets the default values in checkout fields.
*
* @param string $input Input key.
* @return string
* @param string $input Name of the input we want to grab data for. e.g. billing_country.
* @return string The default value.
*/
public function get_value( $input ) {
// If the form was posted, get the posted value. This will only tend to happen when JavaScript is disabled client side.
if ( ! empty( $_POST[ $input ] ) ) { // WPCS: input var ok, CSRF OK.
return wc_clean( wp_unslash( $_POST[ $input ] ) ); // WPCS: input var ok, CSRF OK.
}
// Allow 3rd parties to short circuit the logic and return their own default value.
$value = apply_filters( 'woocommerce_checkout_get_value', null, $input );
if ( null !== $value ) {
if ( ! is_null( $value ) ) {
return $value;
}
if ( is_callable( array( WC()->customer, "get_$input" ) ) ) {
$value = WC()->customer->{"get_$input"}();
} elseif ( WC()->customer->meta_exists( $input ) ) {
$value = WC()->customer->get_meta( $input, true );
/**
* For logged in customers, pull data from their account rather than the session which may contain incomplete data.
* Another reason is that WC sets shipping address to the billing address on the checkout updates unless the
* "ship to another address" box is checked. @see issue #20975.
*/
$customer_object = false;
if ( is_user_logged_in() ) {
// Load customer object, but keep it cached to avoid reloading it multiple times.
if ( is_null( $this->logged_in_customer ) ) {
$this->logged_in_customer = new WC_Customer( get_current_user_id() );
}
$customer_object = $this->logged_in_customer;
}
$value = $value ? $value : null; // Empty value should return null.
if ( ! $customer_object ) {
$customer_object = WC()->customer;
}
if ( is_callable( array( $customer_object, "get_$input" ) ) ) {
$value = $customer_object->{"get_$input"}();
} elseif ( $customer_object->meta_exists( $input ) ) {
$value = $customer_object->get_meta( $input, true );
}
if ( '' === $value ) {
$value = null;
}
return apply_filters( 'default_checkout_' . $input, $value, $input );
}

View File

@ -146,7 +146,7 @@ class WC_Comments {
*/
public static function check_comment_rating( $comment_data ) {
// If posting a comment (not trackback etc) and not logged in.
if ( ! is_admin() && isset( $_POST['comment_post_ID'], $_POST['rating'], $comment_data['comment_type'] ) && 'product' === get_post_type( absint( $_POST['comment_post_ID'] ) ) && empty( $_POST['rating'] ) && '' === $comment_data['comment_type'] && 'yes' === get_option( 'woocommerce_enable_review_rating' ) && 'yes' === get_option( 'woocommerce_review_rating_required' ) ) { // WPCS: input var ok, CSRF ok.
if ( ! is_admin() && isset( $_POST['comment_post_ID'], $_POST['rating'], $comment_data['comment_type'] ) && 'product' === get_post_type( absint( $_POST['comment_post_ID'] ) ) && empty( $_POST['rating'] ) && '' === $comment_data['comment_type'] && wc_review_ratings_enabled() && wc_review_ratings_required() ) { // WPCS: input var ok, CSRF ok.
wp_die( esc_html__( 'Please rate the product.', 'woocommerce' ) );
exit;
}
@ -240,7 +240,8 @@ class WC_Comments {
FROM {$wpdb->comments}
WHERE comment_type NOT IN ('order_note', 'webhook_delivery')
GROUP BY comment_approved
", ARRAY_A
",
ARRAY_A
);
$approved = array(
@ -327,7 +328,8 @@ class WC_Comments {
AND comment_post_ID = %d
AND comment_approved = '1'
AND meta_value > 0
", $product->get_id()
",
$product->get_id()
)
);
$average = number_format( $ratings / $count, 2, '.', '' );
@ -360,7 +362,8 @@ class WC_Comments {
WHERE comment_parent = 0
AND comment_post_ID = %d
AND comment_approved = '1'
", $product->get_id()
",
$product->get_id()
)
);
@ -393,7 +396,8 @@ class WC_Comments {
AND comment_approved = '1'
AND meta_value > 0
GROUP BY meta_value
", $product->get_id()
",
$product->get_id()
)
);

View File

@ -50,7 +50,7 @@ class WC_Countries {
if ( empty( $this->countries ) ) {
$this->countries = apply_filters( 'woocommerce_countries', include WC()->plugin_path() . '/i18n/countries.php' );
if ( apply_filters( 'woocommerce_sort_countries', true ) ) {
asort( $this->countries );
uasort( $this->countries, 'wc_ascii_uasort_comparison' );
}
}
@ -74,7 +74,7 @@ class WC_Countries {
* Get continent code for a country code.
*
* @since 2.6.0
* @param string $cc Continent code.
* @param string $cc Country code.
* @return string
*/
public function get_continent_code_for_country( $cc ) {
@ -90,62 +90,36 @@ class WC_Countries {
return '';
}
/**
* Get continents that the store ships to.
*
* @since 3.6.0
* @return array
*/
public function get_shipping_continents() {
$continents = $this->get_continents();
$shipping_countries = $this->get_shipping_countries();
$shipping_country_codes = array_keys( $shipping_countries );
$shipping_continents = array();
foreach ( $continents as $continent_code => $continent ) {
if ( count( array_intersect( $continent['countries'], $shipping_country_codes ) ) ) {
$shipping_continents[ $continent_code ] = $continent;
}
}
return $shipping_continents;
}
/**
* Load the states.
*
* @deprecated 3.6.0 This method was used to load state files, but is no longer needed. @see get_states().
*/
public function load_country_states() {
global $states;
// States set to array() are blank i.e. the country has no use for the state field.
$states = array(
'AF' => array(),
'AT' => array(),
'AX' => array(),
'BE' => array(),
'BH' => array(),
'BI' => array(),
'CZ' => array(),
'DE' => array(),
'DK' => array(),
'EE' => array(),
'FI' => array(),
'FR' => array(),
'GP' => array(),
'GF' => array(),
'IS' => array(),
'IL' => array(),
'IM' => array(),
'KR' => array(),
'KW' => array(),
'LB' => array(),
'LU' => array(),
'MQ' => array(),
'MT' => array(),
'NL' => array(),
'NO' => array(),
'PL' => array(),
'PT' => array(),
'RE' => array(),
'SG' => array(),
'SK' => array(),
'SI' => array(),
'LK' => array(),
'SE' => array(),
'VN' => array(),
'YT' => array(),
);
// Load only the state files the shop owner wants/needs.
$allowed = array_merge( $this->get_allowed_countries(), $this->get_shipping_countries() );
if ( ! empty( $allowed ) ) {
foreach ( $allowed as $code => $country ) {
if ( ! isset( $states[ $code ] ) && file_exists( WC()->plugin_path() . '/i18n/states/' . $code . '.php' ) ) {
include WC()->plugin_path() . '/i18n/states/' . $code . '.php';
}
}
}
$states = include WC()->plugin_path() . '/i18n/states.php';
$this->states = apply_filters( 'woocommerce_states', $states );
}
@ -156,8 +130,8 @@ class WC_Countries {
* @return false|array of states
*/
public function get_states( $cc = null ) {
if ( empty( $this->states ) ) {
$this->load_country_states();
if ( ! isset( $this->states ) ) {
$this->states = apply_filters( 'woocommerce_states', include WC()->plugin_path() . '/i18n/states.php' );
}
if ( ! is_null( $cc ) ) {
@ -232,7 +206,7 @@ class WC_Countries {
}
/**
* Get the allowed countries for the store.
* Get countries that the store sells to.
*
* @return array
*/
@ -269,7 +243,7 @@ class WC_Countries {
}
/**
* Get the countries you ship to.
* Get countries that the store ships to.
*
* @return array
*/
@ -434,7 +408,7 @@ class WC_Countries {
*
* @param string $selected_country Selected country.
* @param string $selected_state Selected state.
* @param bool $escape If should escape HTML.
* @param bool $escape If we should escape HTML.
*/
public function country_dropdown_options( $selected_country = '', $selected_state = '', $escape = false ) {
if ( $this->countries ) {
@ -762,7 +736,7 @@ class WC_Countries {
'required' => false,
'hidden' => true,
),
'state' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
@ -1004,6 +978,12 @@ class WC_Countries {
'required' => false,
),
),
'LV' => array(
'state' => array(
'label' => __( 'Municipality', 'woocommerce' ),
'required' => false,
),
),
'LB' => array(
'state' => array(
'required' => false,

View File

@ -137,7 +137,8 @@ class WC_Customer extends WC_Legacy_Customer {
public function delete_and_reassign( $reassign = null ) {
if ( $this->data_store ) {
$this->data_store->delete(
$this, array(
$this,
array(
'force_delete' => true,
'reassign' => $reassign,
)
@ -817,12 +818,16 @@ class WC_Customer extends WC_Legacy_Customer {
* @param string $city City.
*/
public function set_billing_location( $country, $state = '', $postcode = '', $city = '' ) {
$billing = $this->get_prop( 'billing', 'edit' );
$billing['country'] = $country;
$billing['state'] = $state;
$billing['postcode'] = $postcode;
$billing['city'] = $city;
$this->set_prop( 'billing', $billing );
$address_data = $this->get_prop( 'billing', 'edit' );
$address_data['address_1'] = '';
$address_data['address_2'] = '';
$address_data['city'] = $city;
$address_data['state'] = $state;
$address_data['postcode'] = $postcode;
$address_data['country'] = $country;
$this->set_prop( 'billing', $address_data );
}
/**
@ -834,12 +839,16 @@ class WC_Customer extends WC_Legacy_Customer {
* @param string $city City.
*/
public function set_shipping_location( $country, $state = '', $postcode = '', $city = '' ) {
$shipping = $this->get_prop( 'shipping', 'edit' );
$shipping['country'] = $country;
$shipping['state'] = $state;
$shipping['postcode'] = $postcode;
$shipping['city'] = $city;
$this->set_prop( 'shipping', $shipping );
$address_data = $this->get_prop( 'shipping', 'edit' );
$address_data['address_1'] = '';
$address_data['address_2'] = '';
$address_data['city'] = $city;
$address_data['state'] = $state;
$address_data['postcode'] = $postcode;
$address_data['country'] = $country;
$this->set_prop( 'shipping', $address_data );
}
/**

View File

@ -56,21 +56,8 @@ class WC_Deprecated_Filter_Hooks extends WC_Deprecated_Hooks {
'default_checkout_billing_postcode' => 'default_checkout_postcode',
'woocommerce_system_status_environment_rows' => 'woocommerce_debug_posting',
'woocommerce_credit_card_type_labels' => 'wocommerce_credit_card_type_labels',
'woocommerce_get_script_data' => array(
'woocommerce_params',
'wc_geolocation_params',
'wc_single_product_params',
'wc_checkout_params',
'wc_address_i18n_params',
'wc_cart_params',
'wc_cart_fragments_params',
'wc_add_to_cart_params',
'wc_add_to_cart_variation_params',
'wc_country_select_params',
'wc_password_strength_meter_params',
),
'woocommerce_settings_tabs_advanced' => 'woocommerce_settings_tabs_api',
'woocommerce_settings_advanced' => 'woocommerce_settings_api',
'woocommerce_settings_tabs_advanced' => 'woocommerce_settings_tabs_api',
'woocommerce_settings_advanced' => 'woocommerce_settings_api',
);
/**

View File

@ -519,8 +519,9 @@ class WC_Discounts {
$apply_quantity = max( 0, apply_filters( 'woocommerce_coupon_get_apply_quantity', $apply_quantity, $item, $coupon, $this ) );
// Run coupon calculations.
$discount = wc_add_number_precision( $coupon->get_discount_amount( $price_to_discount / $item->quantity, $item->object, true ) ) * $apply_quantity;
$discount = wc_round_discount( min( $discounted_price, $discount ), 0 );
$discount = wc_add_number_precision( $coupon->get_discount_amount( $price_to_discount / $item->quantity, $item->object, true ) ) * $apply_quantity;
$discount = wc_round_discount( min( $discounted_price, $discount ), 0 );
$applied_count = $applied_count + $apply_quantity;
// Store code and discount amount per item.
$this->discounts[ $coupon->get_code() ][ $item->key ] += $discount;
@ -664,6 +665,7 @@ class WC_Discounts {
*/
protected function validate_coupon_minimum_amount( $coupon ) {
$subtotal = wc_remove_number_precision( $this->get_object_subtotal() );
if ( $coupon->get_minimum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_minimum_amount', $coupon->get_minimum_amount() > $subtotal, $coupon, $subtotal ) ) {
/* translators: %s: coupon minimum amount */
throw new Exception( sprintf( __( 'The minimum spend for this coupon is %s.', 'woocommerce' ), wc_price( $coupon->get_minimum_amount() ) ), 108 );
@ -682,6 +684,7 @@ class WC_Discounts {
*/
protected function validate_coupon_maximum_amount( $coupon ) {
$subtotal = wc_remove_number_precision( $this->get_object_subtotal() );
if ( $coupon->get_maximum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_maximum_amount', $coupon->get_maximum_amount() < $subtotal, $coupon ) ) {
/* translators: %s: coupon maximum amount */
throw new Exception( sprintf( __( 'The maximum spend for this coupon is %s.', 'woocommerce' ), wc_price( $coupon->get_maximum_amount() ) ), 112 );
@ -906,7 +909,8 @@ class WC_Discounts {
if ( is_a( $this->object, 'WC_Cart' ) ) {
return wc_add_number_precision( $this->object->get_displayed_subtotal() );
} elseif ( is_a( $this->object, 'WC_Order' ) ) {
return wc_add_number_precision( $this->object->get_subtotal() );
$subtotal = wc_add_number_precision( $this->object->get_subtotal() );
return $this->object->get_prices_include_tax() ? $subtotal + round( $this->object->get_total_tax(), wc_get_price_decimals() ) : $subtotal;
} else {
return array_sum( wp_list_pluck( $this->items, 'price' ) );
}
@ -963,9 +967,13 @@ class WC_Discounts {
*/
$message = apply_filters( 'woocommerce_coupon_error', is_numeric( $e->getMessage() ) ? $coupon->get_coupon_error( $e->getMessage() ) : $e->getMessage(), $e->getCode(), $coupon );
return new WP_Error( 'invalid_coupon', $message, array(
'status' => 400,
) );
return new WP_Error(
'invalid_coupon',
$message,
array(
'status' => 400,
)
);
}
return true;
}

View File

@ -2,8 +2,7 @@
/**
* Handle frontend forms.
*
* @version 2.2.0
* @package WooCommerce/Classes/
* @package WooCommerce/Classes/
*/
defined( 'ABSPATH' ) || exit;
@ -40,17 +39,17 @@ class WC_Form_Handler {
* Remove key and user ID (or user login, as a fallback) from query string, set cookie, and redirect to account page to show the form.
*/
public static function redirect_reset_password_link() {
if ( is_account_page() && isset( $_GET['key'] ) && ( isset( $_GET['id'] ) || isset( $_GET['login'] ) ) ) {
if ( is_account_page() && isset( $_GET['key'] ) && ( isset( $_GET['id'] ) || isset( $_GET['login'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
// If available, get $user_login from query string parameter for fallback purposes.
if ( isset( $_GET['login'] ) ) {
$user_login = $_GET['login'];
// If available, get $user_id from query string parameter for fallback purposes.
if ( isset( $_GET['login'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$user = get_user_by( 'login', sanitize_user( wp_unslash( $_GET['login'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$user_id = $user ? $user->ID : 0;
} else {
$user = get_user_by( 'id', absint( $_GET['id'] ) );
$user_login = $user ? $user->user_login : '';
$user_id = absint( $_GET['id'] );
}
$value = sprintf( '%s:%s', wp_unslash( $user_login ), wp_unslash( $_GET['key'] ) );
$value = sprintf( '%d:%s', $user_id, wp_unslash( $_GET['key'] ) ); // phpcs:ignore
WC_Shortcode_My_Account::set_reset_password_cookie( $value );
wp_safe_redirect( add_query_arg( 'show-reset-form', 'true', wc_lostpassword_url() ) );
exit;
@ -64,7 +63,9 @@ class WC_Form_Handler {
public static function save_address() {
global $wp;
if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
$nonce_value = wc_get_var( $_REQUEST['woocommerce-edit-address-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-edit_address' ) ) {
return;
}
@ -74,12 +75,6 @@ class WC_Form_Handler {
wc_nocache_headers();
$nonce_value = wc_get_var( $_REQUEST['woocommerce-edit-address-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-edit_address' ) ) {
return;
}
$user_id = get_current_user_id();
if ( $user_id <= 0 ) {
@ -88,56 +83,59 @@ class WC_Form_Handler {
$load_address = isset( $wp->query_vars['edit-address'] ) ? wc_edit_address_i18n( sanitize_title( $wp->query_vars['edit-address'] ), true ) : 'billing';
$address = WC()->countries->get_address_fields( esc_attr( $_POST[ $load_address . '_country' ] ), $load_address . '_' );
if ( ! isset( $_POST[ $load_address . '_country' ] ) ) {
return;
}
$address = WC()->countries->get_address_fields( wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) ), $load_address . '_' );
foreach ( $address as $key => $field ) {
if ( ! isset( $field['type'] ) ) {
$field['type'] = 'text';
}
// Get Value.
switch ( $field['type'] ) {
case 'checkbox' :
$_POST[ $key ] = (int) isset( $_POST[ $key ] );
break;
default :
$_POST[ $key ] = isset( $_POST[ $key ] ) ? wc_clean( $_POST[ $key ] ) : '';
break;
if ( 'checkbox' === $field['type'] ) {
$value = (int) isset( $_POST[ $key ] );
} else {
$value = isset( $_POST[ $key ] ) ? wc_clean( wp_unslash( $_POST[ $key ] ) ) : '';
}
// Hook to allow modification of value.
$_POST[ $key ] = apply_filters( 'woocommerce_process_myaccount_field_' . $key, $_POST[ $key ] );
$value = apply_filters( 'woocommerce_process_myaccount_field_' . $key, $value );
// Validation: Required fields.
if ( ! empty( $field['required'] ) && empty( $_POST[ $key ] ) ) {
if ( ! empty( $field['required'] ) && empty( $value ) ) {
/* translators: %s: Field name. */
wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), $field['label'] ), 'error' );
}
if ( ! empty( $_POST[ $key ] ) ) {
if ( ! empty( $value ) ) {
// Validation rules.
if ( ! empty( $field['validate'] ) && is_array( $field['validate'] ) ) {
foreach ( $field['validate'] as $rule ) {
switch ( $rule ) {
case 'postcode' :
$_POST[ $key ] = strtoupper( str_replace( ' ', '', $_POST[ $key ] ) );
case 'postcode':
$value = strtoupper( str_replace( ' ', '', $value ) );
if ( ! WC_Validation::is_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] ) ) {
if ( ! WC_Validation::is_postcode( $value, wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) ) ) ) {
wc_add_notice( __( 'Please enter a valid postcode / ZIP.', 'woocommerce' ), 'error' );
} else {
$_POST[ $key ] = wc_format_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] );
$value = wc_format_postcode( $value, wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) ) );
}
break;
case 'phone' :
if ( ! WC_Validation::is_phone( $_POST[ $key ] ) ) {
case 'phone':
if ( ! WC_Validation::is_phone( $value ) ) {
/* translators: %s: Phone number. */
wc_add_notice( sprintf( __( '%s is not a valid phone number.', 'woocommerce' ), '<strong>' . $field['label'] . '</strong>' ), 'error' );
}
break;
case 'email' :
$_POST[ $key ] = strtolower( $_POST[ $key ] );
case 'email':
$value = strtolower( $value );
if ( ! is_email( $_POST[ $key ] ) ) {
if ( ! is_email( $value ) ) {
/* translators: %s: Email address. */
wc_add_notice( sprintf( __( '%s is not a valid email address.', 'woocommerce' ), '<strong>' . $field['label'] . '</strong>' ), 'error' );
}
break;
@ -156,13 +154,13 @@ class WC_Form_Handler {
if ( $customer ) {
foreach ( $address as $key => $field ) {
if ( is_callable( array( $customer, "set_$key" ) ) ) {
$customer->{"set_$key"}( wc_clean( $_POST[ $key ] ) );
$customer->{"set_$key"}( $value );
} else {
$customer->update_meta_data( $key, wc_clean( $_POST[ $key ] ) );
$customer->update_meta_data( $key, $value );
}
if ( WC()->customer && is_callable( array( WC()->customer, "set_$key" ) ) ) {
WC()->customer->{"set_$key"}( wc_clean( $_POST[ $key ] ) );
WC()->customer->{"set_$key"}( $value );
}
}
$customer->save();
@ -181,7 +179,9 @@ class WC_Form_Handler {
* Save the password/account details and redirect back to the my account page.
*/
public static function save_account_details() {
if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
$nonce_value = wc_get_var( $_REQUEST['save-account-details-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce( $nonce_value, 'save_account_details' ) ) {
return;
}
@ -191,25 +191,19 @@ class WC_Form_Handler {
wc_nocache_headers();
$nonce_value = wc_get_var( $_REQUEST['save-account-details-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce( $nonce_value, 'save_account_details' ) ) {
return;
}
$user_id = get_current_user_id();
if ( $user_id <= 0 ) {
return;
}
$account_first_name = ! empty( $_POST['account_first_name'] ) ? wc_clean( $_POST['account_first_name'] ): '';
$account_last_name = ! empty( $_POST['account_last_name'] ) ? wc_clean( $_POST['account_last_name'] ) : '';
$account_display_name = ! empty( $_POST['account_display_name'] ) ? wc_clean( $_POST['account_display_name'] ) : '';
$account_email = ! empty( $_POST['account_email'] ) ? wc_clean( $_POST['account_email'] ) : '';
$pass_cur = ! empty( $_POST['password_current'] ) ? $_POST['password_current'] : '';
$pass1 = ! empty( $_POST['password_1'] ) ? $_POST['password_1'] : '';
$pass2 = ! empty( $_POST['password_2'] ) ? $_POST['password_2'] : '';
$account_first_name = ! empty( $_POST['account_first_name'] ) ? wc_clean( wp_unslash( $_POST['account_first_name'] ) ) : '';
$account_last_name = ! empty( $_POST['account_last_name'] ) ? wc_clean( wp_unslash( $_POST['account_last_name'] ) ) : '';
$account_display_name = ! empty( $_POST['account_display_name'] ) ? wc_clean( wp_unslash( $_POST['account_display_name'] ) ) : '';
$account_email = ! empty( $_POST['account_email'] ) ? wc_clean( wp_unslash( $_POST['account_email'] ) ) : '';
$pass_cur = ! empty( $_POST['password_current'] ) ? wp_unslash( $_POST['password_current'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$pass1 = ! empty( $_POST['password_1'] ) ? wp_unslash( $_POST['password_1'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$pass2 = ! empty( $_POST['password_2'] ) ? wp_unslash( $_POST['password_2'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$save_pass = true;
// Current user data.
@ -219,11 +213,11 @@ class WC_Form_Handler {
$current_email = $current_user->user_email;
// New user data.
$user = new stdClass();
$user->ID = $user_id;
$user->first_name = $account_first_name;
$user->last_name = $account_last_name;
$user->display_name = $account_display_name;
$user = new stdClass();
$user->ID = $user_id;
$user->first_name = $account_first_name;
$user->last_name = $account_last_name;
$user->display_name = $account_display_name;
// Prevent display name to be changed to email.
if ( is_email( $account_display_name ) ) {
@ -231,15 +225,19 @@ class WC_Form_Handler {
}
// Handle required fields.
$required_fields = apply_filters( 'woocommerce_save_account_details_required_fields', array(
'account_first_name' => __( 'First name', 'woocommerce' ),
'account_last_name' => __( 'Last name', 'woocommerce' ),
'account_display_name' => __( 'Display name', 'woocommerce' ),
'account_email' => __( 'Email address', 'woocommerce' ),
) );
$required_fields = apply_filters(
'woocommerce_save_account_details_required_fields',
array(
'account_first_name' => __( 'First name', 'woocommerce' ),
'account_last_name' => __( 'Last name', 'woocommerce' ),
'account_display_name' => __( 'Display name', 'woocommerce' ),
'account_email' => __( 'Email address', 'woocommerce' ),
)
);
foreach ( $required_fields as $field_key => $field_name ) {
if ( empty( $_POST[ $field_key ] ) ) {
/* translators: %s: Field name. */
wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), '<strong>' . esc_html( $field_name ) . '</strong>' ), 'error' );
}
}
@ -321,11 +319,11 @@ class WC_Form_Handler {
* Process the checkout form.
*/
public static function checkout_action() {
if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) {
if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
wc_nocache_headers();
if ( WC()->cart->is_empty() ) {
wp_redirect( wc_get_page_permalink( 'cart' ) );
wp_safe_redirect( wc_get_page_permalink( 'cart' ) );
exit;
}
@ -341,7 +339,7 @@ class WC_Form_Handler {
public static function pay_action() {
global $wp;
if ( isset( $_POST['woocommerce_pay'] ) ) {
if ( isset( $_POST['woocommerce_pay'], $_GET['key'] ) ) {
wc_nocache_headers();
$nonce_value = wc_get_var( $_REQUEST['woocommerce-pay-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
@ -352,32 +350,33 @@ class WC_Form_Handler {
ob_start();
// Pay for existing order
$order_key = $_GET['key'];
$order_id = absint( $wp->query_vars['order-pay'] );
$order = wc_get_order( $order_id );
// Pay for existing order.
$order_key = wp_unslash( $_GET['key'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order_id = absint( $wp->query_vars['order-pay'] );
$order = wc_get_order( $order_id );
if ( $order_id === $order->get_id() && $order_key === $order->get_order_key() && $order->needs_payment() ) {
if ( $order_id === $order->get_id() && hash_equals( $order->get_order_key(), $order_key ) && $order->needs_payment() ) {
do_action( 'woocommerce_before_pay_action', $order );
WC()->customer->set_props( array(
'billing_country' => $order->get_billing_country() ? $order->get_billing_country() : null,
'billing_state' => $order->get_billing_state() ? $order->get_billing_state() : null,
'billing_postcode' => $order->get_billing_postcode() ? $order->get_billing_postcode() : null,
'billing_city' => $order->get_billing_city() ? $order->get_billing_city() : null,
) );
WC()->customer->set_props(
array(
'billing_country' => $order->get_billing_country() ? $order->get_billing_country() : null,
'billing_state' => $order->get_billing_state() ? $order->get_billing_state() : null,
'billing_postcode' => $order->get_billing_postcode() ? $order->get_billing_postcode() : null,
'billing_city' => $order->get_billing_city() ? $order->get_billing_city() : null,
)
);
WC()->customer->save();
// Terms
if ( ! empty( $_POST['terms-field'] ) && empty( $_POST['terms'] ) ) {
wc_add_notice( __( 'Please read and accept the terms and conditions to proceed with your order.', 'woocommerce' ), 'error' );
return;
}
// Update payment method
// Update payment method.
if ( $order->needs_payment() ) {
$payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : false;
$payment_method = isset( $_POST['payment_method'] ) ? wc_clean( wp_unslash( $_POST['payment_method'] ) ) : false;
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
if ( ! $payment_method ) {
@ -385,7 +384,6 @@ class WC_Form_Handler {
return;
}
// Update meta
update_post_meta( $order_id, '_payment_method', $payment_method );
if ( isset( $available_gateways[ $payment_method ] ) ) {
@ -396,22 +394,20 @@ class WC_Form_Handler {
update_post_meta( $order_id, '_payment_method_title', $payment_method_title );
// Validate
$available_gateways[ $payment_method ]->validate_fields();
// Process
if ( 0 === wc_notice_count( 'error' ) ) {
$result = $available_gateways[ $payment_method ]->process_payment( $order_id );
// Redirect to success/confirmation/payment page
// Redirect to success/confirmation/payment page.
if ( 'success' === $result['result'] ) {
wp_redirect( $result['redirect'] );
wp_redirect( $result['redirect'] ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
exit;
}
}
} else {
// No payment was required for order
// No payment was required for order.
$order->payment_complete();
wp_safe_redirect( $order->get_checkout_order_received_url() );
exit;
@ -466,7 +462,7 @@ class WC_Form_Handler {
}
if ( ! empty( $result['redirect'] ) ) {
wp_redirect( $result['redirect'] );
wp_redirect( $result['redirect'] ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
exit();
}
}
@ -485,14 +481,14 @@ class WC_Form_Handler {
$token_id = absint( $wp->query_vars['delete-payment-method'] );
$token = WC_Payment_Tokens::get( $token_id );
if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || false === wp_verify_nonce( $_REQUEST['_wpnonce'], 'delete-payment-method-' . $token_id ) ) {
if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || ! isset( $_REQUEST['_wpnonce'] ) || false === wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'delete-payment-method-' . $token_id ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' );
} else {
WC_Payment_Tokens::delete( $token_id );
wc_add_notice( __( 'Payment method deleted.', 'woocommerce' ) );
}
wp_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
wp_safe_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
exit();
}
@ -510,14 +506,14 @@ class WC_Form_Handler {
$token_id = absint( $wp->query_vars['set-default-payment-method'] );
$token = WC_Payment_Tokens::get( $token_id );
if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || false === wp_verify_nonce( $_REQUEST['_wpnonce'], 'set-default-payment-method-' . $token_id ) ) {
if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || ! isset( $_REQUEST['_wpnonce'] ) || false === wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'set-default-payment-method-' . $token_id ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' );
} else {
WC_Payment_Tokens::set_users_default( $token->get_user_id(), intval( $token_id ) );
wc_add_notice( __( 'This payment method was successfully set as your default.', 'woocommerce' ) );
}
wp_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
wp_safe_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
exit();
}
@ -536,10 +532,10 @@ class WC_Form_Handler {
$nonce_value = wc_get_var( $_REQUEST['woocommerce-cart-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! empty( $_POST['apply_coupon'] ) && ! empty( $_POST['coupon_code'] ) ) {
WC()->cart->add_discount( sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) );
WC()->cart->add_discount( sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
} elseif ( isset( $_GET['remove_coupon'] ) ) {
WC()->cart->remove_coupon( wc_clean( wp_unslash( $_GET['remove_coupon'] ) ) );
WC()->cart->remove_coupon( wc_clean( wp_unslash( $_GET['remove_coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
} elseif ( ! empty( $_GET['remove_item'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-cart' ) ) {
$cart_item_key = sanitize_text_field( wp_unslash( $_GET['remove_item'] ) );
@ -550,6 +546,7 @@ class WC_Form_Handler {
$product = wc_get_product( $cart_item['product_id'] );
/* translators: %s: Item name. */
$item_removed_title = apply_filters( 'woocommerce_cart_item_removed_title', $product ? sprintf( _x( '&ldquo;%s&rdquo;', 'Item name in quotes', 'woocommerce' ), $product->get_name() ) : __( 'Item', 'woocommerce' ), $cart_item );
// Don't show undo link if removed item is out of stock.
@ -565,7 +562,7 @@ class WC_Form_Handler {
wc_add_notice( $removed_notice );
}
$referer = wp_get_referer() ? remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart', 'order_again', '_wpnonce' ), add_query_arg( 'removed_item', '1', wp_get_referer() ) ) : wc_get_cart_url();
$referer = wp_get_referer() ? remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart', 'order_again', '_wpnonce' ), add_query_arg( 'removed_item', '1', wp_get_referer() ) ) : wc_get_cart_url();
wp_safe_redirect( $referer );
exit;
@ -576,7 +573,7 @@ class WC_Form_Handler {
WC()->cart->restore_cart_item( $cart_item_key );
$referer = wp_get_referer() ? remove_query_arg( array( 'undo_item', '_wpnonce' ), wp_get_referer() ) : wc_get_cart_url();
$referer = wp_get_referer() ? remove_query_arg( array( 'undo_item', '_wpnonce' ), wp_get_referer() ) : wc_get_cart_url();
wp_safe_redirect( $referer );
exit;
@ -658,26 +655,23 @@ class WC_Form_Handler {
isset( $_GET['cancel_order'] ) &&
isset( $_GET['order'] ) &&
isset( $_GET['order_id'] ) &&
( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cancel_order' ) )
( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'woocommerce-cancel_order' ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
) {
wc_nocache_headers();
$order_key = $_GET['order'];
$order_key = wp_unslash( $_GET['order'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order_id = absint( $_GET['order_id'] );
$order = wc_get_order( $order_id );
$user_can_cancel = current_user_can( 'cancel_order', $order_id );
$order_can_cancel = $order->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_cancel', array( 'pending', 'failed' ) ) );
$redirect = $_GET['redirect'];
$redirect = isset( $_GET['redirect'] ) ? wp_unslash( $_GET['redirect'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( $order->has_status( 'cancelled' ) ) {
// Already cancelled - take no action
} elseif ( $user_can_cancel && $order_can_cancel && $order->get_id() === $order_id && $order->get_order_key() === $order_key ) {
if ( $user_can_cancel && $order_can_cancel && $order->get_id() === $order_id && hash_equals( $order->get_order_key(), $order_key ) ) {
// Cancel the order + restore stock
// Cancel the order + restore stock.
WC()->session->set( 'order_awaiting_payment', false );
$order->update_status( 'cancelled', __( 'Order cancelled by customer.', 'woocommerce' ) );
// Message
wc_add_notice( apply_filters( 'woocommerce_order_cancelled_notice', __( 'Your order was cancelled.', 'woocommerce' ) ), apply_filters( 'woocommerce_order_cancelled_notice_type', 'notice' ) );
do_action( 'woocommerce_cancelled_order', $order->get_id() );
@ -700,18 +694,18 @@ class WC_Form_Handler {
*
* Checks for a valid request, does validation (via hooks) and then redirects if valid.
*
* @param bool $url (default: false)
* @param bool $url (default: false) URL to redirect to.
*/
public static function add_to_cart_action( $url = false ) {
if ( empty( $_REQUEST['add-to-cart'] ) || ! is_numeric( $_REQUEST['add-to-cart'] ) ) {
if ( ! isset( $_REQUEST['add-to-cart'] ) || ! is_numeric( wp_unslash( $_REQUEST['add-to-cart'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
return;
}
wc_nocache_headers();
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( wp_unslash( $_REQUEST['add-to-cart'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
return;
@ -731,7 +725,9 @@ class WC_Form_Handler {
// If we added the product to the cart we can now optionally do a redirect.
if ( $was_added_to_cart && 0 === wc_notice_count( 'error' ) ) {
if ( $url = apply_filters( 'woocommerce_add_to_cart_redirect', $url, $adding_to_cart ) ) {
$url = apply_filters( 'woocommerce_add_to_cart_redirect', $url, $adding_to_cart );
if ( $url ) {
wp_safe_redirect( $url );
exit;
} elseif ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
@ -749,8 +745,8 @@ class WC_Form_Handler {
* @return bool success or not
*/
private static function add_to_cart_handler_simple( $product_id ) {
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
@ -769,24 +765,25 @@ class WC_Form_Handler {
private static function add_to_cart_handler_grouped( $product_id ) {
$was_added_to_cart = false;
$added_to_cart = array();
$items = isset( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ? wp_unslash( $_REQUEST['quantity'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! empty( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ) {
if ( ! empty( $items ) ) {
$quantity_set = false;
foreach ( $_REQUEST['quantity'] as $item => $quantity ) {
foreach ( $items as $item => $quantity ) {
if ( $quantity <= 0 ) {
continue;
}
$quantity_set = true;
// Add to cart validation
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity );
// Add to cart validation.
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity );
// Suppress total recalculation until finished.
remove_action( 'woocommerce_add_to_cart', array( WC()->cart, 'calculate_totals' ), 20, 0 );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $item, $quantity ) ) {
$was_added_to_cart = true;
$was_added_to_cart = true;
$added_to_cart[ $item ] = $quantity;
}
@ -811,13 +808,14 @@ class WC_Form_Handler {
* Handle adding variable products to the cart.
*
* @since 2.4.6 Split from add_to_cart_action.
* @throws Exception If add to cart fails.
* @param int $product_id Product ID to add to the cart.
* @return bool success or not
*/
private static function add_to_cart_handler_variable( $product_id ) {
try {
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // WPCS: sanitization ok.
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$missing_attributes = array();
$variations = array();
$adding_to_cart = wc_get_product( $product_id );
@ -846,12 +844,12 @@ class WC_Form_Handler {
}
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
if ( isset( $_REQUEST[ $attribute_key ] ) ) {
if ( isset( $_REQUEST[ $attribute_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( $attribute['is_taxonomy'] ) {
// Don't use wc_clean as it destroys sanitized characters.
$value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) );
$value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
} else {
$value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // WPCS: sanitization ok.
$value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
}
$posted_attributes[ $attribute_key ] = $value;
@ -879,7 +877,7 @@ class WC_Form_Handler {
// Get valid value from variation data.
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
$valid_value = isset( $variation_data[ $attribute_key ] ) ? $variation_data[ $attribute_key ]: '';
$valid_value = isset( $variation_data[ $attribute_key ] ) ? $variation_data[ $attribute_key ] : '';
/**
* If the attribute value was posted, check if it's valid.
@ -892,10 +890,11 @@ class WC_Form_Handler {
// Allow if valid or show error.
if ( $valid_value === $value ) {
$variations[ $attribute_key ] = $value;
} elseif ( '' === $valid_value && in_array( $value, $attribute->get_slugs() ) ) {
} elseif ( '' === $valid_value && in_array( $value, $attribute->get_slugs(), true ) ) {
// If valid values are empty, this is an 'any' variation so get all possible values.
$variations[ $attribute_key ] = $value;
} else {
/* translators: %s: Attribute name. */
throw new Exception( sprintf( __( 'Invalid value posted for %s', 'woocommerce' ), wc_attribute_label( $attribute['name'] ) ) );
}
} elseif ( '' === $valid_value ) {
@ -903,6 +902,7 @@ class WC_Form_Handler {
}
}
if ( ! empty( $missing_attributes ) ) {
/* translators: %s: Attribute name. */
throw new Exception( sprintf( _n( '%s is a required field', '%s are required fields', count( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ) );
}
} catch ( Exception $e ) {
@ -922,22 +922,24 @@ class WC_Form_Handler {
/**
* Process the login form.
*
* @throws Exception On login error.
*/
public static function process_login() {
// The global form-login.php template used `_wpnonce` in template versions < 3.3.0.
$nonce_value = wc_get_var( $_REQUEST['woocommerce-login-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! empty( $_POST['login'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-login' ) ) {
if ( isset( $_POST['login'], $_POST['username'], $_POST['password'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-login' ) ) {
try {
$creds = array(
'user_login' => trim( $_POST['username'] ),
'user_password' => $_POST['password'],
'remember' => isset( $_POST['rememberme'] ),
'user_login' => trim( wp_unslash( $_POST['username'] ) ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
'user_password' => wp_unslash( $_POST['password'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
'remember' => isset( $_POST['rememberme'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
);
$validation_error = new WP_Error();
$validation_error = apply_filters( 'woocommerce_process_login_errors', $validation_error, $_POST['username'], $_POST['password'] );
$validation_error = apply_filters( 'woocommerce_process_login_errors', $validation_error, $creds['user_login'], $creds['user_password'] );
if ( $validation_error->get_error_code() ) {
throw new Exception( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . $validation_error->get_error_message() );
@ -956,7 +958,7 @@ class WC_Form_Handler {
}
}
// Perform the login
// Perform the login.
$user = wp_signon( apply_filters( 'woocommerce_login_credentials', $creds ), is_ssl() );
if ( is_wp_error( $user ) ) {
@ -966,14 +968,14 @@ class WC_Form_Handler {
} else {
if ( ! empty( $_POST['redirect'] ) ) {
$redirect = $_POST['redirect'];
$redirect = wp_unslash( $_POST['redirect'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
} elseif ( wc_get_raw_referer() ) {
$redirect = wc_get_raw_referer();
} else {
$redirect = wc_get_page_permalink( 'myaccount' );
}
wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_login_redirect', remove_query_arg( 'wc_error', $redirect ), $user ), wc_get_page_permalink( 'myaccount' ) ) );
wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_login_redirect', remove_query_arg( 'wc_error', $redirect ), $user ), wc_get_page_permalink( 'myaccount' ) ) ); // phpcs:ignore
exit;
}
} catch ( Exception $e ) {
@ -998,7 +1000,7 @@ class WC_Form_Handler {
// If successful, redirect to my account with query arg set.
if ( $success ) {
wp_redirect( add_query_arg( 'reset-link-sent', 'true', wc_get_account_endpoint_url( 'lost-password' ) ) );
wp_safe_redirect( add_query_arg( 'reset-link-sent', 'true', wc_get_account_endpoint_url( 'lost-password' ) ) );
exit;
}
}
@ -1008,19 +1010,19 @@ class WC_Form_Handler {
* Handle reset password form.
*/
public static function process_reset_password() {
$nonce_value = wc_get_var( $_REQUEST['woocommerce-reset-password-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce( $nonce_value, 'reset_password' ) ) {
return;
}
$posted_fields = array( 'wc_reset_password', 'password_1', 'password_2', 'reset_key', 'reset_login' );
foreach ( $posted_fields as $field ) {
if ( ! isset( $_POST[ $field ] ) ) {
return;
}
$posted_fields[ $field ] = $_POST[ $field ];
}
$nonce_value = wc_get_var( $_REQUEST['woocommerce-reset-password-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce( $nonce_value, 'reset_password' ) ) {
return;
$posted_fields[ $field ] = wp_unslash( $_POST[ $field ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
}
$user = WC_Shortcode_My_Account::check_password_reset_key( $posted_fields['reset_key'], $posted_fields['reset_login'] );
@ -1045,7 +1047,7 @@ class WC_Form_Handler {
do_action( 'woocommerce_customer_reset_password', $user );
wp_redirect( add_query_arg( 'password-reset', 'true', wc_get_page_permalink( 'myaccount' ) ) );
wp_safe_redirect( add_query_arg( 'password-reset', 'true', wc_get_page_permalink( 'myaccount' ) ) );
exit;
}
}
@ -1053,15 +1055,17 @@ class WC_Form_Handler {
/**
* Process the registration form.
*
* @throws Exception On registration error.
*/
public static function process_registration() {
$nonce_value = isset( $_POST['_wpnonce'] ) ? $_POST['_wpnonce'] : '';
$nonce_value = isset( $_POST['woocommerce-register-nonce'] ) ? $_POST['woocommerce-register-nonce'] : $nonce_value;
$nonce_value = isset( $_POST['_wpnonce'] ) ? wp_unslash( $_POST['_wpnonce'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
$nonce_value = isset( $_POST['woocommerce-register-nonce'] ) ? wp_unslash( $_POST['woocommerce-register-nonce'] ) : $nonce_value; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
if ( ! empty( $_POST['register'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-register' ) ) {
$username = 'no' === get_option( 'woocommerce_registration_generate_username' ) ? $_POST['username'] : '';
$password = 'no' === get_option( 'woocommerce_registration_generate_password' ) ? $_POST['password'] : '';
$email = $_POST['email'];
if ( isset( $_POST['register'], $_POST['email'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-register' ) ) {
$username = 'no' === get_option( 'woocommerce_registration_generate_username' ) && isset( $_POST['username'] ) ? wp_unslash( $_POST['username'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$password = 'no' === get_option( 'woocommerce_registration_generate_password' ) && isset( $_POST['password'] ) ? wp_unslash( $_POST['password'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$email = wp_unslash( $_POST['email'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
try {
$validation_error = new WP_Error();
@ -1077,21 +1081,27 @@ class WC_Form_Handler {
throw new Exception( $new_customer->get_error_message() );
}
if ( 'yes' === get_option( 'woocommerce_registration_generate_password' ) ) {
wc_add_notice( __( 'Your account was created successfully and a password has been sent to your email address.', 'woocommerce' ) );
} else {
wc_add_notice( __( 'Your account was created successfully. Your login details have been sent to your email address.', 'woocommerce' ) );
}
// Only redirect after a forced login - otherwise output a success notice.
if ( apply_filters( 'woocommerce_registration_auth_new_customer', true, $new_customer ) ) {
wc_set_customer_auth_cookie( $new_customer );
if ( ! empty( $_POST['redirect'] ) ) {
$redirect = wp_sanitize_redirect( wp_unslash( $_POST['redirect'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
} elseif ( wc_get_raw_referer() ) {
$redirect = wc_get_raw_referer();
} else {
$redirect = wc_get_page_permalink( 'myaccount' );
}
wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_registration_redirect', $redirect ), wc_get_page_permalink( 'myaccount' ) ) ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
exit;
}
if ( ! empty( $_POST['redirect'] ) ) {
$redirect = wp_sanitize_redirect( $_POST['redirect'] );
} elseif ( wc_get_raw_referer() ) {
$redirect = wc_get_raw_referer();
} else {
$redirect = wc_get_page_permalink( 'myaccount' );
}
wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_registration_redirect', $redirect ), wc_get_page_permalink( 'myaccount' ) ) );
exit;
} catch ( Exception $e ) {
wc_add_notice( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . $e->getMessage(), 'error' );
}

View File

@ -472,7 +472,7 @@ class WC_Frontend_Scripts {
case 'wc-single-product':
$params = array(
'i18n_required_rating_text' => esc_attr__( 'Please select a rating', 'woocommerce' ),
'review_rating_required' => get_option( 'woocommerce_review_rating_required' ),
'review_rating_required' => wc_review_ratings_required() ? 'yes' : 'no',
'flexslider' => apply_filters(
'woocommerce_single_product_carousel_options',
array(
@ -536,10 +536,11 @@ class WC_Frontend_Scripts {
break;
case 'wc-cart-fragments':
$params = array(
'ajax_url' => WC()->ajax_url(),
'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
'cart_hash_key' => apply_filters( 'woocommerce_cart_hash_key', 'wc_cart_hash_' . md5( get_current_blog_id() . '_' . get_site_url( get_current_blog_id(), '/' ) . get_template() ) ),
'fragment_name' => apply_filters( 'woocommerce_cart_fragment_name', 'wc_fragments_' . md5( get_current_blog_id() . '_' . get_site_url( get_current_blog_id(), '/' ) . get_template() ) ),
'ajax_url' => WC()->ajax_url(),
'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
'cart_hash_key' => apply_filters( 'woocommerce_cart_hash_key', 'wc_cart_hash_' . md5( get_current_blog_id() . '_' . get_site_url( get_current_blog_id(), '/' ) . get_template() ) ),
'fragment_name' => apply_filters( 'woocommerce_cart_fragment_name', 'wc_fragments_' . md5( get_current_blog_id() . '_' . get_site_url( get_current_blog_id(), '/' ) . get_template() ) ),
'request_timeout' => 5000,
);
break;
case 'wc-add-to-cart':
@ -590,6 +591,8 @@ class WC_Frontend_Scripts {
$params = false;
}
$params = apply_filters_deprecated( $handle . '_params', array( $params ), '3.0.0', 'woocommerce_get_script_data' );
return apply_filters( 'woocommerce_get_script_data', $params, $handle );
}

View File

@ -148,7 +148,7 @@ class WC_Geolocation {
/**
* Get user IP Address using an external service.
* This is used mainly as a fallback for users on localhost where
* This can be used as a fallback for users on localhost where
* get_ip_address() will be a local IP and non-geolocatable.
*
* @return string
@ -191,7 +191,7 @@ class WC_Geolocation {
* @param bool $api_fallback If true, uses geolocation APIs if the database file doesn't exist (can be slower).
* @return array
*/
public static function geolocate_ip( $ip_address = '', $fallback = true, $api_fallback = true ) {
public static function geolocate_ip( $ip_address = '', $fallback = false, $api_fallback = true ) {
// Filter to allow custom geolocation of the IP address.
$country_code = apply_filters( 'woocommerce_geolocate_ip', false, $ip_address, $fallback, $api_fallback );

View File

@ -120,6 +120,10 @@ class WC_Install {
'3.5.2' => array(
'wc_update_352_drop_download_log_fk',
),
'3.5.4' => array(
'wc_update_354_modify_shop_manager_caps',
'wc_update_354_db_version',
),
);
/**
@ -418,17 +422,17 @@ class WC_Install {
'cart' => array(
'name' => _x( 'cart', 'Page slug', 'woocommerce' ),
'title' => _x( 'Cart', 'Page title', 'woocommerce' ),
'content' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
'content' => '<!-- wp:shortcode -->[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']<!-- /wp:shortcode -->',
),
'checkout' => array(
'name' => _x( 'checkout', 'Page slug', 'woocommerce' ),
'title' => _x( 'Checkout', 'Page title', 'woocommerce' ),
'content' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
'content' => '<!-- wp:shortcode -->[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']<!-- /wp:shortcode -->',
),
'myaccount' => array(
'name' => _x( 'my-account', 'Page slug', 'woocommerce' ),
'title' => _x( 'My account', 'Page title', 'woocommerce' ),
'content' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
'content' => '<!-- wp:shortcode -->[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']<!-- /wp:shortcode -->',
),
)
);
@ -955,7 +959,6 @@ CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
'read' => true,
'read_private_pages' => true,
'read_private_posts' => true,
'edit_users' => true,
'edit_posts' => true,
'edit_pages' => true,
'edit_published_posts' => true,
@ -1127,16 +1130,17 @@ CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
private static function create_placeholder_image() {
$placeholder_image = get_option( 'woocommerce_placeholder_image', 0 );
if ( ! is_numeric( $placeholder_image ) ) {
return;
}
if ( ! empty( $placeholder_image ) && is_numeric( $placeholder_image ) && wp_attachment_is_image( $placeholder_image ) ) {
return;
// Validate current setting if set. If set, return.
if ( ! empty( $placeholder_image ) ) {
if ( ! is_numeric( $placeholder_image ) ) {
return;
} elseif ( $placeholder_image && wp_attachment_is_image( $placeholder_image ) ) {
return;
}
}
$upload_dir = wp_upload_dir();
$source = WC()->plugin_path() . '/assets/images/placeholder.png';
$source = WC()->plugin_path() . '/assets/images/placeholder-attachment.png';
$filename = $upload_dir['basedir'] . '/woocommerce-placeholder.png';
if ( ! file_exists( $filename ) ) {

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