Merge branch 'master' into refactor/eu-vat-brexit

This commit is contained in:
Claudio Sanches 2020-01-27 13:15:54 -03:00
commit b3ea0b17b4
351 changed files with 20908 additions and 7426 deletions

View File

@ -1,9 +0,0 @@
{
"presets": [
"es2015",
"stage-2"
],
"plugins": [
"add-module-exports"
]
}

View File

@ -8,7 +8,7 @@ coverage:
range: "50...100"
status:
project: yes
project: off
patch: off
changes: off
@ -20,7 +20,4 @@ parsers:
method: no
macro: no
comment:
layout: "files"
behavior: default
require_changes: yes
comment: false

View File

@ -2,13 +2,19 @@
"root": true,
"env": {
"browser": true,
"node": true
"es6": true,
"node": true,
"jest/globals": true
},
"globals": {
"wp": true,
"wpApiSettings": true,
"wcSettings": true,
"es6": true
"es6": true,
"page": true,
"browser": true,
"context": true,
"jestPuppeteer": true
},
"rules": {
"camelcase": 0,
@ -16,7 +22,19 @@
"max-len": [ 2, { "code": 140 } ],
"no-console": 1
},
"plugins": [
"jest"
],
"extends": [
"plugin:jest/recommended"
],
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 6
"ecmaVersion": 8,
"ecmaFeatures": {
"modules": true,
"experimentalObjectRestSpread": true,
"jsx": true
}
}
}

2
.gitattributes vendored
View File

@ -1,4 +1,5 @@
/.* export-ignore
bin export-ignore
CODE_OF_CONDUCT.md export-ignore
CHANGELOG.txt export-ignore
composer.* export-ignore
@ -9,3 +10,4 @@ phpcs.xml export-ignore
phpunit.* export-ignore
README.md export-ignore
tests export-ignore
renovate.json export-ignore

View File

@ -13,7 +13,7 @@ There are many ways to contribute to the project!
If you wish to contribute code, please read the information in the sections below. Then [fork](https://help.github.com/articles/fork-a-repo/) WooCommerce, commit your changes, and [submit a pull request](https://help.github.com/articles/using-pull-requests/) 🎉
We use the `help wanted` label to mark issues that are suitable for new contributors. You can find all the issues with this label [here](https://github.com/woocommerce/woocommerce/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
We use the `good first issue` label to mark issues that are suitable for new contributors. You can find all the issues with this label [here](https://github.com/woocommerce/woocommerce/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
WooCommerce is licensed under the GPLv3+, and all contributions to the project will be released under the same license. You maintain copyright over any contribution you make, and by submitting a pull request, you are agreeing to release that contribution under the GPLv3+ license.
@ -24,6 +24,7 @@ If you have questions about the process to contribute code or want to discuss de
- [How to set up WooCommerce development environment](https://github.com/woocommerce/woocommerce/wiki/How-to-set-up-WooCommerce-development-environment)
- [Git Flow](https://github.com/woocommerce/woocommerce/wiki/WooCommerce-Git-Flow)
- [Minification of SCSS and JS](https://github.com/woocommerce/woocommerce/wiki/Minification-of-SCSS-and-JS)
- [Naming conventions](https://github.com/woocommerce/woocommerce/wiki/Naming-conventions)
- [String localisation guidelines](https://github.com/woocommerce/woocommerce/wiki/String-localisation-guidelines)
- [Running unit tests](https://github.com/woocommerce/woocommerce/blob/master/tests/README.md)
- [Running e2e tests](https://github.com/woocommerce/woocommerce/wiki/End-to-end-Testing)

1
.gitignore vendored
View File

@ -20,6 +20,7 @@ none
# Compiled CSS
/assets/css/*.css
/assets/css/photoswipe/**/*.min.css
# Minified JS
/assets/js/admin/*.min.js

View File

@ -5,6 +5,8 @@ dist: xenial
services:
- xvfb
- mysql
- docker
- docker-compose
sudo: false
@ -20,6 +22,7 @@ php:
- 7.1
- 7.2
- 7.3
- 7.4
env:
- WP_VERSION=latest WP_MULTISITE=0
@ -30,26 +33,25 @@ matrix:
fast_finish: true
include:
- name: "Coding standard check"
php: 7.2
php: 7.4
env: WP_VERSION=latest WP_MULTISITE=0 RUN_PHPCS=1
- name: "e2e tests"
php: 7.2
env: WP_VERSION=latest WP_MULTISITE=0 RUN_E2E=1
addons:
chrome: beta
apt:
packages:
- nginx
- name: "E2E tests"
php: 7.4
script:
- npm install
- npm run build
- docker-compose up --build -d
- bash tests/bin/run-e2e-CI.sh
after_script:
- docker-compose down -v
- name: "Unit tests code coverage"
php: 7.3
php: 7.4
env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
- name: "WooCommerce unit tests using WordPress nightly"
php: 7.3
env: WP_VERSION=nightly WP_MULTISITE=0
- php: 7.4snapshot
php: 7.4
env: WP_VERSION=nightly WP_MULTISITE=0
allow_failures:
- php: 7.3
- php: 7.4
env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
before_script:
@ -73,7 +75,6 @@ before_script:
script:
- bash tests/bin/phpunit.sh
- bash tests/bin/phpcs.sh
- travis_retry bash tests/bin/run-e2e-CI.sh
after_script:
- bash tests/bin/travis.sh after

View File

@ -1,5 +1,314 @@
== Changelog ==
= 3.9.0 - 2020-01-21 =
* Enhancement - Added a "Show" button next to the password field on the login fields. #24915
* Enhancement - New WooCommerce Onboarding experience (shows to only 10% of new users). #24991
* Enhancement - Introduced Payment Gateway API to support "pay button". #25000
* Enhancement - Includes WooCommerce Blocks 2.5.3, introducing an "All Products" block, a new block listing products using client side rendering (requires WordPress 5.3), and more. #25181
* Tweak - Updated PayPal standard "Thank you" page message to comply with PayPal Guidelines. #24756
* Tweak - Account for non-EU countries that collect VAT and rename tax to VAT on the frontend. #24999
* Tweak - Cache checkout fragments and update DOM on change only. #24227
* Tweak - Eliminate extra update order AJAX request on checkout page load. #24271
* Tweak - Prevent billing address from being updated on shipping update. #24374
* Tweak - Added a tooltip in the "Coupon expity date" field. #24749
* Tweak - Make phone numbers clickable in emails. #24786
* Tweak - Prevent PHP warnings in tracker if order doesn't have a created date yet. #24846
* Tweak - Capitalize "T" in "Move to Trash" phrase on order page in wp-admin to be consistent with product and coupon pages. #24867
* Tweak - Changed `wp_cache` invalidation from using increment to using microtime. #24961
* Tweak - Made the usage tracking link on the setup wizard more transparent. #25026
* Tweak - Fixed menu highlight of My Account page when browsing "Add payment method" page. #25041
* Tweak - Prevent creating products before registering related post types and taxonomies. #25049
* Tweak - Include processing orders in tracker data when opted in. #25071
* Tweak - Centralize check for default themes to fix Storefront appearance in the Setup Wizard. #25216
* Tweak - Adds a WordPress version check before recommending the WooCommerce Admin plugin during setup. #25260
* Fix - Added license key support recent changes from MaxMind GeoLite2. #25378
* Fix - Honor tax rounding preference in edit item and refund flows. #24208
* Fix - Prevent incorrect number of decimal points in prices. #24281
* Fix - Fixed initial support for Gutenberg's Experimental Legacy Widget block. #24292
* Fix - Fix overriding of query when using orderby on archives with a static homepage. #24683
* Fix - Use of `wp_unslash()` function when escaping admin settings values. #24793
* Fix - Do not set the tracking cookie when doing ajax requests. #24798
* Fix - Display button to delete images from product galleries in the admin when using a mobile device. #24840
* Fix - Fixed order note's date format. #24843
* Fix - Refactored `WC_Order_Factory::get_order()` to remove function deprecated in PHP 7.0. #24852
* Fix - Fixed product stock status changes on Bulk Edit save when "Enable stock management" is disabled. #24876
* Fix - Fixed default country code fallback in wc_get_customer_default_location(). #24884
* Fix - Fixed misleading message for Shipping options in cart. #24914
* Fix - Customizer not loading when viewing from WordPress.com. #24935
* Fix - Prevent notice when a variable product has no images. #24986
* Fix - Adjusted the slug generation for duplicated variable products to prevent performance degradation when using templates. #25064
* Fix - Added appropriate minification to photoswipe.css. #25074
* Fix - Corrected the sorting behavior for the "products" shortcode when manually sorting products. #25084
* Fix - Fixed invalid backlinks for in-app purchases. #25098
* Fix - Corrected the media element player initialization for product variation descriptions. #25103
* Fix - Enable WooCommerce.com Site API on installations not using permalink. #25131
* Fix - WooCommerce.com Site API now returns success if the plugin was previously installed. #25140
* Fix - WooCommerce.com Site API checks to `move_product` case to make sure result array contains `folder_exists` item and doesn't return a warning. #25160
* Fix - Ensure that categories containing only private products are selectable in the product exporter. #25132
* Fix - Prevent variable product parents from being added to orders. #25162
* Fix - Use sorting settings as a default to product shortcodes. #25180
* Fix - Applied setup wizard CSS fixes to the respective WP versions. #25197
* Fix - Fixed "account erasure request" URL in WordPress 5.3. #25208
* Fix - Ensure all cache get removed on webhook deletion. #25164
* Fix - Adjusted the checkout email validation regex to be more accurate. #25251
* Template - Introduced `woocommerce_product_related_products_heading` filter. #25059
* Template - Introduced `woocommerce_before_lost_password_confirmation_message` and `woocommerce_after_lost_password_confirmation_message` hooks. #25096
* REST API - Fixed `date_created` and `date_created_gmt` for customers v2. #25181
* REST API - Fixed Restored "Total post count" section on System Status endpoint v2 and v3. #25181
* REST API - Filter empty objects from results before loop. #25181
* Dev - Introduce new PHP 7.0 minimum requirement.
* Dev - Introduce new WordPress 5.0 minimum requirement.
* Dev - Check for max discount to be "-ve" to prevent overwriting refunded fee amount. #24341
* Dev - Add unload event to the checkout page to prevent reloading during checkout after placing an order. #24609
* Dev - Only toggle form field description if element exists. #24752
* Dev - Introduced `woocommerce_{$export_type}_export_delimiter` filter to change separator string while exporting CSV files. #24759
* Dev - Introduced `woocommerce_after_order_refund_item_name` hook. #24760
* Dev - Introduced `woocommerce_kses_notice_allowed_tags` filter. #24849
* Dev - Introduced `woocommerce_shipping_not_enabled_on_cart_html` filter. #24914
* Dev - Introduced `woocommerce_show_invalid_variations_notice` filter. #24934
* Dev - Introduced `woocommerce_upsells_order` filter. #25017
* Dev - Introduced `woocommerce_before_settings_{current_tab}` and `woocommerce_after_settings_{current_tab}` hooks. #25028
* Dev - Included third parameter `$order` to `woocommerce_order_get_formatted_billing_address` and `woocommerce_order_get_formatted_shipping_address` filters. #24870
* Dev - Pass the `$clear_persistent_cart` variable to the `woocommerce_before_cart_emptied` and `woocommerce_cart_emptied actions`. #24930
* Dev - Made variables in `assets/css/_variables.scss` default. #24822
* Dev - Refactor to use the same rounding logic in orders and cart. #24828
* Dev - Add order note immediately after status change before the `woocommerce_order_status_changed action. #24879
* Dev - Added support for custom attributes in `wc_placeholder_img()`. #24937
* Dev - Added initial support for inline notices on checkout. #25001
* Dev - Introduced wc_get_product_object() helper. #25031
* Dev - Pass the correct `$this->updated_props` variable to the `woocommerce_coupon_object_updated_props` action's second paramater. #25077
* Dev - Remove a few calls to `func_get_args()` and `call_user_func_array()` with the spread operator for better code legibility and performance gains. #25101
- Dev - New `woocommerce_valid_order_statuses_for_payment` hook that triggers when an order is paid. Use this new hook instead of `woocommerce_order_status_changed` or *woocommerce_order_status_{old_status}}_to_{new_status}` to trigger code for payment completion. #25158
* Dev - Ability to exclude certain product types from product search calls. #25162
* Dev - Raise exception when `WC_Product_Variation` is instantiated with an ID that belongs to an object that is not a variation. #25178
* Localization - Add subdivisions of Laos. #24765
* Localization - Fixed translatable string in WooCommerce's libraries. #24892 #24894
* Localization - Fixed translatable string comments for translators. #24928
* Localization - Add postcode validation for Slovenia. #25174
= 3.8.0 - 2019-11-05 =
* Enhancement - Show error message in "My Account - view order" if order does not exist. #24435
* Enhancement - Add support to allow connect and install for in-app purchase flow. #24451
* Enhancement - Declared support to Unicode CLDR. #24564
* Enhancement - Declared support for PHP 7.4 in CI by removing PHP 7.4 from list of allowed failures. #24668
* Enhancement - Update the recommended PHP version to 7.0 and the recommended WP version to 5.0. #24730
* Enhancement - Change On Boarding Wizard to opt out of usage tracking by default. #24680
* Enhancement - Add `Available on backorder` message for products available on backorder. #24559
* Tweak - Hide Vietnam's state field. #24158
* Tweak - Better wording when no downloads are available on My Account > Downloads. #24172
* Tweak - Only consider orders created via checkout to hold stock. #24159
* Tweak - Stop to load order data twice in "View order" screen on "My Account" page. #24437
* Tweak - Prevent PHP warnings in tracker if order doesn't have a created date yet. #24441
* Tweak - Use `wc_get_checkout_url()` to get checkout URL. #24544
* Tweak - Maintain value of select fields in credit card form. #24720
* Tweak - Prevent filter per category while exporting product variations. #24517
* Tweak - Better wording for subtotal of items in cart and review order. #24440
* Tweak - Prevent new lines in product quantity in checkout details. #24311
* Tweak - Add a tooltip in the "Coupon expity date" field. #24749
* Tweak - CSS styling changes for WP 5.3. #24832
* Template - Moved HTML for displaying product price filter widget to a new template `product price filter widget`. #23384
* Accessibility - Make $subtext color darker. #24739
* Dev - Consistent register/login submit button css class names. Preserve old class names as well for backwards compatibility. #23701
* Dev - Added woocommerce_disable_password_change_notification filter, set to false by default. #24154
* Dev - Add filter `woocommerce_cart_item_removed_message` and `woocommerce_cart_product_cannot_be_purchased_message` to filter notice content when an item is removed from cart, or when a product cannot be purchased. #24176
* Dev - Prevent fatal error if trying to run `wc_load_cart()` before `before_woocommerce_init`. #24198
* Dev - Add woocommerce_get_zone_criteria filter hook to add custom criteria for matching zone ID. #24199
* Dev - Fire actions `woocommerce_before_delete_product_variation`, `woocommerce_delete_product_variation` and `woocommerce_trash_product_variation` appropriately when deleting or trashing product variations. #24239
* Dev - In filter `woocommerce_update_product_stock_query` use `$new_stock` instead of `$stock_quantity`. #24229
* Dev - Introduced woocommerce_prevent_adjust_line_item_product_stock filter. #24279
* Dev - Introduced `woocommerce_logout_default_redirect_url` filter to allow custom default URL. #24282
* Dev - Added woocommerce_sort_fees_callback filter. #24280
* Dev - Remove deprecated i18n/states directory. #24364
* Dev - Add filter `woocommerce_shipping_show_shipping_calculator` for showing shipping calculator. #24375
* Dev - Corrected UG states location. #24388
* Dev - Remove deprecations notices with PHP 7.4 by changing parameter order for `implode`. #24396
* Dev - Add ``$this` param to email filter for additional_content added in 3.7. #24399
* Dev - Add `woocommerce_product_import_process_item_data` filter to allow modifying a row before importing. #24412
* Dev - Fixed warnings when error_get_last() returns null. #24442
* Dev - Use brackets instead of braces to avoid deprecation notice in PHP 7.4. #24460
* Dev - Implement Puppeteer's architecture for running E2E tests locally. #24479
* Dev - Remove call to get_magic_quotes_runtime() as it is deprecated as of PHP 7.4. #24485
* Dev - Return value of `$mailer->send()` in `wc_mail` function. #24505
* Dev - Remove Selenium e2e tests & add Puppeteer new product e2e test. #24513
* Dev - Add a filter `woocommerce_ajax_add_order_item_validation` to allow validations in `add_order_item` function. #24518
* Dev - Use `wc_get_cart_url` instead of `wc_get_page_permalink( 'cart' )` because former has a filter `woocommerce_get_cart_url` to allow customization. #24530
* Dev - New `woocommerce_product_after_tabs` action hook added. #24694
* Dev - Enable append hashes on custom events (like ajax requests) #24665
* Dev - Introduced `woocommerce_order_get_formatted_billing_address` and `woocommerce_order_get_formatted_shipping_address` filters. #24677
* Dev - WC_Abstract_Order::recalculate_coupons() is public now. #24740
* Dev - Added 'applied_coupon' trigger to checkout.js. #24406
* Dev - Introduced woocommerce_output_cart_shortcode_content filter. #24738
* Dev - Add WPML compatibility to the geolocation URL. #24722
* Dev - Validate server requirements in WCCCOM Site Installer endpoints. #24690
* Dev - Introduced woocommerce_payment_token_class filter. #24542
* Dev - Add support for post type count to system status report. #24536
* Dev - Check for max discount to be -ve to prevent overwriting refunded fee amount. #24341
* Dev: Add filter woocommerce_european_union_countries to the method WC_Countries::get_european_union_countries(). #24741
* Dev - Allow WC_Product_Query sort products by include order. #24294
* Dev - Removed duplicated include of WC_Admin_Importers. #24751
* Dev - Refactor minimum requirement notice to use constant for easier changes in the future. #24830
* Dev - Fixed number of arguments in filters on WC_Emails class. #25312
* Fix - Clean products transients when term is removed. #23991
* Fix - Only add the image node to structured data if product has image. #24191
* Fix - Product attribute terms endpoint in legacy REST API v3 by converting `attribute_id` to int. #24203
* Fix - Prevent duplicate processing/stock reduction when IPN or PDT notifications are enabled by checking if order is not already in `processing` or `completed` status. #24249
* Fix - Position of ID section in mobile rows actions when displaying the list of products in the admin. #24277
* Fix - Endpoints URLs to follow slashes preferences from WordPress permalinks. #24283
* Fix - Ensure that postcode validation doesn't return any whitespace on beginning and end of a postcode. #24284
* Fix - Shipping classes sort under products alphabetically. #24291
* Fix - Shipping rates layout in admin settings. #24327
* Fix - Retain the focus on the select box when product variation is changed. #24339
* Fix - Prevent PHP notice in WC_Order_Item_Data_Store::get_order_item_type() when there is no entry in the database for the order item ID passed. #24353
* Fix - Add translation in class-wc-shipping.php for matching zone message. #24366
* Fix - Previewing email template. #24380
* Fix - Check if order exist before generate hash for downloads. #24384
* Fix - Ensure WC_Product_Data_Store_CPT::is_existing_sku() return boolean. #24385
* Fix - `function_exists` check for wc_hex_is_light(). #24391
* Fix - Removed Emoji from default additional email content due problem on some database that doesn't allow Emojis. #24450
* Fix - Fixed escaping on an attribute in `class-wc-admin-menus.php`. #24466
* Fix - Add translation for image alt attribute text in multiple places. #24467, #24468, #24469
* Fix - Uneven padding in the input field with class "location-input" in on boarding wizard. #24476
* Fix - Duplicate id in pages settings. #24478
* Fix - Use `esc_attr_e` instead of `esc_html_e` for escaping an attribute in multiple places. #24481, #24520, #24521, #24522, #24523, #24524
* Fix - Use `esc_attr__` instead of `esc_html__` in escaping attributes string. #24525, #24529
* Fix - Typo fix in payment captured error message. #24501
* Fix - Documentation URL in failed order email content. #24535
* Fix - "Add to cart" links in feed. #24545
* Fix - Escaping in Storefront banner. #24546
* Fix - Use `wp_kses_post` to allow certain html tags in extensions page. #24589
* Fix - Escape `$prefix` in item download links. #24601
* Fix - Use `esc_attr` instead of `esc_html` in multiple places for proper escaping. #24613, #24614
* Fix - Use `esc_html` instead of `esc_attr` in multiple places for proper escaping. #24616
* Fix - Use `esc_html_e` instead of `_e` in multiple places for proper escaping. #24615, #24618, #24630
* Fix - Use `esc_html__` instead of `esc_html` for proper escaping and some typo fixes. #24639
* Fix - Add no-store and remove max-age header (no longer needed). #24652
* Fix - Use correct meta value for `downloadable` column in product lookup table regenerate function. #24681
* Fix - Admin sub-menus becoming unaligned when scrolling down in the orders page when there are no orders. #24688
* Fix - OWB country and sell in person alignment. #24700
* Fix - Domain replacement script now replaces both double and single quoted `woo-gutenberg-products-block` with `woocommerce` in both PHP and JavaScript files. #24696
* Fix - Convert `current_user_id` to string in some places to prevent unnecessary session database updates. #24016
* Fix - Fixed description of failed order emails. #24737
* Fix - Fixed Photoswipe styles. #24296
* Fix - Also consider refunded item when updating order and adjusting stocks. #24745
* Fix - Handle 0 attribute value for variations correctly. #24750
* Fix - Fixed spaces in form fields of External Products. #24295
* Fix - Removed links to downloadable products from refund emails. #24952
* Fix - Fixed button HTML element in the OBW. #25056
* Localization - Add Zambia's Provinces to the list of states. #24307
* Localization - Adaptation of the order of last name and first name and addresses in Japan. #24336
* Localization - Fixed Namibian dollar symbol. #24438
* Localization - Change localization tag `action-scheduler` to `woocommerce`. #24474
* Localization - Fixed missing US Minor Outlying Islands states. #24826
* Security - Add an exit after the redirect when checking author archive capabilities for customers.
* Security - Ensure 404 pages with single product urls cannot be exploited using Open Redirect.
= 3.7.1 - 2019-10-09
* Security - Add an exit after the redirect when checking author archive capabilities for customers.
* Security - Ensure 404 pages with single product urls cannot be exploited using Open Redirect.
= 3.7.0 - 2019-08-12 =
* Enhancement - Added table ENGINE to system status report for debugging purposes. #23101
* Enhancement - Format empty cart message as information notice. #23152
* Enhancement - Add taxonomy-specific classes to active filters widget. #23122
* Enhancement - Allow emails `Thanks` wording to be modified via the email settings. #22927
* Enhancement - Move tax classes from WordPress Options to a new `wc_tax_rate_classes` table. #23093
* Enhancement - Make WooCommerce shop roles translatable. #23150
* Enhancement - Prevent the Cart, Checkout and My Account pages from being set to the same pages. #23479
* Enhancement - New coupon code generate button on the coupon page. #24069
* Enhancement - Add `tag_operator` paramater to the `[products]` shortcode for use with the `tag` paramater ie. `[products tag='tag1,tag2' tag_operator='AND']`. #24111
* Tweak - When cleaning up variations due to product type change, force delete them instead of trashing. #23478
* Tweak - Change wording on the link to change the address so reflect if an address is already present or not. #23532
* Tweak - If variations are missing prices, show a notice in the product data panel. #23133
* Tweak - Use `determine_locale()` to properly load custom translation files. #23785
* Tweak - OBW: Switch shipping labels and shipping zones placement. #23781
* Tweak - Show the quantity refunded on customer facing order screens. #23038
* Tweak - CSV product import now allows true/false values for the published field, as well as the original 0 (private), -1 (draft), 1 (publish) values. #23207
* Tweak - Update product attribute sorting tooltip to clarify usage. #23222
* Tweak - Store tax rate percentage in the tax line items on orders. #23268
* Tweak - Remove the left and right margin from the logo in emails. #23360
* Tweak - Use the high res version of the WP spinner in the coupon Block UI. #23364
* Tweak - Improve user registration validation messages. #23468
* Tweak - Auto generate a new username when a username is blacklisted by WordPress. #23672
* Tweak - Guest cart sessions now gets deleted when a user logs in, preventing duplicate cart sessions. #23687
* Tweak - Include the store's base postcode and city when calculating order taxes. #23695
* Tweak - Update the generate username setting description label to reflect how the username is actually generated. #23911
* Tweak - OBW: Adjust plugin highlight container sizes to avoid overlap. #23997
* Tweak - Round tax amounts late when the round at subtotal level setting is enabled to reduce rounding errors. #24024
* Tweak - OBW: Now includes WooCommerce Admin as a recommended plugin. #24058
* Template - Review and update all template files escaping. #23460
* Template - Remove mention of shipping section from the checkout/form-login.php template as shipping is not always a requirement for an order. #23941
* Template - Add new filter `woocommerce_before_thankyou` to the checkout/thankyou.php template. #23538
* Template - Add new `woocommerce_widget_shopping_cart_total` hook to replace hardcoded subtotal in cart/mini-cart.php template. #24145
* Template - Add new `woocommerce_widget_shopping_cart_after_buttons` hook in cart/mini-cart.php template. #24145
* Template - Add new `woocommerce_before_cart_collaterals` hook in cart/cart.php template. #24145
* Template - Correct the plural forms usage in loop/result-count.php template. #24005
* Dev - Introduce new PHP 5.6 minimum requirement. #23924
* Dev - Introduce new WordPress 4.9 minimum requirement. #24156
* Dev - Move the settings save functionality from the `settings_page_init` function to the `wp_loaded` action so it is not saved after the settings page renders. #23091
* Dev - Add quantity input action hooks `woocommerce_before_add_to_cart_quantity` and `woocommerce_after_add_to_cart_quantity`. #23166
* Dev - Add `$this` parameter to email class filters. #23250
* Dev - Add new `WC_Abstract_Order::get_coupons()` method for returning all coupon line item objects on an order. #23663
* Dev - Added new action `woocommerce_product_read` to `WC_Product_Data_Store_CPT::read()`. #23181
* Dev - Add new filter `woocommerce_admin_order_buyer_name` to the `WC_Admin_List_Table_Orders::render_order_number_column()` method to change the buyer name in orders list screen. #23741
* Dev - Add new actions to `WC_Helper` class for when WooCommerce.com Product Subscription statuses change `woocommerce_helper_subscription_activate_success`, `woocommerce_helper_subscription_activate_error`, `woocommerce_helper_subscription_deactivate_success`, and `woocommerce_helper_subscription_deactivate_error`. #23041
* Dev - Extend usage and event tracking (if opted in) to system status, admin order and admin coupon pages. #23190 #23189 #23883
* Dev - Add `woocommerce_after_X_object_save` actions, and passed objects to `woocommerce_new_x` and `woocommerce_update_x` actions. #23338
* Dev - Update customer order and lifetime spend totals in `wc_update_new_customer_past_orders()` to trigger `customer.updated` webhooks for paid orders. #23402
* Dev - Preserve the State field's custom css classes when selecting an option from the Country dropdown. #23433
* Dev - Add new `woocommerce_product_related_posts_shuffle` filter in `wc_get_related_products()` to enable/disable related product shuffling, defaults to true. #23562
* Dev - Deprecate the `WC_Abstract_Order::get_used_coupons()` method and replace it with a new method `WC_Abstract_Order::get_coupon_codes()`. #23689
* Dev - Add new `woocommerce_prices_include_tax` filter in the `wc_prices_include_tax()` function. #23697
* Dev - Add new `woocommerce_admin_after_product_gallery_item` filter in the `WC_Meta_Box_Product_Images::output()` method for adding additional markup after product gallery items. #23743
* Dev - Remove unused images `assets/images/klarna-white.png` and `assets/images/square-white.png`. #23748
* Dev - Move Free Shipping method JavaScript code from outputting on all shipping setting pages to just the Free Shipping page using the `admin_footer` hook. #23776
* Dev - Prevent PHP fatal error while throwing exceptions in `woocommerce_rest_insert_{post_type}_object` hooks. #23793
* Dev - Add new `woocommerce_enforce_password_strength_meter_on_checkout` filter in the `WC_Frontend_Scripts::get_script_data()` method to allow enforcing the password strength meter on checkout. #23811
* Dev - Add new `woocommerce_search_products_post_statuses` filter in the `WC_Product_Data_Store_CPT::search_products()` method for controlling what post statuses to include in product searches. #23838
* Dev - Allow filtering `woocommerce_order_formatted_shipping_address` even when no shipping address is defined. #23859
* Dev - Change the query in the `WC_Product_Data_Store::find_matching_product_variation()` method to always respect the ordering of variations. #23881
* Dev - Move all feature plugin features out from the WooCommerce codebase and utilize composer and an autoloader for including it in WooCommerce core, affects WC REST API and WC Blocks. #23957
* Dev - Allow displaying multiple error messages through the registration validation. #23968
* Dev - Add new `woocommerce_cart_item_removed_notice_type`, `woocommerce_cart_updated_notice_type` and `woocommerce_add_to_cart_notice_type` filters for changing the default notice types for cart notices. #24021
* Dev - Add namespaced support for Jetpack 7.5 tracking library. #24140
* Dev - Add support for an improved WooCommerce.com Marketplace browse and purchase experience (in progress). #24075 #24123
* Dev - Added `$order` and `$product` as parameters to the `woocommerce_ajax_order_item` filter in `WC_Ajax::add_order_item()`. #24108
* Dev - Add new `woocommerce_product_import_image_separator` filter in `WC_Product_CSV_Importer::parse_images_field()` for adjusting the product images seperator. #24120
* Dev - Add new `woocommerce_widget_shopping_cart_subtotal()` template function that hooks into the `woocommerce_widget_shopping_cart_total` action to output the mini cart subtotal. #24145
* Dev - Deprecate the `woocommerce_before_cart_item_quantity_zero` action from `WC_Cart::restore_cart_item()` in favor of existing `woocommerce_cart_item_removed` action. #23112
* Dev - Deprecate WC_Tax::maybe_remove_tax_class_rates which hooked into the WP Options update hook for taxes in favor of new function WC_Tax::delete_tax_class_by which works on the new tax classes table. #24213
* Fix - Use version_compare for determining the maximum WooCommerce database version number. #23092
* Fix - Missing space and closing `<strong>` tag in WooCommerce.com disconnect message. #24073
* Fix - CSV Importer - Skip rows during update if a SKU column exists, but the value is empty. #23262
* Fix - Allow matching `Any` attributes when calling `WC_Product_Data_Store::find_matching_product_variation()`. #23067
* Fix - Switch coupon amount validation based on decimal seperator setting. #23137
* Fix - Show the correct results for shortcodes on static homepages when sorting. #23159
* Fix - Queue AJAX add to cart events to avoid overwriting session data. #23293
* Fix - Wrong subtotals when changing tax classes via the `woocommerce_product_get_tax_class` filter. #23344
* Fix - Fatal error on plain text order emails where products were deleted. #23754
* Fix - Do not pass the `no_shipping` argument to PayPal when the order contains shippable items. #23773
* Fix - Product review form does respects the `require_name_email` WordPress core option. #23786
* Fix - Do not cache expired sessions, negative expiry causes errors in some caching modules. #23863
* Fix - WC_Log_Handler_DB logs now uses the same timestamp format as text logs, Y-m-d H:i:s. #23863
* Fix - Display line breaks for customer notes in emails, and order details. #23969
* Fix - Correct plural forms usage in `WC_Admin_Report` class. #24020
* Fix - System status database info section throwing a PHP notice on some DB environments. #24023
* Fix - On the system status database info section display a message informing users that WooCommerce was unable to get database information instead of an error, when a database sharding plugin is active. #24034
* Fix - Usage and event tracking (if opted in) was not working correctly in the OBW. #24056
* Fix - Fatal error on downloads report when some download files were missing. #24118
* Fix - Prevents the taxes columns from being removed when the order is no longer editable in admin. #23884
* Performance - Improve the speed of the admin dashboard by only updating transients once per class. #23011
* Performance - Reduce number of queries needed to populate variations data by priming post caches. #23272
* Performance - Persistant cart improvements, only update the persistent cart if the cart items actually change. #23112
* Performance - Exclude `action_log` comment types from `wp_count_comments`. #24071
* Localization - Added validation for Italian postcodes. #23269
* Localization - Remove unused tax locale defaults since we now promote auto tax services instead. #23431
* Localization - Define correct address format for Uganda. #23178
* Localization - Hide the postcode and update the state label to "Province" for Mozambique. #23764
* Localization - OBW: Make postal code optional based on locale data. #23915
* Localization - Add new currency for São Tomé, Príncipe dobra and Mauritanian ouguiya. #23950
* Localization - Change Canada poscode label to `Postal code`. #23740
= 3.6.5 - 2019-07-02 =
* Security - Introduce file type check for tax rate importer.
* Security - Added nonce check to CSV importer actions.

1
Dockerfile Normal file
View File

@ -0,0 +1 @@
FROM wordpress:5.3

View File

@ -148,11 +148,29 @@ module.exports = function( grunt ) {
// Minify all .css files.
cssmin: {
minify: {
expand: true,
cwd: '<%= dirs.css %>/',
src: ['*.css'],
dest: '<%= dirs.css %>/',
ext: '.css'
files: [
{
expand: true,
cwd: '<%= dirs.css %>/',
src: ['*.css'],
dest: '<%= dirs.css %>/',
ext: '.css'
},
{
expand: true,
cwd: '<%= dirs.css %>/photoswipe/',
src: ['*.css', '!*.min.css'],
dest: '<%= dirs.css %>/photoswipe/',
ext: '.min.css'
},
{
expand: true,
cwd: '<%= dirs.css %>/photoswipe/default-skin/',
src: ['*.css', '!*.min.css'],
dest: '<%= dirs.css %>/photoswipe/default-skin/',
ext: '.min.css'
}
]
}
},
@ -229,7 +247,6 @@ module.exports = function( grunt ) {
files: {
src: [
'**/*.php', // Include all files
'!includes/libraries/**', // Exclude libraries/
'!node_modules/**', // Exclude node_modules/
'!tests/**', // Exclude tests/
'!vendor/**', // Exclude vendor/

View File

@ -2,20 +2,20 @@
* WooCommerce CSS Variables
*/
$woocommerce: #a46497;
$green: #7ad03a;
$red: #a00;
$orange: #ffba00;
$blue: #2ea2cc;
$woocommerce: #a46497 !default;
$green: #7ad03a !default;
$red: #a00 !default;
$orange: #ffba00 !default;
$blue: #2ea2cc !default;
$primary: #a46497; // Primary color for buttons (alt)
$primarytext: desaturate(lighten($primary, 50%), 18%); // Text on primary color bg
$primary: #a46497 !default; // Primary color for buttons (alt)
$primarytext: desaturate(lighten($primary, 50%), 18%) !default; // Text on primary color bg
$secondary: desaturate(lighten($primary, 40%), 21%); // Secondary buttons
$secondarytext: desaturate(darken($secondary, 60%), 21%); // Text on secondary color bg
$secondary: desaturate(lighten($primary, 40%), 21%) !default; // Secondary buttons
$secondarytext: desaturate(darken($secondary, 60%), 21%) !default; // Text on secondary color bg
$highlight: adjust-hue($primary, 150deg); // Prices, In stock labels, sales flash
$highlightext: desaturate(lighten($highlight, 50%), 18%); // Text on highlight color bg
$highlight: adjust-hue($primary, 150deg) !default; // Prices, In stock labels, sales flash
$highlightext: desaturate(lighten($highlight, 50%), 18%) !default; // Text on highlight color bg
$contentbg: #fff; // Content BG - Tabs (active state)
$subtext: #767676; // small, breadcrumbs etc
$contentbg: #fff !default; // Content BG - Tabs (active state)
$subtext: #767676 !default; // small, breadcrumbs etc

View File

@ -579,6 +579,7 @@
}
#variable_product_options {
.form-row select {
max-width: 100%;
}
@ -636,6 +637,14 @@ mark.amount {
}
}
.branch-5-3 {
.woocommerce-help-tip {
font-size: 1.2em;
cursor: help;
}
}
h2 .woocommerce-help-tip {
margin-top: -5px;
margin-left: 0.25em;
@ -2158,6 +2167,22 @@ ul.wc_coupon_list_block {
}
}
.branch-5-3 {
.widefat {
.column-wc_actions {
a.button {
&::after {
margin-top: 2px;
}
}
}
}
}
.post-type-shop_order {
.tablenav .one-page .displaying-num {
@ -3035,7 +3060,6 @@ table.wc_input_table {
vertical-align: middle;
input {
width: auto;
padding: 0;
}
}
@ -4099,6 +4123,84 @@ img.help_tip {
}
}
.branch-5-3 {
.woocommerce {
h2.wc-table-list-header {
margin: 1em 0 0.35em 0;
}
input + .subsubsub {
margin: 8px 0 0;
}
table.form-table {
// Give regular settings inputs a standard width and padding.
textarea,
input[type="text"],
input[type="email"],
input[type="number"],
input[type="password"],
input[type="datetime"],
input[type="datetime-local"],
input[type="date"],
input[type="time"],
input[type="week"],
input[type="url"],
input[type="tel"],
input.regular-input {
padding: 0 8px;
@media only screen and (max-width: 782px) {
width: 100%;
}
}
select {
@media only screen and (max-width: 782px) {
width: 100%;
}
}
th label {
img.help_tip,
.woocommerce-help-tip {
margin: -7px -24px 0 0;
@media only screen and (max-width: 782px) {
right: auto;
margin-left: 5px;
}
}
}
.forminp-color {
font-size: 0;
}
.colorpickpreview {
padding: 0;
width: 30px;
height: 30px;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
font-size: 16px;
border-radius: 4px;
margin-right: 3px;
@media only screen and (max-width: 782px) {
float: left;
width: 40px;
height: 40px;
}
}
}
}
}
.woocommerce #tabs-wrap table a.remove {
margin-left: 4px;
}
@ -4184,6 +4286,10 @@ img.help_tip {
padding: 2px;
display: none;
@media (max-width: 768px) {
display: block;
}
li {
float: right;
margin: 0 0 0 2px;
@ -4541,7 +4647,6 @@ img.help_tip {
.woocommerce_options_panel .checkbox,
.woocommerce_variable_attributes .checkbox {
width: auto;
margin: 4px 0 !important;
vertical-align: middle;
float: left;
@ -6589,6 +6694,177 @@ table.bar_chart {
min-width: 400px !important;
}
.branch-5-3 {
.select2-results {
.select2-results__option,
.select2-results__group {
&:focus {
outline: none;
}
}
}
.select2-dropdown {
border-color: #007cba;
&::after {
position: absolute;
left: 0;
right: 0;
height: 1px;
background: #fff;
content: "";
}
}
.select2-dropdown--below {
box-shadow: 0 0 0 1px #007cba, 0 2px 1px rgba(0, 0, 0, 0.1);
&::after {
top: -1px;
}
}
.select2-dropdown--above {
box-shadow: 0 0 0 1px #007cba, 0 -2px 1px rgba(0, 0, 0, 0.1);
&::after {
bottom: -1px;
}
}
.select2-container {
@media only screen and (max-width: 782px) {
font-size: 16px;
}
&:focus {
outline: none;
}
.select2-selection--single {
height: 30px;
border-color: #7e8993;
@media only screen and (max-width: 782px) {
height: 40px;
}
&:focus {
outline: none;
}
.select2-selection__rendered {
line-height: 28px;
@media only screen and (max-width: 782px) {
line-height: 38px;
}
&:hover {
color: #007cba;
}
}
.select2-selection__arrow {
right: 1px;
height: 28px;
width: 28px;
background: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 5px top 55%;
background-size: 16px 16px;
@media only screen and (max-width: 782px) {
height: 38px;
}
b {
display: none;
}
}
}
&.select2-container--focus .select2-selection--single,
&.select2-container--open .select2-selection--single,
&.select2-container--open .select2-selection--multiple {
border-color: #007cba;
box-shadow: 0 0 0 1px #007cba;
}
.select2-selection--multiple {
min-height: 30px;
border-color: #7e8993;
border-radius: 4px;
}
.select2-search--inline .select2-search__field {
padding: 0 0 0 3px;
min-height: 28px;
}
}
.woocommerce table.form-table .select2-container {
@media only screen and (max-width: 782px) {
min-width: 100% !important;
}
}
}
/**
* Select2 colors for built-in admin color themes.
*/
.admin-color {
$wp_admin_colors: (
blue: #096484,
coffee: #c7a589,
ectoplasm: #a3b745,
midnight: #e14d43,
ocean: #9ebaa0,
sunrise: #dd823b,
light: #04a4cc
);
@each $name, $color in $wp_admin_colors {
&-#{$name}.branch-5-3 {
.select2-dropdown {
border-color: $color;
}
.select2-dropdown--below {
box-shadow: 0 0 0 1px $color, 0 2px 1px rgba(0, 0, 0, 0.1);
}
.select2-dropdown--above {
box-shadow: 0 0 0 1px $color, 0 -2px 1px rgba(0, 0, 0, 0.1);
}
.select2-selection--single .select2-selection__rendered:hover {
color: $color;
}
.select2-container.select2-container--focus .select2-selection--single,
.select2-container.select2-container--open .select2-selection--single,
.select2-container.select2-container--open .select2-selection--multiple {
border-color: $color;
box-shadow: 0 0 0 1px $color;
}
.select2-container--default .select2-results__option--highlighted[aria-selected],
.select2-container--default .select2-results__option--highlighted[data-selected] {
background-color: $color;
}
}
}
}
.post-type-product .tablenav,
.post-type-shop_order .tablenav {

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ body {
padding: 0;
}
#wc-logo {
.wc-logo {
border: 0;
margin: 0 0 24px;
padding: 0;
@ -1070,6 +1070,31 @@ h3.jetpack-reasons {
}
}
.wc-setup-step__new_onboarding {
.wc-logo,
.wc-setup-steps {
display: none;
}
.wc-setup-step__new_onboarding-wrapper {
.wc-logo {
display: block;
}
p {
text-align: center;
}
.wc-setup-step__new_onboarding-welcome,
.wc-setup-step__new_onboarding-plugin-info {
color: #7c7c7c;
font-size: 12px;
}
}
}
.step {
text-align: center;
}
@ -1146,7 +1171,7 @@ h3.jetpack-reasons {
border-color: #ddd;
border-radius: 4px;
height: 30px;
width: 100%;
width: calc(100% - 8px - 8px - 2px);
padding-left: 8px;
padding-right: 8px;
font-size: 16px;
@ -1159,6 +1184,15 @@ h3.jetpack-reasons {
}
}
.branch-5-2,
.branch-5-3 {
.location-input {
margin: 0;
width: 100%;
}
}
.address-step {
.select2 {
@ -1380,6 +1414,18 @@ p.jetpack-terms {
}
}
.branch-5-2,
.branch-5-3 {
.wc-wizard-service-setting-stripe_create_account,
.wc-wizard-service-setting-ppec_paypal_reroute_requests {
.payment-checkbox-input {
margin-top: 3px;
}
}
}
.wc-wizard-service-setting-stripe_email,
.wc-wizard-service-setting-ppec_paypal_email {
margin-top: 0.75em;
@ -1504,7 +1550,7 @@ p.jetpack-terms {
@media only screen and (max-width: 400px) {
#wc-logo img {
.wc-logo img {
max-width: 80%;
}

View File

@ -6,17 +6,19 @@
/**
* Imports
*/
@import 'mixins';
@import 'variables';
@import "mixins";
@import "variables";
/**
* Styling begins
*/
.woocommerce, .woocommerce-page {
.woocommerce,
.woocommerce-page {
.woocommerce-message,
.woocommerce-error,
.woocommerce-info {
.button {
float: right;
}
@ -26,6 +28,7 @@
* General layout styles
*/
.col2-set {
@include clearfix();
width: 100%;
@ -33,6 +36,7 @@
float: left;
width: 48%;
}
.col-2 {
float: right;
width: 48%;
@ -49,12 +53,14 @@
*/
div.product,
#content div.product {
div.images {
float: left;
width: 48%;
}
div.thumbnails {
@include clearfix();
a {
@ -73,6 +79,7 @@
}
&.columns-1 {
a {
width: 100%;
margin-right: 0;
@ -81,18 +88,21 @@
}
&.columns-2 {
a {
width: 48%;
}
}
&.columns-4 {
a {
width: 22.05%;
}
}
&.columns-5 {
a {
width: 16.9%;
}
@ -109,12 +119,15 @@
clear: both;
ul.tabs {
@include menu();
}
}
#reviews {
.comment {
@include mediaright();
}
}
@ -125,6 +138,7 @@
*/
ul.products {
clear: both;
@include clearfix();
li.product {
@ -146,28 +160,38 @@
}
ul.products {
&.columns-1 {
li.product {
width: 100%;
margin-right: 0;
}
}
&.columns-2 {
li.product {
width: 48%;
}
}
&.columns-3 {
li.product {
width: 30.75%;
}
}
&.columns-5 {
li.product {
width: 16.95%;
}
}
&.columns-6 {
li.product {
width: 13.5%;
}
@ -175,7 +199,9 @@
}
&.columns-1 {
ul.products {
li.product {
width: 100%;
margin-right: 0;
@ -184,7 +210,9 @@
}
&.columns-2 {
ul.products {
li.product {
width: 48%;
}
@ -192,7 +220,9 @@
}
&.columns-3 {
ul.products {
li.product {
width: 30.75%;
}
@ -200,7 +230,9 @@
}
&.columns-5 {
ul.products {
li.product {
width: 16.95%;
}
@ -208,7 +240,9 @@
}
&.columns-6 {
ul.products {
li.product {
width: 13.5%;
}
@ -218,12 +252,15 @@
.woocommerce-result-count {
float: left;
}
.woocommerce-ordering {
float: right;
}
.woocommerce-pagination {
ul.page-numbers {
@include menu();
}
}
@ -233,6 +270,7 @@
*/
table.cart,
#content table.cart {
img {
height: auto;
}
@ -255,6 +293,7 @@
}
.cart-collaterals {
@include clearfix();
width: 100%;
@ -278,11 +317,13 @@
.shipping_calculator {
width: 48%;
@include clearfix();
clear: right;
float: right;
.col2-set {
.col-1,
.col-2 {
width: 47%;
@ -301,7 +342,9 @@
*/
ul.cart_list,
ul.product_list_widget {
li {
@include mediaright();
}
}
@ -310,7 +353,9 @@
* Forms
*/
form {
.form-row {
@include clearfix();
label {
@ -352,19 +397,54 @@
.form-row-wide {
clear: both;
}
.password-input {
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
input[type="password"] {
padding-right: 2.5rem;
}
/* Hide the Edge "reveal password" native button */
input::-ms-reveal {
display: none;
}
}
.show-password-input {
position: absolute;
right: 0.7em;
top: 0.7em;
cursor: pointer;
}
.show-password-input::after {
@include iconafter( "\e010" ); // Icon styles and glyph
}
.show-password-input.display-password::after {
color: #e8e8e8;
}
}
#payment {
.form-row {
select {
width: auto;
}
}
.wc-terms-and-conditions, .terms {
.wc-terms-and-conditions,
.terms {
text-align: left;
padding: 0 1em 0 0;
float:left;
float: left;
}
#place_order {
@ -374,6 +454,7 @@
.woocommerce-billing-fields,
.woocommerce-shipping-fields {
@include clearfix();
}
@ -391,6 +472,7 @@
}
.woocommerce-account {
.woocommerce-MyAccount-navigation {
float: left;
width: 30%;
@ -406,7 +488,9 @@
* Twenty Eleven specific styles
*/
.woocommerce-page {
&.left-sidebar {
#content.twentyeleven {
width: 58.4%;
margin: 0 7.6%;
@ -415,6 +499,7 @@
}
&.right-sidebar {
#content.twentyeleven {
margin: 0 7.6%;
width: 58.4%;
@ -427,6 +512,7 @@
* Twenty Fourteen specific styles
*/
.twentyfourteen {
.tfwc {
padding: 12px 10px 0;
max-width: 474px;
@ -444,7 +530,9 @@
}
@media screen and (min-width: 673px) {
.twentyfourteen {
.tfwc {
padding-right: 30px;
padding-left: 30px;
@ -453,7 +541,9 @@
}
@media screen and (min-width: 1040px) {
.twentyfourteen {
.tfwc {
padding-right: 15px;
padding-left: 15px;
@ -462,7 +552,9 @@
}
@media screen and (min-width: 1110px) {
.twentyfourteen {
.tfwc {
padding-right: 30px;
padding-left: 30px;
@ -471,13 +563,18 @@
}
@media screen and (min-width: 1218px) {
.twentyfourteen {
.tfwc {
margin-right: 54px;
}
}
.full-width {
.twentyfourteen {
.tfwc {
margin-right: auto;
}
@ -489,6 +586,7 @@
* Twenty Fifteen specific styles
*/
.twentyfifteen {
.t15wc {
padding-left: 7.6923%;
padding-right: 7.6923%;
@ -504,7 +602,9 @@
}
@media screen and (min-width: 38.75em) {
.twentyfifteen {
.t15wc {
margin-right: 7.6923%;
margin-left: 7.6923%;
@ -514,7 +614,9 @@
}
@media screen and (min-width: 59.6875em) {
.twentyfifteen {
.t15wc {
margin-left: 8.3333%;
margin-right: 8.3333%;
@ -523,7 +625,9 @@
}
.single-product {
.twentyfifteen {
.entry-summary {
padding: 0 !important;
}
@ -535,6 +639,7 @@
* Twenty Sixteen specific styles
*/
.twentysixteen {
.site-main {
margin-right: 7.6923%;
margin-left: 7.6923%;
@ -547,8 +652,11 @@
}
#content {
.twentysixteen {
div.product {
div.images,
div.summary {
width: 46.42857%;
@ -558,7 +666,9 @@
}
@media screen and (min-width: 44.375em) {
.twentysixteen {
.site-main {
margin-right: 23.0769%;
}
@ -566,7 +676,9 @@
}
@media screen and (min-width: 56.875em) {
.twentysixteen {
.site-main {
margin-right: 0;
margin-left: 0;
@ -574,7 +686,9 @@
}
.no-sidebar {
.twentysixteen {
.site-main {
margin-right: 15%;
margin-left: 15%;
@ -592,11 +706,16 @@
* RTL styles.
*/
.rtl {
.woocommerce, .woocommerce-page {
.woocommerce,
.woocommerce-page {
.col2-set {
.col-1 {
float: right;
}
.col-2 {
float: left;
}

View File

@ -383,10 +383,12 @@ jQuery( function ( $ ) {
var unit_total_tax = accounting.unformat( $line_total_tax.attr( 'data-total_tax' ), woocommerce_admin.mon_decimal_point ) / o_qty;
var $line_subtotal_tax = $( 'input.line_subtotal_tax[data-tax_id="' + tax_id + '"]', $row );
var unit_subtotal_tax = accounting.unformat( $line_subtotal_tax.attr( 'data-subtotal_tax' ), woocommerce_admin.mon_decimal_point ) / o_qty;
var round_at_subtotal = 'yes' === woocommerce_admin_meta_boxes.round_at_subtotal;
var precision = woocommerce_admin_meta_boxes[ round_at_subtotal ? 'rounding_precision' : 'currency_format_num_decimals' ];
if ( 0 < unit_total_tax ) {
$line_total_tax.val(
parseFloat( accounting.formatNumber( unit_total_tax * qty, woocommerce_admin_meta_boxes.rounding_precision, '' ) )
parseFloat( accounting.formatNumber( unit_total_tax * qty, precision, '' ) )
.toString()
.replace( '.', woocommerce_admin.mon_decimal_point )
);
@ -394,7 +396,7 @@ jQuery( function ( $ ) {
if ( 0 < unit_subtotal_tax ) {
$line_subtotal_tax.val(
parseFloat( accounting.formatNumber( unit_subtotal_tax * qty, woocommerce_admin_meta_boxes.rounding_precision, '' ) )
parseFloat( accounting.formatNumber( unit_subtotal_tax * qty, precision, '' ) )
.toString()
.replace( '.', woocommerce_admin.mon_decimal_point )
);
@ -1019,8 +1021,11 @@ jQuery( function ( $ ) {
var unit_total_tax = accounting.unformat( line_total_tax.data( 'total_tax' ), woocommerce_admin.mon_decimal_point ) / qty;
if ( 0 < unit_total_tax ) {
var round_at_subtotal = 'yes' === woocommerce_admin_meta_boxes.round_at_subtotal;
var precision = woocommerce_admin_meta_boxes[ round_at_subtotal ? 'rounding_precision' : 'currency_format_num_decimals' ];
$refund_line_total_tax.val(
parseFloat( accounting.formatNumber( unit_total_tax * refund_qty, woocommerce_admin_meta_boxes.rounding_precision, '' ) )
parseFloat( accounting.formatNumber( unit_total_tax * refund_qty, precision, '' ) )
.toString()
.replace( '.', woocommerce_admin.mon_decimal_point )
).change();

View File

@ -91,6 +91,7 @@ jQuery( function( $ ) {
action : $( this ).data( 'action' ) || 'woocommerce_json_search_products_and_variations',
security : wc_enhanced_select_params.search_products_nonce,
exclude : $( this ).data( 'exclude' ),
exclude_type : $( this ).data( 'exclude_type' ),
include : $( this ).data( 'include' ),
limit : $( this ).data( 'limit' ),
display_stock: $( this ).data( 'display_stock' )
@ -260,14 +261,16 @@ jQuery( function( $ ) {
// WooCommerce Backbone Modal
.on( 'wc_backbone_modal_before_remove', function() {
$( '.wc-enhanced-select, :input.wc-product-search, :input.wc-customer-search' ).filter( '.select2-hidden-accessible' ).selectWoo( 'close' );
$( '.wc-enhanced-select, :input.wc-product-search, :input.wc-customer-search' ).filter( '.select2-hidden-accessible' )
.selectWoo( 'close' );
})
.trigger( 'wc-enhanced-select-init' );
$( 'html' ).on( 'click', function( event ) {
if ( this === event.target ) {
$( '.wc-enhanced-select, :input.wc-product-search, :input.wc-customer-search' ).filter( '.select2-hidden-accessible' ).selectWoo( 'close' );
$( '.wc-enhanced-select, :input.wc-product-search, :input.wc-customer-search' ).filter( '.select2-hidden-accessible' )
.selectWoo( 'close' );
}
} );
} catch( err ) {

View File

@ -216,6 +216,11 @@ jQuery( function( $ ) {
waitForJetpackInstall();
} );
$( '.activate-new-onboarding' ).on( 'click', '.button-primary', function() {
// Show pending spinner while activate happens.
blockWizardUI();
} );
$( '.wc-wizard-services' ).on( 'change', 'input#stripe_create_account, input#ppec_paypal_reroute_requests', function() {
if ( $( this ).is( ':checked' ) ) {
$( this ).closest( '.wc-wizard-service-settings' )

View File

@ -61,16 +61,18 @@
})
.on( 'change', '.wc_input_price[type=text], .wc_input_decimal[type=text], .wc-order-totals #refund_amount[type=text]', function() {
var regex;
var regex, decimalRegex,
decimailPoint = woocommerce_admin.decimal_point;
if ( $( this ).is( '.wc_input_price' ) || $( this ).is( '#refund_amount' ) ) {
regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.mon_decimal_point + ']+', 'gi' );
} else {
regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.decimal_point + ']+', 'gi' );
decimailPoint = woocommerce_admin.mon_decimal_point;
}
regex = new RegExp( '[^\-0-9\%\\' + decimailPoint + ']+', 'gi' );
decimalRegex = new RegExp( '\\' + decimailPoint + '+', 'gi' );
var value = $( this ).val();
var newvalue = value.replace( regex, '' );
var newvalue = value.replace( regex, '' ).replace( decimalRegex, decimailPoint );
if ( value !== newvalue ) {
$( this ).val( newvalue );
@ -78,22 +80,32 @@
})
.on( 'keyup', '.wc_input_price[type=text], .wc_input_decimal[type=text], .wc_input_country_iso[type=text], .wc-order-totals #refund_amount[type=text]', function() {
var regex, error;
var regex, error, decimalRegex;
var checkDecimalNumbers = false;
if ( $( this ).is( '.wc_input_price' ) || $( this ).is( '#refund_amount' ) ) {
checkDecimalNumbers = true;
regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.mon_decimal_point + ']+', 'gi' );
decimalRegex = new RegExp( '[^\\' + woocommerce_admin.mon_decimal_point + ']', 'gi' );
error = 'i18n_mon_decimal_error';
} else if ( $( this ).is( '.wc_input_country_iso' ) ) {
regex = new RegExp( '([^A-Z])+|(.){3,}', 'im' );
error = 'i18n_country_iso_error';
} else {
checkDecimalNumbers = true;
regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.decimal_point + ']+', 'gi' );
decimalRegex = new RegExp( '[^\\' + woocommerce_admin.decimal_point + ']', 'gi' );
error = 'i18n_decimal_error';
}
var value = $( this ).val();
var newvalue = value.replace( regex, '' );
// Check if newvalue have more than one decimal point.
if ( checkDecimalNumbers && 1 < newvalue.replace( decimalRegex, '' ).length ) {
newvalue = newvalue.replace( decimalRegex, '' );
}
if ( value !== newvalue ) {
$( document.body ).triggerHandler( 'wc_add_error_tip', [ $( this ), error ] );
} else {

View File

@ -88,6 +88,18 @@
event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-selection-needed' ).addClass( 'disabled wc-variation-is-unavailable' );
event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' );
}
// If present, the media element library needs initialized on the variation description.
if ( wp.mediaelement ) {
event.data.variationForm.$form.find( '.wp-audio-shortcode, .wp-video-shortcode' )
.not( '.mejs-container' )
.filter(
function () {
return ! $( this ).parent().hasClass( 'mejs-mediaelement' );
}
)
.mediaelementplayer( wp.mediaelement.settings );
}
};
/**

View File

@ -71,7 +71,7 @@ jQuery( function( $ ) {
var data = {};
$.each( $thisbutton.data(), function( key, value ) {
$.each( $thisbutton[0].dataset, function( key, value ) {
data[ key ] = value;
});

View File

@ -41,16 +41,16 @@ jQuery( function( $ ) {
this.$checkout_form.on( 'update', this.trigger_update_checkout );
// Inputs/selects which update totals
this.$checkout_form.on( 'change', 'select.shipping_method, input[name^="shipping_method"], #ship-to-different-address input, .update_totals_on_change select, .update_totals_on_change input[type="radio"], .update_totals_on_change input[type="checkbox"]', this.trigger_update_checkout );
this.$checkout_form.on( 'change', 'select.shipping_method, input[name^="shipping_method"], #ship-to-different-address input, .update_totals_on_change select, .update_totals_on_change input[type="radio"], .update_totals_on_change input[type="checkbox"]', this.trigger_update_checkout ); // eslint-disable-line max-len
this.$checkout_form.on( 'change', '.address-field select', this.input_changed );
this.$checkout_form.on( 'change', '.address-field input.input-text, .update_totals_on_change input.input-text', this.maybe_input_changed );
this.$checkout_form.on( 'keydown', '.address-field input.input-text, .update_totals_on_change input.input-text', this.queue_update_checkout );
this.$checkout_form.on( 'change', '.address-field input.input-text, .update_totals_on_change input.input-text', this.maybe_input_changed ); // eslint-disable-line max-len
this.$checkout_form.on( 'keydown', '.address-field input.input-text, .update_totals_on_change input.input-text', this.queue_update_checkout ); // eslint-disable-line max-len
// Address fields
this.$checkout_form.on( 'change', '#ship-to-different-address input', this.ship_to_different_address );
// Trigger events
this.$checkout_form.find( '#ship-to-different-address input' ).change();
this.init_ship_to_different_address();
this.init_payment_methods();
// Update on page load
@ -135,7 +135,10 @@ jQuery( function( $ ) {
}
},
init_checkout: function() {
$( document.body ).trigger( 'update_checkout' );
// Fire updated_checkout event after existing ready event handlers.
$( function() {
$( document.body ).trigger( 'updated_checkout' );
} );
},
maybe_input_changed: function( e ) {
if ( wc_checkout_form.dirtyInput ) {
@ -180,10 +183,31 @@ jQuery( function( $ ) {
wc_checkout_form.trigger_update_checkout();
}
},
init_ship_to_different_address: function() {
var $checkbox = $( '#ship-to-different-address input' );
if ( ! $checkbox.prop( 'checked' ) ) {
var $billing = $( 'div.woocommerce-billing-fields' );
// Find shipping field values that diverge from billing.
var $differentFields = $( 'div.shipping_address' ).find( 'input, select' ).filter( function() {
$( this ).attr( 'id' ).replace( 'shipping', 'billing' );
var id = $( this ).attr( 'id' ).replace( 'shipping', 'billing' );
return $( this ).val() !== $billing.find( '#' + id ).val();
} );
if ( $differentFields.length > 0 ) {
$checkbox.prop( 'checked', true );
}
}
$( 'div.shipping_address' ).toggle( $checkbox.prop( 'checked' ) );
},
ship_to_different_address: function() {
$( 'div.shipping_address' ).hide();
if ( $( this ).is( ':checked' ) ) {
$( 'div.shipping_address' ).slideDown();
} else {
$( 'div.shipping_address' ).slideUp();
}
},
reset_update_checkout_timer: function() {
@ -207,7 +231,7 @@ jQuery( function( $ ) {
event_type = e.type;
if ( 'input' === event_type ) {
$parent.removeClass( 'woocommerce-invalid woocommerce-invalid-required-field woocommerce-invalid-email woocommerce-validated' );
$parent.removeClass( 'woocommerce-invalid woocommerce-invalid-required-field woocommerce-invalid-email woocommerce-validated' ); // eslint-disable-line max-len
}
if ( 'validate' === event_type || 'change' === event_type ) {
@ -225,7 +249,7 @@ jQuery( function( $ ) {
if ( validate_email ) {
if ( $this.val() ) {
/* https://stackoverflow.com/questions/2855865/jquery-validate-e-mail-address-regex */
var pattern = new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i);
var pattern = new RegExp(/^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([ \t]*\r\n)?[ \t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([ \t]*\r\n)?[ \t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[0-9a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i); // eslint-disable-line max-len
if ( ! pattern.test( $this.val() ) ) {
$parent.removeClass( 'woocommerce-validated' ).addClass( 'woocommerce-invalid woocommerce-invalid-email' );
@ -235,7 +259,7 @@ jQuery( function( $ ) {
}
if ( validated ) {
$parent.removeClass( 'woocommerce-invalid woocommerce-invalid-required-field woocommerce-invalid-email' ).addClass( 'woocommerce-validated' );
$parent.removeClass( 'woocommerce-invalid woocommerce-invalid-required-field woocommerce-invalid-email' ).addClass( 'woocommerce-validated' ); // eslint-disable-line max-len
}
}
},
@ -311,6 +335,7 @@ jQuery( function( $ ) {
if ( false !== args.update_shipping_method ) {
var shipping_methods = {};
// eslint-disable-next-line max-len
$( 'select.shipping_method, input[name^="shipping_method"][type="radio"]:checked, input[name^="shipping_method"][type="hidden"]' ).each( function() {
shipping_methods[ $( this ).data( 'index' ) ] = $( this ).val();
} );
@ -356,13 +381,16 @@ jQuery( function( $ ) {
}
}
});
// Always update the fragments
if ( data && data.fragments ) {
$.each( data.fragments, function ( key, value ) {
$( key ).replaceWith( value );
if ( ! wc_checkout_form.fragments || wc_checkout_form.fragments[ key ] !== value ) {
$( key ).replaceWith( value );
}
$( key ).unblock();
} );
wc_checkout_form.fragments = data.fragments;
}
// Recheck the terms and conditions box, if needed
@ -396,7 +424,7 @@ jQuery( function( $ ) {
// Add new errors returned by this event
if ( data.messages ) {
$form.prepend( '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-updateOrderReview">' + data.messages + '</div>' );
$form.prepend( '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-updateOrderReview">' + data.messages + '</div>' ); // eslint-disable-line max-len
} else {
$form.prepend( data );
}
@ -416,6 +444,26 @@ jQuery( function( $ ) {
});
},
handleUnloadEvent: function( e ) {
// Modern browsers have their own standard generic messages that they will display.
// Confirm, alert, prompt or custom message are not allowed during the unload event
// Browsers will display their own standard messages
// Check if the browser is Internet Explorer
if((navigator.userAgent.indexOf('MSIE') !== -1 ) || (!!document.documentMode)) {
// IE handles unload events differently than modern browsers
e.preventDefault();
return undefined;
}
return true;
},
attachUnloadEventsOnSubmit: function() {
$( window ).on('beforeunload', this.handleUnloadEvent);
},
detachUnloadEventsOnSubmit: function() {
$( window ).unbind('beforeunload', this.handleUnloadEvent);
},
blockOnSubmit: function( $form ) {
var form_data = $form.data();
@ -441,12 +489,16 @@ jQuery( function( $ ) {
}
// Trigger a handler to let gateways manipulate the checkout if needed
// eslint-disable-next-line max-len
if ( $form.triggerHandler( 'checkout_place_order' ) !== false && $form.triggerHandler( 'checkout_place_order_' + wc_checkout_form.get_payment_method() ) !== false ) {
$form.addClass( 'processing' );
wc_checkout_form.blockOnSubmit( $form );
// Attach event to block reloading the page when the form has been submitted
wc_checkout_form.attachUnloadEventsOnSubmit();
// ajaxSetup is global, but we use it to ensure JSON is valid once returned.
$.ajaxSetup( {
dataFilter: function( raw_response, dataType ) {
@ -482,8 +534,11 @@ jQuery( function( $ ) {
data: $form.serialize(),
dataType: 'json',
success: function( result ) {
// Detach the unload handler that prevents a reload / redirect
wc_checkout_form.detachUnloadEventsOnSubmit();
try {
if ( 'success' === result.result ) {
if ( 'success' === result.result && $form.triggerHandler( 'checkout_place_order_success' ) !== false ) {
if ( -1 === result.redirect.indexOf( 'https://' ) || -1 === result.redirect.indexOf( 'http://' ) ) {
window.location = result.redirect;
} else {
@ -510,11 +565,14 @@ jQuery( function( $ ) {
if ( result.messages ) {
wc_checkout_form.submit_error( result.messages );
} else {
wc_checkout_form.submit_error( '<div class="woocommerce-error">' + wc_checkout_params.i18n_checkout_error + '</div>' );
wc_checkout_form.submit_error( '<div class="woocommerce-error">' + wc_checkout_params.i18n_checkout_error + '</div>' ); // eslint-disable-line max-len
}
}
},
error: function( jqXHR, textStatus, errorThrown ) {
// Detach the unload handler that prevents a reload / redirect
wc_checkout_form.detachUnloadEventsOnSubmit();
wc_checkout_form.submit_error( '<div class="woocommerce-error">' + errorThrown + '</div>' );
}
});
@ -524,7 +582,7 @@ jQuery( function( $ ) {
},
submit_error: function( error_message ) {
$( '.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message' ).remove();
wc_checkout_form.$checkout_form.prepend( '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">' + error_message + '</div>' );
wc_checkout_form.$checkout_form.prepend( '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">' + error_message + '</div>' ); // eslint-disable-line max-len
wc_checkout_form.$checkout_form.removeClass( 'processing' ).unblock();
wc_checkout_form.$checkout_form.find( '.input-text, select, input:checkbox' ).trigger( 'validate' ).blur();
wc_checkout_form.scroll_to_notices();

View File

@ -78,4 +78,19 @@ jQuery( function( $ ) {
}, 1000 );
}
};
// Show password visiblity hover icon on woocommerce forms
$( '.woocommerce form .woocommerce-Input[type="password"]' ).wrap( '<span class="password-input"></span>' );
$( '.password-input' ).append( '<span class="show-password-input"></span>' );
$( '.show-password-input' ).click(
function() {
$( this ).toggleClass( 'display-password' );
if ( $( this ).hasClass( 'display-password' ) ) {
$( this ).siblings( ['input[name="password"]', 'input[type="password"]'] ).prop( 'type', 'text' );
} else {
$( this ).siblings( 'input[name="password"]' ).prop( 'type', 'password' );
}
}
);
});

12
babel.config.js Normal file
View File

@ -0,0 +1,12 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
],
};

View File

@ -7,15 +7,16 @@
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
"automattic/jetpack-autoloader": "^1.2.0",
"php": ">=5.6|>=7.0",
"automattic/jetpack-autoloader": "^1.2.0",
"composer/installers": "1.7.0",
"woocommerce/woocommerce-blocks": "2.4.3",
"woocommerce/woocommerce-rest-api": "1.0.3"
"maxmind-db/reader": "1.6.0",
"woocommerce/woocommerce-blocks": "2.5.11",
"woocommerce/woocommerce-rest-api": "1.0.6"
},
"require-dev": {
"phpunit/phpunit": "7.5.16",
"woocommerce/woocommerce-sniffs": "0.0.8"
"phpunit/phpunit": "7.5.20",
"woocommerce/woocommerce-sniffs": "0.0.9"
},
"config": {
"platform": {

257
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c955d86ce8d65e6fb1e0e97282642d7b",
"content-hash": "e6dfd8d640c9fc3f21795ddb41a23477",
"packages": [
{
"name": "automattic/jetpack-autoloader",
"version": "v1.2.0",
"version": "v1.3.2",
"source": {
"type": "git",
"url": "https://github.com/Automattic/jetpack-autoloader.git",
"reference": "4ad9631e68e9da8b8a764615766287becfb27f81"
"reference": "301c2fbcf070d4f0147753447616b6e982bda09e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/4ad9631e68e9da8b8a764615766287becfb27f81",
"reference": "4ad9631e68e9da8b8a764615766287becfb27f81",
"url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/301c2fbcf070d4f0147753447616b6e982bda09e",
"reference": "301c2fbcf070d4f0147753447616b6e982bda09e",
"shasum": ""
},
"require": {
@ -40,7 +40,7 @@
"GPL-2.0-or-later"
],
"description": "Creates a custom autoloader for a plugin or theme.",
"time": "2019-06-24T15:13:23+00:00"
"time": "2019-09-24T06:39:29+00:00"
},
{
"name": "composer/installers",
@ -165,26 +165,86 @@
"time": "2019-08-12T15:00:31+00:00"
},
{
"name": "woocommerce/woocommerce-blocks",
"version": "v2.4.3",
"name": "maxmind-db/reader",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git",
"reference": "9a4b30a18f055ed83d819959cbc1386111f401a5"
"url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
"reference": "febd4920bf17c1da84cef58e56a8227dfb37fbe4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/9a4b30a18f055ed83d819959cbc1386111f401a5",
"reference": "9a4b30a18f055ed83d819959cbc1386111f401a5",
"url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/febd4920bf17c1da84cef58e56a8227dfb37fbe4",
"reference": "febd4920bf17c1da84cef58e56a8227dfb37fbe4",
"shasum": ""
},
"require": {
"automattic/jetpack-autoloader": "1.2.0",
"php": ">=5.6"
},
"conflict": {
"ext-maxminddb": "<1.6.0,>=2.0.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "2.*",
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpcov": "^3.0",
"phpunit/phpunit": "5.*",
"squizlabs/php_codesniffer": "3.*"
},
"suggest": {
"ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
"ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
"ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
},
"type": "library",
"autoload": {
"psr-4": {
"MaxMind\\Db\\": "src/MaxMind/Db"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Gregory J. Oschwald",
"email": "goschwald@maxmind.com",
"homepage": "https://www.maxmind.com/"
}
],
"description": "MaxMind DB Reader API",
"homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php",
"keywords": [
"database",
"geoip",
"geoip2",
"geolocation",
"maxmind"
],
"time": "2019-12-19T22:59:03+00:00"
},
{
"name": "woocommerce/woocommerce-blocks",
"version": "v2.5.11",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git",
"reference": "3d3c7bf1b425bbf39a222a4715b1c8efe9e72f60"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/3d3c7bf1b425bbf39a222a4715b1c8efe9e72f60",
"reference": "3d3c7bf1b425bbf39a222a4715b1c8efe9e72f60",
"shasum": ""
},
"require": {
"automattic/jetpack-autoloader": "1.3.2",
"composer/installers": "1.7.0"
},
"require-dev": {
"phpunit/phpunit": "6.5.14",
"woocommerce/woocommerce-sniffs": "0.0.6"
"woocommerce/woocommerce-sniffs": "0.0.7"
},
"type": "wordpress-plugin",
"extra": {
@ -209,28 +269,28 @@
"gutenberg",
"woocommerce"
],
"time": "2019-10-14T13:20:09+00:00"
"time": "2020-01-20T20:26:05+00:00"
},
{
"name": "woocommerce/woocommerce-rest-api",
"version": "1.0.3",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-rest-api.git",
"reference": "7d9babf1c25890c32df3edb28b8351732640f5ce"
"reference": "78ccf4d4c6bafbc841182b68aa863e7b0caa37c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-rest-api/zipball/7d9babf1c25890c32df3edb28b8351732640f5ce",
"reference": "7d9babf1c25890c32df3edb28b8351732640f5ce",
"url": "https://api.github.com/repos/woocommerce/woocommerce-rest-api/zipball/78ccf4d4c6bafbc841182b68aa863e7b0caa37c8",
"reference": "78ccf4d4c6bafbc841182b68aa863e7b0caa37c8",
"shasum": ""
},
"require": {
"automattic/jetpack-autoloader": "1.2.0"
"automattic/jetpack-autoloader": "^1.2.0"
},
"require-dev": {
"phpunit/phpunit": "6.5.14",
"woocommerce/woocommerce-sniffs": "0.0.6"
"woocommerce/woocommerce-sniffs": "0.0.9"
},
"type": "wordpress-plugin",
"autoload": {
@ -249,7 +309,7 @@
],
"description": "The WooCommerce core REST API.",
"homepage": "https://github.com/woocommerce/woocommerce-rest-api",
"time": "2019-07-16T14:27:40+00:00"
"time": "2020-01-15T23:29:39+00:00"
}
],
"packages-dev": [
@ -321,16 +381,16 @@
},
{
"name": "doctrine/instantiator",
"version": "1.2.0",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "a2c590166b2133a4633738648b6b064edae0814a"
"reference": "ae466f726242e637cebdd526a7d991b9433bacf1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a",
"reference": "a2c590166b2133a4633738648b6b064edae0814a",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1",
"reference": "ae466f726242e637cebdd526a7d991b9433bacf1",
"shasum": ""
},
"require": {
@ -373,20 +433,20 @@
"constructor",
"instantiate"
],
"time": "2019-03-17T17:37:11+00:00"
"time": "2019-10-21T16:45:58+00:00"
},
{
"name": "myclabs/deep-copy",
"version": "1.9.3",
"version": "1.9.4",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea"
"reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea",
"reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7",
"reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7",
"shasum": ""
},
"require": {
@ -421,7 +481,7 @@
"object",
"object graph"
],
"time": "2019-08-09T12:45:53+00:00"
"time": "2019-12-15T19:12:40+00:00"
},
{
"name": "phar-io/manifest",
@ -527,16 +587,16 @@
},
{
"name": "phpcompatibility/php-compatibility",
"version": "9.3.1",
"version": "9.3.5",
"source": {
"type": "git",
"url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
"reference": "9999344e47e7af6b00e1a898eacc4e4368fb7196"
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9999344e47e7af6b00e1a898eacc4e4368fb7196",
"reference": "9999344e47e7af6b00e1a898eacc4e4368fb7196",
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
"shasum": ""
},
"require": {
@ -581,20 +641,20 @@
"phpcs",
"standards"
],
"time": "2019-09-05T18:36:49+00:00"
"time": "2019-12-27T09:44:58+00:00"
},
{
"name": "phpcompatibility/phpcompatibility-paragonie",
"version": "1.1.0",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
"reference": "b1bb79a7cab1fb856b56f1b5cf110b6e52d8e936"
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b1bb79a7cab1fb856b56f1b5cf110b6e52d8e936",
"reference": "b1bb79a7cab1fb856b56f1b5cf110b6e52d8e936",
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c",
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c",
"shasum": ""
},
"require": {
@ -633,7 +693,7 @@
"polyfill",
"standards"
],
"time": "2019-08-28T15:58:19+00:00"
"time": "2019-11-04T15:17:54+00:00"
},
{
"name": "phpcompatibility/phpcompatibility-wp",
@ -739,16 +799,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "4.3.2",
"version": "4.3.4",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e"
"reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c",
"reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c",
"shasum": ""
},
"require": {
@ -760,6 +820,7 @@
"require-dev": {
"doctrine/instantiator": "^1.0.5",
"mockery/mockery": "^1.0",
"phpdocumentor/type-resolver": "0.4.*",
"phpunit/phpunit": "^6.4"
},
"type": "library",
@ -786,7 +847,7 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2019-09-12T14:27:41+00:00"
"time": "2019-12-28T18:55:12+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@ -837,33 +898,33 @@
},
{
"name": "phpspec/prophecy",
"version": "1.8.1",
"version": "1.10.1",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76"
"reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
"reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
"reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
"sebastian/comparator": "^1.1|^2.0|^3.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
"sebastian/comparator": "^1.2.3|^2.0|^3.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
"require-dev": {
"phpspec/phpspec": "^2.5|^3.2",
"phpspec/phpspec": "^2.5 || ^3.2",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
"dev-master": "1.10.x-dev"
}
},
"autoload": {
@ -896,7 +957,7 @@
"spy",
"stub"
],
"time": "2019-06-13T12:50:23+00:00"
"time": "2019-12-22T21:05:45+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -1152,16 +1213,16 @@
},
{
"name": "phpunit/phpunit",
"version": "7.5.16",
"version": "7.5.20",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "316afa6888d2562e04aeb67ea7f2017a0eb41661"
"reference": "9467db479d1b0487c99733bb1e7944d32deded2c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/316afa6888d2562e04aeb67ea7f2017a0eb41661",
"reference": "316afa6888d2562e04aeb67ea7f2017a0eb41661",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c",
"reference": "9467db479d1b0487c99733bb1e7944d32deded2c",
"shasum": ""
},
"require": {
@ -1232,7 +1293,7 @@
"testing",
"xunit"
],
"time": "2019-09-14T09:08:39+00:00"
"time": "2020-01-08T08:45:45+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@ -1401,16 +1462,16 @@
},
{
"name": "sebastian/environment",
"version": "4.2.2",
"version": "4.2.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404"
"reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
"reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368",
"reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368",
"shasum": ""
},
"require": {
@ -1450,7 +1511,7 @@
"environment",
"hhvm"
],
"time": "2019-05-05T09:05:15+00:00"
"time": "2019-11-20T08:46:58+00:00"
},
{
"name": "sebastian/exporter",
@ -1802,16 +1863,16 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.5.0",
"version": "3.5.3",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "0afebf16a2e7f1e434920fa976253576151effe9"
"reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/0afebf16a2e7f1e434920fa976253576151effe9",
"reference": "0afebf16a2e7f1e434920fa976253576151effe9",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb",
"reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb",
"shasum": ""
},
"require": {
@ -1849,20 +1910,20 @@
"phpcs",
"standards"
],
"time": "2019-09-26T23:12:26+00:00"
"time": "2019-12-04T04:46:47+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.12.0",
"version": "v1.13.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "550ebaac289296ce228a706d0867afc34687e3f4"
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4",
"reference": "550ebaac289296ce228a706d0867afc34687e3f4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"shasum": ""
},
"require": {
@ -1874,7 +1935,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.12-dev"
"dev-master": "1.13-dev"
}
},
"autoload": {
@ -1907,7 +1968,7 @@
"polyfill",
"portable"
],
"time": "2019-08-06T08:03:45+00:00"
"time": "2019-11-27T13:56:44+00:00"
},
{
"name": "theseer/tokenizer",
@ -1951,31 +2012,29 @@
},
{
"name": "webmozart/assert",
"version": "1.5.0",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "88e6d84706d09a236046d686bbea96f07b3a34f4"
"reference": "573381c0a64f155a0d9a23f4b0c797194805b925"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4",
"reference": "88e6d84706d09a236046d686bbea96f07b3a34f4",
"url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925",
"reference": "573381c0a64f155a0d9a23f4b0c797194805b925",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"vimeo/psalm": "<3.6.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
@ -1997,27 +2056,27 @@
"check",
"validate"
],
"time": "2019-08-24T08:43:50+00:00"
"time": "2019-11-24T13:36:37+00:00"
},
{
"name": "woocommerce/woocommerce-sniffs",
"version": "0.0.8",
"version": "0.0.9",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-sniffs.git",
"reference": "ccdae93ba678d59cd9741bec077d0c63c0a82958"
"reference": "7677a84e9a355fe1e088f704090be891e7a6d427"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/ccdae93ba678d59cd9741bec077d0c63c0a82958",
"reference": "ccdae93ba678d59cd9741bec077d0c63c0a82958",
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/7677a84e9a355fe1e088f704090be891e7a6d427",
"reference": "7677a84e9a355fe1e088f704090be891e7a6d427",
"shasum": ""
},
"require": {
"dealerdirect/phpcodesniffer-composer-installer": "0.5.0",
"php": ">=7.0",
"phpcompatibility/phpcompatibility-wp": "2.1.0",
"wp-coding-standards/wpcs": "2.1.1"
"wp-coding-standards/wpcs": "2.2.0"
},
"type": "phpcodesniffer-standard",
"notification-url": "https://packagist.org/downloads/",
@ -2037,20 +2096,20 @@
"woocommerce",
"wordpress"
],
"time": "2019-10-16T18:25:21+00:00"
"time": "2019-11-11T15:48:34+00:00"
},
{
"name": "wp-coding-standards/wpcs",
"version": "2.1.1",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
"reference": "bd9c33152115e6741e3510ff7189605b35167908"
"reference": "f90e8692ce97b693633db7ab20bfa78d930f536a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/bd9c33152115e6741e3510ff7189605b35167908",
"reference": "bd9c33152115e6741e3510ff7189605b35167908",
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/f90e8692ce97b693633db7ab20bfa78d930f536a",
"reference": "f90e8692ce97b693633db7ab20bfa78d930f536a",
"shasum": ""
},
"require": {
@ -2073,7 +2132,7 @@
"authors": [
{
"name": "Contributors",
"homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors"
"homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
}
],
"description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
@ -2082,7 +2141,7 @@
"standards",
"wordpress"
],
"time": "2019-05-21T02:50:00+00:00"
"time": "2019-11-11T12:34:03+00:00"
}
],
"aliases": [],

57
docker-compose.yaml Normal file
View File

@ -0,0 +1,57 @@
version: '3.7'
services:
db:
image: mariadb:10.4
restart: on-failure
environment:
MYSQL_DATABASE: testdb
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
volumes:
- db:/var/lib/mysql
wordpress-woocommerce-dev:
depends_on:
- db
build:
context: .
dockerfile: Dockerfile
ports:
- 8084:80
restart: on-failure
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: testdb
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_TABLE_PREFIX: "wp_"
WORDPRESS_DEBUG: 1
volumes:
- "./:/var/www/html/wp-content/plugins/woocommerce"
- wordpress:/var/www/html
wordpress-cli:
depends_on:
- db
- wordpress-woocommerce-dev
image: wordpress:cli
restart: on-failure
user: xfs
command: >
/bin/sh -c '
wp core install --url=http://localhost:8084 --title="WooCommerce Core E2E Test Suite" --admin_user=admin --admin_password=password --admin_email=admin@woocommercecoree2etestsuite.com --path=/var/www/html --skip-email;
wp plugin activate woocommerce;
wp theme install twentynineteen --activate;
wp user create customer customer@woocommercecoree2etestsuite.com --user_pass=password --role=customer --path=/var/www/html;
wp post create --post_type=page --post_status=publish --post_title='Ready' --post_content='E2E-tests.';
'
volumes:
- "./:/var/www/html/wp-content/plugins/woocommerce"
- wordpress:/var/www/html
volumes:
db:
wordpress:

View File

@ -698,6 +698,26 @@ return array(
),
'KR' => array(),
'KW' => array(),
'LA' => array(
'AT' => __( 'Attapeu', 'woocommerce' ),
'BK' => __( 'Bokeo', 'woocommerce' ),
'BL' => __( 'Bolikhamsai', 'woocommerce' ),
'CH' => __( 'Champasak', 'woocommerce' ),
'HO' => __( 'Houaphanh', 'woocommerce' ),
'KH' => __( 'Khammouane', 'woocommerce' ),
'LM' => __( 'Luang Namtha', 'woocommerce' ),
'LP' => __( 'Luang Prabang', 'woocommerce' ),
'OU' => __( 'Oudomxay', 'woocommerce' ),
'PH' => __( 'Phongsaly', 'woocommerce' ),
'SL' => __( 'Salavan', 'woocommerce' ),
'SV' => __( 'Savannakhet', 'woocommerce' ),
'VI' => __( 'Vientiane Province', 'woocommerce' ),
'VT' => __( 'Vientiane', 'woocommerce' ),
'XA' => __( 'Sainyabuli', 'woocommerce' ),
'XE' => __( 'Sekong', 'woocommerce' ),
'XI' => __( 'Xiangkhouang', 'woocommerce' ),
'XS' => __( 'Xaisomboun', 'woocommerce' ),
),
'LB' => array(),
'LR' => array( // Liberia provinces.
'BM' => __( 'Bomi', 'woocommerce' ),

View File

@ -346,10 +346,10 @@ abstract class WC_Data {
} else {
$value = array_intersect_key( $meta_data, array_flip( $array_keys ) );
}
}
if ( 'view' === $context ) {
$value = apply_filters( $this->get_hook_prefix() . $key, $value, $this );
}
if ( 'view' === $context ) {
$value = apply_filters( $this->get_hook_prefix() . $key, $value, $this );
}
return $value;

View File

@ -80,6 +80,6 @@ abstract class WC_Integration extends WC_Settings_API {
*/
public function init_settings() {
parent::init_settings();
$this->enabled = ! empty( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled'] ? 'yes' : 'no';
$this->enabled = ! empty( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled'] ? 'yes' : 'no';
}
}

View File

@ -39,15 +39,19 @@ abstract class WC_Log_Handler implements WC_Log_Handler_Interface {
* @return string Formatted log entry.
*/
protected static function format_entry( $timestamp, $level, $message, $context ) {
$time_string = self::format_time( $timestamp );
$time_string = self::format_time( $timestamp );
$level_string = strtoupper( $level );
$entry = "{$time_string} {$level_string} {$message}";
$entry = "{$time_string} {$level_string} {$message}";
return apply_filters( 'woocommerce_format_log_entry', $entry, array(
'timestamp' => $timestamp,
'level' => $level,
'message' => $message,
'context' => $context,
) );
return apply_filters(
'woocommerce_format_log_entry',
$entry,
array(
'timestamp' => $timestamp,
'level' => $level,
'message' => $message,
'context' => $context,
)
);
}
}

View File

@ -18,6 +18,7 @@ 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 {
use WC_Item_Totals;
/**
* Order Data array. This is the core order data exposed in APIs since 3.0.0.
@ -769,6 +770,23 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
return apply_filters( 'woocommerce_order_get_items', $items, $this, $types );
}
/**
* Return array of values for calculations.
*
* @param string $field Field name to return.
*
* @return array Array of values.
*/
protected function get_values_for_total( $field ) {
$items = array_map(
function ( $item ) use ( $field ) {
return wc_add_number_precision( $item[ $field ], false );
},
array_values( $this->get_items() )
);
return $items;
}
/**
* Return an array of coupons within this order.
*
@ -961,6 +979,128 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
}
}
/**
* Check and records coupon usage tentatively so that counts validation is correct. Display an error if coupon usage limit has been reached.
*
* If you are using this method, make sure to `release_held_coupons` in case an Exception is thrown.
*
* @throws Exception When not able to apply coupon.
*
* @param string $billing_email Billing email of order.
*/
public function hold_applied_coupons( $billing_email ) {
$held_keys = array();
$held_keys_for_user = array();
$error = null;
try {
foreach ( WC()->cart->get_applied_coupons() as $code ) {
$coupon = new WC_Coupon( $code );
if ( ! $coupon->get_data_store() ) {
continue;
}
// Hold coupon for when global coupon usage limit is present.
if ( 0 < $coupon->get_usage_limit() ) {
$held_key = $this->hold_coupon( $coupon );
if ( $held_key ) {
$held_keys[ $coupon->get_id() ] = $held_key;
}
}
// Hold coupon for when usage limit per customer is enabled.
if ( 0 < $coupon->get_usage_limit_per_user() ) {
if ( ! isset( $user_ids_and_emails ) ) {
$user_alias = get_current_user_id() ? wp_get_current_user()->ID : sanitize_email( $billing_email );
$user_ids_and_emails = $this->get_billing_and_current_user_aliases( $billing_email );
}
$held_key_for_user = $this->hold_coupon_for_users( $coupon, $user_ids_and_emails, $user_alias );
if ( $held_key_for_user ) {
$held_keys_for_user[ $coupon->get_id() ] = $held_key_for_user;
}
}
}
} catch ( Exception $e ) {
$error = $e;
} finally {
// Even in case of error, we will save keys for whatever coupons that were held so our data remains accurate.
// We save them in bulk instead of one by one for performance reasons.
if ( 0 < count( $held_keys_for_user ) || 0 < count( $held_keys ) ) {
$this->get_data_store()->set_coupon_held_keys( $this, $held_keys, $held_keys_for_user );
}
if ( $error instanceof Exception ) {
throw $error;
}
}
}
/**
* Hold coupon if a global usage limit is defined.
*
* @param WC_Coupon $coupon Coupon object.
*
* @return string Meta key which indicates held coupon.
* @throws Exception When can't be held.
*/
private function hold_coupon( $coupon ) {
$result = $coupon->get_data_store()->check_and_hold_coupon( $coupon );
if ( false === $result ) {
// translators: Actual coupon code.
throw new Exception( sprintf( __( 'An unexpected error happened while applying the Coupon %s.', 'woocommerce' ), $coupon->get_code() ) );
} elseif ( 0 === $result ) {
// translators: Actual coupon code.
throw new Exception( sprintf( __( 'Coupon %s was used in another transaction during this checkout, and coupon usage limit is reached. Please remove the coupon and try again.', 'woocommerce' ), $coupon->get_code() ) );
}
return $result;
}
/**
* Hold coupon if usage limit per customer is defined.
*
* @param WC_Coupon $coupon Coupon object.
* @param array $user_ids_and_emails Array of user Id and emails to check for usage limit.
* @param string $user_alias User ID or email to use to record current usage.
*
* @return string Meta key which indicates held coupon.
* @throws Exception When coupon can't be held.
*/
private function hold_coupon_for_users( $coupon, $user_ids_and_emails, $user_alias ) {
$result = $coupon->get_data_store()->check_and_hold_coupon_for_user( $coupon, $user_ids_and_emails, $user_alias );
if ( false === $result ) {
// translators: Actual coupon code.
throw new Exception( sprintf( __( 'An unexpected error happened while applying the Coupon %s.', 'woocommerce' ), $coupon->get_code() ) );
} elseif ( 0 === $result ) {
// translators: Actual coupon code.
throw new Exception( sprintf( __( 'You have used this coupon %s in another transaction during this checkout, and coupon usage limit is reached. Please remove the coupon and try again.', 'woocommerce' ), $coupon->get_code() ) );
}
return $result;
}
/**
* Helper method to get all aliases for current user and provide billing email.
*
* @param string $billing_email Billing email provided in form.
*
* @return array Array of all aliases.
* @throws Exception When validation fails.
*/
private function get_billing_and_current_user_aliases( $billing_email ) {
$emails = array( $billing_email );
if ( get_current_user_id() ) {
$emails[] = wp_get_current_user()->user_email;
}
$emails = array_unique(
array_map( 'strtolower', array_map( 'sanitize_email', $emails ) )
);
$customer_data_store = WC_Data_Store::load( 'customer' );
$user_ids = $customer_data_store->get_user_ids_for_billing_email( $emails );
return array_merge( $user_ids, $emails );
}
/**
* Apply a coupon to the order and recalculate totals.
*
@ -978,13 +1118,6 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( $coupon->get_code() !== $code ) {
return new WP_Error( 'invalid_coupon', __( 'Invalid coupon code', 'woocommerce' ) );
}
$discounts = new WC_Discounts( $this );
$valid = $discounts->is_coupon_valid( $coupon );
if ( is_wp_error( $valid ) ) {
return $valid;
}
} else {
return new WP_Error( 'invalid_coupon', __( 'Invalid coupon', 'woocommerce' ) );
}
@ -1498,6 +1631,34 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$this->save();
}
/**
* Helper function.
* If you add all items in this order in cart again, this would be the cart subtotal (assuming all other settings are same).
*
* @return float Cart subtotal.
*/
protected function get_cart_subtotal_for_order() {
return wc_remove_number_precision(
$this->get_rounded_items_total(
$this->get_values_for_total( 'subtotal' )
)
);
}
/**
* Helper function.
* If you add all items in this order in cart again, this would be the cart total (assuming all other settings are same).
*
* @return float Cart total.
*/
protected function get_cart_total_for_order() {
return wc_remove_number_precision(
$this->get_rounded_items_total(
$this->get_values_for_total( 'total' )
)
);
}
/**
* Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total.
*
@ -1508,18 +1669,13 @@ 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;
$fees_total = 0;
$fees_total = 0;
$shipping_total = 0;
$cart_subtotal_tax = 0;
$cart_total_tax = 0;
// Sum line item costs.
foreach ( $this->get_items() as $item ) {
$cart_subtotal += round( $item->get_subtotal(), wc_get_price_decimals() );
$cart_total += round( $item->get_total(), wc_get_price_decimals() );
}
$cart_subtotal = $this->get_cart_subtotal_for_order();
$cart_total = $this->get_cart_total_for_order();
// Sum shipping costs.
foreach ( $this->get_shipping_methods() as $shipping ) {
@ -1740,15 +1896,16 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
*/
public function get_subtotal_to_display( $compound = false, $tax_display = '' ) {
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
$subtotal = 0;
$subtotal = $this->get_cart_subtotal_for_order();
if ( ! $compound ) {
foreach ( $this->get_items() as $item ) {
$subtotal += $item->get_subtotal();
if ( 'incl' === $tax_display ) {
$subtotal += $item->get_subtotal_tax();
if ( 'incl' === $tax_display ) {
$subtotal_taxes = 0;
foreach ( $this->get_items() as $item ) {
$subtotal_taxes += self::round_line_tax( $item->get_subtotal_tax(), false );
}
$subtotal += wc_round_tax_total( $subtotal_taxes );
}
$subtotal = wc_price( $subtotal, array( 'currency' => $this->get_currency() ) );
@ -1761,10 +1918,6 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
return '';
}
foreach ( $this->get_items() as $item ) {
$subtotal += $item->get_subtotal();
}
// Add Shipping Costs.
$subtotal += $this->get_shipping_total();

View File

@ -131,6 +131,13 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
*/
public $new_method_label = '';
/**
* Pay button ID if supported.
*
* @var string
*/
public $pay_button_id = '';
/**
* Contains a users saved tokens for this gateway.
*
@ -190,7 +197,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
*/
public function init_settings() {
parent::init_settings();
$this->enabled = ! empty( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled'] ? 'yes' : 'no';
$this->enabled = ! empty( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled'] ? 'yes' : 'no';
}
/**
@ -230,7 +237,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
*/
public function get_transaction_url( $order ) {
$return_url = '';
$return_url = '';
$transaction_id = $order->get_transaction_id();
if ( ! empty( $this->view_transaction_url ) && ! empty( $transaction_id ) ) {
@ -247,7 +254,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
*/
protected function get_order_total() {
$total = 0;
$total = 0;
$order_id = absint( get_query_var( 'order-pay' ) );
// Gets order total from "pay for order" page.
@ -317,6 +324,16 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
return apply_filters( 'woocommerce_gateway_icon', $icon, $this->id );
}
/**
* Return the gateway's pay button ID.
*
* @since 3.9.0
* @return string
*/
public function get_pay_button_id() {
return sanitize_html_class( $this->pay_button_id );
}
/**
* Set as current gateway.
*
@ -412,7 +429,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
}
/**
* Core credit card form which gateways can used if needed. Deprecated - inherit WC_Payment_Gateway_CC instead.
* Core credit card form which gateways can use if needed. Deprecated - inherit WC_Payment_Gateway_CC instead.
*
* @param array $args Arguments.
* @param array $fields Fields.
@ -439,7 +456,9 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
);
wp_localize_script(
'woocommerce-tokenization-form', 'wc_tokenization_form_params', array(
'woocommerce-tokenization-form',
'wc_tokenization_form_params',
array(
'is_registration_required' => WC()->checkout()->is_registration_required(),
'is_logged_in' => is_user_logged_in(),
)
@ -521,7 +540,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
esc_html__( 'Save to account', 'woocommerce' )
);
echo apply_filters( 'woocommerce_payment_gateway_save_new_payment_method_option_html', $html, $this );
echo apply_filters( 'woocommerce_payment_gateway_save_new_payment_method_option_html', $html, $this ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**

View File

@ -61,9 +61,9 @@ abstract class WC_Abstract_Privacy {
* @param int $erase_priority Erase priority.
*/
public function __construct( $name = '', $export_priority = 5, $erase_priority = 10 ) {
$this->name = $name;
$this->name = $name;
$this->export_priority = $export_priority;
$this->erase_priority = $erase_priority;
$this->erase_priority = $erase_priority;
$this->init();
}

View File

@ -1517,11 +1517,11 @@ class WC_Product extends WC_Abstract_Legacy_Product {
if ( '' !== (string) $this->get_sale_price( $context ) && $this->get_regular_price( $context ) > $this->get_sale_price( $context ) ) {
$on_sale = true;
if ( $this->get_date_on_sale_from( $context ) && $this->get_date_on_sale_from( $context )->getTimestamp() > current_time( 'timestamp', true ) ) {
if ( $this->get_date_on_sale_from( $context ) && $this->get_date_on_sale_from( $context )->getTimestamp() > time() ) {
$on_sale = false;
}
if ( $this->get_date_on_sale_to( $context ) && $this->get_date_on_sale_to( $context )->getTimestamp() < current_time( 'timestamp', true ) ) {
if ( $this->get_date_on_sale_to( $context ) && $this->get_date_on_sale_to( $context )->getTimestamp() < time() ) {
$on_sale = false;
}
} else {
@ -1859,7 +1859,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
}
if ( ! $image && $placeholder ) {
$image = wc_placeholder_img( $size );
$image = wc_placeholder_img( $size, $attr );
}
return apply_filters( 'woocommerce_product_get_image', $image, $this, $size, $attr, $placeholder, $image );

View File

@ -874,7 +874,8 @@ abstract class WC_Settings_API {
*/
public function validate_textarea_field( $key, $value ) {
$value = is_null( $value ) ? '' : $value;
return wp_kses( trim( stripslashes( $value ) ),
return wp_kses(
trim( stripslashes( $value ) ),
array_merge(
array(
'iframe' => array(

View File

@ -268,13 +268,13 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
wp_parse_args(
$args,
array(
'id' => $this->get_rate_id(), // ID for the rate. If not passed, this id:instance default will be used.
'label' => '', // Label for the rate.
'cost' => '0', // Amount or array of costs (per item shipping).
'taxes' => '', // Pass taxes, or leave empty to have it calculated for you, or 'false' to disable calculations.
'calc_tax' => 'per_order', // Calc tax per_order or per_item. Per item needs an array of costs.
'meta_data' => array(), // Array of misc meta data to store along with this rate - key value pairs.
'package' => false, // Package array this rate was generated for @since 2.6.0.
'id' => $this->get_rate_id(), // ID for the rate. If not passed, this id:instance default will be used.
'label' => '', // Label for the rate.
'cost' => '0', // Amount or array of costs (per item shipping).
'taxes' => '', // Pass taxes, or leave empty to have it calculated for you, or 'false' to disable calculations.
'calc_tax' => 'per_order', // Calc tax per_order or per_item. Per item needs an array of costs.
'meta_data' => array(), // Array of misc meta data to store along with this rate - key value pairs.
'package' => false, // Package array this rate was generated for @since 2.6.0.
'price_decimals' => wc_get_price_decimals(),
)
),

View File

@ -78,6 +78,11 @@ abstract class WC_Widget extends WP_Widget {
* @return bool true if the widget is cached otherwise false
*/
public function get_cached_widget( $args ) {
// Don't get cache if widget_id doesn't exists.
if ( empty( $args['widget_id'] ) ) {
return false;
}
$cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' );
if ( ! is_array( $cache ) ) {
@ -100,6 +105,11 @@ abstract class WC_Widget extends WP_Widget {
* @return string the content that was cached
*/
public function cache_widget( $args, $content ) {
// Don't set any cache if widget_id doesn't exist.
if ( empty( $args['widget_id'] ) ) {
return $content;
}
$cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' );
if ( ! is_array( $cache ) ) {

View File

@ -488,7 +488,7 @@ class WC_Admin_Addons {
$back_admin_path = add_query_arg( array() );
return array(
'wccom-site' => site_url(),
'wccom-back' => esc_url( $back_admin_path ),
'wccom-back' => rawurlencode( $back_admin_path ),
'wccom-woo-version' => WC_VERSION,
'wccom-connect-nonce' => wp_create_nonce( 'connect' ),
);
@ -537,7 +537,7 @@ class WC_Admin_Addons {
*/
public static function output() {
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '_featured';
$search = isset( $_GET['search'] ) ? sanitize_text_field( wp_unslash( $_GET['search'] ) ) : '';
$search = isset( $_GET['search'] ) ? sanitize_text_field( wp_unslash( $_GET['search'] ) ) : '';
if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
do_action( 'woocommerce_helper_output' );

View File

@ -103,8 +103,10 @@ class WC_Admin_API_Keys_Table_List extends WP_List_Table {
add_query_arg(
array(
'revoke-key' => $key['key_id'],
), admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys' )
), 'revoke'
),
admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys' )
),
'revoke'
)
) . '">' . esc_html__( 'Revoke', 'woocommerce' ) . '</a>';
}
@ -221,7 +223,10 @@ class WC_Admin_API_Keys_Table_List extends WP_List_Table {
echo '<label class="screen-reader-text" for="' . esc_attr( $input_id ) . '">' . esc_html( $text ) . ':</label>';
echo '<input type="search" id="' . esc_attr( $input_id ) . '" name="s" value="' . esc_attr( $search_query ) . '" />';
submit_button(
$text, '', '', false,
$text,
'',
'',
false,
array(
'id' => 'search-submit',
)
@ -253,7 +258,8 @@ class WC_Admin_API_Keys_Table_List extends WP_List_Table {
// Get the API keys.
$keys = $wpdb->get_results(
"SELECT key_id, user_id, description, permissions, truncated_key, last_access FROM {$wpdb->prefix}woocommerce_api_keys WHERE 1 = 1 {$search}" .
$wpdb->prepare( 'ORDER BY key_id DESC LIMIT %d OFFSET %d;', $per_page, $offset ), ARRAY_A
$wpdb->prepare( 'ORDER BY key_id DESC LIMIT %d OFFSET %d;', $per_page, $offset ),
ARRAY_A
); // WPCS: unprepared SQL ok.
$count = $wpdb->get_var( "SELECT COUNT(key_id) FROM {$wpdb->prefix}woocommerce_api_keys WHERE 1 = 1 {$search};" ); // WPCS: unprepared SQL ok.

View File

@ -81,7 +81,8 @@ class WC_Admin_API_Keys {
// Add screen option.
add_screen_option(
'per_page', array(
'per_page',
array(
'default' => 10,
'option' => 'woocommerce_keys_per_page',
)
@ -95,7 +96,7 @@ class WC_Admin_API_Keys {
private static function table_list_output() {
global $wpdb, $keys_table_list;
echo '<h2>' . esc_html__( 'REST API', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys&create-key=1' ) ) . '" class="add-new-h2">' . esc_html__( 'Add key', 'woocommerce' ) . '</a></h2>';
echo '<h2 class="wc-table-list-header">' . esc_html__( 'REST API', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys&create-key=1' ) ) . '" class="add-new-h2">' . esc_html__( 'Add key', 'woocommerce' ) . '</a></h2>';
// Get the API keys count.
$count = $wpdb->get_var( "SELECT COUNT(key_id) FROM {$wpdb->prefix}woocommerce_api_keys WHERE 1 = 1;" );
@ -148,7 +149,8 @@ class WC_Admin_API_Keys {
FROM {$wpdb->prefix}woocommerce_api_keys
WHERE key_id = %d",
$key_id
), ARRAY_A
),
ARRAY_A
);
if ( is_null( $key ) ) {

View File

@ -169,9 +169,9 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
$params = array(
/* translators: %s: decimal */
'i18n_decimal_error' => sprintf( __( 'Please enter in decimal (%s) format without thousand separators.', 'woocommerce' ), $decimal ),
'i18n_decimal_error' => sprintf( __( 'Please enter with one decimal point (%s) without thousand separators.', 'woocommerce' ), $decimal ),
/* translators: %s: price decimal separator */
'i18n_mon_decimal_error' => sprintf( __( 'Please enter in monetary decimal (%s) format without thousand separators and currency symbols.', 'woocommerce' ), wc_get_price_decimal_separator() ),
'i18n_mon_decimal_error' => sprintf( __( 'Please enter with one monetary decimal point (%s) without thousand separators and currency symbols.', 'woocommerce' ), wc_get_price_decimal_separator() ),
'i18n_country_iso_error' => __( 'Please enter in country code with two capital letters.', 'woocommerce' ),
'i18n_sale_less_than_regular_error' => __( 'Please enter in a value less than the regular price.', 'woocommerce' ),
'i18n_delete_product_notice' => __( 'This product has produced sales and may be linked to existing orders. Are you sure you want to delete it?', 'woocommerce' ),
@ -295,7 +295,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
if ( $post_id && in_array( get_post_type( $post_id ), wc_get_order_types( 'order-meta-boxes' ) ) ) {
$order = wc_get_order( $post_id );
if ( $order ) {
$currency = $order->get_currency();
$currency = $order->get_currency();
if ( ! $order->has_status( array( 'pending', 'failed', 'cancelled' ) ) ) {
$remove_item_notice = $remove_item_notice . ' ' . __( "You may need to manually restore the item's stock.", 'woocommerce' );

View File

@ -1,17 +1,15 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Duplicate product functionality
*
* @author WooCommerce
* @category Admin
* @package WooCommerce/Admin
* @version 3.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Admin_Duplicate_Product', false ) ) {
return new WC_Admin_Duplicate_Product();
}
@ -87,12 +85,10 @@ class WC_Admin_Duplicate_Product {
return;
}
if ( isset( $_GET['post'] ) ) {
$notify_url = wp_nonce_url( admin_url( 'edit.php?post_type=product&action=duplicate_product&post=' . absint( $_GET['post'] ) ), 'woocommerce-duplicate-product_' . $_GET['post'] );
?>
<div id="duplicate-action"><a class="submitduplicate duplication" href="<?php echo esc_url( $notify_url ); ?>"><?php esc_html_e( 'Copy to a new draft', 'woocommerce' ); ?></a></div>
<?php
}
$notify_url = wp_nonce_url( admin_url( 'edit.php?post_type=product&action=duplicate_product&post=' . absint( $post->ID ) ), 'woocommerce-duplicate-product_' . $post->ID );
?>
<div id="duplicate-action"><a class="submitduplicate duplication" href="<?php echo esc_url( $notify_url ); ?>"><?php esc_html_e( 'Copy to a new draft', 'woocommerce' ); ?></a></div>
<?php
}
/**
@ -111,7 +107,7 @@ class WC_Admin_Duplicate_Product {
if ( false === $product ) {
/* translators: %s: product id */
wp_die( sprintf( esc_html__( 'Product creation failed, could not find original product: %s', 'woocommerce' ), $product_id ) );
wp_die( sprintf( esc_html__( 'Product creation failed, could not find original product: %s', 'woocommerce' ), esc_html( $product_id ) ) );
}
$duplicate = $this->product_duplicate( $product );
@ -120,7 +116,7 @@ class WC_Admin_Duplicate_Product {
do_action( 'woocommerce_product_duplicate', $duplicate, $product );
wc_do_deprecated_action( 'woocommerce_duplicate_product', array( $duplicate->get_id(), $this->get_product_to_duplicate( $product_id ) ), '3.0', 'Use woocommerce_product_duplicate action instead.' );
// Redirect to the edit screen for the new draft page
// Redirect to the edit screen for the new draft page.
wp_redirect( admin_url( 'post.php?action=edit&post=' . $duplicate->get_id() ) );
exit;
}
@ -128,15 +124,20 @@ class WC_Admin_Duplicate_Product {
/**
* Function to create the duplicate of the product.
*
* @param WC_Product $product
* @return WC_Product
* @param WC_Product $product The product to duplicate.
* @return WC_Product The duplicate.
*/
public function product_duplicate( $product ) {
// Filter to allow us to unset/remove data we don't want to copy to the duplicate. @since 2.6
/**
* Filter to allow us to unset/remove data we don't want to copy to the duplicate.
*
* @since 2.6
*/
$meta_to_exclude = array_filter( apply_filters( 'woocommerce_duplicate_product_exclude_meta', array() ) );
$duplicate = clone $product;
$duplicate->set_id( 0 );
/* translators: %s contains the name of the original product. */
$duplicate->set_name( sprintf( esc_html__( '%s (Copy)', 'woocommerce' ), $duplicate->get_name() ) );
$duplicate->set_total_sales( 0 );
if ( '' !== $product->get_sku( 'edit' ) ) {
@ -153,7 +154,11 @@ class WC_Admin_Duplicate_Product {
$duplicate->delete_meta_data( $meta_key );
}
// This action can be used to modify the object further before it is created - it will be passed by reference. @since 3.0
/**
* This action can be used to modify the object further before it is created - it will be passed by reference.
*
* @since 3.0
*/
do_action( 'woocommerce_product_duplicate_before_save', $duplicate, $product );
// Save parent product.
@ -168,6 +173,12 @@ class WC_Admin_Duplicate_Product {
$child_duplicate->set_id( 0 );
$child_duplicate->set_date_created( null );
// If we wait and let the insertion generate the slug, we will see extreme performance degradation
// in the case where a product is used as a template. Every time the template is duplicated, each
// variation will query every consecutive slug until it finds an empty one. To avoid this, we can
// optimize the generation ourselves, avoiding the issue altogether.
$this->generate_unique_slug( $child_duplicate );
if ( '' !== $child->get_sku( 'edit' ) ) {
$child_duplicate->set_sku( wc_product_generate_unique_sku( 0, $child->get_sku( 'edit' ) ) );
}
@ -176,7 +187,11 @@ class WC_Admin_Duplicate_Product {
$child_duplicate->delete_meta_data( $meta_key );
}
// This action can be used to modify the object further before it is created - it will be passed by reference. @since 3.0
/**
* This action can be used to modify the object further before it is created - it will be passed by reference.
*
* @since 3.0
*/
do_action( 'woocommerce_product_duplicate_before_save', $child_duplicate, $child );
$child_duplicate->save();
@ -193,7 +208,7 @@ class WC_Admin_Duplicate_Product {
* Get a product from the database to duplicate.
*
* @deprecated 3.0.0
* @param mixed $id
* @param mixed $id The ID of the product to duplicate.
* @return object|bool
* @see duplicate_product
*/
@ -215,6 +230,44 @@ class WC_Admin_Duplicate_Product {
return $post;
}
/**
* Generates a unique slug for a given product. We do this so that we can override the
* behavior of wp_unique_post_slug(). The normal slug generation will run single
* select queries on every non-unique slug, resulting in very bad performance.
*
* @param WC_Product $product The product to generate a slug for.
* @since 3.9.0
*/
private function generate_unique_slug( $product ) {
global $wpdb;
// We want to remove the suffix from the slug so that we can find the maximum suffix using this root slug.
// This will allow us to find the next-highest suffix that is unique. While this does not support gap
// filling, this shouldn't matter for our use-case.
$root_slug = preg_replace( '/-[0-9]+$/', '', $product->get_slug() );
$results = $wpdb->get_results(
$wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name LIKE %s AND post_type IN ( 'product', 'product_variation' )", $root_slug . '%' )
);
// The slug is already unique!
if ( empty( $results ) ) {
return;
}
// Find the maximum suffix so we can ensure uniqueness.
$max_suffix = 1;
foreach ( $results as $result ) {
// Pull a numerical suffix off the slug after the last hyphen.
$suffix = intval( substr( $result->post_name, strrpos( $result->post_name, '-' ) + 1 ) );
if ( $suffix > $max_suffix ) {
$max_suffix = $suffix;
}
}
$product->set_slug( $root_slug . '-' . ( $max_suffix + 1 ) );
}
}
return new WC_Admin_Duplicate_Product();

View File

@ -115,7 +115,7 @@ class WC_Admin_Menus {
global $current_tab, $current_section;
// We should only save on the settings page.
if ( ! is_admin() || ! isset( $_GET['page'] ) || 'wc-settings' !== $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( ! is_admin() || ! isset( $_GET['page'] ) || 'wc-settings' !== $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}

View File

@ -133,7 +133,7 @@ class WC_Admin_Meta_Boxes {
add_meta_box( 'woocommerce-coupon-data', __( 'Coupon data', 'woocommerce' ), 'WC_Meta_Box_Coupon_Data::output', 'shop_coupon', 'normal', 'high' );
// Comment rating.
if ( 'comment' === $screen_id && isset( $_GET['c'] ) && metadata_exists( 'comment', wc_clean( wp_unslash( $_GET['c'] ) ), 'rating' ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( 'comment' === $screen_id && isset( $_GET['c'] ) && metadata_exists( 'comment', wc_clean( wp_unslash( $_GET['c'] ) ), 'rating' ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
add_meta_box( 'woocommerce-rating', __( 'Rating', 'woocommerce' ), 'WC_Meta_Box_Product_Reviews::output', 'comment', 'normal', 'high' );
}
}

View File

@ -36,6 +36,7 @@ class WC_Admin_Notices {
'no_secure_connection' => 'secure_connection_notice',
'wc_admin' => 'wc_admin_feature_plugin_notice',
WC_PHP_MIN_REQUIREMENTS_NOTICE => 'wp_php_min_requirements_notice',
'maxmind_license_key' => 'maxmind_missing_license_key_notice',
);
/**
@ -87,6 +88,7 @@ class WC_Admin_Notices {
self::add_wc_admin_feature_plugin_notice();
self::add_notice( 'template_files' );
self::add_min_version_notice();
self::add_maxmind_missing_license_key_notice();
}
/**
@ -365,7 +367,7 @@ class WC_Admin_Notices {
* @todo Remove this notice and associated code once the feature plugin has been merged into core.
*/
public static function wc_admin_feature_plugin_notice() {
if ( get_user_meta( get_current_user_id(), 'dismissed_wc_admin_notice', true ) || self::is_plugin_active( 'woocommerce-admin/woocommerce-admin.php' ) ) {
if ( get_user_meta( get_current_user_id(), 'dismissed_wc_admin_notice', true ) || class_exists( 'Automattic\WooCommerce\Admin\FeaturePlugin' ) ) {
self::remove_notice( 'wc_admin' );
return;
}
@ -428,6 +430,41 @@ class WC_Admin_Notices {
include dirname( __FILE__ ) . '/views/html-notice-wp-php-minimum-requirements.php';
}
/**
* Add MaxMind missing license key notice.
*
* @since 3.9.0
*/
public static function add_maxmind_missing_license_key_notice() {
$default_address = get_option( 'woocommerce_default_customer_address' );
if ( ! in_array( $default_address, array( 'geolocation', 'geolocation_ajax' ), true ) ) {
return;
}
$integration_options = get_option( 'woocommerce_maxmind_geolocation_settings' );
if ( empty( $integration_options['license_key'] ) ) {
self::add_notice( 'maxmind_license_key' );
}
}
/**
* Display MaxMind missing license key notice.
*
* @since 3.9.0
*/
public static function maxmind_missing_license_key_notice() {
$user_dismissed_notice = get_user_meta( get_current_user_id(), 'dismissed_maxmind_license_key_notice', true );
$filter_dismissed_notice = ! apply_filters( 'woocommerce_maxmind_geolocation_display_notices', true );
if ( $user_dismissed_notice || $filter_dismissed_notice ) {
self::remove_notice( 'maxmind_license_key' );
return;
}
include dirname( __FILE__ ) . '/views/html-notice-maxmind-license-key.php';
}
/**
* Determine if the store is running SSL.
*

View File

@ -642,6 +642,10 @@ class WC_Admin_Post_Types {
wc_update_product_stock( $product, $stock_amount, 'set', true );
break;
}
} else {
// Reset values if WooCommerce Setting - Manage Stock status is disabled.
$product->set_stock_quantity( '' );
$product->set_manage_stock( 'no' );
}
// Apply product type constraints to stock status.

View File

@ -37,7 +37,8 @@ if ( ! class_exists( 'WC_Admin_Profile', false ) ) :
*/
public function get_customer_meta_fields() {
$show_fields = apply_filters(
'woocommerce_customer_meta_fields', array(
'woocommerce_customer_meta_fields',
array(
'billing' => array(
'title' => __( 'Customer billing address', 'woocommerce' ),
'fields' => array(

View File

@ -706,7 +706,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
} elseif ( $description && in_array( $value['type'], array( 'checkbox' ), true ) ) {
$description = wp_kses_post( $description );
} elseif ( $description ) {
$description = '<span class="description">' . wp_kses_post( $description ) . '</span>';
$description = '<p class="description">' . wp_kses_post( $description ) . '</p>';
}
if ( $tooltip_html && in_array( $value['type'], array( 'checkbox' ), true ) ) {

View File

@ -48,6 +48,13 @@ class WC_Admin_Setup_Wizard {
'Someone give me high five, I just set up a new store with #WordPress and @WooCommerce!',
);
/**
* The version of WordPress required to run the WooCommerce Admin plugin
*
* @var string
*/
private $wc_admin_plugin_minimum_wordpress_version = '5.3';
/**
* Hook in tabs.
*/
@ -73,7 +80,7 @@ class WC_Admin_Setup_Wizard {
* @return boolean
*/
protected function should_show_theme() {
$support_woocommerce = current_theme_supports( 'woocommerce' ) && ! $this->is_default_theme();
$support_woocommerce = current_theme_supports( 'woocommerce' ) && ! wc_is_wp_default_theme_active();
return (
current_user_can( 'install_themes' ) &&
@ -83,27 +90,6 @@ class WC_Admin_Setup_Wizard {
);
}
/**
* Is the user using a default WP theme?
*
* @return boolean
*/
protected function is_default_theme() {
return wc_is_active_theme(
array(
'twentynineteen',
'twentyseventeen',
'twentysixteen',
'twentyfifteen',
'twentyfourteen',
'twentythirteen',
'twentyeleven',
'twentytwelve',
'twentyten',
)
);
}
/**
* The "automated tax" extra should only be shown if the current user can
* install plugins and the store is in a supported country.
@ -147,12 +133,36 @@ class WC_Admin_Setup_Wizard {
/**
* Should we show the WooCommerce Admin install option?
* True only if the user can install plugins,
* and up until the end date of the recommendation.
* and is running the correct version of WordPress.
*
* @see WC_Admin_Setup_Wizard::$wc_admin_plugin_minimum_wordpress_version
*
* @return boolean
*/
protected function should_show_wc_admin() {
return current_user_can( 'install_plugins' );
$wordpress_minimum_met = version_compare( get_bloginfo( 'version' ), $this->wc_admin_plugin_minimum_wordpress_version, '>=' );
return current_user_can( 'install_plugins' ) && $wordpress_minimum_met;
}
/**
* Should we show the new WooCommerce Admin onboarding experience?
*
* @return boolean
*/
protected function should_show_wc_admin_onboarding() {
if ( ! $this->should_show_wc_admin() ) {
return false;
}
$ab_test = get_option( 'woocommerce_setup_ab_wc_admin_onboarding' );
// If it doesn't exist yet, generate it for later use and save it, so we always show the same to this user.
if ( ! $ab_test ) {
$ab_test = 1 !== rand( 1, 10 ) ? 'a' : 'b'; // 10% of users. b gets the new experience.
update_option( 'woocommerce_setup_ab_wc_admin_onboarding', $ab_test );
}
return 'b' === $ab_test;
}
/**
@ -251,38 +261,48 @@ class WC_Admin_Setup_Wizard {
return;
}
$default_steps = array(
'store_setup' => array(
'new_onboarding' => array(
'name' => '',
'view' => array( $this, 'wc_setup_new_onboarding' ),
'handler' => array( $this, 'wc_setup_new_onboarding_save' ),
),
'store_setup' => array(
'name' => __( 'Store setup', 'woocommerce' ),
'view' => array( $this, 'wc_setup_store_setup' ),
'handler' => array( $this, 'wc_setup_store_setup_save' ),
),
'payment' => array(
'payment' => array(
'name' => __( 'Payment', 'woocommerce' ),
'view' => array( $this, 'wc_setup_payment' ),
'handler' => array( $this, 'wc_setup_payment_save' ),
),
'shipping' => array(
'shipping' => array(
'name' => __( 'Shipping', 'woocommerce' ),
'view' => array( $this, 'wc_setup_shipping' ),
'handler' => array( $this, 'wc_setup_shipping_save' ),
),
'recommended' => array(
'recommended' => array(
'name' => __( 'Recommended', 'woocommerce' ),
'view' => array( $this, 'wc_setup_recommended' ),
'handler' => array( $this, 'wc_setup_recommended_save' ),
),
'activate' => array(
'activate' => array(
'name' => __( 'Activate', 'woocommerce' ),
'view' => array( $this, 'wc_setup_activate' ),
'handler' => array( $this, 'wc_setup_activate_save' ),
),
'next_steps' => array(
'next_steps' => array(
'name' => __( 'Ready!', 'woocommerce' ),
'view' => array( $this, 'wc_setup_ready' ),
'handler' => '',
),
);
// Hide the new/improved onboarding experience screen if the user is not part of the a/b test.
if ( ! $this->should_show_wc_admin_onboarding() ) {
unset( $default_steps['new_onboarding'] );
}
// Hide recommended step if nothing is going to be shown there.
if ( ! $this->should_show_recommended_step() ) {
unset( $default_steps['recommended'] );
@ -346,6 +366,9 @@ class WC_Admin_Setup_Wizard {
* Setup Wizard Header.
*/
public function setup_wizard_header() {
// same as default WP from wp-admin/admin-header.php.
$wp_version_class = 'branch-' . str_replace( array( '.', ',' ), '-', floatval( get_bloginfo( 'version' ) ) );
set_current_screen();
?>
<!DOCTYPE html>
@ -359,8 +382,8 @@ class WC_Admin_Setup_Wizard {
<?php do_action( 'admin_print_styles' ); ?>
<?php do_action( 'admin_head' ); ?>
</head>
<body class="wc-setup wp-core-ui">
<h1 id="wc-logo"><a href="https://woocommerce.com/"><img src="<?php echo esc_url( WC()->plugin_url() ); ?>/assets/images/woocommerce_logo.png" alt="<?php esc_attr_e( 'WooCommerce', 'woocommerce' ); ?>" /></a></h1>
<body class="wc-setup wp-core-ui <?php echo esc_attr( 'wc-setup-step__' . $this->step ); ?> <?php echo esc_attr( $wp_version_class ); ?>">
<h1 class="wc-logo"><a href="https://woocommerce.com/"><img src="<?php echo esc_url( WC()->plugin_url() ); ?>/assets/images/woocommerce_logo.png" alt="<?php esc_attr_e( 'WooCommerce', 'woocommerce' ); ?>" /></a></h1>
<?php
}
@ -369,7 +392,9 @@ class WC_Admin_Setup_Wizard {
*/
public function setup_wizard_footer() {
?>
<?php if ( 'store_setup' === $this->step ) : ?>
<?php if ( 'new_onboarding' === $this->step ) : ?>
<a class="wc-setup-footer-links" href="<?php echo esc_url( $this->get_next_step_link() ); ?>"><?php esc_html_e( 'Continue with the old setup wizard', 'woocommerce' ); ?></a>
<?php elseif ( 'store_setup' === $this->step ) : ?>
<a class="wc-setup-footer-links" href="<?php echo esc_url( admin_url() ); ?>"><?php esc_html_e( 'Not right now', 'woocommerce' ); ?></a>
<?php elseif ( 'recommended' === $this->step || 'activate' === $this->step ) : ?>
<a class="wc-setup-footer-links" href="<?php echo esc_url( $this->get_next_step_link() ); ?>"><?php esc_html_e( 'Skip this step', 'woocommerce' ); ?></a>
@ -393,6 +418,8 @@ class WC_Admin_Setup_Wizard {
unset( $output_steps['activate'] );
}
unset( $output_steps['new_onboarding'] );
?>
<ol class="wc-setup-steps">
<?php
@ -431,6 +458,72 @@ class WC_Admin_Setup_Wizard {
echo '</div>';
}
/**
* Display's a prompt for users to try out the new improved WooCommerce onboarding experience in WooCommerce Admin.
*/
public function wc_setup_new_onboarding() {
?>
<div class="wc-setup-step__new_onboarding-wrapper">
<p class="wc-setup-step__new_onboarding-welcome"><?php esc_html_e( 'Welcome to', 'woocommerce' ); ?></p>
<h1 class="wc-logo"><a href="https://woocommerce.com/"><img src="<?php echo esc_url( WC()->plugin_url() ); ?>/assets/images/woocommerce_logo.png" alt="<?php esc_attr_e( 'WooCommerce', 'woocommerce' ); ?>" /></a></h1>
<p><?php esc_html_e( 'Get your store up and running more quickly with our new and improved setup experience', 'woocommerce' ); ?></p>
<form method="post" class="activate-new-onboarding">
<?php wp_nonce_field( 'wc-setup' ); ?>
<input type="hidden" name="save_step" value="new_onboarding" />
<p class="wc-setup-actions step">
<button class="button-primary button button-large" value="<?php esc_attr_e( 'Yes please', 'woocommerce' ); ?>" name="save_step"><?php esc_html_e( 'Yes please', 'woocommerce' ); ?></button>
</p>
</form>
<p class="wc-setup-step__new_onboarding-plugin-info"><?php esc_html_e( 'The "WooCommerce Admin" plugin will be installed and activated', 'woocommerce' ); ?></p>
</div>
<?php
}
/**
* Installs WooCommerce admin and redirects to the new onboarding experience.
*/
public function wc_setup_new_onboarding_save() {
check_admin_referer( 'wc-setup' );
update_option( 'wc_onboarding_opt_in', 'yes' );
if ( function_exists( 'wc_admin_url' ) ) {
$this->wc_setup_redirect_to_wc_admin_onboarding();
exit;
}
WC_Install::background_installer(
'woocommerce-admin',
array(
'name' => __( 'WooCommerce Admin', 'woocommerce' ),
'repo-slug' => 'woocommerce-admin',
)
);
// The plugin was not successfully installed, so continue with normal setup.
if ( ! function_exists( 'wc_admin_url' ) ) {
wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
exit;
}
$this->wc_setup_redirect_to_wc_admin_onboarding();
exit;
}
/**
* Redirects to the onboarding wizard in WooCommerce Admin.
*/
private function wc_setup_redirect_to_wc_admin_onboarding() {
// Renables the wizard.
$profile_updates = array( 'completed' => false );
$onboarding_data = get_option( 'wc_onboarding_profile', array() );
update_option( 'wc_onboarding_profile', array_merge( $onboarding_data, $profile_updates ) );
wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-admin' ) ) );
}
/**
* Initial "store setup" step.
* Location, product type, page setup, and tracking opt-in.
@ -580,9 +673,9 @@ class WC_Admin_Setup_Wizard {
printf(
wp_kses(
/* translators: %1$s: usage tracking help link */
__( 'Learn more about how usage tracking works, and how you\'ll be helping <a href="%1$s" target="_blank">here</a>.', 'woocommerce' ),
__( 'Learn more about how usage tracking works, and how you\'ll be helping in our <a href="%1$s" target="_blank">usage tracking documentation</a>.', 'woocommerce' ),
array(
'a' => array(
'a' => array(
'href' => array(),
'target' => array(),
),
@ -599,7 +692,7 @@ class WC_Admin_Setup_Wizard {
</article>
<footer>
<div class="inner">
<button class="button button-primary button-large" id="wc_tracker_submit" aria-label="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></a>
<button class="button button-primary button-large" id="wc_tracker_submit" aria-label="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></button>
</div>
</footer>
</section>
@ -700,7 +793,7 @@ class WC_Admin_Setup_Wizard {
public function run_deferred_actions() {
$this->close_http_connection();
foreach ( $this->deferred_actions as $action ) {
call_user_func_array( $action['func'], $action['args'] );
$action['func']( ...$action['args'] );
// Clear the background installation flag if this is a plugin.
if (
@ -1583,7 +1676,7 @@ class WC_Admin_Setup_Wizard {
if ( in_array( $klarna_or_square, array( 'klarna_checkout', 'klarna_payments' ), true ) ) {
$gateways[ $klarna_or_square ]['enabled'] = true;
$gateways[ $klarna_or_square ]['featured'] = false;
$offered_gateways += array(
$offered_gateways += array(
$klarna_or_square => $gateways[ $klarna_or_square ],
);
} else {

View File

@ -267,7 +267,7 @@ class WC_Admin_Webhooks {
private static function table_list_output() {
global $webhooks_table_list;
echo '<h2>' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
echo '<h2 class="wc-table-list-header">' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
// Get the webhooks count.
$data_store = WC_Data_Store::load( 'webhook' );

View File

@ -72,8 +72,8 @@ class WC_Admin {
}
// Setup/welcome.
if ( ! empty( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
switch ( $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( ! empty( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
switch ( $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
case 'wc-setup':
include_once dirname( __FILE__ ) . '/class-wc-admin-setup-wizard.php';
break;
@ -127,7 +127,7 @@ class WC_Admin {
* For setup wizard, transient must be present, the user must have access rights, and we must ignore the network/bulk plugin updaters.
*/
public function admin_redirects() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// Nonced plugin install redirects (whitelisted).
if ( ! empty( $_GET['wc-install-plugin-redirect'] ) ) {
$plugin_slug = wc_clean( wp_unslash( $_GET['wc-install-plugin-redirect'] ) );
@ -165,7 +165,7 @@ class WC_Admin {
exit;
}
}
// phpcs:enable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:enable WordPress.Security.NonceVerification.Recommended
}
/**

View File

@ -188,7 +188,8 @@ class WC_Helper_Compat {
array(
'page' => 'wc-addons',
'section' => 'helper',
), admin_url( 'admin.php' )
),
admin_url( 'admin.php' )
);
include WC_Helper::get_view_filename( 'html-helper-compat.php' );
}

View File

@ -59,8 +59,10 @@ class WC_Helper_Plugin_Info {
add_query_arg(
array(
'product_id' => absint( $product_id ),
), 'info'
), array( 'authenticated' => true )
),
'info'
),
array( 'authenticated' => true )
);
$results = json_decode( wp_remote_retrieve_body( $request ), true );

View File

@ -178,7 +178,8 @@ class WC_Helper_Updater {
);
$request = WC_Helper_API::post(
'update-check', array(
'update-check',
array(
'body' => wp_json_encode( array( 'products' => $payload ) ),
'authenticated' => true,
)

View File

@ -149,7 +149,7 @@ class WC_Product_CSV_Importer_Controller {
$this->steps = apply_filters( 'woocommerce_product_csv_importer_steps', $default_steps );
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$this->step = isset( $_REQUEST['step'] ) ? sanitize_key( $_REQUEST['step'] ) : current( array_keys( $this->steps ) );
$this->file = isset( $_REQUEST['file'] ) ? wc_clean( wp_unslash( $_REQUEST['file'] ) ) : '';
$this->update_existing = isset( $_REQUEST['update_existing'] ) ? (bool) $_REQUEST['update_existing'] : false;
@ -263,7 +263,7 @@ class WC_Product_CSV_Importer_Controller {
* Dispatch current step and show correct view.
*/
public function dispatch() {
// phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( ! empty( $_POST['save_step'] ) && ! empty( $this->steps[ $this->step ]['handler'] ) ) {
call_user_func( $this->steps[ $this->step ]['handler'], $this );
}
@ -311,7 +311,7 @@ class WC_Product_CSV_Importer_Controller {
* @return string|WP_Error
*/
public function handle_upload() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification -- Nonce already verified in WC_Product_CSV_Importer_Controller::upload_form_handler()
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce already verified in WC_Product_CSV_Importer_Controller::upload_form_handler()
$file_url = isset( $_POST['file_url'] ) ? wc_clean( wp_unslash( $_POST['file_url'] ) ) : '';
if ( empty( $file_url ) ) {

View File

@ -200,7 +200,7 @@ class WC_Tax_Rate_Importer extends WP_Importer {
* @return bool False if error uploading or invalid file, true otherwise
*/
public function handle_upload() {
$file_url = isset( $_POST['file_url'] ) ? wc_clean( wp_unslash( $_POST['file_url'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification -- Nonce already verified in WC_Tax_Rate_Importer::dispatch()
$file_url = isset( $_POST['file_url'] ) ? wc_clean( wp_unslash( $_POST['file_url'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce already verified in WC_Tax_Rate_Importer::dispatch()
if ( empty( $file_url ) ) {
$file = wp_import_handle_upload();

View File

@ -249,11 +249,11 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
}
// 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 ) ) {
if ( $order_timestamp > strtotime( '-1 day', time() ) && $order_timestamp <= time() ) {
$show_date = sprintf(
/* translators: %s: human-readable time difference */
_x( '%s ago', '%s = human-readable time difference', 'woocommerce' ),
human_time_diff( $this->object->get_date_created()->getTimestamp(), current_time( 'timestamp', true ) )
human_time_diff( $this->object->get_date_created()->getTimestamp(), time() )
);
} else {
$show_date = $this->object->get_date_created()->date_i18n( apply_filters( 'woocommerce_admin_order_date_format', __( 'M j, Y', 'woocommerce' ) ) );
@ -751,7 +751,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$user_string = '';
$user_id = '';
if ( ! empty( $_GET['_customer_user'] ) ) { // phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
if ( ! empty( $_GET['_customer_user'] ) ) { // phpcs:disable WordPress.Security.NonceVerification.Recommended
$user_id = absint( $_GET['_customer_user'] ); // WPCS: input var ok, sanitization ok.
$user = get_user_by( 'id', $user_id );
@ -844,7 +844,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
public function search_label( $query ) {
global $pagenow, $typenow;
if ( 'edit.php' !== $pagenow || 'shop_order' !== $typenow || ! get_query_var( 'shop_order_search' ) || ! isset( $_GET['s'] ) ) { // phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
if ( 'edit.php' !== $pagenow || 'shop_order' !== $typenow || ! get_query_var( 'shop_order_search' ) || ! isset( $_GET['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return $query;
}
@ -870,7 +870,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
public function search_custom_fields( $wp ) {
global $pagenow;
if ( 'edit.php' !== $pagenow || empty( $wp->query_vars['s'] ) || 'shop_order' !== $wp->query_vars['post_type'] || ! isset( $_GET['s'] ) ) { // phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
if ( 'edit.php' !== $pagenow || empty( $wp->query_vars['s'] ) || 'shop_order' !== $wp->query_vars['post_type'] || ! isset( $_GET['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}

View File

@ -124,11 +124,11 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
$show_columns['is_in_stock'] = __( 'Stock', 'woocommerce' );
}
$show_columns['price'] = __( 'Price', 'woocommerce' );
$show_columns['product_cat'] = __( 'Categories', 'woocommerce' );
$show_columns['product_tag'] = __( 'Tags', 'woocommerce' );
$show_columns['featured'] = '<span class="wc-featured parent-tips" data-tip="' . esc_attr__( 'Featured', 'woocommerce' ) . '">' . __( 'Featured', 'woocommerce' ) . '</span>';
$show_columns['date'] = __( 'Date', 'woocommerce' );
$show_columns['price'] = __( 'Price', 'woocommerce' );
$show_columns['product_cat'] = __( 'Categories', 'woocommerce' );
$show_columns['product_tag'] = __( 'Tags', 'woocommerce' );
$show_columns['featured'] = '<span class="wc-featured parent-tips" data-tip="' . esc_attr__( 'Featured', 'woocommerce' ) . '">' . __( 'Featured', 'woocommerce' ) . '</span>';
$show_columns['date'] = __( 'Date', 'woocommerce' );
return array_merge( $show_columns, $columns );
}
@ -479,12 +479,12 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
}
// Stock status filter.
if ( ! empty( $_GET['stock_status'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( ! empty( $_GET['stock_status'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
add_filter( 'posts_clauses', array( $this, 'filter_stock_status_post_clauses' ) );
}
// Shipping class taxonomy.
if ( ! empty( $_GET['product_shipping_class'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( ! empty( $_GET['product_shipping_class'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$query_vars['tax_query'][] = array(
'taxonomy' => 'product_shipping_class',
'field' => 'slug',
@ -614,9 +614,9 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
*/
public function filter_stock_status_post_clauses( $args ) {
global $wpdb;
if ( ! empty( $_GET['stock_status'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( ! empty( $_GET['stock_status'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$args['join'] = $this->append_product_sorting_table_join( $args['join'] );
$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.stock_status=%s ', wc_clean( wp_unslash( $_GET['stock_status'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.stock_status=%s ', wc_clean( wp_unslash( $_GET['stock_status'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
return $args;
}

View File

@ -42,7 +42,8 @@ class WC_Meta_Box_Coupon_Data {
<ul class="coupon_data_tabs wc-tabs" style="display:none;">
<?php
$coupon_data_tabs = apply_filters(
'woocommerce_coupon_data_tabs', array(
'woocommerce_coupon_data_tabs',
array(
'general' => array(
'label' => __( 'General', 'woocommerce' ),
'target' => 'general_coupon_data',

View File

@ -33,7 +33,8 @@ class WC_Meta_Box_Order_Actions {
}
$order_actions = apply_filters(
'woocommerce_order_actions', array(
'woocommerce_order_actions',
array(
'send_order_details' => __( 'Email invoice / order details to customer', 'woocommerce' ),
'send_order_details_admin' => __( 'Resend new order notification', 'woocommerce' ),
'regenerate_download_permissions' => __( 'Regenerate download permissions', 'woocommerce' ),

View File

@ -39,7 +39,8 @@ class WC_Meta_Box_Order_Data {
public static function init_address_fields() {
self::$billing_fields = apply_filters(
'woocommerce_admin_billing_fields', array(
'woocommerce_admin_billing_fields',
array(
'first_name' => array(
'label' => __( 'First name', 'woocommerce' ),
'show' => false,
@ -90,7 +91,8 @@ class WC_Meta_Box_Order_Data {
);
self::$shipping_fields = apply_filters(
'woocommerce_admin_shipping_fields', array(
'woocommerce_admin_shipping_fields',
array(
'first_name' => array(
'label' => __( 'First name', 'woocommerce' ),
'show' => false,
@ -602,7 +604,7 @@ class WC_Meta_Box_Order_Data {
// Update date.
if ( empty( $_POST['order_date'] ) ) {
$date = current_time( 'timestamp', true );
$date = time();
} else {
$date = gmdate( 'Y-m-d H:i:s', strtotime( $_POST['order_date'] . ' ' . (int) $_POST['order_date_hour'] . ':' . (int) $_POST['order_date_minute'] . ':' . (int) $_POST['order_date_second'] ) );
}

View File

@ -214,7 +214,7 @@ class WC_Meta_Box_Product_Data {
* @return array
*/
private static function prepare_children() {
return isset( $_POST['grouped_products'] ) ? array_filter( array_map( 'intval', (array) $_POST['grouped_products'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
return isset( $_POST['grouped_products'] ) ? array_filter( array_map( 'intval', (array) $_POST['grouped_products'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing
}
/**
@ -228,7 +228,7 @@ class WC_Meta_Box_Product_Data {
$attributes = array();
if ( ! $data ) {
$data = stripslashes_deep( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$data = stripslashes_deep( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
}
if ( isset( $data['attribute_names'], $data['attribute_values'] ) ) {
@ -295,9 +295,9 @@ class WC_Meta_Box_Product_Data {
$attribute_key = sanitize_title( $attribute->get_name() );
if ( ! is_null( $index ) ) {
$value = isset( $_POST[ $key_prefix . $attribute_key ][ $index ] ) ? wp_unslash( $_POST[ $key_prefix . $attribute_key ][ $index ] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$value = isset( $_POST[ $key_prefix . $attribute_key ][ $index ] ) ? wp_unslash( $_POST[ $key_prefix . $attribute_key ][ $index ] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
} else {
$value = isset( $_POST[ $key_prefix . $attribute_key ] ) ? wp_unslash( $_POST[ $key_prefix . $attribute_key ] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$value = isset( $_POST[ $key_prefix . $attribute_key ] ) ? wp_unslash( $_POST[ $key_prefix . $attribute_key ] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
}
if ( $attribute->is_taxonomy() ) {
@ -322,7 +322,7 @@ class WC_Meta_Box_Product_Data {
* @param WP_Post $post Post object.
*/
public static function save( $post_id, $post ) {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
// Process product type first so we have the correct class to run setters.
$product_type = empty( $_POST['product-type'] ) ? WC_Product_Factory::get_product_type( $post_id ) : sanitize_title( wp_unslash( $_POST['product-type'] ) );
$classname = WC_Product_Factory::get_product_classname( $post_id, $product_type ? $product_type : 'simple' );
@ -427,7 +427,7 @@ class WC_Meta_Box_Product_Data {
}
do_action( 'woocommerce_process_product_meta_' . $product_type, $post_id );
// phpcs:enable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
@ -437,7 +437,7 @@ class WC_Meta_Box_Product_Data {
* @param WP_Post $post Post object.
*/
public static function save_variations( $post_id, $post ) {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( isset( $_POST['variable_post_id'] ) ) {
$parent = wc_get_product( $post_id );
$parent->set_default_attributes( self::prepare_set_attributes( $parent->get_attributes(), 'default_attribute_' ) );
@ -453,7 +453,7 @@ class WC_Meta_Box_Product_Data {
continue;
}
$variation_id = absint( $_POST['variable_post_id'][ $i ] );
$variation = new WC_Product_Variation( $variation_id );
$variation = wc_get_product_object( 'variation', $variation_id );
$stock = null;
// Handle stock changes.
@ -527,11 +527,20 @@ class WC_Meta_Box_Product_Data {
WC_Admin_Meta_Boxes::add_error( $errors->get_error_message() );
}
/**
* Set variation props before save.
*
* @param object $variation WC_Product_Variation object.
* @param int $i
* @since 3.8.0
*/
do_action( 'woocommerce_admin_process_variation_object', $variation, $i );
$variation->save();
do_action( 'woocommerce_save_product_variation', $variation_id, $i );
}
}
// phpcs:enable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
}

View File

@ -35,28 +35,29 @@ if ( ! defined( 'ABSPATH' ) ) {
<td>
<label><?php esc_html_e( 'Customer download link', 'woocommerce' ); ?></label>
<?php
$download_link = add_query_arg(
array(
'download_file' => $download->get_product_id(),
'order' => $download->get_order_key(),
'email' => urlencode( $download->get_user_email() ),
'key' => $download->get_download_id(),
), trailingslashit( home_url() )
);
$download_link = add_query_arg(
array(
'download_file' => $download->get_product_id(),
'order' => $download->get_order_key(),
'email' => urlencode( $download->get_user_email() ),
'key' => $download->get_download_id(),
),
trailingslashit( home_url() )
);
?>
<a id="copy-download-link" class="button" href="<?php echo esc_url( $download_link ); ?>" data-tip="<?php esc_attr_e( 'Copied!', 'woocommerce' ); ?>" data-tip-failed="<?php esc_attr_e( 'Copying to clipboard failed. You should be able to right-click the button and copy.', 'woocommerce' ); ?>"><?php esc_html_e( 'Copy link', 'woocommerce' ); ?></a>
</td>
<td>
<label><?php esc_html_e( 'Customer download log', 'woocommerce' ); ?></label>
<?php
$report_url = add_query_arg(
'permission_id',
rawurlencode( $download->get_id() ),
admin_url( 'admin.php?page=wc-reports&tab=orders&report=downloads' )
);
echo '<a class="button" href="' . esc_url( $report_url ) . '">';
esc_html_e( 'View report', 'woocommerce' );
echo '</a>';
$report_url = add_query_arg(
'permission_id',
rawurlencode( $download->get_id() ),
admin_url( 'admin.php?page=wc-reports&tab=orders&report=downloads' )
);
echo '<a class="button" href="' . esc_url( $report_url ) . '">';
esc_html_e( 'View report', 'woocommerce' );
echo '</a>';
?>
</td>
</tr>

View File

@ -4,7 +4,8 @@ if ( ! defined( 'ABSPATH' ) ) {
}
$hidden_order_itemmeta = apply_filters(
'woocommerce_hidden_order_itemmeta', array(
'woocommerce_hidden_order_itemmeta',
array(
'_qty',
'_tax_class',
'_product_id',

View File

@ -115,6 +115,10 @@ $row_class = apply_filters( 'woocommerce_admin_html_order_item_class', ! empt
$tax_item_id = $tax_item->get_rate_id();
$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : '';
$tax_item_subtotal = isset( $tax_data['subtotal'][ $tax_item_id ] ) ? $tax_data['subtotal'][ $tax_item_id ] : '';
$round_at_subtotal = 'yes' === get_option( 'woocommerce_tax_round_at_subtotal' );
$tax_item_total = wc_round_tax_total( $tax_item_total, $round_at_subtotal ? wc_get_rounding_precision() : null );
$tax_item_subtotal = wc_round_tax_total( $tax_item_subtotal, $round_at_subtotal ? wc_get_rounding_precision() : null );
?>
<td class="line_tax" width="1%">
<div class="view">

View File

@ -345,7 +345,7 @@ if ( wc_tax_enabled() ) {
</thead>
<?php
$row = '
<td><select class="wc-product-search" name="item_id" data-allow_clear="true" data-display_stock="true" data-placeholder="' . esc_attr__( 'Search for a product&hellip;', 'woocommerce' ) . '"></select></td>
<td><select class="wc-product-search" name="item_id" data-allow_clear="true" data-display_stock="true" data-exclude_type="variable" data-placeholder="' . esc_attr__( 'Search for a product&hellip;', 'woocommerce' ) . '"></select></td>
<td><input type="number" step="1" min="0" max="9999" autocomplete="off" name="item_qty" placeholder="1" size="4" class="quantity" /></td>';
?>
<tbody data-row="<?php echo esc_attr( $row ); ?>">

View File

@ -7,33 +7,33 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="options_group hide_if_external hide_if_grouped">
<?php
woocommerce_wp_textarea_input(
array(
'id' => '_purchase_note',
'value' => $product_object->get_purchase_note( 'edit' ),
'label' => __( 'Purchase note', 'woocommerce' ),
'desc_tip' => true,
'description' => __( 'Enter an optional note to send the customer after purchase.', 'woocommerce' ),
)
);
woocommerce_wp_textarea_input(
array(
'id' => '_purchase_note',
'value' => $product_object->get_purchase_note( 'edit' ),
'label' => __( 'Purchase note', 'woocommerce' ),
'desc_tip' => true,
'description' => __( 'Enter an optional note to send the customer after purchase.', 'woocommerce' ),
)
);
?>
</div>
<div class="options_group">
<?php
woocommerce_wp_text_input(
array(
'id' => 'menu_order',
'value' => $product_object->get_menu_order( 'edit' ),
'label' => __( 'Menu order', 'woocommerce' ),
'desc_tip' => true,
'description' => __( 'Custom ordering position.', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'step' => '1',
),
)
);
woocommerce_wp_text_input(
array(
'id' => 'menu_order',
'value' => $product_object->get_menu_order( 'edit' ),
'label' => __( 'Menu order', 'woocommerce' ),
'desc_tip' => true,
'description' => __( 'Custom ordering position.', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'step' => '1',
),
)
);
?>
</div>

View File

@ -205,7 +205,7 @@ class WC_Report_Coupon_Usage extends WC_Admin_Report {
);
if ( ! empty( $used_coupons ) && is_array( $used_coupons ) ) :
?>
?>
<select id="coupon_codes" name="coupon_codes" class="wc-enhanced-select" data-placeholder="<?php esc_attr_e( 'Choose coupons&hellip;', 'woocommerce' ); ?>" style="width:100%;">
<option value=""><?php esc_html_e( 'All coupons', 'woocommerce' ); ?></option>
<?php

View File

@ -587,7 +587,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
'refund_amount' => '#e74c3c',
);
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.NoNonceVerification
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ), true ) ) {
$current_range = '7day';
@ -603,7 +603,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
* Output an export link.
*/
public function get_export_button() {
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.NoNonceVerification
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
?>
<a
href="#"

View File

@ -150,7 +150,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'item_count' => '#d4d9dc',
);
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ), true ) ) {
$current_range = '7day';
@ -400,7 +400,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
*/
public function get_export_button() {
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
?>
<a
href="#"

View File

@ -122,13 +122,13 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
// We exclude on-hold orders as they are still pending payment.
$tax_rows_orders = $this->get_order_report_data(
array(
'data' => $query_data,
'where' => $query_where,
'order_by' => 'posts.post_date ASC',
'query_type' => 'get_results',
'filter_range' => true,
'order_types' => wc_get_order_types( 'sales-reports' ),
'order_status' => array( 'completed', 'processing', 'refunded' ),
'data' => $query_data,
'where' => $query_where,
'order_by' => 'posts.post_date ASC',
'query_type' => 'get_results',
'filter_range' => true,
'order_types' => wc_get_order_types( 'sales-reports' ),
'order_status' => array( 'completed', 'processing', 'refunded' ),
)
);
@ -160,8 +160,8 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
$tax_rows = array();
foreach ( $tax_rows_orders + $tax_rows_partial_refunds as $tax_row ) {
$key = $tax_row->rate_id;
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array(
$key = $tax_row->rate_id;
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array(
'tax_amount' => 0,
'shipping_tax_amount' => 0,
'total_orders' => 0,
@ -173,8 +173,8 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
}
foreach ( $tax_rows_full_refunds as $tax_row ) {
$key = $tax_row->rate_id;
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array(
$key = $tax_row->rate_id;
$tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array(
'tax_amount' => 0,
'shipping_tax_amount' => 0,
'total_orders' => 0,

View File

@ -33,7 +33,11 @@ class WC_Settings_Accounts extends WC_Settings_Page {
public function get_settings() {
$erasure_text = esc_html__( 'account erasure request', 'woocommerce' );
if ( current_user_can( 'manage_privacy_options' ) ) {
$erasure_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'tools.php?page=remove_personal_data' ) ), $erasure_text );
if ( version_compare( get_bloginfo( 'version' ), '5.3', '<' ) ) {
$erasure_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'tools.php?page=remove_personal_data' ) ), $erasure_text );
} else {
$erasure_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'erase-personal-data.php' ) ), $erasure_text );
}
}
$account_settings = array(

View File

@ -153,7 +153,7 @@ class WC_Settings_Advanced extends WC_Settings_Page {
'id' => 'checkout_process_options',
),
'force_ssl_checkout' => array(
'force_ssl_checkout' => array(
'title' => __( 'Secure checkout', 'woocommerce' ),
'desc' => __( 'Force secure checkout', 'woocommerce' ),
'id' => 'woocommerce_force_ssl_checkout',

View File

@ -39,17 +39,6 @@ class WC_Settings_General extends WC_Settings_Page {
$currency_code_options[ $code ] = $name . ' (' . get_woocommerce_currency_symbol( $code ) . ')';
}
$woocommerce_default_customer_address_options = array(
'' => __( 'No location by default', 'woocommerce' ),
'base' => __( 'Shop base address', 'woocommerce' ),
'geolocation' => __( 'Geolocate', 'woocommerce' ),
'geolocation_ajax' => __( 'Geolocate (with page caching support)', 'woocommerce' ),
);
if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
unset( $woocommerce_default_customer_address_options['geolocation'], $woocommerce_default_customer_address_options['geolocation_ajax'] );
}
$settings = apply_filters(
'woocommerce_general_settings',
array(
@ -182,10 +171,15 @@ class WC_Settings_General extends WC_Settings_Page {
'title' => __( 'Default customer location', 'woocommerce' ),
'id' => 'woocommerce_default_customer_address',
'desc_tip' => __( 'This option determines a customers default location. The MaxMind GeoLite Database will be periodically downloaded to your wp-content directory if using geolocation.', 'woocommerce' ),
'default' => 'geolocation',
'default' => 'base',
'type' => 'select',
'class' => 'wc-enhanced-select',
'options' => $woocommerce_default_customer_address_options,
'options' => array(
'' => __( 'No location by default', 'woocommerce' ),
'base' => __( 'Shop base address', 'woocommerce' ),
'geolocation' => __( 'Geolocate', 'woocommerce' ),
'geolocation_ajax' => __( 'Geolocate (with page caching support)', 'woocommerce' ),
),
),
array(

View File

@ -108,7 +108,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
* Save settings.
*/
public function save() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
global $current_section;
if ( ! $current_section ) {
@ -118,7 +118,6 @@ class WC_Settings_Tax extends WC_Settings_Page {
if ( isset( $_POST['woocommerce_tax_classes'] ) ) {
$this->save_tax_classes( wp_unslash( $_POST['woocommerce_tax_classes'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
}
} elseif ( ! empty( $_POST['tax_rate_country'] ) ) {
$this->save_tax_rates();
}
@ -128,9 +127,9 @@ class WC_Settings_Tax extends WC_Settings_Page {
}
// Invalidate caches.
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
// phpcs:enable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
@ -188,13 +187,16 @@ class WC_Settings_Tax extends WC_Settings_Page {
'page' => 'wc-settings',
'tab' => 'tax',
'section' => $current_section,
), 'admin.php'
),
'admin.php'
)
);
// Localize and enqueue our js.
wp_localize_script(
'wc-settings-tax', 'htmlSettingsTaxLocalizeScript', array(
'wc-settings-tax',
'htmlSettingsTaxLocalizeScript',
array(
'current_class' => $current_class,
'wc_tax_nonce' => wp_create_nonce( 'wc_tax_nonce-class:' . $current_class ),
'base_url' => $base_url,

View File

@ -64,7 +64,13 @@ $exporter = new WC_Product_CSV_Exporter();
<td>
<select id="woocommerce-exporter-category" class="woocommerce-exporter-category wc-enhanced-select" style="width:100%;" multiple data-placeholder="<?php esc_attr_e( 'Export all categories', 'woocommerce' ); ?>">
<?php
foreach ( get_categories( array( 'taxonomy' => 'product_cat' ) ) as $category ) {
$categories = get_categories(
array(
'taxonomy' => 'product_cat',
'hide_empty' => false,
)
);
foreach ( $categories as $category ) {
echo '<option value="' . esc_attr( $category->slug ) . '">' . esc_html( $category->name ) . '</option>';
}
?>

View File

@ -435,25 +435,6 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'min
</td>
</tr>
<?php if ( $settings['geolocation_enabled'] ) { ?>
<tr>
<td data-export-label="MaxMind GeoIP Database"><?php esc_html_e( 'MaxMind GeoIP database', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo wc_help_tip( esc_html__( 'The GeoIP database from MaxMind is used to geolocate customers.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
<td>
<?php
if ( version_compare( $environment['php_version'], '5.4', '<' ) ) {
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . wp_kses_post( __( 'MaxMind GeoIP database requires at least PHP 5.4.', 'woocommerce' ) ) . '</mark>';
} elseif ( file_exists( $database['maxmind_geoip_database'] ) ) {
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> <code class="private">' . esc_html( $database['maxmind_geoip_database'] ) . '</code></mark> ';
} else {
/* Translators: %1$s: Library url, %2$s: install path. */
printf( '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( esc_html__( 'The MaxMind GeoIP Database does not exist - Geolocation will not function. You can download and install it manually from %1$s to the path: %2$s. Scroll down to "Downloads" and download the "MaxMind DB binary, gzipped" file next to "GeoLite2 Country". Please remember to uncompress GeoLite2-Country_xxxxxxxx.tar.gz and upload the GeoLite2-Country.mmdb file only.', 'woocommerce' ), '<a href="https://dev.maxmind.com/geoip/geoip2/geolite2/">https://dev.maxmind.com/geoip/geoip2/geolite2/</a>', '<code class="private">' . esc_html( $database['maxmind_geoip_database'] ) . '</code>' ) . '</mark>', esc_html( WC_LOG_DIR ) );
}
?>
</td>
</tr>
<?php } ?>
<?php if ( ! empty( $database['database_size'] ) && ! empty( $database['database_tables'] ) ) : ?>
<tr>
<td><?php esc_html_e( 'Total Database Size', 'woocommerce' ); ?></td>
@ -584,7 +565,7 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'min
</thead>
<tbody>
<?php
foreach ( $active_plugins as $plugin ) {
foreach ( $active_plugins as $plugin ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
if ( ! empty( $plugin['name'] ) ) {
$dirname = dirname( $plugin['plugin'] );
@ -636,7 +617,7 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'min
</thead>
<tbody>
<?php
foreach ( $inactive_plugins as $plugin ) {
foreach ( $inactive_plugins as $plugin ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
if ( ! empty( $plugin['name'] ) ) {
$dirname = dirname( $plugin['plugin'] );
@ -715,7 +696,7 @@ if ( 0 < count( $dropins_mu_plugins['mu_plugins'] ) ) :
</thead>
<tbody>
<?php
foreach ( $dropins_mu_plugins['mu_plugins'] as $mu_plugin ) {
foreach ( $dropins_mu_plugins['mu_plugins'] as $mu_plugin ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$plugin_name = esc_html( $mu_plugin['name'] );
if ( ! empty( $mu_plugin['url'] ) ) {
$plugin_name = '<a href="' . esc_url( $mu_plugin['url'] ) . '" aria-label="' . esc_attr__( 'Visit plugin homepage', 'woocommerce' ) . '" target="_blank">' . $plugin_name . '</a>';

View File

@ -18,6 +18,7 @@ if ( ! $tab_exists ) {
}
?>
<div class="wrap woocommerce">
<?php do_action( 'woocommerce_before_settings_' . $current_tab ); ?>
<form method="<?php echo esc_attr( apply_filters( 'woocommerce_settings_form_method_tab_' . $current_tab, 'post' ) ); ?>" id="mainform" action="" enctype="multipart/form-data">
<nav class="nav-tab-wrapper woo-nav-tab-wrapper">
<?php
@ -46,4 +47,5 @@ if ( ! $tab_exists ) {
<?php wp_nonce_field( 'woocommerce-settings' ); ?>
</p>
</form>
<?php do_action( 'woocommerce_after_settings_' . $current_tab ); ?>
</div>

View File

@ -0,0 +1,31 @@
<?php
/**
* Admin View: Notice - Missing MaxMind license key
*
* @package WooCommerce\Admin
*/
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', 'maxmind_license_key' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>"><?php esc_html_e( 'Dismiss', 'woocommerce' ); ?></a>
<p>
<strong><?php esc_html_e( 'Geolocation has not been configured.', 'woocommerce' ); ?></strong>
</p>
<p>
<?php
echo wp_kses_post(
sprintf(
/* translators: %1%s: integration page %2$s: general settings page */
__( 'You must enter a valid license key on the <a href="%1$s">MaxMind integration settings page</a> in order to use the geolocation service. If you do not need geolocation for shipping or taxes, you should change the default customer location on the <a href="%2$s">general settings page</a>.', 'woocommerce' ),
admin_url( 'admin.php?page=wc-settings&tab=integration&section=maxmind_geolocation' ),
admin_url( 'admin.php?page=wc-settings&tab=general' )
)
);
?>
</p>
</div>

View File

@ -429,6 +429,11 @@ function wc_render_action_buttons( $actions ) {
function wc_render_invalid_variation_notice( $product_object ) {
global $wpdb;
// Give ability for extensions to hide this notice.
if ( ! apply_filters( 'woocommerce_show_invalid_variations_notice', true, $product_object ) ) {
return;
}
$variation_ids = $product_object ? $product_object->get_children() : array();
if ( empty( $variation_ids ) ) {

View File

@ -74,7 +74,7 @@ class WC_AJAX {
public static function do_wc_ajax() {
global $wp_query;
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( ! empty( $_GET['wc-ajax'] ) ) {
$wp_query->set( 'wc-ajax', sanitize_text_field( wp_unslash( $_GET['wc-ajax'] ) ) );
}
@ -396,7 +396,7 @@ class WC_AJAX {
public static function add_to_cart() {
ob_start();
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['product_id'] ) ) {
return;
}
@ -444,7 +444,7 @@ class WC_AJAX {
public static function remove_from_cart() {
ob_start();
// phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$cart_item_key = wc_clean( isset( $_POST['cart_item_key'] ) ? wp_unslash( $_POST['cart_item_key'] ) : '' );
if ( $cart_item_key && false !== WC()->cart->remove_cart_item( $cart_item_key ) ) {
@ -469,7 +469,7 @@ class WC_AJAX {
public static function get_variation() {
ob_start();
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( empty( $_POST['product_id'] ) ) {
wp_die();
}
@ -707,8 +707,8 @@ class WC_AJAX {
$product_id = intval( $_POST['post_id'] );
$post = get_post( $product_id ); // phpcs:ignore
$loop = intval( $_POST['loop'] );
$product_object = new WC_Product_Variable( $product_id ); // Forces type to variable in case product is unsaved.
$variation_object = new WC_Product_Variation();
$product_object = wc_get_product_object( 'variable', $product_id ); // Forces type to variable in case product is unsaved.
$variation_object = wc_get_product_object( 'variation' );
$variation_object->set_parent_id( $product_id );
$variation_object->set_attributes( array_fill_keys( array_map( 'sanitize_title', array_keys( $product_object->get_variation_attributes() ) ), '' ) );
$variation_id = $variation_object->save();
@ -898,6 +898,10 @@ class WC_AJAX {
if ( ! $product ) {
throw new Exception( __( 'Invalid product ID', 'woocommerce' ) . ' ' . $product_id );
}
if ( 'variable' === $product->get_type() ) {
/* translators: %s product name */
throw new Exception( sprintf( __( '%s is a variable product parent and cannot be added.', 'woocommerce' ), $product->get_name() ) );
}
$validation_error = new WP_Error();
$validation_error = apply_filters( 'woocommerce_ajax_add_order_item_validation', $validation_error, $product, $order, $qty );
@ -1144,7 +1148,7 @@ class WC_AJAX {
$order->set_billing_email( $user_email_arg );
}
$result = $order->apply_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$result = $order->apply_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( is_wp_error( $result ) ) {
throw new Exception( html_entity_decode( wp_strip_all_tags( $result->get_error_message() ) ) );
@ -1196,7 +1200,7 @@ class WC_AJAX {
throw new Exception( __( 'Invalid coupon', 'woocommerce' ) );
}
$order->remove_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order->remove_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order->calculate_taxes( $calculate_tax_args );
$order->calculate_totals( false );
@ -1536,6 +1540,24 @@ class WC_AJAX {
$include_ids = ! empty( $_GET['include'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['include'] ) ) : array();
$exclude_ids = ! empty( $_GET['exclude'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) : array();
$exclude_types = array();
if ( ! empty( $_GET['exclude_type'] ) ) {
// Support both comma-delimited and array format inputs.
$exclude_types = wp_unslash( $_GET['exclude_type'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! is_array( $exclude_types ) ) {
$exclude_types = explode( ',', $exclude_types );
}
// Sanitize the excluded types against valid product types.
foreach ( $exclude_types as &$exclude_type ) {
$exclude_type = strtolower( trim( $exclude_type ) );
}
$exclude_types = array_intersect(
array_merge( array( 'variation' ), array_keys( wc_get_product_types() ) ),
$exclude_types
);
}
$data_store = WC_Data_Store::load( 'product' );
$ids = $data_store->search_products( $term, '', (bool) $include_variations, false, $limit, $include_ids, $exclude_ids );
@ -1546,6 +1568,10 @@ class WC_AJAX {
$formatted_name = $product_object->get_formatted_name();
$managing_stock = $product_object->managing_stock();
if ( in_array( $product_object->get_type(), $exclude_types, true ) ) {
continue;
}
if ( $managing_stock && ! empty( $_GET['display_stock'] ) ) {
$stock_amount = $product_object->get_stock_quantity();
/* Translators: %d stock amount */
@ -1717,7 +1743,7 @@ class WC_AJAX {
* Ajax request handling for categories ordering.
*/
public static function term_ordering() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) {
wp_die( -1 );
}
@ -1750,7 +1776,7 @@ class WC_AJAX {
public static function product_ordering() {
global $wpdb;
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) {
wp_die( -1 );
}
@ -1792,6 +1818,8 @@ class WC_AJAX {
$wpdb->update( $wpdb->posts, array( 'menu_order' => $menu_orders[ $sorting_id ] ), array( 'ID' => $sorting_id ) );
WC_Post_Data::delete_product_query_transients();
do_action( 'woocommerce_after_product_ordering', $sorting_id, $menu_orders );
wp_send_json( $menu_orders );
// phpcs:enable
@ -2536,7 +2564,7 @@ class WC_AJAX {
* Handle submissions from assets/js/settings-views-html-settings-tax.js Backbone model.
*/
public static function tax_rates_save_changes() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['wc_tax_nonce'], $_POST['changes'] ) ) {
wp_send_json_error( 'missing_fields' );
wp_die();
@ -2603,7 +2631,7 @@ class WC_AJAX {
}
}
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
wp_send_json_success(

View File

@ -88,6 +88,8 @@ class WC_Autoloader {
$path = $this->include_path . 'payment-tokens/';
} elseif ( 0 === strpos( $class, 'wc_log_handler_' ) ) {
$path = $this->include_path . 'log-handlers/';
} elseif ( 0 === strpos( $class, 'wc_integration' ) ) {
$path = $this->include_path . 'integrations/' . substr( str_replace( '_', '-', $class ), 15 ) . '/';
}
if ( empty( $path ) || ! $this->load_file( $path . $file ) ) {

View File

@ -94,7 +94,7 @@ class WC_Cache_Helper {
$prefix = wp_cache_get( 'wc_' . $group . '_cache_prefix', $group );
if ( false === $prefix ) {
$prefix = 1;
$prefix = microtime();
wp_cache_set( 'wc_' . $group . '_cache_prefix', $prefix, $group );
}
@ -107,7 +107,18 @@ class WC_Cache_Helper {
* @param string $group Group of cache to clear.
*/
public static function incr_cache_prefix( $group ) {
wp_cache_incr( 'wc_' . $group . '_cache_prefix', 1, $group );
wc_deprecated_function( 'WC_Cache_Helper::incr_cache_prefix', '3.9.0', 'WC_Cache_Helper::invalidate_cache_group' );
self::invalidate_cache_group( $group );
}
/**
* Invalidate cache group.
*
* @param string $group Group of cache to clear.
* @since 3.9.0
*/
public static function invalidate_cache_group( $group ) {
wp_cache_set( 'wc_' . $group . '_cache_prefix', microtime(), $group );
}
/**

View File

@ -23,6 +23,7 @@ if ( ! defined( 'ABSPATH' ) ) {
* @since 3.2.0
*/
final class WC_Cart_Totals {
use WC_Item_Totals;
/**
* Reference to cart object.
@ -199,15 +200,6 @@ final class WC_Cart_Totals {
);
}
/**
* Should we round at subtotal level only?
*
* @return bool
*/
protected function round_at_subtotal() {
return 'yes' === get_option( 'woocommerce_tax_round_at_subtotal' );
}
/**
* Handles a cart or order object passed in for calculation. Normalises data
* into the same format for use by this class.
@ -561,6 +553,16 @@ final class WC_Cart_Totals {
return $in_cents ? $this->totals : wc_remove_number_precision_deep( $this->totals );
}
/**
* Returns array of values for totals calculation.
*
* @param string $field Field name. Will probably be `total` or `subtotal`.
* @return array Items object
*/
protected function get_values_for_total( $field ) {
return array_values( wp_list_pluck( $this->items, $field ) );
}
/**
* Get taxes merged by type.
*
@ -598,6 +600,7 @@ final class WC_Cart_Totals {
/**
* Round merged taxes.
*
* @deprecated 3.9.0 `calculate_item_subtotals` should already appropriately round the tax values.
* @since 3.5.4
* @param array $taxes Taxes to round.
* @return array
@ -681,12 +684,8 @@ final class WC_Cart_Totals {
$this->cart->cart_contents[ $item_key ]['line_tax'] = wc_remove_number_precision( $item->total_tax );
}
$items_total = array_sum(
array_map(
array( $this, 'round_item_subtotal' ),
array_values( wp_list_pluck( $this->items, 'total' ) )
)
);
$items_total = $this->get_rounded_items_total( $this->get_values_for_total( 'total' ) );
$this->set_total( 'items_total', round( $items_total ) );
$this->set_total( 'items_total_tax', array_sum( array_values( wp_list_pluck( $this->items, 'total_tax' ) ) ) );
@ -712,11 +711,14 @@ final class WC_Cart_Totals {
protected function calculate_item_subtotals() {
$merged_subtotal_taxes = array(); // Taxes indexed by tax rate ID for storage later.
$adjust_non_base_location_prices = apply_filters( 'woocommerce_adjust_non_base_location_prices', true );
$is_customer_vat_exempt = $this->cart->get_customer()->get_is_vat_exempt();
foreach ( $this->items as $item_key => $item ) {
if ( $item->price_includes_tax ) {
if ( $this->cart->get_customer()->get_is_vat_exempt() ) {
if ( $is_customer_vat_exempt ) {
$item = $this->remove_item_base_taxes( $item );
} elseif ( apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ) {
} elseif ( $adjust_non_base_location_prices ) {
$item = $this->adjust_non_base_location_price( $item );
}
}
@ -745,12 +747,8 @@ final class WC_Cart_Totals {
$this->cart->cart_contents[ $item_key ]['line_subtotal_tax'] = wc_remove_number_precision( $item->subtotal_tax );
}
$items_subtotal = array_sum(
array_map(
array( $this, 'round_item_subtotal' ),
array_values( wp_list_pluck( $this->items, 'subtotal' ) )
)
);
$items_subtotal = $this->get_rounded_items_total( $this->get_values_for_total( 'subtotal' ) );
$this->set_total( 'items_subtotal', round( $items_subtotal ) );
$this->set_total( 'items_subtotal_tax', wc_round_tax_total( array_sum( $merged_subtotal_taxes ), 0 ) );
@ -862,7 +860,7 @@ final class WC_Cart_Totals {
* @since 3.2.0
*/
protected function calculate_totals() {
$this->set_total( 'total', round( $this->get_total( 'items_total', true ) + $this->get_total( 'fees_total', true ) + $this->get_total( 'shipping_total', true ) + array_sum( $this->get_merged_taxes( true ) ), 0 ) );
$this->set_total( 'total', round( $this->get_total( 'items_total', true ) + $this->get_total( 'fees_total', true ) + $this->get_total( 'shipping_total', true ) + wc_round_tax_total( array_sum( $this->get_merged_taxes( true ) ), 0 ), 0 ) );
$this->cart->set_total_tax( array_sum( $this->get_merged_taxes( false ) ) );
// Allow plugins to hook and alter totals before final total is calculated.
@ -873,32 +871,4 @@ final class WC_Cart_Totals {
// Allow plugins to filter the grand total, and sum the cart totals in case of modifications.
$this->cart->set_total( max( 0, apply_filters( 'woocommerce_calculated_total', $this->get_total( 'total' ), $this->cart ) ) );
}
/**
* Apply rounding to an array of taxes before summing. Rounds to store DP setting, ignoring precision.
*
* @since 3.2.6
* @param float $value Tax value.
* @return float
*/
protected function round_line_tax( $value ) {
if ( ! $this->round_at_subtotal() ) {
$value = wc_round_tax_total( $value, 0 );
}
return $value;
}
/**
* Apply rounding to item subtotal before summing.
*
* @since 3.7.0
* @param float $value Item subtotal value.
* @return float
*/
protected function round_item_subtotal( $value ) {
if ( ! $this->round_at_subtotal() ) {
$value = round( $value );
}
return $value;
}
}

View File

@ -115,7 +115,7 @@ class WC_Cart extends WC_Legacy_Cart {
add_action( 'woocommerce_cart_item_restored', array( $this, 'calculate_totals' ), 20, 0 );
add_action( 'woocommerce_check_cart_items', array( $this, 'check_cart_items' ), 1 );
add_action( 'woocommerce_check_cart_items', array( $this, 'check_cart_coupons' ), 1 );
add_action( 'woocommerce_after_checkout_validation', array( $this, 'check_customer_coupons' ), 1 );
add_action( 'woocommerce_after_checkout_validation', array( $this, 'check_customer_coupons' ), 1, 2 );
}
/**
@ -637,7 +637,7 @@ class WC_Cart extends WC_Legacy_Cart {
*/
public function empty_cart( $clear_persistent_cart = true ) {
do_action( 'woocommerce_before_cart_emptied' );
do_action( 'woocommerce_before_cart_emptied', $clear_persistent_cart );
$this->cart_contents = array();
$this->removed_cart_contents = array();
@ -653,7 +653,7 @@ class WC_Cart extends WC_Legacy_Cart {
$this->fees_api->remove_all_fees();
do_action( 'woocommerce_cart_emptied' );
do_action( 'woocommerce_cart_emptied', $clear_persistent_cart );
}
/**
@ -1476,47 +1476,6 @@ class WC_Cart extends WC_Legacy_Cart {
$coupon->add_coupon_message( WC_Coupon::E_WC_COUPON_NOT_YOURS_REMOVED );
$this->remove_coupon( $code );
}
// Usage limits per user - check against billing and user email and user ID.
$limit_per_user = $coupon->get_usage_limit_per_user();
if ( 0 < $limit_per_user ) {
$used_by = $coupon->get_used_by();
$usage_count = 0;
$user_id_matches = array( get_current_user_id() );
// Check usage against emails.
foreach ( $check_emails as $check_email ) {
$usage_count += count( array_keys( $used_by, $check_email, true ) );
$user = get_user_by( 'email', $check_email );
$user_id_matches[] = $user ? $user->ID : 0;
}
// Check against billing emails of existing users.
$users_query = new WP_User_Query(
array(
'fields' => 'ID',
'meta_query' => array(
array(
'key' => '_billing_email',
'value' => $check_emails,
'compare' => 'IN',
),
),
)
); // WPCS: slow query ok.
$user_id_matches = array_unique( array_filter( array_merge( $user_id_matches, $users_query->get_results() ) ) );
foreach ( $user_id_matches as $user_id ) {
$usage_count += count( array_keys( $used_by, (string) $user_id, true ) );
}
if ( $usage_count >= $coupon->get_usage_limit_per_user() ) {
$coupon->add_coupon_message( WC_Coupon::E_WC_COUPON_USAGE_LIMIT_REACHED );
$this->remove_coupon( $code );
}
}
}
}
}

View File

@ -366,11 +366,12 @@ class WC_Checkout {
}
}
$order->hold_applied_coupons( $data['billing_email'] );
$order->set_created_via( 'checkout' );
$order->set_cart_hash( $cart_hash );
$order->set_customer_id( apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() ) );
$order_vat_exempt = WC()->cart->get_customer()->get_is_vat_exempt() ? 'yes' : 'no';
$order->add_meta_data( 'is_vat_exempt', $order_vat_exempt );
$order->add_meta_data( 'is_vat_exempt', $order_vat_exempt, true );
$order->set_currency( get_woocommerce_currency() );
$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
@ -403,6 +404,9 @@ class WC_Checkout {
return $order_id;
} catch ( Exception $e ) {
if ( $order && $order instanceof WC_Order ) {
$order->get_data_store()->release_held_coupons( $order );
}
return new WP_Error( 'checkout-error', $e->getMessage() );
}
}
@ -712,11 +716,11 @@ class WC_Checkout {
switch ( $fieldset_key ) {
case 'shipping':
/* translators: %s: field name */
$field_label = sprintf( __( 'Shipping %s', 'woocommerce' ), $field_label );
$field_label = sprintf( _x( 'Shipping %s', 'checkout-validation', 'woocommerce' ), $field_label );
break;
case 'billing':
/* translators: %s: field name */
$field_label = sprintf( __( 'Billing %s', 'woocommerce' ), $field_label );
$field_label = sprintf( _x( 'Billing %s', 'checkout-validation', 'woocommerce' ), $field_label );
break;
}
@ -734,14 +738,14 @@ class WC_Checkout {
/* translators: %s: field name */
$postcode_validation_notice = sprintf( __( '%s is not a valid postcode / ZIP.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' );
}
$errors->add( 'validation', apply_filters( 'woocommerce_checkout_postcode_validation_notice', $postcode_validation_notice, $country, $data[ $key ] ) );
$errors->add( 'validation', apply_filters( 'woocommerce_checkout_postcode_validation_notice', $postcode_validation_notice, $country, $data[ $key ] ), array( 'id' => $key ) );
}
}
if ( in_array( 'phone', $format, true ) ) {
if ( $validate_fieldset && '' !== $data[ $key ] && ! WC_Validation::is_phone( $data[ $key ] ) ) {
/* translators: %s: phone number */
$errors->add( 'validation', sprintf( __( '%s is not a valid phone number.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ) );
$errors->add( 'validation', sprintf( __( '%s is not a valid phone number.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ), array( 'id' => $key ) );
}
}
@ -751,7 +755,7 @@ class WC_Checkout {
if ( $validate_fieldset && ! $email_is_valid ) {
/* translators: %s: email address */
$errors->add( 'validation', sprintf( __( '%s is not a valid email address.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ) );
$errors->add( 'validation', sprintf( __( '%s is not a valid email address.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ), array( 'id' => $key ) );
continue;
}
}
@ -771,14 +775,14 @@ class WC_Checkout {
if ( $validate_fieldset && ! in_array( $data[ $key ], $valid_state_values, true ) ) {
/* translators: 1: state field 2: valid states */
$errors->add( 'validation', sprintf( __( '%1$s is not valid. Please enter one of the following: %2$s', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>', implode( ', ', $valid_states ) ) );
$errors->add( 'validation', sprintf( __( '%1$s is not valid. Please enter one of the following: %2$s', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>', implode( ', ', $valid_states ) ), array( 'id' => $key ) );
}
}
}
if ( $validate_fieldset && $required && '' === $data[ $key ] ) {
/* translators: %s: field name */
$errors->add( 'required-field', apply_filters( 'woocommerce_checkout_required_field_notice', sprintf( __( '%s is a required field.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ), $field_label ) );
$errors->add( 'required-field', apply_filters( 'woocommerce_checkout_required_field_notice', sprintf( __( '%s is a required field.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ), $field_label ), array( 'id' => $key ) );
}
}
}
@ -1101,8 +1105,11 @@ class WC_Checkout {
// Validate posted data and cart items before proceeding.
$this->validate_checkout( $posted_data, $errors );
foreach ( $errors->get_error_messages() as $message ) {
wc_add_notice( $message, 'error' );
foreach ( $errors->errors as $code => $messages ) {
$data = $errors->get_error_data( $code );
foreach ( $messages as $message ) {
wc_add_notice( $message, 'error', $data );
}
}
if ( empty( $posted_data['woocommerce_checkout_update_totals'] ) && 0 === wc_notice_count( 'error' ) ) {

View File

@ -371,16 +371,27 @@ class WC_Countries {
* @return array of country codes.
*/
public function get_vat_countries() {
$eu_countries = $this->get_european_union_countries();
$countries = array(
$eu_countries = $this->get_european_union_countries();
$vat_countries = $this->countries_using_vat();
$countries = array(
'GB',
'IM',
'MC',
'NO',
);
return apply_filters( 'woocommerce_vat_countries', array_merge( $eu_countries, $countries ) );
return apply_filters( 'woocommerce_vat_countries', array_merge( $eu_countries, $vat_countries, $countries ) );
}
/**
* Gets an array of Non-EU countries that use VAT as the Local name for their taxes based on this list - https://en.wikipedia.org/wiki/Value-added_tax#Non-European_Union_countries
*
* @return string[]
*/
public function countries_using_vat() {
$countries = array( 'AL', 'AR', 'AZ', 'BS', 'BH', 'BY', 'BB', 'BO', 'EG', 'ET', 'CL', 'CO', 'EC', 'SV', 'FJ', 'GM', 'GH', 'GT', 'IN', 'IR', 'IL', 'KZ', 'MU', 'MK', 'MX', 'MD', 'MN', 'ME', 'NA', 'NP', 'NG', 'PS', 'PY', 'RU', 'RW', 'KN', 'SA', 'RS', 'ZA', 'KR', 'LK', 'TH', 'TR', 'UA', 'UY', 'UZ', 'VE', 'VN', 'AE' );
return apply_filters( 'woocommerce_countries_using_vat', $countries );
}
/**
@ -494,7 +505,7 @@ class WC_Countries {
'AU' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {state} {postcode}\n{country}",
'AT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'BE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'CA' => "{company}\n{name}\n{address_1}\n{address_2}\n{city} {state_code}&nbsp;&nbsp;{postcode}\n{country}",
'CA' => "{company}\n{name}\n{address_1}\n{address_2}\n{city} {state_code} {postcode}\n{country}",
'CH' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'CL' => "{company}\n{name}\n{address_1}\n{address_2}\n{state}\n{postcode} {city}\n{country}",
'CN' => "{country} {postcode}\n{state}, {city}, {address_2}, {address_1}\n{company}\n{name}",

View File

@ -774,11 +774,12 @@ class WC_Coupon extends WC_Legacy_Coupon {
/**
* Increase usage count for current coupon.
*
* @param string $used_by Either user ID or billing email.
* @param string $used_by Either user ID or billing email.
* @param WC_Order $order If provided, will clear the coupons held by this order.
*/
public function increase_usage_count( $used_by = '' ) {
public function increase_usage_count( $used_by = '', $order = null ) {
if ( $this->get_id() && $this->data_store ) {
$new_count = $this->data_store->increase_usage_count( $this, $used_by );
$new_count = $this->data_store->increase_usage_count( $this, $used_by, $order );
// Bypass set_prop and remove pending changes since the data store saves the count already.
$this->data['usage_count'] = $new_count;
@ -813,8 +814,7 @@ class WC_Coupon extends WC_Legacy_Coupon {
/**
* Returns the error_message string.
*
* @access public
* @return string
*/
public function get_error_message() {

View File

@ -202,8 +202,9 @@ class WC_Data_Store {
*/
public function __call( $method, $parameters ) {
if ( is_callable( array( $this->instance, $method ) ) ) {
$object = array_shift( $parameters );
return call_user_func_array( array( $this->instance, $method ), array_merge( array( &$object ), $parameters ) );
$object = array_shift( $parameters );
$parameters = array_merge( array( &$object ), $parameters );
return $this->instance->$method( ...$parameters );
}
}
}

View File

@ -629,8 +629,8 @@ class WC_Discounts {
}
if ( $coupon && $user_id && apply_filters( 'woocommerce_coupon_validate_user_usage_limit', $coupon->get_usage_limit_per_user() > 0, $user_id, $coupon, $this ) && $coupon->get_id() && $coupon->get_data_store() ) {
$date_store = $coupon->get_data_store();
$usage_count = $date_store->get_usage_by_user_id( $coupon, $user_id );
$data_store = $coupon->get_data_store();
$usage_count = $data_store->get_usage_by_user_id( $coupon, $user_id );
if ( $usage_count >= $coupon->get_usage_limit_per_user() ) {
throw new Exception( __( 'Coupon usage limit has been reached.', 'woocommerce' ), 106 );
}
@ -648,7 +648,7 @@ class WC_Discounts {
* @return bool
*/
protected function validate_coupon_expiry_date( $coupon ) {
if ( $coupon->get_date_expires() && apply_filters( 'woocommerce_coupon_validate_expiry_date', current_time( 'timestamp', true ) > $coupon->get_date_expires()->getTimestamp(), $coupon, $this ) ) {
if ( $coupon->get_date_expires() && apply_filters( 'woocommerce_coupon_validate_expiry_date', time() > $coupon->get_date_expires()->getTimestamp(), $coupon, $this ) ) {
throw new Exception( __( 'This coupon has expired.', 'woocommerce' ), 107 );
}

View File

@ -118,8 +118,10 @@ class WC_Emails {
/**
* Queues transactional email so it's not sent in current request if enabled,
* otherwise falls back to send now.
*
* @param mixed ...$args Optional arguments.
*/
public static function queue_transactional_email() {
public static function queue_transactional_email( ...$args ) {
if ( is_a( self::$background_emailer, 'WC_Background_Emailer' ) ) {
self::$background_emailer->push_to_queue(
array(
@ -128,7 +130,7 @@ class WC_Emails {
)
);
} else {
call_user_func_array( array( __CLASS__, 'send_transactional_email' ), func_get_args() ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsUsage.InParameterList
self::send_transactional_email( ...$args );
}
}
@ -428,7 +430,7 @@ class WC_Emails {
* @param string $email Email address.
*/
public function order_downloads( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) {
$show_downloads = $order->has_downloadable_item() && $order->is_download_permitted() && ! $sent_to_admin;
$show_downloads = $order->has_downloadable_item() && $order->is_download_permitted() && ! $sent_to_admin && ! is_a( $email, 'WC_Email_Customer_Refunded_Order' );
if ( ! $show_downloads ) {
return;
@ -614,11 +616,11 @@ class WC_Emails {
);
wp_mail(
apply_filters( 'woocommerce_email_recipient_low_stock', get_option( 'woocommerce_stock_email_recipient' ), $product ),
apply_filters( 'woocommerce_email_subject_low_stock', $subject, $product ),
apply_filters( 'woocommerce_email_recipient_low_stock', get_option( 'woocommerce_stock_email_recipient' ), $product, null ),
apply_filters( 'woocommerce_email_subject_low_stock', $subject, $product, null ),
apply_filters( 'woocommerce_email_content_low_stock', $message, $product ),
apply_filters( 'woocommerce_email_headers', '', 'low_stock', $product ),
apply_filters( 'woocommerce_email_attachments', array(), 'low_stock', $product )
apply_filters( 'woocommerce_email_headers', '', 'low_stock', $product, null ),
apply_filters( 'woocommerce_email_attachments', array(), 'low_stock', $product, null )
);
}
@ -637,11 +639,11 @@ class WC_Emails {
$message = sprintf( __( '%s is out of stock.', 'woocommerce' ), html_entity_decode( wp_strip_all_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ) );
wp_mail(
apply_filters( 'woocommerce_email_recipient_no_stock', get_option( 'woocommerce_stock_email_recipient' ), $product ),
apply_filters( 'woocommerce_email_subject_no_stock', $subject, $product ),
apply_filters( 'woocommerce_email_recipient_no_stock', get_option( 'woocommerce_stock_email_recipient' ), $product, null ),
apply_filters( 'woocommerce_email_subject_no_stock', $subject, $product, null ),
apply_filters( 'woocommerce_email_content_no_stock', $message, $product ),
apply_filters( 'woocommerce_email_headers', '', 'no_stock', $product ),
apply_filters( 'woocommerce_email_attachments', array(), 'no_stock', $product )
apply_filters( 'woocommerce_email_headers', '', 'no_stock', $product, null ),
apply_filters( 'woocommerce_email_attachments', array(), 'no_stock', $product, null )
);
}
@ -675,11 +677,11 @@ class WC_Emails {
$message = sprintf( __( '%1$s units of %2$s have been backordered in order #%3$s.', 'woocommerce' ), $args['quantity'], html_entity_decode( wp_strip_all_tags( $args['product']->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ), $order->get_order_number() );
wp_mail(
apply_filters( 'woocommerce_email_recipient_backorder', get_option( 'woocommerce_stock_email_recipient' ), $args ),
apply_filters( 'woocommerce_email_subject_backorder', $subject, $args ),
apply_filters( 'woocommerce_email_recipient_backorder', get_option( 'woocommerce_stock_email_recipient' ), $args, null ),
apply_filters( 'woocommerce_email_subject_backorder', $subject, $args, null ),
apply_filters( 'woocommerce_email_content_backorder', $message, $args ),
apply_filters( 'woocommerce_email_headers', '', 'backorder', $args ),
apply_filters( 'woocommerce_email_attachments', array(), 'backorder', $args )
apply_filters( 'woocommerce_email_headers', '', 'backorder', $args, null ),
apply_filters( 'woocommerce_email_attachments', array(), 'backorder', $args, null )
);
}

View File

@ -39,11 +39,11 @@ class WC_Form_Handler {
* Remove key and user ID (or user login, as a fallback) from query string, set cookie, and redirect to account page to show the form.
*/
public static function redirect_reset_password_link() {
if ( is_account_page() && isset( $_GET['key'] ) && ( isset( $_GET['id'] ) || isset( $_GET['login'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( is_account_page() && isset( $_GET['key'] ) && ( isset( $_GET['id'] ) || isset( $_GET['login'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
// If available, get $user_id from query string parameter for fallback purposes.
if ( isset( $_GET['login'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$user = get_user_by( 'login', sanitize_user( wp_unslash( $_GET['login'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( isset( $_GET['login'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$user = get_user_by( 'login', sanitize_user( wp_unslash( $_GET['login'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$user_id = $user ? $user->ID : 0;
} else {
$user_id = absint( $_GET['id'] );
@ -113,7 +113,7 @@ class WC_Form_Handler {
// Validation: Required fields.
if ( ! empty( $field['required'] ) && empty( $value ) ) {
/* translators: %s: Field name. */
wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), $field['label'] ), 'error' );
wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), $field['label'] ), 'error', array( 'id' => $key ) );
}
if ( ! empty( $value ) ) {
@ -259,7 +259,7 @@ class WC_Form_Handler {
foreach ( $required_fields as $field_key => $field_name ) {
if ( empty( $_POST[ $field_key ] ) ) {
/* translators: %s: Field name. */
wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), '<strong>' . esc_html( $field_name ) . '</strong>' ), 'error' );
wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), '<strong>' . esc_html( $field_name ) . '</strong>' ), 'error', array( 'id' => $field_key ) );
}
}
@ -340,7 +340,7 @@ class WC_Form_Handler {
* Process the checkout form.
*/
public static function checkout_action() {
if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
wc_nocache_headers();
if ( WC()->cart->is_empty() ) {
@ -459,6 +459,27 @@ class WC_Form_Handler {
return;
}
// Test rate limit.
$current_user_id = get_current_user_id();
$rate_limit_id = 'add_payment_method_' . $current_user_id;
$delay = (int) apply_filters( 'woocommerce_payment_gateway_add_payment_method_delay', 20 );
if ( WC_Rate_Limiter::retried_too_soon( $rate_limit_id ) ) {
wc_add_notice(
/* translators: %d number of seconds */
_n(
'You cannot add a new payment method so soon after the previous one. Please wait for %d second.',
'You cannot add a new payment method so soon after the previous one. Please wait for %d seconds.',
$delay,
'woocommerce'
),
'error'
);
return;
}
WC_Rate_Limiter::set_rate_limit( $rate_limit_id, $delay );
ob_start();
$payment_method_id = wc_clean( wp_unslash( $_POST['payment_method'] ) );
@ -559,10 +580,10 @@ class WC_Form_Handler {
$nonce_value = wc_get_var( $_REQUEST['woocommerce-cart-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
if ( ! empty( $_POST['apply_coupon'] ) && ! empty( $_POST['coupon_code'] ) ) {
WC()->cart->add_discount( wc_format_coupon_code( wp_unslash( $_POST['coupon_code'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
WC()->cart->add_discount( wc_format_coupon_code( wp_unslash( $_POST['coupon_code'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
} elseif ( isset( $_GET['remove_coupon'] ) ) {
WC()->cart->remove_coupon( wc_format_coupon_code( urldecode( wp_unslash( $_GET['remove_coupon'] ) ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
WC()->cart->remove_coupon( wc_format_coupon_code( urldecode( wp_unslash( $_GET['remove_coupon'] ) ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
} elseif ( ! empty( $_GET['remove_item'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-cart' ) ) {
$cart_item_key = sanitize_text_field( wp_unslash( $_GET['remove_item'] ) );
@ -724,13 +745,13 @@ class WC_Form_Handler {
* @param bool $url (default: false) URL to redirect to.
*/
public static function add_to_cart_action( $url = false ) {
if ( ! isset( $_REQUEST['add-to-cart'] ) || ! is_numeric( wp_unslash( $_REQUEST['add-to-cart'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! isset( $_REQUEST['add-to-cart'] ) || ! is_numeric( wp_unslash( $_REQUEST['add-to-cart'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
return;
}
wc_nocache_headers();
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( wp_unslash( $_REQUEST['add-to-cart'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( wp_unslash( $_REQUEST['add-to-cart'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
@ -772,7 +793,7 @@ class WC_Form_Handler {
* @return bool success or not
*/
private static function add_to_cart_handler_simple( $product_id ) {
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
@ -792,7 +813,7 @@ class WC_Form_Handler {
private static function add_to_cart_handler_grouped( $product_id ) {
$was_added_to_cart = false;
$added_to_cart = array();
$items = isset( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ? wp_unslash( $_REQUEST['quantity'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$items = isset( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ? wp_unslash( $_REQUEST['quantity'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! empty( $items ) ) {
$quantity_set = false;
@ -841,8 +862,8 @@ class WC_Form_Handler {
*/
private static function add_to_cart_handler_variable( $product_id ) {
try {
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$missing_attributes = array();
$variations = array();
$adding_to_cart = wc_get_product( $product_id );
@ -871,12 +892,12 @@ class WC_Form_Handler {
}
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
if ( isset( $_REQUEST[ $attribute_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
if ( isset( $_REQUEST[ $attribute_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( $attribute['is_taxonomy'] ) {
// Don't use wc_clean as it destroys sanitized characters.
$value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
} else {
$value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
$posted_attributes[ $attribute_key ] = $value;
@ -1093,8 +1114,8 @@ class WC_Form_Handler {
* @throws Exception On registration error.
*/
public static function process_registration() {
$nonce_value = isset( $_POST['_wpnonce'] ) ? wp_unslash( $_POST['_wpnonce'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
$nonce_value = isset( $_POST['woocommerce-register-nonce'] ) ? wp_unslash( $_POST['woocommerce-register-nonce'] ) : $nonce_value; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
$nonce_value = isset( $_POST['_wpnonce'] ) ? wp_unslash( $_POST['_wpnonce'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$nonce_value = isset( $_POST['woocommerce-register-nonce'] ) ? wp_unslash( $_POST['woocommerce-register-nonce'] ) : $nonce_value; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( isset( $_POST['register'], $_POST['email'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-register' ) ) {
$username = 'no' === get_option( 'woocommerce_registration_generate_username' ) && isset( $_POST['username'] ) ? wp_unslash( $_POST['username'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

View File

@ -307,13 +307,13 @@ class WC_Frontend_Scripts {
private static function register_styles() {
$register_styles = array(
'photoswipe' => array(
'src' => self::get_asset_url( 'assets/css/photoswipe/photoswipe.css' ),
'src' => self::get_asset_url( 'assets/css/photoswipe/photoswipe.min.css' ),
'deps' => array(),
'version' => WC_VERSION,
'has_rtl' => false,
),
'photoswipe-default-skin' => array(
'src' => self::get_asset_url( 'assets/css/photoswipe/default-skin/default-skin.css' ),
'src' => self::get_asset_url( 'assets/css/photoswipe/default-skin/default-skin.min.css' ),
'deps' => array( 'photoswipe' ),
'version' => WC_VERSION,
'has_rtl' => false,

View File

@ -8,12 +8,15 @@
*
* @package WooCommerce\Classes
* @since 3.4.0
* @deprecated 3.9.0
*/
defined( 'ABSPATH' ) || exit;
/**
* Geolite integration class.
*
* @deprecated 3.9.0
*/
class WC_Geolite_Integration {
@ -38,10 +41,6 @@ class WC_Geolite_Integration {
*/
public function __construct( $database ) {
$this->database = $database;
if ( ! class_exists( 'MaxMind\\Db\\Reader', false ) ) {
$this->require_geolite_library();
}
}
/**
@ -50,8 +49,11 @@ class WC_Geolite_Integration {
*
* @param string $ip_address User IP address.
* @return string
* @deprecated 3.9.0
*/
public function get_country_iso( $ip_address ) {
wc_deprecated_function( 'get_country_iso', '3.9.0' );
$iso_code = '';
try {
@ -87,15 +89,4 @@ class WC_Geolite_Integration {
$this->log->log( $level, $message, array( 'source' => 'geoip' ) );
}
/**
* Require geolite library.
*/
private function require_geolite_library() {
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/Decoder.php';
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/InvalidDatabaseException.php';
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/Metadata.php';
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/Util.php';
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader.php';
}
}

View File

@ -7,7 +7,7 @@
* This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com.
*
* @package WooCommerce/Classes
* @version 3.4.0
* @version 3.9.0
*/
defined( 'ABSPATH' ) || exit;
@ -35,6 +35,7 @@ class WC_Geolocation {
* GeoLite2 DB.
*
* @since 3.4.0
* @deprecated 3.9.0
*/
const GEOLITE2_DB = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz';
@ -60,16 +61,6 @@ class WC_Geolocation {
'ip-api.com' => 'http://ip-api.com/json/%s',
);
/**
* Check if server supports MaxMind GeoLite2 Reader.
*
* @since 3.4.0
* @return bool
*/
private static function supports_geolite2() {
return version_compare( PHP_VERSION, '5.4.0', '>=' );
}
/**
* Check if geolocation is enabled.
*
@ -81,67 +72,20 @@ class WC_Geolocation {
return in_array( $current_settings, array( 'geolocation', 'geolocation_ajax' ), true );
}
/**
* Prevent geolocation via MaxMind when using legacy versions of php.
*
* @since 3.4.0
* @param string $default_customer_address current value.
* @return string
*/
public static function disable_geolocation_on_legacy_php( $default_customer_address ) {
if ( self::is_geolocation_enabled( $default_customer_address ) ) {
$default_customer_address = 'base';
}
return $default_customer_address;
}
/**
* Hook in geolocation functionality.
*/
public static function init() {
if ( self::supports_geolite2() ) {
// Only download the database from MaxMind if the geolocation function is enabled, or a plugin specifically requests it.
if ( self::is_geolocation_enabled( get_option( 'woocommerce_default_customer_address' ) ) || apply_filters( 'woocommerce_geolocation_update_database_periodically', false ) ) {
add_action( 'woocommerce_geoip_updater', array( __CLASS__, 'update_database' ) );
}
// Trigger database update when settings are changed to enable geolocation.
add_filter( 'pre_update_option_woocommerce_default_customer_address', array( __CLASS__, 'maybe_update_database' ), 10, 2 );
} else {
add_filter( 'pre_option_woocommerce_default_customer_address', array( __CLASS__, 'disable_geolocation_on_legacy_php' ) );
}
}
/**
* Maybe trigger a DB update for the first time.
*
* @param string $new_value New value.
* @param string $old_value Old value.
* @return string
*/
public static function maybe_update_database( $new_value, $old_value ) {
if ( $new_value !== $old_value && self::is_geolocation_enabled( $new_value ) ) {
self::update_database();
}
return $new_value;
}
/**
* Get current user IP Address.
*
* @return string
*/
public static function get_ip_address() {
if ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) { // WPCS: input var ok, CSRF ok.
return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) ); // WPCS: input var ok, CSRF ok.
} elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { // WPCS: input var ok, CSRF ok.
if ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) );
} elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
// Proxy servers can send through this header like this: X-Forwarded-For: client1, proxy1, proxy2
// Make sure we always only send through the first IP in the list which should always be the client IP.
return (string) rest_is_ip_address( trim( current( preg_split( '/,/', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) ) ) ); // WPCS: input var ok, CSRF ok.
} elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) { // @codingStandardsIgnoreLine
return sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); // @codingStandardsIgnoreLine
return (string) rest_is_ip_address( trim( current( preg_split( '/,/', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) ) ) );
} elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
return sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
}
return '';
}
@ -195,119 +139,114 @@ class WC_Geolocation {
// Filter to allow custom geolocation of the IP address.
$country_code = apply_filters( 'woocommerce_geolocate_ip', false, $ip_address, $fallback, $api_fallback );
if ( false === $country_code ) {
// If GEOIP is enabled in CloudFlare, we can use that (Settings -> CloudFlare Settings -> Settings Overview).
if ( ! empty( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) { // WPCS: input var ok, CSRF ok.
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) ); // WPCS: input var ok, CSRF ok.
} elseif ( ! empty( $_SERVER['GEOIP_COUNTRY_CODE'] ) ) { // WPCS: input var ok, CSRF ok.
// WP.com VIP has a variable available.
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER['GEOIP_COUNTRY_CODE'] ) ) ); // WPCS: input var ok, CSRF ok.
} elseif ( ! empty( $_SERVER['HTTP_X_COUNTRY_CODE'] ) ) { // WPCS: input var ok, CSRF ok.
// VIP Go has a variable available also.
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_COUNTRY_CODE'] ) ) ); // WPCS: input var ok, CSRF ok.
} else {
$ip_address = $ip_address ? $ip_address : self::get_ip_address();
$database = self::get_local_database_path();
if ( false !== $country_code ) {
return array(
'country' => $country_code,
'state' => '',
'city' => '',
'postcode' => '',
);
}
if ( self::supports_geolite2() && file_exists( $database ) ) {
$country_code = self::geolocate_via_db( $ip_address, $database );
} elseif ( $api_fallback ) {
$country_code = self::geolocate_via_api( $ip_address );
} else {
$country_code = '';
}
if ( empty( $ip_address ) ) {
$ip_address = self::get_ip_address();
}
if ( ! $country_code && $fallback ) {
// May be a local environment - find external IP.
return self::geolocate_ip( self::get_external_ip_address(), false, $api_fallback );
}
$country_code = self::get_country_code_from_headers();
/**
* Get geolocation filter.
*
* @since 3.9.0
* @param array $geolocation Geolocation data, including country, state, city, and postcode.
* @param string $ip_address IP Address.
*/
$geolocation = apply_filters(
'woocommerce_get_geolocation',
array(
'country' => $country_code,
'state' => '',
'city' => '',
'postcode' => '',
),
$ip_address
);
// If we still haven't found a country code, let's consider doing an API lookup.
if ( '' === $geolocation['country'] && $api_fallback ) {
$geolocation['country'] = self::geolocate_via_api( $ip_address );
}
// It's possible that we're in a local environment, in which case the geolocation needs to be done from the
// external address.
if ( '' === $geolocation['country'] && $fallback ) {
$external_ip_address = self::get_external_ip_address();
// Only bother with this if the external IP differs.
if ( '0.0.0.0' !== $external_ip_address && $external_ip_address !== $ip_address ) {
return self::geolocate_ip( $external_ip_address, false, $api_fallback );
}
}
return array(
'country' => $country_code,
'state' => '',
'country' => $geolocation['country'],
'state' => $geolocation['state'],
'city' => $geolocation['city'],
'postcode' => $geolocation['postcode'],
);
}
/**
* Path to our local db.
*
* @deprecated 3.9.0
* @param string $deprecated Deprecated since 3.4.0.
* @return string
*/
public static function get_local_database_path( $deprecated = '2' ) {
return apply_filters( 'woocommerce_geolocation_local_database_path', WP_CONTENT_DIR . '/uploads/GeoLite2-Country.mmdb', $deprecated );
wc_deprecated_function( 'WC_Geolocation::get_local_database_path', '3.9.0' );
$integration = wc()->integrations->get_integration( 'maxmind_geolocation' );
return $integration->get_database_service()->get_database_path();
}
/**
* Update geoip database.
*
* @deprecated 3.9.0
* Extract files with PharData. Tool built into PHP since 5.3.
*/
public static function update_database() {
$logger = wc_get_logger();
if ( ! self::supports_geolite2() ) {
$logger->notice( 'Requires PHP 5.4 to be able to download MaxMind GeoLite2 database', array( 'source' => 'geolocation' ) );
return;
}
require_once ABSPATH . 'wp-admin/includes/file.php';
$database = 'GeoLite2-Country.mmdb';
$target_database_path = self::get_local_database_path();
$tmp_database_path = download_url( self::GEOLITE2_DB );
if ( ! is_wp_error( $tmp_database_path ) ) {
WP_Filesystem();
global $wp_filesystem;
try {
// Make sure target dir exists.
$wp_filesystem->mkdir( dirname( $target_database_path ) );
// Extract files with PharData. Tool built into PHP since 5.3.
$file = new PharData( $tmp_database_path ); // phpcs:ignore PHPCompatibility.Classes.NewClasses.phardataFound
$file_path = trailingslashit( $file->current()->getFileName() ) . $database;
$file->extractTo( dirname( $tmp_database_path ), $file_path, true );
// Move file and delete temp.
$wp_filesystem->move( trailingslashit( dirname( $tmp_database_path ) ) . $file_path, $target_database_path, true );
$wp_filesystem->delete( trailingslashit( dirname( $tmp_database_path ) ) . $file->current()->getFileName() );
} catch ( Exception $e ) {
$logger->notice( $e->getMessage(), array( 'source' => 'geolocation' ) );
// Reschedule download of DB.
wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
wp_schedule_event( strtotime( 'first tuesday of next month' ), 'monthly', 'woocommerce_geoip_updater' );
}
// Delete temp file regardless of success.
$wp_filesystem->delete( $tmp_database_path );
} else {
$logger->notice(
'Unable to download GeoIP Database: ' . $tmp_database_path->get_error_message(),
array( 'source' => 'geolocation' )
);
}
wc_deprecated_function( 'WC_Geolocation::update_database', '3.9.0' );
$integration = wc()->integrations->get_integration( 'maxmind_geolocation' );
$integration->update_database();
}
/**
* Use MAXMIND GeoLite database to geolocation the user.
* Fetches the country code from the request headers, if one is available.
*
* @param string $ip_address IP address.
* @param string $database Database path.
* @return string
* @since 3.9.0
* @return string The country code pulled from the headers, or empty string if one was not found.
*/
private static function geolocate_via_db( $ip_address, $database ) {
if ( ! class_exists( 'WC_Geolite_Integration', false ) ) {
require_once WC_ABSPATH . 'includes/class-wc-geolite-integration.php';
private static function get_country_code_from_headers() {
$country_code = '';
$headers = array(
'MM_COUNTRY_CODE',
'GEOIP_COUNTRY_CODE',
'HTTP_CF_IPCOUNTRY',
'HTTP_X_COUNTRY_CODE',
);
foreach ( $headers as $header ) {
if ( empty( $_SERVER[ $header ] ) ) {
continue;
}
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER[ $header ] ) ) );
break;
}
$geolite = new WC_Geolite_Integration( $database );
return $geolite->get_country_iso( $ip_address );
return $country_code;
}
/**
@ -368,6 +307,50 @@ class WC_Geolocation {
return $country_code;
}
}
WC_Geolocation::init();
/**
* Hook in geolocation functionality.
*
* @deprecated 3.9.0
* @return null
*/
public static function init() {
wc_deprecated_function( 'WC_Geolocation::init', '3.9.0' );
return null;
}
/**
* Prevent geolocation via MaxMind when using legacy versions of php.
*
* @deprecated 3.9.0
* @since 3.4.0
* @param string $default_customer_address current value.
* @return string
*/
public static function disable_geolocation_on_legacy_php( $default_customer_address ) {
wc_deprecated_function( 'WC_Geolocation::disable_geolocation_on_legacy_php', '3.9.0' );
if ( self::is_geolocation_enabled( $default_customer_address ) ) {
$default_customer_address = 'base';
}
return $default_customer_address;
}
/**
* Maybe trigger a DB update for the first time.
*
* @deprecated 3.9.0
* @param string $new_value New value.
* @param string $old_value Old value.
* @return string
*/
public static function maybe_update_database( $new_value, $old_value ) {
wc_deprecated_function( 'WC_Geolocation::maybe_update_database', '3.9.0' );
if ( $new_value !== $old_value && self::is_geolocation_enabled( $new_value ) ) {
self::update_database();
}
return $new_value;
}
}

View File

@ -135,6 +135,11 @@ class WC_Install {
'wc_update_370_mro_std_currency',
'wc_update_370_db_version',
),
'3.9.0' => array(
'wc_update_390_move_maxmind_database',
'wc_update_390_change_geolocation_database_update_cron',
'wc_update_390_db_version',
),
);
/**
@ -421,6 +426,10 @@ class WC_Install {
'interval' => 2635200,
'display' => __( 'Monthly', 'woocommerce' ),
);
$schedules['fifteendays'] = array(
'interval' => 1296000,
'display' => __( 'Every 15 Days', 'woocommerce' ),
);
return $schedules;
}
@ -449,11 +458,8 @@ class WC_Install {
wp_schedule_event( time(), 'daily', 'woocommerce_cleanup_personal_data' );
wp_schedule_event( time() + ( 3 * HOUR_IN_SECONDS ), 'daily', 'woocommerce_cleanup_logs' );
wp_schedule_event( time() + ( 6 * HOUR_IN_SECONDS ), 'twicedaily', 'woocommerce_cleanup_sessions' );
wp_schedule_event( strtotime( 'first tuesday of next month' ), 'monthly', 'woocommerce_geoip_updater' );
wp_schedule_event( time() + MINUTE_IN_SECONDS, 'fifteendays', 'woocommerce_geoip_updater' );
wp_schedule_event( time() + 10, apply_filters( 'woocommerce_tracker_event_recurrence', 'daily' ), 'woocommerce_tracker_send_event' );
// Trigger GeoLite2 database download after 1 minute.
wp_schedule_single_event( time() + ( MINUTE_IN_SECONDS * 1 ), 'woocommerce_geoip_updater' );
}
/**
@ -970,7 +976,7 @@ CREATE TABLE {$wpdb->prefix}wc_tax_rate_classes (
$tables = self::get_tables();
foreach ( $tables as $table ) {
$wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
}
}

View File

@ -4,7 +4,7 @@
*
* Loads Integrations into WooCommerce.
*
* @version 2.3.0
* @version 3.9.0
* @package WooCommerce/Classes/Integrations
*/
@ -29,7 +29,11 @@ class WC_Integrations {
do_action( 'woocommerce_integrations_init' );
$load_integrations = apply_filters( 'woocommerce_integrations', array() );
$load_integrations = array(
'WC_Integration_MaxMind_Geolocation',
);
$load_integrations = apply_filters( 'woocommerce_integrations', $load_integrations );
// Load integration classes.
foreach ( $load_integrations as $integration ) {
@ -48,4 +52,19 @@ class WC_Integrations {
public function get_integrations() {
return $this->integrations;
}
/**
* Return a desired integration.
*
* @since 3.9.0
* @param string $id The id of the integration to get.
* @return mixed|null The integration if one is found, otherwise null.
*/
public function get_integration( $id ) {
if ( isset( $this->integrations[ $id ] ) ) {
return $this->integrations[ $id ];
}
return null;
}
}

View File

@ -46,7 +46,7 @@ class WC_Order_Factory {
try {
return new $classname( $order_id );
} catch ( Exception $e ) {
wc_caught_exception( $e, __FUNCTION__, func_get_args() );
wc_caught_exception( $e, __FUNCTION__, array( $order_id ) );
return false;
}
}

View File

@ -113,7 +113,7 @@ class WC_Order extends WC_Abstract_Order {
$this->set_transaction_id( $transaction_id );
}
if ( ! $this->get_date_paid( 'edit' ) ) {
$this->set_date_paid( current_time( 'timestamp', true ) );
$this->set_date_paid( time() );
}
$this->set_status( apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this ) );
$this->save();
@ -292,11 +292,11 @@ class WC_Order extends WC_Abstract_Order {
if ( $this->has_status( $payment_completed_status ) ) {
// If payment complete status is reached, set paid now.
$this->set_date_paid( current_time( 'timestamp', true ) );
$this->set_date_paid( time() );
} elseif ( 'processing' === $payment_completed_status && $this->has_status( 'completed' ) ) {
// If payment complete status was processing, but we've passed that and still have no date, set it now.
$this->set_date_paid( current_time( 'timestamp', true ) );
$this->set_date_paid( time() );
}
}
}
@ -310,7 +310,7 @@ class WC_Order extends WC_Abstract_Order {
*/
protected function maybe_set_date_completed() {
if ( $this->has_status( 'completed' ) ) {
$this->set_date_completed( current_time( 'timestamp', true ) );
$this->set_date_completed( time() );
}
}
@ -366,15 +366,33 @@ class WC_Order extends WC_Abstract_Order {
/* translators: 1: old order status 2: new order status */
$transition_note = sprintf( __( 'Order status changed from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['from'] ), wc_get_order_status_name( $status_transition['to'] ) );
// Note the transition occurred.
$this->add_status_transition_note( $transition_note, $status_transition );
do_action( 'woocommerce_order_status_' . $status_transition['from'] . '_to_' . $status_transition['to'], $this->get_id(), $this );
do_action( 'woocommerce_order_status_changed', $this->get_id(), $status_transition['from'], $status_transition['to'], $this );
// Work out if this was for a payment, and trigger a payment_status hook instead.
if (
in_array( $status_transition['from'], apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this ), true )
&& in_array( $status_transition['to'], wc_get_is_paid_statuses(), true )
) {
/**
* Fires when the order progresses from a pending payment status to a paid one.
*
* @since 3.9.0
* @param int Order ID
* @param WC_Order Order object
*/
do_action( 'woocommerce_order_payment_status_changed', $this->get_id(), $this );
}
} else {
/* translators: %s: new order status */
$transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['to'] ) );
}
// Note the transition occurred.
$this->add_order_note( trim( $status_transition['note'] . ' ' . $transition_note ), 0, $status_transition['manual'] );
// Note the transition occurred.
$this->add_status_transition_note( $transition_note, $status_transition );
}
} catch ( Exception $e ) {
$logger = wc_get_logger();
$logger->error(
@ -883,10 +901,11 @@ class WC_Order extends WC_Abstract_Order {
* Filter orders formatterd billing address.
*
* @since 3.8.0
* @param string $address Formatted billing address string.
* @param array $raw_address Raw billing address.
* @param string $address Formatted billing address string.
* @param array $raw_address Raw billing address.
* @param WC_Order $order Order data. @since 3.9.0
*/
return apply_filters( 'woocommerce_order_get_formatted_billing_address', $address ? $address : $empty_content, $raw_address );
return apply_filters( 'woocommerce_order_get_formatted_billing_address', $address ? $address : $empty_content, $raw_address, $this );
}
/**
@ -908,10 +927,11 @@ class WC_Order extends WC_Abstract_Order {
* Filter orders formatterd shipping address.
*
* @since 3.8.0
* @param string $address Formatted shipping address string.
* @param array $raw_address Raw shipping address.
* @param string $address Formatted billing address string.
* @param array $raw_address Raw billing address.
* @param WC_Order $order Order data. @since 3.9.0
*/
return apply_filters( 'woocommerce_order_get_formatted_shipping_address', $address ? $address : $empty_content, $raw_address );
return apply_filters( 'woocommerce_order_get_formatted_shipping_address', $address ? $address : $empty_content, $raw_address, $this );
}
/**
@ -1426,6 +1446,12 @@ class WC_Order extends WC_Abstract_Order {
continue;
}
// Check item refunds.
$refunded_qty = abs( $this->get_qty_refunded_for_item( $item->get_id() ) );
if ( $refunded_qty && $item->get_quantity() === $refunded_qty ) {
continue;
}
if ( $item->is_type( 'line_item' ) ) {
$item_downloads = $item->get_item_downloads();
$product = $item->get_product();
@ -1699,6 +1725,19 @@ class WC_Order extends WC_Abstract_Order {
return $comment_id;
}
/**
* Add an order note for status transition
*
* @since 3.9.0
* @uses WC_Order::add_order_note()
* @param string $note Note to be added giving status transition from and to details.
* @param bool $transition Details of the status transition.
* @return int Comment ID.
*/
private function add_status_transition_note( $note, $transition ) {
return $this->add_order_note( trim( $transition['note'] . ' ' . $note ), 0, $transition['manual'] );
}
/**
* List order notes (public) for the customer.
*

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