Merge branch 'master' of github.com:woocommerce/woocommerce into exclude-products-from-coupon-validation

This commit is contained in:
Kathy Darling 2018-02-23 22:09:06 -06:00
commit d494daf3cd
139 changed files with 2958 additions and 1918 deletions

View File

@ -6,7 +6,7 @@ When contributing please ensure you follow the guidelines below to help us keep
__Please Note:__
GitHub is for _bug reports and contributions only_ - if you have a support question or a request for a customization this is not the right place to post it. Use [WooCommerce Support](https://support.woocommerce.com) for customer support, [WordPress.org](https://wordpress.org/support/plugin/woocommerce) for community support, and for customizations we recommend one of the following services:
GitHub is for _bug reports and contributions only_ - if you have a support question or a request for a customization this is not the right place to post it. Use [WooCommerce Support](https://woocommerce.com/contact-us/) for customer support, [WordPress.org](https://wordpress.org/support/plugin/woocommerce) for community support, and for customizations we recommend one of the following services:
- [WooExperts](https://woocommerce.com/experts/)
- [Codeable](https://codeable.io/)

View File

@ -1,24 +1,22 @@
<!-- Hi there! This form is for reporting bugs and issues specific to the WooCommerce plugin. This is not a support portal. If you need technical support from a human being, please submit a ticket via the helpdesk instead: https://woocommerce.com/contact-us/ -->
<!-- This form is for reporting bugs and issues specific to the WooCommerce plugin. This is not a support portal. If you need technical support from a human being, please submit a ticket via the helpdesk instead: https://woocommerce.com/contact-us/ -->
<!-- Usage questions can also be directed to the public support forum here: https://wordpress.org/support/plugin/woocommerce, unless this is a question about a premium extension in which case you should use the helpdesk. -->
<!-- If you have a feature request, submit it to: http://ideas.woocommerce.com/forums/133476-woocommerce -->
<!-- If you are a developer who needs a new filter/hook raise a PR instead :) -->
<!-- Please be as descriptive as possible; issues lacking the below details, or for any other reason than to report a bug, may be closed without action. -->
## Prerequisites
<!-- Mark completed items with an [x] -->
<!-- MARK COMPLETED ITEMS WITH AN [x] -->
- [ ] I have searched for similar issues in both open and closed tickets and cannot find a duplicate
- [ ] The issue still exists against the latest `master` branch of WooCommerce on Github (this is **not** the same version as on WordPress.org!)
- [ ] I have attempted to find the simplest possible steps to reproduce the issue
- [ ] I have included a failing test as a pull request (Optional)
## Steps to reproduce the issue
<!-- We need to be able to reproduce the bug in order to fix it so please be descriptive! -->
@ -27,26 +25,20 @@
2.
3.
## Expected/actual behavior
When I follow those steps, I see...
I was expecting to see...
## Isolating the problem
<!-- Mark completed items with an [x] -->
<!-- MARK COMPLETED ITEMS WITH AN [x] -->
- [ ] This bug happens with only WooCommerce plugin active
- [ ] This bug happens with a default WordPress theme active, or [Storefront](https://woocommerce.com/storefront/)
- [ ] I can reproduce this bug consistently using the steps above
## WordPress Environment
<details>

View File

@ -1,5 +1,77 @@
== Changelog ==
= 3.3.3 - 2018-02-21 =
* Fix - Fixed is_numeric check which was affecting order subtotals/totals when using comma decimal separator.
* Fix - Add missing direct script access checks to loop templates.
* Fix - Added wp-post-image class to main image so variation images are swapped correctly.
* Fix - API - Adjusted schema for products shipping_class_id to integer.
* Fix - Made init tooltips event more specific to avoid conflict with Product Invoices extension.
= 3.3.2 - 2018-02-20 =
* Fix - Fixed admin product SKU searching and searching non-published products.
* Fix - PHP7.1 notice when image height is empty.
* Fix - Prevent repeated update_option calls on page load due to php type juggling.
* Fix - Only do unsupported template rendering in the loop to prevent conflicts with other shortcodes on the shop page.
* Fix - Don't prepend regular shortcodes with categories.
* Fix - If using get_catalog_ordering_args. remove the args when finished.
* Fix - Remove "Type" column on attributes table by default unless custom types are defined.
* Fix - Use verbose page rules when shop is in the URL, including shop base with category, to prevent 404s.
* Fix - Set woocommerce_hide_invisible_variations to true so disabled variation attributes are hidden on product pages.
* Fix - Help tip for webhook status.
* Fix - Shipping zone documentation help link was printing wrong.
* Fix - Stop background processing images when disabled via the filter.
* Fix - Only search when a search term is provided. Ignore empty strings.
* Fix - Fix check for external resources.
* Fix - Show full date for future orders.
* Fix - Prevent JS error is 'orders' row is disabled on order screen.
* Fix - Fix save of tax settings when no changes have been made.
* Fix - Add nonce to logout link on my account page so you do not need to confirm the action.
* Fix - Fix plain text entity replacement so currency symbols are included.
* Fix - API - Set status after order is created/updated so triggered emails are current.
* Fix - API - Fix single webhook endpoint.
* Tweak - Added help text for background image processing.
* Tweak - Added notice when background image processing is running, with cancel button.
* Tweak - Run background image processing less often by tracking changes.
* Tweak - Added system status tool to run background image processing manually.
* Tweak - If using Jetpack Photon, use that instead of background image processing.
* Tweak - Gallery thumbnail image size to handle small, square cropped images.
* Tweak - Helper function (and template version bump for image templates) to render gallery images.
* Tweak - Add help text for the default category to explain usage.
* Tweak - Allow changing the default product category.
* Tweak - Tweak mobile view of order preview to improve layout in non-english.
* Tweak - If selecting text, don't link to order on row click.
* Localization - Remove isle of man state.
= 3.3.1 - 2018-02-06 =
* Fix - Added `woocommerce_output_product_categories` to replace `woocommerce_product_subcategories` function to prevent outdated theme template files from outputting categories on the shop and category pages in err.
* Fix - Prevented columns from being set to anything lower than 1.
* Fix - Added extra error checking in Webhooks API to prevent notices when deleting Webhooks.
* Fix - Prevented list table classes being loaded multiple times. This also fixes compatibility with Smart Coupons extension.
* Fix - Removed stray debug string from order email template and fixed some typos.
* Fix - Set up the loop when calling wc_get_loop_prop. Fixes compatibility with some themes.
* Fix - Remove multiple application of filter 'woocommerce_order_item_product'.
* Fix - Protect against theme support being defined too late. Fixes some issues with custom themes defining WooCommerce support incorrectly.
* Fix - Add fallback for themes that just get the pagination template.
* Fix - Made the on-the-fly image regen also regenerate missing sizes.
* Fix - Fixed missing user_id in webhook migration script.
* Fix - Allow uncategorized category to be sorted like the others.
* Fix - If theme support changes, we may need to flush permalinks since some are changed based on this flag.
* Fix - Fire hooks for pagination etc only when pagination is enabled.
* Fix - Default HTML in end wrapper template.
* Fix - Prevent regular pagination showing on archives for unsupported themes.
* Fix - Fix shop when shown as homepage in unsupported themes.
* Fix - Fix SKU mapping for placeholders during CSV import.
* Fix - Use CRUD search helper in admin products table so partial SKU search works.
* Fix - Fix bulk sale/regular price percentage handling.
* Fix - More specificity on smallscreen style override for columns.
* Tweak - Add notice for moved store notice setting.
* Tweak - Allow removing coupons on editable orders only.
* Tweak - Extended the background processing library to avoid changing methods in the library.
* Tweak - Do not show row settings if something is managing the number of products per page.
* Tweak - Allow devs to add 'no-link' class to elements to prevent order view link being triggered on row click.
* Tweak - Made woocommerce_resize_images filter more useful by calling it later.
* Tweak - Revert default columns back to 4 so it's consistent with 3.2.
= 3.3.0 - 2018-01-30 =
* Feature - Improved default appearance in themes which do not support WooCommerce, making the shop page shortcode based.
* Feature - Products shortcodes; improved random sorting, with some caching.

View File

@ -1 +1 @@
div.woocommerce-message{overflow:hidden;position:relative;border-right-color:#cc99c2!important}div.woocommerce-message p{max-width:700px}.woocommerce-message .button-primary,p.woocommerce-actions .button-primary{background:#bb77ae;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;color:#fff;text-shadow:0 -1px 1px #a36597,-1px 0 1px #a36597,0 1px 1px #a36597,1px 0 1px #a36597}.woocommerce-message .button-primary:active,.woocommerce-message .button-primary:focus,.woocommerce-message .button-primary:hover,p.woocommerce-actions .button-primary:active,p.woocommerce-actions .button-primary:focus,p.woocommerce-actions .button-primary:hover{background:#a36597;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597}.woocommerce-message a.woocommerce-message-close,p.woocommerce-actions a.woocommerce-message-close{position:absolute;top:0;left:0;padding:10px 21px 10px 15px;font-size:13px;line-height:1.23076923;text-decoration:none}.woocommerce-message a.woocommerce-message-close::before,p.woocommerce-actions a.woocommerce-message-close::before{position:absolute;top:8px;right:0;-webkit-transition:all .1s ease-in-out;transition:all .1s ease-in-out}.woocommerce-message .button-primary,.woocommerce-message .button-secondary,p.woocommerce-actions .button-primary,p.woocommerce-actions .button-secondary{text-decoration:none!important}.woocommerce-message .twitter-share-button,p.woocommerce-actions .twitter-share-button{margin-top:-3px;margin-right:3px;vertical-align:middle}.woocommerce-about-text,p.woocommerce-actions{margin-bottom:1em!important}div.woocommerce-legacy-shipping-notice,div.woocommerce-no-shipping-methods-notice{overflow:hidden;padding:1px 12px}div.woocommerce-legacy-shipping-notice p,div.woocommerce-no-shipping-methods-notice p{position:relative;z-index:1;max-width:700px;line-height:1.5em;margin:12px 0}div.woocommerce-legacy-shipping-notice p.main,div.woocommerce-no-shipping-methods-notice p.main{font-size:1.1em}div.woocommerce-legacy-shipping-notice::before,div.woocommerce-no-shipping-methods-notice::before{content:'\e01b';font-family:WooCommerce;text-align:center;line-height:1;color:#f7f1f6;display:block;width:1em;font-size:20em;top:36px;left:12px;position:absolute}
div.woocommerce-message{overflow:hidden;position:relative;border-right-color:#cc99c2!important}div.woocommerce-message p{max-width:700px}div.woocommerce-message p:last-child{max-width:inherit}.woocommerce-message .button-primary,p.woocommerce-actions .button-primary{background:#bb77ae;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;color:#fff;text-shadow:0 -1px 1px #a36597,-1px 0 1px #a36597,0 1px 1px #a36597,1px 0 1px #a36597}.woocommerce-message .button-primary:active,.woocommerce-message .button-primary:focus,.woocommerce-message .button-primary:hover,p.woocommerce-actions .button-primary:active,p.woocommerce-actions .button-primary:focus,p.woocommerce-actions .button-primary:hover{background:#a36597;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597}.woocommerce-message a.woocommerce-message-close,p.woocommerce-actions a.woocommerce-message-close{position:absolute;top:0;left:0;padding:10px 21px 10px 15px;font-size:13px;line-height:1.23076923;text-decoration:none}.woocommerce-message a.woocommerce-message-close::before,p.woocommerce-actions a.woocommerce-message-close::before{position:absolute;top:8px;right:0;-webkit-transition:all .1s ease-in-out;transition:all .1s ease-in-out}.woocommerce-message .button-primary,.woocommerce-message .button-secondary,p.woocommerce-actions .button-primary,p.woocommerce-actions .button-secondary{text-decoration:none!important}.woocommerce-message .twitter-share-button,p.woocommerce-actions .twitter-share-button{margin-top:-3px;margin-right:3px;vertical-align:middle}.woocommerce-about-text,p.woocommerce-actions{margin-bottom:1em!important}div.woocommerce-legacy-shipping-notice,div.woocommerce-no-shipping-methods-notice{overflow:hidden;padding:1px 12px}div.woocommerce-legacy-shipping-notice p,div.woocommerce-no-shipping-methods-notice p{position:relative;z-index:1;max-width:700px;line-height:1.5em;margin:12px 0}div.woocommerce-legacy-shipping-notice p.main,div.woocommerce-no-shipping-methods-notice p.main{font-size:1.1em}div.woocommerce-legacy-shipping-notice::before,div.woocommerce-no-shipping-methods-notice::before{content:'\e01b';font-family:WooCommerce;text-align:center;line-height:1;color:#f7f1f6;display:block;width:1em;font-size:20em;top:36px;left:12px;position:absolute}

View File

@ -1 +1 @@
div.woocommerce-message{overflow:hidden;position:relative;border-left-color:#cc99c2!important}div.woocommerce-message p{max-width:700px}.woocommerce-message .button-primary,p.woocommerce-actions .button-primary{background:#bb77ae;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;color:#fff;text-shadow:0 -1px 1px #a36597,1px 0 1px #a36597,0 1px 1px #a36597,-1px 0 1px #a36597}.woocommerce-message .button-primary:active,.woocommerce-message .button-primary:focus,.woocommerce-message .button-primary:hover,p.woocommerce-actions .button-primary:active,p.woocommerce-actions .button-primary:focus,p.woocommerce-actions .button-primary:hover{background:#a36597;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597}.woocommerce-message a.woocommerce-message-close,p.woocommerce-actions a.woocommerce-message-close{position:absolute;top:0;right:0;padding:10px 15px 10px 21px;font-size:13px;line-height:1.23076923;text-decoration:none}.woocommerce-message a.woocommerce-message-close::before,p.woocommerce-actions a.woocommerce-message-close::before{position:absolute;top:8px;left:0;-webkit-transition:all .1s ease-in-out;transition:all .1s ease-in-out}.woocommerce-message .button-primary,.woocommerce-message .button-secondary,p.woocommerce-actions .button-primary,p.woocommerce-actions .button-secondary{text-decoration:none!important}.woocommerce-message .twitter-share-button,p.woocommerce-actions .twitter-share-button{margin-top:-3px;margin-left:3px;vertical-align:middle}.woocommerce-about-text,p.woocommerce-actions{margin-bottom:1em!important}div.woocommerce-legacy-shipping-notice,div.woocommerce-no-shipping-methods-notice{overflow:hidden;padding:1px 12px}div.woocommerce-legacy-shipping-notice p,div.woocommerce-no-shipping-methods-notice p{position:relative;z-index:1;max-width:700px;line-height:1.5em;margin:12px 0}div.woocommerce-legacy-shipping-notice p.main,div.woocommerce-no-shipping-methods-notice p.main{font-size:1.1em}div.woocommerce-legacy-shipping-notice::before,div.woocommerce-no-shipping-methods-notice::before{content:'\e01b';font-family:WooCommerce;text-align:center;line-height:1;color:#f7f1f6;display:block;width:1em;font-size:20em;top:36px;right:12px;position:absolute}
div.woocommerce-message{overflow:hidden;position:relative;border-left-color:#cc99c2!important}div.woocommerce-message p{max-width:700px}div.woocommerce-message p:last-child{max-width:inherit}.woocommerce-message .button-primary,p.woocommerce-actions .button-primary{background:#bb77ae;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;color:#fff;text-shadow:0 -1px 1px #a36597,1px 0 1px #a36597,0 1px 1px #a36597,-1px 0 1px #a36597}.woocommerce-message .button-primary:active,.woocommerce-message .button-primary:focus,.woocommerce-message .button-primary:hover,p.woocommerce-actions .button-primary:active,p.woocommerce-actions .button-primary:focus,p.woocommerce-actions .button-primary:hover{background:#a36597;border-color:#a36597;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597;box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 0 #a36597}.woocommerce-message a.woocommerce-message-close,p.woocommerce-actions a.woocommerce-message-close{position:absolute;top:0;right:0;padding:10px 15px 10px 21px;font-size:13px;line-height:1.23076923;text-decoration:none}.woocommerce-message a.woocommerce-message-close::before,p.woocommerce-actions a.woocommerce-message-close::before{position:absolute;top:8px;left:0;-webkit-transition:all .1s ease-in-out;transition:all .1s ease-in-out}.woocommerce-message .button-primary,.woocommerce-message .button-secondary,p.woocommerce-actions .button-primary,p.woocommerce-actions .button-secondary{text-decoration:none!important}.woocommerce-message .twitter-share-button,p.woocommerce-actions .twitter-share-button{margin-top:-3px;margin-left:3px;vertical-align:middle}.woocommerce-about-text,p.woocommerce-actions{margin-bottom:1em!important}div.woocommerce-legacy-shipping-notice,div.woocommerce-no-shipping-methods-notice{overflow:hidden;padding:1px 12px}div.woocommerce-legacy-shipping-notice p,div.woocommerce-no-shipping-methods-notice p{position:relative;z-index:1;max-width:700px;line-height:1.5em;margin:12px 0}div.woocommerce-legacy-shipping-notice p.main,div.woocommerce-no-shipping-methods-notice p.main{font-size:1.1em}div.woocommerce-legacy-shipping-notice::before,div.woocommerce-no-shipping-methods-notice::before{content:'\e01b';font-family:WooCommerce;text-align:center;line-height:1;color:#f7f1f6;display:block;width:1em;font-size:20em;top:36px;right:12px;position:absolute}

View File

@ -13,6 +13,9 @@ div.woocommerce-message {
p {
max-width: 700px;
}
p:last-child {
max-width: inherit;
}
}
p.woocommerce-actions,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -692,6 +692,16 @@ table.wc_status_table--tools {
}
}
.taxonomy-product_cat {
.column-thumb .woocommerce-help-tip {
font-size: 1.5em;
margin: 0 0 0 -34px;
padding: 0px 2px 5px;
display: block;
position: absolute;
}
}
#debug-report {
display: none;
margin: 10px 0;
@ -903,8 +913,7 @@ ul.wc_coupon_list {
&.code {
display: inline-block;
position: relative;
padding-right: 2em;
padding-left: .5em;
padding: 0 .5em;
background-color: #fff;
border: 1px solid #aaa;
-webkit-box-shadow: 0 1px 0 #dfdfdf;
@ -914,6 +923,10 @@ ul.wc_coupon_list {
margin-right: 5px;
margin-top: 5px;
&.editable {
padding-right: 2em;
}
.tips {
cursor: pointer;
@ -1976,6 +1989,7 @@ ul.wc_coupon_list_block {
}
a.link::after {
font-family: 'WooCommerce';
content: '\e00d';
}
@ -2194,7 +2208,6 @@ ul.wc_coupon_list_block {
.wc-order-preview-table {
width: 100%;
margin: 0;
border-bottom: 1px solid #ccc;
th, td {
padding: 1em 1.5em;
text-align: left;
@ -2233,11 +2246,14 @@ ul.wc_coupon_list_block {
}
}
.wc-order-preview-addresses {
overflow:hidden;
.wc-order-preview-address {
overflow: hidden;
padding-bottom: 1.5em;
.wc-order-preview-address,
.wc-order-preview-note {
width: 50%;
float: left;
padding: 1.5em;
padding: 1.5em 1.5em 0;
box-sizing: border-box;
word-wrap: break-word;
@ -2246,22 +2262,28 @@ ul.wc_coupon_list_block {
}
strong {
display: block;
margin-top: 1em;
margin-top: 1.5em;
}
strong:first-child {
margin-top: 0;
}
}
}
.wc-action-button,
.wc-action-button-group {
float: left;
margin-right: 4px;
}
}
@media screen and (max-width: 782px) {
.wc-action-button-group {
label {
display: none;
footer {
.wc-action-button-group {
display: inline-block;
float: left;
}
.button.button-large {
margin-left: 10px;
padding: 0 10px !important;
line-height: 28px;
height: auto;
display: inline-block;
}
}
.wc-action-button-group label {
display: none;
}
}
@ -2269,28 +2291,34 @@ ul.wc_coupon_list_block {
vertical-align: middle;
line-height: 26px;
text-align: left;
margin-bottom: 4px;
label {
margin-right: 6px;
cursor: default;
font-weight: bold;
line-height: 28px;
}
.wc-action-button-group__items {
white-space: nowrap;
display: inline-flex;
flex-flow: row wrap;
align-content: flex-start;
justify-content: flex-start;
}
.wc-action-button {
margin: 0 0 0 -1px !important;
border: 1px solid #ccc;
padding: 1px 10px !important;
padding: 0 10px !important;
border-radius: 0 !important;
float: none;
line-height: 28px;
height: auto;
z-index: 1;
position:relative;
max-width: 175px;
overflow: hidden;
text-overflow: ellipsis;
flex: 1 0 auto;
box-sizing: border-box;
text-align: center;
white-space: nowrap;
}
.wc-action-button:hover,
.wc-action-button:focus {
@ -2307,6 +2335,25 @@ ul.wc_coupon_list_block {
border-bottom-right-radius: 3px !important;
}
}
@media screen and (max-width: 782px) {
.wc-order-preview footer {
.wc-action-button-group .wc-action-button-group__items {
display: flex;
}
.wc-action-button-group {
float: none;
display: block;
margin-bottom: 4px;
}
.button.button-large {
width: 100%;
float: none;
text-align: center;
margin: 0;
display: block;
}
}
}
.column-customer_message .note-on {
@include ir();
@ -5698,7 +5745,8 @@ table.bar_chart {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 500px;
max-width: 100%;
min-width: 500px;
article {
overflow: auto;
}
@ -5922,7 +5970,7 @@ table.bar_chart {
}
.select2-container {
float: left;
width: 200px !important;
width: 240px !important;
font-size: 14px;
vertical-align: middle;
margin: 1px 6px 4px 1px;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -639,6 +639,8 @@ body {
// Toggle display a list of services.
.wc-wizard-services-list-toggle {
cursor: pointer;
.wc-wizard-service-enable::before {
content: "\f343"; // up chevron
font-family: "dashicons";
@ -658,7 +660,6 @@ body {
.wc-wizard-service-enable input {
visibility: hidden;
position: relative;
cursor: pointer;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -98,18 +98,16 @@
/**
* Products
*/
&, &[class*='columns-'] {
ul.products {
li.product {
width: 48%;
float: left;
clear: both;
margin: 0 0 2.992em;
ul.products[class*='columns-'] {
li.product {
width: 48%;
float: left;
clear: both;
margin: 0 0 2.992em;
&:nth-child( 2n ) {
float: right;
clear: none !important; // This should never clear.
}
&:nth-child( 2n ) {
float: right;
clear: none !important; // This should never clear.
}
}
}

View File

@ -882,7 +882,7 @@ jQuery( function ( $ ) {
var index = $items.find('tr').length + 1;
var $row = '<tr data-meta_id="0">' +
'<td>' +
'<input type="text" placeholder="' + woocommerce_admin_meta_boxes_order.placeholder_name + '" name="meta_key[' + $item.attr( 'data-order_item_id' ) + '][new-' + index + ']" />' +
'<input type="text" maxlength="255" placeholder="' + woocommerce_admin_meta_boxes_order.placeholder_name + '" name="meta_key[' + $item.attr( 'data-order_item_id' ) + '][new-' + index + ']" />' +
'<textarea placeholder="' + woocommerce_admin_meta_boxes_order.placeholder_value + '" name="meta_value[' + $item.attr( 'data-order_item_id' ) + '][new-' + index + ']"></textarea>' +
'</td>' +
'<td width="1%"><button class="remove_order_item_meta button">&times;</button></td>' +
@ -918,9 +918,10 @@ jQuery( function ( $ ) {
}
var $rows = $table.find( 'tr.selected' );
var $bulk_edit_wraper = $( 'div.wc-order-item-bulk-edit' );
if ( $rows.length ) {
$( 'div.wc-order-item-bulk-edit' ).slideDown();
if ( $rows.length && $bulk_edit_wraper.children().length > 0 ) {
$bulk_edit_wraper.slideDown();
var selected_product = false;
@ -1006,10 +1007,18 @@ jQuery( function ( $ ) {
}
},
do_increase_stock: function( e ) {
modify_stock: function( e, action ) {
e.preventDefault();
wc_meta_boxes_order_items.block();
$( '#woocommerce-order-notes' ).block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
var $table = $( 'table.woocommerce_order_items' );
var $rows = $table.find( 'tr.selected' );
var quantities = {};
@ -1027,7 +1036,7 @@ jQuery( function ( $ ) {
order_id: woocommerce_admin_meta_boxes.post_id,
order_item_ids: item_ids,
order_item_qty: quantities,
action: 'woocommerce_increase_order_item_stock',
action: action,
security: woocommerce_admin_meta_boxes.order_item_nonce
};
@ -1036,46 +1045,42 @@ jQuery( function ( $ ) {
data: data,
type: 'POST',
success: function( response ) {
window.alert( response );
wc_meta_boxes_order_items.unblock();
if ( true === response.success ) {
$.map( response.data, function( item ) {
// No items were updated.
if ( ! item.success ) {
window.alert( item.note );
return;
}
var order_note_data = {
action: 'woocommerce_add_order_note',
post_id: woocommerce_admin_meta_boxes.post_id,
note: item.note,
note_type: '',
security: woocommerce_admin_meta_boxes.add_order_note_nonce
};
$.post( woocommerce_admin_meta_boxes.ajax_url, order_note_data, function( response ) {
$( 'ul.order_notes' ).prepend( response );
});
});
}
$( '#woocommerce-order-notes' ).unblock();
}
});
},
do_increase_stock: function( e ) {
wc_meta_boxes_order_items.bulk_actions.modify_stock( e, 'woocommerce_increase_order_item_stock' );
},
do_reduce_stock: function( e ) {
e.preventDefault();
wc_meta_boxes_order_items.block();
var $table = $( 'table.woocommerce_order_items' );
var $rows = $table.find( 'tr.selected' );
var quantities = {};
var item_ids = $.map( $rows, function( $row ) {
return parseInt( $( $row ).data( 'order_item_id' ), 10 );
});
$rows.each(function() {
if ( $( this ).find( 'input.quantity' ).length ) {
quantities[ $( this ).attr( 'data-order_item_id' ) ] = $( this ).find( 'input.quantity' ).val();
}
});
var data = {
order_id: woocommerce_admin_meta_boxes.post_id,
order_item_ids: item_ids,
order_item_qty: quantities,
action: 'woocommerce_reduce_order_item_stock',
security: woocommerce_admin_meta_boxes.order_item_nonce
};
$.ajax({
url: woocommerce_admin_meta_boxes.ajax_url,
data: data,
type: 'POST',
success: function( response ) {
window.alert( response );
wc_meta_boxes_order_items.unblock();
}
});
wc_meta_boxes_order_items.bulk_actions.modify_stock( e, 'woocommerce_reduce_order_item_stock' );
}
},

View File

@ -17,7 +17,7 @@
paginationTemplate = wp.template( 'wc-tax-table-pagination' ),
$table = $( '.wc_tax_rates' ),
$tbody = $( '#rates' ),
$save_button = $( 'input[name="save"]' ),
$save_button = $( ':input[name="save"]' ),
$pagination = $( '#rates-pagination' ),
$search_field = $( '#rates-search .wc-tax-rates-search-field' ),
$submit = $( '.submit .button-primary[type=submit]' ),
@ -91,7 +91,7 @@
changes: self.changes
},
success: function( response, textStatus ) {
if ( 'success' === textStatus ) {
if ( 'success' === textStatus && response.success ) {
WCTaxTableModelInstance.set( 'rates', response.data.rates );
WCTaxTableModelInstance.trigger( 'change:rates' );
@ -125,7 +125,7 @@
$pagination.on( 'change', 'input', { view: this }, this.onPageChange );
$( window ).on( 'beforeunload', { view: this }, this.unloadConfirmation );
$submit.on( 'click', { view: this }, this.onSubmit );
$save_button.attr( 'disabled','disabled' );
$save_button.prop( 'disabled', true );
// Can bind these directly to the buttons, as they won't get overwritten.
$table.find( '.insert' ).on( 'click', { view: this }, this.onAddNewRow );
@ -319,11 +319,11 @@
},
setUnloadConfirmation: function() {
this.needsUnloadConfirm = true;
$save_button.removeAttr( 'disabled' );
$save_button.prop( 'disabled', false );
},
clearUnloadConfirmation: function() {
this.needsUnloadConfirm = false;
$save_button.attr( 'disabled', 'disabled' );
$save_button.prop( 'disabled', true );
},
unloadConfirmation: function( event ) {
if ( event.data.view.needsUnloadConfirm ) {

View File

@ -15,6 +15,13 @@ jQuery( function( $ ) {
$( table_selector ).find( '.column-handle' ).show();
$( document ).ajaxComplete( function( event, request, options ) {
if ( request && 4 === request.readyState && 200 === request.status && options.data && 0 <= options.data.indexOf( '_inline_edit' ) ) {
$( table_selector ).find( '.column-handle' ).show();
$( document.body ).trigger( 'init_tooltips' );
}
} );
$( table_selector ).sortable({
items: item_selector,
cursor: 'move',

View File

@ -1 +1 @@
jQuery(function(e){var t='.column-handle input[name="term_id"]';0===e("table.wp-list-table").find(".column-handle").length&&(e("table.wp-list-table").find("tr:not(.inline-edit-row)").append('<td class="column-handle"></td>'),t=".check-column input"),e("table.wp-list-table").find(".column-handle").show(),e("table.wp-list-table").sortable({items:"tbody tr:not(.inline-edit-row)",cursor:"move",handle:".column-handle",axis:"y",forcePlaceholderSize:!0,helper:"clone",opacity:.65,placeholder:"product-cat-placeholder",scrollSensitivity:40,start:function(e,t){t.item.hasClass("alternate")||t.item.css("background-color","#ffffff"),t.item.children("td, th").css("border-bottom-width","0"),t.item.css("outline","1px solid #aaa")},stop:function(e,t){t.item.removeAttr("style"),t.item.children("td, th").css("border-bottom-width","1px")},update:function(n,i){var l,d,a=i.item.find(t).val(),o=i.item.find(".parent").html(),r=i.item.prev().find(t).val(),c=i.item.next().find(t).val();r!==undefined&&(l=i.item.prev().find(".parent").html())!==o&&(r=undefined),c!==undefined&&(d=i.item.next().find(".parent").html())!==o&&(c=undefined),r===undefined&&c===undefined||c===undefined&&d===r||c!==undefined&&l===a?e("table.wp-list-table").sortable("cancel"):(i.item.find(".check-column input").hide(),i.item.find(".check-column").append('<img alt="processing" src="images/wpspin_light.gif" class="waiting" style="margin-left: 6px;" />'),e.post(ajaxurl,{action:"woocommerce_term_ordering",id:a,nextid:c,thetaxonomy:woocommerce_term_ordering_params.taxonomy},function(e){"children"===e?window.location.reload():(i.item.find(".check-column input").show(),i.item.find(".check-column").find("img").remove())}),e("table.widefat tbody tr").each(function(){jQuery("table.widefat tbody tr").index(this)%2==0?jQuery(this).addClass("alternate"):jQuery(this).removeClass("alternate")}))}})});
jQuery(function(e){var t="table.wp-list-table",n='.column-handle input[name="term_id"]';0===e(t).find(".column-handle").length&&(e(t).find("tr:not(.inline-edit-row)").append('<td class="column-handle"></td>'),n=".check-column input"),e(t).find(".column-handle").show(),e(document).ajaxComplete(function(){e(t).find(".column-handle").show()}),e(t).sortable({items:"tbody tr:not(.inline-edit-row)",cursor:"move",handle:".column-handle",axis:"y",forcePlaceholderSize:!0,helper:"clone",opacity:.65,placeholder:"product-cat-placeholder",scrollSensitivity:40,start:function(e,t){t.item.hasClass("alternate")||t.item.css("background-color","#ffffff"),t.item.children("td, th").css("border-bottom-width","0"),t.item.css("outline","1px solid #aaa")},stop:function(e,t){t.item.removeAttr("style"),t.item.children("td, th").css("border-bottom-width","1px")},update:function(i,d){var o,a,l=d.item.find(n).val(),c=d.item.find(".parent").html(),r=d.item.prev().find(n).val(),m=d.item.next().find(n).val();r!==undefined&&(o=d.item.prev().find(".parent").html())!==c&&(r=undefined),m!==undefined&&(a=d.item.next().find(".parent").html())!==c&&(m=undefined),r===undefined&&m===undefined||m===undefined&&a===r||m!==undefined&&o===l?e(t).sortable("cancel"):(d.item.find(".check-column input").hide(),d.item.find(".check-column").append('<img alt="processing" src="images/wpspin_light.gif" class="waiting" style="margin-left: 6px;" />'),e.post(ajaxurl,{action:"woocommerce_term_ordering",id:l,nextid:m,thetaxonomy:woocommerce_term_ordering_params.taxonomy},function(e){"children"===e?window.location.reload():(d.item.find(".check-column input").show(),d.item.find(".check-column").find("img").remove())}),e("table.widefat tbody tr").each(function(){jQuery("table.widefat tbody tr").index(this)%2==0?jQuery(this).addClass("alternate"):jQuery(this).removeClass("alternate")}))}})});

View File

@ -22,10 +22,14 @@ jQuery( function( $ ) {
return true;
}
if ( window.getSelection && window.getSelection().toString().length ) {
return true;
}
var $row = $( this ).closest( 'tr' ),
href = $row.find( 'a.order-view' ).attr( 'href' );
if ( href.length ) {
if ( href && href.length ) {
e.preventDefault();
if ( e.metaKey || e.ctrlKey ) {

View File

@ -48,7 +48,7 @@ jQuery( function( $ ) {
$checkbox.prop( 'checked', ! $checkbox.prop( 'checked' ) ).change();
} );
$( '.wc-wizard-services-list-toggle' ).on( 'change', '.wc-wizard-service-enable input', function() {
$( '.wc-wizard-services-list-toggle' ).on( 'click', function() {
$( this ).closest( '.wc-wizard-services-list-toggle' ).toggleClass( 'closed' );
$( this ).closest( '.wc-wizard-services' ).find( '.wc-wizard-service-item' )
.slideToggle()

View File

@ -1 +1 @@
jQuery(function(e){function i(){e(".wc-setup-content").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})}function s(){e("form.activate-jetpack").submit()}function t(){wp.ajax.post("setup_wizard_check_jetpack").then(function(e){if(!e||!e.is_active||"yes"===e.is_active)return s();setTimeout(t,3e3)}).fail(function(){s()})}e(".button-next").on("click",function(){var s=e(this).parents("form").get(0);return("function"!=typeof s.checkValidity||s.checkValidity())&&i(),!0}),e(".wc-wizard-services").on("change",".wc-wizard-service-enable input",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-toggle").removeClass("disabled"),e(this).closest(".wc-wizard-service-item").addClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").removeClass("hide")):(e(this).closest(".wc-wizard-service-toggle").addClass("disabled"),e(this).closest(".wc-wizard-service-item").removeClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").addClass("hide"))}),e(".wc-wizard-services").on("click",".wc-wizard-service-enable",function(i){if(e(i.target).is("input"))i.stopPropagation();else{var s=e(this).find('input[type="checkbox"]');s.prop("checked",!s.prop("checked")).change()}}),e(".wc-wizard-services-list-toggle").on("change",".wc-wizard-service-enable input",function(){e(this).closest(".wc-wizard-services-list-toggle").toggleClass("closed"),e(this).closest(".wc-wizard-services").find(".wc-wizard-service-item").slideToggle().css("display","flex")}),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-select .method",function(i){var s=e(this).closest(".wc-wizard-service-description"),t=i.target.value,c=s.find(".shipping-method-descriptions");c.find(".shipping-method-description").addClass("hide"),c.find("."+t).removeClass("hide");var r=s.find(".shipping-method-settings");r.find(".shipping-method-setting").addClass("hide").find(".shipping-method-required-field").prop("required",!1),r.find("."+t).removeClass("hide").find(".shipping-method-required-field").prop("required",!0)}).find(".wc-wizard-shipping-method-select .method").change(),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-enable",function(){var i=e(this).is(":checked");e(this).closest(".wc-wizard-service-item").find(".shipping-method-required-field").prop("required",i)}),e(".activate-jetpack").on("click",".button-primary",function(e){if(i(),"no"===wc_setup_params.pending_jetpack_install)return!0;e.preventDefault(),t()}),e(".wc-wizard-services").on("change","input#stripe_create_account, input#ppec_paypal_reroute_requests",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!0),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email, .wc-wizard-service-setting-ppec_paypal_email").show()):(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!1),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email, .wc-wizard-service-setting-ppec_paypal_email").hide())}).find("input#stripe_create_account, input#ppec_paypal_reroute_requests").change(),e("select#store_country_state").on("change",function(){var i=this.value.split(":")[0];e("select#currency_code").val(wc_setup_currencies[i]).change()})});
jQuery(function(e){function i(){e(".wc-setup-content").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})}function s(){e("form.activate-jetpack").submit()}function t(){wp.ajax.post("setup_wizard_check_jetpack").then(function(e){if(!e||!e.is_active||"yes"===e.is_active)return s();setTimeout(t,3e3)}).fail(function(){s()})}e(".button-next").on("click",function(){var s=e(this).parents("form").get(0);return("function"!=typeof s.checkValidity||s.checkValidity())&&i(),!0}),e(".wc-wizard-services").on("change",".wc-wizard-service-enable input",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-toggle").removeClass("disabled"),e(this).closest(".wc-wizard-service-item").addClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").removeClass("hide")):(e(this).closest(".wc-wizard-service-toggle").addClass("disabled"),e(this).closest(".wc-wizard-service-item").removeClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").addClass("hide"))}),e(".wc-wizard-services").on("click",".wc-wizard-service-enable",function(i){if(e(i.target).is("input"))i.stopPropagation();else{var s=e(this).find('input[type="checkbox"]');s.prop("checked",!s.prop("checked")).change()}}),e(".wc-wizard-services-list-toggle").on("click",function(){e(this).closest(".wc-wizard-services-list-toggle").toggleClass("closed"),e(this).closest(".wc-wizard-services").find(".wc-wizard-service-item").slideToggle().css("display","flex")}),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-select .method",function(i){var s=e(this).closest(".wc-wizard-service-description"),t=i.target.value,c=s.find(".shipping-method-descriptions");c.find(".shipping-method-description").addClass("hide"),c.find("."+t).removeClass("hide");var r=s.find(".shipping-method-settings");r.find(".shipping-method-setting").addClass("hide").find(".shipping-method-required-field").prop("required",!1),r.find("."+t).removeClass("hide").find(".shipping-method-required-field").prop("required",!0)}).find(".wc-wizard-shipping-method-select .method").change(),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-enable",function(){var i=e(this).is(":checked");e(this).closest(".wc-wizard-service-item").find(".shipping-method-required-field").prop("required",i)}),e(".activate-jetpack").on("click",".button-primary",function(e){if(i(),"no"===wc_setup_params.pending_jetpack_install)return!0;e.preventDefault(),t()}),e(".wc-wizard-services").on("change","input#stripe_create_account, input#ppec_paypal_reroute_requests",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!0),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email, .wc-wizard-service-setting-ppec_paypal_email").show()):(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!1),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email, .wc-wizard-service-setting-ppec_paypal_email").hide())}).find("input#stripe_create_account, input#ppec_paypal_reroute_requests").change(),e("select#store_country_state").on("change",function(){var i=this.value.split(":")[0];e("select#currency_code").val(wc_setup_currencies[i]).change()})});

View File

@ -134,6 +134,7 @@ jQuery( function ( $ ) {
})
.on( 'init_tooltips', function() {
$( '.tips, .help_tip, .woocommerce-help-tip' ).tipTip( {
'attribute': 'data-tip',
'fadeIn': 50,
@ -281,15 +282,6 @@ jQuery( function ( $ ) {
}).change();
});
// Demo store notice
$( 'input#woocommerce_demo_store' ).change(function() {
if ( $( this ).is( ':checked' ) ) {
$( '#woocommerce_demo_store_notice' ).closest( 'tr' ).show();
} else {
$( '#woocommerce_demo_store_notice' ).closest( 'tr' ).hide();
}
}).change();
// Reviews.
$( 'input#woocommerce_enable_reviews' ).change(function() {
if ( $( this ).is( ':checked' ) ) {

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
/*
* jQuery FlexSlider v2.6.1
* jQuery FlexSlider v2.7.0
* Copyright 2012 WooThemes
* Contributing Author: Tyler Smith
*/
@ -15,15 +15,15 @@
// making variables public
//if rtl value was not passed and html is in rtl..enable it by default.
if(typeof options.rtl=='undefined' && $('html').attr('dir')=='rtl'){
options.rtl=true;
if(typeof options.rtl=='undefined' && $('html').attr('dir')=='rtl'){
options.rtl=true;
}
slider.vars = $.extend({}, $.flexslider.defaults, options);
var namespace = slider.vars.namespace,
msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
touch = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch) && slider.vars.touch,
// depricating this idea, as devices are being released with both of these events
// deprecating this idea, as devices are being released with both of these events
eventType = "click touchend MSPointerUp keyup",
watchedEvent = "",
watchedEventClearTimer,
@ -176,14 +176,14 @@
e.preventDefault();
var $slide = $(this),
target = $slide.index();
var posFromX;
var posFromX;
if(slider.vars.rtl){
posFromX = -1*($slide.offset().right - $(slider).scrollLeft()); // Find position of slide relative to right of slider container
}
else
{
posFromX = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container
}
posFromX = -1*($slide.offset().right - $(slider).scrollLeft()); // Find position of slide relative to right of slider container
}
else
{
posFromX = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container
}
if( posFromX <= 0 && $slide.hasClass( namespace + 'active-slide' ) ) {
slider.flexAnimate(slider.getTarget("prev"), true);
} else if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass(namespace + "active-slide")) {
@ -792,12 +792,8 @@
}
} else { // FADE:
if (!touch) {
//slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing);
//slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing);
slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
} else {
slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 });
slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 });
@ -894,7 +890,7 @@
}
}());
return (posCalc * -1) + "px";
return (posCalc * ((slider.vars.rtl)?1:-1)) + "px";
}());
if (slider.transitions) {
@ -954,7 +950,7 @@
setTimeout(function(){
slider.doMath();
if(slider.vars.rtl){
slider.newSlides.css({"width": slider.computedW, "marginLeft" : slider.computedM, "float": "right", "display": "block"});
slider.newSlides.css({"width": slider.computedW, "marginRight" : slider.computedM, "float": "left", "display": "block"});
}
else{
slider.newSlides.css({"width": slider.computedW, "marginRight" : slider.computedM, "float": "left", "display": "block"});
@ -1143,7 +1139,7 @@
// Usability features
pauseOnAction: true, //Boolean: Pause the slideshow when interacting with control elements, highly recommended.
pauseOnHover: false, //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering
pauseInvisible: true, //{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage.
pauseInvisible: true, //{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage.
useCSS: true, //{NEW} Boolean: Slider will use CSS3 transitions if available
touch: true, //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices
video: false, //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches
@ -1185,7 +1181,7 @@
added: function(){}, //{NEW} Callback: function(slider) - Fires after a slide is added
removed: function(){}, //{NEW} Callback: function(slider) - Fires after a slide is removed
init: function() {}, //{NEW} Callback: function(slider) - Fires after the slider is initially setup
rtl: false //{NEW} Boolean: Whether or not to enable RTL mode
rtl: false //{NEW} Boolean: Whether or not to enable RTL mode
};
//FlexSlider: Plugin Function

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,4 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
include_once( WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-order.php' );
<?php // @codingStandardsIgnoreLine
/**
* Abstract Order
*
@ -14,8 +8,14 @@ include_once( WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-order.php' );
* @class WC_Abstract_Order
* @version 3.0.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
*/
defined( 'ABSPATH' ) || exit;
require_once WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-order.php';
/**
* WC_Abstract_Order class.
*/
abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
@ -65,6 +65,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Stores meta in cache for future reads.
*
* A group must be set to to enable caching.
*
* @var string
*/
protected $cache_group = 'orders';
@ -78,6 +79,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* This is the name of this object type.
*
* @var string
*/
protected $object_type = 'order';
@ -181,8 +183,11 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Save all order items which are part of this order.
*/
protected function save_items() {
$items_changed = false;
foreach ( $this->items_to_delete as $item ) {
$item->delete();
$items_changed = true;
}
$this->items_to_delete = array();
@ -200,10 +205,16 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$this->items[ $item_group ][ $item_id ] = $item;
unset( $this->items[ $item_group ][ $item_key ] );
$items_changed = true;
}
}
}
}
if ( $items_changed ) {
delete_transient( 'wc_order_' . $this->get_id() . '_needs_processing' );
}
}
/*
@ -216,7 +227,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Get parent order ID.
*
* @since 3.0.0
* @param string $context
* @param string $context View or edit context.
* @return integer
*/
public function get_parent_id( $context = 'view' ) {
@ -226,7 +237,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets order currency.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_currency( $context = 'view' ) {
@ -236,7 +247,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get order_version.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_version( $context = 'view' ) {
@ -246,7 +257,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get prices_include_tax.
*
* @param string $context
* @param string $context View or edit context.
* @return bool
*/
public function get_prices_include_tax( $context = 'view' ) {
@ -256,7 +267,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get date_created.
*
* @param string $context
* @param string $context View or edit context.
* @return WC_DateTime|NULL object if the date is set or null if there is no date.
*/
public function get_date_created( $context = 'view' ) {
@ -266,7 +277,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get date_modified.
*
* @param string $context
* @param string $context View or edit context.
* @return WC_DateTime|NULL object if the date is set or null if there is no date.
*/
public function get_date_modified( $context = 'view' ) {
@ -276,7 +287,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Return the order statuses without wc- internal prefix.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_status( $context = 'view' ) {
@ -292,7 +303,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get discount_total.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_discount_total( $context = 'view' ) {
@ -302,7 +313,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get discount_tax.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_discount_tax( $context = 'view' ) {
@ -312,7 +323,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get shipping_total.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_shipping_total( $context = 'view' ) {
@ -322,7 +333,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get shipping_tax.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_shipping_tax( $context = 'view' ) {
@ -332,7 +343,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets cart tax amount.
*
* @param string $context
* @param string $context View or edit context.
* @return float
*/
public function get_cart_tax( $context = 'view' ) {
@ -342,7 +353,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets order grand total. incl. taxes. Used in gateways.
*
* @param string $context
* @param string $context View or edit context.
* @return float
*/
public function get_total( $context = 'view' ) {
@ -352,7 +363,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get total tax amount. Alias for get_order_tax().
*
* @param string $context
* @param string $context View or edit context.
* @return float
*/
public function get_total_tax( $context = 'view' ) {
@ -382,6 +393,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets order subtotal.
*
* @return float
*/
public function get_subtotal() {
@ -406,16 +418,16 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$code = $tax->get_rate_code();
if ( ! isset( $tax_totals[ $code ] ) ) {
$tax_totals[ $code ] = new stdClass();
$tax_totals[ $code ] = new stdClass();
$tax_totals[ $code ]->amount = 0;
}
$tax_totals[ $code ]->id = $key;
$tax_totals[ $code ]->rate_id = $tax->get_rate_id();
$tax_totals[ $code ]->is_compound = $tax->is_compound();
$tax_totals[ $code ]->label = $tax->get_label();
$tax_totals[ $code ]->amount += (float) $tax->get_tax_total() + (float) $tax->get_shipping_tax_total();
$tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array( 'currency' => $this->get_currency() ) );
$tax_totals[ $code ]->id = $key;
$tax_totals[ $code ]->rate_id = $tax->get_rate_id();
$tax_totals[ $code ]->is_compound = $tax->is_compound();
$tax_totals[ $code ]->label = $tax->get_label();
$tax_totals[ $code ]->amount += (float) $tax->get_tax_total() + (float) $tax->get_shipping_tax_total();
$tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array( 'currency' => $this->get_currency() ) );
}
if ( apply_filters( 'woocommerce_order_hide_zero_taxes', true ) ) {
@ -439,7 +451,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get user ID. Used by orders, not other order types like refunds.
*
* @param string $context
* @param string $context View or edit context.
* @return int
*/
public function get_user_id( $context = 'view' ) {
@ -470,8 +482,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Set parent order ID.
*
* @since 3.0.0
* @param int $value
* @throws WC_Data_Exception
* @param int $value Value to set.
* @throws WC_Data_Exception Exception thrown if parent ID does not exist or is invalid.
*/
public function set_parent_id( $value ) {
if ( $value && ( $value === $this->get_id() || ! wc_get_order( $value ) ) ) {
@ -493,13 +505,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
// If setting the status, ensure it's set to a valid status.
if ( true === $this->object_read ) {
// Only allow valid new status
if ( ! in_array( 'wc-' . $new_status, $this->get_valid_statuses() ) && 'trash' !== $new_status ) {
// Only allow valid new status.
if ( ! in_array( 'wc-' . $new_status, $this->get_valid_statuses(), true ) && 'trash' !== $new_status ) {
$new_status = 'pending';
}
// If the old status is set but unknown (e.g. draft) assume its pending for action usage.
if ( $old_status && ! in_array( 'wc-' . $old_status, $this->get_valid_statuses() ) && 'trash' !== $old_status ) {
if ( $old_status && ! in_array( 'wc-' . $old_status, $this->get_valid_statuses(), true ) && 'trash' !== $old_status ) {
$old_status = 'pending';
}
}
@ -515,8 +527,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set order_version.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_version( $value ) {
$this->set_prop( 'version', $value );
@ -525,11 +537,11 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set order_currency.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_currency( $value ) {
if ( $value && ! in_array( $value, array_keys( get_woocommerce_currencies() ) ) ) {
if ( $value && ! in_array( $value, array_keys( get_woocommerce_currencies() ), true ) ) {
$this->error( 'order_invalid_currency', __( 'Invalid currency code', 'woocommerce' ) );
}
$this->set_prop( 'currency', $value ? $value : get_woocommerce_currency() );
@ -538,8 +550,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set prices_include_tax.
*
* @param bool $value
* @throws WC_Data_Exception
* @param bool $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_prices_include_tax( $value ) {
$this->set_prop( 'prices_include_tax', (bool) $value );
@ -549,7 +561,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Set date_created.
*
* @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if there is no date.
* @throws WC_Data_Exception
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_date_created( $date = null ) {
$this->set_date_prop( 'date_created', $date );
@ -559,7 +571,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Set date_modified.
*
* @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if there is no date.
* @throws WC_Data_Exception
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_date_modified( $date = null ) {
$this->set_date_prop( 'date_modified', $date );
@ -568,8 +580,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set discount_total.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_discount_total( $value ) {
$this->set_prop( 'discount_total', wc_format_decimal( $value ) );
@ -578,8 +590,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set discount_tax.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_discount_tax( $value ) {
$this->set_prop( 'discount_tax', wc_format_decimal( $value ) );
@ -588,8 +600,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set shipping_total.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_shipping_total( $value ) {
$this->set_prop( 'shipping_total', wc_format_decimal( $value ) );
@ -598,8 +610,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set shipping_tax.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_shipping_tax( $value ) {
$this->set_prop( 'shipping_tax', wc_format_decimal( $value ) );
@ -609,8 +621,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set cart tax.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_cart_tax( $value ) {
$this->set_prop( 'cart_tax', wc_format_decimal( $value ) );
@ -620,8 +632,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Sets order tax (sum of cart and shipping tax). Used internally only.
*
* @param string $value
* @throws WC_Data_Exception
* @param string $value Value to set.
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
protected function set_total_tax( $value ) {
$this->set_prop( 'total_tax', wc_format_decimal( $value ) );
@ -630,11 +642,11 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Set total.
*
* @param string $value
* @param string $value Value to set.
* @param string $deprecated Function used to set different totals based on this.
*
* @return bool|void
* @throws WC_Data_Exception
* @throws WC_Data_Exception Exception may be thrown if value is invalid.
*/
public function set_total( $value, $deprecated = '' ) {
if ( $deprecated ) {
@ -662,7 +674,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( ! empty( $type ) ) {
$this->data_store->delete_items( $this, $type );
if ( $group = $this->type_to_group( $type ) ) {
$group = $this->type_to_group( $type );
if ( $group ) {
unset( $this->items[ $group ] );
}
} else {
@ -674,8 +688,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Convert a type to a types group.
*
* @param string $type
* @return string group
* @param string $type type to lookup.
* @return string
*/
protected function type_to_group( $type ) {
$type_to_group = apply_filters( 'woocommerce_order_type_to_group', array(
@ -699,11 +713,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$types = array_filter( (array) $types );
foreach ( $types as $type ) {
if ( $group = $this->type_to_group( $type ) ) {
$group = $this->type_to_group( $type );
if ( $group ) {
if ( ! isset( $this->items[ $group ] ) ) {
$this->items[ $group ] = array_filter( $this->data_store->read_items( $this, $type ) );
}
// Don't use array_merge here because keys are numeric
// Don't use array_merge here because keys are numeric.
$items = $items + $this->items[ $group ];
}
}
@ -758,7 +774,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
*/
public function get_used_coupons() {
$coupon_codes = array();
if ( $coupons = $this->get_items( 'coupon' ) ) {
$coupons = $this->get_items( 'coupon' );
if ( $coupons ) {
foreach ( $coupons as $coupon ) {
$coupon_codes[] = $coupon->get_code();
}
@ -769,7 +787,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets the count of order items of a certain type.
*
* @param string $item_type
* @param string $item_type Item type to lookup.
* @return string
*/
public function get_item_count( $item_type = '' ) {
@ -821,7 +839,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Get key for where a certain item type is stored in _items.
*
* @since 3.0.0
* @param $item object Order item (product, shipping, fee, coupon, tax)
* @param string $item object Order item (product, shipping, fee, coupon, tax).
* @return string
*/
protected function get_items_key( $item ) {
@ -846,9 +864,10 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* @return false|void
*/
public function remove_item( $item_id ) {
$item = $this->get_item( $item_id, false );
$item = $this->get_item( $item_id, false );
$items_key = $item ? $this->get_items_key( $item ) : false;
if ( ! $item || ! ( $items_key = $this->get_items_key( $item ) ) ) {
if ( ! $items_key ) {
return false;
}
@ -861,12 +880,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Adds an order item to this order. The order item will not persist until save.
*
* @since 3.0.0
* @param WC_Order_Item Order item object (product, shipping, fee, coupon, tax)
*
* @param WC_Order_Item $item Order item object (product, shipping, fee, coupon, tax).
* @return false|void
*/
public function add_item( $item ) {
if ( ! $items_key = $this->get_items_key( $item ) ) {
$items_key = $this->get_items_key( $item );
if ( ! $items_key ) {
return false;
}
@ -879,10 +899,12 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$item->set_order_id( $this->get_id() );
// Append new row with generated temporary ID.
if ( $item_id = $item->get_id() ) {
$item_id = $item->get_id();
if ( $item_id ) {
$this->items[ $items_key ][ $item_id ] = $item;
} else {
$this->items[ $items_key ][ 'new:' . $items_key . sizeof( $this->items[ $items_key ] ) ] = $item;
$this->items[ $items_key ][ 'new:' . $items_key . count( $this->items[ $items_key ] ) ] = $item;
}
}
@ -897,8 +919,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( is_a( $raw_coupon, 'WC_Coupon' ) ) {
$coupon = $raw_coupon;
} elseif ( is_string( $raw_coupon ) ) {
$code = wc_format_coupon_code( $raw_coupon );
$coupon = new WC_Coupon( $code );
$code = wc_format_coupon_code( $raw_coupon );
$coupon = new WC_Coupon( $code );
if ( $coupon->get_code() !== $code ) {
return new WP_Error( 'invalid_coupon', __( 'Invalid coupon code', 'woocommerce' ) );
@ -936,7 +958,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$this->calculate_totals( true );
// Record usage so counts and validation is correct.
if ( ! $used_by = $this->get_user_id() ) {
$used_by = $this->get_user_id();
if ( ! $used_by ) {
$used_by = $this->get_billing_email();
}
@ -990,8 +1014,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$discounts = new WC_Discounts( $this );
foreach ( $this->get_items( 'coupon' ) as $coupon_item ) {
$coupon_code = $coupon_item->get_code();
$coupon_id = wc_get_coupon_id_by_code( $coupon_code );
$coupon_code = $coupon_item->get_code();
$coupon_id = wc_get_coupon_id_by_code( $coupon_code );
// If we have a coupon ID (loaded via wc_get_coupon_id_by_code) we can simply load the new coupon object using the ID.
if ( $coupon_id ) {
@ -1044,7 +1068,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* @param WC_Discounts $discounts Discounts class.
*/
protected function set_item_discount_amounts( $discounts ) {
if ( $item_discounts = $discounts->get_discounts_by_item() ) {
$item_discounts = $discounts->get_discounts_by_item();
if ( $item_discounts ) {
foreach ( $item_discounts as $item_id => $amount ) {
$item = $this->get_item( $item_id, false );
@ -1110,11 +1136,11 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Add a product line item to the order. This is the only line item type with
* it's own method because it saves looking up order amounts (costs are added up for you).
*
* @param \WC_Product $product
* @param int $qty
* @param array $args
* @return int order item ID
* @throws WC_Data_Exception
* @param WC_Product $product Product object.
* @param int $qty Quantity to add.
* @param array $args Args for the added product.
* @return int
* @throws WC_Data_Exception Exception thrown if the item cannot be added to the cart.
*/
public function add_product( $product, $qty = 1, $args = array() ) {
if ( $product ) {
@ -1130,13 +1156,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
);
} else {
$default_args = array(
'quantity' => $qty,
'quantity' => $qty,
);
}
$args = wp_parse_args( $args, $default_args );
// BW compatibility with old args
// BW compatibility with old args.
if ( isset( $args['totals'] ) ) {
foreach ( $args['totals'] as $key => $value ) {
if ( 'tax' === $key ) {
@ -1172,7 +1198,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* Add a payment token to an order
*
* @since 2.6
* @param WC_Payment_Token $token Payment token object
* @param WC_Payment_Token $token Payment token object.
* @return boolean|int The new token ID or false if it failed.
*/
public function add_payment_token( $token ) {
@ -1247,8 +1273,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get tax location for this order.
*
* @since 3.2.0
* @param $args array Override the location.
* @since 3.2.0
* @param array $args array Override the location.
* @return array
*/
protected function get_tax_location( $args = array() ) {
@ -1259,13 +1285,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
}
$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(),
'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(),
'city' => 'billing' === $tax_based_on ? $this->get_billing_city() : $this->get_shipping_city(),
) );
// Default to base
// Default to base.
if ( 'base' === $tax_based_on || empty( $args['country'] ) ) {
$default = wc_get_base_location();
$args['country'] = $default['country'];
@ -1294,8 +1320,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' );
if ( 'inherit' === $shipping_tax_class ) {
$found_classes = array_intersect( array_merge( array( '' ), WC_Tax :: get_tax_class_slugs() ), $this->get_items_tax_classes() );
$shipping_tax_class = count( $found_classes ) ? current( $found_classes ): false;
$found_classes = array_intersect( array_merge( array( '' ), WC_Tax::get_tax_class_slugs() ), $this->get_items_tax_classes() );
$shipping_tax_class = count( $found_classes ) ? current( $found_classes ) : false;
}
$is_vat_exempt = apply_filters( 'woocommerce_order_is_vat_exempt', 'yes' === $this->get_meta( 'is_vat_exempt' ) );
@ -1345,7 +1371,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
foreach ( $existing_taxes as $tax ) {
// Remove taxes which no longer exist for cart/shipping.
if ( ( ! array_key_exists( $tax->get_rate_id(), $cart_taxes ) && ! array_key_exists( $tax->get_rate_id(), $shipping_taxes ) ) || in_array( $tax->get_rate_id(), $saved_rate_ids ) ) {
if ( ( ! array_key_exists( $tax->get_rate_id(), $cart_taxes ) && ! array_key_exists( $tax->get_rate_id(), $shipping_taxes ) ) || in_array( $tax->get_rate_id(), $saved_rate_ids, true ) ) {
$this->remove_item( $tax->get_id() );
continue;
}
@ -1387,12 +1413,12 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
public function calculate_totals( $and_taxes = true ) {
do_action( 'woocommerce_order_before_calculate_totals', $and_taxes, $this );
$cart_subtotal = 0;
$cart_total = 0;
$fee_total = 0;
$shipping_total = 0;
$cart_subtotal_tax = 0;
$cart_total_tax = 0;
$cart_subtotal = 0;
$cart_total = 0;
$fee_total = 0;
$shipping_total = 0;
$cart_subtotal_tax = 0;
$cart_total_tax = 0;
// Sum line item costs.
foreach ( $this->get_items() as $item ) {
@ -1423,7 +1449,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$fee_total += $item->get_total();
}
// Calculate taxes for items, shipping, discounts.
// Calculate taxes for items, shipping, discounts. Note; this also triggers save().
if ( $and_taxes ) {
$this->calculate_taxes();
}
@ -1448,9 +1474,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get item subtotal - this is the cost before discount.
*
* @param object $item
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @param object $item Item to get total from.
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @return float
*/
public function get_item_subtotal( $item, $inc_tax = false, $round = true ) {
@ -1472,9 +1498,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get line subtotal - this is the cost before discount.
*
* @param object $item
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @param object $item Item to get total from.
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @return float
*/
public function get_line_subtotal( $item, $inc_tax = false, $round = true ) {
@ -1496,9 +1522,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Calculate item cost - useful for gateways.
*
* @param object $item
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @param object $item Item to get total from.
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @return float
*/
public function get_item_total( $item, $inc_tax = false, $round = true ) {
@ -1520,9 +1546,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Calculate line total - useful for gateways.
*
* @param object $item
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @param object $item Item to get total from.
* @param bool $inc_tax (default: false).
* @param bool $round (default: true).
* @return float
*/
public function get_line_total( $item, $inc_tax = false, $round = true ) {
@ -1542,8 +1568,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get item tax - useful for gateways.
*
* @param mixed $item
* @param bool $round (default: true).
* @param mixed $item Item to get total from.
* @param bool $round (default: true).
* @return float
*/
public function get_item_tax( $item, $round = true ) {
@ -1560,7 +1586,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get line tax - useful for gateways.
*
* @param mixed $item
* @param mixed $item Item to get total from.
* @return float
*/
public function get_line_tax( $item ) {
@ -1570,17 +1596,20 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets line subtotal - formatted for display.
*
* @param array $item
* @param string $tax_display
* @param array $item Item to get total from.
* @param string $tax_display Incl or excl tax display mode.
* @return string
*/
public function get_formatted_line_subtotal( $item, $tax_display = '' ) {
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
if ( 'excl' == $tax_display ) {
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() ) );
}
@ -1590,6 +1619,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets order total - formatted for display.
*
* @return string
*/
public function get_formatted_order_total() {
@ -1600,7 +1630,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets subtotal - subtotal is shown before discounts, but with localised taxes.
*
* @param bool $compound (default: false).
* @param bool $compound (default: false).
* @param string $tax_display (default: the tax_display_cart value).
* @return string
*/
@ -1653,21 +1683,20 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Gets shipping (formatted).
*
* @param string $tax_display
*
* @param string $tax_display Excl or incl tax display mode.
* @return string
*/
public function get_shipping_to_display( $tax_display = '' ) {
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
if ( $this->get_shipping_total() != 0 ) {
if ( $this->get_shipping_total() !== 0 ) {
if ( 'excl' === $tax_display ) {
// Show shipping excluding tax.
$shipping = wc_price( $this->get_shipping_total(), array( 'currency' => $this->get_currency() ) );
if ( $this->get_shipping_tax() != 0 && $this->get_prices_include_tax() ) {
if ( $this->get_shipping_tax() !== 0 && $this->get_prices_include_tax() ) {
$shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', '&nbsp;<small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>', $this, $tax_display );
}
} else {
@ -1675,7 +1704,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
// Show shipping including tax.
$shipping = wc_price( $this->get_shipping_total() + $this->get_shipping_tax(), array( 'currency' => $this->get_currency() ) );
if ( $this->get_shipping_tax() != 0 && ! $this->get_prices_include_tax() ) {
if ( $this->get_shipping_tax() !== 0 && ! $this->get_prices_include_tax() ) {
$shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', '&nbsp;<small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>', $this, $tax_display );
}
}
@ -1694,10 +1723,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Get the discount amount (formatted).
*
* @since 2.3.0
*
* @param string $tax_display
*
* @param string $tax_display Excl or incl tax display mode.
* @return string
*/
public function get_discount_to_display( $tax_display = '' ) {
@ -1708,14 +1736,16 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Add total row for subtotal.
*
* @param array $total_rows
* @param string $tax_display
* @param array $total_rows Reference to total rows array.
* @param string $tax_display Excl or incl tax display mode.
*/
protected function add_order_item_totals_subtotal_row( &$total_rows, $tax_display ) {
if ( $subtotal = $this->get_subtotal_to_display( false, $tax_display ) ) {
$subtotal = $this->get_subtotal_to_display( false, $tax_display );
if ( $subtotal ) {
$total_rows['cart_subtotal'] = array(
'label' => __( 'Subtotal:', 'woocommerce' ),
'value' => $subtotal,
'value' => $subtotal,
);
}
}
@ -1723,14 +1753,14 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Add total row for discounts.
*
* @param array $total_rows
* @param string $tax_display
* @param array $total_rows Reference to total rows array.
* @param string $tax_display Excl or incl tax display mode.
*/
protected function add_order_item_totals_discount_row( &$total_rows, $tax_display ) {
if ( $this->get_total_discount() > 0 ) {
$total_rows['discount'] = array(
'label' => __( 'Discount:', 'woocommerce' ),
'value' => '-' . $this->get_discount_to_display( $tax_display ),
'value' => '-' . $this->get_discount_to_display( $tax_display ),
);
}
}
@ -1738,14 +1768,14 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Add total row for shipping.
*
* @param array $total_rows
* @param string $tax_display
* @param array $total_rows Reference to total rows array.
* @param string $tax_display Excl or incl tax display mode.
*/
protected function add_order_item_totals_shipping_row( &$total_rows, $tax_display ) {
if ( $this->get_shipping_method() ) {
$total_rows['shipping'] = array(
'label' => __( 'Shipping:', 'woocommerce' ),
'value' => $this->get_shipping_to_display( $tax_display ),
'value' => $this->get_shipping_to_display( $tax_display ),
);
}
}
@ -1753,11 +1783,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Add total row for fees.
*
* @param array $total_rows
* @param string $tax_display
* @param array $total_rows Reference to total rows array.
* @param string $tax_display Excl or incl tax display mode.
*/
protected function add_order_item_totals_fee_rows( &$total_rows, $tax_display ) {
if ( $fees = $this->get_fees() ) {
$fees = $this->get_fees();
if ( $fees ) {
foreach ( $fees as $id => $fee ) {
if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', empty( $fee['line_total'] ) && empty( $fee['line_tax'] ), $id ) ) {
continue;
@ -1773,8 +1805,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Add total row for taxes.
*
* @param array $total_rows
* @param string $tax_display
* @param array $total_rows Reference to total rows array.
* @param string $tax_display Excl or incl tax display mode.
*/
protected function add_order_item_totals_tax_rows( &$total_rows, $tax_display ) {
// Tax for tax exclusive prices.
@ -1783,13 +1815,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
foreach ( $this->get_tax_totals() as $code => $tax ) {
$total_rows[ sanitize_title( $code ) ] = array(
'label' => $tax->label . ':',
'value' => $tax->formatted_amount,
'value' => $tax->formatted_amount,
);
}
} else {
$total_rows['tax'] = array(
'label' => WC()->countries->tax_or_vat() . ':',
'value' => wc_price( $this->get_total_tax(), array( 'currency' => $this->get_currency() ) ),
'value' => wc_price( $this->get_total_tax(), array( 'currency' => $this->get_currency() ) ),
);
}
}
@ -1798,20 +1830,20 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Add total row for grand total.
*
* @param array $total_rows
* @param string $tax_display
* @param array $total_rows Reference to total rows array.
* @param string $tax_display Excl or incl tax display mode.
*/
protected function add_order_item_totals_total_row( &$total_rows, $tax_display ) {
$total_rows['order_total'] = array(
'label' => __( 'Total:', 'woocommerce' ),
'value' => $this->get_formatted_order_total( $tax_display ),
'value' => $this->get_formatted_order_total( $tax_display ),
);
}
/**
* Get totals for display on pages and in emails.
*
* @param mixed $tax_display
* @param mixed $tax_display Excl or incl tax display mode.
* @return array
*/
public function get_order_item_totals( $tax_display = '' ) {
@ -1840,18 +1872,17 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Checks the order status against a passed in status.
*
* @param array|string $status
*
* @param array|string $status Status to check.
* @return bool
*/
public function has_status( $status ) {
return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status );
return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status, true ) ) || $this->get_status() === $status ? true : false, $this, $status );
}
/**
* Check whether this order has a specific shipping method or not.
*
* @param string $method_id
* @param string $method_id Method ID to check.
* @return bool
*/
public function has_shipping_method( $method_id ) {
@ -1865,6 +1896,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
/**
* Returns true if the order contains a free product.
*
* @since 2.5.0
* @return bool
*/

View File

@ -1808,7 +1808,8 @@ class WC_Product extends WC_Abstract_Legacy_Product {
} else {
$image = '';
}
return apply_filters( 'woocommerce_product_get_image', wc_get_relative_url( $image ), $this, $size, $attr, $placeholder );
return apply_filters( 'woocommerce_product_get_image', wc_get_relative_url( $image ), $this, $size, $attr, $placeholder, $image );
}
/**

View File

@ -1,60 +1,64 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
<?php // @codingStandardsIgnoreLine.
/**
* Abstract Settings API Class
*
* Admin Settings API used by Integrations, Shipping Methods, and Payment Gateways.
*
* @class WC_Settings_API
* @version 2.6.0
* @package WooCommerce/Abstracts
* @category Abstract Class
* @author WooThemes
*/
defined( 'ABSPATH' ) || exit;
/**
* WC_Settings_API class.
*/
abstract class WC_Settings_API {
/**
* The plugin ID. Used for option names.
*
* @var string
*/
public $plugin_id = 'woocommerce_';
/**
* ID of the class extending the settings API. Used in option names.
*
* @var string
*/
public $id = '';
/**
* Validation errors.
*
* @var array of strings
*/
public $errors = array();
/**
* Setting values.
*
* @var array
*/
public $settings = array();
/**
* Form option fields.
*
* @var array
*/
public $form_fields = array();
/**
* The posted settings data. When empty, $_POST data will be used.
*
* @var array
*/
protected $data = array();
/**
* Get the form fields after they are initialized.
*
* @return array of options
*/
public function get_form_fields() {
@ -64,8 +68,7 @@ abstract class WC_Settings_API {
/**
* Set default required properties for each field.
*
* @param array $field
*
* @param array $field Setting field array.
* @return array
*/
protected function set_defaults( $field ) {
@ -79,14 +82,13 @@ abstract class WC_Settings_API {
* Output the admin options table.
*/
public function admin_options() {
echo '<table class="form-table">' . $this->generate_settings_html( $this->get_form_fields(), false ) . '</table>';
echo '<table class="form-table">' . $this->generate_settings_html( $this->get_form_fields(), false ) . '</table>'; // WPCS: XSS ok.
}
/**
* Initialise settings form fields.
*
* Add an array of fields to be displayed
* on the gateway's settings screen.
* Add an array of fields to be displayed on the gateway's settings screen.
*
* @since 1.0.0
*/
@ -94,6 +96,7 @@ abstract class WC_Settings_API {
/**
* Return the name of the option in the WP DB.
*
* @since 2.6.0
* @return string
*/
@ -103,7 +106,8 @@ abstract class WC_Settings_API {
/**
* Get a fields type. Defaults to "text" if not set.
* @param array $field
*
* @param array $field Field key.
* @return string
*/
public function get_field_type( $field ) {
@ -112,7 +116,8 @@ abstract class WC_Settings_API {
/**
* Get a fields default value. Defaults to "" if not set.
* @param array $field
*
* @param array $field Field key.
* @return string
*/
public function get_field_default( $field ) {
@ -121,35 +126,40 @@ abstract class WC_Settings_API {
/**
* Get a field's posted and validated value.
* @param string $key
* @param array $field
* @param array $post_data
*
* @param string $key Field key.
* @param array $field Field array.
* @param array $post_data Posted data.
* @return string
*/
public function get_field_value( $key, $field, $post_data = array() ) {
$type = $this->get_field_type( $field );
$field_key = $this->get_field_key( $key );
$post_data = empty( $post_data ) ? $_POST : $post_data;
$post_data = empty( $post_data ) ? $_POST : $post_data; // WPCS: CSRF ok, input var ok.
$value = isset( $post_data[ $field_key ] ) ? $post_data[ $field_key ] : null;
// Look for a validate_FIELDID_field method for special handling
if ( isset( $field['sanitize_callback'] ) && is_callable( $field['sanitize_callback'] ) ) {
return call_user_func( $field['sanitize_callback'], $value );
}
// Look for a validate_FIELDID_field method for special handling.
if ( is_callable( array( $this, 'validate_' . $key . '_field' ) ) ) {
return $this->{'validate_' . $key . '_field'}( $key, $value );
}
// Look for a validate_FIELDTYPE_field method
// Look for a validate_FIELDTYPE_field method.
if ( is_callable( array( $this, 'validate_' . $type . '_field' ) ) ) {
return $this->{'validate_' . $type . '_field'}( $key, $value );
}
// Fallback to text
// Fallback to text.
return $this->validate_text_field( $key, $value );
}
/**
* Sets the POSTed data. This method can be used to set specific data, instead
* of taking it from the $_POST array.
* @param array data
* Sets the POSTed data. This method can be used to set specific data, instead of taking it from the $_POST array.
*
* @param array $data Posted data.
*/
public function set_post_data( $data = array() ) {
$this->data = $data;
@ -157,18 +167,20 @@ abstract class WC_Settings_API {
/**
* Returns the POSTed data, to be used to save the settings.
*
* @return array
*/
public function get_post_data() {
if ( ! empty( $this->data ) && is_array( $this->data ) ) {
return $this->data;
}
return $_POST;
return $_POST; // WPCS: CSRF ok, input var ok.
}
/**
* Processes and saves options.
* If there is an error thrown, will continue to save and validate fields, but will leave the erroring field out.
*
* @return bool was anything saved?
*/
public function process_admin_options() {
@ -191,7 +203,8 @@ abstract class WC_Settings_API {
/**
* Add an error message for display in admin on save.
* @param string $error
*
* @param string $error Error message.
*/
public function add_error( $error ) {
$this->errors[] = $error;
@ -238,12 +251,12 @@ abstract class WC_Settings_API {
}
/**
* get_option function.
* Get option from DB.
*
* Gets an option from the settings API, using defaults if necessary to prevent undefined notices.
*
* @param string $key
* @param mixed $empty_value
* @param string $key Option key.
* @param mixed $empty_value Value when empty.
* @return string The value specified for the option or a default value for the option.
*/
public function get_option( $key, $empty_value = null ) {
@ -267,7 +280,7 @@ abstract class WC_Settings_API {
/**
* Prefix key for settings.
*
* @param mixed $key
* @param string $key Field key.
* @return string
*/
public function get_field_key( $key ) {
@ -279,9 +292,8 @@ abstract class WC_Settings_API {
*
* Generate the HTML for the fields on the "settings" screen.
*
* @param array $form_fields (default: array())
* @param bool $echo
*
* @param array $form_fields (default: array()) Array of form fields.
* @param bool $echo Echo or return.
* @return string the html for the settings
* @since 1.0.0
* @uses method_exists()
@ -303,7 +315,7 @@ abstract class WC_Settings_API {
}
if ( $echo ) {
echo $html;
echo $html; // WPCS: XSS ok.
} else {
return $html;
}
@ -312,7 +324,7 @@ abstract class WC_Settings_API {
/**
* Get HTML for tooltips.
*
* @param array $data
* @param array $data Data for the tooltip.
* @return string
*/
public function get_tooltip_html( $data ) {
@ -330,7 +342,7 @@ abstract class WC_Settings_API {
/**
* Get HTML for descriptions.
*
* @param array $data
* @param array $data Data for the description.
* @return string
*/
public function get_description_html( $data ) {
@ -350,7 +362,7 @@ abstract class WC_Settings_API {
/**
* Get custom attributes.
*
* @param array $data
* @param array $data Field data.
* @return string
*/
public function get_custom_attribute_html( $data ) {
@ -368,8 +380,8 @@ abstract class WC_Settings_API {
/**
* Generate Text Input HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -393,14 +405,14 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<input class="input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( $this->get_option( $key ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?> />
<?php echo $this->get_description_html( $data ); ?>
<input class="input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( $this->get_option( $key ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
</fieldset>
</td>
</tr>
@ -412,8 +424,8 @@ abstract class WC_Settings_API {
/**
* Generate Price Input HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -437,14 +449,14 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<input class="wc_input_price input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $this->get_option( $key ) ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?> />
<?php echo $this->get_description_html( $data ); ?>
<input class="wc_input_price input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $this->get_option( $key ) ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
</fieldset>
</td>
</tr>
@ -456,8 +468,8 @@ abstract class WC_Settings_API {
/**
* Generate Decimal Input HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -481,14 +493,14 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<input class="wc_input_decimal input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( wc_format_localized_decimal( $this->get_option( $key ) ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?> />
<?php echo $this->get_description_html( $data ); ?>
<input class="wc_input_decimal input-text regular-input <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( wc_format_localized_decimal( $this->get_option( $key ) ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
</fieldset>
</td>
</tr>
@ -500,8 +512,8 @@ abstract class WC_Settings_API {
/**
* Generate Password Input HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -513,8 +525,8 @@ abstract class WC_Settings_API {
/**
* Generate Color Picker Input HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -537,16 +549,16 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<span class="colorpickpreview" style="background:<?php echo esc_attr( $this->get_option( $key ) ); ?>;"></span>
<input class="colorpick <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( $this->get_option( $key ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?> />
<input class="colorpick <?php echo esc_attr( $data['class'] ); ?>" type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="<?php echo esc_attr( $this->get_option( $key ) ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> />
<div id="colorPickerDiv_<?php echo esc_attr( $field_key ); ?>" class="colorpickdiv" style="z-index: 100; background: #eee; border: 1px solid #ccc; position: absolute; display: none;"></div>
<?php echo $this->get_description_html( $data ); ?>
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
</fieldset>
</td>
</tr>
@ -558,8 +570,8 @@ abstract class WC_Settings_API {
/**
* Generate Textarea HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -583,14 +595,14 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<textarea rows="3" cols="20" class="input-text wide-input <?php echo esc_attr( $data['class'] ); ?>" type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?>><?php echo esc_textarea( $this->get_option( $key ) ); ?></textarea>
<?php echo $this->get_description_html( $data ); ?>
<textarea rows="3" cols="20" class="input-text wide-input <?php echo esc_attr( $data['class'] ); ?>" type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" placeholder="<?php echo esc_attr( $data['placeholder'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>><?php echo esc_textarea( $this->get_option( $key ) ); ?></textarea>
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
</fieldset>
</td>
</tr>
@ -602,8 +614,8 @@ abstract class WC_Settings_API {
/**
* Generate Checkbox HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -631,15 +643,15 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<label for="<?php echo esc_attr( $field_key ); ?>">
<input <?php disabled( $data['disabled'], true ); ?> class="<?php echo esc_attr( $data['class'] ); ?>" type="checkbox" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="1" <?php checked( $this->get_option( $key ), 'yes' ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?> /> <?php echo wp_kses_post( $data['label'] ); ?></label><br/>
<?php echo $this->get_description_html( $data ); ?>
<input <?php disabled( $data['disabled'], true ); ?> class="<?php echo esc_attr( $data['class'] ); ?>" type="checkbox" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" value="1" <?php checked( $this->get_option( $key ), 'yes' ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?> /> <?php echo wp_kses_post( $data['label'] ); ?></label><br/>
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
</fieldset>
</td>
</tr>
@ -651,8 +663,8 @@ abstract class WC_Settings_API {
/**
* Generate Select HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -677,18 +689,18 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<select class="select <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?>>
<select class="select <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>>
<?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( $option_key, esc_attr( $this->get_option( $key ) ) ); ?>><?php echo esc_attr( $option_value ); ?></option>
<?php endforeach; ?>
</select>
<?php echo $this->get_description_html( $data ); ?>
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
</fieldset>
</td>
</tr>
@ -700,8 +712,8 @@ abstract class WC_Settings_API {
/**
* Generate Multiselect HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -728,20 +740,20 @@ abstract class WC_Settings_API {
?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php echo $this->get_tooltip_html( $data ); ?>
<?php echo $this->get_tooltip_html( $data ); // WPCS: XSS ok. ?>
<label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<select multiple="multiple" class="multiselect <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>[]" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); ?>>
<select multiple="multiple" class="multiselect <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>[]" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>>
<?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( in_array( $option_key, $value ), true ); ?>><?php echo esc_attr( $option_value ); ?></option>
<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( in_array( $option_key, $value, true ), true ); ?>><?php echo esc_attr( $option_value ); ?></option>
<?php endforeach; ?>
</select>
<?php echo $this->get_description_html( $data ); ?>
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
<?php if ( $data['select_buttons'] ) : ?>
<br/><a class="select_all button" href="#"><?php _e( 'Select all', 'woocommerce' ); ?></a> <a class="select_none button" href="#"><?php _e( 'Select none', 'woocommerce' ); ?></a>
<br/><a class="select_all button" href="#"><?php esc_html_e( 'Select all', 'woocommerce' ); ?></a> <a class="select_none button" href="#"><?php esc_html_e( 'Select none', 'woocommerce' ); ?></a>
<?php endif; ?>
</fieldset>
</td>
@ -754,8 +766,8 @@ abstract class WC_Settings_API {
/**
* Generate Title HTML.
*
* @param mixed $key
* @param mixed $data
* @param string $key Field key.
* @param array $data Field data.
* @since 1.0.0
* @return string
*/
@ -786,8 +798,8 @@ abstract class WC_Settings_API {
*
* Make sure the data is escaped correctly, etc.
*
* @param string $key Field key
* @param string|null $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string
*/
public function validate_text_field( $key, $value ) {
@ -800,8 +812,8 @@ abstract class WC_Settings_API {
*
* Make sure the data is escaped correctly, etc.
*
* @param string $key
* @param string|null $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string
*/
public function validate_price_field( $key, $value ) {
@ -814,8 +826,8 @@ abstract class WC_Settings_API {
*
* Make sure the data is escaped correctly, etc.
*
* @param string $key
* @param string|null $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string
*/
public function validate_decimal_field( $key, $value ) {
@ -826,8 +838,8 @@ abstract class WC_Settings_API {
/**
* Validate Password Field. No input sanitization is used to avoid corrupting passwords.
*
* @param string $key
* @param string|null $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string
*/
public function validate_password_field( $key, $value ) {
@ -838,8 +850,8 @@ abstract class WC_Settings_API {
/**
* Validate Textarea Field.
*
* @param string $key
* @param string|null $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string
*/
public function validate_textarea_field( $key, $value ) {
@ -847,7 +859,12 @@ abstract class WC_Settings_API {
return wp_kses( trim( stripslashes( $value ) ),
array_merge(
array(
'iframe' => array( 'src' => true, 'style' => true, 'id' => true, 'class' => true ),
'iframe' => array(
'src' => true,
'style' => true,
'id' => true,
'class' => true,
),
),
wp_kses_allowed_html( 'post' )
)
@ -859,8 +876,8 @@ abstract class WC_Settings_API {
*
* If not set, return "no", otherwise return "yes".
*
* @param string $key
* @param string|null $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string
*/
public function validate_checkbox_field( $key, $value ) {
@ -870,8 +887,8 @@ abstract class WC_Settings_API {
/**
* Validate Select Field.
*
* @param string $key
* @param string $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string
*/
public function validate_select_field( $key, $value ) {
@ -882,8 +899,8 @@ abstract class WC_Settings_API {
/**
* Validate Multiselect Field.
*
* @param string $key
* @param string $value Posted Value
* @param string $key Field key.
* @param string $value Posted Value.
* @return string|array
*/
public function validate_multiselect_field( $key, $value ) {
@ -892,9 +909,9 @@ abstract class WC_Settings_API {
/**
* Validate the data on the "Settings" form.
* @deprecated 2.6.0 No longer used
*
* @param array $form_fields
* @deprecated 2.6.0 No longer used.
* @param array $form_fields Array of fields.
*/
public function validate_settings_fields( $form_fields = array() ) {
wc_deprecated_function( 'validate_settings_fields', '2.6' );
@ -902,8 +919,9 @@ abstract class WC_Settings_API {
/**
* Format settings if needed.
* @deprecated 2.6.0 Unused
* @param array $value
*
* @deprecated 2.6.0 Unused.
* @param array $value Value to format.
* @return array
*/
public function format_settings( $value ) {

View File

@ -221,9 +221,7 @@ class WC_Admin_Attributes {
* `product_attributes_type_selector` filter. If there is only the default type registered,
* this setting will be hidden.
*/
$attribute_types = wc_get_attribute_types();
if ( 1 < count( $attribute_types ) || ! array_key_exists( 'select', $attribute_types ) ) {
if ( wc_has_custom_attribute_types() ) {
?>
<tr class="form-field form-required">
<th scope="row" valign="top">
@ -294,7 +292,9 @@ class WC_Admin_Attributes {
<tr>
<th scope="col"><?php esc_html_e( 'Name', 'woocommerce' ); ?></th>
<th scope="col"><?php esc_html_e( 'Slug', 'woocommerce' ); ?></th>
<th scope="col"><?php esc_html_e( 'Type', 'woocommerce' ); ?></th>
<?php if ( wc_has_custom_attribute_types() ) : ?>
<th scope="col"><?php esc_html_e( 'Type', 'woocommerce' ); ?></th>
<?php endif; ?>
<th scope="col"><?php esc_html_e( 'Order by', 'woocommerce' ); ?></th>
<th scope="col"><?php esc_html_e( 'Terms', 'woocommerce' ); ?></th>
</tr>
@ -310,7 +310,9 @@ class WC_Admin_Attributes {
<div class="row-actions"><span class="edit"><a href="<?php echo esc_url( add_query_arg( 'edit', $tax->attribute_id, 'edit.php?post_type=product&amp;page=product_attributes' ) ); ?>"><?php esc_html_e( 'Edit', 'woocommerce' ); ?></a> | </span><span class="delete"><a class="delete" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'delete', $tax->attribute_id, 'edit.php?post_type=product&amp;page=product_attributes' ), 'woocommerce-delete-attribute_' . $tax->attribute_id ) ); ?>"><?php esc_html_e( 'Delete', 'woocommerce' ); ?></a></span></div>
</td>
<td><?php echo esc_html( $tax->attribute_name ); ?></td>
<td><?php echo esc_html( wc_get_attribute_type_label( $tax->attribute_type ) ); ?> <?php echo $tax->attribute_public ? esc_html__( '(Public)', 'woocommerce' ) : ''; ?></td>
<?php if ( wc_has_custom_attribute_types() ) : ?>
<td><?php echo esc_html( wc_get_attribute_type_label( $tax->attribute_type ) ); ?> <?php echo $tax->attribute_public ? esc_html__( '(Public)', 'woocommerce' ) : ''; ?></td>
<?php endif; ?>
<td><?php
switch ( $tax->attribute_orderby ) {
case 'name' :
@ -405,9 +407,7 @@ class WC_Admin_Attributes {
* `product_attributes_type_selector` filter. If there is only the default type registered,
* this setting will be hidden.
*/
$attribute_types = wc_get_attribute_types();
if ( 1 < count( $attribute_types ) || ! array_key_exists( 'select', $attribute_types ) ) {
if ( wc_has_custom_attribute_types() ) {
?>
<div class="form-field">
<label for="attribute_type"><?php esc_html_e( 'Type', 'woocommerce' ); ?></label>

View File

@ -28,12 +28,13 @@ class WC_Admin_Notices {
* @var array
*/
private static $core_notices = array(
'install' => 'install_notice',
'update' => 'update_notice',
'template_files' => 'template_file_check_notice',
'legacy_shipping' => 'legacy_shipping_notice',
'no_shipping_methods' => 'no_shipping_methods_notice',
'simplify_commerce' => 'simplify_commerce_notice',
'install' => 'install_notice',
'update' => 'update_notice',
'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',
);
/**
@ -124,7 +125,7 @@ class WC_Admin_Notices {
}
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( __( 'Cheatin&#8217; huh?', 'woocommerce' ) );
wp_die( __( 'You don&#8217;t have permission to do this.', 'woocommerce' ) );
}
$hide_notice = sanitize_text_field( $_GET['wc-hide-notice'] );
@ -315,6 +316,13 @@ class WC_Admin_Notices {
include( 'views/html-notice-simplify-commerce.php' );
}
}
/**
* Notice shown when regenerating thumbnails background process is running.
*/
public static function regenerating_thumbnails_notice() {
include( 'views/html-notice-regenerating-thumbnails.php' );
}
}
WC_Admin_Notices::init();

View File

@ -204,7 +204,7 @@ class WC_Admin_Permalink_Settings {
$shop_page_id = wc_get_page_id( 'shop' );
$shop_permalink = ( $shop_page_id > 0 && get_post( $shop_page_id ) ) ? get_page_uri( $shop_page_id ) : _x( 'shop', 'default-slug', 'woocommerce' );
if ( $shop_page_id && trim( $permalinks['product_base'], '/' ) === $shop_permalink ) {
if ( $shop_page_id && stristr( trim( $permalinks['product_base'], '/' ), $shop_permalink ) ) {
$permalinks['use_verbose_page_rules'] = true;
}

View File

@ -511,23 +511,25 @@ class WC_Admin_Post_Types {
if ( ! empty( $_REQUEST['change_regular_price'] ) && isset( $_REQUEST['_regular_price'] ) ) { // WPCS: input var ok, sanitization ok.
$change_regular_price = absint( $_REQUEST['change_regular_price'] ); // WPCS: input var ok, sanitization ok.
$regular_price = wc_format_decimal( wc_clean( wp_unslash( $_REQUEST['_regular_price'] ) ) ); // WPCS: input var ok, sanitization ok.
$raw_regular_price = wc_clean( wp_unslash( $_REQUEST['_regular_price'] ) ); // WPCS: input var ok, sanitization ok.
$is_percentage = (bool) strstr( $raw_regular_price, '%' );
$regular_price = wc_format_decimal( $raw_regular_price );
switch ( $change_regular_price ) {
case 1:
$new_price = $regular_price;
break;
case 2:
if ( strstr( $regular_price, '%' ) ) {
$percent = str_replace( '%', '', $regular_price ) / 100;
if ( $is_percentage ) {
$percent = $regular_price / 100;
$new_price = $old_regular_price + ( round( $old_regular_price * $percent, wc_get_price_decimals() ) );
} else {
$new_price = $old_regular_price + $regular_price;
}
break;
case 3:
if ( strstr( $regular_price, '%' ) ) {
$percent = str_replace( '%', '', $regular_price ) / 100;
if ( $is_percentage ) {
$percent = $regular_price / 100;
$new_price = max( 0, $old_regular_price - ( round( $old_regular_price * $percent, wc_get_price_decimals() ) ) );
} else {
$new_price = max( 0, $old_regular_price - $regular_price );
@ -547,31 +549,33 @@ class WC_Admin_Post_Types {
if ( ! empty( $_REQUEST['change_sale_price'] ) && isset( $_REQUEST['_sale_price'] ) ) { // WPCS: input var ok, sanitization ok.
$change_sale_price = absint( $_REQUEST['change_sale_price'] ); // WPCS: input var ok, sanitization ok.
$sale_price = wc_format_decimal( wc_clean( wp_unslash( $_REQUEST['_sale_price'] ) ) ); // WPCS: input var ok, sanitization ok.
$raw_sale_price = wc_clean( wp_unslash( $_REQUEST['_sale_price'] ) ); // WPCS: input var ok, sanitization ok.
$is_percentage = (bool) strstr( $raw_sale_price, '%' );
$sale_price = wc_format_decimal( $raw_sale_price );
switch ( $change_sale_price ) {
case 1:
$new_price = $sale_price;
break;
case 2:
if ( strstr( $sale_price, '%' ) ) {
$percent = str_replace( '%', '', $sale_price ) / 100;
if ( $is_percentage ) {
$percent = $sale_price / 100;
$new_price = $old_sale_price + ( $old_sale_price * $percent );
} else {
$new_price = $old_sale_price + $sale_price;
}
break;
case 3:
if ( strstr( $sale_price, '%' ) ) {
$percent = str_replace( '%', '', $sale_price ) / 100;
if ( $is_percentage ) {
$percent = $sale_price / 100;
$new_price = max( 0, $old_sale_price - ( $old_sale_price * $percent ) );
} else {
$new_price = max( 0, $old_sale_price - $sale_price );
}
break;
case 4:
if ( strstr( $sale_price, '%' ) ) {
$percent = str_replace( '%', '', $sale_price ) / 100;
if ( $is_percentage ) {
$percent = $sale_price / 100;
$new_price = max( 0, $product->regular_price - ( $product->regular_price * $percent ) );
} else {
$new_price = max( 0, $product->regular_price - $sale_price );

View File

@ -80,7 +80,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
self::check_download_folder_protection();
// Clear any unwanted data and flush rules.
add_option( 'woocommerce_queue_flush_rewrite_rules', 'true' );
update_option( 'woocommerce_queue_flush_rewrite_rules', 'yes' );
WC()->query->init_query_vars();
WC()->query->add_endpoints();

View File

@ -427,7 +427,12 @@ class WC_Admin_Setup_Wizard {
>
<option value=""><?php esc_html_e( 'Choose a currency&hellip;', 'woocommerce' ); ?></option>
<?php foreach ( get_woocommerce_currencies() as $code => $name ) : ?>
<option value="<?php echo esc_attr( $code ); ?>" <?php selected( $currency, $code ); ?>><?php printf( esc_html__( '%1$s (%2$s)', 'woocommerce' ), $name, get_woocommerce_currency_symbol( $code ) ); ?></option>
<option value="<?php echo esc_attr( $code ); ?>" <?php selected( $currency, $code ); ?>>
<?php
/* translators: 1: currency name 2: currency code */
echo esc_html( sprintf( __( '%1$s (%2$s)', 'woocommerce' ), $name, get_woocommerce_currency_symbol( $code ) ) );
?>
</option>
<?php endforeach; ?>
</select>
<script type="text/javascript">
@ -904,9 +909,9 @@ class WC_Admin_Setup_Wizard {
// @codingStandardsIgnoreStart
$setup_domestic = isset( $_POST['shipping_zones']['domestic']['enabled'] ) && ( 'yes' === $_POST['shipping_zones']['domestic']['enabled'] );
$domestic_method = sanitize_text_field( wp_unslash( $_POST['shipping_zones']['domestic']['method'] ) );
$domestic_method = isset( $_POST['shipping_zones']['domestic']['method'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_zones']['domestic']['method'] ) ) : '';
$setup_intl = isset( $_POST['shipping_zones']['intl']['enabled'] ) && ( 'yes' === $_POST['shipping_zones']['intl']['enabled'] );
$intl_method = sanitize_text_field( wp_unslash( $_POST['shipping_zones']['intl']['method'] ) );
$intl_method = isset( $_POST['shipping_zones']['intl']['method'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_zones']['intl']['method'] ) ) : '';
$weight_unit = sanitize_text_field( wp_unslash( $_POST['weight_unit'] ) );
$dimension_unit = sanitize_text_field( wp_unslash( $_POST['dimension_unit'] ) );
$existing_zones = WC_Shipping_Zones::get_zones();
@ -1304,7 +1309,7 @@ class WC_Admin_Setup_Wizard {
// Show the user-saved state if it was previously saved.
// Otherwise, rely on the item info.
if ( is_array( $previously_saved_settings ) ) {
$should_enable_toggle = 'yes' === $previously_saved_settings['enabled'];
$should_enable_toggle = isset( $previously_saved_settings['enabled'] ) && 'yes' === $previously_saved_settings['enabled'];
} else {
$should_enable_toggle = isset( $item_info['enabled'] ) && $item_info['enabled'];
}
@ -1884,8 +1889,8 @@ class WC_Admin_Setup_Wizard {
<li class="wc-wizard-next-step-item">
<div class="wc-wizard-next-step-description">
<p class="next-step-heading"><?php esc_html_e( 'Next step', 'woocommerce' ); ?></p>
<h3 class="next-step-description"><?php esc_html_e( 'Create your first product', 'woocommerce' ); ?></h3>
<p class="next-step-extra-info"><?php esc_html_e( "You're ready to add your first product.", 'woocommerce' ); ?></p>
<h3 class="next-step-description"><?php esc_html_e( 'Create some products', 'woocommerce' ); ?></h3>
<p class="next-step-extra-info"><?php esc_html_e( "You're ready to add products to your store.", 'woocommerce' ); ?></p>
</div>
<div class="wc-wizard-next-step-action">
<p class="wc-setup-actions step">

View File

@ -2,8 +2,6 @@
/**
* Debug/Status page
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin/System Status
* @version 2.2.0
*/

View File

@ -36,8 +36,13 @@ class WC_Admin_Taxonomies {
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 );
// Add row actions.
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
add_action( 'product_cat_pre_add_form', array( $this, 'product_cat_description' ) );
add_action( 'after-product_cat-table', array( $this, 'product_cat_notes' ) );
$attribute_taxonomies = wc_get_attribute_taxonomies();
@ -295,6 +300,29 @@ class WC_Admin_Taxonomies {
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' ) );
}
/**
* Add some notes to describe the behavior of the default category.
*/
public function product_cat_notes() {
$category_id = get_option( 'default_product_cat', 0 );
$category = get_term( $category_id, 'product_cat' );
$category_name = ( ! $category || is_wp_error( $category ) ) ? _x( 'Uncategorized', 'Default category slug', 'woocommerce' ) : $category->name;
?>
<div class="form-wrap edit-term-notes">
<p>
<strong><?php _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' ),
'<strong>' . esc_html( $category_name ) . '</strong>'
);
?>
</p>
</div>
<?php
}
/**
* Description for shipping class page to aid users.
*/
@ -324,6 +352,42 @@ class WC_Admin_Taxonomies {
return $columns;
}
/**
* Adjust row actions.
*
* @param array $actions Array of actions.
* @param object $term Term object.
* @return array
*/
public function product_cat_row_actions( $actions = array(), $term ) {
$default_category_id = absint( get_option( 'default_product_cat', 0 ) );
if ( $default_category_id !== $term->term_id && current_user_can( 'edit_term', $term->term_id ) ) {
$actions['make_default'] = sprintf(
'<a href="%s" aria-label="%s">%s</a>',
wp_nonce_url( 'edit-tags.php?action=make_default&amp;taxonomy=product_cat&amp;tag_ID=' . absint( $term->term_id ), 'make_default_' . absint( $term->term_id ) ),
/* translators: %s: taxonomy term name */
esc_attr( sprintf( __( 'Make &#8220;%s&#8221; the default category', 'woocommerce' ), $term->name ) ),
__( 'Make default', 'woocommerce' )
);
}
return $actions;
}
/**
* 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 ( wp_verify_nonce( $_GET['_wpnonce'], 'make_default_' . $make_default_id ) && current_user_can( 'edit_term', $make_default_id ) ) {
update_option( 'default_product_cat', $make_default_id );
}
}
}
/**
* Thumbnail column value added to category admin.
*
@ -335,6 +399,13 @@ class WC_Admin_Taxonomies {
*/
public function product_cat_column( $columns, $column, $id ) {
if ( 'thumb' === $column ) {
// Prepend tooltip for default category.
$default_category_id = absint( get_option( 'default_product_cat', 0 ) );
if ( $default_category_id === $id ) {
$columns .= wc_help_tip( __( 'This is the default category and it cannot be deleted. It will be automatically assigned to products with no category.', 'woocommerce' ) );
}
$thumbnail_id = get_woocommerce_term_meta( $id, 'thumbnail_id', true );
if ( $thumbnail_id ) {

View File

@ -41,7 +41,7 @@ if ( ! defined( 'ABSPATH' ) ) {
/* translators: %s: maximum upload size */
printf(
esc_html__( 'Maximum size: %s', 'woocommerce' ),
absint( $size )
$size
);
?>
</small>
@ -95,4 +95,4 @@ if ( ! defined( 'ABSPATH' ) ) {
<button type="submit" class="button button-primary button-next" value="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>" name="save_step"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></button>
<?php wp_nonce_field( 'woocommerce-csv-importer' ); ?>
</div>
</form>
</form>

View File

@ -3,8 +3,6 @@
* List tables: orders.
*
* @author WooCommerce
* @category Admin
* @package WooCommerce/Admin
* @version 3.3.0
*/
@ -225,7 +223,8 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
protected function render_order_date_column() {
$order_timestamp = $this->object->get_date_created()->getTimestamp();
if ( $order_timestamp > strtotime( '-1 day', current_time( 'timestamp', true ) ) ) {
// Check if the order was created within the last 24 hours, and not in the future.
if ( $order_timestamp > strtotime( '-1 day', current_time( 'timestamp', true ) ) && $order_timestamp <= current_time( 'timestamp', true ) ) {
$show_date = sprintf(
/* translators: %s: human-readable time difference */
_x( '%s ago', '%s = human-readable time difference', 'woocommerce' ),
@ -375,17 +374,19 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
<a href="{{ data.shipping_address_map_url }}" target="_blank">{{{ data.formatted_shipping_address }}}</a>
<# } #>
<# if ( data.data.customer_note ) { #>
<strong><?php esc_html_e( 'Note', 'woocommerce' ); ?></strong>
{{ data.data.customer_note }}
<# } #>
<# if ( data.shipping_via ) { #>
<strong><?php esc_html_e( 'Shipping method', 'woocommerce' ); ?></strong>
{{ data.shipping_via }}
<# } #>
</div>
<# } #>
<# if ( data.data.customer_note ) { #>
<div class="wc-order-preview-note">
<strong><?php esc_html_e( 'Note', 'woocommerce' ); ?></strong>
{{ data.data.customer_note }}
</div>
<# } #>
</div>
{{{ data.item_html }}}
@ -396,7 +397,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
<div class="inner">
{{{ data.actions_html }}}
<a class="button button-primary button-large" href="<?php echo esc_url( admin_url( 'post.php?action=edit' ) ); ?>&post={{ data.data.id }}"><?php esc_html_e( 'Edit order', 'woocommerce' ); ?></a>
<a class="button button-primary button-large" aria-label="<?php esc_attr_e( 'Edit this order', 'woocommerce' ); ?>" href="<?php echo esc_url( admin_url( 'post.php?action=edit' ) ); ?>&post={{ data.data.id }}"><?php esc_html_e( 'Edit', 'woocommerce' ); ?></a>
</div>
</footer>
</section>
@ -530,6 +531,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$status_actions['on-hold'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=on-hold&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'On-hold', 'woocommerce' ),
'title' => __( 'Change order status to on-hold', 'woocommerce' ),
'action' => 'on-hold',
);
}
@ -538,6 +540,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$status_actions['processing'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=processing&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Processing', 'woocommerce' ),
'title' => __( 'Change order status to processing', 'woocommerce' ),
'action' => 'processing',
);
}
@ -546,6 +549,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$status_actions['complete'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=completed&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Completed', 'woocommerce' ),
'title' => __( 'Change order status to completed', 'woocommerce' ),
'action' => 'complete',
);
}
@ -712,7 +716,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
);
}
?>
<select class="wc-customer-search" name="_customer_user" data-placeholder="<?php esc_attr_e( 'Search for a customer&hellip;', 'woocommerce' ); ?>" data-allow_clear="true">
<select class="wc-customer-search" name="_customer_user" data-placeholder="<?php esc_attr_e( 'Filter by registered customer', 'woocommerce' ); ?>" data-allow_clear="true">
<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo wp_kses_post( $user_string ); ?><option>
</select>
<?php

View File

@ -38,6 +38,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
add_filter( 'disable_months_dropdown', '__return_true' );
add_filter( 'query_vars', array( $this, 'add_custom_query_var' ) );
add_filter( 'views_edit-product', array( $this, 'product_views' ) );
add_filter( 'get_search_query', array( $this, 'search_label' ) );
}
/**
@ -456,10 +457,13 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
}
// Search using CRUD.
if ( isset( $query_vars['s'] ) ) {
if ( ! empty( $query_vars['s'] ) ) {
$data_store = WC_Data_Store::load( 'product' );
$ids = $data_store->search_products( wc_clean( $query_vars['s'] ), '', true );
$ids = $data_store->search_products( wc_clean( $query_vars['s'] ), '', true, true );
$query_vars['post__in'] = array_merge( $ids, array( 0 ) );
// So we know we are searching products.
$query_vars['product_search'] = true;
unset( $query_vars['s'] );
}
return $query_vars;
@ -499,4 +503,20 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
return $views;
}
/**
* Change the label when searching products
*
* @param string $query Search Query.
* @return string
*/
public function search_label( $query ) {
global $pagenow, $typenow;
if ( 'edit.php' !== $pagenow || 'product' !== $typenow || ! get_query_var( 'product_search' ) || ! isset( $_GET['s'] ) ) { // WPCS: input var ok.
return $query;
}
return wc_clean( wp_unslash( $_GET['s'] ) ); // WPCS: input var ok, sanitization ok.
}
}

View File

@ -25,21 +25,18 @@ class WC_Meta_Box_Product_Images {
* @param WP_Post $post
*/
public static function output( $post ) {
global $thepostid, $product_object;
$thepostid = $post->ID;
$product_object = $thepostid ? wc_get_product( $thepostid ) : new WC_Product;
wp_nonce_field( 'woocommerce_save_data', 'woocommerce_meta_nonce' );
?>
<div id="product_images_container">
<ul class="product_images">
<?php
if ( metadata_exists( 'post', $post->ID, '_product_image_gallery' ) ) {
$product_image_gallery = get_post_meta( $post->ID, '_product_image_gallery', true );
} else {
// Backwards compatibility.
$attachment_ids = get_posts( 'post_parent=' . $post->ID . '&numberposts=-1&post_type=attachment&orderby=menu_order&order=ASC&post_mime_type=image&fields=ids&meta_key=_woocommerce_exclude_image&meta_value=0' );
$attachment_ids = array_diff( $attachment_ids, array( get_post_thumbnail_id() ) );
$product_image_gallery = implode( ',', $attachment_ids );
}
$product_image_gallery = $product_object->get_gallery_image_ids( 'edit' );
$attachments = array_filter( explode( ',', $product_image_gallery ) );
$attachments = array_filter( $product_image_gallery );
$update_meta = false;
$updated_gallery_ids = array();
@ -72,7 +69,7 @@ class WC_Meta_Box_Product_Images {
?>
</ul>
<input type="hidden" id="product_image_gallery" name="product_image_gallery" value="<?php echo esc_attr( $product_image_gallery ); ?>" />
<input type="hidden" id="product_image_gallery" name="product_image_gallery" value="<?php echo esc_attr( implode( ',', $updated_gallery_ids ) ) ?>" />
</div>
<p class="add_product_images hide-if-no-js">
@ -88,8 +85,12 @@ class WC_Meta_Box_Product_Images {
* @param WP_Post $post
*/
public static function save( $post_id, $post ) {
$product_type = empty( $_POST['product-type'] ) ? WC_Product_Factory::get_product_type( $post_id ) : sanitize_title( stripslashes( $_POST['product-type'] ) );
$classname = WC_Product_Factory::get_product_classname( $post_id, $product_type ? $product_type : 'simple' );
$product = new $classname( $post_id );
$attachment_ids = isset( $_POST['product_image_gallery'] ) ? array_filter( explode( ',', wc_clean( $_POST['product_image_gallery'] ) ) ) : array();
update_post_meta( $post_id, '_product_image_gallery', implode( ',', $attachment_ids ) );
$product->set_gallery_image_ids( $attachment_ids );
$product->save();
}
}

View File

@ -44,7 +44,7 @@ $hidden_order_itemmeta = apply_filters( 'woocommerce_hidden_order_itemmeta', arr
?>
<tr data-meta_id="<?php echo esc_attr( $meta_id ); ?>">
<td>
<input type="text" placeholder="<?php esc_attr_e( 'Name (required)', 'woocommerce' ); ?>" name="meta_key[<?php echo esc_attr( $item_id ); ?>][<?php echo esc_attr( $meta_id ); ?>]" value="<?php echo esc_attr( $meta->key ); ?>" />
<input type="text" maxlength="255" placeholder="<?php esc_attr_e( 'Name (required)', 'woocommerce' ); ?>" name="meta_key[<?php echo esc_attr( $item_id ); ?>][<?php echo esc_attr( $meta_id ); ?>]" value="<?php echo esc_attr( $meta->key ); ?>" />
<textarea placeholder="<?php esc_attr_e( 'Value (required)', 'woocommerce' ); ?>" name="meta_value[<?php echo esc_attr( $item_id ); ?>][<?php echo esc_attr( $meta_id ); ?>]"><?php echo esc_textarea( rawurldecode( $meta->value ) ); ?></textarea>
</td>
<td width="1%"><button class="remove_order_item_meta button">&times;</button></td>

View File

@ -98,32 +98,42 @@ if ( wc_tax_enabled() ) {
<button type="button" class="button bulk-delete-items"><?php esc_html_e( 'Delete selected row(s)', 'woocommerce' ); ?></button>
<?php endif; ?>
<button type="button" class="button bulk-decrease-stock"><?php esc_html_e( 'Reduce stock', 'woocommerce' ); ?></button>
<button type="button" class="button bulk-increase-stock"><?php esc_html_e( 'Increase stock', 'woocommerce' ); ?></button>
<?php if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) : ?>
<button type="button" class="button bulk-decrease-stock"><?php esc_html_e( 'Reduce stock', 'woocommerce' ); ?></button>
<button type="button" class="button bulk-increase-stock"><?php esc_html_e( 'Increase stock', 'woocommerce' ); ?></button>
<?php endif; ?>
<?php do_action( 'woocommerce_admin_order_item_bulk_actions', $order ); ?>
</div>
<div class="wc-order-data-row wc-order-totals-items wc-order-items-editable">
<?php
$coupons = $order->get_items( 'coupon' );
if ( $coupons ) {
?>
if ( $coupons ) : ?>
<div class="wc-used-coupons">
<ul class="wc_coupon_list"><?php
echo '<li><strong>' . esc_html__( 'Coupon(s)', 'woocommerce' ) . '</strong></li>';
foreach ( $coupons as $item_id => $item ) {
<ul class="wc_coupon_list">
<li><strong><?php esc_html_e( 'Coupon(s)', 'woocommerce' ) ?></strong></li>
<?php foreach ( $coupons as $item_id => $item ) :
$post_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' LIMIT 1;", $item->get_code() ) );
if ( $post_id ) {
echo '<li class="code"><a href="' . esc_url( add_query_arg( array( 'post' => $post_id, 'action' => 'edit' ), admin_url( 'post.php' ) ) ) . '" class="tips" data-tip="' . esc_attr( wc_price( $item->get_discount(), array( 'currency' => $order->get_currency() ) ) ) . '"><span>' . esc_html( $item->get_code() ) . '</span></a> <a class="remove-coupon" href="javascript:void(0)" aria-label="Remove" data-code="' . esc_attr( $item->get_code() ) . '"></a></li>';
} else {
echo '<li class="code"><span class="tips" data-tip="' . esc_attr( wc_price( $item->get_discount(), array( 'currency' => $order->get_currency() ) ) ) . '"><span>' . esc_html( $item->get_code() ) . '</span></span> <a class="remove-coupon" href="javascript:void(0)" aria-label="Remove" data-code="' . esc_attr( $item->get_code() ) . '"></a></li>';
}
}
?></ul>
$class = $order->is_editable() ? 'code editable' : 'code';
?>
<li class="<?php echo $class ?>">
<?php if ( $post_id ) : ?>
<a href="<?php echo esc_url( add_query_arg( array( 'post' => $post_id, 'action' => 'edit' ), admin_url( 'post.php' ) ) ) ?>" class="tips" data-tip="<?php echo esc_attr( wc_price( $item->get_discount(), array( 'currency' => $order->get_currency() ) ) ) ?>">
<span><?php echo esc_html( $item->get_code() ) ?></span>
</a>
<?php else : ?>
<span class="tips" data-tip="<?php echo esc_attr( wc_price( $item->get_discount(), array( 'currency' => $order->get_currency() ) ) ) ?>">
<span><?php echo esc_html( $item->get_code() ) ?></span>
</span>
<?php endif; ?>
<?php if ( $order->is_editable() ) : ?>
<a class="remove-coupon" href="javascript:void(0)" aria-label="Remove" data-code="<?php echo esc_attr( $item->get_code() ) ?>"></a>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php
}
?>
<?php endif; ?>
<table class="wc-order-totals">
<?php if ( 0 < $order->get_total_discount() ) : ?>
<tr>

View File

@ -151,17 +151,31 @@ class WC_Report_Taxes_By_Date extends WC_Admin_Report {
$tax_rows = array();
foreach ( $tax_rows_orders + $tax_rows_partial_refunds as $tax_row ) {
$key = date( ( 'month' === $this->chart_groupby ) ? 'Ym' : 'Ymd', strtotime( $tax_row->post_date ) );
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array( 'tax_amount' => 0, 'shipping_tax_amount' => 0, 'total_sales' => 0, 'total_shipping' => 0, 'total_orders' => 0 );
$key = date( ( 'month' === $this->chart_groupby ) ? 'Ym': 'Ymd', strtotime( $tax_row->post_date ) );
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ]: (object) array(
'tax_amount' => 0,
'shipping_tax_amount' => 0,
'total_sales' => 0,
'total_shipping' => 0,
'total_orders' => 0,
);
}
foreach ( $tax_rows_orders as $tax_row ) {
$key = date( ( 'month' === $this->chart_groupby ) ? 'Ym': 'Ymd', strtotime( $tax_row->post_date ) );
$tax_rows[ $key ]->total_orders += $tax_row->total_orders;
$tax_rows[ $key ]->tax_amount += $tax_row->tax_amount;
$tax_rows[ $key ]->shipping_tax_amount += $tax_row->shipping_tax_amount;
$tax_rows[ $key ]->total_sales += $tax_row->total_sales;
$tax_rows[ $key ]->total_shipping += $tax_row->total_shipping;
}
foreach ( $tax_rows_orders as $tax_row ) {
$key = date( ( 'month' === $this->chart_groupby ) ? 'Ym': 'Ymd', strtotime( $tax_row->post_date ) );
$tax_rows[ $key ]->total_orders += $tax_row->total_orders;
foreach ( $tax_rows_partial_refunds as $tax_row ) {
$key = date( ( 'month' === $this->chart_groupby ) ? 'Ym': 'Ymd', strtotime( $tax_row->post_date ) );
$tax_rows[ $key ]->tax_amount += $tax_row->tax_amount;
$tax_rows[ $key ]->shipping_tax_amount += $tax_row->shipping_tax_amount;
$tax_rows[ $key ]->total_sales += $tax_row->total_sales;
$tax_rows[ $key ]->total_shipping += $tax_row->total_shipping;
}
foreach ( $tax_rows_full_refunds as $tax_row ) {

View File

@ -373,6 +373,10 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
}
}
}
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
}
}
}

View File

@ -269,6 +269,49 @@ class WC_Settings_General extends WC_Settings_Page {
</div>';
}
/**
* Show a notice showing where the store notice setting has moved.
*
* @since 3.3.1
* @todo remove in next major release.
*/
private function store_notice_setting_moved_notice() {
if ( get_user_meta( get_current_user_id(), 'dismissed_store_notice_setting_moved_notice', true ) ) {
return;
}
?>
<div id="message" class="updated woocommerce-message inline">
<a class="woocommerce-message-close notice-dismiss" style="top:0;" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc-hide-notice', 'store_notice_setting_moved' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>"><?php esc_html_e( 'Dismiss', 'woocommerce' ); ?></a>
<p><?php
/* translators: %s: URL to customizer. */
echo wp_kses( sprintf( __( 'Looking for the store notice setting? It can now be found <a href="%s">in the Customizer</a>.', 'woocommerce' ), esc_url( add_query_arg( array(
'autofocus' => array(
'panel' => 'woocommerce',
),
'url' => wc_get_page_permalink( 'shop' ),
), admin_url( 'customize.php' ) ) ) ), array(
'a' => array(
'href' => array(),
'title' => array(),
),
) );
?></p>
</div>
<?php
}
/**
* Output the settings.
*/
public function output() {
$settings = $this->get_settings();
$this->store_notice_setting_moved_notice();
WC_Admin_Settings::output_fields( $settings );
}
/**
* Save settings.
*/

View File

@ -75,7 +75,12 @@ class WC_Settings_Products extends WC_Settings_Page {
<p><?php
/* translators: %s: URL to customizer. */
echo wp_kses( sprintf( __( 'Looking for the product display options? They can now be found in the Customizer. <a href="%s">Go see them in action here.</a>', 'woocommerce' ), esc_url( admin_url( 'customize.php?url=' . wc_get_page_permalink( 'shop' ) . '&autofocus[panel]=woocommerce' ) ) ), array(
echo wp_kses( sprintf( __( 'Looking for the product display options? They can now be found in the Customizer. <a href="%s">Go see them in action here.</a>', 'woocommerce' ), esc_url( add_query_arg( array(
'autofocus' => array(
'panel' => 'woocommerce',
),
'url' => wc_get_page_permalink( 'shop' ),
), admin_url( 'customize.php' ) ) ) ), array(
'a' => array(
'href' => array(),
'title' => array(),
@ -94,6 +99,10 @@ class WC_Settings_Products extends WC_Settings_Page {
$settings = $this->get_settings( $current_section );
WC_Admin_Settings::save_fields( $settings );
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
}
}
/**

View File

@ -146,6 +146,10 @@ class WC_Settings_Rest_API extends WC_Settings_Page {
if ( apply_filters( 'woocommerce_rest_api_valid_to_save', ! in_array( $current_section, array( 'keys', 'webhooks' ), true ) ) ) {
$settings = $this->get_settings();
WC_Admin_Settings::save_fields( $settings );
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
}
}
}
}

View File

@ -186,6 +186,10 @@ class WC_Settings_Shipping extends WC_Settings_Page {
break;
}
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
}
// Increments the transient version to invalidate cache.
WC_Cache_Helper::get_transient_version( 'shipping', true );
}
@ -240,7 +244,7 @@ class WC_Settings_Shipping extends WC_Settings_Page {
}
wp_localize_script( 'wc-shipping-zone-methods', 'shippingZoneMethodsLocalizeScript', array(
'methods' => $zone->get_shipping_methods(),
'methods' => $zone->get_shipping_methods( false, 'json' ),
'zone_name' => $zone->get_zone_name(),
'zone_id' => $zone->get_id(),
'wc_shipping_zones_nonce' => wp_create_nonce( 'wc_shipping_zones_nonce' ),

View File

@ -118,6 +118,10 @@ class WC_Settings_Tax extends WC_Settings_Page {
$this->save_tax_rates();
}
if ( $current_section ) {
do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
}
// Invalidate caches.
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::get_transient_version( 'shipping', true );

View File

@ -60,8 +60,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="wc-shipping-zone-postcodes">
<textarea name="zone_postcodes" data-attribute="zone_postcodes" id="zone_postcodes" placeholder="<?php esc_attr_e( 'List 1 postcode per line', 'woocommerce' ); ?>" class="input-text large-text" cols="25" rows="5"><?php echo esc_textarea( implode( "\n", $postcodes ) ); ?></textarea>
<?php /* translators: WooCommerce link to setting up shipping zones */ ?>
<span class="description"><?php sprintf( _e( 'Postcodes containing wildcards (e.g. CB23*) or fully numeric ranges (e.g. <code>90210...99000</code>) are also supported. Please see the shipping zones <a href="%s" target="_blank">documentation</a>) for more information.', 'woocommerce' ), 'https://docs.woocommerce.com/document/setting-up-shipping-zones/#section-3' ); ?></span><?php // @codingStandardsIgnoreLine. ?>
?>
<span class="description"><?php printf( __( 'Postcodes containing wildcards (e.g. CB23*) or fully numeric ranges (e.g. <code>90210...99000</code>) are also supported. Please see the shipping zones <a href="%s" target="_blank">documentation</a>) for more information.', 'woocommerce' ), 'https://docs.woocommerce.com/document/setting-up-shipping-zones/#section-3' ); ?></span><?php // @codingStandardsIgnoreLine. ?>
</div>
</td>
<?php endif; ?>

View File

@ -31,7 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_status"><?php esc_html_e( 'Status', 'woocommerce' ); ?></label>
<?php wc_help_tip( __( 'The options are &quot;Active&quot; (delivers payload), &quot;Paused&quot; (does not deliver), or &quot;Disabled&quot; (does not deliver due delivery failures).', 'woocommerce' ) ); ?>
<?php echo wc_help_tip( __( 'The options are &quot;Active&quot; (delivers payload), &quot;Paused&quot; (does not deliver), or &quot;Disabled&quot; (does not deliver due delivery failures).', 'woocommerce' ) ); ?>
</th>
<td class="forminp">
<select name="webhook_status" id="webhook_status" class="wc-enhanced-select">

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
<?php
/**
* Admin View: Notice - Regenerating thumbnails.
*/
defined( 'ABSPATH' ) || exit;
?>
<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', 'regenerating_thumbnails' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>"><?php _e( 'Cancel thumbnail regeneration', 'woocommerce' ); ?></a>
<p><?php esc_html_e( 'Thumbnail regeneration is running in the background. Depending on the amount of images in your store this may take a while.', 'woocommerce' ); ?></p>
</div>

View File

@ -234,7 +234,7 @@ function wc_save_order_items( $order_id, $items ) {
if ( isset( $items['meta_key'][ $item_id ], $items['meta_value'][ $item_id ] ) ) {
foreach ( $items['meta_key'][ $item_id ] as $meta_id => $meta_key ) {
$meta_key = wp_unslash( $meta_key );
$meta_key = substr( wp_unslash( $meta_key ), 0, 255 );
$meta_value = isset( $items['meta_value'][ $item_id ][ $meta_id ] ) ? wp_unslash( $items['meta_value'][ $item_id ][ $meta_id ] ): '';
if ( '' === $meta_key && '' === $meta_value ) {
@ -324,7 +324,7 @@ function wc_render_action_buttons( $actions ) {
if ( isset( $action['group'] ) ) {
$actions_html .= '<div class="wc-action-button-group"><label>' . $action['group'] . '</label> <span class="wc-action-button-group__items">' . wc_render_action_buttons( $action['actions'] ) . '</span></div>';
} elseif ( isset( $action['action'], $action['url'], $action['name'] ) ) {
$actions_html .= sprintf( '<a class="button wc-action-button wc-action-button-%s %s" href="%s" title="%s">%s</a>', esc_attr( $action['action'] ), esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_attr( $action['name'] ) );
$actions_html .= sprintf( '<a class="button wc-action-button wc-action-button-%1$s %1$s" href="%2$s" aria-label="%3$s" title="%3$s">%4$s</a>', esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( isset( $action['title'] ) ? $action['title'] : $action['name'] ), esc_html( $action['name'] ) );
}
}

View File

@ -184,49 +184,55 @@ function woocommerce_wp_checkbox( $field ) {
/**
* Output a select input box.
*
* @param array $field
* @param array $field Data about the field to render.
*/
function woocommerce_wp_select( $field ) {
global $thepostid, $post;
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
$field['class'] = isset( $field['class'] ) ? $field['class'] : 'select short';
$field['style'] = isset( $field['style'] ) ? $field['style'] : '';
$field['wrapper_class'] = isset( $field['wrapper_class'] ) ? $field['wrapper_class'] : '';
$field['value'] = isset( $field['value'] ) ? $field['value'] : get_post_meta( $thepostid, $field['id'], true );
$field['name'] = isset( $field['name'] ) ? $field['name'] : $field['id'];
$field['desc_tip'] = isset( $field['desc_tip'] ) ? $field['desc_tip'] : false;
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
$field = wp_parse_args( $field, array(
'class' => 'select short',
'style' => '',
'wrapper_class' => '',
'value' => get_post_meta( $thepostid, $field['id'], true ),
'name' => $field['id'],
'desc_tip' => false,
'custom_attributes' => array(),
) );
// Custom attribute handling
$custom_attributes = array();
$wrapper_attributes = array(
'class' => $field['wrapper_class'] . " form-field {$field['id']}_field",
);
if ( ! empty( $field['custom_attributes'] ) && is_array( $field['custom_attributes'] ) ) {
$label_attributes = array(
'for' => $field['id'],
);
foreach ( $field['custom_attributes'] as $attribute => $value ) {
$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $value ) . '"';
}
}
$field_attributes = (array) $field['custom_attributes'];
$field_attributes['style'] = $field['style'];
$field_attributes['id'] = $field['id'];
$field_attributes['name'] = $field['name'];
echo '<p class="form-field ' . esc_attr( $field['id'] ) . '_field ' . esc_attr( $field['wrapper_class'] ) . '">
<label for="' . esc_attr( $field['id'] ) . '">' . wp_kses_post( $field['label'] ) . '</label>';
if ( ! empty( $field['description'] ) && false !== $field['desc_tip'] ) {
echo wc_help_tip( $field['description'] );
}
echo '<select id="' . esc_attr( $field['id'] ) . '" name="' . esc_attr( $field['name'] ) . '" class="' . esc_attr( $field['class'] ) . '" style="' . esc_attr( $field['style'] ) . '" ' . implode( ' ', $custom_attributes ) . '>';
foreach ( $field['options'] as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '" ' . selected( esc_attr( $field['value'] ), esc_attr( $key ), false ) . '>' . esc_html( $value ) . '</option>';
}
echo '</select> ';
if ( ! empty( $field['description'] ) && false === $field['desc_tip'] ) {
echo '<span class="description">' . wp_kses_post( $field['description'] ) . '</span>';
}
echo '</p>';
$tooltip = ! empty( $field['description'] ) && false !== $field['desc_tip'] ? $field['description'] : '';
$description = ! empty( $field['description'] ) && false === $field['desc_tip'] ? $field['description'] : '';
?>
<p <?php echo wc_implode_html_attributes( $wrapper_attributes ); // WPCS: XSS ok. ?>>
<label <?php echo wc_implode_html_attributes( $label_attributes ); // WPCS: XSS ok. ?>><?php echo wp_kses_post( $field['label'] ); ?></label>
<?php if ( $tooltip ) : ?>
<?php echo wc_help_tip( $tooltip ); // WPCS: XSS ok. ?>
<?php endif; ?>
<select <?php echo wc_implode_html_attributes( $field_attributes ); // WPCS: XSS ok. ?>>
<?php
foreach ( $field['options'] as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '" ' . selected( $field['value'] === $key || ( is_array( $field['value'] ) && in_array( $key, $field['value'], true ) ), true, false ) . '>' . esc_html( $value ) . '</option>';
}
?>
</select>
<?php if ( $description ) : ?>
<span class="description"><?php echo wp_kses_post( $description ); ?></span>
<?php endif; ?>
</p>
<?php
}
/**

View File

@ -433,6 +433,9 @@ class WC_REST_Orders_Controller extends WC_REST_Legacy_Orders_Controller {
if ( ! is_null( $value ) ) {
switch ( $key ) {
case 'status' :
// Status change should be done later so transitions have new data.
break;
case 'billing' :
case 'shipping' :
$this->update_address( $order, $value, $key );
@ -514,25 +517,25 @@ class WC_REST_Orders_Controller extends WC_REST_Legacy_Orders_Controller {
$object->set_created_via( 'rest-api' );
$object->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$object->calculate_totals();
} else {
// If items have changed, recalculate order totals.
if ( isset( $request['billing'] ) || isset( $request['shipping'] ) || isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) {
$object->calculate_totals();
}
}
// Set status.
if ( ! empty( $request['status'] ) ) {
$object->set_status( $request['status'] );
}
$object->save();
// Actions for after the order is saved.
if ( $creating ) {
if ( true === $request['set_paid'] ) {
if ( true === $request['set_paid'] ) {
if ( $creating || $object->needs_payment() ) {
$object->payment_complete( $request['transaction_id'] );
}
} else {
// Handle set paid.
if ( $object->needs_payment() && true === $request['set_paid'] ) {
$object->payment_complete( $request['transaction_id'] );
}
// If items have changed, recalculate order totals.
if ( isset( $request['billing'] ) || isset( $request['shipping'] ) || isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) {
$object->calculate_totals();
}
}
return $this->get_object( $object->get_id() );

View File

@ -53,83 +53,91 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
* Register the routes for products.
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
'args' => array(
'product_id' => array(
'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),
'type' => 'integer',
),
),
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
'args' => array(
'product_id' => array(
'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),
'type' => 'integer',
),
'id' => array(
'description' => __( 'Unique identifier for the variation.', 'woocommerce' ),
'type' => 'integer',
),
),
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'context' => $this->get_context_param( array(
'default' => 'view',
) ),
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_item' ),
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
'args' => array(
'force' => array(
'default' => false,
'type' => 'boolean',
'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce' ),
register_rest_route(
$this->namespace, '/' . $this->rest_base, array(
'args' => array(
'product_id' => array(
'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),
'type' => 'integer',
),
),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
'args' => array(
'product_id' => array(
'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),
'type' => 'integer',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'batch_items' ),
'permission_callback' => array( $this, 'batch_items_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
'schema' => array( $this, 'get_public_batch_schema' ),
) );
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
'args' => array(
'product_id' => array(
'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),
'type' => 'integer',
),
'id' => array(
'description' => __( 'Unique identifier for the variation.', 'woocommerce' ),
'type' => 'integer',
),
),
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'context' => $this->get_context_param(
array(
'default' => 'view',
)
),
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_item' ),
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
'args' => array(
'force' => array(
'default' => false,
'type' => 'boolean',
'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce' ),
),
),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/batch', array(
'args' => array(
'product_id' => array(
'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),
'type' => 'integer',
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'batch_items' ),
'permission_callback' => array( $this, 'batch_items_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
'schema' => array( $this, 'get_public_batch_schema' ),
)
);
}
/**
@ -143,6 +151,27 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
return wc_get_product( $id );
}
/**
* Check if a given request has access to update an item.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$object = $this->get_object( (int) $request['id'] );
if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'edit', $object->get_id() ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
// Check if variation belongs to the correct parent product.
if ( 0 !== $object->get_parent_id() && absint( $request['product_id'] ) !== $object->get_parent_id() ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Parent product does not match current variation.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Prepare a single variation output for response.
*
@ -186,9 +215,9 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
'backordered' => $object->is_on_backorder(),
'weight' => $object->get_weight(),
'dimensions' => array(
'length' => $object->get_length(),
'width' => $object->get_width(),
'height' => $object->get_height(),
'length' => $object->get_length(),
'width' => $object->get_width(),
'height' => $object->get_height(),
),
'shipping_class' => $object->get_shipping_class(),
'shipping_class_id' => $object->get_shipping_class_id(),
@ -246,7 +275,10 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
$variation = new WC_Product_Variation();
}
$variation->set_parent_id( absint( $request['product_id'] ) );
// Update parent ID just once.
if ( 0 === $variation->get_parent_id() ) {
$variation->set_parent_id( absint( $request['product_id'] ) );
}
// Status.
if ( isset( $request['visible'] ) ) {
@ -461,9 +493,11 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
$result = false;
if ( ! $object || 0 === $object->get_id() ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array(
'status' => 404,
) );
return new WP_Error(
"woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array(
'status' => 404,
)
);
}
$supports_trash = EMPTY_TRASH_DAYS > 0 && is_callable( array( $object, 'get_status' ) );
@ -479,10 +513,12 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
$supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object );
if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) {
/* translators: %s: post type */
return new WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array(
'status' => rest_authorization_required_code(),
) );
return new WP_Error(
/* 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(
'status' => rest_authorization_required_code(),
)
);
}
$request->set_param( 'context', 'edit' );
@ -495,19 +531,23 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
} else {
// If we don't support trashing for this type, error out.
if ( ! $supports_trash ) {
/* translators: %s: post type */
return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ), array(
'status' => 501,
) );
return new WP_Error(
/* translators: %s: post type */
'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ), array(
'status' => 501,
)
);
}
// Otherwise, only trash if we haven't already.
if ( is_callable( array( $object, 'get_status' ) ) ) {
if ( 'trash' === $object->get_status() ) {
/* translators: %s: post type */
return new WP_Error( 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ), array(
'status' => 410,
) );
return new WP_Error(
/* translators: %s: post type */
'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ), array(
'status' => 410,
)
);
}
$object->delete();
@ -516,10 +556,12 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
}
if ( ! $result ) {
/* translators: %s: post type */
return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array(
'status' => 500,
) );
return new WP_Error(
/* translators: %s: post type */
'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array(
'status' => 500,
)
);
}
// Delete parent product transients.
@ -556,9 +598,11 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
if ( ! empty( $items[ $batch_type ] ) ) {
$injected_items = array();
foreach ( $items[ $batch_type ] as $item ) {
$injected_items[] = is_array( $item ) ? array_merge( array(
'product_id' => $product_id,
), $item ) : $item;
$injected_items[] = is_array( $item ) ? array_merge(
array(
'product_id' => $product_id,
), $item
) : $item;
}
$body_params[ $batch_type ] = $injected_items;
}
@ -581,13 +625,13 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
$product_id = (int) $request['product_id'];
$base = str_replace( '(?P<product_id>[\d]+)', $product_id, $this->rest_base );
$links = array(
'self' => array(
'self' => array(
'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $object->get_id() ) ),
),
'collection' => array(
'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ),
),
'up' => array(
'up' => array(
'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $product_id ) ),
),
);
@ -607,58 +651,58 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
'title' => $this->post_type,
'type' => 'object',
'properties' => array(
'id' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'date_created' => array(
'date_created' => array(
'description' => __( "The date the variation was created, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'date_modified' => array(
'date_modified' => array(
'description' => __( "The date the variation was last modified, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'description' => array(
'description' => array(
'description' => __( 'Variation description.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'permalink' => array(
'permalink' => array(
'description' => __( 'Variation URL.', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'sku' => array(
'sku' => array(
'description' => __( 'Unique identifier.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'price' => array(
'price' => array(
'description' => __( 'Current variation price.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'regular_price' => array(
'regular_price' => array(
'description' => __( 'Variation regular price.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'sale_price' => array(
'sale_price' => array(
'description' => __( 'Variation sale price.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'date_on_sale_from' => array(
'date_on_sale_from' => array(
'description' => __( "Start date of sale price, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
@ -668,54 +712,54 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
),
'date_on_sale_to' => array(
'date_on_sale_to' => array(
'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
),
'date_on_sale_to_gmt' => array(
'date_on_sale_to_gmt' => array(
'description' => __( 'End date of sale price, as GMT.', 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
),
'on_sale' => array(
'on_sale' => array(
'description' => __( 'Shows if the variation is on sale.', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'visible' => array(
'visible' => array(
'description' => __( "Define if the variation is visible on the product's page.", 'woocommerce' ),
'type' => 'boolean',
'default' => true,
'context' => array( 'view', 'edit' ),
),
'purchasable' => array(
'purchasable' => array(
'description' => __( 'Shows if the variation can be bought.', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'virtual' => array(
'virtual' => array(
'description' => __( 'If the variation is virtual.', 'woocommerce' ),
'type' => 'boolean',
'default' => false,
'context' => array( 'view', 'edit' ),
),
'downloadable' => array(
'downloadable' => array(
'description' => __( 'If the variation is downloadable.', 'woocommerce' ),
'type' => 'boolean',
'default' => false,
'context' => array( 'view', 'edit' ),
),
'downloads' => array(
'downloads' => array(
'description' => __( 'List of downloadable files.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
'items' => array(
'type' => 'object',
'properties' => array(
'id' => array(
'id' => array(
'description' => __( 'File MD5 hash.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
@ -734,73 +778,73 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
),
),
),
'download_limit' => array(
'download_limit' => array(
'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce' ),
'type' => 'integer',
'default' => -1,
'context' => array( 'view', 'edit' ),
),
'download_expiry' => array(
'download_expiry' => array(
'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce' ),
'type' => 'integer',
'default' => -1,
'context' => array( 'view', 'edit' ),
),
'tax_status' => array(
'tax_status' => array(
'description' => __( 'Tax status.', 'woocommerce' ),
'type' => 'string',
'default' => 'taxable',
'enum' => array( 'taxable', 'shipping', 'none' ),
'context' => array( 'view', 'edit' ),
),
'tax_class' => array(
'tax_class' => array(
'description' => __( 'Tax class.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'manage_stock' => array(
'manage_stock' => array(
'description' => __( 'Stock management at variation level.', 'woocommerce' ),
'type' => 'boolean',
'default' => false,
'context' => array( 'view', 'edit' ),
),
'stock_quantity' => array(
'stock_quantity' => array(
'description' => __( 'Stock quantity.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'in_stock' => array(
'in_stock' => array(
'description' => __( 'Controls whether or not the variation is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce' ),
'type' => 'boolean',
'default' => true,
'context' => array( 'view', 'edit' ),
),
'backorders' => array(
'backorders' => array(
'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce' ),
'type' => 'string',
'default' => 'no',
'enum' => array( 'no', 'notify', 'yes' ),
'context' => array( 'view', 'edit' ),
),
'backorders_allowed' => array(
'backorders_allowed' => array(
'description' => __( 'Shows if backorders are allowed.', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'backordered' => array(
'backordered' => array(
'description' => __( 'Shows if the variation is on backordered.', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'weight' => array(
'weight' => array(
/* translators: %s: weight unit */
'description' => sprintf( __( 'Variation weight (%s).', 'woocommerce' ), $weight_unit ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'dimensions' => array(
'dimensions' => array(
'description' => __( 'Variation dimensions.', 'woocommerce' ),
'type' => 'object',
'context' => array( 'view', 'edit' ),
@ -811,7 +855,7 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'width' => array(
'width' => array(
/* translators: %s: dimension unit */
'description' => sprintf( __( 'Variation width (%s).', 'woocommerce' ), $dimension_unit ),
'type' => 'string',
@ -825,40 +869,40 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
),
),
),
'shipping_class' => array(
'shipping_class' => array(
'description' => __( 'Shipping class slug.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'shipping_class_id' => array(
'shipping_class_id' => array(
'description' => __( 'Shipping class ID.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'image' => array(
'image' => array(
'description' => __( 'Variation image data.', 'woocommerce' ),
'type' => 'object',
'context' => array( 'view', 'edit' ),
'properties' => array(
'id' => array(
'id' => array(
'description' => __( 'Image ID.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'date_created' => array(
'date_created' => array(
'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'date_created_gmt' => array(
'date_created_gmt' => array(
'description' => __( 'The date the image was created, as GMT.', 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'date_modified' => array(
'date_modified' => array(
'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
@ -870,42 +914,42 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'src' => array(
'src' => array(
'description' => __( 'Image URL.', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
'name' => array(
'name' => array(
'description' => __( 'Image name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'alt' => array(
'alt' => array(
'description' => __( 'Image alternative text.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'position' => array(
'position' => array(
'description' => __( 'Image position. 0 means that the image is featured.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
),
),
'attributes' => array(
'attributes' => array(
'description' => __( 'List of attributes.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
'items' => array(
'type' => 'object',
'properties' => array(
'id' => array(
'id' => array(
'description' => __( 'Attribute ID.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'name' => array(
'name' => array(
'description' => __( 'Attribute name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
@ -918,25 +962,25 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
),
),
),
'menu_order' => array(
'menu_order' => array(
'description' => __( 'Menu order, used to custom sort products.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
),
'meta_data' => array(
'meta_data' => array(
'description' => __( 'Meta data.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
'items' => array(
'type' => 'object',
'properties' => array(
'id' => array(
'id' => array(
'description' => __( 'Meta ID.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'key' => array(
'key' => array(
'description' => __( 'Meta key.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),

View File

@ -1740,7 +1740,7 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
),
'shipping_class_id' => array(
'description' => __( 'Shipping class ID.', 'woocommerce' ),
'type' => 'string',
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),

View File

@ -38,15 +38,18 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
* Register the route for /system_status
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
register_rest_route(
$this->namespace, '/' . $this->rest_base,
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
}
/**
@ -69,9 +72,9 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
* @return WP_Error|WP_REST_Response
*/
public function get_items( $request ) {
$schema = $this->get_item_schema();
$mappings = $this->get_item_mappings();
$response = array();
$schema = $this->get_item_schema();
$mappings = $this->get_item_mappings();
$response = array();
foreach ( $mappings as $section => $values ) {
foreach ( $values as $key => $value ) {
@ -99,135 +102,135 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'title' => 'system_status',
'type' => 'object',
'properties' => array(
'environment' => array(
'environment' => array(
'description' => __( 'Environment.', 'woocommerce' ),
'type' => 'object',
'context' => array( 'view' ),
'readonly' => true,
'properties' => array(
'home_url' => array(
'home_url' => array(
'description' => __( 'Home URL.', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view' ),
'readonly' => true,
),
'site_url' => array(
'site_url' => array(
'description' => __( 'Site URL.', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view' ),
'readonly' => true,
),
'wc_version' => array(
'wc_version' => array(
'description' => __( 'WooCommerce version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'log_directory' => array(
'log_directory' => array(
'description' => __( 'Log directory.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'log_directory_writable' => array(
'log_directory_writable' => array(
'description' => __( 'Is log directory writable?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'wp_version' => array(
'wp_version' => array(
'description' => __( 'WordPress version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'wp_multisite' => array(
'wp_multisite' => array(
'description' => __( 'Is WordPress multisite?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'wp_memory_limit' => array(
'wp_memory_limit' => array(
'description' => __( 'WordPress memory limit.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'readonly' => true,
),
'wp_debug_mode' => array(
'wp_debug_mode' => array(
'description' => __( 'Is WordPress debug mode active?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'wp_cron' => array(
'wp_cron' => array(
'description' => __( 'Are WordPress cron jobs enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'language' => array(
'language' => array(
'description' => __( 'WordPress language.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'server_info' => array(
'server_info' => array(
'description' => __( 'Server info.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'php_version' => array(
'php_version' => array(
'description' => __( 'PHP version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'php_post_max_size' => array(
'php_post_max_size' => array(
'description' => __( 'PHP post max size.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'readonly' => true,
),
'php_max_execution_time' => array(
'php_max_execution_time' => array(
'description' => __( 'PHP max execution time.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'readonly' => true,
),
'php_max_input_vars' => array(
'php_max_input_vars' => array(
'description' => __( 'PHP max input vars.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'readonly' => true,
),
'curl_version' => array(
'curl_version' => array(
'description' => __( 'cURL version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'suhosin_installed' => array(
'suhosin_installed' => array(
'description' => __( 'Is SUHOSIN installed?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'max_upload_size' => array(
'max_upload_size' => array(
'description' => __( 'Max upload size.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'readonly' => true,
),
'mysql_version' => array(
'mysql_version' => array(
'description' => __( 'MySQL version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'default_timezone' => array(
'default_timezone' => array(
'description' => __( 'Default timezone.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
@ -239,49 +242,49 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
),
'soapclient_enabled' => array(
'soapclient_enabled' => array(
'description' => __( 'Is SoapClient class enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'domdocument_enabled' => array(
'domdocument_enabled' => array(
'description' => __( 'Is DomDocument class enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'gzip_enabled' => array(
'gzip_enabled' => array(
'description' => __( 'Is GZip enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'mbstring_enabled' => array(
'mbstring_enabled' => array(
'description' => __( 'Is mbstring enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'remote_post_successful' => array(
'remote_post_successful' => array(
'description' => __( 'Remote POST successful?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'remote_post_response' => array(
'remote_post_response' => array(
'description' => __( 'Remote POST response.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'remote_get_successful' => array(
'remote_get_successful' => array(
'description' => __( 'Remote GET successful?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'remote_get_response' => array(
'remote_get_response' => array(
'description' => __( 'Remote GET response.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
@ -289,19 +292,19 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
),
),
),
'database' => array(
'database' => array(
'description' => __( 'Database.', 'woocommerce' ),
'type' => 'object',
'context' => array( 'view' ),
'readonly' => true,
'properties' => array(
'wc_database_version' => array(
'wc_database_version' => array(
'description' => __( 'WC database version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'database_prefix' => array(
'database_prefix' => array(
'description' => __( 'Database prefix.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
@ -313,13 +316,13 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
),
'database_tables' => array(
'database_tables' => array(
'description' => __( 'Database tables.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'string',
'type' => 'string',
),
),
),
@ -330,41 +333,41 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'string',
'type' => 'string',
),
),
'theme' => array(
'theme' => array(
'description' => __( 'Theme.', 'woocommerce' ),
'type' => 'object',
'context' => array( 'view' ),
'readonly' => true,
'properties' => array(
'name' => array(
'name' => array(
'description' => __( 'Theme name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'version' => array(
'version' => array(
'description' => __( 'Theme version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'version_latest' => array(
'version_latest' => array(
'description' => __( 'Latest version of theme.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'author_url' => array(
'author_url' => array(
'description' => __( 'Theme author URL.', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
'context' => array( 'view' ),
'readonly' => true,
),
'is_child_theme' => array(
'is_child_theme' => array(
'description' => __( 'Is this theme a child theme?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
@ -376,40 +379,40 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
),
'has_woocommerce_file' => array(
'has_woocommerce_file' => array(
'description' => __( 'Does the theme have a woocommerce.php file?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'has_outdated_templates' => array(
'has_outdated_templates' => array(
'description' => __( 'Does this theme have outdated templates?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'overrides' => array(
'overrides' => array(
'description' => __( 'Template overrides.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'string',
'type' => 'string',
),
),
'parent_name' => array(
'parent_name' => array(
'description' => __( 'Parent theme name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'parent_version' => array(
'parent_version' => array(
'description' => __( 'Parent theme version.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'parent_author_url' => array(
'parent_author_url' => array(
'description' => __( 'Parent theme author URL.', 'woocommerce' ),
'type' => 'string',
'format' => 'uri',
@ -418,73 +421,73 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
),
),
),
'settings' => array(
'settings' => array(
'description' => __( 'Settings.', 'woocommerce' ),
'type' => 'object',
'context' => array( 'view' ),
'readonly' => true,
'properties' => array(
'api_enabled' => array(
'api_enabled' => array(
'description' => __( 'REST API enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'force_ssl' => array(
'force_ssl' => array(
'description' => __( 'SSL forced?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'currency' => array(
'currency' => array(
'description' => __( 'Currency.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'currency_symbol' => array(
'currency_symbol' => array(
'description' => __( 'Currency symbol.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'currency_position' => array(
'currency_position' => array(
'description' => __( 'Currency position.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'thousand_separator' => array(
'thousand_separator' => array(
'description' => __( 'Thousand separator.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'decimal_separator' => array(
'decimal_separator' => array(
'description' => __( 'Decimal separator.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
'number_of_decimals' => array(
'number_of_decimals' => array(
'description' => __( 'Number of decimals.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view' ),
'readonly' => true,
),
'geolocation_enabled' => array(
'geolocation_enabled' => array(
'description' => __( 'Geolocation enabled?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
'readonly' => true,
),
'taxonomies' => array(
'taxonomies' => array(
'description' => __( 'Taxonomy terms for product/order statuses.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'string',
'type' => 'string',
),
),
'product_visibility_terms' => array(
@ -493,12 +496,12 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'string',
'type' => 'string',
),
),
),
),
'security' => array(
'security' => array(
'description' => __( 'Security.', 'woocommerce' ),
'type' => 'object',
'context' => array( 'view' ),
@ -510,7 +513,7 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
),
'hide_errors' => array(
'hide_errors' => array(
'description' => __( 'Hide errors from visitors?', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view' ),
@ -518,13 +521,13 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
),
),
),
'pages' => array(
'pages' => array(
'description' => __( 'WooCommerce pages.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'string',
'type' => 'string',
),
),
),
@ -573,21 +576,24 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
}
// Test POST requests
$post_response = wp_safe_remote_post( 'https://www.paypal.com/cgi-bin/webscr', array(
'timeout' => 10,
'user-agent' => 'WooCommerce/' . WC()->version,
'httpversion' => '1.1',
'body' => array(
'cmd' => '_notify-validate',
),
) );
$post_response = wp_safe_remote_post(
'https://www.paypal.com/cgi-bin/webscr',
array(
'timeout' => 10,
'user-agent' => 'WooCommerce/' . WC()->version,
'httpversion' => '1.1',
'body' => array(
'cmd' => '_notify-validate',
),
)
);
$post_response_successful = false;
if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) {
$post_response_successful = true;
}
// Test GET requests
$get_response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) );
$get_response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) );
$get_response_successful = false;
if ( ! is_wp_error( $post_response ) && $post_response['response']['code'] >= 200 && $post_response['response']['code'] < 300 ) {
$get_response_successful = true;
@ -597,7 +603,7 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
return array(
'home_url' => get_option( 'home' ),
'site_url' => get_option( 'siteurl' ),
'version' => WC()->version,
'version' => WC()->version,
'log_directory' => WC_LOG_DIR,
'log_directory_writable' => ( @fopen( WC_LOG_DIR . 'test-log.log', 'a' ) ? true : false ),
'wp_version' => get_bloginfo( 'version' ),
@ -606,6 +612,7 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'wp_debug_mode' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
'wp_cron' => ! ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ),
'language' => get_locale(),
'external_object_cache' => wp_using_ext_object_cache(),
'server_info' => $_SERVER['SERVER_SOFTWARE'],
'php_version' => phpversion(),
'php_post_max_size' => wc_let_to_num( ini_get( 'post_max_size' ) ),
@ -647,33 +654,39 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
public function get_database_info() {
global $wpdb;
$database_table_sizes = $wpdb->get_results( $wpdb->prepare( "
SELECT
table_name AS 'name',
round( ( data_length / 1024 / 1024 ), 2 ) 'data',
round( ( index_length / 1024 / 1024 ), 2 ) 'index'
FROM information_schema.TABLES
WHERE table_schema = %s
ORDER BY name ASC;
", DB_NAME ) );
$database_table_sizes = $wpdb->get_results(
$wpdb->prepare(
"SELECT
table_name AS 'name',
round( ( data_length / 1024 / 1024 ), 2 ) 'data',
round( ( index_length / 1024 / 1024 ), 2 ) 'index'
FROM information_schema.TABLES
WHERE table_schema = %s
ORDER BY name ASC;",
DB_NAME
)
);
// WC Core tables to check existence of
$core_tables = apply_filters( 'woocommerce_database_tables', array(
'woocommerce_sessions',
'woocommerce_api_keys',
'woocommerce_attribute_taxonomies',
'woocommerce_downloadable_product_permissions',
'woocommerce_order_items',
'woocommerce_order_itemmeta',
'woocommerce_tax_rates',
'woocommerce_tax_rate_locations',
'woocommerce_shipping_zones',
'woocommerce_shipping_zone_locations',
'woocommerce_shipping_zone_methods',
'woocommerce_payment_tokens',
'woocommerce_payment_tokenmeta',
'woocommerce_log',
) );
$core_tables = apply_filters(
'woocommerce_database_tables',
array(
'woocommerce_sessions',
'woocommerce_api_keys',
'woocommerce_attribute_taxonomies',
'woocommerce_downloadable_product_permissions',
'woocommerce_order_items',
'woocommerce_order_itemmeta',
'woocommerce_tax_rates',
'woocommerce_tax_rate_locations',
'woocommerce_shipping_zones',
'woocommerce_shipping_zone_locations',
'woocommerce_shipping_zone_methods',
'woocommerce_payment_tokens',
'woocommerce_payment_tokenmeta',
'woocommerce_log',
)
);
if ( get_option( 'db_version' ) < 34370 ) {
$core_tables[] = 'woocommerce_termmeta';
@ -693,12 +706,12 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
*/
$tables = array(
'woocommerce' => array_fill_keys( $core_tables, false ),
'other' => array()
'other' => array(),
);
$database_size = array(
'data' => 0,
'index' => 0
'data' => 0,
'index' => 0,
);
foreach ( $database_table_sizes as $table ) {
@ -706,11 +719,11 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
$tables[ $table_type ][ $table->name ] = array(
'data' => $table->data,
'index' => $table->index
'index' => $table->index,
);
$database_size[ 'data' ] += $table->data;
$database_size[ 'index' ] += $table->index;
$database_size['data'] += $table->data;
$database_size['index'] += $table->index;
}
// Return all database info. Described by JSON Schema.
@ -742,8 +755,8 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
* @return array
*/
public function get_active_plugins() {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
require_once( ABSPATH . 'wp-admin/includes/update.php' );
require_once ABSPATH . 'wp-admin/includes/plugin.php';
require_once ABSPATH . 'wp-admin/includes/update.php';
if ( ! function_exists( 'get_plugin_updates' ) ) {
return array();
@ -774,10 +787,15 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
if ( ! empty( $cl_lines ) ) {
foreach ( $cl_lines as $line_num => $cl_line ) {
if ( preg_match( '/^[0-9]/', $cl_line ) ) {
$date = str_replace( '.' , '-' , trim( substr( $cl_line , 0 , strpos( $cl_line , '-' ) ) ) );
$version = preg_replace( '~[^0-9,.]~' , '' ,stristr( $cl_line , "version" ) );
$update = trim( str_replace( "*" , "" , $cl_lines[ $line_num + 1 ] ) );
$version_data = array( 'date' => $date , 'version' => $version , 'update' => $update , 'changelog' => $changelog );
$date = str_replace( '.', '-', trim( substr( $cl_line, 0, strpos( $cl_line, '-' ) ) ) );
$version = preg_replace( '~[^0-9,.]~', '', stristr( $cl_line, 'version' ) );
$update = trim( str_replace( '*', '', $cl_lines[ $line_num + 1 ] ) );
$version_data = array(
'date' => $date,
'version' => $version,
'update' => $update,
'changelog' => $changelog,
);
set_transient( md5( $plugin ) . '_version_data', $version_data, DAY_IN_SECONDS );
break;
}
@ -825,7 +843,12 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
'parent_author_url' => $parent_theme->{'Author URI'},
);
} else {
$parent_theme_info = array( 'parent_name' => '', 'parent_version' => '', 'parent_version_latest' => '', 'parent_author_url' => '' );
$parent_theme_info = array(
'parent_name' => '',
'parent_version' => '',
'parent_version_latest' => '',
'parent_author_url' => '',
);
}
/**
@ -966,8 +989,8 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
$pages_output = array();
foreach ( $check_pages as $page_name => $values ) {
$page_id = get_option( $values['option'] );
$page_set = $page_exists = $page_visible = false;
$page_id = get_option( $values['option'] );
$page_set = $page_exists = $page_visible = false;
$shortcode_present = $shortcode_required = false;
// Page checks
@ -982,9 +1005,9 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
}
// Shortcode checks
if ( $values['shortcode'] && get_post( $page_id ) ) {
if ( $values['shortcode'] && get_post( $page_id ) ) {
$shortcode_required = true;
$page = get_post( $page_id );
$page = get_post( $page_id );
if ( strstr( $page->post_content, $values['shortcode'] ) ) {
$shortcode_present = true;
}
@ -1020,7 +1043,7 @@ class WC_REST_System_Status_Controller extends WC_REST_Controller {
/**
* Prepare the system status response
*
* @param array $system_status
* @param array $system_status
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response Response data.
*/

View File

@ -4,15 +4,11 @@
*
* Handles requests to the /system_status/tools/* endpoints.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 3.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
/**
* @package WooCommerce/API
@ -179,8 +175,18 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller {
'button' => __( 'Reset', 'woocommerce' ),
'desc' => __( 'This will reset your usage tracking settings, causing it to show the opt-in banner again and not sending any data.', 'woocommerce' ),
),
'regenerate_thumbnails' => array(
'name' => __( 'Regenerate shop thumbnails', 'woocommerce' ),
'button' => __( 'Regenerate', 'woocommerce' ),
'desc' => __( 'This will regenerate all shop thumbnails to match your theme and/or image settings.', 'woocommerce' ),
)
);
// Jetpack does the image resizing heavy lifting so you don't have to.
if ( ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) || ! apply_filters( 'woocommerce_background_image_regeneration', true ) ) {
unset( $tools['regenerate_thumbnails'] );
}
return apply_filters( 'woocommerce_debug_tools', $tools );
}
@ -468,6 +474,11 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller {
$message = __( 'Usage tracking settings successfully reset.', 'woocommerce' );
break;
case 'regenerate_thumbnails':
WC_Regenerate_Images::queue_image_regeneration();
$message = __( 'Thumbnail regeneration has been scheduled to run in the background.', 'woocommerce' );
break;
default:
$tools = $this->get_tools();
if ( isset( $tools[ $tool ]['callback'] ) ) {

View File

@ -2029,7 +2029,7 @@ class WC_REST_Products_V1_Controller extends WC_REST_Posts_Controller {
),
'shipping_class_id' => array(
'description' => __( 'Shipping class ID.', 'woocommerce' ),
'type' => 'string',
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
@ -2471,7 +2471,7 @@ class WC_REST_Products_V1_Controller extends WC_REST_Posts_Controller {
),
'shipping_class_id' => array(
'description' => __( 'Shipping class ID.', 'woocommerce' ),
'type' => 'string',
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),

View File

@ -290,6 +290,25 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
return $response;
}
/**
* Get a single item.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|WP_REST_Response
*/
public function get_item( $request ) {
$id = (int) $request['id'];
if ( empty( $id ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$data = $this->prepare_item_for_response( $id, $request );
$response = rest_ensure_response( $data );
return $response;
}
/**
* Create a single webhook.
*

View File

@ -1126,19 +1126,25 @@ class WC_AJAX {
if ( $_product && $_product->exists() && $_product->managing_stock() && isset( $order_item_qty[ $item_id ] ) && $order_item_qty[ $item_id ] > 0 ) {
$stock_change = apply_filters( 'woocommerce_reduce_order_stock_quantity', $order_item_qty[ $item_id ], $item_id );
$new_stock = wc_update_product_stock( $_product, $stock_change, 'decrease' );
$item_name = $_product->get_sku() ? $_product->get_sku() : $_product->get_id();
$note = sprintf( __( 'Item %1$s stock reduced from %2$s to %3$s.', 'woocommerce' ), $item_name, $new_stock + $stock_change, $new_stock );
$return[] = $note;
$order->add_order_note( $note );
$item_name = $_product->get_formatted_name();
$return[] = array(
'note' => sprintf( wp_kses_post( __( '%1$s stock reduced from %2$s to %3$s.', 'woocommerce' ) ), $item_name, $new_stock + $stock_change, $new_stock ),
'success' => true,
);
}
}
do_action( 'woocommerce_reduce_order_stock', $order );
if ( empty( $return ) ) {
$return[] = __( 'No products had their stock reduced - they may not have stock management enabled.', 'woocommerce' );
$return[] = array(
'note' => wp_kses_post( __( 'No products had their stock reduced - they may not have stock management enabled.', 'woocommerce' ) ),
'success' => false,
);
}
echo wp_kses_post( implode( ', ', $return ) );
wp_send_json_success( $return );
}
wp_die();
wp_send_json_error();
}
/**
@ -1166,19 +1172,24 @@ class WC_AJAX {
$old_stock = $_product->get_stock_quantity();
$stock_change = apply_filters( 'woocommerce_restore_order_stock_quantity', $order_item_qty[ $item_id ], $item_id );
$new_quantity = wc_update_product_stock( $_product, $stock_change, 'increase' );
$item_name = $_product->get_sku() ? $_product->get_sku() : $_product->get_id();
$note = sprintf( __( 'Item %1$s stock increased from %2$s to %3$s.', 'woocommerce' ), $item_name, $old_stock, $new_quantity );
$return[] = $note;
$order->add_order_note( $note );
$item_name = $_product->get_formatted_name();
$return[] = array(
'note' => sprintf( wp_kses_post( __( '%1$s stock increased from %2$s to %3$s.', 'woocommerce' ) ), $item_name, $old_stock, $new_quantity ),
'success' => true,
);
}
}
do_action( 'woocommerce_restore_order_stock', $order );
if ( empty( $return ) ) {
$return[] = __( 'No products had their stock increased - they may not have stock management enabled.', 'woocommerce' );
$return[] = array(
'note' => wp_kses_post( __( 'No products had their stock increased - they may not have stock management enabled.', 'woocommerce' ) ),
'success' => false,
);
}
echo wp_kses_post( implode( ', ', $return ) );
wp_send_json_success( $return );
}
wp_die();
wp_send_json_error();
}
/**
@ -2438,7 +2449,7 @@ class WC_AJAX {
'instance_id' => $instance_id,
'zone_id' => $zone->get_id(),
'zone_name' => $zone->get_zone_name(),
'methods' => $zone->get_shipping_methods(),
'methods' => $zone->get_shipping_methods( false, 'json' ),
) );
}
@ -2536,7 +2547,7 @@ class WC_AJAX {
wp_send_json_success( array(
'zone_id' => $zone->get_id(),
'zone_name' => $zone->get_zone_name(),
'methods' => $zone->get_shipping_methods(),
'methods' => $zone->get_shipping_methods( false, 'json' ),
) );
}
@ -2568,7 +2579,7 @@ class WC_AJAX {
wp_send_json_success( array(
'zone_id' => $zone->get_id(),
'zone_name' => $zone->get_zone_name(),
'methods' => $zone->get_shipping_methods(),
'methods' => $zone->get_shipping_methods( false, 'json' ),
'errors' => $shipping_method->get_errors(),
) );
}

View File

@ -144,7 +144,13 @@ class WC_Breadcrumb {
if ( 'product' === get_post_type( $post ) ) {
$this->prepend_shop_page();
if ( $terms = wc_get_product_terms( $post->ID, 'product_cat', array( 'orderby' => 'parent', 'order' => 'DESC' ) ) ) {
$terms = wc_get_product_terms( $post->ID, 'product_cat', apply_filters( 'woocommerce_breadcrumb_product_terms_args', array(
'orderby' => 'parent',
'order' => 'DESC',
) ) );
if ( $terms ) {
$main_term = apply_filters( 'woocommerce_breadcrumb_main_term', $terms[0], $terms );
$this->term_ancestors( $main_term->term_id, 'product_cat' );
$this->add_crumb( $main_term->name, get_term_link( $main_term ) );

View File

@ -71,12 +71,18 @@ final class WC_Cart_Session {
$this->cart->set_coupon_discount_tax_totals( WC()->session->get( 'coupon_discount_tax_totals', array() ) );
$this->cart->set_removed_cart_contents( WC()->session->get( 'removed_cart_contents', array() ) );
if ( is_null( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), true ) ) ) { // @codingStandardsIgnoreLine
if ( apply_filters( 'woocommerce_persistent_cart_enabled', true ) ) {
$saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), true );
} else {
$saved_cart = false;
}
if ( is_null( $cart ) && $saved_cart ) {
$cart = $saved_cart['cart'];
$update_cart_session = true;
} elseif ( is_null( $cart ) ) {
$cart = array();
} elseif ( is_array( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), true ) ) ) { // @codingStandardsIgnoreLine
} elseif ( is_array( $cart ) && $saved_cart ) {
$cart = array_merge( $saved_cart['cart'], $cart );
$update_cart_session = true;
}
@ -184,7 +190,7 @@ final class WC_Cart_Session {
* Save the persistent cart when the cart is updated.
*/
public function persistent_cart_update() {
if ( get_current_user_id() ) {
if ( get_current_user_id() && apply_filters( 'woocommerce_persistent_cart_enabled', true ) ) {
update_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), array(
'cart' => $this->get_cart_for_session(),
) );
@ -195,7 +201,7 @@ final class WC_Cart_Session {
* Delete the persistent cart permanently.
*/
public function persistent_cart_destroy() {
if ( get_current_user_id() ) {
if ( get_current_user_id() && apply_filters( 'woocommerce_persistent_cart_enabled', true ) ) {
delete_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id() );
}
}

View File

@ -153,14 +153,14 @@ class WC_Checkout {
* Cloning is forbidden.
*/
public function __clone() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Cloning is forbidden.', 'woocommerce' ), '2.1' );
}
/**
* Unserializing instances of this class is forbidden.
*/
public function __wakeup() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Unserializing instances of this class is forbidden.', 'woocommerce' ), '2.1' );
}
/**

View File

@ -115,6 +115,7 @@ class WC_Countries {
'GF' => array(),
'IS' => array(),
'IL' => array(),
'IM' => array(),
'KR' => array(),
'KW' => array(),
'LB' => array(),
@ -926,6 +927,11 @@ class WC_Countries {
'required' => false,
),
),
'IM' => array(
'state' => array(
'required' => false,
),
),
'IT' => array(
'postcode' => array(
'priority' => 65,

View File

@ -459,13 +459,21 @@ class WC_Coupon extends WC_Legacy_Coupon {
* @throws WC_Data_Exception
*/
public function set_amount( $amount ) {
$amount = wc_format_decimal( $amount );
if ( ! is_numeric( $amount ) ) {
$amount = 0;
}
if ( $amount < 0 ) {
$this->error( 'coupon_invalid_amount', __( 'Invalid discount amount', 'woocommerce' ) );
}
if ( 'percent' === $this->get_discount_type() && $amount > 100 ) {
$this->error( 'coupon_invalid_amount', __( 'Invalid discount amount', 'woocommerce' ) );
}
$this->set_prop( 'amount', wc_format_decimal( $amount ) );
$this->set_prop( 'amount', $amount );
}
/**

View File

@ -749,11 +749,11 @@ class WC_Customer extends WC_Legacy_Customer {
* Set customer's display name.
*
* @since 3.1.0
* @param string $display_name
* @throws WC_Data_Exception
* @param string $display_name Display name.
*/
public function set_display_name( $display_name ) {
$this->set_prop( 'display_name', $display_name );
/* translators: 1: first name 2: last name */
$this->set_prop( 'display_name', is_email( $display_name ) ? sprintf( __( '%1$s %2$s', 'display name', 'woocommerce' ), $this->get_first_name(), $this->get_last_name() ) : $display_name );
}
/**

View File

@ -362,8 +362,7 @@ class WC_Discounts {
$limit_usage_qty = $coupon->get_limit_usage_to_x_items();
}
// Because get_amount() could return an empty string, let's be sure to set our local variable to a known good value.
$coupon_amount = ( '' === $coupon->get_amount() ) ? 0 : $coupon->get_amount();
$coupon_amount = $coupon->get_amount();
foreach ( $items_to_apply as $item ) {
// Find out how much price is available to discount for the item.
@ -420,7 +419,7 @@ class WC_Discounts {
*/
protected function apply_coupon_fixed_product( $coupon, $items_to_apply, $amount = null ) {
$total_discount = 0;
$amount = $amount ? $amount: wc_add_number_precision( $coupon->get_amount() );
$amount = $amount ? $amount : wc_add_number_precision( $coupon->get_amount() );
$limit_usage_qty = 0;
$applied_count = 0;

View File

@ -21,7 +21,7 @@ class WC_Download_Handler {
* Hook in methods.
*/
public static function init() {
if ( isset( $_GET['download_file'], $_GET['order'], $_GET['email'] ) ) {
if ( isset( $_GET['download_file'], $_GET['order'] ) && ( isset( $_GET['email'] ) || isset( $_GET['uid'] ) ) ) {
add_action( 'init', array( __CLASS__, 'download_product' ) );
}
add_action( 'woocommerce_download_file_redirect', array( __CLASS__, 'download_file_redirect' ), 10, 2 );
@ -41,8 +41,26 @@ class WC_Download_Handler {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
// Fallback, accept email address if it's passed.
if ( empty( $_GET['email'] ) && empty( $_GET['uid'] ) ) {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
if ( isset( $_GET['email'] ) ) {
$email_address = $_GET['email'];
} else {
// Get email address from order to verify hash.
$order_id = wc_get_order_id_by_order_key( $_GET['order'] );
$order = wc_get_order( $order_id );
$email_address = is_a( $order, 'WC_Order' ) ? $order->get_billing_email() : null;
if ( is_null( $email_address ) || ! hash_equals( $_GET['uid'], hash( 'sha256', $email_address ) ) ) {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
}
$download_ids = $data_store->get_downloads( array(
'user_email' => sanitize_email( str_replace( ' ', '+', $_GET['email'] ) ),
'user_email' => sanitize_email( str_replace( ' ', '+', $email_address ) ),
'order_key' => wc_clean( $_GET['order'] ),
'product_id' => $product_id,
'download_id' => wc_clean( preg_replace( '/\s+/', ' ', $_GET['key'] ) ),

View File

@ -50,7 +50,7 @@ class WC_Emails {
* @since 2.1
*/
public function __clone() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Cloning is forbidden.', 'woocommerce' ), '2.1' );
}
/**
@ -59,7 +59,7 @@ class WC_Emails {
* @since 2.1
*/
public function __wakeup() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Unserializing instances of this class is forbidden.', 'woocommerce' ), '2.1' );
}
/**

View File

@ -188,32 +188,39 @@ class WC_Form_Handler {
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'] : '';
$save_pass = true;
// Current user data.
$current_user = get_user_by( 'id', $user_id );
$current_first_name = $current_user->first_name;
$current_last_name = $current_user->last_name;
$current_email = $current_user->user_email;
$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_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'] : '';
$save_pass = true;
// 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;
// Prevent emails being displayed, or leave alone.
$user->display_name = is_email( $current_user->display_name ) ? $user->first_name : $current_user->display_name;
// Prevent display name to be changed to email.
if ( is_email( $account_display_name ) ) {
wc_add_notice( __( 'Display name cannot be changed to email address due to privacy concern.', 'woocommerce' ), 'error' );
}
// 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_email' => __( 'Email address', 'woocommerce' ),
'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 ) {

View File

@ -170,7 +170,7 @@ class WC_Frontend_Scripts {
'flexslider' => array(
'src' => self::get_asset_url( 'assets/js/flexslider/jquery.flexslider' . $suffix . '.js' ),
'deps' => array( 'jquery' ),
'version' => '2.6.1',
'version' => '2.7.0',
),
'js-cookie' => array(
'src' => self::get_asset_url( 'assets/js/js-cookie/js.cookie' . $suffix . '.js' ),

View File

@ -2,8 +2,6 @@
/**
* Installation related functions and actions.
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Classes
* @version 3.0.0
*/
@ -141,7 +139,7 @@ class WC_Install {
* This check is done on all requests and runs if the versions do not match.
*/
public static function check_version() {
if ( ! defined( 'IFRAME_REQUEST' ) && get_option( 'woocommerce_version' ) !== WC()->version ) {
if ( ! defined( 'IFRAME_REQUEST' ) && version_compare( get_option( 'woocommerce_version' ), WC()->version, '<' ) ) {
self::install();
do_action( 'woocommerce_updated' );
}
@ -541,6 +539,8 @@ class WC_Install {
* Changing indexes may cause duplicate index notices in logs due to https://core.trac.wordpress.org/ticket/34870 but dropping
* indexes first causes too much load on some servers/larger DB.
*
* When adding or removing a table, make sure to update the list of tables in WC_Install::get_tables().
*
* @return string
*/
private static function get_schema() {
@ -747,6 +747,67 @@ CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
return $tables;
}
/**
* Return a list of WooCommerce tables. Used to make sure all WC tables are dropped when uninstalling the plugin
* in a single site or multi site environment.
*
* @return array WC tables.
*/
public static function get_tables() {
global $wpdb;
$tables = array(
"{$wpdb->prefix}wc_download_log",
"{$wpdb->prefix}wc_webhooks",
"{$wpdb->prefix}woocommerce_api_keys",
"{$wpdb->prefix}woocommerce_attribute_taxonomies",
"{$wpdb->prefix}woocommerce_downloadable_product_permissions",
"{$wpdb->prefix}woocommerce_log",
"{$wpdb->prefix}woocommerce_order_itemmeta",
"{$wpdb->prefix}woocommerce_order_items",
"{$wpdb->prefix}woocommerce_payment_tokenmeta",
"{$wpdb->prefix}woocommerce_payment_tokens",
"{$wpdb->prefix}woocommerce_sessions",
"{$wpdb->prefix}woocommerce_shipping_zone_locations",
"{$wpdb->prefix}woocommerce_shipping_zone_methods",
"{$wpdb->prefix}woocommerce_shipping_zones",
"{$wpdb->prefix}woocommerce_tax_rate_locations",
"{$wpdb->prefix}woocommerce_tax_rates",
);
if ( ! function_exists( 'get_term_meta' ) ) {
// This table is only needed for old installs and is now @deprecated by WordPress term meta.
$tables[] = "{$wpdb->prefix}woocommerce_termmeta";
}
return $tables;
}
/**
* Drop WooCommerce tables.
*
* @return void
*/
public static function drop_tables() {
global $wpdb;
$tables = self::get_tables();
foreach ( $tables as $table ) {
$wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
}
}
/**
* Uninstall tables when MU blog is deleted.
*
* @param array $tables List of tables that will be deleted by WP.
* @return string[]
*/
public static function wpmu_drop_tables( $tables ) {
return array_merge( $tables, self::get_tables() );
}
/**
* Create roles and capabilities.
*/
@ -983,32 +1044,6 @@ CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
return (array) $links;
}
/**
* Uninstall tables when MU blog is deleted.
*
* @param array $tables List of tables that will be deleted by WP.
* @return string[]
*/
public static function wpmu_drop_tables( $tables ) {
global $wpdb;
$tables[] = $wpdb->prefix . 'woocommerce_sessions';
$tables[] = $wpdb->prefix . 'woocommerce_api_keys';
$tables[] = $wpdb->prefix . 'woocommerce_attribute_taxonomies';
$tables[] = $wpdb->prefix . 'woocommerce_downloadable_product_permissions';
$tables[] = $wpdb->prefix . 'woocommerce_termmeta';
$tables[] = $wpdb->prefix . 'woocommerce_tax_rates';
$tables[] = $wpdb->prefix . 'woocommerce_tax_rate_locations';
$tables[] = $wpdb->prefix . 'woocommerce_order_items';
$tables[] = $wpdb->prefix . 'woocommerce_order_itemmeta';
$tables[] = $wpdb->prefix . 'woocommerce_payment_tokens';
$tables[] = $wpdb->prefix . 'woocommerce_shipping_zones';
$tables[] = $wpdb->prefix . 'woocommerce_shipping_zone_locations';
$tables[] = $wpdb->prefix . 'woocommerce_shipping_zone_methods';
return $tables;
}
/**
* Get slug from path
*

View File

@ -96,7 +96,13 @@ class WC_Order_Item_Product extends WC_Order_Item {
* @throws WC_Data_Exception
*/
public function set_subtotal( $value ) {
$this->set_prop( 'subtotal', wc_format_decimal( $value ) );
$value = wc_format_decimal( $value );
if ( ! is_numeric( $value ) ) {
$value = 0;
}
$this->set_prop( 'subtotal', $value );
}
/**
@ -106,7 +112,13 @@ class WC_Order_Item_Product extends WC_Order_Item {
* @throws WC_Data_Exception
*/
public function set_total( $value ) {
$this->set_prop( 'total', wc_format_decimal( $value ) );
$value = wc_format_decimal( $value );
if ( ! is_numeric( $value ) ) {
$value = 0;
}
$this->set_prop( 'total', $value );
// Subtotal cannot be less than total
if ( '' === $this->get_subtotal() || $this->get_subtotal() < $this->get_total() ) {
@ -375,7 +387,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
$files[ $download_id ]['download_url'] = add_query_arg( array(
'download_file' => $product_id,
'order' => $order->get_order_key(),
'email' => urlencode( $order->get_billing_email() ),
'uid' => hash( 'sha256', $order->get_billing_email() ),
'key' => $download_id,
), trailingslashit( home_url() ) );
}

View File

@ -2,14 +2,11 @@
/**
* Regular order
*
* @author Automattic
* @package WooCommerce\Classes
* @version 2.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
defined( 'ABSPATH' ) || exit;
/**
* Order Class.
@ -1377,6 +1374,10 @@ class WC_Order extends WC_Abstract_Order {
'order_key' => $this->get_order_key(),
'downloads_remaining' => $file['downloads_remaining'],
'access_expires' => $file['access_expires'],
'file' => array(
'name' => $file['name'],
'file' => $file['file'],
),
);
}
}
@ -1402,31 +1403,42 @@ class WC_Order extends WC_Abstract_Order {
* Orders which only contain virtual, downloadable items do not need admin
* intervention.
*
* Uses a transient so these calls are not repeated multiple times, and because
* once the order is processed this code/transient does not need to persist.
*
* @since 3.0.0
* @return bool
*/
public function needs_processing() {
$needs_processing = false;
$transient_name = 'wc_order_' . $this->get_id() . '_needs_processing';
$needs_processing = get_transient( $transient_name );
if ( count( $this->get_items() ) > 0 ) {
foreach ( $this->get_items() as $item ) {
if ( $item->is_type( 'line_item' ) ) {
$product = $item->get_product();
if ( ! $product ) {
continue;
}
if ( false === $needs_processing ) {
$needs_processing = 0;
$virtual_downloadable_item = $product->is_downloadable() && $product->is_virtual();
if ( count( $this->get_items() ) > 0 ) {
foreach ( $this->get_items() as $item ) {
if ( $item->is_type( 'line_item' ) ) {
$product = $item->get_product();
if ( apply_filters( 'woocommerce_order_item_needs_processing', ! $virtual_downloadable_item, $product, $this->get_id() ) ) {
$needs_processing = true;
break;
if ( ! $product ) {
continue;
}
$virtual_downloadable_item = $product->is_downloadable() && $product->is_virtual();
if ( apply_filters( 'woocommerce_order_item_needs_processing', ! $virtual_downloadable_item, $product, $this->get_id() ) ) {
$needs_processing = 1;
break;
}
}
}
}
set_transient( $transient_name, $needs_processing, DAY_IN_SECONDS );
}
return $needs_processing;
return 1 === absint( $needs_processing );
}
/*

View File

@ -48,7 +48,7 @@ class WC_Payment_Gateways {
* @since 2.1
*/
public function __clone() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Cloning is forbidden.', 'woocommerce' ), '2.1' );
}
/**
@ -57,7 +57,7 @@ class WC_Payment_Gateways {
* @since 2.1
*/
public function __wakeup() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Unserializing instances of this class is forbidden.', 'woocommerce' ), '2.1' );
}
/**

View File

@ -265,8 +265,8 @@ class WC_Post_types {
}
// If theme support changes, we may need to flush permalinks since some are changed based on this flag.
if ( update_option( 'current_theme_supports_woocommerce', current_theme_supports( 'woocommerce' ) ? 1 : 0 ) ) {
add_option( 'woocommerce_queue_flush_rewrite_rules', 'true' );
if ( update_option( 'current_theme_supports_woocommerce', current_theme_supports( 'woocommerce' ) ? 'yes' : 'no' ) ) {
update_option( 'woocommerce_queue_flush_rewrite_rules', 'yes' );
}
register_post_type( 'product',
@ -511,8 +511,8 @@ class WC_Post_types {
* @since 3.3.0
*/
public static function maybe_flush_rewrite_rules() {
if ( 'true' === get_option( 'woocommerce_queue_flush_rewrite_rules' ) ) {
delete_option( 'woocommerce_queue_flush_rewrite_rules' );
if ( 'yes' === get_option( 'woocommerce_queue_flush_rewrite_rules' ) ) {
update_option( 'woocommerce_queue_flush_rewrite_rules', 'no' );
self::flush_rewrite_rules();
}
}

View File

@ -96,7 +96,7 @@ class WC_Product_Download implements ArrayAccess {
$file_url = $this->get_file();
if ( '..' === substr( $file_url, 0, 2 ) || '/' !== substr( $file_url, 0, 1 ) ) {
$file_url = realpath( ABSPATH . $file_url );
} elseif ( '/wp-content' === substr( $file_url, 0, 11 ) ) {
} elseif ( substr( WP_CONTENT_DIR, strlen( untrailingslashit( ABSPATH ) ) ) === substr( $file_url, 0, strlen( substr( WP_CONTENT_DIR, strlen( untrailingslashit( ABSPATH ) ) ) ) ) ) {
$file_url = realpath( WP_CONTENT_DIR . substr( $file_url, 11 ) );
}
return apply_filters( 'woocommerce_downloadable_file_exists', file_exists( $file_url ), $this->get_file() );

View File

@ -272,8 +272,8 @@ class WC_Product_Variable extends WC_Product {
continue;
}
// Filter 'woocommerce_hide_invisible_variations' to optionally hide invisible variations (disabled variations and variations with empty price)
if ( apply_filters( 'woocommerce_hide_invisible_variations', false, $this->get_id(), $variation ) && ! $variation->variation_is_visible() ) {
// Filter 'woocommerce_hide_invisible_variations' to optionally hide invisible variations (disabled variations and variations with empty price).
if ( apply_filters( 'woocommerce_hide_invisible_variations', true, $this->get_id(), $variation ) && ! $variation->variation_is_visible() ) {
continue;
}

View File

@ -473,7 +473,7 @@ class WC_Product_Variation extends WC_Product_Simple {
* @return bool
*/
public function is_purchasable() {
return apply_filters( 'woocommerce_variation_is_purchasable', $this->variation_is_visible() && parent::is_purchasable(), $this );
return apply_filters( 'woocommerce_variation_is_purchasable', $this->variation_is_visible() && parent::is_purchasable() && ( 'publish' === $this->parent_data['status'] || current_user_can( 'edit_post', $this->get_parent_id() ) ), $this );
}
/**

View File

@ -39,6 +39,15 @@ class WC_Regenerate_Images_Request extends WC_Background_Process {
parent::__construct();
}
/**
* Is job running?
*
* @return boolean
*/
public function is_running() {
return $this->is_queue_empty();
}
/**
* Limit each task ran per batch to 1 for image regen.
*
@ -132,6 +141,16 @@ class WC_Regenerate_Images_Request extends WC_Background_Process {
$new_metadata['sizes'][ $old_size ] = $old_metadata['sizes'][ $old_size ];
}
}
// Handle legacy sizes.
if ( isset( $new_metadata['sizes']['shop_thumbnail'], $new_metadata['sizes']['woocommerce_gallery_thumbnail'] ) ) {
$new_metadata['sizes']['shop_thumbnail'] = $new_metadata['sizes']['woocommerce_gallery_thumbnail'];
}
if ( isset( $new_metadata['sizes']['shop_catalog'], $new_metadata['sizes']['woocommerce_thumbnail'] ) ) {
$new_metadata['sizes']['shop_catalog'] = $new_metadata['sizes']['woocommerce_thumbnail'];
}
if ( isset( $new_metadata['sizes']['shop_single'], $new_metadata['sizes']['woocommerce_single'] ) ) {
$new_metadata['sizes']['shop_single'] = $new_metadata['sizes']['woocommerce_single'];
}
}
// Update the meta data with the new size values.
@ -213,7 +232,7 @@ class WC_Regenerate_Images_Request extends WC_Background_Process {
* @return array
*/
public function adjust_intermediate_image_sizes( $sizes ) {
return apply_filters( 'woocommerce_regenerate_images_intermediate_image_sizes', array( 'woocommerce_thumbnail', 'woocommerce_thumbnail_2x', 'woocommerce_single' ) );
return apply_filters( 'woocommerce_regenerate_images_intermediate_image_sizes', array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single' ) );
}
/**

View File

@ -23,24 +23,166 @@ class WC_Regenerate_Images {
*/
protected static $background_process;
/**
* Stores size being generated on the fly.
*
* @var string
*/
protected static $regenerate_size;
/**
* Init function
*/
public static function init() {
include_once WC_ABSPATH . 'includes/class-wc-regenerate-images-request.php';
self::$background_process = new WC_Regenerate_Images_Request();
add_action( 'image_get_intermediate_size', array( __CLASS__, 'filter_image_get_intermediate_size' ), 10, 3 );
add_filter( 'wp_generate_attachment_metadata', array( __CLASS__, 'add_uncropped_metadata' ) );
if ( ! is_admin() ) {
// Handle on-the-fly image resizing.
// Resize WooCommerce images on the fly when browsing site through customizer as to showcase image setting changes in real time.
if ( is_customize_preview() ) {
add_filter( 'wp_get_attachment_image_src', array( __CLASS__, 'maybe_resize_image' ), 10, 4 );
}
// Not required when Jetpack Photon is in use.
if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) {
return;
}
if ( apply_filters( 'woocommerce_background_image_regeneration', true ) ) {
// Actions to handle image generation when settings change.
add_action( 'update_option_woocommerce_thumbnail_cropping', array( __CLASS__, 'maybe_regenerate_images_option_update' ), 10, 3 );
add_action( 'update_option_woocommerce_thumbnail_image_width', array( __CLASS__, 'maybe_regenerate_images_option_update' ), 10, 3 );
add_action( 'update_option_woocommerce_single_image_width', array( __CLASS__, 'maybe_regenerate_images_option_update' ), 10, 3 );
add_action( 'after_switch_theme', array( __CLASS__, 'maybe_regenerate_image_theme_switch' ) );
include_once WC_ABSPATH . 'includes/class-wc-regenerate-images-request.php';
self::$background_process = new WC_Regenerate_Images_Request();
add_action( 'admin_init', array( __CLASS__, 'regenerating_notice' ) );
add_action( 'woocommerce_hide_regenerating_thumbnails_notice', array( __CLASS__, 'dismiss_regenerating_notice' ) );
// Regenerate thumbnails in the background after settings changes. Not ran on multisite to avoid multiple simultanious jobs.
if ( ! is_multisite() ) {
add_action( 'customize_save_after', array( __CLASS__, 'maybe_regenerate_images' ) );
add_action( 'after_switch_theme', array( __CLASS__, 'maybe_regenerate_images' ) );
}
}
}
/**
* If an intermediate size meta differs from the actual image size (settings were changed?) return false so the wrong size is not used.
*
* @param array $data Size data.
* @param int $attachment_id Attachment ID.
* @param string $size Size name.
* @return array
*/
public static function filter_image_get_intermediate_size( $data, $attachment_id, $size ) {
if ( ! is_string( $size ) || ! in_array( $size, apply_filters( 'woocommerce_image_sizes_to_resize', array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single', 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ), true ) ) {
return $data;
}
// If we don't have sizes, we cannot proceed.
if ( ! isset( $data['width'], $data['height'] ) ) {
return $data;
}
// See if the image size has changed from our settings.
if ( ! self::image_size_matches_settings( $data, $size ) ) {
// If Photon is running we can just return false and let Jetpack handle regeneration.
if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) {
return false;
} else {
// If we get here, Jetpack is not running and we don't have the correct image sized stored. Try to return closest match.
$size_data = wc_get_image_size( $size );
return image_get_intermediate_size( $attachment_id, array( absint( $size_data['width'] ), absint( $size_data['height'] ) ) );
}
return false;
}
return $data;
}
/**
* We need to track if uncropped was on or off when generating the images.
*
* @param array $meta_data Array of meta data.
* @return array
*/
public static function add_uncropped_metadata( $meta_data ) {
$size_data = wc_get_image_size( 'woocommerce_thumbnail' );
if ( isset( $meta_data['sizes'], $meta_data['sizes']['woocommerce_thumbnail'] ) ) {
$meta_data['sizes']['woocommerce_thumbnail']['uncropped'] = empty( $size_settings['height'] );
}
return $meta_data;
}
/**
* See if an image's dimensions match actual settings.
*
* @param array $image Image dimensions array.
* @param string $size Named size.
* @return bool
*/
protected static function image_size_matches_settings( $image, $size ) {
$size_data = wc_get_image_size( $size );
// Size is invalid if the widths or crop setting don't match.
if ( $size_data['width'] !== $image['width'] ) {
return false;
}
// Size is invalid if the heights don't match.
if ( $size_data['height'] && $size_data['height'] !== $image['height'] ) {
return false;
}
// If cropping mode has changed, regenerate the image.
if ( '' === $size_data['height'] && empty( $image['uncropped'] ) ) {
return false;
}
return true;
}
/**
* Show notice when job is running in background.
*/
public static function regenerating_notice() {
if ( ! self::$background_process->is_running() ) {
WC_Admin_Notices::add_notice( 'regenerating_thumbnails' );
} else {
WC_Admin_Notices::remove_notice( 'regenerating_thumbnails' );
}
}
/**
* Dismiss notice and cancel jobs.
*/
public static function dismiss_regenerating_notice() {
if ( self::$background_process ) {
self::$background_process->kill_process();
$log = wc_get_logger();
$log->info( __( 'Cancelled product image regeneration job.', 'woocommerce' ),
array(
'source' => 'wc-image-regeneration',
)
);
}
WC_Admin_Notices::remove_notice( 'regenerating_thumbnails' );
}
/**
* Regenerate images if the settings have changed since last re-generation.
*
* @return void
*/
public static function maybe_regenerate_images() {
$size_hash = md5( wp_json_encode( array(
wc_get_image_size( 'thumbnail' ),
wc_get_image_size( 'single' ),
wc_get_image_size( 'gallery_thumbnail' ),
) ) );
if ( update_option( 'woocommerce_maybe_regenerate_images_hash', $size_hash ) ) {
// Size settings have changed. Trigger regen.
self::queue_image_regeneration();
}
}
@ -54,33 +196,91 @@ class WC_Regenerate_Images {
* @return array
*/
public static function maybe_resize_image( $image, $attachment_id, $size, $icon ) {
if ( ! apply_filters( 'woocommerce_resize_images', true ) ) {
return $image;
}
// Use a whitelist of sizes we want to resize. Ignore others.
if ( ! in_array( $size, apply_filters( 'woocommerce_image_sizes_to_resize', array( 'woocommerce_thumbnail', 'woocommerce_single', 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ), true ) ) {
if ( ! in_array( $size, apply_filters( 'woocommerce_image_sizes_to_resize', array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single', 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ), true ) ) {
return $image;
}
// Get image metadata - we need it to proceed.
$imagemeta = wp_get_attachment_metadata( $attachment_id );
if ( false === $imagemeta || empty( $imagemeta ) ) {
if ( empty( $imagemeta ) ) {
return $image;
}
$size_settings = wc_get_image_size( $size );
// If size differs from image meta, regen.
if ( ! isset( $imagemeta['sizes'], $imagemeta['sizes'][ $size ] ) || $imagemeta['sizes'][ $size ]['width'] !== $size_settings['width'] || ( $size_settings['crop'] && $imagemeta['sizes'][ $size ]['height'] !== $size_settings['height'] ) ) {
$image = self::resize_and_return_image( $attachment_id, $image, $size, $icon );
if ( ! isset( $imagemeta['sizes'], $imagemeta['sizes'][ $size ] ) || ! self::image_size_matches_settings( $imagemeta['sizes'][ $size ], $size ) ) {
return self::resize_and_return_image( $attachment_id, $image, $size, $icon );
}
return $image;
}
/**
* Ensure we are dealing with the correct image attachment
*
* @param WP_Post $attachment Attachment object.
* @return boolean
*/
public static function is_regeneratable( $attachment ) {
if ( 'site-icon' === get_post_meta( $attachment->ID, '_wp_attachment_context', true ) ) {
return false;
}
if ( wp_attachment_is_image( $attachment ) ) {
return true;
}
return false;
}
/**
* Only regenerate images for the requested size.
*
* @param array $sizes Array of image sizes.
* @return array
*/
public static function adjust_intermediate_image_sizes( $sizes ) {
return array( self::$regenerate_size );
}
/**
* Generate the thumbnail filename and dimensions for a given file.
*
* @param string $fullsizepath Path to full size image.
* @param int $thumbnail_width The width of the thumbnail.
* @param int $thumbnail_height The height of the thumbnail.
* @param bool $crop Whether to crop or not.
* @return array|false An array of the filename, thumbnail width, and thumbnail height, or false on failure to resize such as the thumbnail being larger than the fullsize image.
*/
private static function get_image( $fullsizepath, $thumbnail_width, $thumbnail_height, $crop ) {
list( $fullsize_width, $fullsize_height ) = getimagesize( $fullsizepath );
$dimensions = image_resize_dimensions( $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop );
$editor = wp_get_image_editor( $fullsizepath );
if ( is_wp_error( $editor ) ) {
return false;
}
if ( ! $dimensions || ! is_array( $dimensions ) ) {
return false;
}
list( , , , , $dst_w, $dst_h ) = $dimensions;
$suffix = "{$dst_w}x{$dst_h}";
$file_ext = strtolower( pathinfo( $fullsizepath, PATHINFO_EXTENSION ) );
return array(
'filename' => $editor->generate_filename( $suffix, null, $file_ext ),
'width' => $dst_w,
'height' => $dst_h,
);
}
/**
* Regenerate the image according to the required size
*
@ -91,8 +291,19 @@ class WC_Regenerate_Images {
* @return string
*/
private static function resize_and_return_image( $attachment_id, $image, $size, $icon ) {
$attachment = get_post( $attachment_id );
if ( ! $attachment || 'attachment' !== $attachment->post_type || 'image/' !== substr( $attachment->post_mime_type, 0, 6 ) ) {
$image_size = wc_get_image_size( $size );
$wp_uploads = wp_upload_dir( null, false );
$wp_uploads_dir = $wp_uploads['basedir'];
$wp_uploads_url = $wp_uploads['baseurl'];
$attachment = get_post( $attachment_id );
if ( ! $attachment || 'attachment' !== $attachment->post_type || ! self::is_regeneratable( $attachment ) ) {
return $image;
}
$fullsizepath = get_attached_file( $attachment_id );
if ( false === $fullsizepath || is_wp_error( $fullsizepath ) || ! file_exists( $fullsizepath ) ) {
return $image;
}
@ -100,83 +311,52 @@ class WC_Regenerate_Images {
include ABSPATH . 'wp-admin/includes/image.php';
}
$wp_uploads = wp_upload_dir( null, false );
$wp_uploads_dir = $wp_uploads['basedir'];
$wp_uploads_url = $wp_uploads['baseurl'];
$original_image_file_path = get_attached_file( $attachment->ID );
if ( ! file_exists( $original_image_file_path ) || ! getimagesize( $original_image_file_path ) ) {
return $image;
}
$info = pathinfo( $original_image_file_path );
$ext = $info['extension'];
list( $orig_w, $orig_h ) = getimagesize( $original_image_file_path );
// Get image size after cropping.
$image_size = wc_get_image_size( $size );
$dimensions = image_resize_dimensions( $orig_w, $orig_h, $image_size['width'], $image_size['height'], $image_size['crop'] );
if ( ! $dimensions || ! is_array( $dimensions ) ) {
return $image;
}
$dst_w = $dimensions[4];
$dst_h = $dimensions[5];
$suffix = "{$dst_w}x{$dst_h}";
$dst_rel_path = str_replace( '.' . $ext, '', $original_image_file_path );
$destfilename = "{$dst_rel_path}-{$suffix}.{$ext}";
$thumbnail = self::get_image( $fullsizepath, $image_size['width'], $image_size['height'], $image_size['crop'] );
// If the file is already there perhaps just load it.
if ( file_exists( $destfilename ) ) {
if ( $thumbnail && file_exists( $thumbnail['filename'] ) ) {
$wp_uploads = wp_upload_dir( null, false );
$wp_uploads_dir = $wp_uploads['basedir'];
$wp_uploads_url = $wp_uploads['baseurl'];
return array(
0 => str_replace( $wp_uploads_dir, $wp_uploads_url, $destfilename ),
1 => $image_size['width'],
2 => $image_size['height'],
0 => str_replace( $wp_uploads_dir, $wp_uploads_url, $thumbnail['filename'] ),
1 => $thumbnail['width'],
2 => $thumbnail['height'],
);
}
// Lets resize the image if it does not exist yet.
$editor = wp_get_image_editor( $original_image_file_path );
if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $image_size['width'], $image_size['height'], $image_size['crop'] ) ) ) {
$metadata = wp_get_attachment_metadata( $attachment_id );
// Make sure registered image size matches the size we're requesting.
add_image_size( $size . '_preview', $image_size['width'], $image_size['height'], $image_size['crop'] );
self::$regenerate_size = $size . '_preview';
// We only want to regen a specific image size.
add_filter( 'intermediate_image_sizes', array( __CLASS__, 'adjust_intermediate_image_sizes' ) );
// This function will generate the new image sizes.
$new_metadata = wp_generate_attachment_metadata( $attachment_id, $fullsizepath );
// Remove custom filter.
remove_filter( 'intermediate_image_sizes', array( __CLASS__, 'adjust_intermediate_image_sizes' ) );
// If something went wrong lets just return the original image.
if ( is_wp_error( $new_metadata ) || empty( $new_metadata ) ) {
return $image;
}
$resized_file = $editor->save();
if ( ! is_wp_error( $resized_file ) ) {
$img_url = str_replace( $wp_uploads_dir, $wp_uploads_url, $resized_file['path'] );
return array(
0 => $img_url,
1 => $image_size['width'],
2 => $image_size['height'],
);
// Since this is only a preview we should not update the actual size. That will be done later by the background job.
if ( isset( $new_metadata['sizes'][ $size . '_preview' ] ) ) {
$metadata['sizes'][ $size . '_preview' ] = $new_metadata['sizes'][ $size . '_preview' ];
wp_update_attachment_metadata( $attachment_id, $metadata );
}
// Lets just add this here as a fallback.
return $image;
}
// Now we've done our regen, attempt to return the new size.
$new_image = image_downsize( $attachment_id, $size . '_preview' );
/**
* Check if we should regenerate the product images when options change.
*
* @param mixed $old_value Old option value.
* @param mixed $new_value New option value.
* @param string $option Option name.
*/
public static function maybe_regenerate_images_option_update( $old_value, $new_value, $option ) {
if ( $new_value === $old_value ) {
return;
}
self::queue_image_regeneration();
}
/**
* Check if we should generate images when new themes declares custom sizes.
*/
public static function maybe_regenerate_image_theme_switch() {
if ( wc_get_theme_support( 'single_image_width' ) || wc_get_theme_support( 'thumbnail_image_width' ) ) {
self::queue_image_regeneration();
}
return $new_image ? $new_image : $image;
}
/**
@ -184,7 +364,7 @@ class WC_Regenerate_Images {
*
* @return void
*/
private static function queue_image_regeneration() {
public static function queue_image_regeneration() {
global $wpdb;
// First lets cancel existing running queue to avoid running it more than once.
self::$background_process->kill_process();
@ -207,4 +387,5 @@ class WC_Regenerate_Images {
self::$background_process->save()->dispatch();
}
}
WC_Regenerate_Images::init();
add_action( 'init', array( 'WC_Regenerate_Images', 'init' ) );

View File

@ -1,36 +1,38 @@
<?php
include_once( 'legacy/class-wc-legacy-shipping-zone.php' );
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Represents a single shipping zone
*
* @class WC_Shipping_Zone
* @since 2.6.0
* @version 3.0.0
* @package WooCommerce/Classes
* @category Class
* @author WooCommerce
* @since 2.6.0
* @version 3.0.0
* @package WooCommerce/Classes
*/
defined( 'ABSPATH' ) || exit;
require_once 'legacy/class-wc-legacy-shipping-zone.php';
/**
* WC_Shipping_Zone class.
*/
class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Zone ID
*
* @var int|null
*/
protected $id = null;
/**
* This is the name of this object type.
*
* @var string
*/
protected $object_type = 'shipping_zone';
/**
* Zone Data
* Zone Data.
*
* @var array
*/
protected $data = array(
@ -49,7 +51,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
$this->set_id( $zone );
} elseif ( is_object( $zone ) ) {
$this->set_id( $zone->zone_id );
} elseif ( 0 === $zone || "0" === $zone ) {
} elseif ( 0 === $zone || '0' === $zone ) {
$this->set_id( 0 );
} else {
$this->set_object_read( true );
@ -61,16 +63,16 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
}
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
/**
* --------------------------------------------------------------------------
* Getters
* --------------------------------------------------------------------------
*/
/**
* Get zone name.
*
* @param string $context
* @param string $context View or edit context.
* @return string
*/
public function get_zone_name( $context = 'view' ) {
@ -80,7 +82,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Get zone order.
*
* @param string $context
* @param string $context View or edit context.
* @return int
*/
public function get_zone_order( $context = 'view' ) {
@ -90,7 +92,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Get zone locations.
*
* @param string $context
* @param string $context View or edit context.
* @return array of zone objects
*/
public function get_zone_locations( $context = 'view' ) {
@ -100,8 +102,8 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Return a text string representing what this zone is for.
*
* @param int $max
* @param string $context
* @param int $max Max locations to return.
* @param string $context View or edit context.
* @return string
*/
public function get_formatted_location( $max = 10, $context = 'view' ) {
@ -124,7 +126,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
}
foreach ( $states as $location ) {
$location_codes = explode( ':', $location->code );
$location_codes = explode( ':', $location->code );
$location_parts[] = $all_states[ $location_codes[0] ][ $location_codes[1] ];
}
@ -135,8 +137,8 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
// Fix display of encoded characters.
$location_parts = array_map( 'html_entity_decode', $location_parts );
if ( sizeof( $location_parts ) > $max ) {
$remaining = sizeof( $location_parts ) - $max;
if ( count( $location_parts ) > $max ) {
$remaining = count( $location_parts ) - $max;
// @codingStandardsIgnoreStart
return sprintf( _n( '%s and %d other region', '%s and %d other regions', $remaining, 'woocommerce' ), implode( ', ', array_splice( $location_parts, 0, $max ) ), $remaining );
// @codingStandardsIgnoreEnd
@ -150,10 +152,11 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Get shipping methods linked to this zone.
*
* @param bool Only return enabled methods.
* @param bool $enabled_only Only return enabled methods.
* @param string $context Getting shipping methods for what context. Valid values, admin, json.
* @return array of objects
*/
public function get_shipping_methods( $enabled_only = false ) {
public function get_shipping_methods( $enabled_only = false, $context = 'admin' ) {
if ( null === $this->get_id() ) {
return array();
}
@ -165,30 +168,37 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
foreach ( $raw_methods as $raw_method ) {
if ( in_array( $raw_method->method_id, array_keys( $allowed_classes ), true ) ) {
$class_name = $allowed_classes[ $raw_method->method_id ];
$class_name = $allowed_classes[ $raw_method->method_id ];
$instance_id = $raw_method->instance_id;
// The returned array may contain instances of shipping methods, as well
// as classes. If the "class" is an instance, just use it. If not,
// create an instance.
if ( is_object( $class_name ) ) {
$class_name_of_instance = get_class( $class_name );
$methods[ $raw_method->instance_id ] = new $class_name_of_instance( $raw_method->instance_id );
$class_name_of_instance = get_class( $class_name );
$methods[ $instance_id ] = new $class_name_of_instance( $instance_id );
} else {
// If the class is not an object, it should be a string. It's better
// to double check, to be sure (a class must be a string, anything)
// else would be useless
// else would be useless.
if ( is_string( $class_name ) && class_exists( $class_name ) ) {
$methods[ $raw_method->instance_id ] = new $class_name( $raw_method->instance_id );
$methods[ $instance_id ] = new $class_name( $instance_id );
}
}
// Let's make sure that we have an instance before setting its attributes
if ( is_object( $methods[ $raw_method->instance_id ] ) ) {
$methods[ $raw_method->instance_id ]->method_order = absint( $raw_method->method_order );
$methods[ $raw_method->instance_id ]->enabled = $raw_method->is_enabled ? 'yes' : 'no';
$methods[ $raw_method->instance_id ]->has_settings = $methods[ $raw_method->instance_id ]->has_settings();
$methods[ $raw_method->instance_id ]->settings_html = $methods[ $raw_method->instance_id ]->supports( 'instance-settings-modal' ) ? $methods[ $raw_method->instance_id ]->get_admin_options_html() : false;
$methods[ $raw_method->instance_id ]->method_description = wp_kses_post( wpautop( $methods[ $raw_method->instance_id ]->method_description ) );
// Let's make sure that we have an instance before setting its attributes.
if ( is_object( $methods[ $instance_id ] ) ) {
$methods[ $instance_id ]->method_order = absint( $raw_method->method_order );
$methods[ $instance_id ]->enabled = $raw_method->is_enabled ? 'yes' : 'no';
$methods[ $instance_id ]->has_settings = $methods[ $instance_id ]->has_settings();
$methods[ $instance_id ]->settings_html = $methods[ $instance_id ]->supports( 'instance-settings-modal' ) ? $methods[ $instance_id ]->get_admin_options_html(): false;
$methods[ $instance_id ]->method_description = wp_kses_post( wpautop( $methods[ $instance_id ]->method_description ) );
}
if ( 'json' === $context ) {
// We don't want the entire object in this context, just the public props.
$methods[ $instance_id ] = (object) get_object_vars( $methods[ $instance_id ] );
unset( $methods[ $instance_id ]->instance_form_fields, $methods[ $instance_id ]->form_fields );
}
}
}
@ -198,25 +208,25 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
return apply_filters( 'woocommerce_shipping_zone_shipping_methods', $methods, $raw_methods, $allowed_classes, $this );
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
/**
* --------------------------------------------------------------------------
* Setters
* --------------------------------------------------------------------------
*/
/**
* Set zone name.
*
* @param string $set
* @param string $set Value to set.
*/
public function set_zone_name( $set ) {
$this->set_prop( 'zone_name', wc_clean( $set ) );
}
/**
* Set zone order.
* Set zone order. Value to set.
*
* @param int $set
* @param int $set Value to set.
*/
public function set_zone_order( $set ) {
$this->set_prop( 'zone_order', absint( $set ) );
@ -226,7 +236,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
* Set zone locations.
*
* @since 3.0.0
* @param array
* @param array $locations Value to set.
*/
public function set_zone_locations( $locations ) {
if ( 0 !== $this->get_id() ) {
@ -234,10 +244,10 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
}
}
/*
|--------------------------------------------------------------------------
| Other Methods
|--------------------------------------------------------------------------
/**
* --------------------------------------------------------------------------
* Other
* --------------------------------------------------------------------------
*/
/**
@ -280,7 +290,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Location type detection.
*
* @param object $location
* @param object $location Location to check.
* @return boolean
*/
private function location_is_continent( $location ) {
@ -290,7 +300,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Location type detection.
*
* @param object $location
* @param object $location Location to check.
* @return boolean
*/
private function location_is_country( $location ) {
@ -300,7 +310,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Location type detection.
*
* @param object $location
* @param object $location Location to check.
* @return boolean
*/
private function location_is_state( $location ) {
@ -310,7 +320,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Location type detection.
*
* @param object $location
* @param object $location Location to check.
* @return boolean
*/
private function location_is_postcode( $location ) {
@ -320,29 +330,29 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Is passed location type valid?
*
* @param string $type
* @param string $type Type to check.
* @return boolean
*/
public function is_valid_location_type( $type ) {
return in_array( $type, array( 'postcode', 'state', 'country', 'continent' ) );
return in_array( $type, array( 'postcode', 'state', 'country', 'continent' ), true );
}
/**
* Add location (state or postcode) to a zone.
*
* @param string $code
* @param string $type state or postcode
* @param string $code Location code.
* @param string $type state or postcode.
*/
public function add_location( $code, $type ) {
if ( 0 !== $this->get_id() && $this->is_valid_location_type( $type ) ) {
if ( 'postcode' === $type ) {
$code = trim( strtoupper( str_replace( chr( 226 ) . chr( 128 ) . chr( 166 ), '...', $code ) ) ); // No normalization - postcodes are matched against both normal and formatted versions to support wildcards.
}
$location = array(
$location = array(
'code' => wc_clean( $code ),
'type' => wc_clean( $type ),
);
$zone_locations = $this->get_prop( 'zone_locations', 'edit' );
$zone_locations = $this->get_prop( 'zone_locations', 'edit' );
$zone_locations[] = (object) $location;
$this->set_prop( 'zone_locations', $zone_locations );
}
@ -352,7 +362,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Clear all locations for this zone.
*
* @param array|string $types of location to clear
* @param array|string $types of location to clear.
*/
public function clear_locations( $types = array( 'postcode', 'state', 'country', 'continent' ) ) {
if ( ! is_array( $types ) ) {
@ -360,7 +370,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
}
$zone_locations = $this->get_prop( 'zone_locations', 'edit' );
foreach ( $zone_locations as $key => $values ) {
if ( in_array( $values->type, $types ) ) {
if ( in_array( $values->type, $types, true ) ) {
unset( $zone_locations[ $key ] );
}
}
@ -371,7 +381,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Set locations.
*
* @param array $locations Array of locations
* @param array $locations Array of locations.
*/
public function set_locations( $locations = array() ) {
$this->clear_locations();
@ -383,7 +393,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Add a shipping method to this zone.
*
* @param string $type shipping method type
* @param string $type shipping method type.
* @return int new instance_id, 0 on failure
*/
public function add_shipping_method( $type ) {
@ -396,7 +406,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
$allowed_classes = $wc_shipping->get_shipping_method_class_names();
$count = $this->data_store->get_method_count( $this->get_id() );
if ( in_array( $type, array_keys( $allowed_classes ) ) ) {
if ( in_array( $type, array_keys( $allowed_classes ), true ) ) {
$instance_id = $this->data_store->add_method( $this->get_id(), $type, $count + 1 );
}
@ -412,7 +422,7 @@ class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
/**
* Delete a shipping method from a zone.
*
* @param int $instance_id
* @param int $instance_id Shipping method instance ID.
* @return True on success, false on failure
*/
public function delete_shipping_method( $instance_id ) {

View File

@ -60,7 +60,7 @@ class WC_Shipping {
* @since 2.1
*/
public function __clone() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Cloning is forbidden.', 'woocommerce' ), '2.1' );
}
/**
@ -69,7 +69,7 @@ class WC_Shipping {
* @since 2.1
*/
public function __wakeup() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Unserializing instances of this class is forbidden.', 'woocommerce' ), '2.1' );
}
/**

View File

@ -502,6 +502,9 @@ class WC_Shortcodes {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
}
// Change form action to avoid redirect.
add_filter( 'woocommerce_add_to_cart_form_action', '__return_empty_string' );
$single_product = new WP_Query( $args );
$preselected_id = '0';
@ -574,6 +577,8 @@ class WC_Shortcodes {
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
}
remove_filter( 'woocommerce_add_to_cart_form_action', '__return_empty_string' );
return '<div class="woocommerce">' . ob_get_clean() . '</div>';
}

View File

@ -410,14 +410,14 @@ class WC_Template_Loader {
public static function unsupported_theme_shop_content_filter( $content ) {
global $wp_query;
if ( self::$theme_support || ! is_main_query() ) {
if ( self::$theme_support || ! is_main_query() || ! in_the_loop() ) {
return $content;
}
self::$in_content_filter = true;
// Remove the filter we're in to avoid nested calls.
remove_filter( 'the_content', array( __CLASS__, 'the_content_filter' ) );
remove_filter( 'the_content', array( __CLASS__, 'unsupported_theme_shop_content_filter' ) );
// Unsupported theme shop page.
if ( is_page( self::$shop_page_id ) ) {
@ -444,6 +444,7 @@ class WC_Template_Loader {
// Remove actions and self to avoid nested calls.
remove_action( 'pre_get_posts', array( wc()->query, 'product_query' ) );
WC()->query->remove_ordering_args();
}
self::$in_content_filter = false;
@ -463,14 +464,14 @@ class WC_Template_Loader {
public static function unsupported_theme_product_content_filter( $content ) {
global $wp_query;
if ( self::$theme_support || ! is_main_query() ) {
if ( self::$theme_support || ! is_main_query() || ! in_the_loop() ) {
return $content;
}
self::$in_content_filter = true;
// Remove the filter we're in to avoid nested calls.
remove_filter( 'the_content', array( __CLASS__, 'the_content_filter' ) );
remove_filter( 'the_content', array( __CLASS__, 'unsupported_theme_product_content_filter' ) );
if ( is_product() ) {
$content = do_shortcode( '[product_page id="' . get_the_ID() . '" show_title=0]' );
@ -481,6 +482,16 @@ class WC_Template_Loader {
return $content;
}
/**
* Are we filtering content for unsupported themes?
*
* @since 3.3.2
* @return bool
*/
public static function in_content_filter() {
return (bool) self::$in_content_filter;
}
/**
* Prevent the main featured image on product pages because there will be another featured image
* in the gallery.
@ -490,7 +501,7 @@ class WC_Template_Loader {
* @return string
*/
public static function unsupported_theme_single_featured_image_filter( $html ) {
if ( self::$in_content_filter || ! is_product() || ! is_main_query() ) {
if ( self::in_content_filter() || ! is_product() || ! is_main_query() ) {
return $html;
}

View File

@ -123,7 +123,7 @@ final class WooCommerce {
* @since 2.1
*/
public function __clone() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Cloning is forbidden.', 'woocommerce' ), '2.1' );
}
/**
@ -132,7 +132,7 @@ final class WooCommerce {
* @since 2.1
*/
public function __wakeup() {
wc_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
wc_doing_it_wrong( __FUNCTION__, __( 'Unserializing instances of this class is forbidden.', 'woocommerce' ), '2.1' );
}
/**
@ -539,19 +539,18 @@ final class WooCommerce {
* @since 2.3
*/
public function add_image_sizes() {
$thumbnail = wc_get_image_size( 'thumbnail' );
$single = wc_get_image_size( 'single' );
$thumbnail = wc_get_image_size( 'thumbnail' );
$single = wc_get_image_size( 'single' );
$gallery_thumbnail = wc_get_image_size( 'gallery_thumbnail' );
add_image_size( 'woocommerce_thumbnail', $thumbnail['width'], $thumbnail['height'], $thumbnail['crop'] );
add_image_size( 'woocommerce_single', $single['width'], $single['height'], $single['crop'] );
// 2x thumbnail size for retina, and when showing less columns.
add_image_size( 'woocommerce_thumbnail_2x', $thumbnail['width'] * 2, $thumbnail['height'] * 2, $thumbnail['crop'] );
add_image_size( 'woocommerce_gallery_thumbnail', $gallery_thumbnail['width'], $gallery_thumbnail['height'], $gallery_thumbnail['crop'] );
// Registered for bw compat. @todo remove in 4.0.
add_image_size( 'shop_thumbnail', $thumbnail['width'], $thumbnail['height'], $thumbnail['crop'] );
add_image_size( 'shop_catalog', $thumbnail['width'], $thumbnail['height'], $thumbnail['crop'] );
add_image_size( 'shop_single', $single['width'], $single['height'], $single['crop'] );
add_image_size( 'shop_thumbnail', $gallery_thumbnail['width'], $gallery_thumbnail['height'], $gallery_thumbnail['crop'] );
}
/**

View File

@ -154,8 +154,10 @@ class WC_Shop_Customizer {
wp.customize( 'woocommerce_catalog_rows', function( setting ) {
setting.bind( function( value ) {
var min = '<?php echo esc_js( $min_rows ); ?>';
var max = '<?php echo esc_js( $max_rows ); ?>';
var min = parseInt( '<?php echo esc_js( $min_rows ); ?>', 10 );
var max = parseInt( '<?php echo esc_js( $max_rows ); ?>', 10 );
value = parseInt( value, 10 );
if ( max && value > max ) {
setting.notifications.add( 'max_rows_error', new wp.customize.Notification(
@ -441,12 +443,23 @@ class WC_Shop_Customizer {
* @param WP_Customize_Manager $wp_customize Theme Customizer object.
*/
private function add_product_images_section( $wp_customize ) {
if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) {
$regen_description = ''; // Nothing to report; Jetpack will handle magically.
} elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && ! is_multisite() ) {
$regen_description = __( 'After publishing your changes, new image sizes will be generated automatically.', 'woocommerce' );
} elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && is_multisite() ) {
$regen_description = sprintf( __( 'After publishing your changes, new image sizes may not be shown until you regenerate thumbnails. You can do this from the <a href="%1$s" target="_blank">tools section in WooCommerce</a> or by using a plugin such as <a href="%2$s" target="_blank">Regenerate Thumbnails</a>.', 'woocommerce' ), admin_url( 'admin.php?page=wc-status&tab=tools' ), 'https://en-gb.wordpress.org/plugins/regenerate-thumbnails/' );
} else {
$regen_description = sprintf( __( 'After publishing your changes, new image sizes may not be shown until you <a href="%2$s" target="_blank">Regenerate Thumbnails</a>.', 'woocommerce' ), 'https://en-gb.wordpress.org/plugins/regenerate-thumbnails/' );
}
$wp_customize->add_section(
'woocommerce_product_images',
array(
'title' => __( 'Product Images', 'woocommerce' ),
'priority' => 20,
'panel' => 'woocommerce',
'title' => __( 'Product Images', 'woocommerce' ),
'description' => $regen_description,
'priority' => 20,
'panel' => 'woocommerce',
)
);
@ -494,7 +507,7 @@ class WC_Shop_Customizer {
'woocommerce_thumbnail_image_width',
array(
'label' => __( 'Thumbnail width', 'woocommerce' ),
'description' => __( 'Image size used for products in the catalog and product gallery thumbnails.', 'woocommerce' ),
'description' => __( 'Image size used for products in the catalog.', 'woocommerce' ),
'section' => 'woocommerce_product_images',
'settings' => 'woocommerce_thumbnail_image_width',
'type' => 'number',

View File

@ -114,7 +114,7 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat
wp_update_user( apply_filters( 'woocommerce_update_customer_args', array(
'ID' => $customer->get_id(),
'role' => $customer->get_role(),
'display_name' => $customer->get_first_name() . ' ' . $customer->get_last_name(),
'display_name' => $customer->get_display_name(),
), $customer ) );
$wp_user = new WP_User( $customer->get_id() );
$customer->set_date_created( $wp_user->user_registered );

View File

@ -223,7 +223,7 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
'product_id' => '',
'download_id' => '',
'orderby' => 'permission_id',
'order' => 'DESC',
'order' => 'ASC',
'limit' => -1,
'return' => 'objects',
) );
@ -252,9 +252,9 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
}
$allowed_orders = array( 'permission_id', 'download_id', 'product_id', 'order_id', 'order_key', 'user_email', 'user_id', 'downloads_remaining', 'access_granted', 'access_expires', 'download_count' );
$order = in_array( $args['order'], $allowed_orders ) ? $args['order'] : 'permission_id';
$orderby = 'DESC' === strtoupper( $args['orderby'] ) ? 'DESC' : 'ASC';
$orderby_sql = sanitize_sql_orderby( "{$order} {$orderby}" );
$orderby = in_array( $args['orderby'], $allowed_orders, true ) ? $args['orderby'] : 'permission_id';
$order = 'DESC' === strtoupper( $args['order'] ) ? 'DESC' : 'ASC';
$orderby_sql = sanitize_sql_orderby( "{$orderby} {$order}" );
$query[] = "ORDER BY {$orderby_sql}";
if ( 0 < $args['limit'] ) {

View File

@ -48,20 +48,23 @@ class WC_Order_Item_Product_Data_Store extends Abstract_WC_Order_Item_Type_Data_
* @param WC_Order_Item_Product $item
*/
public function save_item_data( &$item ) {
$id = $item->get_id();
$save_values = array(
'_product_id' => $item->get_product_id( 'edit' ),
'_variation_id' => $item->get_variation_id( 'edit' ),
'_qty' => $item->get_quantity( 'edit' ),
'_tax_class' => $item->get_tax_class( 'edit' ),
'_line_subtotal' => $item->get_subtotal( 'edit' ),
'_line_subtotal_tax' => $item->get_subtotal_tax( 'edit' ),
'_line_total' => $item->get_total( 'edit' ),
'_line_tax' => $item->get_total_tax( 'edit' ),
'_line_tax_data' => $item->get_taxes( 'edit' ),
$id = $item->get_id();
$changes = $item->get_changes();
$meta_key_to_props = array(
'_product_id' => 'product_id',
'_variation_id' => 'variation_id',
'_qty' => 'quantity',
'_tax_class' => 'tax_class',
'_line_subtotal' => 'subtotal',
'_line_subtotal_tax' => 'subtotal_tax',
'_line_total' => 'total',
'_line_tax' => 'total_tax',
'_line_tax_data' => 'taxes',
);
foreach ( $save_values as $key => $value ) {
update_metadata( 'order_item', $id, $key, $value );
$props_to_update = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
foreach ( $props_to_update as $meta_key => $prop ) {
update_metadata( 'order_item', $id, $meta_key, $item->{"get_$prop"}( 'edit' ) );
}
}

View File

@ -44,15 +44,18 @@ class WC_Order_Item_Shipping_Data_Store extends Abstract_WC_Order_Item_Type_Data
* @param WC_Order_Item_Shipping $item
*/
public function save_item_data( &$item ) {
$id = $item->get_id();
$save_values = array(
'method_id' => $item->get_method_id( 'edit' ),
'cost' => $item->get_total( 'edit' ),
'total_tax' => $item->get_total_tax( 'edit' ),
'taxes' => $item->get_taxes( 'edit' ),
$id = $item->get_id();
$changes = $item->get_changes();
$meta_key_to_props = array(
'method_id' => 'method_id',
'cost' => 'total',
'total_tax' => 'total_tax',
'taxes' => 'taxes',
);
foreach ( $save_values as $key => $value ) {
update_metadata( 'order_item', $id, $key, $value );
$props_to_update = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
foreach ( $props_to_update as $meta_key => $prop ) {
update_metadata( 'order_item', $id, $meta_key, $item->{"get_$prop"}( 'edit' ) );
}
}
}

View File

@ -46,16 +46,19 @@ class WC_Order_Item_Tax_Data_Store extends Abstract_WC_Order_Item_Type_Data_Stor
* @param WC_Order_Item_Tax $item
*/
public function save_item_data( &$item ) {
$id = $item->get_id();
$save_values = array(
'rate_id' => $item->get_rate_id( 'edit' ),
'label' => $item->get_label( 'edit' ),
'compound' => $item->get_compound( 'edit' ),
'tax_amount' => $item->get_tax_total( 'edit' ),
'shipping_tax_amount' => $item->get_shipping_tax_total( 'edit' ),
$id = $item->get_id();
$changes = $item->get_changes();
$meta_key_to_props = array(
'rate_id' => 'rate_id',
'label' => 'label',
'compound' => 'compound',
'tax_amount' => 'tax_total',
'shipping_tax_amount' => 'shipping_tax_total',
);
foreach ( $save_values as $key => $value ) {
update_metadata( 'order_item', $id, $key, $value );
$props_to_update = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
foreach ( $props_to_update as $meta_key => $prop ) {
update_metadata( 'order_item', $id, $meta_key, $item->{"get_$prop"}( 'edit' ) );
}
}
}

View File

@ -809,14 +809,28 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
public function get_on_sale_products() {
global $wpdb;
$decimals = absint( wc_get_price_decimals() );
$decimals = absint( wc_get_price_decimals() );
$exclude_term_ids = array();
$outofstock_join = '';
$outofstock_where = '';
$product_visibility_term_ids = wc_get_product_visibility_term_ids();
// phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && $product_visibility_term_ids['outofstock'] ) {
$exclude_term_ids[] = $product_visibility_term_ids['outofstock'];
}
if ( count( $exclude_term_ids ) ) {
$outofstock_join = " LEFT JOIN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( " . implode( ',', array_map( 'absint', $exclude_term_ids ) ) . ' ) ) AS exclude_join ON exclude_join.object_id = id';
$outofstock_where = ' AND exclude_join.object_id IS NULL';
}
// @codingStandardsIgnoreStart.
return $wpdb->get_results(
$wpdb->prepare(
"SELECT post.ID as id, post.post_parent as parent_id FROM `$wpdb->posts` AS post
LEFT JOIN `$wpdb->postmeta` AS meta ON post.ID = meta.post_id
LEFT JOIN `$wpdb->postmeta` AS meta2 ON post.ID = meta2.post_id
$outofstock_join
WHERE post.post_type IN ( 'product', 'product_variation' )
AND post.post_status = 'publish'
AND meta.meta_key = '_sale_price'
@ -824,11 +838,13 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
AND CAST( meta.meta_value AS DECIMAL ) >= 0
AND CAST( meta.meta_value AS CHAR ) != ''
AND CAST( meta.meta_value AS DECIMAL( 10, %d ) ) = CAST( meta2.meta_value AS DECIMAL( 10, %d ) )
$outofstock_where
GROUP BY post.ID",
$decimals,
$decimals
)
);
// @codingStandardsIgnoreEnd.
}
/**
@ -1304,9 +1320,10 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
* @param string $term Search term.
* @param string $type Type of product.
* @param bool $include_variations Include variations in search or not.
* @param bool $all_statuses Should we search all statuses or limit to published.
* @return array of ids
*/
public function search_products( $term, $type = '', $include_variations = false ) {
public function search_products( $term, $type = '', $include_variations = false, $all_statuses = false ) {
global $wpdb;
$like_term = '%' . $wpdb->esc_like( $term ) . '%';
@ -1314,6 +1331,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
$post_statuses = current_user_can( 'edit_private_products' ) ? array( 'private', 'publish' ) : array( 'publish' );
$type_join = '';
$type_where = '';
$status_where = '';
if ( $type ) {
if ( in_array( $type, array( 'virtual', 'downloadable' ), true ) ) {
@ -1322,11 +1340,15 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
}
}
if ( ! $all_statuses ) {
$status_where = " AND posts.post_status IN ('" . implode( "','", $post_statuses ) . "') ";
}
// phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
$product_ids = $wpdb->get_col(
$search_results = $wpdb->get_results(
// phpcs:disable
$wpdb->prepare(
"SELECT DISTINCT posts.ID FROM {$wpdb->posts} posts
"SELECT DISTINCT posts.ID as product_id, posts.post_parent as parent_id FROM {$wpdb->posts} posts
LEFT JOIN {$wpdb->postmeta} postmeta ON posts.ID = postmeta.post_id
$type_join
WHERE (
@ -1337,7 +1359,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
)
)
AND posts.post_type IN ('" . implode( "','", $post_types ) . "')
AND posts.post_status IN ('" . implode( "','", $post_statuses ) . "')
$status_where
$type_where
ORDER BY posts.post_parent ASC, posts.post_title ASC",
$like_term,
@ -1347,6 +1369,8 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
// phpcs:enable
);
$product_ids = wp_parse_id_list( array_merge( wp_list_pluck( $search_results, 'product_id' ), wp_list_pluck( $search_results, 'parent_id' ) ) );
if ( is_numeric( $term ) ) {
$post_id = absint( $term );
$post_type = get_post_type( $post_id );

View File

@ -317,6 +317,7 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
$product->set_parent_data( array(
'title' => $parent_object ? $parent_object->post_title : '',
'status' => $parent_object ? $parent_object->post_status : '',
'sku' => get_post_meta( $product->get_parent_id(), '_sku', true ),
'manage_stock' => get_post_meta( $product->get_parent_id(), '_manage_stock', true ),
'backorders' => get_post_meta( $product->get_parent_id(), '_backorders', true ),

View File

@ -133,26 +133,25 @@ class WC_Email extends WC_Settings_API {
* @see $plain_replace
*/
public $plain_search = array(
"/\r/", // Non-legal carriage return
'/&(nbsp|#160);/i', // Non-breaking space
'/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i', // Double quotes
'/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes
'/&gt;/i', // Greater-than
'/&lt;/i', // Less-than
'/&#38;/i', // Ampersand
'/&#038;/i', // Ampersand
'/&amp;/i', // Ampersand
'/&(copy|#169);/i', // Copyright
'/&(trade|#8482|#153);/i', // Trademark
'/&(reg|#174);/i', // Registered
'/&(mdash|#151|#8212);/i', // mdash
'/&(ndash|minus|#8211|#8722);/i', // ndash
'/&(bull|#149|#8226);/i', // Bullet
'/&(pound|#163);/i', // Pound sign
'/&(euro|#8364);/i', // Euro sign
'/&#36;/', // Dollar sign
'/&[^&\s;]+;/i', // Unknown/unhandled entities
'/[ ]{2,}/', // Runs of spaces, post-handling
"/\r/", // Non-legal carriage return
'/&(nbsp|#0*160);/i', // Non-breaking space
'/&(quot|rdquo|ldquo|#0*8220|#0*8221|#0*147|#0*148);/i', // Double quotes
'/&(apos|rsquo|lsquo|#0*8216|#0*8217);/i', // Single quotes
'/&gt;/i', // Greater-than
'/&lt;/i', // Less-than
'/&#0*38;/i', // Ampersand
'/&amp;/i', // Ampersand
'/&(copy|#0*169);/i', // Copyright
'/&(trade|#0*8482|#0*153);/i', // Trademark
'/&(reg|#0*174);/i', // Registered
'/&(mdash|#0*151|#0*8212);/i', // mdash
'/&(ndash|minus|#0*8211|#0*8722);/i', // ndash
'/&(bull|#0*149|#0*8226);/i', // Bullet
'/&(pound|#0*163);/i', // Pound sign
'/&(euro|#0*8364);/i', // Euro sign
'/&(dollar|#0*36);/i', // Dollar sign
'/&[^&\s;]+;/i', // Unknown/unhandled entities
'/[ ]{2,}/', // Runs of spaces, post-handling
);
/**
@ -169,7 +168,6 @@ class WC_Email extends WC_Settings_API {
'<', // Less-than
'&', // Ampersand
'&', // Ampersand
'&', // Ampersand
'(c)', // Copyright
'(tm)', // Trademark
'(R)', // Registered
@ -771,7 +769,7 @@ class WC_Email extends WC_Settings_API {
}
if ( ! current_user_can( 'edit_themes' ) ) {
wp_die( __( 'Cheatin&#8217; huh?', 'woocommerce' ) );
wp_die( __( 'You don&#8217;t have permission to do this.', 'woocommerce' ) );
}
if ( ! empty( $_GET['move_template'] ) ) {

View File

@ -22,6 +22,13 @@ if ( ! class_exists( 'WC_Product_Importer', false ) ) {
*/
class WC_Product_CSV_Importer extends WC_Product_Importer {
/**
* Tracks current row being parsed.
*
* @var integer
*/
protected $parsing_raw_data_index = 0;
/**
* Initialize importer.
*
@ -222,11 +229,14 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
// Not updating? Make sure we have a new placeholder for this ID.
if ( ! $this->params['update_existing'] ) {
$id = isset( $this->raw_data['sku'] ) ? wc_get_product_id_by_sku( $this->raw_data['sku'] ) : '';
$mapped_keys = $this->get_mapped_keys();
$sku_column_index = absint( array_search( 'sku', $mapped_keys, true ) );
$row_sku = isset( $this->raw_data[ $this->parsing_raw_data_index ][ $sku_column_index ] ) ? $this->raw_data[ $this->parsing_raw_data_index ][ $sku_column_index ] : '';
$id_from_sku = $row_sku ? wc_get_product_id_by_sku( $row_sku ) : '';
// If row has a SKU, make sure placeholder was not made already.
if ( $id ) {
return $id;
if ( $id_from_sku ) {
return $id_from_sku;
}
$product = new WC_Product_Simple();
@ -235,8 +245,8 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
$product->add_meta_data( '_original_id', $id, true );
// If row has a SKU, make sure placeholder has it too.
if ( isset( $this->raw_data['sku'] ) ) {
$product->set_sku( $this->raw_data['sku'] );
if ( $row_sku ) {
$product->set_sku( $row_sku );
}
$id = $product->save();
}
@ -777,11 +787,14 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
$use_mb = function_exists( 'mb_convert_encoding' );
// Parse the data.
foreach ( $this->raw_data as $row ) {
foreach ( $this->raw_data as $row_index => $row ) {
// Skip empty rows.
if ( ! count( array_filter( $row ) ) ) {
continue;
}
$this->parsing_raw_data_index = $row_index;
$data = array();
do_action( 'woocommerce_product_importer_before_set_parsed_data', $row, $mapped_keys );
@ -869,7 +882,9 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
if ( $id ) {
$product = wc_get_product( $id );
$id_exists = $product && 'importing' !== $product->get_status();
} elseif ( $sku ) {
}
if ( $sku ) {
$id_from_sku = wc_get_product_id_by_sku( $sku );
$product = $id_from_sku ? wc_get_product( $id_from_sku ) : false;
$sku_exists = $product && 'importing' !== $product->get_status();

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