Merge branch 'trunk' into add/woocommerce_inbox_variant

This commit is contained in:
Roy Ho 2021-05-19 10:36:21 -07:00 committed by GitHub
commit 0643ccf4c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 1803 additions and 275 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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": [],

View File

@ -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",

View File

@ -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": [],

View File

@ -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"

72
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": "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"
}

View File

@ -534,6 +534,73 @@ class WC_Admin_Addons {
<?php
}
/**
* Handles the output of a full-width block.
*
* @param array $section Section data.
*/
public static function output_promotion_block( $section ) {
if (
! current_user_can( 'install_plugins' ) ||
! current_user_can( 'activate_plugins' )
) {
return;
}
$section_object = (object) $section;
if ( ! empty( $section_object->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;
}
?>
<div class="addons-banner-block addons-promotion-block">
<img
class="addons-img"
src="<?php echo esc_url( $section['image'] ); ?>"
alt="<?php echo esc_attr( $section['image_alt'] ); ?>"
/>
<div class="addons-promotion-block-content">
<h1 class="addons-promotion-block-title"><?php echo esc_html( $section['title'] ); ?></h1>
<div class="addons-promotion-block-description">
<?php echo wp_kses_post( $section['description'] ); ?>
</div>
<div class="addons-promotion-block-buttons">
<?php
if ( $section['button_1'] ) {
self::output_button(
$section['button_1_href'],
$section['button_1'],
'addons-button-expandable addons-button-solid',
$section['plugin']
);
}
if ( $section['button_2'] ) {
self::output_button(
$section['button_2_href'],
$section['button_2'],
'addons-button-expandable addons-button-outline-purple',
$section['plugin']
);
}
?>
</div>
</div>
</div>
<?php
}
/**
* Handles the outputting of featured sections
*
@ -566,6 +633,9 @@ class WC_Admin_Addons {
case 'wcpay_banner_block':
self::output_wcpay_banner_block( (array) $section );
break;
case 'promotion_block':
self::output_promotion_block( (array) $section );
break;
}
}
}

View File

@ -67,44 +67,12 @@ class WC_Admin_Notices {
/**
* Parses query to create nonces when available.
*
* @deprecated 5.4.0
* @param object $response The WP_REST_Response we're working with.
* @return object $response The prepared WP_REST_Response object.
*/
public static function prepare_note_with_nonce( $response ) {
if ( 'wc-update-db-reminder' !== $response->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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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 );

View File

@ -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}",

View File

@ -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 );
}

View File

@ -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' ) );

View File

@ -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' ), '<code>' . WC_Log_Handler_File::get_log_file_path( 'paypal' ) . '</code>' ),
),
'ipn_notification' => array(
'title' => __( 'IPN Email Notifications', 'woocommerce' ),
'title' => __( 'IPN email notifications', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable IPN email notifications', 'woocommerce' ),
'default' => 'yes',

View File

@ -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';
}
}

View File

@ -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 );

4
package-lock.json generated
View File

@ -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

View File

@ -1,7 +1,7 @@
{
"name": "woocommerce",
"title": "WooCommerce",
"version": "5.4.0",
"version": "5.5.0",
"homepage": "https://woocommerce.com/",
"repository": {
"type": "git",

View File

@ -29,7 +29,7 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
<?php /* translators: %s: Customer first name */ ?>
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
<?php if ( $order->has_status( 'pending' ) ) { ?>
<?php if ( $order->needs_payment() ) { ?>
<p>
<?php
printf(

View File

@ -1,5 +1,12 @@
# Unreleased
## Added
- Support for orders.
## Changed
- `delete()` now deletes products and coupons instead of moving to `trash`.
# 0.1.2
@ -14,7 +21,7 @@
## Breaking Changes
- The `HTTPClientFactory` API was changed to make it easier to configure instances with
- The `HTTPClientFactory` API was changed to make it easier to configure instances
## Added

View File

@ -6,7 +6,7 @@ features:
- [x] TypeScript Definitions
- [x] Axios API Client with support for OAuth & basic auth
- [x] Repositories to simplify interaction with basic data types
- [ ] Service classes for common activities such as changing settings
- [x] Service classes for common activities such as changing settings
## Usage
@ -51,12 +51,20 @@ httpClient.get( '/wc/v3/products' ).then( ( response ) => {
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 );

View File

@ -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<string> = [];
/**
* The coupon's links.
*
* @type {ReadonlyArray.<ObjectLinks>}
*/
public readonly links: ObjectLinks = {
collection: [ { href: '' } ],
self: [ { href: '' } ],
};
/**
* Creates a new coupon instance with the given properties
*

View File

@ -3,3 +3,4 @@ export * from './model';
export * from './settings';
export * from './shared-types';
export * from './coupons';
export * from './orders';

View File

@ -0,0 +1,2 @@
export * from './orders';
export * from './shared';

View File

@ -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.<Order>
*/
export type CreatesOrders = CreatesModels< OrderRepositoryParams >;
/**
* An interface for reading orders using the repository.
*
* @typedef ReadsOrders
* @alias ReadsModels.<Order>
*/
export type ReadsOrders = ReadsModels< OrderRepositoryParams >;
/**
* An interface for updating orders using the repository.
*
* @typedef UpdatesOrders
* @alias UpdatesModels.<Order>
*/
export type UpdatesOrders = UpdatesModels< OrderRepositoryParams >;
/**
* An interface for listing orders using the repository.
*
* @typedef ListsOrders
* @alias ListsModels.<Order>
*/
export type ListsOrders = ListsModels< OrderRepositoryParams >;
/**
* An interface for deleting orders using the repository.
*
* @typedef DeletesOrders
* @alias DeletesModels.<Orders>
*/
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.<OrderLineItem>}
*/
public readonly lineItems: OrderLineItem[] = [];
/**
* The order's tax rates.
*
* @type {ReadonlyArray.<OrderTaxRate>}
*/
public readonly taxLines: OrderTaxRate[] = [];
/**
* The order's shipping charges.
*
* @type {ReadonlyArray.<OrderShippingLine>}
*/
public readonly shippingLines: OrderShippingLine[] = [];
/**
* The order's fees.
*
* @type {ReadonlyArray.<OrderFeeLine>}
*/
public readonly feeLines: OrderFeeLine[] = [];
/**
* The coupons used on the order.
*
* @type {ReadonlyArray.<OrderCouponLine>}
*/
public readonly couponLines: OrderCouponLine[] = [];
/**
* The refunds to the order.
*
* @type {ReadonlyArray.<OrderRefundLine>}
*/
public readonly refunds: OrderRefundLine[] = [];
/**
* The order's links.
*
* @type {ReadonlyArray.<ObjectLinks>}
*/
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 );
}
}

View File

@ -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.<MetaData>}
*/
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.<OrderItemTax>}
*/
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.<OrderItemTax>}
*/
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.<OrderItemTax>}
*/
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 = '';
}

View File

@ -0,0 +1,2 @@
export * from './classes';
export * from './types';

View File

@ -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';

View File

@ -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.<ProductLinks>}
* @type {ReadonlyArray.<ObjectLinks>}
*/
public readonly links: ProductLinks = {
public readonly links: ObjectLinks = {
collection: [ { href: '' } ],
self: [ { href: '' } ],
};

View File

@ -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.<ProductLinks>}
* @type {ReadonlyArray.<ObjectLinks>}
*/
public readonly links: ProductLinks = {
public readonly links: ObjectLinks = {
collection: [ { href: '' } ],
self: [ { href: '' } ],
};

View File

@ -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.<string>}
*/
public readonly href: string = '';
/**
* Creates a new product link item.
*
* @param {Partial.<ProductLinkItem>} 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.<ProductLinkItem>}
*/
public readonly collection: readonly ProductLinkItem[] = [];
/**
* Self referential link to the product.
*
* @type {ReadonlyArray.<ProductLinkItem>}
*/
public readonly self: readonly ProductLinkItem[] = [];
/**
* The link to the parent.
*
* @type {ReadonlyArray.<ProductLinkItem>}
*/
public readonly up?: readonly ProductLinkItem[] = [];
/**
* Creates a new product link list.
*
* @param {Partial.<ProductLinks>} properties The properties to set.
*/
public constructor( properties?: Partial< ProductLinks > ) {
Object.assign( this, properties );
}
}

View File

@ -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.<ProductLinks>}
* @type {ReadonlyArray.<ObjectLinks>}
*/
public readonly links: ProductLinks = {
public readonly links: ObjectLinks = {
collection: [ { href: '' } ],
self: [ { href: '' } ],
up: [ { href: '' } ],

View File

@ -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.<string>}
*/
public readonly href: string = '';
/**
* Creates a new product link item.
*
* @param {Partial.<LinkItem>} 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.<LinkItem>}
*/
public readonly collection: readonly LinkItem[] = [];
/**
* Self referential link to the object.
*
* @type {ReadonlyArray.<LinkItem>}
*/
public readonly self: readonly LinkItem[] = [];
/**
* The link to the parent object.
*
* @type {ReadonlyArray.<LinkItem>}
*/
public readonly up?: readonly LinkItem[] = [];
/**
* Creates a new product link list.
*
* @param {Partial.<ObjectLinks>} properties The properties to set.
*/
public constructor( properties?: Partial< ObjectLinks > ) {
Object.assign( this, properties );
}
}

View File

@ -57,6 +57,7 @@ export function createCouponTransformer(): ModelTransformer< Coupon > {
maximumAmount: 'maximum_amount',
emailRestrictions: 'email_restrictions',
usedBy: 'used_by',
links: '_links',
},
),
],

View File

@ -1,3 +1,4 @@
export * from './products';
export * from './settings';
export * from './coupons';
export * from './products';
export * from './orders';
export * from './settings';

View File

@ -0,0 +1,3 @@
import orderRESTRepository from './order';
export { orderRESTRepository };

View File

@ -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 ),
);
}

View File

@ -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',
},
),
],
);
}

View File

@ -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',
},
),
],
);
}

View File

@ -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",

View File

@ -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;

View File

@ -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,

View File

@ -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';

View File

@ -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();
});
});
};

View File

@ -0,0 +1,6 @@
/*
* Internal dependencies
*/
const { runOrderApiTest } = require( '@woocommerce/e2e-core-tests' );
runOrderApiTest();

View File

@ -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();
}
};

View File

@ -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