fix merge conflicts
This commit is contained in:
commit
617a523057
|
@ -0,0 +1,24 @@
|
|||
.*
|
||||
.*/
|
||||
*.lock
|
||||
*.md
|
||||
*.zip
|
||||
babel.config.js
|
||||
bin/
|
||||
build/
|
||||
CHANGELOG.txt
|
||||
composer.*
|
||||
docker-compose.yaml
|
||||
Dockerfile
|
||||
Gruntfile.js
|
||||
node_modules/
|
||||
none
|
||||
package-lock.json
|
||||
package.json
|
||||
packages/woocommerce-admin/docs
|
||||
phpcs.xml
|
||||
phpunit.xml
|
||||
phpunit.xml.dist
|
||||
README.md
|
||||
renovate.json
|
||||
tests
|
|
@ -0,0 +1,25 @@
|
|||
name: Build release asset
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
jobs:
|
||||
build:
|
||||
name: Build release asset
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
id: build
|
||||
uses: woocommerce/action-build@master
|
||||
with:
|
||||
generate-zip: true
|
||||
- name: Upload release asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ github.event.release.upload_url }}
|
||||
asset_path: ${{ steps.build.outputs.zip_path }}
|
||||
asset_name: woocommerce.zip
|
||||
asset_content_type: application/zip
|
|
@ -10,6 +10,7 @@ project.properties
|
|||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.sublimelinterrc
|
||||
*.swp
|
||||
|
||||
# Grunt
|
||||
node_modules/
|
||||
|
@ -65,3 +66,6 @@ contributors.md
|
|||
|
||||
# Language files
|
||||
i18n/languages/woocommerce.pot
|
||||
|
||||
# Build
|
||||
build/
|
||||
|
|
|
@ -1,5 +1,48 @@
|
|||
== Changelog ==
|
||||
|
||||
= 4.1.0 - 2020-05-05 =
|
||||
|
||||
**WooCommerce**
|
||||
* Enhancement - Update dependency woocommerce/woocommerce-admin to v1.1.0 #26057
|
||||
* Enhancement - Updated jetpack-autoloader to 1.6 and woocommerce-blocks to 2.5.16. #26099
|
||||
* Enhancement - Added option to ignore discounts from cart's total amount to enable free shipping. #24776
|
||||
* Enhancement - Changed show password icon color to a darker grey hue. #25625
|
||||
* Enhancement - Use new Setup Wizard for all users. #26016
|
||||
* Tweak - Show notice for WP min version to WP 5.2. #26094
|
||||
* Tweak - Improve the string for untested WooCommerce extensions in the system status page to avoid confusion. #25904
|
||||
* Tweak - Updated KZT (₸) symbol. #25609
|
||||
* Tweak - Trim whitespaces and strip slashes from MaxMind License Key. #25466
|
||||
* Tweak - Updated "Help" tabs documentation. #25826
|
||||
* Tweak - Update serbian currency symbol to рсд from дин. #25885
|
||||
* Fix - Password visibility toggle to hide password again from text. #25627
|
||||
* Fix - Undefined property error when attempting to modify the coupon post meta. #25755
|
||||
* Fix - Remove some of the individual rounding logic to make sure we round at certain places only. #25800
|
||||
* Fix - Order totals calculation if the order contains taxable and non-taxable products and percentage coupons. #25092
|
||||
* Fix - Wording for cancelled order email. #25316
|
||||
* Fix - Removed guided tour videos link on setup wizard (since current link only redirects to the docs). #25823
|
||||
* Fix - Add RTL style to the onboarding wizard. #25835
|
||||
* Fix - Trigger change and set val to qty on the frontend so that it properly updates event handlers. #25903
|
||||
* Fix - Corrected the way percent coupons apply remainders across the order. #25943
|
||||
* Fix - Clarified the error messaging for WooCommerce.com package update failures. #26034
|
||||
* Fix - Enforce per user usage limit check for a coupon on guest users based on email. #26066
|
||||
* Fix - Remove elements with style=display:none explicitly to address a regression causing broken email html. #26075
|
||||
* Dev - Added woocommerce_can_restock_refunded_items filter. #25728
|
||||
* Dev - Added woocommerce_order_get_tax_location filter. #25727
|
||||
* Dev - Updated stock handling to prevent race conditions when orders come in at the same time. #25708
|
||||
* Dev - Updated /myaccount/form-login.php to use consistent kebab-case class names for woocommerce-form-row. #25668
|
||||
* Dev - Add filter woocommerce_product_upsells_products_heading to allow heading modification without having to override the template file. #25628
|
||||
* Dev - Added woocommerce_order_get_tax_location filter. #25727
|
||||
* Dev - Added the get_woocommerce_currency_symbols function to allow develops to get an array of all the currency symbol registered with WooCommerce. #25733
|
||||
* Dev - Changed string typed label_class to array in checkout fields.
|
||||
* Dev - Added "woocommerce_emogrifier" action before the content of the emails is "emogrified". #25801
|
||||
* Dev - Add Ability to Filter Event Props. #25851
|
||||
* Dev - Updated the unit test install script to support paths to MySQL sockets that contain spaces. #25923
|
||||
* Dev - Made the default test source folders support the system tmp folder. #25923
|
||||
* Dev - Add cart & checkout block/shortcode info to tracker data. #25932
|
||||
* Dev - Make WC_Product_Data_Store_CPT::update_product_stock operations atomic. #26039
|
||||
* Dev - Adds usage data for the of cart & checkout blocks (currently in development in WooCommmerce Blocks plugin) to the WC Tracker snapshot. #26084
|
||||
* Dev - Implement some additional tracks for coupons, orders, and products. #26085
|
||||
|
||||
= 4.0.1 - 2020-03-18 =
|
||||
|
||||
**WooCommerce**
|
||||
|
|
|
@ -15,7 +15,7 @@ Welcome to the WooCommerce repository on GitHub. Here you can browse the source,
|
|||
If you are not a developer, please use the [WooCommerce plugin page](https://wordpress.org/plugins/woocommerce/) on WordPress.org.
|
||||
|
||||
## Documentation
|
||||
* [WooCommerce Documentation](https://docs.woocommerce.com/documentation/plugins/woocommerce/)
|
||||
* [WooCommerce Documentation](https://docs.woocommerce.com/)
|
||||
* [WooCommerce Developer Documentation](https://github.com/woocommerce/woocommerce/wiki)
|
||||
* [WooCommerce Code Reference](https://docs.woocommerce.com/wc-apidocs/)
|
||||
* [WooCommerce REST API Docs](https://woocommerce.github.io/woocommerce-rest-api-docs/)
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
div.woocommerce-message {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border-left-color: #cc99c2 !important;
|
||||
|
||||
&.updated {
|
||||
border-left-color: #cc99c2 !important;
|
||||
}
|
||||
}
|
||||
|
||||
p.woocommerce-actions,
|
||||
|
|
|
@ -541,9 +541,12 @@
|
|||
|
||||
.woocommerce-message {
|
||||
position: relative;
|
||||
border-left-color: #cc99c2 !important;
|
||||
overflow: hidden;
|
||||
|
||||
&.updated {
|
||||
border-left-color: #cc99c2 !important;
|
||||
}
|
||||
|
||||
a.skip,
|
||||
a.docs {
|
||||
text-decoration: none !important;
|
||||
|
@ -637,7 +640,7 @@ mark.amount {
|
|||
}
|
||||
}
|
||||
|
||||
.branch-5-3 {
|
||||
.wc-wp-version-gte-53 {
|
||||
|
||||
.woocommerce-help-tip {
|
||||
font-size: 1.2em;
|
||||
|
@ -2167,7 +2170,7 @@ ul.wc_coupon_list_block {
|
|||
}
|
||||
}
|
||||
|
||||
.branch-5-3 {
|
||||
.wc-wp-version-gte-53 {
|
||||
|
||||
.widefat {
|
||||
|
||||
|
@ -4123,7 +4126,7 @@ img.help_tip {
|
|||
}
|
||||
}
|
||||
|
||||
.branch-5-3 {
|
||||
.wc-wp-version-gte-53 {
|
||||
|
||||
.woocommerce {
|
||||
|
||||
|
@ -6694,7 +6697,7 @@ table.bar_chart {
|
|||
min-width: 400px !important;
|
||||
}
|
||||
|
||||
.branch-5-3 {
|
||||
.wc-wp-version-gte-53 {
|
||||
|
||||
.select2-results {
|
||||
|
||||
|
@ -6831,7 +6834,7 @@ table.bar_chart {
|
|||
|
||||
@each $name, $color in $wp_admin_colors {
|
||||
|
||||
&-#{$name}.branch-5-3 {
|
||||
&-#{$name}.wc-wp-version-gte-53 {
|
||||
|
||||
.select2-dropdown {
|
||||
border-color: $color;
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* privacy.scss
|
||||
* Styles applied to the Privacy Policy Guide to support WooCommerce content.
|
||||
* Adds support for styling ul/ol elements.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Styling begins
|
||||
*/
|
||||
|
||||
// Support for indented bullet-lists.
|
||||
.policy-text ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
.policy-text ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.policy-text ul li,
|
||||
.policy-text ol li {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
// Pre-5.4 support for italics.
|
||||
.branch-5-2 .policy-text ul,
|
||||
.branch-5-2 .policy-text ol,
|
||||
.branch-5-3 .policy-text ul,
|
||||
.branch-5-3 .policy-text ol {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
// 5.4 support for white background and padding.
|
||||
.branch-5-4 .policy-text ul:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.branch-5-4 .policy-text ol:not(.privacy-policy-tutorial):not(.wp-policy-help) {
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.branch-5-4 .hide-privacy-policy-tutorial ul:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.branch-5-4 .hide-privacy-policy-tutorial ol:not(.privacy-policy-tutorial):not(.wp-policy-help) {
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.policy-text p:not(.privacy-policy-tutorial):not(.wp-policy-help) + ul:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.policy-text p:not(.privacy-policy-tutorial):not(.wp-policy-help) + ol:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.policy-text ul:not(.privacy-policy-tutorial):not(.wp-policy-help) + p:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.policy-text ul:not(.privacy-policy-tutorial):not(.wp-policy-help) + ul:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.policy-text ul:not(.privacy-policy-tutorial):not(.wp-policy-help) + ol:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.policy-text ol:not(.privacy-policy-tutorial):not(.wp-policy-help) + p:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.policy-text ol:not(.privacy-policy-tutorial):not(.wp-policy-help) + ul:not(.privacy-policy-tutorial):not(.wp-policy-help),
|
||||
.policy-text ol:not(.privacy-policy-tutorial):not(.wp-policy-help) + ol:not(.privacy-policy-tutorial):not(.wp-policy-help) {
|
||||
padding-top: 0;
|
||||
}
|
|
@ -170,6 +170,7 @@ a.button {
|
|||
}
|
||||
|
||||
.wc-block-grid__products {
|
||||
|
||||
.wc-block-grid__product-onsale {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -296,6 +297,7 @@ a.button {
|
|||
}
|
||||
|
||||
#site-content {
|
||||
|
||||
.post-inner {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
@ -319,7 +321,7 @@ a.button {
|
|||
/* Make thumbnails in the gallery affect parent's height and wrapping */
|
||||
.flex-control-nav::after {
|
||||
clear: both;
|
||||
content: '';
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
|
||||
|
@ -501,7 +503,7 @@ dl.variation,
|
|||
|
||||
.product_meta {
|
||||
clear: both;
|
||||
font-size: .7em;
|
||||
font-size: 0.7em;
|
||||
padding-top: 0.5em;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
@ -726,7 +728,7 @@ a.reset_variations {
|
|||
margin: 4rem 0 2rem;
|
||||
|
||||
/* reset description tab width to full width */
|
||||
#tab-description{
|
||||
#tab-description {
|
||||
|
||||
h2,
|
||||
p {
|
||||
|
@ -836,7 +838,7 @@ a.reset_variations {
|
|||
}
|
||||
}
|
||||
|
||||
.comment-form-rating{
|
||||
.comment-form-rating {
|
||||
|
||||
label {
|
||||
max-width: 58rem;
|
||||
|
@ -910,7 +912,7 @@ a.reset_variations {
|
|||
}
|
||||
|
||||
.comment-form-author,
|
||||
.comment-form-email{
|
||||
.comment-form-email {
|
||||
float: none;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
@ -924,6 +926,8 @@ a.reset_variations {
|
|||
.related.products,
|
||||
.up-sells {
|
||||
|
||||
clear: both;
|
||||
|
||||
ul.products {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
|
@ -1185,6 +1189,7 @@ a.reset_variations {
|
|||
}
|
||||
|
||||
form {
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
@ -1215,7 +1220,7 @@ a.reset_variations {
|
|||
}
|
||||
}
|
||||
|
||||
table.account-orders-table:not( .has-background ) {
|
||||
table.account-orders-table:not(.has-background) {
|
||||
|
||||
tbody {
|
||||
|
||||
|
@ -1343,6 +1348,7 @@ a.reset_variations {
|
|||
}
|
||||
|
||||
tbody {
|
||||
|
||||
tr {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
@ -1399,7 +1405,7 @@ a.reset_variations {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
input[type='radio'].shipping_method {
|
||||
input[type="radio"].shipping_method {
|
||||
display: none;
|
||||
|
||||
& + label {
|
||||
|
@ -1713,9 +1719,9 @@ a.reset_variations {
|
|||
}
|
||||
|
||||
tbody::after {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 2rem;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.woocommerce-Price-amount {
|
||||
|
@ -1723,7 +1729,7 @@ a.reset_variations {
|
|||
}
|
||||
|
||||
.cart-subtotal,
|
||||
.order-total{
|
||||
.order-total {
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
|
@ -1774,6 +1780,7 @@ a.reset_variations {
|
|||
}
|
||||
|
||||
.woocommerce-form-login {
|
||||
|
||||
p.form-row.form-row-first,
|
||||
p.form-row.form-row-last {
|
||||
float: none;
|
||||
|
@ -1836,7 +1843,7 @@ a.reset_variations {
|
|||
|
||||
.woocommerce-checkout-review-order-table {
|
||||
|
||||
input[type='radio'].shipping_method {
|
||||
input[type="radio"].shipping_method {
|
||||
display: none;
|
||||
|
||||
& + label {
|
||||
|
@ -2134,13 +2141,15 @@ ul.wc-block-grid__products {
|
|||
.wc-block-grid__product-rating {
|
||||
|
||||
.star-rating {
|
||||
font-size: 0.7em
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
|
||||
.woocommerce {
|
||||
|
||||
.woocommerce-ordering {
|
||||
float: left;
|
||||
clear: both;
|
||||
|
@ -2265,7 +2274,7 @@ ul.wc-block-grid__products {
|
|||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2385,8 +2394,8 @@ ul.wc-block-grid__products {
|
|||
table.account-orders-table {
|
||||
|
||||
.button {
|
||||
padding-left: .5em;
|
||||
padding-right: .5em;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
width: 100%;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
@ -2427,6 +2436,7 @@ ul.wc-block-grid__products {
|
|||
}
|
||||
|
||||
.wc-block-grid__products {
|
||||
|
||||
.wc-block-grid__product-onsale {
|
||||
font-size: 1.5rem;
|
||||
padding: 1rem;
|
||||
|
@ -2587,6 +2597,7 @@ ul.wc-block-grid__products {
|
|||
}
|
||||
|
||||
.wc-block-grid__products {
|
||||
|
||||
.wc-block-grid__product-onsale {
|
||||
font-size: 1.7rem;
|
||||
padding: 1.5rem;
|
||||
|
|
|
@ -1185,7 +1185,7 @@ h3.jetpack-reasons {
|
|||
}
|
||||
|
||||
.branch-5-2,
|
||||
.branch-5-3 {
|
||||
.wc-wp-version-gte-53 {
|
||||
|
||||
.location-input {
|
||||
margin: 0;
|
||||
|
@ -1415,7 +1415,7 @@ p.jetpack-terms {
|
|||
}
|
||||
|
||||
.branch-5-2,
|
||||
.branch-5-3 {
|
||||
.wc-wp-version-gte-53 {
|
||||
|
||||
.wc-wizard-service-setting-stripe_create_account,
|
||||
.wc-wizard-service-setting-ppec_paypal_reroute_requests {
|
||||
|
|
|
@ -17,6 +17,7 @@ jQuery( function( $ ) {
|
|||
.on( 'click', '.add_to_cart_button', { addToCartHandler: this }, this.onAddToCart )
|
||||
.on( 'click', '.remove_from_cart_button', { addToCartHandler: this }, this.onRemoveFromCart )
|
||||
.on( 'added_to_cart', this.updateButton )
|
||||
.on( 'ajax_request_not_sent.adding_to_cart', this.updateButton )
|
||||
.on( 'added_to_cart removed_from_cart', { addToCartHandler: this }, this.updateFragments );
|
||||
};
|
||||
|
||||
|
@ -69,6 +70,12 @@ jQuery( function( $ ) {
|
|||
$thisbutton.removeClass( 'added' );
|
||||
$thisbutton.addClass( 'loading' );
|
||||
|
||||
// Allow 3rd parties to validate and quit early.
|
||||
if ( false === $( document.body ).triggerHandler( 'should_send_ajax_request.adding_to_cart', [ $thisbutton ] ) ) {
|
||||
$( document.body ).trigger( 'ajax_request_not_sent.adding_to_cart', [ false, false, $thisbutton ] );
|
||||
return true;
|
||||
}
|
||||
|
||||
var data = {};
|
||||
|
||||
// Fetch changes that are directly added by calling $thisbutton.data( key, value )
|
||||
|
@ -159,10 +166,13 @@ jQuery( function( $ ) {
|
|||
|
||||
if ( $button ) {
|
||||
$button.removeClass( 'loading' );
|
||||
$button.addClass( 'added' );
|
||||
|
||||
if ( fragments ) {
|
||||
$button.addClass( 'added' );
|
||||
}
|
||||
|
||||
// View cart text.
|
||||
if ( ! wc_add_to_cart_params.is_cart && $button.parent().find( '.added_to_cart' ).length === 0 ) {
|
||||
if ( fragments && ! wc_add_to_cart_params.is_cart && $button.parent().find( '.added_to_cart' ).length === 0 ) {
|
||||
$button.after( ' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
|
||||
wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>' );
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ jQuery( function( $ ) {
|
|||
|
||||
var country = $( this ).val(),
|
||||
$statebox = $wrapper.find( '#billing_state, #shipping_state, #calc_shipping_state' ),
|
||||
$parent = $statebox.closest( 'p.form-row' ),
|
||||
$parent = $statebox.closest( '.form-row' ),
|
||||
input_name = $statebox.attr( 'name' ),
|
||||
input_id = $statebox.attr('id'),
|
||||
input_classes = $statebox.attr('data-input-classes'),
|
||||
|
|
|
@ -81,7 +81,7 @@ jQuery( function( $ ) {
|
|||
|
||||
// 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>' );
|
||||
$( '.password-input' ).prepend( '<span class="show-password-input"></span>' );
|
||||
|
||||
$( '.show-password-input' ).click(
|
||||
function() {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
|
||||
PLUGIN_SLUG="woocommerce"
|
||||
PROJECT_PATH=$(pwd)
|
||||
BUILD_PATH="${PROJECT_PATH}/build"
|
||||
DEST_PATH="$BUILD_PATH/$PLUGIN_SLUG"
|
||||
|
||||
echo "Generating build directory..."
|
||||
rm -rf "$BUILD_PATH"
|
||||
mkdir -p "$DEST_PATH"
|
||||
|
||||
echo "Installing PHP and JS dependencies..."
|
||||
npm install
|
||||
composer install || exit "$?"
|
||||
echo "Running JS Build..."
|
||||
npm run build || exit "$?"
|
||||
echo "Cleaning up PHP dependencies..."
|
||||
composer install --no-dev || exit "$?"
|
||||
|
||||
echo "Syncing files..."
|
||||
rsync -rc --exclude-from="$PROJECT_PATH/.distignore" "$PROJECT_PATH/" "$DEST_PATH/" --delete --delete-excluded
|
||||
|
||||
echo "Restoring PHP dependencies..."
|
||||
composer install || exit "$?"
|
||||
npm run build || exit "$?"
|
||||
|
||||
echo "Generating zip file..."
|
||||
cd "$BUILD_PATH" || exit
|
||||
zip -q -r "${PLUGIN_SLUG}.zip" "$PLUGIN_SLUG/"
|
||||
echo "$BUILD_PATH/${PLUGIN_SLUG}.zip file generated!"
|
||||
|
||||
echo "Build done!"
|
|
@ -13,10 +13,10 @@
|
|||
"composer/installers": "1.7.0",
|
||||
"maxmind-db/reader": "1.6.0",
|
||||
"pelago/emogrifier": "^3.1",
|
||||
"woocommerce/action-scheduler": "3.1.5",
|
||||
"woocommerce/woocommerce-admin": "1.1.1",
|
||||
"woocommerce/action-scheduler": "3.1.6",
|
||||
"woocommerce/woocommerce-admin": "1.2.0",
|
||||
"woocommerce/woocommerce-blocks": "2.5.16",
|
||||
"woocommerce/woocommerce-rest-api": "1.0.7"
|
||||
"woocommerce/woocommerce-rest-api": "1.0.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "7.5.20",
|
||||
|
@ -45,7 +45,7 @@
|
|||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Automattic\\WooCommerce\\Tests\\": "tests/php/"
|
||||
"Automattic\\WooCommerce\\Tests\\": "tests/php/src"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -68,7 +68,7 @@
|
|||
"phpcbf -p"
|
||||
],
|
||||
"makepot-audit": [
|
||||
"wp i18n make-pot . --exclude=\".github,.wordpress-org,bin,sample-data,node_modules,tests\" --slug=woocommerce"
|
||||
"wp --allow-root i18n make-pot . --exclude=\".github,.wordpress-org,bin,sample-data,node_modules,tests\" --slug=woocommerce"
|
||||
],
|
||||
"makepot": [
|
||||
"@makepot-audit --skip-audit"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "265265cc587459cc670e28108c87c9aa",
|
||||
"content-hash": "9548fdb91087ffaa8f14374698bf402e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "automattic/jetpack-autoloader",
|
||||
|
@ -384,16 +384,16 @@
|
|||
},
|
||||
{
|
||||
"name": "woocommerce/action-scheduler",
|
||||
"version": "3.1.5",
|
||||
"version": "3.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/action-scheduler.git",
|
||||
"reference": "84e8ecba7d4f542f85fae7663e90eede1858b41b"
|
||||
"reference": "275d0ba54b1c263dfc62688de2fa9a25a373edf8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/action-scheduler/zipball/84e8ecba7d4f542f85fae7663e90eede1858b41b",
|
||||
"reference": "84e8ecba7d4f542f85fae7663e90eede1858b41b",
|
||||
"url": "https://api.github.com/repos/woocommerce/action-scheduler/zipball/275d0ba54b1c263dfc62688de2fa9a25a373edf8",
|
||||
"reference": "275d0ba54b1c263dfc62688de2fa9a25a373edf8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -415,20 +415,20 @@
|
|||
],
|
||||
"description": "Action Scheduler for WordPress and WooCommerce",
|
||||
"homepage": "https://actionscheduler.org/",
|
||||
"time": "2020-04-29T16:19:22+00:00"
|
||||
"time": "2020-05-12T16:22:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-admin",
|
||||
"version": "v1.1.1",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-admin.git",
|
||||
"reference": "79e78bb8b71fa0c0b0a77efee5474b46d62c1a76"
|
||||
"reference": "aa5062218a399843e68160e1b4b884320a7530ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/79e78bb8b71fa0c0b0a77efee5474b46d62c1a76",
|
||||
"reference": "79e78bb8b71fa0c0b0a77efee5474b46d62c1a76",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/aa5062218a399843e68160e1b4b884320a7530ae",
|
||||
"reference": "aa5062218a399843e68160e1b4b884320a7530ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -462,7 +462,7 @@
|
|||
],
|
||||
"description": "A modern, javascript-driven WooCommerce Admin experience.",
|
||||
"homepage": "https://github.com/woocommerce/woocommerce-admin",
|
||||
"time": "2020-04-28T22:16:15+00:00"
|
||||
"time": "2020-05-08T22:39:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-blocks",
|
||||
|
@ -513,16 +513,16 @@
|
|||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-rest-api",
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-rest-api.git",
|
||||
"reference": "49162ec26a25bd0c6efc0f3452b113cdfff0a823"
|
||||
"reference": "0756027c669bb5749554ee58b9416cbdcceaa752"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-rest-api/zipball/49162ec26a25bd0c6efc0f3452b113cdfff0a823",
|
||||
"reference": "49162ec26a25bd0c6efc0f3452b113cdfff0a823",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-rest-api/zipball/0756027c669bb5749554ee58b9416cbdcceaa752",
|
||||
"reference": "0756027c669bb5749554ee58b9416cbdcceaa752",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -549,7 +549,7 @@
|
|||
],
|
||||
"description": "The WooCommerce core REST API.",
|
||||
"homepage": "https://github.com/woocommerce/woocommerce-rest-api",
|
||||
"time": "2020-01-28T21:04:51+00:00"
|
||||
"time": "2020-05-11T14:54:30+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -2463,16 +2463,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.15.0",
|
||||
"version": "v1.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14"
|
||||
"reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
|
||||
"reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1aab00e39cebaef4d8652497f46c15c1b7e45294",
|
||||
"reference": "1aab00e39cebaef4d8652497f46c15c1b7e45294",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2484,7 +2484,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.15-dev"
|
||||
"dev-master": "1.16-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -2517,7 +2517,7 @@
|
|||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"time": "2020-02-27T09:26:54+00:00"
|
||||
"time": "2020-05-08T16:50:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
|
|
|
@ -349,6 +349,26 @@ return array(
|
|||
),
|
||||
'FI' => array(),
|
||||
'FR' => array(),
|
||||
'GH' => array( // Ghanaian Regions.
|
||||
'AF' => __( 'Ahafo', 'woocommerce' ),
|
||||
'AH' => __( 'Ashanti', 'woocommerce' ),
|
||||
'AV' => __( 'Avannaata Kommunia', 'woocommerce' ),
|
||||
'BA' => __( 'Brong-Ahafo', 'woocommerce' ),
|
||||
'BO' => __( 'Bono', 'woocommerce' ),
|
||||
'BE' => __( 'Bono East', 'woocommerce' ),
|
||||
'CP' => __( 'Central', 'woocommerce' ),
|
||||
'EP' => __( 'Eastern', 'woocommerce' ),
|
||||
'AA' => __( 'Greater Accra', 'woocommerce' ),
|
||||
'NE' => __( 'North East', 'woocommerce' ),
|
||||
'NP' => __( 'Northern', 'woocommerce' ),
|
||||
'OT' => __( 'Oti', 'woocommerce' ),
|
||||
'SV' => __( 'Savannah', 'woocommerce' ),
|
||||
'UE' => __( 'Upper East', 'woocommerce' ),
|
||||
'UW' => __( 'Upper West', 'woocommerce' ),
|
||||
'TV' => __( 'Volta', 'woocommerce' ),
|
||||
'WP' => __( 'Western', 'woocommerce' ),
|
||||
'WN' => __( 'Western North', 'woocommerce' ),
|
||||
),
|
||||
'GP' => array(),
|
||||
'GR' => array( // Greek Regions.
|
||||
'I' => __( 'Αττική', 'woocommerce' ),
|
||||
|
@ -828,6 +848,19 @@ return array(
|
|||
'PJY' => __( 'Putrajaya', 'woocommerce' ),
|
||||
'KUL' => __( 'Kuala Lumpur', 'woocommerce' ),
|
||||
),
|
||||
'MZ' => array( // Mozambique provinces.
|
||||
'MZP' => __( 'Cabo Delgado', 'woocommerce' ),
|
||||
'MZG' => __( 'Gaza', 'woocommerce' ),
|
||||
'MZI' => __( 'Inhambane', 'woocommerce' ),
|
||||
'MZB' => __( 'Manica', 'woocommerce' ),
|
||||
'MZL' => __( 'Maputo Province', 'woocommerce' ),
|
||||
'MZMPM' => __( 'Maputo', 'woocommerce' ),
|
||||
'MZN' => __( 'Nampula', 'woocommerce' ),
|
||||
'MZA' => __( 'Niassa', 'woocommerce' ),
|
||||
'MZS' => __( 'Sofala', 'woocommerce' ),
|
||||
'MZT' => __( 'Tete', 'woocommerce' ),
|
||||
'MZQ' => __( 'Zambézia', 'woocommerce' ),
|
||||
),
|
||||
'NG' => array( // Nigerian provinces.
|
||||
'AB' => __( 'Abia', 'woocommerce' ),
|
||||
'FC' => __( 'Abuja', 'woocommerce' ),
|
||||
|
|
|
@ -51,13 +51,13 @@ class WC_Admin_Addons {
|
|||
*/
|
||||
public static function build_parameter_string( $category, $term, $country ) {
|
||||
|
||||
$paramters = array(
|
||||
$parameters = array(
|
||||
'category' => $category,
|
||||
'term' => $term,
|
||||
'country' => $country,
|
||||
);
|
||||
|
||||
return '?' . http_build_query( $paramters );
|
||||
return '?' . http_build_query( $parameters );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
|||
wp_register_style( 'woocommerce_admin_dashboard_styles', WC()->plugin_url() . '/assets/css/dashboard.css', array(), $version );
|
||||
wp_register_style( 'woocommerce_admin_print_reports_styles', WC()->plugin_url() . '/assets/css/reports-print.css', array(), $version, 'print' );
|
||||
wp_register_style( 'woocommerce_admin_marketplace_styles', WC()->plugin_url() . '/assets/css/marketplace-suggestions.css', array(), $version );
|
||||
wp_register_style( 'woocommerce_admin_privacy_styles', WC()->plugin_url() . '/assets/css/privacy.css', array(), $version );
|
||||
|
||||
// Add RTL support for admin styles.
|
||||
wp_style_add_data( 'woocommerce_admin_menu_styles', 'rtl', 'replace' );
|
||||
|
@ -51,6 +52,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
|||
wp_style_add_data( 'woocommerce_admin_dashboard_styles', 'rtl', 'replace' );
|
||||
wp_style_add_data( 'woocommerce_admin_print_reports_styles', 'rtl', 'replace' );
|
||||
wp_style_add_data( 'woocommerce_admin_marketplace_styles', 'rtl', 'replace' );
|
||||
wp_style_add_data( 'woocommerce_admin_privacy_styles', 'rtl', 'replace' );
|
||||
|
||||
// Sitewide menu CSS.
|
||||
wp_enqueue_style( 'woocommerce_admin_menu_styles' );
|
||||
|
@ -70,6 +72,11 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
|||
wp_enqueue_style( 'woocommerce_admin_print_reports_styles' );
|
||||
}
|
||||
|
||||
// Privacy Policy Guide css for back-compat.
|
||||
if ( isset( $_GET['wp-privacy-policy-guide'] ) || in_array( $screen_id, array( 'privacy-policy-guide' ) ) ) {
|
||||
wp_enqueue_style( 'woocommerce_admin_privacy_styles' );
|
||||
}
|
||||
|
||||
// @deprecated 2.3.
|
||||
if ( has_action( 'woocommerce_admin_css' ) ) {
|
||||
do_action( 'woocommerce_admin_css' );
|
||||
|
|
|
@ -49,9 +49,9 @@ class WC_Admin_Meta_Boxes {
|
|||
* Save order data - also updates status and sends out admin emails if needed. Last to show latest data.
|
||||
* Save actions - sends out other emails. Last to show latest data.
|
||||
*/
|
||||
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Items::save', 10, 2 );
|
||||
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Items::save', 10 );
|
||||
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Downloads::save', 30, 2 );
|
||||
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Data::save', 40, 2 );
|
||||
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Data::save', 40 );
|
||||
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Actions::save', 50, 2 );
|
||||
|
||||
// Save Product Meta Boxes.
|
||||
|
|
|
@ -28,17 +28,18 @@ class WC_Admin_Notices {
|
|||
* @var array
|
||||
*/
|
||||
private static $core_notices = array(
|
||||
'install' => 'install_notice',
|
||||
'update' => 'update_notice',
|
||||
'template_files' => 'template_file_check_notice',
|
||||
'legacy_shipping' => 'legacy_shipping_notice',
|
||||
'no_shipping_methods' => 'no_shipping_methods_notice',
|
||||
'regenerating_thumbnails' => 'regenerating_thumbnails_notice',
|
||||
'regenerating_lookup_table' => 'regenerating_lookup_table_notice',
|
||||
'no_secure_connection' => 'secure_connection_notice',
|
||||
WC_PHP_MIN_REQUIREMENTS_NOTICE => 'wp_php_min_requirements_notice',
|
||||
'maxmind_license_key' => 'maxmind_missing_license_key_notice',
|
||||
'redirect_download_method' => 'redirect_download_method_notice',
|
||||
'install' => 'install_notice',
|
||||
'update' => 'update_notice',
|
||||
'template_files' => 'template_file_check_notice',
|
||||
'legacy_shipping' => 'legacy_shipping_notice',
|
||||
'no_shipping_methods' => 'no_shipping_methods_notice',
|
||||
'regenerating_thumbnails' => 'regenerating_thumbnails_notice',
|
||||
'regenerating_lookup_table' => 'regenerating_lookup_table_notice',
|
||||
'no_secure_connection' => 'secure_connection_notice',
|
||||
WC_PHP_MIN_REQUIREMENTS_NOTICE => 'wp_php_min_requirements_notice',
|
||||
'maxmind_license_key' => 'maxmind_missing_license_key_notice',
|
||||
'redirect_download_method' => 'redirect_download_method_notice',
|
||||
'uploads_directory_is_unprotected' => 'uploads_directory_is_unprotected_notice',
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -93,6 +94,9 @@ class WC_Admin_Notices {
|
|||
if ( ! self::is_ssl() ) {
|
||||
self::add_notice( 'no_secure_connection' );
|
||||
}
|
||||
if ( ! self::is_uploads_directory_protected() ) {
|
||||
self::add_notice( 'uploads_directory_is_unprotected' );
|
||||
}
|
||||
self::add_notice( 'template_files' );
|
||||
self::add_min_version_notice();
|
||||
self::add_maxmind_missing_license_key_notice();
|
||||
|
@ -488,6 +492,20 @@ class WC_Admin_Notices {
|
|||
include dirname( __FILE__ ) . '/views/html-notice-redirect-only-download.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice about uploads directory begin unprotected.
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public static function uploads_directory_is_unprotected_notice() {
|
||||
if ( get_user_meta( get_current_user_id(), 'dismissed_uploads_directory_is_unprotected_notice', true ) || self::is_uploads_directory_protected() ) {
|
||||
self::remove_notice( 'uploads_directory_is_unprotected' );
|
||||
return;
|
||||
}
|
||||
|
||||
include dirname( __FILE__ ) . '/views/html-notice-uploads-directory-is-unprotected.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the store is running SSL.
|
||||
*
|
||||
|
@ -530,6 +548,37 @@ class WC_Admin_Notices {
|
|||
public static function theme_check_notice() {
|
||||
wc_deprecated_function( 'WC_Admin_Notices::theme_check_notice', '3.3.0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if uploads directory is protected.
|
||||
*
|
||||
* @since 4.2.0
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_uploads_directory_protected() {
|
||||
$cache_key = '_woocommerce_upload_directory_status';
|
||||
$status = get_transient( $cache_key );
|
||||
|
||||
// Check for cache.
|
||||
if ( false !== $status ) {
|
||||
return 'protected' === $status;
|
||||
}
|
||||
|
||||
// Get only data from the uploads directory.
|
||||
$uploads = wp_get_upload_dir();
|
||||
|
||||
// Check for the "uploads/woocommerce_uploads" directory.
|
||||
$response = wp_safe_remote_get( esc_url_raw( $uploads['baseurl'] . '/woocommerce_uploads' ) );
|
||||
$response_code = intval( wp_remote_retrieve_response_code( $response ) );
|
||||
$response_content = wp_remote_retrieve_body( $response );
|
||||
|
||||
// Check if returns 200 with empty content in case can open an index.html file,
|
||||
// and check for non-200 codes in case the directory is protected.
|
||||
$is_protected = ( 200 === $response_code && empty( $response_content ) ) || ( 200 !== $response_code );
|
||||
set_transient( $cache_key, $is_protected ? 'protected' : 'unprotected', 1 * DAY_IN_SECONDS );
|
||||
|
||||
return $is_protected;
|
||||
}
|
||||
}
|
||||
|
||||
WC_Admin_Notices::init();
|
||||
|
|
|
@ -200,7 +200,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
|||
/**
|
||||
* Output admin fields.
|
||||
*
|
||||
* Loops though the woocommerce options array and outputs each field.
|
||||
* Loops through the woocommerce options array and outputs each field.
|
||||
*
|
||||
* @param array[] $options Opens array to output.
|
||||
*/
|
||||
|
@ -726,7 +726,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
|||
/**
|
||||
* Save admin fields.
|
||||
*
|
||||
* Loops though the woocommerce options array and outputs each field.
|
||||
* Loops through the woocommerce options array and outputs each field.
|
||||
*
|
||||
* @param array $options Options array to output.
|
||||
* @param array $data Optional. Data to use for saving. Defaults to $_POST.
|
||||
|
|
|
@ -33,6 +33,9 @@ class WC_Admin {
|
|||
|
||||
// Disable WXR export of schedule action posts.
|
||||
add_filter( 'action_scheduler_post_type_args', array( $this, 'disable_webhook_post_export' ) );
|
||||
|
||||
// Add body class for WP 5.3+ compatibility.
|
||||
add_filter( 'admin_body_class', array( $this, 'include_admin_body_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -306,6 +309,30 @@ class WC_Admin {
|
|||
$args['can_export'] = false;
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include admin classes.
|
||||
*
|
||||
* @since 4.2.0
|
||||
* @param string $classes Body classes string.
|
||||
* @return string
|
||||
*/
|
||||
public function include_admin_body_class( $classes ) {
|
||||
if ( false !== strpos( $classes, 'wc-wp-version-gte-53' ) ) {
|
||||
return $classes;
|
||||
}
|
||||
|
||||
$raw_version = get_bloginfo( 'version' );
|
||||
$version_parts = explode( '-', $raw_version );
|
||||
$version = count( $version_parts ) > 1 ? $version_parts[0] : $raw_version;
|
||||
|
||||
// Add WP 5.3+ compatibility class.
|
||||
if ( $raw_version && version_compare( $version, '5.3', '>=' ) ) {
|
||||
$classes .= ' wc-wp-version-gte-53';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
|
||||
return new WC_Admin();
|
||||
|
|
|
@ -471,6 +471,7 @@ class WC_Helper {
|
|||
|
||||
if ( $wc_screen_id . '_page_wc-addons' === $screen_id && isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
|
||||
wp_enqueue_style( 'woocommerce-helper', WC()->plugin_url() . '/assets/css/helper.css', array(), Constants::get_constant( 'WC_VERSION' ) );
|
||||
wp_style_add_data( 'woocommerce-helper', 'rtl', 'replace' );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1149,9 +1150,18 @@ class WC_Helper {
|
|||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
// Reset plugin cache before retrieving plugin list.
|
||||
wp_clean_plugins_cache();
|
||||
$plugins = get_plugins();
|
||||
$plugins = get_plugins();
|
||||
|
||||
/**
|
||||
* Check if plugins have WC headers, if not then clear cache and fetch again.
|
||||
* WC Headers will not be present if `wc_enable_wc_plugin_headers` hook was added after a `get_plugins` call -- for example when WC is activated/updated.
|
||||
* Also, get_plugins call is expensive so we should clear this cache very conservatively.
|
||||
*/
|
||||
if ( ! empty( $plugins ) && ! array_key_exists( 'Woo', current( $plugins ) ) ) {
|
||||
wp_clean_plugins_cache( false );
|
||||
$plugins = get_plugins();
|
||||
}
|
||||
|
||||
$woo_plugins = array();
|
||||
|
||||
// Backwards compatibility for woothemes_queue_update().
|
||||
|
@ -1469,8 +1479,6 @@ class WC_Helper {
|
|||
$screen = get_current_screen();
|
||||
$screen_id = $screen ? $screen->id : '';
|
||||
|
||||
self::_prompt_helper_connect( $screen_id );
|
||||
|
||||
if ( 'update-core' !== $screen_id ) {
|
||||
return;
|
||||
}
|
||||
|
@ -1487,56 +1495,6 @@ class WC_Helper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt a Helper connection if the user has WooCommerce.com extensions.
|
||||
*
|
||||
* @param string $screen_id Current screen ID.
|
||||
*/
|
||||
private static function _prompt_helper_connect( $screen_id ) {
|
||||
if ( apply_filters( 'woocommerce_helper_suppress_connect_notice', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screens = wc_get_screen_ids();
|
||||
$screens[] = 'plugins';
|
||||
|
||||
if ( ! in_array( $screen_id, $screens, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't show the notice on the Helper screens.
|
||||
$screen_addons = sanitize_title( __( 'WooCommerce', 'woocommerce' ) ) . '_page_wc-addons';
|
||||
|
||||
if ( $screen_addons === $screen_id && ! empty( $_REQUEST['section'] ) && 'helper' === $_REQUEST['section'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We believe we have an active connection.
|
||||
$auth = WC_Helper_Options::get( 'auth' );
|
||||
if ( ! empty( $auth['access_token'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$active_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
|
||||
if ( empty( $active_plugins ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$woo_plugins = self::get_local_woo_plugins();
|
||||
if ( empty( $woo_plugins ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$active_woo_plugins = array_intersect_key( $woo_plugins, array_flip( $active_plugins ) );
|
||||
|
||||
if ( count( $active_woo_plugins ) > 0 ) {
|
||||
/* translators: %s: helper screen url */
|
||||
$notice = __( '<a href="%s">Connect your store</a> to WooCommerce.com to receive extensions updates and support.', 'woocommerce' );
|
||||
$notice = sprintf( $notice, admin_url( 'admin.php?page=wc-addons§ion=helper' ) );
|
||||
echo '<div class="updated woocommerce-message"><p>' . wp_kses_post( $notice ) . '</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an update notice if one or more Woo extensions has an update available.
|
||||
*
|
||||
|
|
|
@ -319,6 +319,7 @@ class WC_Product_CSV_Importer_Controller {
|
|||
return new WP_Error( 'woocommerce_product_csv_importer_upload_file_empty', __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
|
||||
if ( ! self::is_file_valid_csv( wc_clean( wp_unslash( $_FILES['import']['name'] ) ), false ) ) {
|
||||
return new WP_Error( 'woocommerce_product_csv_importer_upload_file_invalid', __( 'Invalid file type. The importer supports CSV and TXT file formats.', 'woocommerce' ) );
|
||||
}
|
||||
|
@ -327,7 +328,7 @@ class WC_Product_CSV_Importer_Controller {
|
|||
'test_form' => false,
|
||||
'mimes' => self::get_valid_csv_filetypes(),
|
||||
);
|
||||
$import = $_FILES['import']; // WPCS: sanitization ok, input var ok.
|
||||
$import = $_FILES['import']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
$upload = wp_handle_upload( $import, $overrides );
|
||||
|
||||
if ( isset( $upload['error'] ) ) {
|
||||
|
@ -577,14 +578,15 @@ class WC_Product_CSV_Importer_Controller {
|
|||
|
||||
$headers = array();
|
||||
foreach ( $raw_headers as $key => $field ) {
|
||||
$field = strtolower( $field );
|
||||
$normalized_field = strtolower( $field );
|
||||
$index = $num_indexes ? $key : $field;
|
||||
$headers[ $index ] = $field;
|
||||
$headers[ $index ] = $normalized_field;
|
||||
|
||||
if ( isset( $default_columns[ $field ] ) ) {
|
||||
$headers[ $index ] = $default_columns[ $field ];
|
||||
if ( isset( $default_columns[ $normalized_field ] ) ) {
|
||||
$headers[ $index ] = $default_columns[ $normalized_field ];
|
||||
} else {
|
||||
foreach ( $special_columns as $regex => $special_key ) {
|
||||
// Don't use the normalized field in the regex since meta might be case-sensitive.
|
||||
if ( preg_match( $regex, $field, $matches ) ) {
|
||||
$headers[ $index ] = $special_key . $matches[1];
|
||||
break;
|
||||
|
@ -619,7 +621,7 @@ class WC_Product_CSV_Importer_Controller {
|
|||
* @return string
|
||||
*/
|
||||
protected function sanitize_special_column_name_regex( $value ) {
|
||||
return '/' . str_replace( array( '%d', '%s' ), '(.*)', trim( quotemeta( $value ) ) ) . '/';
|
||||
return '/' . str_replace( array( '%d', '%s' ), '(.*)', trim( quotemeta( $value ) ) ) . '/i';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,12 +48,22 @@ class WC_Notes_Run_Db_Update {
|
|||
} catch ( Exception $e ) {
|
||||
return;
|
||||
}
|
||||
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
|
||||
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
|
||||
|
||||
if ( empty( $note_ids ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( count( $note_ids ) > 1 ) {
|
||||
// Remove weird duplicates. Leave the first one.
|
||||
$current_notice = array_shift( $note_ids );
|
||||
foreach ( $note_ids as $note_id ) {
|
||||
$note = new WC_Admin_Note( $note_id );
|
||||
$data_store->delete( $note );
|
||||
}
|
||||
return $current_notice;
|
||||
}
|
||||
|
||||
return current( $note_ids );
|
||||
}
|
||||
|
||||
|
@ -79,14 +89,15 @@ class WC_Notes_Run_Db_Update {
|
|||
* - actions are set up for the first 'Update database' notice, and
|
||||
* - URL for note's action is equal to the given URL (to check for potential nonce update).
|
||||
*
|
||||
* @param WC_Admin_Note $note Note to check.
|
||||
* @param string $update_url URL to check the note against.
|
||||
* @param WC_Admin_Note $note Note to check.
|
||||
* @param string $update_url URL to check the note against.
|
||||
* @param array( string ) $current_actions List of actions to check for.
|
||||
* @return bool
|
||||
*/
|
||||
private static function note_up_to_date( $note, $update_url ) {
|
||||
private static function note_up_to_date( $note, $update_url, $current_actions ) {
|
||||
$actions = $note->get_actions();
|
||||
if ( 2 === count( array_intersect( wp_list_pluck( $actions, 'name' ), array( 'update-db_run', 'update-db_learn-more' ) ) )
|
||||
&& in_array( $update_url, wp_list_pluck( $actions, 'query' ) ) ) {
|
||||
if ( count( $current_actions ) === count( array_intersect( wp_list_pluck( $actions, 'name' ), $current_actions ) )
|
||||
&& in_array( $update_url, wp_list_pluck( $actions, 'query' ), true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -110,6 +121,23 @@ class WC_Notes_Run_Db_Update {
|
|||
)
|
||||
);
|
||||
|
||||
$note_actions = array(
|
||||
array(
|
||||
'name' => 'update-db_run',
|
||||
'label' => __( 'Update WooCommerce Database', 'woocommerce' ),
|
||||
'url' => $update_url,
|
||||
'status' => 'unactioned',
|
||||
'primary' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'update-db_learn-more',
|
||||
'label' => __( 'Learn more about updates', 'woocommerce' ),
|
||||
'url' => 'https://docs.woocommerce.com/document/how-to-update-woocommerce/',
|
||||
'status' => 'unactioned',
|
||||
'primary' => false,
|
||||
),
|
||||
);
|
||||
|
||||
if ( $note_id ) {
|
||||
$note = new WC_Admin_Note( $note_id );
|
||||
} else {
|
||||
|
@ -117,7 +145,7 @@ class WC_Notes_Run_Db_Update {
|
|||
}
|
||||
|
||||
// Check if the note needs to be updated (e.g. expired nonce or different note type stored in the previous run).
|
||||
if ( self::note_up_to_date( $note, $update_url ) ) {
|
||||
if ( self::note_up_to_date( $note, $update_url, wp_list_pluck( $note_actions, 'name' ) ) ) {
|
||||
return $note_id;
|
||||
}
|
||||
|
||||
|
@ -138,20 +166,9 @@ class WC_Notes_Run_Db_Update {
|
|||
|
||||
// Set new actions.
|
||||
$note->clear_actions();
|
||||
$note->add_action(
|
||||
'update-db_run',
|
||||
__( 'Update WooCommerce Database', 'woocommerce' ),
|
||||
$update_url,
|
||||
'unactioned',
|
||||
true
|
||||
);
|
||||
$note->add_action(
|
||||
'update-db_learn-more',
|
||||
__( 'Learn more about updates', 'woocommerce' ),
|
||||
'https://docs.woocommerce.com/document/how-to-update-woocommerce/',
|
||||
'unactioned',
|
||||
false
|
||||
);
|
||||
foreach ( $note_actions as $note_action ) {
|
||||
$note->add_action( ...array_values( $note_action ) );
|
||||
}
|
||||
|
||||
return $note->save();
|
||||
}
|
||||
|
@ -164,7 +181,7 @@ class WC_Notes_Run_Db_Update {
|
|||
* @param int $note_id Note id to update.
|
||||
*/
|
||||
private static function update_in_progress_notice( $note_id ) {
|
||||
// Same actions as in includes/admin/views/html-notice-updating.php.
|
||||
// Same actions as in includes/admin/views/html-notice-updating.php. This just redirects, performs no action, so without nonce.
|
||||
$pending_actions_url = admin_url( 'admin.php?page=wc-status&tab=action-scheduler&s=woocommerce_run_update&status=pending' );
|
||||
$cron_disabled = Constants::is_true( 'DISABLE_WP_CRON' );
|
||||
$cron_cta = $cron_disabled ? __( 'You can manually run queued updates here.', 'woocommerce' ) : __( 'View progress →', 'woocommerce' );
|
||||
|
@ -205,89 +222,81 @@ class WC_Notes_Run_Db_Update {
|
|||
)
|
||||
);
|
||||
|
||||
$note_actions = array(
|
||||
array(
|
||||
'name' => 'update-db_done',
|
||||
'label' => __( 'Thanks!', 'woocommerce' ),
|
||||
'url' => $hide_notices_url,
|
||||
'status' => 'actioned',
|
||||
'primary' => true,
|
||||
),
|
||||
);
|
||||
|
||||
$note = new WC_Admin_Note( $note_id );
|
||||
|
||||
// Check if the note needs to be updated (e.g. expired nonce or different note type stored in the previous run).
|
||||
if ( self::note_up_to_date( $note, $hide_notices_url, wp_list_pluck( $note_actions, 'name' ) ) ) {
|
||||
return $note_id;
|
||||
}
|
||||
|
||||
$note->set_title( __( 'WooCommerce database update done', 'woocommerce' ) );
|
||||
$note->set_content( __( 'WooCommerce database update complete. Thank you for updating to the latest version!', 'woocommerce' ) );
|
||||
|
||||
$actions = $note->get_actions();
|
||||
if ( ! in_array( 'update-db_done', wp_list_pluck( $actions, 'name' ) ) ) {
|
||||
$note->clear_actions();
|
||||
$note->add_action(
|
||||
'update-db_done',
|
||||
__( 'Thanks!', 'woocommerce' ),
|
||||
$hide_notices_url,
|
||||
'actioned',
|
||||
true
|
||||
);
|
||||
|
||||
$note->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if db update notice should be shown, false otherwise.
|
||||
*
|
||||
* If the db needs an update, the notice should be always shown.
|
||||
* If the db does not need an update, but the notice has *not* been actioned (i.e. after the db update, when
|
||||
* store owner hasn't acknowledged the successful db update), still show the notice.
|
||||
* If the db does not need an update, and the notice has been actioned, then notice should *not* be shown.
|
||||
* The same is true if the db does not need an update and the notice does not exist.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function should_show_notice() {
|
||||
if ( ! \WC_Install::needs_db_update() ) {
|
||||
try {
|
||||
$data_store = \WC_Data_Store::load( 'admin-note' );
|
||||
} catch ( Exception $e ) {
|
||||
// Bail out in case of incorrect use.
|
||||
return false;
|
||||
}
|
||||
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
|
||||
|
||||
if ( ! empty( $note_ids ) ) {
|
||||
// Db update not needed && note actioned -> don't show it.
|
||||
$note = new WC_Admin_Note( $note_ids[0] );
|
||||
if ( $note::E_WC_ADMIN_NOTE_ACTIONED === $note->get_status() ) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Db update not needed && note does not exist -> don't show it.
|
||||
return false;
|
||||
}
|
||||
$note->clear_actions();
|
||||
foreach ( $note_actions as $note_action ) {
|
||||
$note->add_action( ...array_values( $note_action ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
$note->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the correct content of the db update note to be displayed by WC Admin.
|
||||
*
|
||||
* This one gets called on each page load, so try to bail quickly.
|
||||
*
|
||||
* If the db needs an update, the notice should be always shown.
|
||||
* If the db does not need an update, but the notice has *not* been actioned (i.e. after the db update, when
|
||||
* store owner hasn't acknowledged the successful db update), still show the Thanks notice.
|
||||
* If the db does not need an update, and the notice has been actioned, then notice should *not* be shown.
|
||||
* The notice should also be hidden if the db does not need an update and the notice does not exist.
|
||||
*/
|
||||
public static function show_reminder() {
|
||||
if ( ! self::should_show_notice() ) {
|
||||
return;
|
||||
}
|
||||
$needs_db_update = \WC_Install::needs_db_update();
|
||||
|
||||
$note_id = self::get_current_notice();
|
||||
if ( ! $needs_db_update ) {
|
||||
// Db update not needed && note does not exist -> don't show it.
|
||||
if ( ! $note_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( \WC_Install::needs_db_update() && empty( $note_id ) ) {
|
||||
// Db needs update && no notice exists -> create one.
|
||||
$note_id = self::update_needed_notice();
|
||||
}
|
||||
|
||||
if ( \WC_Install::needs_db_update() ) {
|
||||
$next_scheduled_date = WC()->queue()->get_next( 'woocommerce_run_update_callback', null, 'woocommerce-db-updates' );
|
||||
|
||||
if ( $next_scheduled_date || ! empty( $_GET['do_update_woocommerce'] ) ) { // WPCS: input var ok, CSRF ok.
|
||||
self::update_in_progress_notice( $note_id );
|
||||
$note = new WC_Admin_Note( $note_id );
|
||||
if ( $note::E_WC_ADMIN_NOTE_ACTIONED === $note->get_status() ) {
|
||||
// Db update not needed && note actioned -> don't show it.
|
||||
return;
|
||||
} else {
|
||||
self::update_needed_notice( $note_id );
|
||||
// Db update not needed && notice is unactioned -> Thank you note.
|
||||
\WC_Install::update_db_version();
|
||||
self::update_done_notice( $note_id );
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
\WC_Install::update_db_version();
|
||||
self::update_done_notice( $note_id );
|
||||
// Db needs update &&.
|
||||
if ( ! $note_id ) {
|
||||
// Db needs update && no notice exists -> create one that shows Nudge to update.
|
||||
$note_id = self::update_needed_notice();
|
||||
}
|
||||
|
||||
$next_scheduled_date = WC()->queue()->get_next( 'woocommerce_run_update_callback', null, 'woocommerce-db-updates' );
|
||||
|
||||
if ( $next_scheduled_date || ! empty( $_GET['do_update_woocommerce'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
// Db needs update && db update is scheduled -> update note to In progress.
|
||||
self::update_in_progress_notice( $note_id );
|
||||
} else {
|
||||
// Db needs update && db update is not scheduled -> Nudge to run the db update.
|
||||
self::update_needed_notice( $note_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ class WC_Settings_Emails extends WC_Settings_Page {
|
|||
array(
|
||||
'title' => __( 'Footer text', 'woocommerce' ),
|
||||
/* translators: %s: Available placeholders for use */
|
||||
'desc' => __( 'The text to appear in the footer of all WooCommerce emails.', 'woocommerce' ) . ' ' . sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '{site_title} {site_address}' ),
|
||||
'desc' => __( 'The text to appear in the footer of all WooCommerce emails.', 'woocommerce' ) . ' ' . sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '{site_title} {site_url}' ),
|
||||
'id' => 'woocommerce_email_footer_text',
|
||||
'css' => 'width:400px; height: 75px;',
|
||||
'placeholder' => __( 'N/A', 'woocommerce' ),
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin View: Notice - Uploads directory is unprotected.
|
||||
*
|
||||
* @package WooCommerce\Admin\Notices
|
||||
* @since 4.2.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$uploads = wp_get_upload_dir();
|
||||
|
||||
?>
|
||||
<div id="message" class="error woocommerce-message">
|
||||
<a class="woocommerce-message-close notice-dismiss" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc-hide-notice', 'uploads_directory_is_public' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>"><?php esc_html_e( 'Dismiss', 'woocommerce' ); ?></a>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses_post(
|
||||
sprintf(
|
||||
/* translators: 1: uploads directory URL 2: documentation URL */
|
||||
__( 'Your store\'s uploads directory is <a href="%1$s">browsable via the web</a>. We strongly recommend <a href="%2$s">configuring your web server to prevent directory indexing</a>.', 'woocommerce' ),
|
||||
esc_url( $uploads['baseurl'] . '/woocommerce_uploads' ),
|
||||
'https://docs.woocommerce.com/document/digital-downloadable-product-handling/#protecting-your-uploads-directory'
|
||||
)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
|
@ -137,7 +137,7 @@ function wc_create_page( $slug, $option = '', $page_title = '', $page_content =
|
|||
/**
|
||||
* Output admin fields.
|
||||
*
|
||||
* Loops though the woocommerce options array and outputs each field.
|
||||
* Loops through the woocommerce options array and outputs each field.
|
||||
*
|
||||
* @param array $options Opens array to output.
|
||||
*/
|
||||
|
|
|
@ -748,14 +748,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 ] ), array( 'id' => $key ) );
|
||||
$errors->add( $key . '_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>' ), array( 'id' => $key ) );
|
||||
$errors->add( $key . '_validation', sprintf( __( '%s is not a valid phone number.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ), array( 'id' => $key ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -765,7 +765,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>' ), array( 'id' => $key ) );
|
||||
$errors->add( $key . '_validation', sprintf( __( '%s is not a valid email address.', 'woocommerce' ), '<strong>' . esc_html( $field_label ) . '</strong>' ), array( 'id' => $key ) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -785,14 +785,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 ) ), array( 'id' => $key ) );
|
||||
$errors->add( $key . '_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 ), array( 'id' => $key ) );
|
||||
$errors->add( $key . '_required', 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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -910,6 +910,7 @@ class WC_Countries {
|
|||
),
|
||||
'state' => array(
|
||||
'required' => false,
|
||||
'hidden' => true,
|
||||
),
|
||||
),
|
||||
'DK' => array(
|
||||
|
@ -918,6 +919,7 @@ class WC_Countries {
|
|||
),
|
||||
'state' => array(
|
||||
'required' => false,
|
||||
'hidden' => true,
|
||||
),
|
||||
),
|
||||
'EE' => array(
|
||||
|
@ -944,6 +946,14 @@ class WC_Countries {
|
|||
'required' => false,
|
||||
),
|
||||
),
|
||||
'GH' => array(
|
||||
'postcode' => array(
|
||||
'required' => false,
|
||||
),
|
||||
'state' => array(
|
||||
'label' => __( 'Region', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'GP' => array(
|
||||
'state' => array(
|
||||
'required' => false,
|
||||
|
@ -1229,6 +1239,7 @@ class WC_Countries {
|
|||
),
|
||||
'state' => array(
|
||||
'required' => false,
|
||||
'hidden' => true,
|
||||
),
|
||||
),
|
||||
'TR' => array(
|
||||
|
|
|
@ -290,12 +290,14 @@ class WC_Emails {
|
|||
array(
|
||||
'{site_title}',
|
||||
'{site_address}',
|
||||
'{site_url}',
|
||||
'{woocommerce}',
|
||||
'{WooCommerce}',
|
||||
),
|
||||
array(
|
||||
$this->get_blogname(),
|
||||
$domain,
|
||||
$domain,
|
||||
'<a href="https://woocommerce.com">WooCommerce</a>',
|
||||
'<a href="https://woocommerce.com">WooCommerce</a>',
|
||||
),
|
||||
|
|
|
@ -459,6 +459,10 @@ class WC_Form_Handler {
|
|||
return;
|
||||
}
|
||||
|
||||
if ( ! apply_filters( 'woocommerce_add_payment_method_form_is_valid', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Test rate limit.
|
||||
$current_user_id = get_current_user_id();
|
||||
$rate_limit_id = 'add_payment_method_' . $current_user_id;
|
||||
|
@ -466,12 +470,15 @@ class WC_Form_Handler {
|
|||
|
||||
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'
|
||||
sprintf(
|
||||
/* 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'
|
||||
),
|
||||
$delay
|
||||
),
|
||||
'error'
|
||||
);
|
||||
|
|
|
@ -419,6 +419,19 @@ class WC_Order extends WC_Abstract_Order {
|
|||
|
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get basic order data in array format.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_base_data() {
|
||||
return array_merge(
|
||||
array( 'id' => $this->get_id() ),
|
||||
$this->data,
|
||||
array( 'number' => $this->get_order_number() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all class data in array format.
|
||||
*
|
||||
|
@ -427,12 +440,8 @@ class WC_Order extends WC_Abstract_Order {
|
|||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
$this->get_base_data(),
|
||||
array(
|
||||
'id' => $this->get_id(),
|
||||
),
|
||||
$this->data,
|
||||
array(
|
||||
'number' => $this->get_order_number(),
|
||||
'meta_data' => $this->get_meta_data(),
|
||||
'line_items' => $this->get_items( 'line_item' ),
|
||||
'tax_lines' => $this->get_items( 'tax' ),
|
||||
|
|
|
@ -27,10 +27,11 @@ class WC_Privacy_Exporters {
|
|||
$customer_personal_data = self::get_customer_personal_data( $user );
|
||||
if ( ! empty( $customer_personal_data ) ) {
|
||||
$data_to_export[] = array(
|
||||
'group_id' => 'woocommerce_customer',
|
||||
'group_label' => __( 'Customer Data', 'woocommerce' ),
|
||||
'item_id' => 'user',
|
||||
'data' => $customer_personal_data,
|
||||
'group_id' => 'woocommerce_customer',
|
||||
'group_label' => __( 'Customer Data', 'woocommerce' ),
|
||||
'group_description' => __( 'User’s WooCommerce customer data.', 'woocommerce' ),
|
||||
'item_id' => 'user',
|
||||
'data' => $customer_personal_data,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -71,10 +72,11 @@ class WC_Privacy_Exporters {
|
|||
if ( 0 < count( $orders ) ) {
|
||||
foreach ( $orders as $order ) {
|
||||
$data_to_export[] = array(
|
||||
'group_id' => 'woocommerce_orders',
|
||||
'group_label' => __( 'Orders', 'woocommerce' ),
|
||||
'item_id' => 'order-' . $order->get_id(),
|
||||
'data' => self::get_order_personal_data( $order ),
|
||||
'group_id' => 'woocommerce_orders',
|
||||
'group_label' => __( 'Orders', 'woocommerce' ),
|
||||
'group_description' => __( 'User’s WooCommerce orders data.', 'woocommerce' ),
|
||||
'item_id' => 'order-' . $order->get_id(),
|
||||
'data' => self::get_order_personal_data( $order ),
|
||||
);
|
||||
}
|
||||
$done = 10 > count( $orders );
|
||||
|
@ -118,22 +120,24 @@ class WC_Privacy_Exporters {
|
|||
if ( 0 < count( $downloads ) ) {
|
||||
foreach ( $downloads as $download ) {
|
||||
$data_to_export[] = array(
|
||||
'group_id' => 'woocommerce_downloads',
|
||||
'group_id' => 'woocommerce_downloads',
|
||||
/* translators: This is the headline for a list of downloads purchased from the store for a given user. */
|
||||
'group_label' => __( 'Purchased Downloads', 'woocommerce' ),
|
||||
'item_id' => 'download-' . $download->get_id(),
|
||||
'data' => self::get_download_personal_data( $download ),
|
||||
'group_label' => __( 'Purchased Downloads', 'woocommerce' ),
|
||||
'group_description' => __( 'User’s WooCommerce purchased downloads data.', 'woocommerce' ),
|
||||
'item_id' => 'download-' . $download->get_id(),
|
||||
'data' => self::get_download_personal_data( $download ),
|
||||
);
|
||||
|
||||
$download_logs = $customer_download_log_data_store->get_download_logs_for_permission( $download->get_id() );
|
||||
|
||||
foreach ( $download_logs as $download_log ) {
|
||||
$data_to_export[] = array(
|
||||
'group_id' => 'woocommerce_download_logs',
|
||||
'group_id' => 'woocommerce_download_logs',
|
||||
/* translators: This is the headline for a list of access logs for downloads purchased from the store for a given user. */
|
||||
'group_label' => __( 'Access to Purchased Downloads', 'woocommerce' ),
|
||||
'item_id' => 'download-log-' . $download_log->get_id(),
|
||||
'data' => array(
|
||||
'group_label' => __( 'Access to Purchased Downloads', 'woocommerce' ),
|
||||
'group_description' => __( 'User’s WooCommerce access to purchased downloads data.', 'woocommerce' ),
|
||||
'item_id' => 'download-log-' . $download_log->get_id(),
|
||||
'data' => array(
|
||||
array(
|
||||
'name' => __( 'Download ID', 'woocommerce' ),
|
||||
'value' => $download_log->get_permission_id(),
|
||||
|
@ -413,10 +417,11 @@ class WC_Privacy_Exporters {
|
|||
if ( 0 < count( $tokens ) ) {
|
||||
foreach ( $tokens as $token ) {
|
||||
$data_to_export[] = array(
|
||||
'group_id' => 'woocommerce_tokens',
|
||||
'group_label' => __( 'Payment Tokens', 'woocommerce' ),
|
||||
'item_id' => 'token-' . $token->get_id(),
|
||||
'data' => array(
|
||||
'group_id' => 'woocommerce_tokens',
|
||||
'group_label' => __( 'Payment Tokens', 'woocommerce' ),
|
||||
'group_description' => __( 'User’s WooCommerce payment tokens data.', 'woocommerce' ),
|
||||
'item_id' => 'token-' . $token->get_id(),
|
||||
'data' => array(
|
||||
array(
|
||||
'name' => __( 'Token', 'woocommerce' ),
|
||||
'value' => $token->get_display_name(),
|
||||
|
|
|
@ -66,12 +66,10 @@ class WC_Privacy extends WC_Abstract_Privacy {
|
|||
* @since 3.4.0
|
||||
*/
|
||||
public function get_privacy_message() {
|
||||
$content = '
|
||||
<div contenteditable="false">' .
|
||||
'<p class="wp-policy-help">' .
|
||||
__( 'This sample language includes the basics around what personal data your store may be collecting, storing and sharing, as well as who may have access to that data. Depending on what settings are enabled and which additional plugins are used, the specific information shared by your store will vary. We recommend consulting with a lawyer when deciding what information to disclose on your privacy policy.', 'woocommerce' ) .
|
||||
'</p>' .
|
||||
'</div>' .
|
||||
$content = '<div class="wp-suggested-text">' .
|
||||
'<p class="privacy-policy-tutorial">' .
|
||||
__( 'This sample language includes the basics around what personal data your store may be collecting, storing and sharing, as well as who may have access to that data. Depending on what settings are enabled and which additional plugins are used, the specific information shared by your store will vary. We recommend consulting with a lawyer when deciding what information to disclose on your privacy policy.', 'woocommerce' ) .
|
||||
'</p>' .
|
||||
'<p>' . __( 'We collect information about you during the checkout process on our store.', 'woocommerce' ) . '</p>' .
|
||||
'<h2>' . __( 'What we collect and store', 'woocommerce' ) . '</h2>' .
|
||||
'<p>' . __( 'While you visit our site, we’ll track:', 'woocommerce' ) . '</p>' .
|
||||
|
@ -81,9 +79,9 @@ class WC_Privacy extends WC_Abstract_Privacy {
|
|||
'<li>' . __( 'Shipping address: we’ll ask you to enter this so we can, for instance, estimate shipping before you place an order, and send you the order!', 'woocommerce' ) . '</li>' .
|
||||
'</ul>' .
|
||||
'<p>' . __( 'We’ll also use cookies to keep track of cart contents while you’re browsing our site.', 'woocommerce' ) . '</p>' .
|
||||
'<div contenteditable="false">' .
|
||||
'<p class="wp-policy-help">' . __( 'Note: you may want to further detail your cookie policy, and link to that section from here.', 'woocommerce' ) . '</p>' .
|
||||
'</div>' .
|
||||
'<p class="privacy-policy-tutorial">' .
|
||||
__( 'Note: you may want to further detail your cookie policy, and link to that section from here.', 'woocommerce' ) .
|
||||
'</p>' .
|
||||
'<p>' . __( 'When you purchase from us, we’ll ask you to provide information including your name, billing address, shipping address, email address, phone number, credit card/payment details and optional account information like username and password. We’ll use this information for purposes, such as, to:', 'woocommerce' ) . '</p>' .
|
||||
'<ul>' .
|
||||
'<li>' . __( 'Send you information about your account and order', 'woocommerce' ) . '</li>' .
|
||||
|
@ -105,16 +103,17 @@ class WC_Privacy extends WC_Abstract_Privacy {
|
|||
'</ul>' .
|
||||
'<p>' . __( 'Our team members have access to this information to help fulfill orders, process refunds and support you.', 'woocommerce' ) . '</p>' .
|
||||
'<h2>' . __( 'What we share with others', 'woocommerce' ) . '</h2>' .
|
||||
'<div contenteditable="false">' .
|
||||
'<p class="wp-policy-help">' . __( 'In this section you should list who you’re sharing data with, and for what purpose. This could include, but may not be limited to, analytics, marketing, payment gateways, shipping providers, and third party embeds.', 'woocommerce' ) . '</p>' .
|
||||
'</div>' .
|
||||
'<p class="privacy-policy-tutorial">' .
|
||||
__( 'In this section you should list who you’re sharing data with, and for what purpose. This could include, but may not be limited to, analytics, marketing, payment gateways, shipping providers, and third party embeds.', 'woocommerce' ) .
|
||||
'</p>' .
|
||||
'<p>' . __( 'We share information with third parties who help us provide our orders and store services to you; for example --', 'woocommerce' ) . '</p>' .
|
||||
'<h3>' . __( 'Payments', 'woocommerce' ) . '</h3>' .
|
||||
'<div contenteditable="false">' .
|
||||
'<p class="wp-policy-help">' . __( 'In this subsection you should list which third party payment processors you’re using to take payments on your store since these may handle customer data. We’ve included PayPal as an example, but you should remove this if you’re not using PayPal.', 'woocommerce' ) . '</p>' .
|
||||
'</div>' .
|
||||
'<p class="privacy-policy-tutorial">' .
|
||||
__( 'In this subsection you should list which third party payment processors you’re using to take payments on your store since these may handle customer data. We’ve included PayPal as an example, but you should remove this if you’re not using PayPal.', 'woocommerce' ) .
|
||||
'</p>' .
|
||||
'<p>' . __( 'We accept payments through PayPal. When processing payments, some of your data will be passed to PayPal, including information required to process or support the payment, such as the purchase total and billing information.', 'woocommerce' ) . '</p>' .
|
||||
'<p>' . __( 'Please see the <a href="https://www.paypal.com/us/webapps/mpp/ua/privacy-full">PayPal Privacy Policy</a> for more details.', 'woocommerce' ) . '</p>';
|
||||
'<p>' . __( 'Please see the <a href="https://www.paypal.com/us/webapps/mpp/ua/privacy-full">PayPal Privacy Policy</a> for more details.', 'woocommerce' ) . '</p>' .
|
||||
'</div>';
|
||||
|
||||
return apply_filters( 'wc_privacy_policy_content', $content );
|
||||
}
|
||||
|
|
|
@ -495,7 +495,7 @@ class WC_Tax {
|
|||
);
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_matched_rates', $matched_tax_rates, $tax_class );
|
||||
return apply_filters( 'woocommerce_matched_rates', $matched_tax_rates, $tax_class, $customer );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,7 +20,7 @@ final class WooCommerce {
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
public $version = '4.1.0';
|
||||
public $version = '4.3.0';
|
||||
|
||||
/**
|
||||
* The single instance of the class.
|
||||
|
|
|
@ -69,7 +69,9 @@ class WC_Coupon_Data_Store_CPT extends WC_Data_Store_WP implements WC_Coupon_Dat
|
|||
* @param WC_Coupon $coupon Coupon object.
|
||||
*/
|
||||
public function create( &$coupon ) {
|
||||
$coupon->set_date_created( time() );
|
||||
if ( ! $coupon->get_date_created( 'edit' ) ) {
|
||||
$coupon->set_date_created( time() );
|
||||
}
|
||||
|
||||
$coupon_id = wp_insert_post(
|
||||
apply_filters(
|
||||
|
|
|
@ -282,7 +282,7 @@ class WC_Shipping_Zone_Data_Store extends WC_Data_Store_WP implements WC_Shippin
|
|||
"SELECT zones.zone_id FROM {$wpdb->prefix}woocommerce_shipping_zones as zones
|
||||
LEFT OUTER JOIN {$wpdb->prefix}woocommerce_shipping_zone_locations as locations ON zones.zone_id = locations.zone_id AND location_type != 'postcode'
|
||||
WHERE " . implode( ' ', $criteria ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
. ' ORDER BY zone_order ASC, zone_id ASC LIMIT 1'
|
||||
. ' ORDER BY zone_order ASC, zones.zone_id ASC LIMIT 1'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ if ( ! class_exists( 'WC_Email_Customer_Invoice', false ) ) :
|
|||
* @return string
|
||||
*/
|
||||
public function get_default_additional_content() {
|
||||
return __( 'Thanks for using {site_address}!', 'woocommerce' );
|
||||
return __( 'Thanks for using {site_url}!', 'woocommerce' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -141,7 +141,7 @@ if ( ! class_exists( 'WC_Email_Customer_Processing_Order', false ) ) :
|
|||
* @return string
|
||||
*/
|
||||
public function get_default_additional_content() {
|
||||
return __( 'Thanks for using {site_address}!', 'woocommerce' );
|
||||
return __( 'Thanks for using {site_url}!', 'woocommerce' );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -233,6 +233,7 @@ class WC_Email extends WC_Settings_API {
|
|||
array(
|
||||
'{site_title}' => $this->get_blogname(),
|
||||
'{site_address}' => wp_parse_url( home_url(), PHP_URL_HOST ),
|
||||
'{site_url}' => wp_parse_url( home_url(), PHP_URL_HOST ),
|
||||
),
|
||||
$this->placeholders
|
||||
);
|
||||
|
|
|
@ -21,6 +21,31 @@ class WC_Orders_Tracking {
|
|||
// WC_Meta_Box_Order_Actions::save() hooks in at priority 50.
|
||||
add_action( 'woocommerce_process_shop_order_meta', array( $this, 'track_order_action' ), 51 );
|
||||
add_action( 'load-post-new.php', array( $this, 'track_add_order_from_edit' ), 10 );
|
||||
add_filter( 'woocommerce_shop_order_search_results', array( $this, 'track_order_search' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a track event when on the Order Listing page, and search results are being displayed.
|
||||
*
|
||||
* @param array $order_ids Array of order_ids that are matches for the search.
|
||||
* @param string $term The string that was used in the search.
|
||||
* @param array $search_fields Fields that were used in the original search.
|
||||
*/
|
||||
public function track_order_search( $order_ids, $term, $search_fields ) {
|
||||
// Since `woocommerce_shop_order_search_results` can run in the front-end context, exit if get_current_screen isn't defined.
|
||||
if ( ! function_exists( 'get_current_screen' ) ) {
|
||||
return $order_ids;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
// We only want to record this track when the filter is executed on the order listing page.
|
||||
if ( 'edit-shop_order' === $screen->id ) {
|
||||
// we are on the order listing page, and query results are being shown.
|
||||
WC_Tracks::record_event( 'orders_view_search' );
|
||||
}
|
||||
|
||||
return $order_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,12 +17,88 @@ class WC_Products_Tracking {
|
|||
* Init tracking.
|
||||
*/
|
||||
public function init() {
|
||||
add_action( 'load-edit.php', array( $this, 'track_products_view' ), 10 );
|
||||
add_action( 'load-edit-tags.php', array( $this, 'track_categories_and_tags_view' ), 10, 2 );
|
||||
add_action( 'edit_post', array( $this, 'track_product_updated' ), 10, 2 );
|
||||
add_action( 'transition_post_status', array( $this, 'track_product_published' ), 10, 3 );
|
||||
add_action( 'created_product_cat', array( $this, 'track_product_category_created' ) );
|
||||
add_action( 'add_meta_boxes_product', array( $this, 'track_product_updated_client_side' ), 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a Tracks event when the Products page is viewed.
|
||||
*/
|
||||
public function track_products_view() {
|
||||
// We only record Tracks event when no `_wp_http_referer` query arg is set, since
|
||||
// when searching, the request gets sent from the browser twice,
|
||||
// once with the `_wp_http_referer` and once without it.
|
||||
//
|
||||
// Otherwise, we would double-record the view and search events.
|
||||
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
|
||||
if (
|
||||
isset( $_GET['post_type'] )
|
||||
&& 'product' === wp_unslash( $_GET['post_type'] )
|
||||
&& ! isset( $_GET['_wp_http_referer'] )
|
||||
) {
|
||||
// phpcs:enable
|
||||
|
||||
WC_Tracks::record_event( 'products_view' );
|
||||
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
|
||||
if (
|
||||
isset( $_GET['s'] )
|
||||
&& 0 < strlen( sanitize_text_field( wp_unslash( $_GET['s'] ) ) )
|
||||
) {
|
||||
// phpcs:enable
|
||||
|
||||
WC_Tracks::record_event( 'products_search' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a Tracks event when the Products Categories and Tags page is viewed.
|
||||
*/
|
||||
public function track_categories_and_tags_view() {
|
||||
// We only record Tracks event when no `_wp_http_referer` query arg is set, since
|
||||
// when searching, the request gets sent from the browser twice,
|
||||
// once with the `_wp_http_referer` and once without it.
|
||||
//
|
||||
// Otherwise, we would double-record the view and search events.
|
||||
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
|
||||
if (
|
||||
isset( $_GET['post_type'] )
|
||||
&& 'product' === wp_unslash( $_GET['post_type'] )
|
||||
&& isset( $_GET['taxonomy'] )
|
||||
&& ! isset( $_GET['_wp_http_referer'] )
|
||||
) {
|
||||
$taxonomy = wp_unslash( $_GET['taxonomy'] );
|
||||
// phpcs:enable
|
||||
|
||||
if ( 'product_cat' === $taxonomy ) {
|
||||
WC_Tracks::record_event( 'categories_view' );
|
||||
} elseif ( 'product_tag' === $taxonomy ) {
|
||||
WC_Tracks::record_event( 'tags_view' );
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
|
||||
if (
|
||||
isset( $_GET['s'] )
|
||||
&& 0 < strlen( sanitize_text_field( wp_unslash( $_GET['s'] ) ) )
|
||||
) {
|
||||
// phpcs:enable
|
||||
|
||||
if ( 'product_cat' === $taxonomy ) {
|
||||
WC_Tracks::record_event( 'categories_search' );
|
||||
} elseif ( 'product_tag' === $taxonomy ) {
|
||||
WC_Tracks::record_event( 'tags_search' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a Tracks event when a product is updated.
|
||||
*
|
||||
|
|
|
@ -185,9 +185,9 @@ function wc_attribute_taxonomy_id_by_name( $name ) {
|
|||
*/
|
||||
function wc_attribute_label( $name, $product = '' ) {
|
||||
if ( taxonomy_is_product_attribute( $name ) ) {
|
||||
$name = wc_attribute_taxonomy_slug( $name );
|
||||
$slug = wc_attribute_taxonomy_slug( $name );
|
||||
$all_labels = wc_get_attribute_taxonomy_labels();
|
||||
$label = isset( $all_labels[ $name ] ) ? $all_labels[ $name ] : $name;
|
||||
$label = isset( $all_labels[ $slug ] ) ? $all_labels[ $slug ] : $slug;
|
||||
} elseif ( $product ) {
|
||||
if ( $product->is_type( 'variation' ) ) {
|
||||
$product = wc_get_product( $product->get_parent_id() );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "woocommerce",
|
||||
"title": "WooCommerce",
|
||||
"version": "4.1.0",
|
||||
"version": "4.3.0",
|
||||
"homepage": "https://woocommerce.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -13,6 +13,7 @@
|
|||
"build": "grunt && npm run makepot",
|
||||
"build-watch": "grunt watch",
|
||||
"build:packages": "node ./tests/e2e/bin/build.js",
|
||||
"build:zip": "./bin/build-zip.sh",
|
||||
"lint:js": "eslint assets/js --ext=js",
|
||||
"docker:up": "npm explore @woocommerce/e2e-environment -- npm run docker:up",
|
||||
"docker:down": "npm explore @woocommerce/e2e-environment -- npm run docker:down",
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
<!-- Exclude paths -->
|
||||
<exclude-pattern>tests/cli/</exclude-pattern>
|
||||
<exclude-pattern>tests/legacy/</exclude-pattern>
|
||||
<exclude-pattern>includes/libraries/</exclude-pattern>
|
||||
<exclude-pattern>includes/legacy/</exclude-pattern>
|
||||
<exclude-pattern>includes/api/legacy/</exclude-pattern>
|
||||
|
@ -59,5 +58,6 @@
|
|||
<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
|
||||
<exclude-pattern>i18n/</exclude-pattern>
|
||||
<exclude-pattern>src/</exclude-pattern>
|
||||
<exclude-pattern>tests/php</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
|
|
@ -22,7 +22,7 @@ global $product;
|
|||
/**
|
||||
* Hook: woocommerce_before_single_product.
|
||||
*
|
||||
* @hooked wc_print_notices - 10
|
||||
* @hooked woocommerce_output_all_notices - 10
|
||||
*/
|
||||
do_action( 'woocommerce_before_single_product' );
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* This is extra customer data which can be filtered by plugins. It outputs below the order item table.
|
||||
*
|
||||
* This template can be overridden by copying it to yourtheme/woocommerce/emails/plain/email-addresses.php.
|
||||
* This template can be overridden by copying it to yourtheme/woocommerce/emails/plain/email-customer-details.php.
|
||||
*
|
||||
* HOWEVER, on occasion WooCommerce will need to update template files and you
|
||||
* (the theme developer) will need to copy the new files to your theme to
|
||||
|
|
|
@ -47,6 +47,8 @@ if ( $available_gateways ) : ?>
|
|||
?>
|
||||
</ul>
|
||||
|
||||
<?php do_action( 'woocommerce_add_payment_method_form_bottom' ); ?>
|
||||
|
||||
<div class="form-row">
|
||||
<?php wp_nonce_field( 'woocommerce-add-payment-method', 'woocommerce-add-payment-method-nonce' ); ?>
|
||||
<button type="submit" class="woocommerce-Button woocommerce-Button--alt button alt" id="place_order" value="<?php esc_attr_e( 'Add payment method', 'woocommerce' ); ?>"><?php esc_html_e( 'Add payment method', 'woocommerce' ); ?></button>
|
||||
|
|
|
@ -76,4 +76,4 @@ Code coverage is available on [Codecov](https://codecov.io/gh/woocommerce/woocom
|
|||
|
||||
## WooCommerce E2E Tests
|
||||
|
||||
See [e2e-tests README](https://github.com/woocommerce/woocommerce/tree/master/tests/e2e-tests) to learn how to setup testing environment for running e2e tests and run them.
|
||||
See [e2e README](https://github.com/woocommerce/woocommerce/tree/master/tests/e2e) to learn how to setup testing environment for running e2e tests and run them.
|
||||
|
|
|
@ -54,7 +54,7 @@ We recommend using Docker for running tests locally in order for the test enviro
|
|||
|
||||
### Environment Variables
|
||||
|
||||
During the process of Docker building a container with test site for running tests, site URL is being set. Admin and customer users are also being created in advance with details specified in the `docker-compose.yaml` file. As a result, there is `./tests/e2e-tests/config/default.json` file that contains pre-set variables needed to run the test:
|
||||
During the process of Docker building a container with test site for running tests, site URL is being set. Admin and customer users are also being created in advance with details specified in the `docker-compose.yaml` file. As a result, there is `./tests/e2e/config/default.json` file that contains pre-set variables needed to run the test:
|
||||
|
||||
```
|
||||
{
|
||||
|
@ -90,6 +90,8 @@ Setup Wizard e2e test (located in `activate-and-setup` directory) will run befor
|
|||
|
||||
- Run `npm install`
|
||||
|
||||
- Run `npm install jest --global`
|
||||
|
||||
- Run `composer install --no-dev`
|
||||
|
||||
- Run `npm run build`
|
||||
|
@ -132,14 +134,14 @@ Tests are being run headless by default. However, sometimes it's useful to obser
|
|||
npm run test:e2e-dev
|
||||
```
|
||||
|
||||
The dev mode also enables SlowMo mode. SlowMo slows down Puppeteer’s operations so we can better see what is happening in the browser. You can adjust the SlowMo value by editing `PUPPETEER_SLOWMO` variable in `./tests/bin/e2e-test-integration.js` file. The default `PUPPETEER_SLOWMO=50` means test actions will be slowed down by 50 milliseconds.
|
||||
The dev mode also enables SlowMo mode. SlowMo slows down Puppeteer’s operations so we can better see what is happening in the browser. You can adjust the SlowMo value by copying `/tests/e2e/env/config/jest.puppetee.config.js` to `/tests/e2e/config` and editing the value in that file. The default `PUPPETEER_SLOWMO=50` means test actions will be slowed down by 50 milliseconds.
|
||||
|
||||
### How to run an individual test
|
||||
|
||||
To run an individual test, use the direct path to the spec. For example:
|
||||
|
||||
```bash
|
||||
npm run test:e2e ./tests/e2e-tests/specs/wp-admin/wp-admin-product-new.test.js
|
||||
npm run test:e2e ./tests/e2e/specs/wp-admin/wp-admin-product-new.test.js
|
||||
```
|
||||
|
||||
### How to skip tests
|
||||
|
@ -159,7 +161,7 @@ it.only( 'Can make sure WooCommerce is activated. If not, activate it', async ()
|
|||
As a result, when you run `setup-wizard.test.js`, only the login and activate tests will run. The rest will be skipped. You should see the following in the terminal:
|
||||
|
||||
```
|
||||
PASS tests/e2e-tests/specs/activate-and-setup/setup-wizard.test.js (11.927s)
|
||||
PASS tests/e2e/specs/activate-and-setup/setup-wizard.test.js (11.927s)
|
||||
Store owner can login and make sure WooCommerce is activated
|
||||
✓ Can login (7189ms)
|
||||
✓ Can make sure WooCommerce is activated. If not, activate it (1187ms)
|
||||
|
@ -196,7 +198,7 @@ We use the following tools to write e2e tests:
|
|||
- [jest-puppeteer](https://github.com/smooth-code/jest-puppeteer) – provides all required configuration to run tests using Puppeteer
|
||||
- [expect-puppeteer](https://github.com/smooth-code/jest-puppeteer/tree/master/packages/expect-puppeteer) – assertion library for Puppeteer
|
||||
|
||||
Tests are kept in `tests/e2e-tests/specs` folder.
|
||||
Tests are kept in `tests/e2e/specs` folder.
|
||||
|
||||
The following packages are being used to write tests:
|
||||
|
||||
|
|
|
@ -160,8 +160,13 @@ version: ~> 1.0
|
|||
....
|
||||
|
||||
script:
|
||||
- npm explore @woocommerce/e2e-environment -- npm run test:e2e-CI
|
||||
- npm install jest --global
|
||||
- npm explore @woocommerce/e2e-environment -- npm run test:e2e
|
||||
|
||||
....
|
||||
|
||||
after_script:
|
||||
- npm explore @woocommerce/e2e-environment -- npm run docker:down
|
||||
```
|
||||
|
||||
Use `[[ ${RUN_E2E} == 1 ]]` in your bash scripts to test for the core e2e test run.
|
||||
|
|
|
@ -46,10 +46,10 @@ else
|
|||
--admin_email=${WORDPRESS_EMAIL} \
|
||||
--skip-email
|
||||
wp post create \
|
||||
--post_type=page \
|
||||
--post_status=publish \
|
||||
--post_title='Ready' \
|
||||
--post_content='E2E-tests.'
|
||||
--post_type=page \
|
||||
--post_status=publish \
|
||||
--post_title='Ready' \
|
||||
--post_content='E2E-tests.'
|
||||
fi
|
||||
|
||||
## Check for an initialization script.
|
||||
|
|
|
@ -69,7 +69,7 @@ const completeOnboardingWizard = async () => {
|
|||
// Wait for usage tracking pop-up window to appear
|
||||
await page.waitForSelector( '.components-modal__header-heading' );
|
||||
await expect( page ).toMatchElement(
|
||||
'.components-modal__header-heading', { text: 'Build a Better WooCommerce' }
|
||||
'.components-modal__header-heading', { text: 'Build a better WooCommerce' }
|
||||
);
|
||||
|
||||
// Query for "Continue" buttons
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?php // phpcs:ignoreFile
|
||||
/**
|
||||
* Plugin Name: Sample WooCommerce PLugin
|
||||
* Woo: 1:sample-woo-plugin
|
||||
*/
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
<?php
|
||||
/**
|
||||
* Class WC_Notes_Run_Db_Update file.
|
||||
*
|
||||
* @package WooCommerce\Tests\Admin\Notes
|
||||
*/
|
||||
|
||||
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Note;
|
||||
|
||||
/**
|
||||
* Tests for the WC_Notes_Run_Db_Update class.
|
||||
*/
|
||||
class WC_Tests_Notes_Run_Db_Update extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Load the necessary files, as they're not automatically loaded by WooCommerce.
|
||||
*
|
||||
*/
|
||||
public static function setUpBeforeClass() {
|
||||
include_once WC_Unit_Tests_Bootstrap::instance()->plugin_dir . '/includes/admin/notes/class-wc-notes-run-db-update.php';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up before each test.
|
||||
*/
|
||||
public function setUp() {
|
||||
if ( ! WC()->is_wc_admin_active() ) {
|
||||
$this->markTestSkipped( 'WC Admin is not active on WP versions < 5.3' );
|
||||
return;
|
||||
}
|
||||
self::remove_db_update_notes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of note ids with name 'wc-update-db-reminder' from the database.
|
||||
*
|
||||
* @return array( int ) List of note ids with name 'wc-update-db-reminder'.
|
||||
*/
|
||||
private static function get_db_update_notes() {
|
||||
$data_store = \WC_Data_Store::load( 'admin-note' );
|
||||
$note_ids = $data_store->get_notes_with_name( WC_Notes_Run_Db_Update::NOTE_NAME );
|
||||
return $note_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the notes with name 'wc-update-db-reminder' from the database.
|
||||
*/
|
||||
private static function remove_db_update_notes() {
|
||||
$data_store = \WC_Data_Store::load( 'admin-note' );
|
||||
$note_ids = $data_store->get_notes_with_name( WC_Notes_Run_Db_Update::NOTE_NAME );
|
||||
foreach ( $note_ids as $note_id ) {
|
||||
$note = new WC_Admin_Note( $note_id );
|
||||
$data_store->delete( $note );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sample note with name 'wc-update-db-reminder'.
|
||||
*
|
||||
* @return int Newly create note's id.
|
||||
*/
|
||||
private static function create_db_update_note() {
|
||||
$update_url = html_entity_decode(
|
||||
wp_nonce_url(
|
||||
add_query_arg( 'do_update_woocommerce', 'true', admin_url( 'admin.php?page=wc-settings' ) ),
|
||||
'wc_db_update',
|
||||
'wc_db_update_nonce'
|
||||
)
|
||||
);
|
||||
|
||||
$note_actions = array(
|
||||
array(
|
||||
'name' => 'update-db_run',
|
||||
'label' => __( 'Update WooCommerce Database', 'woocommerce' ),
|
||||
'url' => $update_url,
|
||||
'status' => 'unactioned',
|
||||
'primary' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'update-db_learn-more',
|
||||
'label' => __( 'Learn more about updates', 'woocommerce' ),
|
||||
'url' => 'https://docs.woocommerce.com/document/how-to-update-woocommerce/',
|
||||
'status' => 'unactioned',
|
||||
'primary' => false,
|
||||
),
|
||||
);
|
||||
|
||||
$note = new WC_Admin_Note();
|
||||
|
||||
$note->set_title( 'WooCommerce database update required' );
|
||||
$note->set_content( 'To keep things running smoothly, we have to update your database to the newest version.' );
|
||||
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_UPDATE );
|
||||
$note->set_icon( 'info' );
|
||||
$note->set_name( WC_Notes_Run_Db_Update::NOTE_NAME );
|
||||
$note->set_content_data( (object) array() );
|
||||
$note->set_source( 'woocommerce-core' );
|
||||
$note->set_status( WC_Admin_Note::E_WC_ADMIN_NOTE_UNACTIONED );
|
||||
|
||||
// Set new actions.
|
||||
$note->clear_actions();
|
||||
foreach ( $note_actions as $note_action ) {
|
||||
$note->add_action( ...array_values( $note_action ) );
|
||||
}
|
||||
|
||||
return $note->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* No note should be created/exist if db version is equal to WC code version.
|
||||
*/
|
||||
public function test_noop_db_update_note() {
|
||||
update_option( 'woocommerce_db_version', WC()->version );
|
||||
|
||||
// No notes initially.
|
||||
$this->assertEquals( 0, count( self::get_db_update_notes() ), 'There should be no db update notes initially.' );
|
||||
|
||||
WC_Notes_Run_Db_Update::show_reminder();
|
||||
|
||||
// No notice should be created.
|
||||
$this->assertEquals( 0, count( self::get_db_update_notes() ), 'There should be no db update notes created if db is up to date.' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note should be created if there is none and WC is updated.
|
||||
*/
|
||||
public function test_create_db_update_note() {
|
||||
// No notes initially.
|
||||
$this->assertEquals( 0, count( self::get_db_update_notes() ), 'There should be no db update notes initially.' );
|
||||
|
||||
// Make it appear as if db version is lower than WC version, i.e. db update is required.
|
||||
update_option( 'woocommerce_db_version', '3.9.0' );
|
||||
|
||||
WC_Notes_Run_Db_Update::show_reminder();
|
||||
|
||||
// A notice should be created.
|
||||
$this->assertEquals( 1, count( self::get_db_update_notes() ), 'A db update note should be created if db is NOT up to date.' );
|
||||
|
||||
// Update the db option back.
|
||||
update_option( 'woocommerce_db_version', WC()->version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Note should be created if there is none and WC is updated.
|
||||
*/
|
||||
public function test_clean_up_multiple_db_update_notes() {
|
||||
// No notes initially.
|
||||
$this->assertEquals( 0, count( self::get_db_update_notes() ), 'There should be no db update notes initially.' );
|
||||
|
||||
$note_1 = self::create_db_update_note();
|
||||
$note_2 = self::create_db_update_note();
|
||||
|
||||
$this->assertEquals( 2, count( self::get_db_update_notes() ), 'There should be 2 db update notes after I created 2.' );
|
||||
|
||||
WC_Notes_Run_Db_Update::show_reminder();
|
||||
|
||||
// Only one notice should remain, in case 2 were created under some weird circumstances.
|
||||
$this->assertEquals( 1, count( self::get_db_update_notes() ), 'A db update note should be created if db is NOT up to date.' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test switch from db update needed to thanks note.
|
||||
*/
|
||||
public function test_db_update_note_to_thanks_note() {
|
||||
// No notes initially.
|
||||
$this->assertEquals( 0, count( self::get_db_update_notes() ), 'There should be no db update notes initially.' );
|
||||
|
||||
// Make it appear as if db version is lower than WC version, i.e. db update is required.
|
||||
update_option( 'woocommerce_db_version', '3.9.0' );
|
||||
|
||||
// Magic 1: nothing to update-db note.
|
||||
WC_Notes_Run_Db_Update::show_reminder();
|
||||
|
||||
$note_ids = self::get_db_update_notes();
|
||||
// An 'update required' notice should be created.
|
||||
$this->assertEquals( 1, count( $note_ids ), 'A db update note should be created if db is NOT up to date.' );
|
||||
|
||||
$note = new WC_Admin_Note( $note_ids[0] );
|
||||
$actions = $note->get_actions();
|
||||
$this->assertEquals( 'update-db_run', $actions[0]->name, 'A db update note to update the database should be displayed now.' );
|
||||
|
||||
// Simulate database update has been performed.
|
||||
update_option( 'woocommerce_db_version', WC()->version );
|
||||
|
||||
// Magic 2: update-db note to thank you note.
|
||||
WC_Notes_Run_Db_Update::show_reminder();
|
||||
|
||||
$note = new WC_Admin_Note( $note_ids[0] );
|
||||
$actions = $note->get_actions();
|
||||
$this->assertEquals( 'update-db_done', $actions[0]->name, 'A db update note--Thanks for the update--should be displayed now.' );
|
||||
}
|
||||
|
||||
}
|
|
@ -181,6 +181,10 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
|
||||
// Create tax classes first.
|
||||
WC_Tax::create_tax_class( '23percent' );
|
||||
WC_Tax::create_tax_class( '5percent' );
|
||||
|
||||
$tax_rate = array(
|
||||
'tax_rate_country' => '',
|
||||
'tax_rate_state' => '',
|
||||
|
@ -218,7 +222,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
$product2 = WC_Helper_Product::create_simple_product();
|
||||
$product2->set_price( 59 );
|
||||
$product2->set_regular_price( 59 );
|
||||
$product->set_tax_class( '5percent' );
|
||||
$product2->set_tax_class( '23percent' );
|
||||
$product2->save();
|
||||
|
||||
// Create a flat rate method.
|
||||
|
@ -244,7 +248,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
||||
WC()->session->set( 'chosen_shipping_methods', array( 'flat_rate' ) );
|
||||
WC()->cart->calculate_totals();
|
||||
$this->assertEquals( 28.9, WC()->cart->total );
|
||||
$this->assertEquals( 27.05, WC()->cart->total );
|
||||
|
||||
// Add product2 to cart.
|
||||
WC()->cart->add_to_cart( $product2->get_id(), 1 );
|
||||
|
|
|
@ -71,10 +71,11 @@ class WC_Test_Privacy_Export extends WC_Unit_Test_Case {
|
|||
$this->assertEquals(
|
||||
array(
|
||||
array(
|
||||
'group_id' => 'woocommerce_customer',
|
||||
'group_label' => 'Customer Data',
|
||||
'item_id' => 'user',
|
||||
'data' => array(
|
||||
'group_id' => 'woocommerce_customer',
|
||||
'group_label' => 'Customer Data',
|
||||
'group_description' => 'User’s WooCommerce customer data.',
|
||||
'item_id' => 'user',
|
||||
'data' => array(
|
||||
array(
|
||||
'name' => 'Billing Address 1',
|
||||
'value' => '123 South Street',
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* Class WC_Tests_WC_Helper file.
|
||||
*
|
||||
* @package WooCommerce|Tests|WC_Helper.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Tests_WC_Helper.
|
||||
*/
|
||||
class WC_Helper_Test extends \WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Test that woo plugins are loaded correctly even if incorrect cache is intially set.
|
||||
*/
|
||||
public function test_get_local_woo_plugins_without_woo_header_cache() {
|
||||
$woocommerce_key = 'sample-woo-plugin.php';
|
||||
|
||||
remove_filter( 'extra_plugin_headers', 'wc_enable_wc_plugin_headers' );
|
||||
wp_clean_plugins_cache( false );
|
||||
get_plugins();
|
||||
|
||||
if ( file_exists( WP_PLUGIN_DIR . '/sample-woo-plugin.php' ) ) {
|
||||
unlink( WP_PLUGIN_DIR . '/sample-woo-plugin.php' );
|
||||
}
|
||||
copy( \WC_Unit_Tests_Bootstrap::instance()->tests_dir . '/data/sample-woo-plugin.php', WP_PLUGIN_DIR . '/sample-woo-plugin.php' );
|
||||
|
||||
add_filter( 'extra_plugin_headers', 'wc_enable_wc_plugin_headers' );
|
||||
|
||||
$woo_plugins = \WC_Helper::get_local_woo_plugins();
|
||||
|
||||
// Restore previous state.
|
||||
wp_clean_plugins_cache( false );
|
||||
|
||||
$this->assertArrayHasKey( $woocommerce_key, $woo_plugins );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
/**
|
||||
* Class WC_Product_CSV_Importer_Controller_Test
|
||||
* @package WooCommerce\Tests\Admin
|
||||
*
|
||||
* Tests to ensure that the CSV product importer works as expected.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Product_CSV_Importer_Controller_Test
|
||||
*/
|
||||
class WC_Product_CSV_Importer_Controller_Test extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Load up the importer classes since they aren't loaded by default.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$bootstrap = WC_Unit_Tests_Bootstrap::instance();
|
||||
require_once $bootstrap->plugin_dir . '/includes/import/class-wc-product-csv-importer.php';
|
||||
require_once $bootstrap->plugin_dir . '/includes/admin/importers/class-wc-product-csv-importer-controller.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the automatic mapping is case insensitive so that columns can be matched more easily.
|
||||
*/
|
||||
public function test_that_auto_mapping_is_case_insensitive() {
|
||||
// Allow us to call the protected method.
|
||||
$class = new ReflectionClass( WC_Product_CSV_Importer_Controller::class );
|
||||
$method = $class->getMethod( 'auto_map_columns' );
|
||||
$method->setAccessible( true );
|
||||
|
||||
$controller = new WC_Product_CSV_Importer_Controller();
|
||||
|
||||
// Test a few different casing formats first.
|
||||
$columns = $method->invoke( $controller, array( 'Name', 'Type' ) );
|
||||
$this->assertEquals(
|
||||
array(
|
||||
0 => 'name',
|
||||
1 => 'type',
|
||||
),
|
||||
$columns
|
||||
);
|
||||
$columns = $method->invoke( $controller, array( 'NAME', 'tYpE' ) );
|
||||
$this->assertEquals(
|
||||
array(
|
||||
0 => 'name',
|
||||
1 => 'type',
|
||||
),
|
||||
$columns
|
||||
);
|
||||
|
||||
// Make sure that the case sensitivity doesn't squash the meta keys.
|
||||
$columns = $method->invoke( $controller, array( 'Meta: _TESTING', 'Meta: _testing' ) );
|
||||
$this->assertEquals(
|
||||
array(
|
||||
0 => 'meta:_TESTING',
|
||||
1 => 'meta:_testing',
|
||||
),
|
||||
$columns
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* Plugin Name: WooCommerce
|
||||
* Plugin URI: https://woocommerce.com/
|
||||
* Description: An eCommerce toolkit that helps you sell anything. Beautifully.
|
||||
* Version: 4.1.0
|
||||
* Version: 4.3.0-dev
|
||||
* Author: Automattic
|
||||
* Author URI: https://woocommerce.com
|
||||
* Text Domain: woocommerce
|
||||
|
|
Loading…
Reference in New Issue