merge master

This commit is contained in:
Ron Rennick 2020-09-11 14:35:27 -03:00
commit cd80e67717
75 changed files with 20101 additions and 32339 deletions

31
.gitattributes vendored
View File

@ -1,13 +1,20 @@
/.* export-ignore
bin export-ignore
# Set the default behavior, in case people don't have `core.autocrlf` set.
* text=auto
# Declare files that will always have LF line endings on checkout.
*.php text eol=lf
# Remove files for archives generated using `git archive`.
/.* export-ignore
bin export-ignore
CODE_OF_CONDUCT.md export-ignore
changelog.txt export-ignore
composer.* export-ignore
Gruntfile.js export-ignore
package.json export-ignore
package-lock.json export-ignore
phpcs.xml export-ignore
phpunit.* export-ignore
README.md export-ignore
tests export-ignore
renovate.json export-ignore
changelog.txt export-ignore
composer.* export-ignore
Gruntfile.js export-ignore
package.json export-ignore
package-lock.json export-ignore
phpcs.xml export-ignore
phpunit.* export-ignore
README.md export-ignore
renovate.json export-ignore
tests export-ignore

View File

@ -11,9 +11,7 @@ jobs:
uses: actions/checkout@v2
- name: Build
id: build
uses: woocommerce/action-build@master
with:
generate-zip: true
uses: woocommerce/action-build@v2
- name: Upload release asset
uses: actions/upload-release-asset@v1
env:

View File

@ -17,9 +17,7 @@ jobs:
ref: ${{ matrix.build }}
- name: Build
id: build
uses: woocommerce/action-build@master
with:
generate-zip: true
uses: woocommerce/action-build@v2
- name: Deploy nightly build
uses: WebFreak001/deploy-nightly@v1.0.3
env:

View File

@ -33,8 +33,8 @@ jobs:
php: 7.4
env: WP_VERSION=latest WP_MULTISITE=0 RUN_E2E=1
script:
- npm install
- npm run build:assets
- npm run build:packages
- npm install jest --global
- npm run docker:up
- npm run test:e2e

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 279 KiB

View File

@ -5067,6 +5067,7 @@ img.help_tip {
.handlediv {
width: 27px;
float: right;
&::before {
content: "\f142" !important;

View File

@ -188,15 +188,24 @@ a.button {
.woocommerce-info {
margin-bottom: 5rem;
margin-left: 0;
padding: 1.5rem 3rem;
background: #eee;
font-size: 0.88889em;
font-family: $headings;
list-style: none;
overflow: hidden;
}
.woocommerce-message,
.woocommerce-error li,
.woocommerce-info {
padding: 1.5rem 3rem;
display: flex;
justify-content: space-between;
align-items: center;
.button {
order: 2;
}
}
.woocommerce-message {
@ -219,6 +228,10 @@ a.button {
background: #111;
}
}
> li {
margin: 0;
}
}
#site-content {
@ -1628,7 +1641,6 @@ a.reset_variations {
.woocommerce-checkout {
ul.woocommerce-error {
margin-left: 0;
flex-direction: column;
align-items: flex-start;

View File

@ -1315,6 +1315,7 @@ jQuery( function ( $ ) {
};
$.post( woocommerce_admin_meta_boxes.ajax_url, data, function( response ) {
$( 'ul.order_notes .no-items' ).remove();
$( 'ul.order_notes' ).prepend( response );
$( '#woocommerce-order-notes' ).unblock();
$( '#add_order_note' ).val( '' );

View File

@ -173,7 +173,7 @@ jQuery( function( $ ) {
// View cart text.
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="' +
$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>' );
}

View File

@ -1,11 +1,16 @@
== Changelog ==
= 4.5.1 - 2020-09-09 =
* Fix - Check for state and postcode fields only if required in `show_shipping`. #27628
= 4.5.0 - 2020-09-08 =
**WooCommerce**
* Localization - Added postcode validation for Bosnia and Herzegovina. #27048
* Localization - Added the postcode validation for Liechtenstein. #27059
* Localization - Add i18n locale information for Liechtenstein, Switzerland and Austria. #27193
* Tweak - Increase priority of `admin_body_class` filter to avoid comflict with plugins that incorrectly remove all body classes from WP. #27426
* Tweak - Rename built-in PayPal payment method to PayPal Standard. #27468
* Fix - Remove whitespace within a link. #26897
* Fix - `get_review_count_for_product` return all comments count not only 'review' types #26928
* Fix - Hidden field type is now supported by `woocommerce_form_field`. #27023
@ -18,6 +23,10 @@
* Fix - Fixes Japan zip code format issue (dash is now optional). #27244
* Fix - Restore backward compatibility with WC 4.x and forward compatibility with WC 5.5. #27318
* Fix - Switch to site locale before translating refund reason. #27323
* Fix - Declare `WC_Post_Types::updated_term_messages` as a static method to remove PHP deprecation warning. #27436
* Fix - Allow HTML to be entered in product title for formatting purposes. #27465
* Fix - Filter by attribute widget not working properly for variations having attribute values of "Any...". #27508
* Fix - Fixed the layout of the variations and attributes sections in the product page in the admin when running WP >= 5.5. #27590
* Dev - Added additional stock-based cart filters including `woocommerce_cart_product_cannot_add_another_message`, `woocommerce_cart_product_out_of_stock_message`, and `woocommerce_cart_product_not_enough_stock_message`. #26439
* Dev - Changed text domain to `woocommerce` for REST API files. #27248
* Dev - Added file path to the `woocommerce_file_download_method` filter. #27152
@ -26,7 +35,7 @@
**WooCommerce Admin 1.5.0**
* Enhancement - Add eWAY to Payment Setup for AU/NZ Stores. #4947
* Fix - Use clipRule and fillRule props. #4889, part of #4864
* Tweak: Remove the Composite products option from the onboarding wizard #4703
* Fix - Admin order page shipping label prompt compatibility with WCS 1.24. #5025
* Dev - New notification: Don't forget to test your checkout. #4805
* Dev - Enable tax calculation before redirecting to standard tax rates page. #4878
* Dev - Added event recording to Orders, Stock, and Reviews panels. #4861
@ -869,7 +878,7 @@
* Tweak - Remove the left and right margin from the logo in emails. #23360
* Tweak - Use the high res version of the WP spinner in the coupon Block UI. #23364
* Tweak - Improve user registration validation messages. #23468
* Tweak - Auto generate a new username when a username is blacklisted by WordPress. #23672
* Tweak - Auto generate a new username when a username is blocked by WordPress. #23672
* Tweak - Guest cart sessions now gets deleted when a user logs in, preventing duplicate cart sessions. #23687
* Tweak - Include the store's base postcode and city when calculating order taxes. #23695
* Tweak - Update the generate username setting description label to reflect how the username is actually generated. #23911
@ -3965,7 +3974,7 @@
* Fix - Fix bulk editing variation sale price.
* Fix - Remove comment exclusion in order notes meta box.
* Fix - Sync min and max prices for regular and sale prices so prices are displayed correctly when sale price is lower than a regular price of another variation.
* Fix - Expanding line item_meta causes conflicts if attributes are named with things like 'name', 'type' or 'qty'. Added blacklist to exclude unsafe values.
* Fix - Expanding line item_meta causes conflicts if attributes are named with things like 'name', 'type' or 'qty'. Added blocklist to exclude unsafe values.
* Fix - Added support for clearing report transients when using object caching.
* Fix - encoding issues with attribute values.
* Fix - Escape the contents of the changelog when displayed.

View File

@ -13,15 +13,15 @@
"composer/installers": "1.7.0",
"maxmind-db/reader": "1.6.0",
"pelago/emogrifier": "3.1.0",
"psr/container": "^1.0",
"psr/container": "1.0.0",
"woocommerce/action-scheduler": "3.1.6",
"woocommerce/woocommerce-admin": "1.5.0-rc.1",
"woocommerce/woocommerce-admin": "1.5.0",
"woocommerce/woocommerce-blocks": "3.1.0"
},
"require-dev": {
"phpunit/phpunit": "7.5.20",
"woocommerce/woocommerce-sniffs": "^0.1.0",
"wp-cli/i18n-command": "^2.2"
"woocommerce/woocommerce-sniffs": "0.1.0",
"wp-cli/i18n-command": "2.2.5"
},
"config": {
"platform": {

19
composer.lock generated
View File

@ -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": "7f82f8a4f08f7f4f966dc2ef68081293",
"content-hash": "11ae24e5fa6a835a12e6e4f853825392",
"packages": [
{
"name": "automattic/jetpack-autoloader",
@ -380,7 +380,7 @@
},
{
"name": "symfony/css-selector",
"version": "v3.4.43",
"version": "v3.4.44",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
@ -468,16 +468,16 @@
},
{
"name": "woocommerce/woocommerce-admin",
"version": "1.5.0-rc.1",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
"reference": "97a540e2e114b8c7566dc97109ba04536f905de0"
"reference": "b788329894265b4698c5ea997ce73a9f506d3e4c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/97a540e2e114b8c7566dc97109ba04536f905de0",
"reference": "97a540e2e114b8c7566dc97109ba04536f905de0",
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/b788329894265b4698c5ea997ce73a9f506d3e4c",
"reference": "b788329894265b4698c5ea997ce73a9f506d3e4c",
"shasum": ""
},
"require": {
@ -511,7 +511,7 @@
],
"description": "A modern, javascript-driven WooCommerce Admin experience.",
"homepage": "https://github.com/woocommerce/woocommerce-admin",
"time": "2020-08-18T03:05:31+00:00"
"time": "2020-09-07T02:36:13+00:00"
},
{
"name": "woocommerce/woocommerce-blocks",
@ -2424,7 +2424,7 @@
},
{
"name": "symfony/finder",
"version": "v3.4.43",
"version": "v3.4.44",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
@ -2937,6 +2937,5 @@
"platform-dev": [],
"platform-overrides": {
"php": "7.1"
},
"plugin-api-version": "1.1.0"
}
}

View File

@ -154,7 +154,6 @@ return array(
'BG',
'BY',
'CH',
'CY',
'CZ',
'DE',
'DK',

View File

@ -162,6 +162,15 @@ return array(
'weight_unit' => 'kg',
'dimension_unit' => 'cm',
),
'KR' => array(
'currency_code' => 'KRW',
'currency_pos' => 'right',
'thousand_sep' => ',',
'decimal_sep' => '.',
'num_decimals' => 0,
'weight_unit' => 'kg',
'dimension_unit' => 'cm',
),
'LI' => array(
'currency_code' => 'CHF',
'currency_pos' => 'left_space',

View File

@ -343,6 +343,35 @@ return array(
'DZ-48' => __( 'Relizane', 'woocommerce' ),
),
'EE' => array(),
'EG' => array( // Egypt states.
'EGALX' => __( 'Alexandria', 'woocommerce' ),
'EGASN' => __( 'Aswan', 'woocommerce' ),
'EGAST' => __( 'Asyut', 'woocommerce' ),
'EGBA' => __( 'Red Sea', 'woocommerce' ),
'EGBH' => __( 'Beheira', 'woocommerce' ),
'EGBNS' => __( 'Beni Suef', 'woocommerce' ),
'EGC' => __( 'Cairo', 'woocommerce' ),
'EGDK' => __( 'Dakahlia', 'woocommerce' ),
'EGDT' => __( 'Damietta', 'woocommerce' ),
'EGFYM' => __( 'Faiyum', 'woocommerce' ),
'EGGH' => __( 'Gharbia', 'woocommerce' ),
'EGGZ' => __( 'Giza', 'woocommerce' ),
'EGIS' => __( 'Ismailia', 'woocommerce' ),
'EGJS' => __( 'South Sinai', 'woocommerce' ),
'EGKB' => __( 'Qalyubia', 'woocommerce' ),
'EGKFS' => __( 'Kafr el-Sheikh', 'woocommerce' ),
'EGKN' => __( 'Qena', 'woocommerce' ),
'EGLX' => __( 'Luxor', 'woocommerce' ),
'EGMN' => __( 'Minya', 'woocommerce' ),
'EGMNF' => __( 'Monufia', 'woocommerce' ),
'EGMT' => __( 'Matrouh', 'woocommerce' ),
'EGPTS' => __( 'Port Said', 'woocommerce' ),
'EGSHG' => __( 'Sohag', 'woocommerce' ),
'EGSHR' => __( 'Al Sharqia', 'woocommerce' ),
'EGSIN' => __( 'North Sinai', 'woocommerce' ),
'EGSUZ' => __( 'Suez', 'woocommerce' ),
'EGWAD' => __( 'New Valley', 'woocommerce' ),
),
'ES' => array( // Spanish states.
'C' => __( 'A Coruña', 'woocommerce' ),
'VI' => __( 'Araba/Álava', 'woocommerce' ),
@ -393,7 +422,7 @@ return array(
'TO' => __( 'Toledo', 'woocommerce' ),
'V' => __( 'Valencia', 'woocommerce' ),
'VA' => __( 'Valladolid', 'woocommerce' ),
'BI' => __( 'Bizkaia', 'woocommerce' ),
'BI' => __( 'Biscay', 'woocommerce' ),
'ZA' => __( 'Zamora', 'woocommerce' ),
'Z' => __( 'Zaragoza', 'woocommerce' ),
),

View File

@ -137,7 +137,7 @@ class WC_Admin {
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// Nonced plugin install redirects (whitelisted).
// Nonced plugin install redirects.
if ( ! empty( $_GET['wc-install-plugin-redirect'] ) ) {
$plugin_slug = wc_clean( wp_unslash( $_GET['wc-install-plugin-redirect'] ) );

View File

@ -267,7 +267,7 @@ class WC_Meta_Box_Coupon_Data {
'id' => 'customer_email',
'label' => __( 'Allowed emails', 'woocommerce' ),
'placeholder' => __( 'No restrictions', 'woocommerce' ),
'description' => __( 'Whitelist of billing emails to check against when an order is placed. Separate email addresses with commas. You can also use an asterisk (*) to match parts of an email. For example "*@gmail.com" would match all gmail addresses.', 'woocommerce' ),
'description' => __( 'List of allowed billing emails to check against when an order is placed. Separate email addresses with commas. You can also use an asterisk (*) to match parts of an email. For example "*@gmail.com" would match all gmail addresses.', 'woocommerce' ),
'value' => implode( ', ', (array) $coupon->get_email_restrictions( 'edit' ) ),
'desc_tip' => true,
'type' => 'email',

View File

@ -41,7 +41,7 @@ defined( 'ABSPATH' ) || exit;
}
} else {
?>
<li><?php esc_html_e( 'There are no notes yet.', 'woocommerce' ); ?></li>
<li class="no-items"><?php esc_html_e( 'There are no notes yet.', 'woocommerce' ); ?></li>
<?php
}
?>

View File

@ -776,7 +776,15 @@ class WC_Cart extends WC_Legacy_Cart {
$held_stock = wc_get_held_stock_quantity( $product, $current_session_order_id );
$required_stock = $product_qty_in_cart[ $product->get_stock_managed_by_id() ];
if ( $product->get_stock_quantity() < ( $held_stock + $required_stock ) ) {
/**
* Allows filter if product have enough stock to get added to the cart.
*
* @since 4.6.0
* @param bool $has_stock If have enough stock.
* @param WC_Product $product Product instance.
* @param array $values Cart item values.
*/
if ( apply_filters( 'woocommerce_cart_item_required_stock_is_not_enough', $product->get_stock_quantity() < ( $held_stock + $required_stock ), $product, $values ) ) {
/* translators: 1: product name 2: quantity in stock */
$error->add( 'out-of-stock', sprintf( __( 'Sorry, we do not have enough "%1$s" in stock to fulfill your order (%2$s available). We apologize for any inconvenience caused.', 'woocommerce' ), $product->get_name(), wc_format_stock_quantity_for_display( $product->get_stock_quantity() - $held_stock, $product ) ) );
return $error;
@ -1032,7 +1040,6 @@ class WC_Cart extends WC_Legacy_Cart {
// Gather posted attributes.
$posted_attributes = array();
foreach ( $parent_data->get_attributes() as $attribute ) {
if ( ! $attribute['is_variation'] ) {
continue;
@ -1048,7 +1055,7 @@ class WC_Cart extends WC_Legacy_Cart {
}
// Don't include if it's empty.
if ( ! empty( $value ) ) {
if ( ! empty( $value ) || '0' === $value ) {
$posted_attributes[ $attribute_key ] = $value;
}
}
@ -1520,7 +1527,15 @@ class WC_Cart extends WC_Legacy_Cart {
}
if ( 'yes' === get_option( 'woocommerce_shipping_cost_requires_address' ) ) {
if ( ! $this->get_customer()->get_shipping_country() || ! $this->get_customer()->get_shipping_state() || ! $this->get_customer()->get_shipping_postcode() ) {
$country = $this->get_customer()->get_shipping_country();
if ( ! $country ) {
return false;
}
$country_fields = WC()->countries->get_address_fields( $country, 'shipping_' );
if ( isset( $country_fields['shipping_state'] ) && $country_fields['shipping_state']['required'] && ! $this->get_customer()->get_shipping_state() ) {
return false;
}
if ( isset( $country_fields['shipping_postcode'] ) && $country_fields['shipping_postcode']['required'] && ! $this->get_customer()->get_shipping_postcode() ) {
return false;
}
}

View File

@ -1177,7 +1177,7 @@ CREATE TABLE {$wpdb->prefix}wc_reserved_stock (
*
* @return array
*/
private static function get_core_capabilities() {
public static function get_core_capabilities() {
$capabilities = array();
$capabilities['core'] = array(

View File

@ -489,7 +489,7 @@ class WC_Post_Types {
* @since 4.4.0
* @return bool
*/
public function updated_term_messages( $messages ) {
public static function updated_term_messages( $messages ) {
$messages['product_cat'] = array(
0 => '',
1 => __( 'Category added.', 'woocommerce' ),

View File

@ -593,94 +593,6 @@ class WC_Product_Variable extends WC_Product {
return true;
}
/**
* Returns whether or not the product is visible in the catalog (doesn't trigger filters).
*
* @return bool
*/
protected function is_visible_core() {
if ( ! $this->parent_is_visible_core() ) {
return false;
}
$query_filters = $this->get_layered_nav_chosen_attributes();
if ( empty( $query_filters ) ) {
return true;
}
/**
* If there are attribute filters in the request, a variable product will be visible
* if at least one of the available variations matches the filters.
*/
$attributes_with_terms = array();
array_walk(
$query_filters,
function( $value, $key ) use ( &$attributes_with_terms ) {
$attributes_with_terms[ $key ] = $value['terms'];
}
);
$variations = $this->get_available_variations( 'objects' );
foreach ( $variations as $variation ) {
if ( $this->variation_matches_filters( $variation, $attributes_with_terms ) ) {
return true;
}
}
return false;
}
/**
* Checks if a given variation matches the active attribute filters.
*
* @param WC_Product_Variation $variation The variation to check.
* @param array $query_filters The active filters as an array of attribute_name => [term1, term2...].
*
* @return bool True if the variation matches the active attribute filters.
*/
private function variation_matches_filters( WC_Product_Variation $variation, array $query_filters ) {
// Get the variation attributes as an array of attribute_name => attribute_value.
// The array_filter will filter out attributes having a value of '', these correspond
// to "Any..." variations that don't participate in filtering.
$variation_attributes = array_filter( $variation->get_variation_attributes( false ) );
$variation_attribute_names_in_filters = array_intersect( array_keys( $query_filters ), array_keys( $variation_attributes ) );
if ( empty( $variation_attribute_names_in_filters ) ) {
// The variation doesn't have any attribute that participates in filtering so we consider it a match.
return true;
}
foreach ( $variation_attribute_names_in_filters as $attribute_name ) {
if ( ! in_array( $variation_attributes[ $attribute_name ], $query_filters[ $attribute_name ], true ) ) {
// Multiple filters interact with AND logic, so as soon as one of them
// doesn't match then the variation doesn't match.
return false;
}
}
return true;
}
/**
* What does is_visible_core in the parent class say?
* This method exists to ease unit testing.
*
* @return bool
*/
protected function parent_is_visible_core() {
return parent::is_visible_core();
}
/**
* Get an array of attributes and terms selected with the layered nav widget.
* This method exists to ease unit testing.
*
* @return array
*/
protected function get_layered_nav_chosen_attributes() {
return WC()->query::get_layered_nav_chosen_attributes();
}
/*
|--------------------------------------------------------------------------

View File

@ -23,7 +23,7 @@ class WC_Query {
/**
* Reference to the main product query on the page.
*
* @var array
* @var WP_Query
*/
private static $product_query;
@ -362,23 +362,10 @@ class WC_Query {
if ( 'product_query' !== $query->get( 'wc_query' ) ) {
return $posts;
}
$this->adjust_total_pages();
$this->remove_product_query_filters( $posts );
return $posts;
}
/**
* The 'adjust_posts_count' method that handles the 'found_posts' filter indirectly initializes
* the loop properties with a call to 'wc_setup_loop'. This includes setting 'total_pages' to
* '$GLOBALS['wp_query']->max_num_pages', which at that point has a value of zero.
* Thus we need to set the real value from the 'the_posts' filter, where $GLOBALS['wp_query']->max_num_pages'
* will aready have been initialized.
*/
private function adjust_total_pages() {
if ( 0 === wc_get_loop_prop( 'total_pages' ) ) {
wc_set_loop_prop( 'total_pages', $GLOBALS['wp_query']->max_num_pages );
}
}
/**
* Pre_get_posts above may adjust the main query to add WooCommerce logic. When this query is done, we need to ensure
@ -396,12 +383,9 @@ class WC_Query {
}
/**
* When we are listing products and the request is filtering by attributes via layered nav plugin
* we need to adjust the total posts count to account for variable products having stock
* in some variations but not in others.
* We do that by just checking if each product is visible.
*
* We also cache the post visibility so that it isn't checked again when displaying the posts list.
* This function used to be hooked to found_posts and adjust the posts count when the filtering by attribute
* widget was used and variable products were present. Now it isn't hooked anymore and does nothing but return
* the input unchanged, since the pull request in which it was introduced has been reverted.
*
* @since 4.4.0
* @param int $count Original posts count, as supplied by the found_posts filter.
@ -410,35 +394,6 @@ class WC_Query {
* @return int Adjusted posts count.
*/
public function adjust_posts_count( $count, $query ) {
if ( ! $query->get( 'wc_query' ) ) {
return $count;
}
$posts = $this->get_current_posts();
if ( is_null( $posts ) ) {
return $count;
}
foreach ( $posts as $post ) {
if ( is_object( $post ) && 'product' !== $post->post_type ) {
continue;
}
$product_id = is_object( $post ) ? $post->ID : $post;
$product = wc_get_product( $product_id );
if ( ! is_object( $product ) ) {
continue;
}
if ( $product->is_visible() ) {
wc_set_loop_product_visibility( $product_id, true );
} else {
wc_set_loop_product_visibility( $product_id, false );
$count--;
}
}
wc_set_loop_prop( 'total', $count );
return $count;
}
@ -514,7 +469,7 @@ class WC_Query {
// Additonal hooks to change WP Query.
add_filter( 'posts_clauses', array( $this, 'price_filter_post_clauses' ), 10, 2 );
add_filter( 'the_posts', array( $this, 'handle_get_posts' ), 10, 2 );
add_filter( 'found_posts', array( $this, 'adjust_posts_count' ), 10, 2 );
do_action( 'woocommerce_product_query', $q, $this );
}
@ -614,7 +569,7 @@ class WC_Query {
* @since 3.6.0
*
* @param array $args Query args.
* @param WC_Query $wp_query WC_Query object.
* @param WP_Query $wp_query WP_Query object.
*
* @return array
*/
@ -806,7 +761,7 @@ class WC_Query {
/**
* Get the main query which product queries ran against.
*
* @return array
* @return WP_Query
*/
public static function get_main_query() {
return self::$product_query;

View File

@ -203,7 +203,7 @@ class WC_Regenerate_Images {
return $image;
}
// Use a whitelist of sizes we want to resize. Ignore others.
// List of sizes we want to resize. Ignore others.
if ( ! $image || ! in_array( $size, apply_filters( 'woocommerce_image_sizes_to_resize', array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single', 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ), true ) ) {
return $image;
}

View File

@ -22,7 +22,7 @@ final class WooCommerce {
*
* @var string
*/
public $version = '4.5.0';
public $version = '4.5.1';
/**
* WooCommerce Schema version.

View File

@ -226,7 +226,7 @@ class WC_Shop_Customizer {
'max_rows_error',
{
type : 'error',
message: '<?php echo esc_js( sprintf( $min_notice, $max_rows ) ); ?>'
message: '<?php echo esc_js( sprintf( $max_notice, $max_rows ) ); ?>'
}
) );
} else {

View File

@ -1708,7 +1708,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
$product_type = 'variation';
} elseif ( 'product' === $post_type ) {
$terms = get_the_terms( $product_id, 'product_type' );
$product_type = ! empty( $terms ) ? sanitize_title( current( $terms )->name ) : 'simple';
$product_type = ! empty( $terms ) && ! is_wp_error( $terms ) ? sanitize_title( current( $terms )->name ) : 'simple';
} else {
$product_type = false;
}

View File

@ -499,6 +499,7 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
// Set the attributes as regular taxonomy terms too...
$variation_attributes = array_keys( $product->get_variation_attributes( false ) );
foreach ( $attributes as $name => $value ) {
$value = strval( $value );
if ( '' !== $value && in_array( $name, $variation_attributes, true ) && term_exists( $value, $name ) ) {
wp_set_post_terms( $product_id, array( $value ), $name );
} elseif ( taxonomy_exists( $name ) ) {

View File

@ -42,7 +42,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
$this->id = 'paypal';
$this->has_fields = false;
$this->order_button_text = __( 'Proceed to PayPal', 'woocommerce' );
$this->method_title = __( 'PayPal', 'woocommerce' );
$this->method_title = __( 'PayPal Standard', 'woocommerce' );
/* translators: %s: Link to WC system status page */
$this->method_description = __( 'PayPal Standard redirects customers to PayPal to enter their payment information.', 'woocommerce' );
$this->supports = array(
@ -283,7 +283,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
?>
<div class="inline error">
<p>
<strong><?php esc_html_e( 'Gateway disabled', 'woocommerce' ); ?></strong>: <?php esc_html_e( 'PayPal does not support your store currency.', 'woocommerce' ); ?>
<strong><?php esc_html_e( 'Gateway disabled', 'woocommerce' ); ?></strong>: <?php esc_html_e( 'PayPal Standard does not support your store currency.', 'woocommerce' ); ?>
</p>
</div>
<?php

View File

@ -1,6 +1,6 @@
<?php
/**
* Settings for PayPal Gateway.
* Settings for PayPal Standard Gateway.
*
* @package WooCommerce\Classes\Payment
*/

View File

@ -521,7 +521,7 @@ class WC_Shortcode_Products {
* Get wrapper classes.
*
* @since 3.2.0
* @param array $columns Number of columns.
* @param int $columns Number of columns.
* @return array
*/
protected function get_wrapper_classes( $columns ) {

View File

@ -86,7 +86,7 @@ class WC_Tracks_Event {
$_event = (object) array_merge( (array) $event, $validated );
// If you want to blacklist property names, do it here.
// If you want to block property names, do it here.
// Make sure we have an event timestamp.
if ( ! isset( $_event->_ts ) ) {
$_event->_ts = WC_Tracks_Client::build_timestamp();
@ -150,13 +150,13 @@ class WC_Tracks_Event {
return;
}
$whitelisted_key_names = array(
$allowed_key_names = array(
'anonId',
'Browser_Type',
);
foreach ( array_keys( (array) $event ) as $key ) {
if ( in_array( $key, $whitelisted_key_names, true ) ) {
if ( in_array( $key, $allowed_key_names, true ) ) {
continue;
}
if ( ! self::prop_name_is_valid( $key ) ) {

View File

@ -30,7 +30,7 @@ class WC_Admin_Setup_Wizard_Tracking {
add_action( 'shutdown', array( $this, 'track_skip_step' ), 1 );
add_action( 'add_option_woocommerce_allow_tracking', array( $this, 'track_start' ), 10, 2 );
add_action( 'admin_init', array( $this, 'track_ready_next_steps' ), 1 );
add_action( 'wp_print_scripts', array( $this, 'dequeue_non_whitelisted_scripts' ) );
add_action( 'wp_print_scripts', array( $this, 'dequeue_non_allowed_scripts' ) );
$this->add_step_save_events();
add_action( 'woocommerce_setup_footer', array( $this, 'add_footer_scripts' ) );
}
@ -56,12 +56,12 @@ class WC_Admin_Setup_Wizard_Tracking {
/**
* Dequeue unwanted scripts from OBW footer.
*/
public function dequeue_non_whitelisted_scripts() {
public function dequeue_non_allowed_scripts() {
global $wp_scripts;
$whitelist = array( 'woo-tracks' );
$allowed = array( 'woo-tracks' );
foreach ( $wp_scripts->queue as $script ) {
if ( in_array( $script, $whitelist, true ) ) {
if ( in_array( $script, $allowed, true ) ) {
continue;
}
wp_dequeue_script( $script );

View File

@ -11,12 +11,13 @@ defined( 'ABSPATH' ) || exit;
* This class adds actions to track usage of WooCommerce Settings.
*/
class WC_Settings_Tracking {
/**
* Whitelisted WooCommerce settings to potentially track updates for.
* List of allowed WooCommerce settings to potentially track updates for.
*
* @var array
*/
protected $whitelist = array();
protected $allowed_options = array();
/**
* WooCommerce settings that have been updated (and will be tracked).
@ -30,22 +31,22 @@ class WC_Settings_Tracking {
*/
public function init() {
add_action( 'woocommerce_settings_page_init', array( $this, 'track_settings_page_view' ) );
add_action( 'woocommerce_update_option', array( $this, 'add_option_to_whitelist' ) );
add_action( 'woocommerce_update_option', array( $this, 'add_option_to_list' ) );
add_action( 'woocommerce_update_options', array( $this, 'send_settings_change_event' ) );
}
/**
* Add a WooCommerce option name to our whitelist and attach
* Add a WooCommerce option name to our allowed options list and attach
* the `update_option` hook. Rather than inspecting every updated
* option and pattern matching for "woocommerce", just build a dynamic
* whitelist for WooCommerce options that might get updated.
* list for WooCommerce options that might get updated.
*
* See `woocommerce_update_option` hook.
*
* @param array $option WooCommerce option (config) that might get updated.
*/
public function add_option_to_whitelist( $option ) {
$this->whitelist[] = $option['id'];
public function add_option_to_list( $option ) {
$this->allowed_options[] = $option['id'];
// Delay attaching this action since it could get fired a lot.
if ( false === has_action( 'update_option', array( $this, 'track_setting_change' ) ) ) {
@ -62,7 +63,7 @@ class WC_Settings_Tracking {
*/
public function track_setting_change( $option_name, $old_value, $new_value ) {
// Make sure this is a WooCommerce option.
if ( ! in_array( $option_name, $this->whitelist, true ) ) {
if ( ! in_array( $option_name, $this->allowed_options, true ) ) {
return;
}

View File

@ -1693,7 +1693,9 @@ function wc_nocache_headers() {
* @return int
*/
function wc_product_attribute_uasort_comparison( $a, $b ) {
return wc_uasort_comparison( $a['position'], $b['position'] );
$a_position = is_null( $a ) ? null : $a['position'];
$b_position = is_null( $b ) ? null : $b['position'];
return wc_uasort_comparison( $a_position, $b_position );
}
/**
@ -1918,8 +1920,8 @@ add_action( 'woocommerce_cleanup_logs', 'wc_cleanup_logs' );
/**
* Prints human-readable information about a variable.
*
* Some server environments blacklist some debugging functions. This function provides a safe way to
* turn an expression into a printable, readable form without calling blacklisted functions.
* Some server environments block some debugging functions. This function provides a safe way to
* turn an expression into a printable, readable form without calling blocked functions.
*
* @since 3.0
*

View File

@ -82,7 +82,7 @@ function wc_get_coupon_code_by_id( $id ) {
}
/**
* Get coupon code by ID.
* Get coupon ID by code.
*
* @since 3.0.0
* @param string $code Coupon code.

View File

@ -88,7 +88,7 @@ function wc_add_notice( $message, $notice_type = 'success', $data = array() ) {
if ( ! empty( $message ) ) {
$notices[ $notice_type ][] = array(
'notice' => apply_filters( 'woocommerce_add_' . $notice_type, $message ),
'notice' => $message,
'data' => $data,
);
}

View File

@ -162,10 +162,10 @@ function wc_create_new_customer_username( $email, $new_user_args = array(), $suf
}
/**
* WordPress 4.4 - filters the list of blacklisted usernames.
* WordPress 4.4 - filters the list of blocked usernames.
*
* @since 3.7.0
* @param array $usernames Array of blacklisted usernames.
* @param array $usernames Array of blocked usernames.
*/
$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );

View File

@ -344,65 +344,38 @@ class WC_Widget_Layered_Nav extends WC_Widget {
protected function get_filtered_term_product_counts( $term_ids, $taxonomy, $query_type ) {
global $wpdb;
$main_tax_query = $this->get_main_tax_query();
$meta_query = $this->get_main_meta_query();
$tax_query = $this->get_main_tax_query();
$meta_query = $this->get_main_meta_query();
$non_variable_tax_query_sql = array( 'where' => '' );
$is_and_query = 'and' === $query_type;
foreach ( $main_tax_query as $key => $query ) {
if ( is_array( $query ) && $taxonomy === $query['taxonomy'] ) {
if ( $is_and_query ) {
$non_variable_tax_query_sql = $this->convert_tax_query_to_sql( array( $query ) );
if ( 'or' === $query_type ) {
foreach ( $tax_query as $key => $query ) {
if ( is_array( $query ) && $taxonomy === $query['taxonomy'] ) {
unset( $tax_query[ $key ] );
}
unset( $main_tax_query[ $key ] );
}
}
$exclude_variable_products_tax_query_sql = $this->get_extra_tax_query_sql( 'product_type', array( 'variable' ), 'NOT IN' );
$meta_query_sql = ( new WP_Meta_Query( $meta_query ) )->get_sql( 'post', $wpdb->posts, 'ID' );
$main_tax_query_sql = $this->convert_tax_query_to_sql( $main_tax_query );
$term_ids_sql = '(' . implode( ',', array_map( 'absint', $term_ids ) ) . ')';
$meta_query = new WP_Meta_Query( $meta_query );
$tax_query = new WP_Tax_Query( $tax_query );
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
$term_ids_sql = '(' . implode( ',', array_map( 'absint', $term_ids ) ) . ')';
// Generate query.
$query = array();
$query['select'] = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) as term_count, terms.term_id as term_count_id";
$query['select'] = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) AS term_count, terms.term_id AS term_count_id";
$query['from'] = "FROM {$wpdb->posts}";
$query['join'] = "
INNER JOIN {$wpdb->term_relationships} AS tr ON {$wpdb->posts}.ID = tr.object_id
INNER JOIN {$wpdb->term_relationships} AS term_relationships ON {$wpdb->posts}.ID = term_relationships.object_id
INNER JOIN {$wpdb->term_taxonomy} AS term_taxonomy USING( term_taxonomy_id )
INNER JOIN {$wpdb->terms} AS terms USING( term_id )
{$main_tax_query_sql['join']} {$meta_query_sql['join']}"; // Not an omission, really no more JOINs required.
$variable_where_part = "
OR ({$wpdb->posts}.post_type = 'product_variation'
AND NOT EXISTS (
SELECT ID FROM {$wpdb->posts} AS parent
WHERE parent.ID = {$wpdb->posts}.post_parent AND parent.post_status NOT IN ('publish')
))
";
$search_sql = '';
$search = $this->get_main_search_query_sql();
if ( $search ) {
$search_sql = ' AND ' . $search;
}
" . $tax_query_sql['join'] . $meta_query_sql['join'];
$query['where'] = "
WHERE
{$wpdb->posts}.post_status = 'publish'
{$main_tax_query_sql['where']} {$meta_query_sql['where']}
AND (
(
{$wpdb->posts}.post_type = 'product'
{$exclude_variable_products_tax_query_sql['where']}
{$non_variable_tax_query_sql['where']}
)
{$variable_where_part}
)
AND terms.term_id IN {$term_ids_sql}
{$search_sql}";
WHERE {$wpdb->posts}.post_type IN ( 'product' )
AND {$wpdb->posts}.post_status = 'publish'
{$tax_query_sql['where']} {$meta_query_sql['where']}
AND terms.term_id IN $term_ids_sql";
$search = $this->get_main_search_query_sql();
if ( $search ) {
@ -425,14 +398,13 @@ class WC_Widget_Layered_Nav extends WC_Widget {
}
if ( ! isset( $cached_counts[ $query_hash ] ) ) {
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$results = $wpdb->get_results( $query_sql, ARRAY_A );
$counts = array_map( 'absint', wp_list_pluck( $results, 'term_count', 'term_count_id' ) );
$cached_counts[ $query_hash ] = $counts;
if ( true === $cache ) {
set_transient( 'wc_layered_nav_counts_' . sanitize_title( $taxonomy ), $cached_counts, DAY_IN_SECONDS );
}
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
}
return array_map( 'absint', (array) $cached_counts[ $query_hash ] );
@ -468,45 +440,6 @@ class WC_Widget_Layered_Nav extends WC_Widget {
return WC_Query::get_main_meta_query();
}
/**
* Get a tax query SQL for a given set of taxonomy, terms and operator.
* Uses an intermediate WP_Tax_Query object.
*
* @since 4.4.0
* @param string $taxonomy Taxonomy name.
* @param array $terms Terms to include in the query.
* @param string $operator Query operator, as supported by WP_Tax_Query; e.g. "NOT IN".
*
* @return array
*/
private function get_extra_tax_query_sql( $taxonomy, $terms, $operator ) {
$query = array(
array(
'taxonomy' => $taxonomy,
'field' => 'slug',
'terms' => $terms,
'operator' => $operator,
'include_children' => false,
),
);
return $this->convert_tax_query_to_sql( $query );
}
/**
* Convert a tax query array to SQL using an intermediate WP_Tax_Query object.
*
* @since 4.4.0
* @param array $query Query array in the same format accepted by WP_Tax_Query constructor.
*
* @return array Query SQL as returned by WP_Tax_Query->get_sql.
*/
private function convert_tax_query_to_sql( $query ) {
global $wpdb;
return ( new WP_Tax_Query( $query ) )->get_sql( $wpdb->posts, 'ID' );
}
/**
* Show list based layered nav.
*

29404
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
"name": "woocommerce",
"title": "WooCommerce",
"version": "4.5.0",
"version": "4.5.1",
"homepage": "https://woocommerce.com/",
"repository": {
"type": "git",
@ -13,6 +13,7 @@
"wp_org_slug": "woocommerce"
},
"scripts": {
"install": "lerna bootstrap",
"build": "./bin/build-zip.sh",
"build:core": "grunt && npm run makepot",
"build:dev": "npm run build:core && npm run build:packages",
@ -37,13 +38,15 @@
"@babel/preset-env": "7.10.4",
"@babel/register": "7.10.4",
"@typescript-eslint/eslint-plugin": "3.1.0",
"@typescript-eslint/experimental-utils": "^2.34.0",
"@typescript-eslint/parser": "3.1.0",
"@woocommerce/e2e-environment": "file:tests/e2e/env",
"@woocommerce/e2e-utils": "file:tests/e2e/utils",
"@woocommerce/model-factories": "file:tests/e2e/factories",
"@wordpress/babel-plugin-import-jsx-pragma": "1.1.3",
"@wordpress/babel-preset-default": "3.0.2",
"@wordpress/e2e-test-utils": "4.6.0",
"@wordpress/eslint-plugin": "7.1.0",
"@woocommerce/e2e-utils": "file:tests/e2e/utils",
"autoprefixer": "9.8.6",
"babel-eslint": "10.1.0",
"chai": "4.2.0",
@ -67,7 +70,7 @@
"grunt-postcss": "0.9.0",
"grunt-rtlcss": "2.0.2",
"grunt-sass": "3.1.0",
"grunt-stylelint": "0.14.0",
"grunt-stylelint": "0.15.0",
"gruntify-eslint": "5.0.0",
"husky": "4.2.5",
"istanbul": "1.0.0-alpha.2",
@ -75,14 +78,15 @@
"lerna": "3.22.1",
"lint-staged": "9.5.0",
"mocha": "7.2.0",
"node-sass": "4.13.0",
"prettier": "npm:wp-prettier@^2.0.5",
"node-sass": "4.13.1",
"prettier": "npm:wp-prettier@2.0.5",
"puppeteer": "^2.1.1",
"stylelint": "12.0.1",
"stylelint-config-wordpress": "16.0.0",
"typescript": "3.9.5",
"webpack": "4.41.6",
"webpack-cli": "3.3.11",
"wp-textdomain": "^1.0.1"
"webpack": "4.44.1",
"webpack-cli": "3.3.12",
"wp-textdomain": "1.0.1"
},
"engines": {
"node": ">=10.15.0",

View File

@ -1,146 +1,133 @@
=== WooCommerce ===
Contributors: automattic, mikejolley, jameskoster, claudiosanches, kloon, rodrigosprimo, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski
Tags: e-commerce, store, sales, sell, woo, shop, cart, checkout, downloadable, downloads, payments, paypal, storefront, stripe, woo commerce
Requires at least: 5.2
Requires at least: 5.3
Tested up to: 5.5
Requires PHP: 7.0
Stable tag: 4.4.1
Stable tag: 4.5.1
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html
WooCommerce is a flexible, open-source eCommerce solution built on WordPress. Sell anything, anywhere and make your way.
WooCommerce is the worlds most popular open-source eCommerce solution.
== Description ==
WooCommerce is a flexible, open-source eCommerce solution built on WordPress. Whether you're launching a business, taking an existing brick and mortar store online, or designing sites for clients you can get started quickly and build exactly the store you want.
WooCommerce is the worlds most popular open-source eCommerce solution.
Activate the free WooCommerce plugin on a new or existing WordPress site, follow the optional guided tour, and set up a new store in minutes with:
Our core platform is free, flexible, and amplified by a global community. The freedom of open-source means you retain full ownership of your stores content and data forever.
- Product, Cart, and Checkout pages
- Secure payments by credit card and alternatives
- Configurable shipping options, including flat rates and [label printing](https://woocommerce.com/products/shipping/?utm_source=wp%20org%20repo%20listing&utm_content=3.6)
- Integrate content and commerce across your site via modular blocks
- [Automated tax calculations](https://woocommerce.com/products/tax/?utm_source=wp%20org%20repo%20listing&utm_content=3.6)
- [Google Analytics](https://woocommerce.com/products/woocommerce-google-analytics/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [MailChimp](https://woocommerce.com/products/mailchimp-for-woocommerce/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), and [Facebook](https://woocommerce.com/products/facebook/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) integration
- [Central store dashboard](https://woocommerce.com/posts/woocommerce-admin-a-new-central-dashboard-for-woocommerce/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) with key metrics, and more.
Whether youre launching a business, taking brick-and-mortar retail online, or developing sites for clients, use WooCommerce for a store that powerfully blends content and commerce.
Beyond the basics, WooCommerce is fully customizable and extendable:
- **Create beautiful, enticing storefronts** with [themes](https://woocommerce.com/product-category/themes/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) suited to your brand and industry.
- **Customize pages in minutes** using modular [product blocks](https://docs.woocommerce.com/document/woocommerce-blocks/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
- Showcase physical and digital goods, product variations, custom configurations, instant downloads, and affiliate items. [Bookings](https://woocommerce.com/products/woocommerce-bookings/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), [memberships](https://woocommerce.com/products/woocommerce-memberships/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), [subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), and [dynamic pricing](https://woocommerce.com/products/dynamic-pricing/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) rules are only an extension away.
- **Rise to the top of search results** by leveraging [WordPress SEO advantage](https://www.searchenginejournal.com/wordpress-best-cms-seo/).
- Choose a design to suit your brand and industry.
- Enhance your store with free and paid extensions: add features and integrate with local and global eCommerce web services.
- Inspect and modify any aspect of the core plugin code.
- Leverage hooks and filters to modify functions.
- Build on top of the REST API and webhooks.
Built-in tools and popular integrations help you efficiently manage your business operations. Many services are free to add with a single click via the optional [Setup Wizard](https://docs.woocommerce.com/document/woocommerce-setup-wizard/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
Open-source freedoms mean full ownership of content and data forever plus the expertise of a friendly [global community](https://woocommerce.com/meetups/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
- **Choose how you want to get paid**. Conveniently manage payments from the comfort of your store with [WooCommerce Payments](https://woocommerce.com/payments/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) (U.S.-only). Securely accept cards, mobile wallets, bank transfers, and cash thanks to [100+ payment gateways](https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) including [Stripe](https://woocommerce.com/products/stripe/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), [PayPal](https://woocommerce.com/products/woocommerce-gateway-paypal-checkout/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), and [Square](https://woocommerce.com/products/square/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
- **Configure your shipping options**. Print USPS labels right from your dashboard and even schedule a pickup with [WooCommerce Shipping](https://woocommerce.com/products/shipping/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) (U.S.-only). Connect with [well-known carriers](https://woocommerce.com/product-category/woocommerce-extensions/shipping-methods/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) such as UPS, FedEx, and ShipStation plus a wide variety of delivery, inventory, and fulfillment solutions for your locale.
- **Simplify sales tax**. Add [WooCommerce Tax](https://woocommerce.com/products/tax/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) or [similar integrated services](https://woocommerce.com/product-category/woocommerce-extensions/tax?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) to make automated calculations a reality.
WooCommerce is built to allow store managers to run an eCommerce site themselves, no web developer needed. There is also a free WooCommerce [mobile app](https://woocommerce.com/mobile/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) (Android and iOS) for store management on the go.
= Grow your business, add features, and monitor your store on the go =
WooCommerce is developed and supported by Automattic, the creators of Jetpack and WordPress.com, along with independent contributors. The [official extension marketplace](https://woocommerce.com/product-category/woocommerce-extensions/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) is on WooCommerce.com.
WooCommerce means business. Keep tabs on the performance metrics most important to you with [WooCommerce Admin](https://wordpress.org/plugins/woocommerce-admin/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) a powerful, customizable central dashboard for your store.
= From subscriptions to gym classes to luxury cars =
With WooCommerce, you can sell both physical and digital goods in all shapes and sizes, offer product variations, complex configurations, and instant downloads to shoppers; and even sell affiliate goods from online marketplaces.
Expand your audience across marketing and social channels with [Google Ads](https://woocommerce.com/products/google-ads/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), [HubSpot](https://woocommerce.com/products/hubspot-for-woocommerce/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), [Mailchimp](https://woocommerce.com/products/mailchimp-for-woocommerce/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), and [Facebook](https://woocommerce.com/products/facebook/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) integrations. You can always check out the in-dashboard [Marketing Hub](https://docs.woocommerce.com/document/marketing-hub/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) for fresh ideas and tips to help you succeed.
And those are just the out-of-the-box options. With paid extensions, you can extend your WooCommerce store to take bookings, offer memberships, set up recurring payments by subscription, create dynamic pricing rules, and much more.
Enhance store functionality with hundreds of free and paid extensions from the [official WooCommerce Marketplace](https://woocommerce.com/products/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing). Our developers [vet each new extension](https://docs.woocommerce.com/document/marketplace-overview/#section-6?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) and regularly review existing inventory to maintain Marketplace quality standards. We are actively [looking for products that help store builders create successful stores](https://docs.woocommerce.com/document/marketplace-overview/#section-2?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
Start a monthly wine subscription box, offer a discount on yoga mats to members whove attended 10+ classes, offer configurable hampers or personalized jewelry its all possible with WooCommerce.
Manage your store from anywhere with the free WooCommerce [mobile app](https://woocommerce.com/mobile/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) (Android and iOS). Spoiler alert: Keep an ear out for the slightly addictive "cha-ching" notification sound each time you make a new sale!
= Comprehensive payment options =
WooCommerce comes bundled with the ability to accept major credit cards, alternative payment methods, BACS (bank transfers), and cash on delivery.
= Own and control your store data forever =
For additional options, WooCommerce also integrates with more than 140 region-specific gateways including popular choices like [Stripe](https://woocommerce.com/products/stripe/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [PayPal](https://woocommerce.com/products/woocommerce-gateway-paypal-checkout/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Square](https://woocommerce.com/products/square/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) and [Amazon Pay](https://woocommerce.com/products/pay-with-amazon/?utm_source=wp%20org%20repo%20listing&utm_content=3.6). [Apple Pay](https://woocommerce.com/apple-pay/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) and Google Pay are also supported.
With WooCommerce, your data belongs to you. Always.
Search for your payment service provider of choice on the [official marketplace](https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
If you opt to share [usage data](https://woocommerce.com/usage-tracking/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) with us, you can feel confident knowing that its anonymized and kept secure. Choose to opt-out at any time without impacting your store.
= Ship locally and globally =
Shipping with WooCommerce is highly configurable. Adjust the built-in settings to offer free shipping or flat rate shipping, limit your shipments to specific countries by setting up shipping zones, or open your store up to the world.
Unlike hosted eCommerce solutions, WooCommerce store data is future-proof; should you wish to migrate to a different platform, youre free to export all your content and take your site wherever you choose. No restrictions.
Official extensions connect you with hundreds of local and international carriers including [Royal Mail](https://woocommerce.com/products/royal-mail/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [FedEx](https://woocommerce.com/products/fedex-shipping-module/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), and [Australia Post](https://woocommerce.com/products/australia-post-shipping-method/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) and let you integrate with [inventory management and fulfilment providers](https://woocommerce.com/product-category/woocommerce-extensions/shipping-methods/inventory-fulfillment/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
= Why developers choose (and love) WooCommerce =
There are also extensions available to add [delivery and shipping options](https://woocommerce.com/product-category/woocommerce-extensions/shipping-methods/delivery-shipping-options/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) and support strategies like buy-one-get-one free, free gifts, and add-ons. [WooCommerce Shipping](https://woocommerce.com/products/shipping/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) supports real-time calculations and printing labels at home.
Developers can use WooCommerce to create, customize, and scale a store to meet a clients exact specifications, making enhancements through extensions or custom solutions.
= Design your store with themes and blocks =
- Leverage [hooks and filters](https://docs.woocommerce.com/document/introduction-to-hooks-actions-and-filters/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) to modify or create functionality.
- Integrate virtually any service using a robust [REST API](https://docs.woocommerce.com/document/woocommerce-rest-api/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) and webhooks.
- Design and build custom content blocks with React.
- [Inspect and modify](https://docs.woocommerce.com/documentation/plugins/woocommerce/woocommerce-codex/extending/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) any aspect of the core plugin code.
- Speed up development with a lightning-fast [CLI](https://woocommerce.github.io/code-reference/classes/wc-cli-rest-command.html?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
WooCommerce store design starts with a theme of your choice. There are hundreds of free and paid themes available, including [Storefront](https://woocommerce.com/storefront/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) by Automattic -- it's free to all stores and you can choose to have it installed for you during the guided setup.
The core platform is tested rigorously and often, supported by a dedicated development team working across time zones. Comprehensive documentation is updated with each release, empowering you to build exactly the store required.
Storefront offers deep WooCommerce integration and prioritizes speed and uptime. You can add your brand and define your style by customizing Storefront yourself or adding one of several industry-themed [Storefront child themes](https://woocommerce.com/product-category/themes/storefront-child-theme-themes/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
= Be part of our growing international community =
Personalize your store's design even more with WooCommerce Blocks (available in WooCommerce 3.6 and above) -- use them to add selections of or single products to any page, for a seamless blending of commerce into content.
WooCommerce has a large, passionate community dedicated to helping merchants succeed, and its growing fast.
= Customize your store with extensions =
There are [WooCommerce Meetups](https://woocommerce.com/meetups/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) in locations around the world that you can attend for free and even get involved in running. These events are a great way to learn from others, share your expertise, and connect with like-minded folks.
The easiest way to add features and functionality to a WooCommerce store is with an extension:
WooCommerce also has a regular presence at WordCamps across the globe wed love to meet you.
- Sell anything - [Subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Memberships](https://woocommerce.com/products/woocommerce-memberships/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Bookings](https://woocommerce.com/products/woocommerce-bookings/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Product Bundles](https://woocommerce.com/products/product-bundles/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), and [more](https://woocommerce.com/product-category/woocommerce-extensions/product-type/).
- Make your store, your way - [Product Add-Ons](https://woocommerce.com/products/product-add-ons/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Checkout Field Editor](https://woocommerce.com/products/woocommerce-checkout-field-editor/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Additional Variation Images](https://woocommerce.com/products/woocommerce-additional-variation-images/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), and [more](https://woocommerce.com/customize-product-pages?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
- Customize your shipping options - [Table Rate Shipping](https://woocommerce.com/products/table-rate-shipping/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Shipment Tracking](https://woocommerce.com/products/shipment-tracking/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), live rates from [top carriers](https://woocommerce.com/product-category/woocommerce-extensions/shipping-methods/shipping-carriers/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), and [more](https://woocommerce.com/product-category/woocommerce-extensions/shipping-methods/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
- Find your audience, market to them your way - [Google Product Feed](https://woocommerce.com/products/google-product-feed/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [LiveChat](https://woocommerce.com/products/livechat/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Amazon/eBay marketplace integration](https://woocommerce.com/products/amazon-ebay-integration/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), and [more](https://woocommerce.com/product-category/woocommerce-extensions/marketing-extensions/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
- Drive sales [Dynamic Pricing](https://woocommerce.com/products/dynamic-pricing/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Smart Coupons](https://woocommerce.com/products/smart-coupons/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), [Google Ads](https://woocommerce.com/products/google-ads/?utm_source=wp%20org%20repo%20listing&utm_content=3.6), and [more](https://woocommerce.com/product-category/woocommerce-extensions/marketing-extensions/promotions/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
= Contribute and translate =
There are hundreds of official extensions reviewed by WooCommerce developers available on the WooCommerce.com marketplace, and many in the WordPress.org repository and on the wider web.
WooCommerce is developed and supported by Automattic, the creators of WordPress.com and Jetpack. We also have hundreds of independent contributors, and theres always room for more. Head to the [WooCommerce GitHub Repository](https://github.com/woocommerce/woocommerce?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) to find out how you can pitch in.
= Control your data forever =
WooCommerce gives you complete control from taxes to stock levels to customer accounts. Add and remove extensions, change your stores design, and switch themes or hosts or payment service providers, all as you please.
In a world increasingly aware of the importance of data protection, WooCommerce gives you full ownership over what is tracked and stored. If you opt to share [usage data](https://woocommerce.com/usage-tracking/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) with us, your data is anonymized and kept secure. At any stage, you can opt out of all forms of tracking while still enjoying all of WooCommerce's capabilities.
With WooCommerce, your data belongs to you. One of the risks of using a hosted eCommerce platform the risk of losing your store if the provider closes. WooCommerce store data is future-proof -- youre are free to export all your content and take your site wherever you choose.
= Why developers like WooCommerce =
WooCommerce was originally created with developers in mind. Built with a REST API, it integrates with virtually any service. Store data can be accessed anywhere, anytime, 100% securely.
WooCommerce allows developers to easily create, modify, and scale a store that meets clients specifications, and to make enhancements either with extensions or with customs solution.
No matter the size of the store you want to build, WooCommerce has a robust framework that supports stores from basic to enterprise with content and commerce in a single, central location.
WooCommerce is audited by a dedicated team of developers who work across time zones to identify and patch any and all discovered bugs. There is comprehensive, easily-accessible documentation that is updated with each release. With our docs, youll learn how to create the site your client needs.
= Join our growing community =
WooCommerce is one of the fastest-growing eCommerce communities. Were proud that the helpfulness of the community and wealth of resources available online are frequently cited as reasons our users love it.
There are 80+ [WooCommerce Meetups](https://woocommerce.com/woocommerce/meetups/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) taking place in cities across the world that you can attend for free and even get involved in running. WooCommerce also has a regular presence at WordCamps across the globe and wed love to meet you.
If youre interested in contributing to WooCommerce weve got more than 350 contributors, and theres always room for more. Head to the [WooCommerce GitHub Repository](https://github.com/woocommerce/woocommerce?utm_source=wp%20org%20repo%20listing&utm_content=3.6) to find out how you can pitch in.
WooCommerce is currently 100% translated into 24 languages, including Danish, Ukrainian, and Persian. If youre interested in helping to localize WooCommerce by adding your local language, visit [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/woocommerce?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
WooCommerce is translated into multiple languages, including Danish, Ukrainian, and Persian. Help localize WooCommerce even further by adding your locale visit [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/woocommerce/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
== Frequently Asked Questions ==
= Where can I find WooCommerce documentation and user guides? =
For help setting up and configuring WooCommerce please refer to our [user guide](https://docs.woocommerce.com/documentation/plugins/woocommerce/getting-started/?utm_source=wp%20org%20repo%20listing&utm_content=3.6)
For help setting up and configuring WooCommerce, please refer to [Getting Started](https://docs.woocommerce.com/documentation/plugins/woocommerce/getting-started/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) and the [New WooCommerce Store Owner Guide](https://woocommerce.com/guides/new-store/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
For extending or theming WooCommerce, see our [codex](https://docs.woocommerce.com/documentation/plugins/woocommerce/woocommerce-codex/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
For extending or theming WooCommerce, see our [codex](https://docs.woocommerce.com/documentation/plugins/woocommerce/woocommerce-codex/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), as well as the [Plugin Developer Handbook](https://docs.woocommerce.com/document/create-a-plugin/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
= Where can I get support or talk to other users? =
= Where can I get help or talk to other users about WooCommerce Core? =
If you get stuck, you can ask for help in the [WooCommerce Plugin Forum](https://wordpress.org/support/plugin/woocommerce).
If you get stuck, you can ask for help in the [WooCommerce Support Forum](https://wordpress.org/support/plugin/woocommerce/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) by following [these guidelines](https://wordpress.org/support/topic/guide-to-the-woocommerce-forum/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), reach out via the [WooCommerce Community Slack](https://woocommerce.com/community-slack/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), or post in the [WooCommerce Community group](https://www.facebook.com/groups/advanced.woocommerce?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) on Facebook.
For help with paid extensions from WooCommerce.com, use [our helpdesk](https://woocommerce.com/my-account/tickets/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
= Where can I get help for extensions I have purchased on WooCommerce.com? =
For assistance with paid extensions from the WooCommerce.com Marketplace: first, review our [self-service troubleshooting guide](https://docs.woocommerce.com/document/woocommerce-self-service-guide/). If the problem persists, kindly log a support ticket via [our helpdesk](https://woocommerce.com/my-account/create-a-ticket/). Our dedicated Happiness Engineers aim to respond within 24 hours.
= Im having trouble logging in to WooCommerce.com what now? =
First, troubleshoot common login issues using this helpful [step-by-step guide](https://docs.woocommerce.com/document/log-into-woocommerce-com-with-wordpress-com/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing). Still not working? [Get in touch with us](https://woocommerce.com/contact-us/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
= Will WooCommerce work with my theme? =
Yes! WooCommerce will work with any theme, but may require some styling. Please see our [codex](https://docs.woocommerce.com/documentation/plugins/woocommerce/woocommerce-codex/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) for help. If you're looking for a theme with built in WooCommerce integration we recommend [Storefront](https://woocommerce.com/storefront/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
Yes! WooCommerce will work with any theme but may require some additional styling. If youre looking for a theme featuring deep WooCommerce integration, we recommend [Storefront](https://woocommerce.com/storefront/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
= Where can I request new features, eCommerce themes, and extensions? =
= How do I update WooCommerce? =
You can vote on and request new features and extensions on our [WooIdeas board](http://ideas.woocommerce.com/forums/133476-woocommerce?utm_source=wp%20org%20repo%20listing&utm_content=3.6)
We have a detailed guide on [How To Update WooCommerce](https://docs.woocommerce.com/document/how-to-update-woocommerce/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
= Where can I report bugs or contribute to the project? =
= My site broke what do I do? =
Report bugs on the [WooCommerce GitHub repository](https://github.com/woocommerce/woocommerce/issues?utm_source=wp%20org%20repo%20listing&utm_content=3.6). You can also report them in our [support forum](https://wordpress.org/support/plugin/woocommerce).
Start by diagnosing the issue using our helpful [troubleshooting guide](https://docs.woocommerce.com/documentation/get-help/troubleshooting-get-help/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
If you noticed the error after updating a theme or plugin, there might be compatibility issues between it and WooCommerce. If the issue appeared after updating WooCommerce, there could be a conflict between WooCommerce and an outdated theme or plugin.
= Where can I find the REST API documentation? =
In both instances, we recommend running a conflict test using [Health Check](https://docs.woocommerce.com/document/troubleshooting-using-health-check/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) (which allows you to disable themes and plugins without affecting your visitors) or troubleshooting the issue using a [staging site](https://docs.woocommerce.com/document/how-to-test-for-conflicts/#section-3?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
You can find the documentation of our REST API on the [WooCommerce REST API Docs](https://woocommerce.github.io/woocommerce-rest-api-docs/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
= Where can I report bugs? =
Report bugs on the [WooCommerce GitHub repository](https://github.com/woocommerce/woocommerce/issues?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing). You can also notify us via our support forum be sure to search the forums to confirm that the error has not already been reported.
= Where can I request new features, themes, and extensions? =
Request new features and extensions and vote on existing suggestions on our official [ideas board](https://ideas.woocommerce.com/forums/133476-woocommerce?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing). Our Product teams regularly review requests and consider them valuable for product planning.
= WooCommerce is awesome! Can I contribute? =
Yes you can! Join in on our [GitHub repository](https://github.com/woocommerce/woocommerce/?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
Yes, you can! Join in on our [GitHub repository](https://github.com/woocommerce/woocommerce/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) and follow the [development blog](https://woocommerce.wordpress.com/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) to stay up-to-date with everything happening in the project.
= Where can I find REST API documentation? =
Extensive [WooCommerce REST API Documentation](https://woocommerce.github.io/woocommerce-rest-api-docs/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) is available on GitHub.
= My question is not listed here. Where can I find more answers? =
Check out [Frequently Asked Questions](https://docs.woocommerce.com/document/frequently-asked-questions/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) for more.
== Installation ==
@ -171,15 +158,12 @@ If you encounter issues with the shop/category pages after an update, flush the
WooCommerce comes with some sample data you can use to see how products look; import sample_products.xml via the [WordPress importer](https://wordpress.org/plugins/wordpress-importer/). You can also use the core [CSV importer](https://docs.woocommerce.com/document/product-csv-importer-exporter/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) or our [CSV Import Suite extension](https://woocommerce.com/products/product-csv-import-suite/?utm_source=wp%20org%20repo%20listing&utm_content=3.6) to import sample_products.csv
== Contributors & Developers ==
“WooCommerce” has been translated into 55 locales. Thank you to [the translators](https://translate.wordpress.org/projects/wp-plugins/woocommerce/contributors) for their contributions. [Translate “WooCommerce” into your language](https://translate.wordpress.org/projects/wp-plugins/woocommerce?utm_source=wp%20org%20repo%20listing&utm_content=3.6).
INTERESTED IN DEVELOPMENT?
[Browse the code](https://plugins.trac.wordpress.org/browser/woocommerce/), check out the [SVN repository](https://plugins.svn.wordpress.org/woocommerce/), or subscribe to the [development log](https://plugins.trac.wordpress.org/log/woocommerce/) by [RSS](https://plugins.trac.wordpress.org/log/woocommerce/?limit=100&mode=stop_on_copy&format=rss).
== Changelog ==
= 4.5.1 - 2020-09-09 =
**WooCommerce**
* Fix - Check for state and postcode fields only if required in `show_shipping`. #27628
= 4.5.0 - 2020-09-08 =
@ -187,6 +171,8 @@ INTERESTED IN DEVELOPMENT?
* Localization - Added postcode validation for Bosnia and Herzegovina. #27048
* Localization - Added the postcode validation for Liechtenstein. #27059
* Localization - Add i18n locale information for Liechtenstein, Switzerland and Austria. #27193
* Tweak - Increase priority of `admin_body_class` filter to avoid comflict with plugins that incorrectly remove all body classes from WP. #27426
* Tweak - Rename built-in PayPal payment method to PayPal Standard. #27468
* Fix - Remove whitespace within a link. #26897
* Fix - `get_review_count_for_product` return all comments count not only 'review' types #26928
* Fix - Hidden field type is now supported by `woocommerce_form_field`. #27023
@ -199,6 +185,10 @@ INTERESTED IN DEVELOPMENT?
* Fix - Fixes Japan zip code format issue (dash is now optional). #27244
* Fix - Restore backward compatibility with WC 4.x and forward compatibility with WC 5.5. #27318
* Fix - Switch to site locale before translating refund reason. #27323
* Fix - Declare `WC_Post_Types::updated_term_messages` as a static method to remove PHP deprecation warning. #27436
* Fix - Allow HTML to be entered in product title for formatting purposes. #27465
* Fix - Filter by attribute widget not working properly for variations having attribute values of "Any...". #27508
* Fix - Fixed the layout of the variations and attributes sections in the product page in the admin when running WP >= 5.5. #27590
* Dev - Added additional stock-based cart filters including `woocommerce_cart_product_cannot_add_another_message`, `woocommerce_cart_product_out_of_stock_message`, and `woocommerce_cart_product_not_enough_stock_message`. #26439
* Dev - Changed text domain to `woocommerce` for REST API files. #27248
* Dev - Added file path to the `woocommerce_file_download_method` filter. #27152
@ -207,7 +197,7 @@ INTERESTED IN DEVELOPMENT?
**WooCommerce Admin 1.5.0**
* Enhancement - Add eWAY to Payment Setup for AU/NZ Stores. #4947
* Fix - Use clipRule and fillRule props. #4889, part of #4864
* Tweak: Remove the Composite products option from the onboarding wizard #4703
* Fix - Admin order page shipping label prompt compatibility with WCS 1.24. #5025
* Dev - New notification: Don't forget to test your checkout. #4805
* Dev - Enable tax calculation before redirecting to standard tax rates page. #4878
* Dev - Added event recording to Orders, Stock, and Reviews panels. #4861

View File

@ -25,7 +25,15 @@ do_action( 'woocommerce_cart_is_empty' );
if ( wc_get_page_id( 'shop' ) > 0 ) : ?>
<p class="return-to-shop">
<a class="button wc-backward" href="<?php echo esc_url( apply_filters( 'woocommerce_return_to_shop_redirect', wc_get_page_permalink( 'shop' ) ) ); ?>">
<?php esc_html_e( 'Return to shop', 'woocommerce' ); ?>
<?php
/**
* Filter "Return To Shop" text.
*
* @since 4.6.0
* @param string $default_text Default text.
*/
echo esc_html( apply_filters( 'woocommerce_return_to_shop_text', __( 'Return To Shop', 'woocommerce' ) ) );
?>
</a>
</p>
<?php endif; ?>

View File

@ -11,8 +11,8 @@
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce\Templates
* @version 4.4.0
* @package WooCommerce/Templates
* @version 3.8.0
*/
defined( 'ABSPATH' ) || exit;
@ -77,9 +77,9 @@ do_action( 'woocommerce_before_cart' ); ?>
<td class="product-name" data-title="<?php esc_attr_e( 'Product', 'woocommerce' ); ?>">
<?php
if ( ! $product_permalink ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', esc_html( $_product->get_name() ), $cart_item, $cart_item_key ) . '&nbsp;' );
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . '&nbsp;' );
} else {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '<a href="%s">%s</a>', esc_url( $product_permalink ), esc_html( $_product->get_name() ) ), $cart_item, $cart_item_key ) );
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '<a href="%s">%s</a>', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
}
do_action( 'woocommerce_after_cart_item_name', $cart_item, $cart_item_key );

View File

@ -20,7 +20,7 @@ defined( 'ABSPATH' ) || exit;
global $product;
// Ensure visibility.
if ( empty( $product ) || false === wc_get_loop_product_visibility( $product->get_id() ) || ! $product->is_visible() ) {
if ( empty( $product ) || ! $product->is_visible() ) {
return;
}
?>

View File

@ -76,6 +76,7 @@ body {
#template_header h1,
#template_header h1 a {
color: <?php echo esc_attr( $base_text ); ?>;
background-color: inherit;
}
#template_header_image img {

View File

@ -12,7 +12,7 @@
*
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce\Templates
* @version 3.7.0
* @version 4.6.0
*/
defined( 'ABSPATH' ) || exit;
@ -101,6 +101,14 @@ if ( $show_downloads ) {
</section>
<?php
/**
* Action hook fired after the order details.
*
* @since 4.4.0
* @param WC_Order $order Order data.
*/
do_action( 'woocommerce_after_order_details', $order );
if ( $show_customer_details ) {
wc_get_template( 'order/order-details-customer.php', array( 'order' => $order ) );
}

View File

@ -10,16 +10,13 @@
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce\Templates
* @version 4.4.0
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce/Templates
* @version 1.6.4
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
?>
<h1 class="product_title entry-title">
<?php echo esc_html( get_the_title() ); ?>
</h1>
the_title( '<h1 class="product_title entry-title">', '</h1>' );

View File

@ -7,10 +7,10 @@ if [[ ${RUN_PHPCS} == 1 ]]; then
if [ "$CHANGED_FILES" != "" ]; then
if [ ! -f "./vendor/bin/phpcs" ]; then
# Install wpcs globally
composer require woocommerce/woocommerce-sniffs --update-with-all-dependencies
composer global require woocommerce/woocommerce-sniffs --update-with-all-dependencies
fi
echo "Running Code Sniffer."
./vendor/bin/phpcs --ignore=$IGNORE --encoding=utf-8 -s -n -p $CHANGED_FILES
phpcs --ignore=$IGNORE --encoding=utf-8 -s -n -p $CHANGED_FILES
fi
fi

View File

@ -130,16 +130,16 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface {
private static function terminate_proc( $proc ) {
$status = proc_get_status( $proc );
$master_pid = $status['pid'];
$pid = $status['pid'];
$output = `ps -o ppid,pid,command | grep $master_pid`;
$output = `ps -o ppid,pid,command | grep $pid`;
foreach ( explode( PHP_EOL, $output ) as $line ) {
if ( preg_match( '/^\s*(\d+)\s+(\d+)/', $line, $matches ) ) {
$parent = $matches[1];
$child = $matches[2];
if ( $parent == $master_pid ) {
if ( $parent == $pid ) {
if ( ! posix_kill( (int) $child, 9 ) ) {
throw new RuntimeException( posix_strerror( posix_get_last_error() ) );
}
@ -147,7 +147,7 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface {
}
}
if ( ! posix_kill( (int) $master_pid, 9 ) ) {
if ( ! posix_kill( (int) $pid, 9 ) ) {
throw new RuntimeException( posix_strerror( posix_get_last_error() ) );
}
}

View File

@ -10,7 +10,7 @@ if [[ $1 ]]; then
if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+ ]]; then
export WORDPRESS_VERSION=$WP_VERSION
else
export WORDPRESS_VERSION="5.4.2"
export WORDPRESS_VERSION="5.5.1"
fi
if ! [[ $TRAVIS_PHP_VERSION =~ ^[0-9]+\.[0-9]+ ]]; then
@ -20,7 +20,7 @@ if [[ $1 ]]; then
if [[ $TRAVIS_PHP_VERSION =~ ^[0-9]+\.[0-9]+ ]]; then
export DC_PHP_VERSION=$TRAVIS_PHP_VERSION
else
export DC_PHP_VERSION="7.4.8"
export DC_PHP_VERSION="7.4.9"
fi
if ! [[ $TRAVIS_MARIADB_VERSION =~ ^[0-9]+\.[0-9]+ ]]; then
@ -30,7 +30,7 @@ if [[ $1 ]]; then
if [[ $TRAVIS_MARIADB_VERSION =~ ^[0-9]+\.[0-9]+ ]]; then
export DC_MARIADB_VERSION=$TRAVIS_MARIADB_VERSION
else
export DC_MARIADB_VERSION="10.5.4"
export DC_MARIADB_VERSION="10.5.5"
fi
if [[ $1 == 'up' ]]; then

View File

@ -33,7 +33,6 @@ if $(wp core is-installed);
then
echo "Wordpress is already installed..."
else
WORDPRESS_INSTALLING=1
declare -p WORDPRESS_TITLE >/dev/null
declare -p WORDPRESS_LOGIN >/dev/null
declare -p WORDPRESS_PASSWORD >/dev/null
@ -62,8 +61,10 @@ if ! [[ ${CURRENT_DOMAIN} == ${URL} ]]; then
wp search-replace ${CURRENT_DOMAIN} ${URL}
fi
if [[ $WORDPRESS_INSTALLING ]];
if $(wp post list --post_type=page --name=ready);
then
echo "Ready page already exists..."
else
wp post create \
--url=${URL} \
--post_type=page \

11585
tests/e2e/env/package-lock.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

218
tests/e2e/utils/package-lock.json generated Normal file
View File

@ -0,0 +1,218 @@
{
"name": "@woocommerce/e2e-utils",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/runtime": {
"version": "7.11.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
"integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"@tannin/compile": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.1.0.tgz",
"integrity": "sha512-n8m9eNDfoNZoxdvWiTfW/hSPhehzLJ3zW7f8E7oT6mCROoMNWCB4TYtv041+2FMAxweiE0j7i1jubQU4MEC/Gg==",
"requires": {
"@tannin/evaluate": "^1.2.0",
"@tannin/postfix": "^1.1.0"
}
},
"@tannin/evaluate": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.2.0.tgz",
"integrity": "sha512-3ioXvNowbO/wSrxsDG5DKIMxC81P0QrQTYai8zFNY+umuoHWRPbQ/TuuDEOju9E+jQDXmj6yI5GyejNuh8I+eg=="
},
"@tannin/plural-forms": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.1.0.tgz",
"integrity": "sha512-xl9R2mDZO/qiHam1AgMnAES6IKIg7OBhcXqy6eDsRCdXuxAFPcjrej9HMjyCLE0DJ/8cHf0i5OQTstuBRhpbHw==",
"requires": {
"@tannin/compile": "^1.1.0"
}
},
"@tannin/postfix": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.1.0.tgz",
"integrity": "sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw=="
},
"@wordpress/e2e-test-utils": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-4.6.0.tgz",
"integrity": "sha512-oqnFEOuWkUFwzSVGeKZOfs9YhWVyCKdsOtJKnXd6Vv5Q1quq2fmbDp6HL+dIUI2DlJZISUmOWG4B37mMVA0DLg==",
"requires": {
"@babel/runtime": "^7.9.2",
"@wordpress/keycodes": "^2.12.0",
"@wordpress/url": "^2.14.0",
"lodash": "^4.17.15",
"node-fetch": "^1.7.3"
}
},
"@wordpress/i18n": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-3.15.0.tgz",
"integrity": "sha512-AawJgHEGPyMoPATl8a3Qa+cCZV3S6azPfvqeStbN2pSc7v0HqYhJhWaw80WToHkN4kyOsfu1PUVf1wefuoMNEA==",
"requires": {
"@babel/runtime": "^7.9.2",
"gettext-parser": "^1.3.1",
"lodash": "^4.17.19",
"memize": "^1.1.0",
"sprintf-js": "^1.1.1",
"tannin": "^1.2.0"
}
},
"@wordpress/keycodes": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-2.15.0.tgz",
"integrity": "sha512-XHyBmhzWjp0svzwiGLOwovlQHH42KkACKTfakDizB5OaaAzlmgZ34Fdl03S7pWl+HUBa7MqItRhGsd4kxdo0bQ==",
"requires": {
"@babel/runtime": "^7.9.2",
"@wordpress/i18n": "^3.15.0",
"lodash": "^4.17.19"
}
},
"@wordpress/url": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/@wordpress/url/-/url-2.18.0.tgz",
"integrity": "sha512-FX6CYVG8vYgQnxjA9SsWTDAWPHarPSBIGk2shZ3I+cq+LV31dDaAz8OhvVMD6rvUoQW0INlWe1t2JKXoHhcTcw==",
"requires": {
"@babel/runtime": "^7.9.2",
"lodash": "^4.17.19",
"qs": "^6.5.2",
"react-native-url-polyfill": "^1.1.2"
}
},
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"buffer": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
"integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
},
"encoding": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
"requires": {
"iconv-lite": "^0.6.2"
}
},
"gettext-parser": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz",
"integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==",
"requires": {
"encoding": "^0.1.12",
"safe-buffer": "^5.1.1"
}
},
"iconv-lite": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"memize": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/memize/-/memize-1.1.0.tgz",
"integrity": "sha512-K4FcPETOMTwe7KL2LK0orMhpOmWD2wRGwWWpbZy0fyArwsyIKR8YJVz8+efBAh3BO4zPqlSICu4vsLTRRqtFAg=="
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"qs": {
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"react-native-url-polyfill": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.2.0.tgz",
"integrity": "sha512-hpLZ8RyS3oGVyTOe/HjoqVoCOSkeJvrCoEB3bJsY7t9uh7kpQDV6kgvdlECEafYpxe3RzMrKLVcmWRbPU7CuAw==",
"requires": {
"whatwg-url-without-unicode": "8.0.0-3"
}
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sprintf-js": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
},
"tannin": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/tannin/-/tannin-1.2.0.tgz",
"integrity": "sha512-U7GgX/RcSeUETbV7gYgoz8PD7Ni4y95pgIP/Z6ayI3CfhSujwKEBlGFTCRN+Aqnuyf4AN2yHL+L8x+TCGjb9uA==",
"requires": {
"@tannin/plural-forms": "^1.1.0"
}
},
"webidl-conversions": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
"integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
},
"whatwg-url-without-unicode": {
"version": "8.0.0-3",
"resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
"integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==",
"requires": {
"buffer": "^5.4.3",
"punycode": "^2.1.1",
"webidl-conversions": "^5.0.0"
}
}
}
}

View File

@ -90,10 +90,10 @@ const completeOnboardingWizard = async () => {
// Query for the industries checkboxes
const industryCheckboxes = await page.$$( '.components-checkbox-control__input' );
expect( industryCheckboxes ).toHaveLength( 10 );
expect( industryCheckboxes ).toHaveLength( 9 );
// Select all industries including "Other"
for ( let i = 0; i < 10; i++ ) {
for ( let i = 0; i < 9; i++ ) {
await industryCheckboxes[i].click();
}
@ -115,7 +115,7 @@ const completeOnboardingWizard = async () => {
// Query for the product types checkboxes
const productTypesCheckboxes = await page.$$( '.components-checkbox-control__input' );
expect( productTypesCheckboxes ).toHaveLength( 8 );
expect( productTypesCheckboxes ).toHaveLength( 7 );
// Select Physical and Downloadable products
for ( let i = 1; i < 2; i++ ) {
@ -149,9 +149,14 @@ const completeOnboardingWizard = async () => {
await page.waitForSelector( '.woocommerce-select-control__control' );
await expect( page ).toClick( '.woocommerce-select-control__option', { text: config.get( 'onboardingwizard.sellingelsewhere' ) } );
// Disable business extension downloads
const pluginToggle = await page.$( '.woocommerce-business-extensions .components-checkbox-control__input-container' );
pluginToggle.click();
// Query for the extensions toggles
const extensionsToggles = await page.$$( '.components-form-toggle__input' );
expect( extensionsToggles ).toHaveLength( 3 );
// Disable download of the 3 extensions
for ( let i = 0; i < 3; i++ ) {
await extensionsToggles[i].click();
}
// Wait for "Continue" button to become active
await page.waitForSelector( 'button.is-primary:not(:disabled)' );
@ -189,16 +194,26 @@ const completeOnboardingWizard = async () => {
// End of onboarding wizard
// Wait for "Woo-hoo almost there" window to appear
await page.waitForSelector( '.components-modal__header-heading' );
// Wait for homescreen welcome modal to appear
await page.waitForSelector( '.woocommerce__welcome-modal__page-content__header' );
await expect( page ).toMatchElement(
'.components-modal__header-heading', { text: 'Woo hoo - you\'re almost there!' }
'.woocommerce__welcome-modal__page-content__header', { text: 'Welcome to your WooCommerce store\s online HQ!' }
);
// Wait for "Continue" button to become active
await page.waitForSelector( 'button.is-primary:not(:disabled)' );
// Click on "Continue" button to move to the next step
await page.click( 'button.is-primary:not(:disabled)' );
// Wait for "Next" button to become active
await page.waitForSelector( 'button.components-guide__forward-button' );
// Click on "Next" button to move to the next step
await page.click( 'button.components-guide__forward-button' );
// Wait for "Next" button to become active
await page.waitForSelector( 'button.components-guide__forward-button' );
// Click on "Next" button to move to the next step
await page.click( 'button.components-guide__forward-button' );
// Wait for "Let's go" button to become active
await page.waitForSelector( 'button.components-guide__finish-button' );
// Click on "Let's go" button to move to the next step
await page.click( 'button.components-guide__finish-button' );
};
/**

View File

@ -2248,7 +2248,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
// Attempt adding variation with add_to_cart_action, without specifying attribute_pa_colour.
$_REQUEST['add-to-cart'] = $variation['variation_id'];
$_REQUEST['attribute_pa_number'] = '0';
$_REQUEST['attribute_pa_number'] = '';
WC_Form_Handler::add_to_cart_action( false );
$notices = WC()->session->get( 'wc_notices', array() );

View File

@ -13,7 +13,7 @@ class WC_Tests_Customer_Functions extends WC_Unit_Test_Case {
/**
* Set illegal login
*
* @param array $logins Array of blacklisted logins.
* @param array $logins Array of blocked logins.
* @return array
*/
public function setup_illegal_user_logins( $logins ) {

View File

@ -176,199 +176,4 @@ class WC_Tests_Product_Variable extends WC_Unit_Test_Case {
$this->assertEquals( $expected_stock_status, $product->get_stock_status() );
}
/**
* Setup for a test for is_visible.
*
* @param array $filtering_attributes Simulated filtering attributes as an array of attribute_name => [term1, term2...].
* @param bool $hide_out_of_stock_products Should the woocommerce_hide_out_of_stock_items option be set?.
* @param bool $is_visible_from_parent Return value of is_visible from base class.
*
* @return WC_Product_Variable A properly configured instance of WC_Product_Variable to test.
*/
private function prepare_visibility_test( $filtering_attributes, $hide_out_of_stock_products = true, $is_visible_from_parent = true ) {
foreach ( $filtering_attributes as $attribute_name => $terms ) {
$filtering_attributes[ $attribute_name ]['query_type'] = 'ANY_QUERY_TYPE';
$filtering_attributes[ $attribute_name ]['terms'] = $terms;
}
update_option( 'woocommerce_hide_out_of_stock_items', $hide_out_of_stock_products ? 'yes' : 'no' );
$sut = $this
->getMockBuilder( WC_Product_Variable::class )
->setMethods( array( 'parent_is_visible_core', 'get_layered_nav_chosen_attributes' ) )
->getMock();
$sut = WC_Helper_Product::create_variation_product( $sut, true );
$sut->save();
$sut->method( 'parent_is_visible_core' )->willReturn( $is_visible_from_parent );
$sut->method( 'get_layered_nav_chosen_attributes' )->willReturn( $filtering_attributes );
return $sut;
}
/**
* Configure the stock status for the attribute-based variations of a product.
*
* @param WC_Product_Variable $product Product with the variations to configure.
* @param array $attributes An array of attribute_name => [attribute_values], only the matching variations will have stock.
*/
private function set_variations_with_stock( $product, $attributes ) {
$variation_ids = $product->get_children();
foreach ( $variation_ids as $id ) {
$variation = wc_get_product( $id );
$attribute_matches = true;
foreach ( $attributes as $name => $values ) {
if ( ! in_array( $variation->get_attribute( $name ), $values, true ) ) {
$attribute_matches = false;
}
}
$variation->set_stock_status( $attribute_matches ? 'instock' : 'outofstock' );
$variation->save();
}
}
/**
* @testdox The product should be invisible when the parent 'is_visible' method returns false.
*/
public function test_is_invisible_when_parent_is_visible_returns_false() {
$sut = $this->prepare_visibility_test( array(), '', false, false );
$this->assertFalse( $sut->is_visible() );
}
/**
* @testdox The product should be visible when no nav filtering is supplied if at least one variation has stock.
*
* Note that if no variations have stock the base is_visible will already return false.
*/
public function test_is_visible_when_no_filtering_supplied_and_at_least_one_variation_has_stock() {
$sut = $this->prepare_visibility_test( array(), '' );
$this->set_variations_with_stock( $sut, array( 'pa_size' => array( 'small' ) ) );
$this->assertTrue( $sut->is_visible() );
}
/**
* @testdox Test product visibility when the variation requested in nav filtering has no stock, result depends on woocommerce_hide_out_of_stock_items option.
*
* @param bool $hide_out_of_stock Value for woocommerce_hide_out_of_stock_items.
* @param bool $expected_visibility Expected value of is_visible for the tested product.
*
* @testWith [true, false]
* [false, true]
*/
public function test_visibility_when_supplied_filter_has_no_stock( $hide_out_of_stock, $expected_visibility ) {
$sut = $this->prepare_visibility_test( array( 'pa_size' => array( 'large' ) ), $hide_out_of_stock );
$this->set_variations_with_stock( $sut, array( 'pa_size' => array( 'small' ) ) );
$this->assertEquals( $expected_visibility, $sut->is_visible() );
}
/**
* @testdox Product should always be visible when only one of the variations requested in nav filtering has stock.
*
* @param bool $hide_out_of_stock Value for woocommerce_hide_out_of_stock_items.
*
* @testWith [true]
* [false]
*/
public function test_visibility_when_multiple_filter_values_supplied_and_only_one_has_stock( $hide_out_of_stock ) {
$sut = $this->prepare_visibility_test( array( 'pa_size' => array( 'small', 'large' ) ), $hide_out_of_stock );
$this->set_variations_with_stock( $sut, array( 'pa_size' => array( 'small' ) ) );
$this->assertTrue( $sut->is_visible() );
}
/**
* @testdox Product should be visible when all of the variations requested in nav filtering have stock.
*
* @param bool $hide_out_of_stock Value for woocommerce_hide_out_of_stock_items.
*
* @testWith [true]
* [false]
*/
public function test_visibility_when_multiple_filter_values_supplied_and_all_of_them_have_stock( $hide_out_of_stock ) {
$sut = $this->prepare_visibility_test( array( 'pa_size' => array( 'small', 'large' ) ), $hide_out_of_stock );
$this->set_variations_with_stock( $sut, array( 'pa_size' => array( 'small', 'large' ) ) );
$this->assertTrue( $sut->is_visible() );
}
/**
* @testdox Product should be visible when multiple filters are present, and there's a variation matching all of them.
*/
public function test_visibility_when_multiple_filters_are_used_and_all_of_them_match() {
$sut = $this->prepare_visibility_test(
array(
'pa_size' => array( 'huge' ),
'pa_colour' => array( 'blue' ),
),
true
);
$this->set_variations_with_stock(
$sut,
array(
'pa_size' => array( 'huge' ),
'pa_colour' => array( 'blue' ),
'pa_number' => array( '2' ),
)
);
$this->assertTrue( $sut->is_visible() );
}
/**
* @testdox Product should not be visible when multiple filters are present, and there are no variations matching all of them.
*/
public function test_visibility_when_multiple_filters_are_used_and_one_of_them_does_not_match() {
$sut = $this->prepare_visibility_test(
array(
'pa_size' => array( 'small', 'huge' ),
'pa_colour' => array( 'red' ),
),
true
);
$this->set_variations_with_stock(
$sut,
array(
'pa_size' => array( 'huge' ),
'pa_colour' => array( 'blue' ),
'pa_number' => array( '2' ),
)
);
$this->assertFalse( $sut->is_visible() );
}
/**
* @testdox Attributes having "Any..." as value should not count when searching for matching attributes.
*/
public function test_visibility_when_multiple_filters_are_used_and_an_attribute_has_any_value() {
$sut = $this->prepare_visibility_test(
array(
'pa_size' => array( 'huge' ),
'pa_number' => array( '34' ),
),
true
);
$this->set_variations_with_stock(
$sut,
array(
'pa_size' => array( 'huge' ),
'pa_colour' => array( 'blue' ),
'pa_number' => array( '' ),
)
);
$this->assertTrue( $sut->is_visible() );
}
}

View File

@ -6,6 +6,9 @@
* @since 3.0.0
*/
/**
* Payment gateway test class.
*/
class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
/**
@ -107,7 +110,7 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
'description' => "Pay via PayPal; you can pay with your credit card if you don't have a PayPal account.",
'order' => '',
'enabled' => false,
'method_title' => 'PayPal',
'method_title' => 'PayPal Standard',
'method_description' => 'PayPal Standard redirects customers to PayPal to enter their payment information.',
'settings' => array_diff_key(
$this->get_settings( 'WC_Gateway_Paypal' ),
@ -151,7 +154,7 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
public function test_update_payment_gateway() {
wp_set_current_user( $this->user );
// Test defaults
// Test defaults.
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v2/payment_gateways/paypal' ) );
$paypal = $response->get_data();
@ -159,7 +162,7 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'admin@example.org', $paypal['settings']['email']['value'] );
$this->assertEquals( 'no', $paypal['settings']['testmode']['value'] );
// test updating single setting
// Test updating single setting.
$request = new WP_REST_Request( 'POST', '/wc/v2/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -176,7 +179,7 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
$this->assertEquals( 'no', $paypal['settings']['testmode']['value'] );
// test updating multiple settings
// Test updating multiple settings.
$request = new WP_REST_Request( 'POST', '/wc/v2/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -194,7 +197,7 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
$this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] );
// Test other parameters, and recheck settings
// Test other parameters, and recheck settings.
$request = new WP_REST_Request( 'POST', '/wc/v2/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -211,7 +214,7 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
$this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] );
// test bogus
// Test bogus parameter.
$request = new WP_REST_Request( 'POST', '/wc/v2/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -308,11 +311,11 @@ class Payment_Gateways_V2 extends WC_REST_Unit_Test_Case {
$settings = array();
$gateway->init_form_fields();
foreach ( $gateway->form_fields as $id => $field ) {
// Make sure we at least have a title and type
// Make sure we at least have a title and type.
if ( empty( $field['title'] ) || empty( $field['type'] ) ) {
continue;
}
// Ignore 'title' settings/fields -- they are UI only
// Ignore 'title' settings/fields -- they are UI only.
if ( 'title' === $field['type'] ) {
continue;
}

View File

@ -6,6 +6,9 @@
* @since 3.5.0
*/
/**
* Payment gateway test class.
*/
class Payment_Gateways extends WC_REST_Unit_Test_Case {
/**
@ -110,7 +113,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
'description' => "Pay via PayPal; you can pay with your credit card if you don't have a PayPal account.",
'order' => '',
'enabled' => false,
'method_title' => 'PayPal',
'method_title' => 'PayPal Standard',
'method_description' => 'PayPal Standard redirects customers to PayPal to enter their payment information.',
'method_supports' => array(
'products',
@ -158,7 +161,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
public function test_update_payment_gateway() {
wp_set_current_user( $this->user );
// Test defaults
// Test defaults.
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways/paypal' ) );
$paypal = $response->get_data();
@ -166,7 +169,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'admin@example.org', $paypal['settings']['email']['value'] );
$this->assertEquals( 'no', $paypal['settings']['testmode']['value'] );
// test updating single setting
// Test updating single setting.
$request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -183,7 +186,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
$this->assertEquals( 'no', $paypal['settings']['testmode']['value'] );
// test updating multiple settings
// Test updating multiple settings.
$request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -201,7 +204,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
$this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] );
// Test other parameters, and recheck settings
// Test other parameters, and recheck settings.
$request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -218,7 +221,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
$this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
$this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] );
// test bogus
// Test bogus paramter.
$request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
$request->set_body_params(
array(
@ -316,7 +319,7 @@ class Payment_Gateways extends WC_REST_Unit_Test_Case {
$settings = array();
$gateway->init_form_fields();
foreach ( $gateway->form_fields as $id => $field ) {
// Make sure we at least have a title and type
// Make sure we at least have a title and type.
if ( empty( $field['title'] ) || empty( $field['type'] ) ) {
continue;
}

View File

@ -405,7 +405,7 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case {
);
// This filter will sequentially remove handlers, allowing us to test as though our
// functions were accumulatively blacklisted, adding one on each call.
// functions were accumulatively blocked, adding one on each call.
add_filter( 'woocommerce_print_r_alternatives', array( $this, 'filter_wc_print_r_alternatives' ) );
$this->expectOutputString(

View File

@ -437,124 +437,4 @@ class WC_Tests_WC_Query extends WC_Unit_Test_Case {
WC()->query->remove_ordering_args();
}
/**
* Setup for a test for adjust_posts.
*
* @param bool $with_nav_filtering_data Should WC_Query::get_layered_nav_chosen_attributes return filtering data?.
* @param bool $use_objects If true, get_current_posts will return objects with an ID property; if false, it will returns the ids.
* @param string $post_type The value of the 'post_type' property for the objects generated when $use_objects is true.
*
* @return array An array where the first element is the instance of WC_Query, and the second is an array of sample products created.
*/
private function setup_adjust_posts_test( $with_nav_filtering_data, $use_objects, $post_type = 'product' ) {
update_option( 'woocommerce_hide_out_of_stock_items', 'yes' );
if ( $with_nav_filtering_data ) {
$nav_filtering_data = array( 'pa_something' => array( 'terms' => array( 'foo', 'bar' ) ) );
} else {
$nav_filtering_data = array();
}
$products = array();
$posts = array();
for ( $i = 0; $i < 5; $i++ ) {
$product = WC_Helper_Product::create_simple_product();
array_push( $products, $product );
$post = $use_objects ? (object) array(
'ID' => $product->get_id(),
'post_type' => $post_type,
) : $product->get_id();
array_push( $posts, $post );
}
$products[0]->set_stock_status( 'outofstock' );
$sut = $this
->getMockBuilder( WC_Query::class )
->setMethods( array( 'get_current_posts', 'get_layered_nav_chosen_attributes_inst' ) )
->getMock();
$sut->method( 'get_current_posts' )->willReturn( $posts );
$sut->method( 'get_layered_nav_chosen_attributes_inst' )->willReturn( $nav_filtering_data );
return array( $sut, $products );
}
/**
* @param bool $with_nav_filtering_data Should WC_Query::get_layered_nav_chosen_attributes return filtering data?.
* @param bool $use_objects If true, get_current_posts will return objects with an ID property; if false, it will returns the ids.
*
* @testdox adjust_posts should return the number of visible products and create product visibility loop variables
* @testWith [true, true]
* [false, false]
* [true, false]
* [false, true]
*/
public function test_adjust_posts_count_with_nav_filtering_attributes( $with_nav_filtering_data, $use_objects ) {
global $wp_query;
list($sut, $products) = $this->setup_adjust_posts_test( $with_nav_filtering_data, $use_objects );
$products[0]->set_stock_status( 'outofstock' );
$products[0]->save();
$products[1]->set_stock_status( 'outofstock' );
$products[1]->save();
$wp_query->set( 'wc_query', 'product_query' );
$this->assertEquals( 32, $sut->adjust_posts_count( 34, $wp_query ) );
$this->assertEquals( 32, wc_get_loop_prop( 'total' ) );
$this->assertEquals( false, wc_get_loop_product_visibility( $products[0]->get_id() ) );
$this->assertEquals( false, wc_get_loop_product_visibility( $products[1]->get_id() ) );
foreach ( array_slice( $products, 2 ) as $product ) {
$this->assertEquals( true, wc_get_loop_product_visibility( $product->get_id() ) );
}
}
/**
* @testdox adjust_posts should return the input unmodified if get_current_posts returns null.
*/
public function test_adjust_posts_count_when_there_are_no_posts() {
global $wp_query;
$sut = $this
->getMockBuilder( WC_Query::class )
->setMethods( array( 'get_current_posts', 'get_layered_nav_chosen_attributes_inst' ) )
->getMock();
$sut->method( 'get_current_posts' )->willReturn( null );
$wp_query->set( 'wc_query', 'product_query' );
$this->assertEquals( 34, $sut->adjust_posts_count( 34, $wp_query ) );
}
/**
* @testdox adjust_posts should return the input unmodified if the posts do not represent products.
*/
public function test_adjust_posts_count_when_the_posts_are_not_products() {
global $wp_query;
list( $sut, $products ) = $this->setup_adjust_posts_test( true, true, 'page' );
$products[0]->set_stock_status( 'outofstock' );
$products[0]->save();
$wp_query->set( 'wc_query', 'product_query' );
$this->assertEquals( 34, $sut->adjust_posts_count( 34, $wp_query ) );
}
/**
* @testdox adjust_posts should return the input unmodified if not in the main product query.
*/
public function test_adjust_posts_count_when_not_in_the_main_product_query() {
global $wp_query;
list( $sut, $products ) = $this->setup_adjust_posts_test( true, true );
$products[0]->set_stock_status( 'outofstock' );
$products[0]->save();
$wp_query->set( 'wc_query', null );
$this->assertEquals( 34, $sut->adjust_posts_count( 34, $wp_query ) );
}
}

View File

@ -99,4 +99,37 @@ class WC_Cart_Test extends \WC_Unit_Test_Case {
WC()->cart->get_customer()->set_shipping_state( '' );
WC()->cart->get_customer()->set_shipping_postcode( '' );
}
/**
* Test show_shipping for countries with various state/postcode requirement.
*/
public function test_show_shipping_for_countries_different_shipping_requirements() {
$default_shipping_cost_requires_address = get_option( 'woocommerce_shipping_cost_requires_address', 'no' );
update_option( 'woocommerce_shipping_cost_requires_address', 'yes' );
WC()->cart->empty_cart();
$this->assertFalse( WC()->cart->show_shipping() );
$product = WC_Helper_Product::create_simple_product();
WC()->cart->add_to_cart( $product->get_id(), 1 );
// Country that does not require state.
WC()->cart->get_customer()->set_shipping_country( 'LB' );
WC()->cart->get_customer()->set_shipping_state( '' );
WC()->cart->get_customer()->set_shipping_postcode( '12345' );
$this->assertTrue( WC()->cart->show_shipping() );
// Country that does not require postcode.
WC()->cart->get_customer()->set_shipping_country( 'NG' );
WC()->cart->get_customer()->set_shipping_state( 'AB' );
WC()->cart->get_customer()->set_shipping_postcode( '' );
$this->assertTrue( WC()->cart->show_shipping() );
// Reset.
update_option( 'woocommerce_shipping_cost_requires_address', $default_shipping_cost_requires_address );
$product->delete( true );
WC()->cart->get_customer()->set_shipping_country( 'GB' );
WC()->cart->get_customer()->set_shipping_state( '' );
WC()->cart->get_customer()->set_shipping_postcode( '' );
}
}

View File

@ -476,4 +476,127 @@ class WC_Tests_Widget_Layered_Nav extends WC_Unit_Test_Case {
);
$this->assertEquals( $expected, $actual );
}
/**
* Create a product that has two variations for two styles, and each variation
* has a value of "Any" for the color.
*
* @param string $set_as_out_of_stock 'one': set one of the variations as "Out of stock", 'all': set all the variations as "Out of stock".
* @param string $set_as_unpublished 'one': set one of the variations as "draft", 'all': set all the variations as "draft".
* @param bool $set_main_as_unpublished If true, set the main product as "draft".
*
* @return WC_Product_Variable
*/
private function create_product_with_all_styles_and_any_color( $set_as_out_of_stock, $set_as_unpublished, $set_main_as_unpublished ) {
$main_product = new WC_Product_Variable();
$main_product->set_props(
array(
'name' => 'Some shoes',
'sku' => 'SKU for Some shoes',
)
);
$existing_colors = array( 'black', 'brown', 'blue', 'green', 'pink', 'yellow' );
$existing_styles = array( 'classic', 'sport' );
$attributes = array(
WC_Helper_Product::create_product_attribute_object( 'color', array_values( $existing_colors ) ),
WC_Helper_Product::create_product_attribute_object( 'style', array_values( $existing_styles ) ),
);
$main_product->set_attributes( $attributes );
$main_product->save();
if ( $set_main_as_unpublished ) {
wp_update_post(
array(
'ID' => $main_product->get_id(),
'post_status' => 'draft',
)
);
}
$variation_objects = array();
foreach ( $existing_styles as $style ) {
$variation_attributes = array(
'pa_style' => $style,
);
$variation_object = WC_Helper_Product::create_product_variation_object(
$main_product->get_id(),
"SKU for $style Some shoes",
10,
$variation_attributes
);
if ( 'all' === $set_as_out_of_stock || ( 'one' === $set_as_out_of_stock && $style === $existing_styles[0] ) ) {
$variation_object->set_stock_status( 'outofstock' );
}
$variation_object->save();
if ( 'all' === $set_as_unpublished || ( 'one' === $set_as_unpublished && $style === $existing_styles[0] ) ) {
wp_update_post(
array(
'ID' => $variation_object->get_id(),
'post_status' => 'draft',
)
);
}
array_push( $variation_objects, $variation_object->get_id() );
}
$main_product->set_children( $variation_objects );
$main_product->save();
return $main_product;
}
/**
* @testdox When a variation has a value of "Any" for an attribute it should be included in the count of all the attribute values used by the main product.
*
* @testWith [null, null]
* [null, "one"]
* ["one", null]
*
* @param string $set_as_out_of_stock "one" to set one of the variations as out of stock.
* @param string $set_as_unpublished "one" to set one of the variations as a draft.
*
* @throws ReflectionException Error when dealing with reflection to invoke the tested method.
*/
public function test_product_count_per_attribute_with_any_valued_variations( $set_as_out_of_stock, $set_as_unpublished ) {
$this->create_product_with_all_styles_and_any_color( $set_as_out_of_stock, $set_as_unpublished, false );
$this->create_colored_product( 'Medium shoes', array( 'black', 'brown', 'blue' ) );
$this->create_colored_product( 'Medium shoes 2', array( 'black', 'brown', 'blue', 'pink' ) );
$actual = $this->run_get_filtered_term_product_counts( 'or', array() );
$expected = array(
'black' => 3,
'brown' => 3,
'blue' => 3,
'pink' => 2,
'green' => 1,
'yellow' => 1,
);
$this->assertEquals( $expected, $actual );
}
/**
* @testdox When variations have a value of "Any" for an attribute BUT the main product is unpublished, none of them should be included in the count of all the attribute values used by the main product.
*
* @throws ReflectionException Error when dealing with reflection to invoke the tested method.
*/
public function test_product_count_per_attribute_with_any_valued_variations_when_main_is_unpublished() {
$this->create_colored_product( 'Medium shoes', array( 'black', 'brown', 'blue' ) );
$this->create_product_with_all_styles_and_any_color( null, null, true );
$actual = $this->run_get_filtered_term_product_counts( 'or', array() );
$expected = array(
'black' => 1,
'brown' => 1,
'blue' => 1,
);
$this->assertEquals( $expected, $actual );
}
}

View File

@ -3,12 +3,12 @@
* Plugin Name: WooCommerce
* Plugin URI: https://woocommerce.com/
* Description: An eCommerce toolkit that helps you sell anything. Beautifully.
* Version: 4.5.0-beta.1
* Version: 4.5.1
* Author: Automattic
* Author URI: https://woocommerce.com
* Text Domain: woocommerce
* Domain Path: /i18n/languages/
* Requires at least: 5.2
* Requires at least: 5.3
* Requires PHP: 7.0
*
* @package WooCommerce