diff --git a/.github/workflows/update-feedback-labels.yml b/.github/workflows/update-feedback-labels.yml
index 2c311f0195a..bb0af46f64b 100644
--- a/.github/workflows/update-feedback-labels.yml
+++ b/.github/workflows/update-feedback-labels.yml
@@ -15,10 +15,13 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: 'has feedback'
- - name: remove needs feedback, stale
+ - name: remove needs feedback
uses: actions-ecosystem/action-remove-labels@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- labels: |
- 'needs feedback'
- 'Stale'
+ labels: 'needs feedback'
+ - name: remove stale
+ uses: actions-ecosystem/action-remove-labels@v1
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ labels: Stale
diff --git a/assets/css/admin.scss b/assets/css/admin.scss
index 3dca45bdf8c..6ea357b8e2a 100644
--- a/assets/css/admin.scss
+++ b/assets/css/admin.scss
@@ -161,6 +161,43 @@
}
}
+ .addons-promotion-block {
+ display: flex;
+ padding: 20px;
+
+ .addons-img {
+ height: auto;
+ width: 200px;
+ }
+ }
+
+ .addons-promotion-block-content {
+ display: flex;
+ flex-direction: column;
+ margin-left: 24px;
+ }
+
+ .addons-promotion-block-description {
+ margin-bottom: 20px;
+ }
+
+ .addons-promotion-block-title {
+ margin: 0 0 16px;
+ padding: 0;
+ }
+
+ .addons-promotion-block-buttons {
+ margin-top: auto;
+
+ .addons-button {
+ margin-right: 8px;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
.addons-shipping-methods .addons-wcs-banner-block {
margin-left: 0;
margin-right: 0;
@@ -364,6 +401,12 @@
color: #fff;
}
+ .addons-button-expandable {
+ display: inline-block;
+ padding: 0 16px;
+ width: auto;
+ }
+
.addons-button-solid:hover {
color: #fff;
opacity: 0.8;
@@ -2642,6 +2685,30 @@ ul.wc_coupon_list_block {
float: right;
}
}
+
+ .wc_addons_wrap {
+
+ .addons-promotion-block {
+ flex-direction: column;
+ padding: 24px;
+
+ .addons-img {
+ height: auto;
+ width: 100%;
+ max-width: 240px;
+ margin: 0 auto 20px;
+ }
+ }
+
+ .addons-promotion-block-content {
+ display: block;
+ margin-left: 0;
+ }
+
+ .addons-promotion-block-title {
+ margin-top: 4px;
+ }
+ }
}
.column-customer_message .note-on {
diff --git a/bin/composer/mozart/composer.lock b/bin/composer/mozart/composer.lock
index 6e9a52a1179..81ac1cea0fc 100644
--- a/bin/composer/mozart/composer.lock
+++ b/bin/composer/mozart/composer.lock
@@ -267,16 +267,16 @@
},
{
"name": "symfony/console",
- "version": "v5.2.6",
+ "version": "v5.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d"
+ "reference": "864568fdc0208b3eba3638b6000b69d2386e6768"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/35f039df40a3b335ebf310f244cb242b3a83ac8d",
- "reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d",
+ "url": "https://api.github.com/repos/symfony/console/zipball/864568fdc0208b3eba3638b6000b69d2386e6768",
+ "reference": "864568fdc0208b3eba3638b6000b69d2386e6768",
"shasum": ""
},
"require": {
@@ -344,7 +344,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v5.2.6"
+ "source": "https://github.com/symfony/console/tree/v5.2.8"
},
"funding": [
{
@@ -360,20 +360,20 @@
"type": "tidelift"
}
],
- "time": "2021-03-28T09:42:18+00:00"
+ "time": "2021-05-11T15:45:21+00:00"
},
{
"name": "symfony/finder",
- "version": "v5.2.4",
+ "version": "v5.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "0d639a0943822626290d169965804f79400e6a04"
+ "reference": "eccb8be70d7a6a2230d05f6ecede40f3fdd9e252"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04",
- "reference": "0d639a0943822626290d169965804f79400e6a04",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/eccb8be70d7a6a2230d05f6ecede40f3fdd9e252",
+ "reference": "eccb8be70d7a6a2230d05f6ecede40f3fdd9e252",
"shasum": ""
},
"require": {
@@ -405,7 +405,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v5.2.4"
+ "source": "https://github.com/symfony/finder/tree/v5.2.8"
},
"funding": [
{
@@ -421,7 +421,7 @@
"type": "tidelift"
}
],
- "time": "2021-02-15T18:55:04+00:00"
+ "time": "2021-05-10T14:39:23+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -911,21 +911,21 @@
},
{
"name": "symfony/service-contracts",
- "version": "v2.2.0",
+ "version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1"
+ "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1",
- "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
+ "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
- "psr/container": "^1.0"
+ "psr/container": "^1.1"
},
"suggest": {
"symfony/service-implementation": ""
@@ -933,7 +933,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.2-dev"
+ "dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -970,7 +970,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/master"
+ "source": "https://github.com/symfony/service-contracts/tree/v2.4.0"
},
"funding": [
{
@@ -986,20 +986,20 @@
"type": "tidelift"
}
],
- "time": "2020-09-07T11:33:47+00:00"
+ "time": "2021-04-01T10:43:52+00:00"
},
{
"name": "symfony/string",
- "version": "v5.2.6",
+ "version": "v5.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572"
+ "reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572",
- "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572",
+ "url": "https://api.github.com/repos/symfony/string/zipball/01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db",
+ "reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db",
"shasum": ""
},
"require": {
@@ -1053,7 +1053,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v5.2.6"
+ "source": "https://github.com/symfony/string/tree/v5.2.8"
},
"funding": [
{
@@ -1069,7 +1069,7 @@
"type": "tidelift"
}
],
- "time": "2021-03-17T17:12:15+00:00"
+ "time": "2021-05-10T14:56:10+00:00"
}
],
"aliases": [],
diff --git a/bin/composer/phpcs/composer.lock b/bin/composer/phpcs/composer.lock
index d784a60a0a0..e0653d55467 100644
--- a/bin/composer/phpcs/composer.lock
+++ b/bin/composer/phpcs/composer.lock
@@ -251,16 +251,16 @@
},
{
"name": "squizlabs/php_codesniffer",
- "version": "3.5.8",
+ "version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
- "reference": "9d583721a7157ee997f235f327de038e7ea6dac4"
+ "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4",
- "reference": "9d583721a7157ee997f235f327de038e7ea6dac4",
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
+ "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"shasum": ""
},
"require": {
@@ -303,7 +303,7 @@
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
- "time": "2020-10-23T02:01:07+00:00"
+ "time": "2021-04-09T00:54:41+00:00"
},
{
"name": "woocommerce/woocommerce-sniffs",
diff --git a/bin/composer/wp/composer.lock b/bin/composer/wp/composer.lock
index 8fb33475e13..3532eb3520e 100644
--- a/bin/composer/wp/composer.lock
+++ b/bin/composer/wp/composer.lock
@@ -254,23 +254,30 @@
},
{
"name": "rmccue/requests",
- "version": "v1.7.0",
+ "version": "v1.8.0",
"source": {
"type": "git",
- "url": "https://github.com/rmccue/Requests.git",
- "reference": "87932f52ffad70504d93f04f15690cf16a089546"
+ "url": "https://github.com/WordPress/Requests.git",
+ "reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546",
- "reference": "87932f52ffad70504d93f04f15690cf16a089546",
+ "url": "https://api.github.com/repos/WordPress/Requests/zipball/afbe4790e4def03581c4a0963a1e8aa01f6030f1",
+ "reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
- "requests/test-server": "dev-master"
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.7",
+ "php-parallel-lint/php-console-highlighter": "^0.5.0",
+ "php-parallel-lint/php-parallel-lint": "^1.3",
+ "phpcompatibility/php-compatibility": "^9.0",
+ "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5",
+ "requests/test-server": "dev-master",
+ "squizlabs/php_codesniffer": "^3.5",
+ "wp-coding-standards/wpcs": "^2.0"
},
"type": "library",
"autoload": {
@@ -289,7 +296,7 @@
}
],
"description": "A HTTP library written in PHP, for human beings.",
- "homepage": "http://github.com/rmccue/Requests",
+ "homepage": "http://github.com/WordPress/Requests",
"keywords": [
"curl",
"fsockopen",
@@ -300,10 +307,10 @@
"sockets"
],
"support": {
- "issues": "https://github.com/rmccue/Requests/issues",
- "source": "https://github.com/rmccue/Requests/tree/master"
+ "issues": "https://github.com/WordPress/Requests/issues",
+ "source": "https://github.com/WordPress/Requests/tree/v1.8.0"
},
- "time": "2016-10-13T00:11:37+00:00"
+ "time": "2021-04-27T11:05:25+00:00"
},
{
"name": "symfony/finder",
@@ -359,26 +366,26 @@
},
{
"name": "wp-cli/i18n-command",
- "version": "v2.2.6",
+ "version": "v2.2.8",
"source": {
"type": "git",
"url": "https://github.com/wp-cli/i18n-command.git",
- "reference": "a66da3f09f6a728832381012848c3074bf1635c8"
+ "reference": "8bc234617edc533590ac0f41080164a8d85ec9ce"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/wp-cli/i18n-command/zipball/a66da3f09f6a728832381012848c3074bf1635c8",
- "reference": "a66da3f09f6a728832381012848c3074bf1635c8",
+ "url": "https://api.github.com/repos/wp-cli/i18n-command/zipball/8bc234617edc533590ac0f41080164a8d85ec9ce",
+ "reference": "8bc234617edc533590ac0f41080164a8d85ec9ce",
"shasum": ""
},
"require": {
"gettext/gettext": "^4.8",
"mck89/peast": "^1.8",
- "wp-cli/wp-cli": "^2"
+ "wp-cli/wp-cli": "^2.5"
},
"require-dev": {
"wp-cli/scaffold-command": "^1.2 || ^2",
- "wp-cli/wp-cli-tests": "^2.1.3"
+ "wp-cli/wp-cli-tests": "^3.0.11"
},
"type": "wp-cli-package",
"extra": {
@@ -414,9 +421,9 @@
"homepage": "https://github.com/wp-cli/i18n-command",
"support": {
"issues": "https://github.com/wp-cli/i18n-command/issues",
- "source": "https://github.com/wp-cli/i18n-command/tree/v2.2.6"
+ "source": "https://github.com/wp-cli/i18n-command/tree/v2.2.8"
},
- "time": "2020-12-07T19:28:27+00:00"
+ "time": "2021-05-10T10:24:16+00:00"
},
{
"name": "wp-cli/mustangostang-spyc",
@@ -525,23 +532,23 @@
},
{
"name": "wp-cli/wp-cli",
- "version": "v2.4.1",
+ "version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/wp-cli/wp-cli.git",
- "reference": "ceb18598e79befa9b2a37a51efbb34910628988b"
+ "reference": "4c4746d06640af7698f3792cc4c327a8482dc40f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/ceb18598e79befa9b2a37a51efbb34910628988b",
- "reference": "ceb18598e79befa9b2a37a51efbb34910628988b",
+ "url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/4c4746d06640af7698f3792cc4c327a8482dc40f",
+ "reference": "4c4746d06640af7698f3792cc4c327a8482dc40f",
"shasum": ""
},
"require": {
"ext-curl": "*",
"mustache/mustache": "~2.13",
- "php": "^5.4 || ^7.0",
- "rmccue/requests": "~1.6",
+ "php": "^5.6 || ^7.0 || ^8.0",
+ "rmccue/requests": "^1.8",
"symfony/finder": ">2.7",
"wp-cli/mustangostang-spyc": "^0.6.3",
"wp-cli/php-cli-tools": "~0.11.2"
@@ -552,12 +559,13 @@
"wp-cli/entity-command": "^1.2 || ^2",
"wp-cli/extension-command": "^1.1 || ^2",
"wp-cli/package-command": "^1 || ^2",
- "wp-cli/wp-cli-tests": "^2.1"
+ "wp-cli/wp-cli-tests": "^3.0.7"
},
"suggest": {
"ext-readline": "Include for a better --prompt implementation",
"ext-zip": "Needed to support extraction of ZIP archives when doing downloads or updates"
},
+ "default-branch": true,
"bin": [
"bin/wp",
"bin/wp.bat"
@@ -565,13 +573,17 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.4.x-dev"
+ "dev-master": "2.5.x-dev"
}
},
"autoload": {
"psr-0": {
- "WP_CLI": "php"
- }
+ "WP_CLI\\": "php/"
+ },
+ "classmap": [
+ "php/class-wp-cli.php",
+ "php/class-wp-cli-command.php"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -588,7 +600,7 @@
"issues": "https://github.com/wp-cli/wp-cli/issues",
"source": "https://github.com/wp-cli/wp-cli"
},
- "time": "2020-02-18T08:15:37+00:00"
+ "time": "2021-05-13T09:36:33+00:00"
}
],
"aliases": [],
diff --git a/composer.json b/composer.json
index 462458e7920..34a1dc6a246 100644
--- a/composer.json
+++ b/composer.json
@@ -21,8 +21,8 @@
"pelago/emogrifier": "3.1.0",
"psr/container": "1.0.0",
"woocommerce/action-scheduler": "3.1.6",
- "woocommerce/woocommerce-admin": "2.2.6",
- "woocommerce/woocommerce-blocks": "4.9.1"
+ "woocommerce/woocommerce-admin": "2.3.0",
+ "woocommerce/woocommerce-blocks": "5.1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4"
diff --git a/composer.lock b/composer.lock
index 3f506ced4f6..966a06ec993 100644
--- a/composer.lock
+++ b/composer.lock
@@ -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": "a604678b268820c78736d599e1eb6726",
+ "content-hash": "ac338dadb8929c73ad9606426621f9ba",
"packages": [
{
"name": "automattic/jetpack-autoloader",
@@ -51,6 +51,9 @@
"GPL-2.0-or-later"
],
"description": "Creates a custom autoloader for a plugin or theme.",
+ "support": {
+ "source": "https://github.com/Automattic/jetpack-autoloader/tree/2.10.1"
+ },
"time": "2021-03-30T15:15:59+00:00"
},
{
@@ -82,6 +85,9 @@
"GPL-2.0-or-later"
],
"description": "A wrapper for defining constants in a more testable way.",
+ "support": {
+ "source": "https://github.com/Automattic/jetpack-constants/tree/v1.5.1"
+ },
"time": "2020-10-28T19:00:31+00:00"
},
{
@@ -214,6 +220,10 @@
"zend",
"zikula"
],
+ "support": {
+ "issues": "https://github.com/composer/installers/issues",
+ "source": "https://github.com/composer/installers/tree/v1.11.0"
+ },
"funding": [
{
"url": "https://packagist.com",
@@ -288,6 +298,10 @@
"geolocation",
"maxmind"
],
+ "support": {
+ "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues",
+ "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.6.0"
+ },
"time": "2019-12-19T22:59:03+00:00"
},
{
@@ -362,6 +376,10 @@
"email",
"pre-processing"
],
+ "support": {
+ "issues": "https://github.com/MyIntervals/emogrifier/issues",
+ "source": "https://github.com/MyIntervals/emogrifier"
+ },
"time": "2019-12-26T19:37:31+00:00"
},
{
@@ -411,6 +429,10 @@
"container-interop",
"psr"
],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/master"
+ },
"time": "2017-02-14T16:28:37+00:00"
},
{
@@ -464,6 +486,9 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/css-selector/tree/master"
+ },
"time": "2017-05-01T15:01:29+00:00"
},
{
@@ -499,20 +524,24 @@
],
"description": "Action Scheduler for WordPress and WooCommerce",
"homepage": "https://actionscheduler.org/",
+ "support": {
+ "issues": "https://github.com/woocommerce/action-scheduler/issues",
+ "source": "https://github.com/woocommerce/action-scheduler/tree/master"
+ },
"time": "2020-05-12T16:22:33+00:00"
},
{
"name": "woocommerce/woocommerce-admin",
- "version": "2.2.6",
+ "version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
- "reference": "161e6afa01a3fb69533cfa2b245a71df7512ec3f"
+ "reference": "c690969d301ddb7145b43e72e4dd99c84cc8ba66"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/65c5a4d0b0c3a7c7457e250c9ba1f7c15cac6cb8",
- "reference": "65c5a4d0b0c3a7c7457e250c9ba1f7c15cac6cb8",
+ "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/c690969d301ddb7145b43e72e4dd99c84cc8ba66",
+ "reference": "c690969d301ddb7145b43e72e4dd99c84cc8ba66",
"shasum": ""
},
"require": {
@@ -521,7 +550,7 @@
"php": ">=7.0"
},
"require-dev": {
- "phpunit/phpunit": "7.5.20",
+ "bamarni/composer-bin-plugin": "^1.4",
"suin/phpcs-psr4-sniff": "^2.2",
"woocommerce/woocommerce-sniffs": "0.1.0"
},
@@ -531,6 +560,9 @@
"test": "Run unit tests",
"phpcs": "Analyze code against the WordPress coding standards with PHP_CodeSniffer",
"phpcbf": "Fix coding standards warnings/errors automatically with PHP Code Beautifier"
+ },
+ "bamarni-bin": {
+ "target-directory": "bin/composer"
}
},
"autoload": {
@@ -544,20 +576,24 @@
],
"description": "A modern, javascript-driven WooCommerce Admin experience.",
"homepage": "https://github.com/woocommerce/woocommerce-admin",
- "time": "2021-04-29T14:11:48+00:00"
+ "support": {
+ "issues": "https://github.com/woocommerce/woocommerce-admin/issues",
+ "source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.3.0"
+ },
+ "time": "2021-05-12T15:20:07+00:00"
},
{
"name": "woocommerce/woocommerce-blocks",
- "version": "v4.9.1",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git",
- "reference": "62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce"
+ "reference": "a4f168596f3832e161b26dec636b69293039ee51"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce",
- "reference": "62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce",
+ "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/a4f168596f3832e161b26dec636b69293039ee51",
+ "reference": "a4f168596f3832e161b26dec636b69293039ee51",
"shasum": ""
},
"require": {
@@ -565,7 +601,7 @@
"composer/installers": "^1.7.0"
},
"require-dev": {
- "phpunit/phpunit": "6.5.14",
+ "phpunit/phpunit": "7.5.20",
"woocommerce/woocommerce-sniffs": "0.1.0"
},
"type": "wordpress-plugin",
@@ -591,7 +627,11 @@
"gutenberg",
"woocommerce"
],
- "time": "2021-04-13T16:11:16+00:00"
+ "support": {
+ "issues": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues",
+ "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v5.1.0"
+ },
+ "time": "2021-05-10T15:01:42+00:00"
}
],
"packages-dev": [
@@ -639,6 +679,10 @@
"isolation",
"tool"
],
+ "support": {
+ "issues": "https://github.com/bamarni/composer-bin-plugin/issues",
+ "source": "https://github.com/bamarni/composer-bin-plugin/tree/master"
+ },
"time": "2020-05-03T08:27:20+00:00"
}
],
@@ -654,5 +698,5 @@
"platform-overrides": {
"php": "7.0"
},
- "plugin-api-version": "1.1.0"
+ "plugin-api-version": "2.0.0"
}
diff --git a/includes/admin/class-wc-admin-addons.php b/includes/admin/class-wc-admin-addons.php
index ed3a0461368..ff33de129e0 100644
--- a/includes/admin/class-wc-admin-addons.php
+++ b/includes/admin/class-wc-admin-addons.php
@@ -534,6 +534,73 @@ class WC_Admin_Addons {
geowhitelist ) ) {
+ $section_object->geowhitelist = explode( ',', $section_object->geowhitelist );
+ }
+
+ if ( ! empty( $section_object->geoblacklist ) ) {
+ $section_object->geoblacklist = explode( ',', $section_object->geoblacklist );
+ }
+
+ if ( ! self::show_extension( $section_object ) ) {
+ return;
+ }
+
+ ?>
+
+ data['name'] || ! isset( $response->data['actions'] ) ) {
- return $response;
- }
-
- foreach ( $response->data['actions'] as $action_key => $action ) {
- $url_parts = ! empty( $action->query ) ? wp_parse_url( $action->query ) : '';
-
- if ( ! isset( $url_parts['query'] ) ) {
- continue;
- }
-
- wp_parse_str( $url_parts['query'], $params );
-
- if ( array_key_exists( '_nonce_action', $params ) && array_key_exists( '_nonce_name', $params ) ) {
- $org_params = $params;
-
- // Check to make sure we're acting on the whitelisted nonce actions.
- if ( 'wc_db_update' !== $params['_nonce_action'] && 'woocommerce_hide_notices_nonce' !== $params['_nonce_action'] ) {
- continue;
- }
-
- unset( $org_params['_nonce_action'] );
- unset( $org_params['_nonce_name'] );
-
- $url = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'];
-
- $nonce = array( $params['_nonce_name'] => wp_create_nonce( $params['_nonce_action'] ) );
- $merged_params = array_merge( $nonce, $org_params );
- $parsed_query = add_query_arg( $merged_params, $url );
-
- $response->data['actions'][ $action_key ]->query = $parsed_query;
- $response->data['actions'][ $action_key ]->url = $parsed_query;
- }
- }
+ wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '5.4.0' );
return $response;
}
diff --git a/includes/admin/notes/class-wc-notes-run-db-update.php b/includes/admin/notes/class-wc-notes-run-db-update.php
index 1fad100ff9e..77017ec2ca2 100644
--- a/includes/admin/notes/class-wc-notes-run-db-update.php
+++ b/includes/admin/notes/class-wc-notes-run-db-update.php
@@ -109,24 +109,23 @@ class WC_Notes_Run_Db_Update {
* @return int Created/Updated note id
*/
private static function update_needed_notice( $note_id = null ) {
- $update_url = html_entity_decode(
+ $update_url =
add_query_arg(
array(
'do_update_woocommerce' => 'true',
- '_nonce_action' => 'wc_db_update',
- '_nonce_name' => 'wc_db_update_nonce',
),
wc_get_current_admin_url() ? wc_get_current_admin_url() : admin_url( 'admin.php?page=wc-settings' )
- )
- );
+ );
$note_actions = array(
array(
- 'name' => 'update-db_run',
- 'label' => __( 'Update WooCommerce Database', 'woocommerce' ),
- 'url' => $update_url,
- 'status' => 'unactioned',
- 'primary' => true,
+ 'name' => 'update-db_run',
+ 'label' => __( 'Update WooCommerce Database', 'woocommerce' ),
+ 'url' => $update_url,
+ 'status' => 'unactioned',
+ 'primary' => true,
+ 'nonce_action' => 'wc_db_update',
+ 'nonce_name' => 'wc_db_update_nonce',
),
array(
'name' => 'update-db_learn-more',
@@ -166,6 +165,10 @@ class WC_Notes_Run_Db_Update {
$note->clear_actions();
foreach ( $note_actions as $note_action ) {
$note->add_action( ...array_values( $note_action ) );
+
+ if ( isset( $note_action['nonce_action'] ) ) {
+ $note->add_nonce_to_action( $note_action['name'], $note_action['nonce_action'], $note_action['nonce_name'] );
+ }
}
return $note->save();
@@ -212,8 +215,6 @@ class WC_Notes_Run_Db_Update {
add_query_arg(
array(
'wc-hide-notice' => 'update',
- '_nonce_action' => 'woocommerce_hide_notices_nonce',
- '_nonce_name' => '_wc_notice_nonce',
),
wc_get_current_admin_url() ? remove_query_arg( 'do_update_woocommerce', wc_get_current_admin_url() ) : admin_url( 'admin.php?page=wc-settings' )
)
@@ -221,11 +222,13 @@ class WC_Notes_Run_Db_Update {
$note_actions = array(
array(
- 'name' => 'update-db_done',
- 'label' => __( 'Thanks!', 'woocommerce' ),
- 'url' => $hide_notices_url,
- 'status' => 'actioned',
- 'primary' => true,
+ 'name' => 'update-db_done',
+ 'label' => __( 'Thanks!', 'woocommerce' ),
+ 'url' => $hide_notices_url,
+ 'status' => 'actioned',
+ 'primary' => true,
+ 'nonce_action' => 'woocommerce_hide_notices_nonce',
+ 'nonce_name' => '_wc_notice_nonce',
),
);
@@ -242,6 +245,10 @@ class WC_Notes_Run_Db_Update {
$note->clear_actions();
foreach ( $note_actions as $note_action ) {
$note->add_action( ...array_values( $note_action ) );
+
+ if ( isset( $note_action['nonce_action'] ) ) {
+ $note->add_nonce_to_action( $note_action['name'], $note_action['nonce_action'], $note_action['nonce_name'] );
+ }
}
$note->save();
diff --git a/includes/class-wc-cache-helper.php b/includes/class-wc-cache-helper.php
index f07fca63eb0..4a9c0604eab 100644
--- a/includes/class-wc-cache-helper.php
+++ b/includes/class-wc-cache-helper.php
@@ -42,14 +42,33 @@ class WC_Cache_Helper {
*/
public static function additional_nocache_headers( $headers ) {
$agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+
+ $set_cache = false;
+
/**
* Allow plugins to enable nocache headers. Enabled for Google weblight.
*
- * @see https://support.google.com/webmasters/answer/1061943?hl=en
* @param bool $enable_nocache_headers Flag indicating whether to add nocache headers. Default: false.
*/
- if ( false !== strpos( $agent, 'googleweblight' ) || apply_filters( 'woocommerce_enable_nocache_headers', false ) ) {
+ if ( apply_filters( 'woocommerce_enable_nocache_headers', false ) ) {
+ $set_cache = true;
+ }
+
+ /**
+ * Enabled for Google weblight.
+ *
+ * @see https://support.google.com/webmasters/answer/1061943?hl=en
+ */
+ if ( false !== strpos( $agent, 'googleweblight' ) ) {
// no-transform: Opt-out of Google weblight. https://support.google.com/webmasters/answer/6211428?hl=en.
+ $set_cache = true;
+ }
+
+ if ( false !== strpos( $agent, 'Chrome' ) && is_cart() ) {
+ $set_cache = true;
+ }
+
+ if ( $set_cache ) {
$headers['Cache-Control'] = 'no-transform, no-cache, no-store, must-revalidate';
}
return $headers;
diff --git a/includes/class-wc-checkout.php b/includes/class-wc-checkout.php
index 036c4ba612c..3133be81505 100644
--- a/includes/class-wc-checkout.php
+++ b/includes/class-wc-checkout.php
@@ -679,6 +679,8 @@ class WC_Checkout {
// phpcs:enable WordPress.Security.NonceVerification.Missing
$skipped = array();
+ $form_was_shown = isset( $_POST['woocommerce-process-checkout-nonce'] ); // phpcs:disable WordPress.Security.NonceVerification.Missing
+
foreach ( $this->get_checkout_fields() as $fieldset_key => $fieldset ) {
if ( $this->maybe_skip_fieldset( $fieldset_key, $data ) ) {
$skipped[] = $fieldset_key;
@@ -688,25 +690,32 @@ class WC_Checkout {
foreach ( $fieldset as $key => $field ) {
$type = sanitize_title( isset( $field['type'] ) ? $field['type'] : 'text' );
- // phpcs:disable WordPress.Security.NonceVerification.Missing
- switch ( $type ) {
- case 'checkbox':
- $value = isset( $_POST[ $key ] ) ? 1 : '';
- break;
- case 'multiselect':
- $value = isset( $_POST[ $key ] ) ? implode( ', ', wc_clean( wp_unslash( $_POST[ $key ] ) ) ) : '';
- break;
- case 'textarea':
- $value = isset( $_POST[ $key ] ) ? wc_sanitize_textarea( wp_unslash( $_POST[ $key ] ) ) : '';
- break;
- case 'password':
- $value = isset( $_POST[ $key ] ) ? wp_unslash( $_POST[ $key ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- break;
- default:
- $value = isset( $_POST[ $key ] ) ? wc_clean( wp_unslash( $_POST[ $key ] ) ) : '';
- break;
+ if ( isset( $_POST[ $key ] ) && '' !== $_POST[ $key ] ) { // phpcs:disable WordPress.Security.NonceVerification.Missing
+ $value = wp_unslash( $_POST[ $key ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ } elseif ( isset( $field['default'] ) && 'checkbox' !== $type && ! $form_was_shown ) {
+ $value = $field['default'];
+ } else {
+ $value = '';
+ }
+
+ if ( '' !== $value ) {
+ switch ( $type ) {
+ case 'checkbox':
+ $value = 1;
+ break;
+ case 'multiselect':
+ $value = implode( ', ', wc_clean( $value ) );
+ break;
+ case 'textarea':
+ $value = wc_sanitize_textarea( $value );
+ break;
+ case 'password':
+ break;
+ default:
+ $value = wc_clean( $value );
+ break;
+ }
}
- // phpcs:enable WordPress.Security.NonceVerification.Missing
$data[ $key ] = apply_filters( 'woocommerce_process_checkout_' . $type . '_field', apply_filters( 'woocommerce_process_checkout_field_' . $key, $value ) );
}
@@ -1123,7 +1132,7 @@ class WC_Checkout {
*/
public function process_checkout() {
try {
- $nonce_value = wc_get_var( $_REQUEST['woocommerce-process-checkout-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
+ $nonce_value = wc_get_var( $_REQUEST['woocommerce-process-checkout-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // phpcs:ignore
if ( empty( $nonce_value ) || ! wp_verify_nonce( $nonce_value, 'woocommerce-process_checkout' ) ) {
WC()->session->set( 'refresh_totals', true );
diff --git a/includes/class-wc-countries.php b/includes/class-wc-countries.php
index 064f035cabc..e20d1358b27 100644
--- a/includes/class-wc-countries.php
+++ b/includes/class-wc-countries.php
@@ -365,7 +365,7 @@ class WC_Countries {
* @return string[]
*/
public function get_european_union_countries( $type = '' ) {
- $countries = array( 'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HU', 'HR', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK' );
+ $countries = array( 'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK' );
if ( 'eu_vat' === $type ) {
$countries[] = 'MC';
@@ -383,7 +383,7 @@ class WC_Countries {
*/
public function countries_using_vat() {
wc_deprecated_function( 'countries_using_vat', '4.0', 'WC_Countries::get_vat_countries' );
- $countries = array( 'AL', 'AR', 'AZ', 'BS', 'BH', 'BY', 'BB', 'BO', 'EG', 'ET', 'CL', 'CO', 'EC', 'SV', 'FJ', 'GM', 'GH', 'GT', 'IN', 'IR', 'IL', 'KZ', 'MU', 'MK', 'MX', 'MD', 'MN', 'ME', 'NA', 'NP', 'NG', 'PS', 'PY', 'RU', 'RW', 'KN', 'SA', 'RS', 'ZA', 'KR', 'LK', 'TH', 'TR', 'UA', 'UY', 'UZ', 'VE', 'VN', 'AE' );
+ $countries = array( 'AE', 'AL', 'AR', 'AZ', 'BB', 'BH', 'BO', 'BS', 'BY', 'CL', 'CO', 'EC', 'EG', 'ET', 'FJ', 'GH', 'GM', 'GT', 'IL', 'IN', 'IR', 'KN', 'KR', 'KZ', 'LK', 'MD', 'ME', 'MK', 'MN', 'MU', 'MX', 'NA', 'NG', 'NP', 'PS', 'PY', 'RS', 'RU', 'RW', 'SA', 'SV', 'TH', 'TR', 'UA', 'UY', 'UZ', 'VE', 'VN', 'ZA' );
return apply_filters( 'woocommerce_countries_using_vat', $countries );
}
@@ -409,7 +409,7 @@ class WC_Countries {
*/
public function shipping_to_prefix( $country_code = '' ) {
$country_code = $country_code ? $country_code : WC()->customer->get_shipping_country();
- $countries = array( 'GB', 'US', 'AE', 'CZ', 'DO', 'NL', 'PH', 'USAF' );
+ $countries = array( 'AE', 'CZ', 'DO', 'GB', 'NL', 'PH', 'US', 'USAF' );
$return = in_array( $country_code, $countries, true ) ? __( 'to the', 'woocommerce' ) : __( 'to', 'woocommerce' );
return apply_filters( 'woocommerce_countries_shipping_to_prefix', $return, $country_code );
@@ -423,7 +423,7 @@ class WC_Countries {
*/
public function estimated_for_prefix( $country_code = '' ) {
$country_code = $country_code ? $country_code : $this->get_base_country();
- $countries = array( 'GB', 'US', 'AE', 'CZ', 'DO', 'NL', 'PH', 'USAF' );
+ $countries = array( 'AE', 'CZ', 'DO', 'GB', 'NL', 'PH', 'US', 'USAF' );
$return = in_array( $country_code, $countries, true ) ? __( 'the', 'woocommerce' ) . ' ' : '';
return apply_filters( 'woocommerce_countries_estimated_for_prefix', $return, $country_code );
@@ -510,8 +510,8 @@ class WC_Countries {
'woocommerce_localisation_address_formats',
array(
'default' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}\n{state}\n{postcode}\n{country}",
- 'AU' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {state} {postcode}\n{country}",
'AT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
+ 'AU' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {state} {postcode}\n{country}",
'BE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'CA' => "{company}\n{name}\n{address_1}\n{address_2}\n{city} {state_code} {postcode}\n{country}",
'CH' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
@@ -519,9 +519,10 @@ class WC_Countries {
'CN' => "{country} {postcode}\n{state}, {city}, {address_2}, {address_1}\n{company}\n{name}",
'CZ' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'DE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
- 'EE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
- 'FI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'DK' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
+ 'EE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
+ 'ES' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city}\n{state}\n{country}",
+ 'FI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'FR' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city_upper}\n{country}",
'HK' => "{company}\n{first_name} {last_name_upper}\n{address_1}\n{address_2}\n{city_upper}\n{state_upper}\n{country}",
'HU' => "{last_name} {first_name}\n{company}\n{city}\n{address_1}\n{address_2}\n{postcode}\n{country}",
@@ -530,20 +531,19 @@ class WC_Countries {
'IT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode}\n{city}\n{state_upper}\n{country}",
'JM' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}\n{state}\n{postcode_upper}\n{country}",
'JP' => "{postcode}\n{state} {city} {address_1}\n{address_2}\n{company}\n{last_name} {first_name}\n{country}",
- 'TW' => "{company}\n{last_name} {first_name}\n{address_1}\n{address_2}\n{state}, {city} {postcode}\n{country}",
'LI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'NL' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
- 'NZ' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {postcode}\n{country}",
'NO' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
+ 'NZ' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {postcode}\n{country}",
'PL' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'PR' => "{company}\n{name}\n{address_1} {address_2}\n{city} \n{country} {postcode}",
'PT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
- 'SK' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'RS' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
- 'SI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
- 'ES' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city}\n{state}\n{country}",
'SE' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
+ 'SI' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
+ 'SK' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode} {city}\n{country}",
'TR' => "{name}\n{company}\n{address_1}\n{address_2}\n{postcode} {city} {state}\n{country}",
+ 'TW' => "{company}\n{last_name} {first_name}\n{address_1}\n{address_2}\n{state}, {city} {postcode}\n{country}",
'UG' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}\n{state}, {country}",
'US' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}, {state_code} {postcode}\n{country}",
'VN' => "{name}\n{company}\n{address_1}\n{city}\n{country}",
diff --git a/includes/class-wc-tax.php b/includes/class-wc-tax.php
index bf6956e6639..a59f60cc4de 100644
--- a/includes/class-wc-tax.php
+++ b/includes/class-wc-tax.php
@@ -82,13 +82,7 @@ class WC_Tax {
* @return array
*/
public static function calc_shipping_tax( $price, $rates ) {
- // Backwards compatible from WC_Shipping_Rate::get_cost().
- if ( has_filter( 'woocommerce_shipping_rate_cost' ) ) {
- $rate = new WC_Shipping_Rate();
- $price = $rate->get_cost();
- }
$taxes = self::calc_exclusive_tax( $price, $rates );
-
return apply_filters( 'woocommerce_calc_shipping_tax', $taxes, $price, $rates );
}
diff --git a/includes/class-woocommerce.php b/includes/class-woocommerce.php
index 8dff19c4d0c..e999e73c24e 100644
--- a/includes/class-woocommerce.php
+++ b/includes/class-woocommerce.php
@@ -25,7 +25,7 @@ final class WooCommerce {
*
* @var string
*/
- public $version = '5.3.0';
+ public $version = '5.5.0';
/**
* WooCommerce Schema version.
@@ -205,7 +205,6 @@ final class WooCommerce {
add_action( 'switch_blog', array( $this, 'wpdb_table_fix' ), 0 );
add_action( 'activated_plugin', array( $this, 'activated_plugin' ) );
add_action( 'deactivated_plugin', array( $this, 'deactivated_plugin' ) );
- add_filter( 'woocommerce_rest_prepare_note', array( 'WC_Admin_Notices', 'prepare_note_with_nonce' ) );
add_action( 'woocommerce_installed', array( $this, 'add_woocommerce_inbox_variant' ) );
add_action( 'woocommerce_updated', array( $this, 'add_woocommerce_inbox_variant' ) );
diff --git a/includes/gateways/paypal/includes/settings-paypal.php b/includes/gateways/paypal/includes/settings-paypal.php
index d9d56ddaadf..53729429e8e 100644
--- a/includes/gateways/paypal/includes/settings-paypal.php
+++ b/includes/gateways/paypal/includes/settings-paypal.php
@@ -58,7 +58,7 @@ return array(
'description' => sprintf( __( 'Log PayPal events, such as IPN requests, inside %s Note: this may log personal information. We recommend using this for debugging purposes only and deleting the logs when finished.', 'woocommerce' ), '' . WC_Log_Handler_File::get_log_file_path( 'paypal' ) . '
' ),
),
'ipn_notification' => array(
- 'title' => __( 'IPN Email Notifications', 'woocommerce' ),
+ 'title' => __( 'IPN email notifications', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable IPN email notifications', 'woocommerce' ),
'default' => 'yes',
diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-crud-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-crud-controller.php
index 2ebf47a1eab..310bd2367e0 100644
--- a/includes/rest-api/Controllers/Version3/class-wc-rest-crud-controller.php
+++ b/includes/rest-api/Controllers/Version3/class-wc-rest-crud-controller.php
@@ -303,7 +303,7 @@ abstract class WC_REST_CRUD_Controller extends WC_REST_Posts_Controller {
// Check flag to use post_date vs post_date_gmt.
if ( true === $request['dates_are_gmt'] ) {
if ( isset( $request['before'] ) || isset( $request['after'] ) ) {
- $args['date_query']['column'] = 'post_date_gmt';
+ $args['date_query'][0]['column'] = 'post_date_gmt';
}
}
diff --git a/includes/widgets/class-wc-widget-products.php b/includes/widgets/class-wc-widget-products.php
index be373488920..4d5b61240a7 100644
--- a/includes/widgets/class-wc-widget-products.php
+++ b/includes/widgets/class-wc-widget-products.php
@@ -186,6 +186,8 @@ class WC_Widget_Products extends WC_Widget {
ob_start();
+ wc_set_loop_prop( 'name', 'widget' );
+
$products = $this->get_products( $args, $instance );
if ( $products && $products->have_posts() ) {
$this->widget_start( $args, $instance );
diff --git a/package-lock.json b/package-lock.json
index 0c5d1334562..92b593f6ebb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "woocommerce",
- "version": "5.3.0",
+ "version": "5.5.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -9308,7 +9308,7 @@
}
},
"prettier": {
- "version": "npm:wp-prettier@1.19.1",
+ "version": "npm:prettier@1.19.1",
"resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-1.19.1.tgz",
"integrity": "sha512-mqAC2r1NDmRjG+z3KCJ/i61tycKlmADIjxnDhQab+KBxSAGbF/W7/zwB2guy/ypIeKrrftNsIYkNZZQKf3vJcg==",
"dev": true
diff --git a/package.json b/package.json
index 00559ae31f1..3c9b50a16e1 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "woocommerce",
"title": "WooCommerce",
- "version": "5.4.0",
+ "version": "5.5.0",
"homepage": "https://woocommerce.com/",
"repository": {
"type": "git",
diff --git a/templates/emails/customer-invoice.php b/templates/emails/customer-invoice.php
index e0564448390..139512a5b22 100644
--- a/templates/emails/customer-invoice.php
+++ b/templates/emails/customer-invoice.php
@@ -29,7 +29,7 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
get_billing_first_name() ) ); ?>
-has_status( 'pending' ) ) { ?>
+needs_payment() ) { ?>
{
As a convenience utility we've created repositories for core data types that can simplify interacting with the API:
+#### Parent/Base Repositories
+
- `SimpleProduct`
- `ExternalProduct`
- `GroupedProduct`
- `VariableProduct`
-- `ProductVariation`
- `Coupon`
+- `Order`
+- `SettingsGroup`
+
+#### Child Repositories
+
+- `ProductVariation`
+- `Setting`
These repositories provide CRUD methods for ease-of-use:
@@ -80,7 +88,7 @@ product.id;
#### Repository Methods
-The following methods are available on all repositories:
+The following methods are available on all repositories if the corresponding method is available on the API endpoint:
- `create( {...properties} )` - Create a single object of the model type
- `delete( objectId )` - Delete a single object of the model type
@@ -90,14 +98,14 @@ The following methods are available on all repositories:
#### Child Repositories
-`ProductVariation` is a child model repository. In child model repositories, each method requires the `parentId` as the first parameter:
+In child model repositories, each method requires the `parentId` as the first parameter:
```javascript
import { HTTPClientFactory, VariableProduct, ProductVariation } from '@woocommerce/api';
const httpClient = HTTPClientFactory.build( 'https://example.com' )
.withBasicAuth( 'username', 'password' )
- .withIndexPermalinks()
+ .withIndexPermalinks()
.create();
const productRepository = VariableProduct.restRepository( httpClient );
diff --git a/tests/e2e/api/src/models/coupons/coupon.ts b/tests/e2e/api/src/models/coupons/coupon.ts
index a0ee904de29..20e3f42ee9b 100644
--- a/tests/e2e/api/src/models/coupons/coupon.ts
+++ b/tests/e2e/api/src/models/coupons/coupon.ts
@@ -12,6 +12,7 @@ import {
import {
CouponUpdateParams,
} from './shared';
+import { ObjectLinks } from '../shared-types';
/**
* The parameters embedded in this generic can be used in the ModelRepository in order to give
@@ -222,6 +223,16 @@ export class Coupon extends Model {
*/
public readonly usedBy: Array = [];
+ /**
+ * The coupon's links.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly links: ObjectLinks = {
+ collection: [ { href: '' } ],
+ self: [ { href: '' } ],
+ };
+
/**
* Creates a new coupon instance with the given properties
*
diff --git a/tests/e2e/api/src/models/index.ts b/tests/e2e/api/src/models/index.ts
index 13ce569f196..902fdec58e3 100644
--- a/tests/e2e/api/src/models/index.ts
+++ b/tests/e2e/api/src/models/index.ts
@@ -3,3 +3,4 @@ export * from './model';
export * from './settings';
export * from './shared-types';
export * from './coupons';
+export * from './orders';
diff --git a/tests/e2e/api/src/models/orders/index.ts b/tests/e2e/api/src/models/orders/index.ts
new file mode 100644
index 00000000000..d4df1e6ca90
--- /dev/null
+++ b/tests/e2e/api/src/models/orders/index.ts
@@ -0,0 +1,2 @@
+export * from './orders';
+export * from './shared';
diff --git a/tests/e2e/api/src/models/orders/orders.ts b/tests/e2e/api/src/models/orders/orders.ts
new file mode 100644
index 00000000000..d23c4ca7611
--- /dev/null
+++ b/tests/e2e/api/src/models/orders/orders.ts
@@ -0,0 +1,369 @@
+import { HTTPClient } from '../../http';
+import { orderRESTRepository } from '../../repositories';
+import {
+ ModelRepositoryParams,
+ CreatesModels,
+ ListsModels,
+ ReadsModels,
+ UpdatesModels,
+ DeletesModels,
+} from '../../framework';
+import {
+ OrderAddressUpdateParams,
+ OrderCouponUpdateParams,
+ OrderDataUpdateParams,
+ OrderFeeUpdateParams,
+ OrderLineItemUpdateParams,
+ OrderRefundUpdateParams,
+ OrderShippingUpdateParams,
+ OrderTaxUpdateParams,
+ OrderTotalUpdateParams,
+ OrderItemMeta,
+ OrderAddress,
+ OrderCouponLine,
+ OrderFeeLine,
+ OrderLineItem,
+ OrderRefundLine,
+ OrderShippingLine,
+ OrderStatus,
+ OrderTaxRate,
+} from './shared';
+import { ObjectLinks } from '../shared-types';
+
+/**
+ * The parameters that orders can update.
+ */
+type OrderUpdateParams = OrderAddressUpdateParams
+ & OrderCouponUpdateParams
+ & OrderDataUpdateParams
+ & OrderFeeUpdateParams
+ & OrderLineItemUpdateParams
+ & OrderRefundUpdateParams
+ & OrderShippingUpdateParams
+ & OrderTaxUpdateParams
+ & OrderTotalUpdateParams;
+
+/**
+ * The parameters embedded in this generic can be used in the ModelRepository in order to give
+ * type-safety in an incredibly granular way.
+ */
+export type OrderRepositoryParams = ModelRepositoryParams< Order, never, never, OrderUpdateParams >;
+
+/**
+ * An interface for creating orders using the repository.
+ *
+ * @typedef CreatesOrders
+ * @alias CreatesModels.
+ */
+export type CreatesOrders = CreatesModels< OrderRepositoryParams >;
+
+/**
+ * An interface for reading orders using the repository.
+ *
+ * @typedef ReadsOrders
+ * @alias ReadsModels.
+ */
+export type ReadsOrders = ReadsModels< OrderRepositoryParams >;
+
+/**
+ * An interface for updating orders using the repository.
+ *
+ * @typedef UpdatesOrders
+ * @alias UpdatesModels.
+ */
+export type UpdatesOrders = UpdatesModels< OrderRepositoryParams >;
+
+/**
+ * An interface for listing orders using the repository.
+ *
+ * @typedef ListsOrders
+ * @alias ListsModels.
+ */
+export type ListsOrders = ListsModels< OrderRepositoryParams >;
+
+/**
+ * An interface for deleting orders using the repository.
+ *
+ * @typedef DeletesOrders
+ * @alias DeletesModels.
+ */
+export type DeletesOrders = DeletesModels< OrderRepositoryParams >;
+
+/**
+ * An order object.
+ */
+export class Order extends OrderItemMeta {
+ /**
+ * The parent order id.
+ *
+ * @type {number}
+ */
+ public readonly parentId: number = 0;
+
+ /**
+ * The order status.
+ *
+ * @type {string}
+ */
+ public readonly status: OrderStatus = '';
+
+ /**
+ * The order currency.
+ *
+ * @type {string}
+ */
+ public readonly currency: string = '';
+
+ /**
+ * The WC version used to create the order.
+ *
+ * @type {string}
+ */
+ public readonly version: string = '';
+
+ /**
+ * Flags if the prices include tax.
+ *
+ * @type {boolean}
+ */
+ public readonly pricesIncludeTax: boolean = false;
+
+ /**
+ * The total of the discounts on the order.
+ *
+ * @type {string}
+ */
+ public readonly discountTotal: string = '';
+
+ /**
+ * The total of the tax on discounts on the order.
+ *
+ * @type {string}
+ */
+ public readonly discountTax: string = '';
+
+ /**
+ * The total of the shipping on the order.
+ *
+ * @type {string}
+ */
+ public readonly shippingTotal: string = '';
+
+ /**
+ * The total of the tax on shipping on the order.
+ *
+ * @type {string}
+ */
+ public readonly shippingTax: string = '';
+
+ /**
+ * The total cart tax on the order.
+ *
+ * @type {string}
+ */
+ public readonly cartTax: string = '';
+
+ /**
+ * The total for the order including adjustments.
+ *
+ * @type {string}
+ */
+ public readonly total: string = '';
+
+ /**
+ * The total tax for the order including adjustments.
+ *
+ * @type {string}
+ */
+ public readonly totalTax: string = '';
+
+ /**
+ * The customer id.
+ *
+ * @type {number}
+ */
+ public readonly customerId: number = 0;
+
+ /**
+ * A unique key assigned to the order.
+ *
+ * @type {string}
+ */
+ public readonly orderKey: string = '';
+
+ /**
+ * The billing address.
+ *
+ * @type {OrderAddress}
+ */
+ public readonly billing: OrderAddress | null = null;
+
+ /**
+ * The shipping address.
+ *
+ * @type {OrderAddress}
+ */
+ public readonly shipping: OrderAddress | null = null;
+
+ /**
+ * Name of the payment method.
+ *
+ * @type {string}
+ */
+ public readonly paymentMethod: string = '';
+
+ /**
+ * Title of the payment method
+ *
+ * @type {string}
+ */
+ public readonly paymentMethodTitle: string = '';
+
+ /**
+ * Payment transaction ID.
+ *
+ * @type {string}
+ */
+ public readonly transactionId: string = '';
+
+ /**
+ * Customer IP address.
+ *
+ * @type {string}
+ */
+ public readonly customerIpAddress: string = '';
+
+ /**
+ * Customer web browser user agent.
+ *
+ * @type {string}
+ */
+ public readonly customerUserAgent: string = '';
+
+ /**
+ * Method used to create the order.
+ *
+ * @type {string}
+ */
+ public readonly createdVia: string = '';
+
+ /**
+ * Customer note.
+ *
+ * @type {string}
+ */
+ public readonly customerNote: string = '';
+
+ /**
+ * Date the order was completed.
+ *
+ * @type {string}
+ */
+ public readonly dateCompleted: Date | null = null;
+
+ /**
+ * Date the order was paid.
+ *
+ * @type {string}
+ */
+ public readonly datePaid: Date | null = null;
+
+ /**
+ * Hash of the cart's contents.
+ *
+ * @type {string}
+ */
+ public readonly cartHash: string = '';
+
+ /**
+ * Number assigned to the order.
+ *
+ * @type {string}
+ */
+ public readonly orderNumber: string = '';
+
+ /**
+ * Currency symbol for the order.
+ *
+ * @type {string}
+ */
+ public readonly currencySymbol: string = '';
+
+ /**
+ * The order's paid state.
+ *
+ * @type {boolean}
+ */
+ public readonly setPaid: boolean = false;
+
+ /**
+ * The order's line items.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly lineItems: OrderLineItem[] = [];
+
+ /**
+ * The order's tax rates.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly taxLines: OrderTaxRate[] = [];
+
+ /**
+ * The order's shipping charges.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly shippingLines: OrderShippingLine[] = [];
+
+ /**
+ * The order's fees.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly feeLines: OrderFeeLine[] = [];
+
+ /**
+ * The coupons used on the order.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly couponLines: OrderCouponLine[] = [];
+
+ /**
+ * The refunds to the order.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly refunds: OrderRefundLine[] = [];
+
+ /**
+ * The order's links.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly links: ObjectLinks = {
+ collection: [ { href: '' } ],
+ self: [ { href: '' } ],
+ };
+
+ /**
+ * Creates a new order instance with the given properties
+ *
+ * @param {Object} properties The properties to set in the object.
+ */
+ public constructor( properties?: Partial< Order > ) {
+ super();
+ Object.assign( this, properties );
+ }
+
+ /**
+ * Returns the repository for interacting with this type of model.
+ *
+ * @param {HTTPClient} httpClient The client for communicating via HTTP.
+ */
+ public static restRepository( httpClient: HTTPClient ): ReturnType< typeof orderRESTRepository > {
+ return orderRESTRepository( httpClient );
+ }
+}
diff --git a/tests/e2e/api/src/models/orders/shared/classes.ts b/tests/e2e/api/src/models/orders/shared/classes.ts
new file mode 100644
index 00000000000..540c543d4ae
--- /dev/null
+++ b/tests/e2e/api/src/models/orders/shared/classes.ts
@@ -0,0 +1,412 @@
+import { MetaData } from '../../shared-types';
+import { Model } from '../../model';
+import { TaxStatus } from './types';
+
+/**
+ * Order item meta.
+ */
+export class OrderItemMeta extends Model {
+ /**
+ * The meta data the order item.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly metaData: MetaData[] = [];
+}
+
+/**
+ * Order line item tax entry.
+ */
+export class OrderItemTax extends Model {
+ /**
+ * The total tax for this tax rate on this item.
+ *
+ * @type {string}
+ */
+ public readonly total: string = '';
+
+ /**
+ * The subtotal tax for this tax rate on this item.
+ *
+ * @type {string}
+ */
+ public readonly subtotal: string = '';
+}
+
+/**
+ * An order address.
+ */
+export class OrderAddress extends Model {
+ /**
+ * The first name of the person in the address.
+ *
+ * @type {string}
+ */
+ public readonly firstName: string = '';
+
+ /**
+ * The last name of the person in the address.
+ *
+ * @type {string}
+ */
+ public readonly lastName: string = '';
+
+ /**
+ * The company name of the person in the address.
+ *
+ * @type {string}
+ */
+ public readonly companyName: string = '';
+
+ /**
+ * The first address line in the address.
+ *
+ * @type {string}
+ */
+ public readonly address1: string = '';
+
+ /**
+ * The second address line in the address.
+ *
+ * @type {string}
+ */
+ public readonly address2: string = '';
+
+ /**
+ * The city in the address.
+ *
+ * @type {string}
+ */
+ public readonly city: string = '';
+
+ /**
+ * The state in the address.
+ *
+ * @type {string}
+ */
+ public readonly state: string = '';
+
+ /**
+ * The postal code in the address.
+ *
+ * @type {string}
+ */
+ public readonly postCode: string = '';
+
+ /**
+ * The country code for the address.
+ *
+ * @type {string}
+ */
+ public readonly countryCode: string = '';
+
+ /**
+ * The email address of the person in the address.
+ *
+ * @type {string}
+ */
+ public readonly email: string = '';
+
+ /**
+ * The phone number of the person in the address.
+ *
+ * @type {string}
+ */
+ public readonly phone: string = '';
+}
+
+/**
+ * Order Line Item
+ */
+export class OrderLineItem extends OrderItemMeta {
+ /**
+ * The name of the product.
+ *
+ * @type {string}
+ */
+ public readonly name: string = '';
+
+ /**
+ * The ID of the product.
+ *
+ * @type {number}
+ */
+ public readonly productId: number = -1;
+
+ /**
+ * The ID of the product variation.
+ *
+ * @type {number}
+ */
+ public readonly variationId: number = 0;
+
+ /**
+ * The quantity of the product.
+ *
+ * @type {number}
+ */
+ public readonly quantity: number = -1;
+
+ /**
+ * The tax class for the product.
+ *
+ * @type {string}
+ */
+ public readonly taxClass: string = '';
+
+ /**
+ * The subtotal for the product.
+ *
+ * @type {string}
+ */
+ public readonly subtotal: string = '';
+
+ /**
+ * The subtotal tax for the product.
+ *
+ * @type {string}
+ */
+ public readonly subtotalTax: string = '';
+
+ /**
+ * The total for the product including adjustments.
+ *
+ * @type {string}
+ */
+ public readonly total: string = '';
+
+ /**
+ * The total tax for the product including adjustments.
+ *
+ * @type {string}
+ */
+ public readonly totalTax: string = '';
+
+ /**
+ * The taxes applied to the product.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly taxes: OrderItemTax[] = [];
+
+ /**
+ * The product SKU.
+ *
+ * @type {string}
+ */
+ public readonly sku: string = '';
+
+ /**
+ * The price of the product.
+ *
+ * @type {number}
+ */
+ public readonly price: number = -1;
+
+ /**
+ * The name of the parent product.
+ *
+ * @type {string|null}
+ */
+ public readonly parentName: string | null = null;
+}
+
+/**
+ * Order Tax Rate
+ */
+export class OrderTaxRate extends Model {
+ /**
+ * The tax rate code.
+ *
+ * @type {string}
+ */
+ public readonly rateCode: string = '';
+
+ /**
+ * The tax rate id.
+ *
+ * @type {number}
+ */
+ public readonly rateId: number = 0;
+
+ /**
+ * The tax label.
+ *
+ * @type {string}
+ */
+ public readonly label: string = '';
+
+ /**
+ * Flag indicating whether it's a compound tax rate.
+ *
+ * @type {boolean}
+ */
+ public readonly compoundRate: boolean = false;
+
+ /**
+ * The total tax for this rate code.
+ *
+ * @type {string}
+ */
+ public readonly taxTotal: string = '';
+
+ /**
+ * The total shipping tax for this rate code.
+ *
+ * @type {string}
+ */
+ public readonly shippingTaxTotal: string = '';
+
+ /**
+ * The tax rate as a percentage.
+ *
+ * @type {number}
+ */
+ public readonly ratePercent: number = 0;
+}
+
+/**
+ * Order shipping line
+ */
+export class OrderShippingLine extends OrderItemMeta {
+ /**
+ * The shipping method title.
+ *
+ * @type {string}
+ */
+ public readonly methodTitle: string = '';
+
+ /**
+ * The shipping method id.
+ *
+ * @type {string}
+ */
+ public readonly methodId: string = '';
+
+ /**
+ * The shipping method instance id.
+ *
+ * @type {string}
+ */
+ public readonly instanceId: string = '';
+
+ /**
+ * The total shipping amount for this method.
+ *
+ * @type {string}
+ */
+ public readonly total: string = '';
+
+ /**
+ * The total tax amount for this shipping method.
+ *
+ * @type {string}
+ */
+ public readonly totalTax: string = '';
+
+ /**
+ * The taxes applied to this shipping method.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly taxes: OrderItemTax[] = [];
+}
+
+/**
+ * Order fee line
+ */
+export class OrderFeeLine extends OrderItemMeta {
+ /**
+ * The name of the fee.
+ *
+ * @type {string}
+ */
+ public readonly name: string = '';
+
+ /**
+ * The tax class of the fee.
+ *
+ * @type {string}
+ */
+ public readonly taxClass: string = '';
+
+ /**
+ * The tax status of the fee.
+ *
+ * @type {TaxStatus}
+ */
+ public readonly taxStatus: TaxStatus = 'taxable';
+
+ /**
+ * The total amount for this fee.
+ *
+ * @type {string}
+ */
+ public readonly amount: string = '';
+
+ /**
+ * The display total amount for this fee.
+ *
+ * @type {string}
+ */
+ public readonly total: string = '';
+
+ /**
+ * The total tax amount for this fee.
+ *
+ * @type {string}
+ */
+ public readonly totalTax: string = '';
+
+ /**
+ * The taxes applied to this fee.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly taxes: OrderItemTax[] = [];
+}
+
+/**
+ * Order coupon line
+ */
+export class OrderCouponLine extends OrderItemMeta {
+ /**
+ * The coupon code
+ *
+ * @type {string}
+ */
+ public readonly code: string = '';
+
+ /**
+ * The discount amount.
+ *
+ * @type {string}
+ */
+ public readonly discount: string = '';
+
+ /**
+ * The discount tax.
+ *
+ * @type {string}
+ */
+ public readonly discountTax: string = '';
+}
+
+/**
+ * Order refund line
+ */
+export class OrderRefundLine extends Model {
+ /**
+ * The reason for giving the refund.
+ *
+ * @type {string}
+ */
+ public readonly reason: string = '';
+
+ /**
+ * The total amount of the refund.
+ *
+ * @type {string}
+ */
+ public readonly total: string = '';
+}
diff --git a/tests/e2e/api/src/models/orders/shared/index.ts b/tests/e2e/api/src/models/orders/shared/index.ts
new file mode 100644
index 00000000000..15eb796c953
--- /dev/null
+++ b/tests/e2e/api/src/models/orders/shared/index.ts
@@ -0,0 +1,2 @@
+export * from './classes';
+export * from './types';
diff --git a/tests/e2e/api/src/models/orders/shared/types.ts b/tests/e2e/api/src/models/orders/shared/types.ts
new file mode 100644
index 00000000000..adeba0128c4
--- /dev/null
+++ b/tests/e2e/api/src/models/orders/shared/types.ts
@@ -0,0 +1,66 @@
+/**
+ * An order's status.
+ *
+ * @typedef OrderStatus
+ */
+export type OrderStatus = 'pending' | 'processing' | 'complete' | 'on-hold' | 'refunded'
+ | 'cancelled' | 'failed' | 'trash' | string;
+
+/**
+ * An fee's tax status.
+ *
+ * @typedef TaxStatus
+ */
+export type TaxStatus = 'taxable' | 'none';
+
+/**
+ * Base order properties
+ */
+export type OrderDataUpdateParams = 'id' | 'parentId' | 'status' | 'currency' | 'version'
+ | 'pricesIncludeTax' | 'discountTotal' | 'discountTax' | 'shippingTotal' | 'shippingTax'
+ | 'cartTax' | 'customerId' | 'orderKey' | 'paymentMethod' | 'paymentMethodTitle'
+ | 'transactionId' | 'customerIpAddress' | 'customerUserAgent' | 'createdVia' | 'datePaid'
+ | 'customerNote' | 'dateCompleted' | 'cartHash' | 'orderNumber' | 'currencySymbol';
+
+/**
+ * Common total properties
+ */
+export type OrderTotalUpdateParams = 'total' | 'totalTax';
+
+/**
+ * Order address properties
+ */
+export type OrderAddressUpdateParams = 'firstName' | 'lastName' | 'companyName' | 'address1'
+ | 'address2' | 'city' | 'state' | 'postCode' | 'countryCode' | 'email' | 'phone';
+
+/**
+ * Line item properties
+ */
+export type OrderLineItemUpdateParams = 'name' | 'ProductId' | 'variationId' | 'quantity'
+ | 'taxClass' | 'subtotal' | 'subtotalTax' | 'sku' | 'price' | 'parentName';
+
+/**
+ * Tax rate properties
+ */
+export type OrderTaxUpdateParams = 'rateCode' | 'rateId' | 'label' | 'compoundRate'
+ | 'taxTotal' | 'shippingTaxTotal' | 'ratePercent';
+
+/**
+ * Order shipping properties
+ */
+export type OrderShippingUpdateParams = 'methodTitle' | 'methodId' | 'instanceId';
+
+/**
+ * Order fee properties
+ */
+export type OrderFeeUpdateParams = 'name' | 'taxClass' | 'taxStatus' | 'amount';
+
+/**
+ * Order coupon properties
+ */
+export type OrderCouponUpdateParams = 'code' | 'discount' | 'discountTax';
+
+/**
+ * Order refund properties
+ */
+export type OrderRefundUpdateParams = 'reason' | 'total';
diff --git a/tests/e2e/api/src/models/products/abstract/common.ts b/tests/e2e/api/src/models/products/abstract/common.ts
index d9a4a3525db..bab3e1dc6b7 100644
--- a/tests/e2e/api/src/models/products/abstract/common.ts
+++ b/tests/e2e/api/src/models/products/abstract/common.ts
@@ -3,9 +3,9 @@ import { ModelID } from '../../model';
import {
CatalogVisibility,
ProductTerm,
- ProductLinks,
ProductAttribute,
} from '../shared';
+import { ObjectLinks } from '../../shared-types';
/**
* The common parameters that all products can use in search.
@@ -145,11 +145,11 @@ export abstract class AbstractProduct extends AbstractProductData {
public readonly attributes: readonly ProductAttribute[] = [];
/**
- * The products links.
+ * The product's links.
*
- * @type {ReadonlyArray.}
+ * @type {ReadonlyArray.}
*/
- public readonly links: ProductLinks = {
+ public readonly links: ObjectLinks = {
collection: [ { href: '' } ],
self: [ { href: '' } ],
};
diff --git a/tests/e2e/api/src/models/products/abstract/data.ts b/tests/e2e/api/src/models/products/abstract/data.ts
index 0d1b83cb37e..e76c1c7d9d8 100644
--- a/tests/e2e/api/src/models/products/abstract/data.ts
+++ b/tests/e2e/api/src/models/products/abstract/data.ts
@@ -1,6 +1,6 @@
import { Model } from '../../model';
-import { MetaData, PostStatus } from '../../shared-types';
-import { ProductImage, ProductLinks } from '../shared';
+import { MetaData, PostStatus, ObjectLinks } from '../../shared-types';
+import { ProductImage } from '../shared';
/**
* Base product data.
@@ -93,9 +93,9 @@ export abstract class AbstractProductData extends Model {
/**
* The product data links.
*
- * @type {ReadonlyArray.}
+ * @type {ReadonlyArray.}
*/
- public readonly links: ProductLinks = {
+ public readonly links: ObjectLinks = {
collection: [ { href: '' } ],
self: [ { href: '' } ],
};
diff --git a/tests/e2e/api/src/models/products/shared/classes.ts b/tests/e2e/api/src/models/products/shared/classes.ts
index 7343c594352..c08e0a20b70 100644
--- a/tests/e2e/api/src/models/products/shared/classes.ts
+++ b/tests/e2e/api/src/models/products/shared/classes.ts
@@ -208,59 +208,3 @@ export class ProductImage {
Object.assign( this, properties );
}
}
-
-/**
- * A product link item.
- */
-class ProductLinkItem {
- /**
- * The options which are available for the attribute.
- *
- * @type {ReadonlyArray.}
- */
- public readonly href: string = '';
-
- /**
- * Creates a new product link item.
- *
- * @param {Partial.} properties The properties to set.
- */
- public constructor( properties?: Partial< ProductLinkItem > ) {
- Object.assign( this, properties );
- }
-}
-
-/**
- * A product's links.
- */
-export class ProductLinks {
- /**
- * The collection containing the product.
- *
- * @type {ReadonlyArray.}
- */
- public readonly collection: readonly ProductLinkItem[] = [];
-
- /**
- * Self referential link to the product.
- *
- * @type {ReadonlyArray.}
- */
- public readonly self: readonly ProductLinkItem[] = [];
-
- /**
- * The link to the parent.
- *
- * @type {ReadonlyArray.}
- */
- public readonly up?: readonly ProductLinkItem[] = [];
-
- /**
- * Creates a new product link list.
- *
- * @param {Partial.} properties The properties to set.
- */
- public constructor( properties?: Partial< ProductLinks > ) {
- Object.assign( this, properties );
- }
-}
diff --git a/tests/e2e/api/src/models/products/variation.ts b/tests/e2e/api/src/models/products/variation.ts
index 78e8580c2fa..beb1bad8071 100644
--- a/tests/e2e/api/src/models/products/variation.ts
+++ b/tests/e2e/api/src/models/products/variation.ts
@@ -15,13 +15,13 @@ import {
ProductPriceUpdateParams,
ProductSalesTaxUpdateParams,
ProductShippingUpdateParams,
- ProductLinks,
Taxability,
ProductDownload,
StockStatus,
BackorderStatus,
ProductDefaultAttribute,
} from './shared';
+import { ObjectLinks } from '../shared-types';
import {
CreatesChildModels,
DeletesChildModels,
@@ -149,11 +149,11 @@ export class ProductVariation extends AbstractProductData implements
public readonly shippingClassId: number = 0;
/**
- * The variation links.
+ * The variation's links.
*
- * @type {ReadonlyArray.}
+ * @type {ReadonlyArray.}
*/
- public readonly links: ProductLinks = {
+ public readonly links: ObjectLinks = {
collection: [ { href: '' } ],
self: [ { href: '' } ],
up: [ { href: '' } ],
diff --git a/tests/e2e/api/src/models/shared-types.ts b/tests/e2e/api/src/models/shared-types.ts
index 5f64fff0b72..d041f3c48c8 100644
--- a/tests/e2e/api/src/models/shared-types.ts
+++ b/tests/e2e/api/src/models/shared-types.ts
@@ -35,6 +35,20 @@ export class MetaData extends Model {
*/
public readonly value: any = '';
+ /**
+ * The key of the metadata.
+ *
+ * @type {string}
+ */
+ public readonly displayKey?: string = '';
+
+ /**
+ * The value of the metadata.
+ *
+ * @type {*}
+ */
+ public readonly displayValue?: string = '';
+
/**
* Creates a new metadata.
*
@@ -45,3 +59,59 @@ export class MetaData extends Model {
Object.assign( this, properties );
}
}
+
+/**
+ * An object link item.
+ */
+class LinkItem {
+ /**
+ * The href of the link.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly href: string = '';
+
+ /**
+ * Creates a new product link item.
+ *
+ * @param {Partial.} properties The properties to set.
+ */
+ public constructor( properties?: Partial< LinkItem > ) {
+ Object.assign( this, properties );
+ }
+}
+
+/**
+ * An object's links.
+ */
+export class ObjectLinks {
+ /**
+ * The collection containing the object.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly collection: readonly LinkItem[] = [];
+
+ /**
+ * Self referential link to the object.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly self: readonly LinkItem[] = [];
+
+ /**
+ * The link to the parent object.
+ *
+ * @type {ReadonlyArray.}
+ */
+ public readonly up?: readonly LinkItem[] = [];
+
+ /**
+ * Creates a new product link list.
+ *
+ * @param {Partial.} properties The properties to set.
+ */
+ public constructor( properties?: Partial< ObjectLinks > ) {
+ Object.assign( this, properties );
+ }
+}
diff --git a/tests/e2e/api/src/repositories/rest/coupons/transformer.ts b/tests/e2e/api/src/repositories/rest/coupons/transformer.ts
index b3827471242..8e0c7d85eb9 100644
--- a/tests/e2e/api/src/repositories/rest/coupons/transformer.ts
+++ b/tests/e2e/api/src/repositories/rest/coupons/transformer.ts
@@ -57,6 +57,7 @@ export function createCouponTransformer(): ModelTransformer< Coupon > {
maximumAmount: 'maximum_amount',
emailRestrictions: 'email_restrictions',
usedBy: 'used_by',
+ links: '_links',
},
),
],
diff --git a/tests/e2e/api/src/repositories/rest/index.ts b/tests/e2e/api/src/repositories/rest/index.ts
index 15f18f10ee0..7ae5c9a38a2 100644
--- a/tests/e2e/api/src/repositories/rest/index.ts
+++ b/tests/e2e/api/src/repositories/rest/index.ts
@@ -1,3 +1,4 @@
-export * from './products';
-export * from './settings';
export * from './coupons';
+export * from './products';
+export * from './orders';
+export * from './settings';
diff --git a/tests/e2e/api/src/repositories/rest/orders/index.ts b/tests/e2e/api/src/repositories/rest/orders/index.ts
new file mode 100644
index 00000000000..fa4dd50d134
--- /dev/null
+++ b/tests/e2e/api/src/repositories/rest/orders/index.ts
@@ -0,0 +1,3 @@
+import orderRESTRepository from './order';
+
+export { orderRESTRepository };
diff --git a/tests/e2e/api/src/repositories/rest/orders/order.ts b/tests/e2e/api/src/repositories/rest/orders/order.ts
new file mode 100644
index 00000000000..76e29525982
--- /dev/null
+++ b/tests/e2e/api/src/repositories/rest/orders/order.ts
@@ -0,0 +1,47 @@
+import { HTTPClient } from '../../../http';
+import {
+ ModelRepository,
+} from '../../../framework';
+import {
+ ModelID,
+ Order,
+ OrderRepositoryParams,
+ ListsOrders,
+ ReadsOrders,
+ UpdatesOrders,
+ CreatesOrders,
+ DeletesOrders,
+} from '../../../models';
+
+import {
+ restList,
+ restCreate,
+ restRead,
+ restUpdate,
+ restDelete,
+} from '../shared';
+
+import { createOrderTransformer } from './transformer';
+/**
+ *
+ * @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
+ */
+export default function orderRESTRepository( httpClient: HTTPClient ): CreatesOrders
+& ListsOrders
+& ReadsOrders
+& UpdatesOrders
+& DeletesOrders {
+ const buildURL = ( id: ModelID ) => '/wc/v3/orders/' + id;
+ // Using `?force=true` permanently deletes the order
+ const buildDeleteUrl = ( id: ModelID ) => `/wc/v3/orders/${ id }?force=true`;
+
+ const transformer = createOrderTransformer();
+
+ return new ModelRepository(
+ restList< OrderRepositoryParams >( () => '/wc/v3/orders', Order, httpClient, transformer ),
+ restCreate< OrderRepositoryParams >( () => '/wc/v3/orders', Order, httpClient, transformer ),
+ restRead< OrderRepositoryParams >( buildURL, Order, httpClient, transformer ),
+ restUpdate< OrderRepositoryParams >( buildURL, Order, httpClient, transformer ),
+ restDelete< OrderRepositoryParams >( buildDeleteUrl, httpClient ),
+ );
+}
diff --git a/tests/e2e/api/src/repositories/rest/orders/transformer.ts b/tests/e2e/api/src/repositories/rest/orders/transformer.ts
new file mode 100644
index 00000000000..5cd3c0e2b6f
--- /dev/null
+++ b/tests/e2e/api/src/repositories/rest/orders/transformer.ts
@@ -0,0 +1,277 @@
+import {
+ IgnorePropertyTransformation,
+ KeyChangeTransformation,
+ ModelTransformer,
+ ModelTransformerTransformation,
+ PropertyType,
+ PropertyTypeTransformation,
+} from '../../../framework';
+import {
+ Order,
+ OrderAddress,
+ OrderCouponLine,
+ OrderFeeLine,
+ OrderLineItem,
+ OrderRefundLine,
+ OrderShippingLine,
+ OrderTaxRate,
+} from '../../../models';
+
+/**
+ * Creates a transformer for an order object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+export function createOrderTransformer(): ModelTransformer< Order > {
+ return new ModelTransformer(
+ [
+ new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
+ new ModelTransformerTransformation( 'billing', OrderAddress, createOrderAddressTransformer() ),
+ new ModelTransformerTransformation( 'tax_lines', OrderTaxRate, createOrderTaxRateTransformer() ),
+ new ModelTransformerTransformation( 'refunds', OrderRefundLine, createOrderRefundLineTransformer() ),
+ new ModelTransformerTransformation( 'coupon_lines', OrderCouponLine, createOrdeCouponLineTransformer() ),
+ new ModelTransformerTransformation( 'fee_lines', OrderFeeLine, createOrderFeeLineTransformer() ),
+ new ModelTransformerTransformation( 'line_items', OrderLineItem, createOrderLineItemTransformer() ),
+ new ModelTransformerTransformation( 'shipping_lines', OrderShippingLine, createOrderShippingItemTransformer() ),
+
+ new PropertyTypeTransformation(
+ {
+ status: PropertyType.String,
+ currency: PropertyType.String,
+ discountTotal: PropertyType.String,
+ discountTax: PropertyType.String,
+ shippingTotal: PropertyType.String,
+ shippingTax: PropertyType.String,
+ cartTax: PropertyType.String,
+ total: PropertyType.String,
+ totalTax: PropertyType.String,
+ pricesIncludeTax: PropertyType.Boolean,
+ customerId: PropertyType.Integer,
+ customerNote: PropertyType.String,
+ paymentMethod: PropertyType.String,
+ transactionId: PropertyType.String,
+ setPaid: PropertyType.Boolean,
+ },
+ ),
+ new KeyChangeTransformation< Order >(
+ {
+ discountTotal: 'discount_total',
+ discountTax: 'discount_tax',
+ shippingTotal: 'shipping_total',
+ shippingTax: 'shipping_tax',
+ cartTax: 'cart_tax',
+ totalTax: 'total_tax',
+ pricesIncludeTax: 'prices_include_tax',
+ customerId: 'customer_id',
+ customerNote: 'customer_note',
+ paymentMethod: 'payment_method',
+ transactionId: 'transaction_id',
+ setPaid: 'set_paid',
+ },
+ ),
+ ],
+ );
+}
+
+/**
+ * Creates a transformer for an order address object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+export function createOrderAddressTransformer(): ModelTransformer< OrderAddress > {
+ return new ModelTransformer(
+ [
+ new PropertyTypeTransformation(
+ {
+ firstName: PropertyType.String,
+ lastName: PropertyType.String,
+ company: PropertyType.String,
+ address1: PropertyType.String,
+ address2: PropertyType.String,
+ city: PropertyType.String,
+ state: PropertyType.String,
+ postCode: PropertyType.String,
+ country: PropertyType.String,
+ },
+ ),
+ new KeyChangeTransformation< OrderAddress >(
+ {
+ firstName: 'first_name',
+ lastName: 'last_name',
+ address1: 'address_1',
+ address2: 'address_2',
+ postCode: 'postcode',
+ },
+ ),
+ ],
+ );
+}
+
+/**
+ * Creates a transformer for an order tax rate object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+function createOrderTaxRateTransformer(): ModelTransformer< OrderTaxRate > {
+ return new ModelTransformer(
+ [
+ new PropertyTypeTransformation(
+ {
+ rateCode: PropertyType.String,
+ rateId: PropertyType.Integer,
+ label: PropertyType.String,
+ compoundRate: PropertyType.Boolean,
+ taxTotal: PropertyType.String,
+ shippingTaxTotal: PropertyType.String,
+ ratePercent: PropertyType.Integer,
+ },
+ ),
+ new KeyChangeTransformation< OrderTaxRate >(
+ {
+ rateCode: 'rate_code',
+ rateId: 'rate_id',
+ compoundRate: 'compound',
+ taxTotal: 'tax_total',
+ shippingTaxTotal: 'shipping_tax_total',
+ },
+ ),
+ ],
+ );
+}
+
+/**
+ * Creates a transformer for an order refund line object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+function createOrderRefundLineTransformer(): ModelTransformer< OrderRefundLine > {
+ return new ModelTransformer(
+ [
+ new PropertyTypeTransformation(
+ {
+ reason: PropertyType.String,
+ total: PropertyType.String,
+ },
+ ),
+ ],
+ );
+}
+
+/**
+ * Creates a transformer for an order coupon line object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+function createOrdeCouponLineTransformer(): ModelTransformer< OrderCouponLine > {
+ return new ModelTransformer(
+ [
+ new PropertyTypeTransformation(
+ {
+ code: PropertyType.String,
+ discount: PropertyType.Integer,
+ discountTax: PropertyType.String,
+ },
+ ),
+ new KeyChangeTransformation< OrderCouponLine >(
+ {
+ discountTax: 'discount_tax',
+ },
+ ),
+ ],
+ );
+}
+
+/**
+ * Creates a transformer for an order fee line object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+function createOrderFeeLineTransformer(): ModelTransformer< OrderFeeLine > {
+ return new ModelTransformer(
+ [
+ new ModelTransformerTransformation( 'taxes', OrderTaxRate, createOrderTaxRateTransformer() ),
+ new PropertyTypeTransformation(
+ {
+ name: PropertyType.String,
+ taxClass: PropertyType.String,
+ taxStatus: PropertyType.String,
+ total: PropertyType.String,
+ totalTax: PropertyType.String,
+ },
+ ),
+ new KeyChangeTransformation< OrderFeeLine >(
+ {
+ taxClass: 'tax_class',
+ taxStatus: 'tax_status',
+ totalTax: 'total_tax',
+ },
+ ),
+ ],
+ );
+}
+
+/**
+ * Creates a transformer for an order line item object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+function createOrderLineItemTransformer(): ModelTransformer< OrderLineItem > {
+ return new ModelTransformer(
+ [
+ new ModelTransformerTransformation( 'taxes', OrderTaxRate, createOrderTaxRateTransformer() ),
+ new PropertyTypeTransformation(
+ {
+ name: PropertyType.String,
+ productId: PropertyType.Integer,
+ variationId: PropertyType.Integer,
+ quantity: PropertyType.Integer,
+ taxClass: PropertyType.String,
+ subtotal: PropertyType.String,
+ subtotalTax: PropertyType.String,
+ total: PropertyType.String,
+ totalTax: PropertyType.String,
+ sku: PropertyType.String,
+ price: PropertyType.Integer,
+ parentName: PropertyType.String,
+ },
+ ),
+ new KeyChangeTransformation< OrderLineItem >(
+ {
+ productId: 'product_id',
+ variationId: 'variation_id',
+ taxClass: 'tax_class',
+ subtotalTax: 'subtotal_tax',
+ totalTax: 'total_tax',
+ },
+ ),
+ ],
+ );
+}
+
+/**
+ * Creates a transformer for an order shipping line item object.
+ *
+ * @return {ModelTransformer} The created transformer.
+ */
+function createOrderShippingItemTransformer(): ModelTransformer< OrderShippingLine > {
+ return new ModelTransformer(
+ [
+ new ModelTransformerTransformation( 'taxes', OrderTaxRate, createOrderTaxRateTransformer() ),
+ new PropertyTypeTransformation(
+ {
+ methodTitle: PropertyType.String,
+ methodId: PropertyType.String,
+ total: PropertyType.String,
+ totalTax: PropertyType.String,
+ },
+ ),
+ new KeyChangeTransformation< OrderShippingLine >(
+ {
+ methodTitle: 'method_title',
+ methodId: 'method_id',
+ totalTax: 'total_tax',
+ },
+ ),
+ ],
+ );
+}
diff --git a/tests/e2e/api/src/repositories/rest/shared.ts b/tests/e2e/api/src/repositories/rest/shared.ts
index 1d52d73ec3d..3c4e976d177 100644
--- a/tests/e2e/api/src/repositories/rest/shared.ts
+++ b/tests/e2e/api/src/repositories/rest/shared.ts
@@ -16,6 +16,7 @@ import {
CreateChildFn,
ModelTransformer,
IgnorePropertyTransformation,
+ KeyChangeTransformation,
// @ts-ignore
ModelParentID,
} from '../../framework';
@@ -34,6 +35,12 @@ export function createMetaDataTransformer(): ModelTransformer< MetaData > {
return new ModelTransformer(
[
new IgnorePropertyTransformation( [ 'id' ] ),
+ new KeyChangeTransformation< MetaData >(
+ {
+ displayKey: 'display_key',
+ displayValue: 'display_value',
+ },
+ ),
],
);
}
diff --git a/tests/e2e/config/default.json b/tests/e2e/config/default.json
index 4d6b397aac2..adb8538915e 100644
--- a/tests/e2e/config/default.json
+++ b/tests/e2e/config/default.json
@@ -180,6 +180,17 @@
}
}
},
+ "orders": {
+ "basicPaidOrder": {
+ "paymentMethod": "cod",
+ "status": "processing",
+ "billing": {
+ "firstName": "John",
+ "lastName": "Doe",
+ "email": "john.doe@example.com"
+ }
+ }
+ },
"onboardingwizard": {
"industry": "Test industry",
"numberofproducts": "1 - 10",
diff --git a/tests/e2e/core-tests/specs/api/order.test.js b/tests/e2e/core-tests/specs/api/order.test.js
new file mode 100644
index 00000000000..cdfc0b7a5c1
--- /dev/null
+++ b/tests/e2e/core-tests/specs/api/order.test.js
@@ -0,0 +1,82 @@
+/* eslint-disable jest/no-export, jest/no-disabled-tests */
+/**
+ * Internal dependencies
+ */
+ const { HTTPClientFactory, Order } = require( '@woocommerce/api' );
+
+ /**
+ * External dependencies
+ */
+ const config = require( 'config' );
+ const {
+ it,
+ describe,
+ beforeAll,
+ } = require( '@jest/globals' );
+
+ /**
+ * Creates an order and tests interactions with it via the API.
+ */
+const runOrderApiTest = () => {
+ describe('REST API > Order', () => {
+ let client;
+ let order;
+ let repository;
+
+ beforeAll(async () => {
+ order = config.get( 'orders.basicPaidOrder' );
+ const admin = config.get( 'users.admin' );
+ const url = config.get( 'url' );
+
+ client = HTTPClientFactory.build( url )
+ .withBasicAuth( admin.username, admin.password )
+ .withIndexPermalinks()
+ .create();
+ } );
+
+ it('can create an order', async () => {
+ repository = Order.restRepository( client );
+
+ // Check properties of the order in the create order response.
+ order = await repository.create( order );
+ expect( order ).toEqual( expect.objectContaining( order ) );
+ });
+
+ it('can retrieve an order', async () => {
+ const orderProperties = {
+ id: order.id,
+ payment_method: order.paymentMethod,
+ status: order.status,
+ };
+
+ // Read order directly from API to compare.
+ const response = await client.get( `/wc/v3/orders/${order.id}` );
+ expect( response.statusCode ).toBe( 200 );
+ expect( response.data ).toEqual( expect.objectContaining( orderProperties ) );
+ });
+
+ it('can update an order', async () => {
+ const updatedOrderProperties = {
+ payment_method: 'bacs',
+ status: 'completed',
+ };
+
+ await repository.update( order.id, updatedOrderProperties );
+
+ // Check the order response for the updated values.
+ const response = await client.get( `/wc/v3/orders/${order.id}` );
+ expect( response.statusCode ).toBe( 200 );
+ expect( response.data ).toEqual( expect.objectContaining( updatedOrderProperties ) );
+ });
+
+ it('can delete an order', async () => {
+ // Delete the order
+ const status = await repository.delete( order.id );
+
+ // If the delete is successful, the response comes back truthy
+ expect( status ).toBeTruthy();
+ });
+ });
+};
+
+module.exports = runOrderApiTest;
diff --git a/tests/e2e/core-tests/specs/index.js b/tests/e2e/core-tests/specs/index.js
index c7cbd79b2fe..030605d5bd3 100644
--- a/tests/e2e/core-tests/specs/index.js
+++ b/tests/e2e/core-tests/specs/index.js
@@ -52,6 +52,7 @@ const runExternalProductAPITest = require( './api/external-product.test' );
const runCouponApiTest = require( './api/coupon.test' );
const runGroupedProductAPITest = require( './api/grouped-product.test' );
const runVariableProductAPITest = require( './api/variable-product.test' );
+const runOrderApiTest = require( './api/order.test' );
const runSetupOnboardingTests = () => {
runActivationTest();
@@ -106,6 +107,7 @@ const runApiTests = () => {
runGroupedProductAPITest();
runVariableProductAPITest();
runCouponApiTest();
+ runOrderApiTest();
}
module.exports = {
@@ -135,6 +137,7 @@ module.exports = {
runUpdateGeneralSettingsTest,
runProductSettingsTest,
runTaxSettingsTest,
+ runOrderApiTest,
runOrderStatusFiltersTest,
runOrderRefundTest,
runOrderApplyCouponTest,
diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-order-emails.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-order-emails.test.js
index ad18a8de6d1..3b69ba28beb 100644
--- a/tests/e2e/core-tests/specs/merchant/wp-admin-order-emails.test.js
+++ b/tests/e2e/core-tests/specs/merchant/wp-admin-order-emails.test.js
@@ -11,7 +11,6 @@ const {
} = require( '@woocommerce/e2e-utils' );
const config = require( 'config' );
-const simpleProductName = config.get( 'products.simple.name' );
const customerEmail = config.get( 'addresses.customer.billing.email' );
const adminEmail = 'admin@woocommercecoree2etestsuite.com';
const storeName = 'WooCommerce Core E2E Test Suite';
diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-product-import-csv.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-product-import-csv.test.js
index e3705010a93..1e2b945ad24 100644
--- a/tests/e2e/core-tests/specs/merchant/wp-admin-product-import-csv.test.js
+++ b/tests/e2e/core-tests/specs/merchant/wp-admin-product-import-csv.test.js
@@ -5,7 +5,7 @@
const {
merchant,
setCheckbox,
- moveAllItemsToTrash
+ withRestApi,
} = require( '@woocommerce/e2e-utils' );
const getCoreTestsRoot = require( '../../core-tests-root' );
@@ -108,10 +108,12 @@ const runImportProductsTest = () => {
// Gathering product names
await page.waitForSelector('a.row-title');
- const productTitles = await page.$$eval('a.row-title',
- elements => elements.map(item => item.innerHTML));
+ const productTitles = await page.$$eval(
+ 'a.row-title',
+ elements => elements.map(item => item.innerHTML)
+ );
- // Compare overriden product names
+ // Compare overridden product names
expect(productTitles.sort()).toEqual(productNamesOverride.sort());
// Gathering product prices
@@ -119,12 +121,11 @@ const runImportProductsTest = () => {
const productPrices = await page.$$eval('.amount',
elements => elements.map(item => item.innerText));
- // Compare overriden product prices
+ // Compare overridden product prices
expect(productPrices.sort()).toEqual(productPricesOverride.sort());
- // Move all imported products to trash
- await moveAllItemsToTrash();
-
+ // Delete imported products
+ await withRestApi.deleteAllProducts();
});
});
};
diff --git a/tests/e2e/specs/rest-api/order.js b/tests/e2e/specs/rest-api/order.js
new file mode 100644
index 00000000000..d73a8be5f28
--- /dev/null
+++ b/tests/e2e/specs/rest-api/order.js
@@ -0,0 +1,6 @@
+/*
+ * Internal dependencies
+ */
+const { runOrderApiTest } = require( '@woocommerce/e2e-core-tests' );
+
+runOrderApiTest();
diff --git a/tests/e2e/utils/src/flows/with-rest-api.js b/tests/e2e/utils/src/flows/with-rest-api.js
index 442d1d20a8c..64b40d773ee 100644
--- a/tests/e2e/utils/src/flows/with-rest-api.js
+++ b/tests/e2e/utils/src/flows/with-rest-api.js
@@ -16,20 +16,24 @@ const userEndpoint = '/wp/v2/users';
const deleteAllRepositoryObjects = async ( repository, defaultObjectId = null ) => {
let objects;
const minimum = defaultObjectId == null ? 0 : 1;
+ const statuses = ['draft','publish','trash'];
- objects = await repository.list();
- while ( objects.length > minimum ) {
- for (let o = 0; o < objects.length; o++ ) {
- // Skip default data store object
- if ( objects[ o ].id == defaultObjectId ) {
- continue;
+ for ( let s = 0; s < statuses.length; s++ ) {
+ const status = statuses[ s ];
+ objects = await repository.list( { status } );
+ while (objects.length > minimum) {
+ for (let o = 0; o < objects.length; o++) {
+ // Skip default data store object
+ if (objects[o].id == defaultObjectId) {
+ continue;
+ }
+ // We may be getting a cached copy of the dataset and the object has already been deleted.
+ try {
+ await repository.delete(objects[o].id);
+ } catch (e) {}
}
- // We may be getting a cached copy of the dataset and the object has already been deleted.
- try {
- await repository.delete(objects[o].id);
- } catch (e) {}
+ objects = await repository.list( { status } );
}
- objects = await repository.list();
}
};
diff --git a/woocommerce.php b/woocommerce.php
index 1fb1516fb43..57edd900f95 100644
--- a/woocommerce.php
+++ b/woocommerce.php
@@ -3,7 +3,7 @@
* Plugin Name: WooCommerce
* Plugin URI: https://woocommerce.com/
* Description: An eCommerce toolkit that helps you sell anything. Beautifully.
- * Version: 5.4.0-dev
+ * Version: 5.5.0-dev
* Author: Automattic
* Author URI: https://woocommerce.com
* Text Domain: woocommerce