diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index c3dfa83750f..00000000000 --- a/.editorconfig +++ /dev/null @@ -1,24 +0,0 @@ -# This file is for unifying the coding style for different editors and IDEs -# editorconfig.org - -# WordPress Coding Standards -# https://make.wordpress.org/core/handbook/coding-standards/ - -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_size = 4 -tab_width = 4 -indent_style = tab -insert_final_newline = true -trim_trailing_whitespace = true - -[*.txt] -trim_trailing_whitespace = false - -[*.{md,json,yml}] -trim_trailing_whitespace = false -indent_style = space -indent_size = 2 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index b5d3da03cbb..00000000000 --- a/.gitattributes +++ /dev/null @@ -1,7 +0,0 @@ -/.* export-ignore -/phpcs.xml export-ignore -/phpunit.* export-ignore -/unit-tests export-ignore -/vendor export-ignore -/README.md export-ignore -/readme.txt export-ignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b19a8d1f0ae..00000000000 --- a/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -# Editors -project.xml -project.properties -/nbproject/private/ -.buildpath -.project -.settings* -.idea -.vscode -*.sublime-project -*.sublime-workspace -.sublimelinterrc - -# Grunt -/node_modules/ -none - -# Sass -.sass-cache/ - -# OS X metadata -.DS_Store - -# Windows junk -Thumbs.db - -# Unit tests -/tmp -/unit-tests/bin/tmp - -# Logs -/logs - -# composer -vendor/ diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 04bbd2b73b4..00000000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,118 +0,0 @@ -tools: - php_code_sniffer: - config: - standard: WordPress - sensiolabs_security_checker: true -checks: - php: - avoid_closing_tag: false - avoid_superglobals: false - coding_standard: - name: WordPress - no_exit: false - no_global_keyword: false - one_class_per_file: false - psr2_class_declaration: false - psr2_control_structure_declaration: false - psr2_switch_declaration: false - variable_existence: false - verify_access_scope_valid: false - verify_argument_usable_as_reference: false - verify_property_names: false -filter: - dependency_paths: - - wordpress/ - - woocommerce/ - excluded_paths: - - src/Controllers/Version1/ - - src/Controllers/Version2/ - - src/Controllers/Version3/ - - tests/ - - vendor/ - - classmap.php -coding_style: - php: - indentation: - general: - use_tabs: true - size: 4 - switch: - indent_case: true - spaces: - around_operators: - concatenation: true - negation: true - within: - brackets: true - grouping: true - function_call: true - function_declaration: true - if: true - for: true - while: true - switch: true - catch: true - before_left_brace: - class: true - function: true - if: true - else: true - for: true - while: true - do: true - switch: true - try: true - catch: true - finally: true - before_keywords: - else: true - while: true - catch: true - finally: true - ternary_operator: - before_condition: true - after_condition: true - before_alternative: true - after_alternative: true - in_short_version: false - other: - before_comma: false - after_comma: true - before_semicolon: false - after_semicolon: true - after_type_cast: true - braces: - classes_functions: - class: end-of-line - function: end-of-line - closure: end-of-line - if: - opening: undefined - always: true - else_on_new_line: false - for: - opening: undefined - always: true - while: - opening: undefined - always: true - do_while: - opening: undefined - always: true - while_on_new_line: false - switch: - opening: undefined - try: - opening: undefined - catch_on_new_line: false - finally_on_new_line: false -build: - tests: - override: - command: "php -v" - nodes: - analysis: - dependencies: - before: - - composer require --dev johnpbloch/wordpress-core - - composer require --dev woocommerce/woocommerce diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c907c8983a9..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: php -dist: trusty -sudo: required -cache: - directories: - - vendor - - $HOME/.composer/cache -matrix: - include: - - name: "PHP 7.2 unit tests, PHP Coding standards check" - php: 7.2 - env: WP_VERSION=latest WP_MULTISITE=0 WP_CORE_DIR=/tmp/wordpress RUN_PHPCS=1 - - name: "PHP 7.1 unit tests" - php: 7.1 - env: WP_VERSION=latest WP_MULTISITE=0 WP_CORE_DIR=/tmp/wordpress - -before_script: - - export PATH="$HOME/.composer/vendor/bin:$PATH" - - phpenv config-rm xdebug.ini - - composer install - - composer global require "phpunit/phpunit=4.8.*|6.5.*" - - bash unit-tests/bin/install.sh woocommerce_test root '' localhost $WP_VERSION - -script: - - bash unit-tests/bin/phpunit.sh - - bash unit-tests/bin/phpcs.sh diff --git a/README.md b/README.md deleted file mode 100644 index 9a2eff0a244..00000000000 --- a/README.md +++ /dev/null @@ -1,67 +0,0 @@ -WooCommerce REST API -=== - - - - - - -This repository is home to the WooCommerce REST API package. - -The stable version of this package is bundled with [WooCommerce core](https://github.com/woocommerce/woocommerce) releases, but it can also be used as a standalone plugin so bleeding-edge API features can be tested or used by other feature plugins. - -## Using this package as a plugin - -After checking out the code to your `wp-content/plugins` directory, you'll need to run `composer install` in the plugin directory (`wp-content/plugins/woocommerce-rest-api`) to install dependencies and to enable the autoloader. Without performing this step, if you activate the plugin it will simply show an admin notice. - -## API documentation - -- [Usage documentation for the REST API can be found here](https://github.com/woocommerce/woocommerce/wiki/Getting-started-with-the-REST-API). -- [Contribution documentation can be found here.](https://github.com/woocommerce/woocommerce/wiki/Contributing-to-the-WooCommerce-REST-API) - -### Versions - -| Namespace | Status | Docs | -| -------- | -------- | -------- | -| `wc/v4` | Development | [Link](https://woocommerce.github.io/woocommerce-rest-api-docs/) | -| `wc/v3` | Stable | [Link](https://woocommerce.github.io/woocommerce-rest-api-docs/) | -| `wc/v2` | Deprecated - October 2020 | [Link](https://woocommerce.github.io/woocommerce-rest-api-docs/wp-api-v2.html) | -| `wc/v1` | Deprecated - April 2019 | [Link](https://woocommerce.github.io/woocommerce-rest-api-docs/wp-api-v1.html) | - -Note: API Versions are kept around for 2 years after being replaced, and may be removed in the next major version after that date passes. - -## Using this package in other projects - -This package is [hosted on Packagist](https://packagist.org/packages/woocommerce/woocommerce-rest-api) and can be included using composer.json: - -```json -"require": { - "woocommerce/woocommerce-rest-api": "1.0" -}, -``` - -Since multiple versions of this package may be included at the same time, it includes a special package-version autoloader. This dependency is also on Packagist: - -```json - "automattic/jetpack-autoloader": "^1" -``` - -And using this autoloader requires the following include in your codebase: - -``` -$autoloader = __DIR__ . '/vendor/autoload_packages.php'; -``` - -If you choose to use your own autoloader, please note you won't be able to determine which version of the package is running since it could use the version in WooCommerce core or your version. The namespaces would conflict. All of our feature plugins and packages use the package autoloader. - -## Contributing - -Please read the [WooCommerce contributor guidelines](https://github.com/woocommerce/woocommerce/blob/master/.github/CONTRIBUTING.md) for more information how you can contribute to WooCommerce, and [the REST API contribution documentation here](https://github.com/woocommerce/woocommerce/wiki/Contributing-to-the-WooCommerce-REST-API). - -Within this package, namespaces and endpoint classes are located within the `src/RestAPI/` directory. If you need to change the behavior of an endpoint, you can do so in these classes. - -Run tests using `phpunit` in the root of the package. All pull-requests must pass unit tests in order to be accepted. - -## Translation - -For strings located in API endpoints, use `woocommerce` as your text-domain. These endpoints will be translated in the WooCommerce Core PO/MO files. diff --git a/composer.json b/composer.json deleted file mode 100644 index 537262ed3c2..00000000000 --- a/composer.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "woocommerce/woocommerce-rest-api", - "description": "The WooCommerce core REST API.", - "homepage": "https://github.com/woocommerce/woocommerce-rest-api", - "license": "GPL-3.0-or-later", - "type": "wordpress-plugin", - "prefer-stable": true, - "minimum-stability": "dev", - "require": { - "automattic/jetpack-autoloader": "^1.6.0" - }, - "require-dev": { - "phpunit/phpunit": "6.5.14", - "woocommerce/woocommerce-sniffs": "0.0.9" - }, - "scripts": { - "post-install-cmd": [ - "composer dump-autoload" - ], - "post-update-cmd": [ - "composer dump-autoload" - ], - "test": [ - "phpunit" - ], - "phpcs": [ - "phpcs -s -p" - ], - "phpcs-pre-commit": [ - "phpcs -s -p -n" - ], - "phpcbf": [ - "phpcbf -p" - ] - }, - "autoload": { - "classmap": [ - "src/Controllers/Version1", - "src/Controllers/Version2", - "src/Controllers/Version3" - ], - "psr-4": { - "Automattic\\WooCommerce\\RestApi\\": "src" - } - } -} diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 35c89885f43..00000000000 --- a/composer.lock +++ /dev/null @@ -1,1934 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "18fc7a15ab7921e538dea77490edd41b", - "packages": [ - { - "name": "automattic/jetpack-autoloader", - "version": "v1.6.0", - "source": { - "type": "git", - "url": "https://github.com/Automattic/jetpack-autoloader.git", - "reference": "3bcbe1ae19febd6beeb181cf11af0bf0b7abe7e7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/3bcbe1ae19febd6beeb181cf11af0bf0b7abe7e7", - "reference": "3bcbe1ae19febd6beeb181cf11af0bf0b7abe7e7", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5" - }, - "type": "composer-plugin", - "extra": { - "class": "Automattic\\Jetpack\\Autoloader\\CustomAutoloaderPlugin" - }, - "autoload": { - "psr-4": { - "Automattic\\Jetpack\\Autoloader\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-or-later" - ], - "description": "Creates a custom autoloader for a plugin or theme.", - "time": "2020-03-26T07:57:53+00:00" - } - ], - "packages-dev": [ - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.5.0", - "source": { - "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "e749410375ff6fb7a040a68878c656c2e610b132" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132", - "reference": "e749410375ff6fb7a040a68878c656c2e610b132", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0", - "php": "^5.3|^7", - "squizlabs/php_codesniffer": "^2|^3" - }, - "require-dev": { - "composer/composer": "*", - "phpcompatibility/php-compatibility": "^9.0", - "sensiolabs/security-checker": "^4.1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "time": "2018-10-26T13:21:45+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2019-10-21T16:45:58+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.9.3", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, - "files": [ - "src/DeepCopy/deep_copy.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2019-08-09T12:45:53+00:00" - }, - { - "name": "phar-io/manifest", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^1.0.1", - "php": "^5.6 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" - }, - { - "name": "phar-io/version", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" - }, - { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.4", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "1f37659196e4f3113ea506a7efba201c52303bf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/1f37659196e4f3113ea506a7efba201c52303bf1", - "reference": "1f37659196e4f3113ea506a7efba201c52303bf1", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" - }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "homepage": "https://github.com/wimg", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - } - ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", - "keywords": [ - "compatibility", - "phpcs", - "standards" - ], - "time": "2019-11-15T04:12:02+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-paragonie", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", - "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c", - "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5", - "paragonie/random_compat": "dev-master", - "paragonie/sodium_compat": "dev-master" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "paragonie", - "phpcs", - "polyfill", - "standards" - ], - "time": "2019-11-04T15:17:54+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0", - "phpcompatibility/phpcompatibility-paragonie": "^1.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "phpcs", - "standards", - "wordpress" - ], - "time": "2019-08-28T14:22:28+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2018-08-07T13:53:10+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "4.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", - "shasum": "" - }, - "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-09-12T14:27:41+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "shasum": "" - }, - "require": { - "php": "^7.1", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "1.9.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2019-10-03T11:07:50+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "5.3.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.0", - "phpunit/php-file-iterator": "^1.4.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "suggest": { - "ext-xdebug": "^2.5.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2018-04-06T15:36:58+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2017-11-27T13:52:08+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2017-02-26T11:10:40+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.2.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2017-11-27T05:48:46+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "6.5.14", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.0", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", - "phpunit/php-file-iterator": "^1.4.3", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.9", - "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", - "sebastian/environment": "^3.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", - "sebastian/version": "^2.0.1" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.5.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2019-02-01T05:22:47+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "5.0.10", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.0", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.5.11" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "abandoned": true, - "time": "2018-08-09T05:50:03+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" - }, - { - "name": "sebastian/comparator", - "version": "2.1.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", - "sebastian/exporter": "^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2018-02-01T13:46:46+00:00" - }, - { - "name": "sebastian/diff", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2017-08-03T08:09:46+00:00" - }, - { - "name": "sebastian/environment", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2017-07-01T08:51:00+00:00" - }, - { - "name": "sebastian/exporter", - "version": "3.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2019-09-14T09:02:43+00:00" - }, - { - "name": "sebastian/global-state", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2017-04-27T15:39:26+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "shasum": "" - }, - "require": { - "php": ">=5.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.5.3", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", - "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2019-12-04T04:46:47+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "time": "2019-11-27T13:56:44+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "vimeo/psalm": "<3.6.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" - }, - "type": "library", - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2019-11-24T13:36:37+00:00" - }, - { - "name": "woocommerce/woocommerce-sniffs", - "version": "0.0.9", - "source": { - "type": "git", - "url": "https://github.com/woocommerce/woocommerce-sniffs.git", - "reference": "7677a84e9a355fe1e088f704090be891e7a6d427" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/7677a84e9a355fe1e088f704090be891e7a6d427", - "reference": "7677a84e9a355fe1e088f704090be891e7a6d427", - "shasum": "" - }, - "require": { - "dealerdirect/phpcodesniffer-composer-installer": "0.5.0", - "php": ">=7.0", - "phpcompatibility/phpcompatibility-wp": "2.1.0", - "wp-coding-standards/wpcs": "2.2.0" - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Claudio Sanches", - "email": "claudio@automattic.com" - } - ], - "description": "WooCommerce sniffs", - "keywords": [ - "phpcs", - "standards", - "woocommerce", - "wordpress" - ], - "time": "2019-11-11T15:48:34+00:00" - }, - { - "name": "wp-coding-standards/wpcs", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "f90e8692ce97b693633db7ab20bfa78d930f536a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/f90e8692ce97b693633db7ab20bfa78d930f536a", - "reference": "f90e8692ce97b693633db7ab20bfa78d930f536a", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "phpcompatibility/php-compatibility": "^9.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Contributors", - "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", - "keywords": [ - "phpcs", - "standards", - "wordpress" - ], - "time": "2019-11-11T12:34:03+00:00" - } - ], - "aliases": [], - "minimum-stability": "dev", - "stability-flags": [], - "prefer-stable": true, - "prefer-lowest": false, - "platform": [], - "platform-dev": [] -} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index b1506082765..00000000000 --- a/package-lock.json +++ /dev/null @@ -1,1618 +0,0 @@ -{ - "name": "woocommerce-rest-api", - "version": "1.0.5", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", - "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/runtime": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz", - "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - } - }, - "@samverschueren/stream-to-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", - "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", - "dev": true, - "requires": { - "any-observable": "^0.3.0" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/node": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.5.0.tgz", - "integrity": "sha512-Onhn+z72D2O2Pb2ql2xukJ55rglumsVo1H6Fmyi8mlU9SvKdBk/pUSUAiBY/d9bAOF7VVWajX3sths/+g6ZiAQ==", - "dev": true - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "cross-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", - "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "del": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", - "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", - "dev": true, - "requires": { - "globby": "^10.0.1", - "graceful-fs": "^4.2.2", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.1", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", - "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^3.0.0", - "onetime": "^5.1.0", - "p-finally": "^2.0.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "fast-glob": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", - "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2" - } - }, - "fastq": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", - "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", - "dev": true, - "requires": { - "reusify": "^1.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "husky": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.0.10.tgz", - "integrity": "sha512-Ptm4k2DqOwxeK/kzu5RaJmNRoGvESrgDXObFcZ8aJZcyXyMBHhM2FqZj6zYKdetadmP3wCwxEHCBuB9xGlRp8A==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "ci-info": "^2.0.0", - "cosmiconfig": "^6.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - } - }, - "ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", - "dev": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" - } - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "lint-staged": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.5.0.tgz", - "integrity": "sha512-nawMob9cb/G1J98nb8v3VC/E8rcX1rryUYXVZ69aT9kde6YWX+uvNOEHY5yf2gcWcTJGiD0kqXmCnS3oD75GIA==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "commander": "^2.20.0", - "cosmiconfig": "^5.2.1", - "debug": "^4.1.1", - "dedent": "^0.7.0", - "del": "^5.0.0", - "execa": "^2.0.3", - "listr": "^0.14.3", - "log-symbols": "^3.0.0", - "micromatch": "^4.0.2", - "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "string-argv": "^0.3.0", - "stringify-object": "^3.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", - "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "dependencies": { - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", - "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", - "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "opencollective-postinstall": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", - "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", - "dev": true - }, - "p-finally": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", - "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", - "dev": true - }, - "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picomatch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", - "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - } - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "rxjs": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", - "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", - "dev": true - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true - }, - "wrap-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "yaml": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz", - "integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.6.3" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 2d17f61330a..00000000000 --- a/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "woocommerce-rest-api", - "title": "WooCommerce REST API", - "version": "1.0.10", - "homepage": "https://woocommerce.com/", - "repository": { - "type": "git", - "url": "https://github.com/woocommerce/woocommerce-rest-api.git" - }, - "license": "GPL-3.0+", - "main": "Gruntfile.js", - "devDependencies": { - "husky": "4.0.10", - "lint-staged": "9.5.0" - }, - "engines": { - "node": ">=10.15.0", - "npm": ">=6.4.1" - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, - "lint-staged": { - "*.php": [ - "php -d display_errors=1 -l", - "composer run-script phpcs-pre-commit" - ] - } -} diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index ceb59896bf8..00000000000 --- a/phpcs.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - WooCommerce dev PHP_CodeSniffer ruleset. - - - tests/ - apigen/ - */node_modules/* - */vendor/* - - - - - - - - - - - - - - - - tests/ - - - - * - - - - tests/ - - - - i18n/ - * - - diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index 9119520176d..00000000000 --- a/phpunit.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - ./unit-tests/Tests - - - diff --git a/src/Controllers/Version1/class-wc-rest-coupons-v1-controller.php b/src/Controllers/Version1/class-wc-rest-coupons-v1-controller.php deleted file mode 100644 index 06ca52b6047..00000000000 --- a/src/Controllers/Version1/class-wc-rest-coupons-v1-controller.php +++ /dev/null @@ -1,580 +0,0 @@ -post_type}_query", array( $this, 'query_args' ), 10, 2 ); - } - - /** - * Register the routes for coupons. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'code' => array( - 'description' => __( 'Coupon code.', 'woocommerce-rest-api' ), - 'required' => true, - 'type' => 'string', - ), - ) ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Query args. - * - * @param array $args Query args - * @param WP_REST_Request $request Request data. - * @return array - */ - public function query_args( $args, $request ) { - if ( ! empty( $request['code'] ) ) { - $id = wc_get_coupon_id_by_code( $request['code'] ); - $args['post__in'] = array( $id ); - } - - return $args; - } - - /** - * Prepare a single coupon output for response. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $data - */ - public function prepare_item_for_response( $post, $request ) { - $coupon = new WC_Coupon( (int) $post->ID ); - $_data = $coupon->get_data(); - - $format_decimal = array( 'amount', 'minimum_amount', 'maximum_amount' ); - $format_date = array( 'date_created', 'date_modified' ); - $format_date_utc = array( 'date_expires' ); - $format_null = array( 'usage_limit', 'usage_limit_per_user' ); - - // Format decimal values. - foreach ( $format_decimal as $key ) { - $_data[ $key ] = wc_format_decimal( $_data[ $key ], 2 ); - } - - // Format date values. - foreach ( $format_date as $key ) { - $_data[ $key ] = $_data[ $key ] ? wc_rest_prepare_date_response( $_data[ $key ], false ) : null; - } - foreach ( $format_date_utc as $key ) { - $_data[ $key ] = $_data[ $key ] ? wc_rest_prepare_date_response( $_data[ $key ] ) : null; - } - - // Format null values. - foreach ( $format_null as $key ) { - $_data[ $key ] = $_data[ $key ] ? $_data[ $key ] : null; - } - - $data = array( - 'id' => $_data['id'], - 'code' => $_data['code'], - 'date_created' => $_data['date_created'], - 'date_modified' => $_data['date_modified'], - 'discount_type' => $_data['discount_type'], - 'description' => $_data['description'], - 'amount' => $_data['amount'], - 'expiry_date' => $_data['date_expires'], - 'usage_count' => $_data['usage_count'], - 'individual_use' => $_data['individual_use'], - 'product_ids' => $_data['product_ids'], - 'exclude_product_ids' => $_data['excluded_product_ids'], - 'usage_limit' => $_data['usage_limit'], - 'usage_limit_per_user' => $_data['usage_limit_per_user'], - 'limit_usage_to_x_items' => $_data['limit_usage_to_x_items'], - 'free_shipping' => $_data['free_shipping'], - 'product_categories' => $_data['product_categories'], - 'excluded_product_categories' => $_data['excluded_product_categories'], - 'exclude_sale_items' => $_data['exclude_sale_items'], - 'minimum_amount' => $_data['minimum_amount'], - 'maximum_amount' => $_data['maximum_amount'], - 'email_restrictions' => $_data['email_restrictions'], - 'used_by' => $_data['used_by'], - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $post, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request ); - } - - /** - * Only return writable props from schema. - * @param array $schema - * @return bool - */ - protected function filter_writable_props( $schema ) { - return empty( $schema['readonly'] ); - } - - /** - * Prepare a single coupon for create or update. - * - * @param WP_REST_Request $request Request object. - * @return WP_Error|stdClass $data Post object. - */ - protected function prepare_item_for_database( $request ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $coupon = new WC_Coupon( $id ); - $schema = $this->get_item_schema(); - $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); - - // Update to schema to make compatible with CRUD schema. - if ( $request['exclude_product_ids'] ) { - $request['excluded_product_ids'] = $request['exclude_product_ids']; - } - if ( $request['expiry_date'] ) { - $request['date_expires'] = $request['expiry_date']; - } - - // Validate required POST fields. - if ( 'POST' === $request->get_method() && 0 === $coupon->get_id() ) { - if ( empty( $request['code'] ) ) { - return new WP_Error( 'woocommerce_rest_empty_coupon_code', sprintf( __( 'The coupon code cannot be empty.', 'woocommerce-rest-api' ), 'code' ), array( 'status' => 400 ) ); - } - } - - // Handle all writable props. - foreach ( $data_keys as $key ) { - $value = $request[ $key ]; - - if ( ! is_null( $value ) ) { - switch ( $key ) { - case 'code' : - $coupon_code = wc_format_coupon_code( $value ); - $id = $coupon->get_id() ? $coupon->get_id() : 0; - $id_from_code = wc_get_coupon_id_by_code( $coupon_code, $id ); - - if ( $id_from_code ) { - return new WP_Error( 'woocommerce_rest_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $coupon->set_code( $coupon_code ); - break; - case 'description' : - $coupon->set_description( wp_filter_post_kses( $value ) ); - break; - case 'expiry_date' : - $coupon->set_date_expires( $value ); - break; - default : - if ( is_callable( array( $coupon, "set_{$key}" ) ) ) { - $coupon->{"set_{$key}"}( $value ); - } - break; - } - } - } - - /** - * Filter the query_vars used in `get_items` for the constructed query. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for insertion. - * - * @param WC_Coupon $coupon The coupon object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $coupon, $request ); - } - - /** - * Create a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $coupon_id = $this->save_coupon( $request ); - if ( is_wp_error( $coupon_id ) ) { - return $coupon_id; - } - - $post = get_post( $coupon_id ); - $this->update_additional_fields_for_object( $post, $request ); - - $this->add_post_meta_fields( $post, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true ); - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ) ); - - return $response; - } - - /** - * Update a single coupon. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - try { - $post_id = (int) $request['id']; - - if ( empty( $post_id ) || get_post_type( $post_id ) !== $this->post_type ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $coupon_id = $this->save_coupon( $request ); - if ( is_wp_error( $coupon_id ) ) { - return $coupon_id; - } - - $post = get_post( $coupon_id ); - $this->update_additional_fields_for_object( $post, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false ); - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - return rest_ensure_response( $response ); - - } catch ( Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Saves a coupon to the database. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|int - */ - protected function save_coupon( $request ) { - try { - $coupon = $this->prepare_item_for_database( $request ); - - if ( is_wp_error( $coupon ) ) { - return $coupon; - } - - $coupon->save(); - return $coupon->get_id(); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Get the Coupon's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the object.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'code' => array( - 'description' => __( 'Coupon code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the coupon was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the coupon was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'Coupon description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'discount_type' => array( - 'description' => __( 'Determines the type of discount that will be applied.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'fixed_cart', - 'enum' => array_keys( wc_get_coupon_types() ), - 'context' => array( 'view', 'edit' ), - ), - 'amount' => array( - 'description' => __( 'The amount of discount. Should always be numeric, even if setting a percentage.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'expiry_date' => array( - 'description' => __( 'UTC DateTime when the coupon expires.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'usage_count' => array( - 'description' => __( 'Number of times the coupon has been used already.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'individual_use' => array( - 'description' => __( 'If true, the coupon can only be used individually. Other applied coupons will be removed from the cart.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'product_ids' => array( - 'description' => __( "List of product IDs the coupon can be used on.", 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'exclude_product_ids' => array( - 'description' => __( "List of product IDs the coupon cannot be used on.", 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'usage_limit' => array( - 'description' => __( 'How many times the coupon can be used in total.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'usage_limit_per_user' => array( - 'description' => __( 'How many times the coupon can be used per customer.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'limit_usage_to_x_items' => array( - 'description' => __( 'Max number of items in the cart the coupon can be applied to.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'free_shipping' => array( - 'description' => __( 'If true and if the free shipping method requires a coupon, this coupon will enable free shipping.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'product_categories' => array( - 'description' => __( "List of category IDs the coupon applies to.", 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'excluded_product_categories' => array( - 'description' => __( "List of category IDs the coupon does not apply to.", 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'exclude_sale_items' => array( - 'description' => __( 'If true, this coupon will not be applied to items that have sale prices.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'minimum_amount' => array( - 'description' => __( 'Minimum order amount that needs to be in the cart before coupon applies.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'maximum_amount' => array( - 'description' => __( 'Maximum order amount allowed when using the coupon.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email_restrictions' => array( - 'description' => __( 'List of email addresses that can use this coupon.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'string', - ), - 'context' => array( 'view', 'edit' ), - ), - 'used_by' => array( - 'description' => __( 'List of user IDs (or guest email addresses) that have used the coupon.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['code'] = array( - 'description' => __( 'Limit result set to resources with a specific code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version1/class-wc-rest-customer-downloads-v1-controller.php b/src/Controllers/Version1/class-wc-rest-customer-downloads-v1-controller.php deleted file mode 100644 index 0d65f93dff9..00000000000 --- a/src/Controllers/Version1/class-wc-rest-customer-downloads-v1-controller.php +++ /dev/null @@ -1,252 +0,0 @@ -/downloads endpoint. - * - * @author WooThemes - * @category API - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * REST API Customers controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Controller - */ -class WC_REST_Customer_Downloads_V1_Controller extends WC_REST_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v1'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'customers/(?P[\d]+)/downloads'; - - /** - * Register the routes for customers. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'customer_id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read customers. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - $customer = get_user_by( 'id', (int) $request['customer_id'] ); - - if ( ! $customer ) { - return new WP_Error( 'woocommerce_rest_customer_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_user_permissions( 'read', $customer->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get all customer downloads. - * - * @param WP_REST_Request $request - * @return array - */ - public function get_items( $request ) { - $downloads = wc_get_customer_available_downloads( (int) $request['customer_id'] ); - - $data = array(); - foreach ( $downloads as $download_data ) { - $download = $this->prepare_item_for_response( (object) $download_data, $request ); - $download = $this->prepare_response_for_collection( $download ); - $data[] = $download; - } - - return rest_ensure_response( $data ); - } - - /** - * Prepare a single download output for response. - * - * @param stdObject $download Download object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $download, $request ) { - $data = (array) $download; - $data['access_expires'] = $data['access_expires'] ? wc_rest_prepare_date_response( $data['access_expires'] ) : 'never'; - $data['downloads_remaining'] = '' === $data['downloads_remaining'] ? 'unlimited' : $data['downloads_remaining']; - - // Remove "product_name" since it's new in 3.0. - unset( $data['product_name'] ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $download, $request ) ); - - /** - * Filter customer download data returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param stdObject $download Download object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_customer_download', $response, $download, $request ); - } - - /** - * Prepare links for the request. - * - * @param stdClass $download Download object. - * @param WP_REST_Request $request Request object. - * @return array Links for the given customer download. - */ - protected function prepare_links( $download, $request ) { - $base = str_replace( '(?P[\d]+)', $request['customer_id'], $this->rest_base ); - $links = array( - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - 'product' => array( - 'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $download->product_id ) ), - ), - 'order' => array( - 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $download->order_id ) ), - ), - ); - - return $links; - } - - /** - * Get the Customer Download's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'customer_download', - 'type' => 'object', - 'properties' => array( - 'download_url' => array( - 'description' => __( 'Download file URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'download_id' => array( - 'description' => __( 'Download ID (MD5).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Downloadable product ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'download_name' => array( - 'description' => __( 'Downloadable file name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'order_id' => array( - 'description' => __( 'Order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'order_key' => array( - 'description' => __( 'Order key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'downloads_remaining' => array( - 'description' => __( 'Number of downloads remaining.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'access_expires' => array( - 'description' => __( "The date when download access expires, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'file' => array( - 'description' => __( 'File details.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-customers-v1-controller.php b/src/Controllers/Version1/class-wc-rest-customers-v1-controller.php deleted file mode 100644 index 8fc2687ca16..00000000000 --- a/src/Controllers/Version1/class-wc-rest-customers-v1-controller.php +++ /dev/null @@ -1,924 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'email' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'New user email address.', 'woocommerce-rest-api' ), - ), - 'username' => array( - 'required' => 'no' === get_option( 'woocommerce_registration_generate_username', 'yes' ), - 'description' => __( 'New user username.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - 'password' => array( - 'required' => 'no' === get_option( 'woocommerce_registration_generate_password', 'no' ), - 'description' => __( 'New user password.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ) ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - 'reassign' => array( - 'default' => 0, - 'type' => 'integer', - 'description' => __( 'ID to reassign posts to.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read customers. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_user_permissions( 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access create customers. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_user_permissions( 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a customer. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - $id = (int) $request['id']; - - if ( ! wc_rest_check_user_permissions( 'read', $id ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access update a customer. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function update_item_permissions_check( $request ) { - $id = (int) $request['id']; - - if ( ! wc_rest_check_user_permissions( 'edit', $id ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access delete a customer. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function delete_item_permissions_check( $request ) { - $id = (int) $request['id']; - - if ( ! wc_rest_check_user_permissions( 'delete', $id ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access batch create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function batch_items_permissions_check( $request ) { - if ( ! wc_rest_check_user_permissions( 'batch' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get all customers. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $prepared_args = array(); - $prepared_args['exclude'] = $request['exclude']; - $prepared_args['include'] = $request['include']; - $prepared_args['order'] = $request['order']; - $prepared_args['number'] = $request['per_page']; - if ( ! empty( $request['offset'] ) ) { - $prepared_args['offset'] = $request['offset']; - } else { - $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; - } - $orderby_possibles = array( - 'id' => 'ID', - 'include' => 'include', - 'name' => 'display_name', - 'registered_date' => 'registered', - ); - $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ]; - $prepared_args['search'] = $request['search']; - - if ( '' !== $prepared_args['search'] ) { - $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; - } - - // Filter by email. - if ( ! empty( $request['email'] ) ) { - $prepared_args['search'] = $request['email']; - $prepared_args['search_columns'] = array( 'user_email' ); - } - - // Filter by role. - if ( 'all' !== $request['role'] ) { - $prepared_args['role'] = $request['role']; - } - - /** - * Filter arguments, before passing to WP_User_Query, when querying users via the REST API. - * - * @see https://developer.wordpress.org/reference/classes/wp_user_query/ - * - * @param array $prepared_args Array of arguments for WP_User_Query. - * @param WP_REST_Request $request The current request. - */ - $prepared_args = apply_filters( 'woocommerce_rest_customer_query', $prepared_args, $request ); - - $query = new WP_User_Query( $prepared_args ); - - $users = array(); - foreach ( $query->results as $user ) { - $data = $this->prepare_item_for_response( $user, $request ); - $users[] = $this->prepare_response_for_collection( $data ); - } - - $response = rest_ensure_response( $users ); - - // Store pagination values for headers then unset for count query. - $per_page = (int) $prepared_args['number']; - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); - - $prepared_args['fields'] = 'ID'; - - $total_users = $query->get_total(); - if ( $total_users < 1 ) { - // Out-of-bounds, run the query again without LIMIT for total count. - unset( $prepared_args['number'] ); - unset( $prepared_args['offset'] ); - $count_query = new WP_User_Query( $prepared_args ); - $total_users = $count_query->get_total(); - } - $response->header( 'X-WP-Total', (int) $total_users ); - $max_pages = ceil( $total_users / $per_page ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } - - return $response; - } - - /** - * Create a single customer. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - try { - if ( ! empty( $request['id'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_customer_exists', __( 'Cannot create existing resource.', 'woocommerce-rest-api' ), 400 ); - } - - // Sets the username. - $request['username'] = ! empty( $request['username'] ) ? $request['username'] : ''; - - // Sets the password. - $request['password'] = ! empty( $request['password'] ) ? $request['password'] : ''; - - // Create customer. - $customer = new WC_Customer; - $customer->set_username( $request['username'] ); - $customer->set_password( $request['password'] ); - $customer->set_email( $request['email'] ); - $this->update_customer_meta_fields( $customer, $request ); - $customer->save(); - - if ( ! $customer->get_id() ) { - throw new WC_REST_Exception( 'woocommerce_rest_cannot_create', __( 'This resource cannot be created.', 'woocommerce-rest-api' ), 400 ); - } - - $user_data = get_userdata( $customer->get_id() ); - $this->update_additional_fields_for_object( $user_data, $request ); - - /** - * Fires after a customer is created or updated via the REST API. - * - * @param WP_User $user_data Data used to create the customer. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating customer, false when updating customer. - */ - do_action( 'woocommerce_rest_insert_customer', $user_data, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $user_data, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $customer->get_id() ) ) ); - - return $response; - } catch ( Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Get a single customer. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $id = (int) $request['id']; - $user_data = get_userdata( $id ); - - if ( empty( $id ) || empty( $user_data->ID ) ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $customer = $this->prepare_item_for_response( $user_data, $request ); - $response = rest_ensure_response( $customer ); - - return $response; - } - - /** - * Update a single user. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - try { - $id = (int) $request['id']; - $customer = new WC_Customer( $id ); - - if ( ! $customer->get_id() ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), 400 ); - } - - if ( ! empty( $request['email'] ) && email_exists( $request['email'] ) && $request['email'] !== $customer->get_email() ) { - throw new WC_REST_Exception( 'woocommerce_rest_customer_invalid_email', __( 'Email address is invalid.', 'woocommerce-rest-api' ), 400 ); - } - - if ( ! empty( $request['username'] ) && $request['username'] !== $customer->get_username() ) { - throw new WC_REST_Exception( 'woocommerce_rest_customer_invalid_argument', __( "Username isn't editable.", 'woocommerce-rest-api' ), 400 ); - } - - // Customer email. - if ( isset( $request['email'] ) ) { - $customer->set_email( sanitize_email( $request['email'] ) ); - } - - // Customer password. - if ( isset( $request['password'] ) ) { - $customer->set_password( $request['password'] ); - } - - $this->update_customer_meta_fields( $customer, $request ); - $customer->save(); - - $user_data = get_userdata( $customer->get_id() ); - $this->update_additional_fields_for_object( $user_data, $request ); - - if ( ! is_user_member_of_blog( $user_data->ID ) ) { - $user_data->add_role( 'customer' ); - } - - /** - * Fires after a customer is created or updated via the REST API. - * - * @param WP_User $customer Data used to create the customer. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating customer, false when updating customer. - */ - do_action( 'woocommerce_rest_insert_customer', $user_data, $request, false ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $user_data, $request ); - $response = rest_ensure_response( $response ); - return $response; - } catch ( Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Delete a single customer. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function delete_item( $request ) { - $id = (int) $request['id']; - $reassign = isset( $request['reassign'] ) ? absint( $request['reassign'] ) : null; - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out. - if ( ! $force ) { - return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Customers do not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - $user_data = get_userdata( $id ); - if ( ! $user_data ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - if ( ! empty( $reassign ) ) { - if ( $reassign === $id || ! get_userdata( $reassign ) ) { - return new WP_Error( 'woocommerce_rest_customer_invalid_reassign', __( 'Invalid resource id for reassignment.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $user_data, $request ); - - /** Include admin customer functions to get access to wp_delete_user() */ - require_once ABSPATH . 'wp-admin/includes/user.php'; - - $customer = new WC_Customer( $id ); - - if ( ! is_null( $reassign ) ) { - $result = $customer->delete_and_reassign( $reassign ); - } else { - $result = $customer->delete(); - } - - if ( ! $result ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a customer is deleted via the REST API. - * - * @param WP_User $user_data User data. - * @param WP_REST_Response $response The response returned from the API. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'woocommerce_rest_delete_customer', $user_data, $response, $request ); - - return $response; - } - - /** - * Prepare a single customer output for response. - * - * @param WP_User $user_data User object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $user_data, $request ) { - $customer = new WC_Customer( $user_data->ID ); - $_data = $customer->get_data(); - $last_order = wc_get_customer_last_order( $customer->get_id() ); - $format_date = array( 'date_created', 'date_modified' ); - - // Format date values. - foreach ( $format_date as $key ) { - $_data[ $key ] = $_data[ $key ] ? wc_rest_prepare_date_response( $_data[ $key ] ) : null; // v1 API used UTC. - } - - $data = array( - 'id' => $_data['id'], - 'date_created' => $_data['date_created'], - 'date_modified' => $_data['date_modified'], - 'email' => $_data['email'], - 'first_name' => $_data['first_name'], - 'last_name' => $_data['last_name'], - 'username' => $_data['username'], - 'last_order' => array( - 'id' => is_object( $last_order ) ? $last_order->get_id() : null, - 'date' => is_object( $last_order ) ? wc_rest_prepare_date_response( $last_order->get_date_created() ) : null, // v1 API used UTC. - ), - 'orders_count' => $customer->get_order_count(), - 'total_spent' => $customer->get_total_spent(), - 'avatar_url' => $customer->get_avatar_url(), - 'billing' => $_data['billing'], - 'shipping' => $_data['shipping'], - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $user_data ) ); - - /** - * Filter customer data returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_User $user_data User object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_customer', $response, $user_data, $request ); - } - - /** - * Update customer meta fields. - * - * @param WC_Customer $customer - * @param WP_REST_Request $request - */ - protected function update_customer_meta_fields( $customer, $request ) { - $schema = $this->get_item_schema(); - - // Customer first name. - if ( isset( $request['first_name'] ) ) { - $customer->set_first_name( wc_clean( $request['first_name'] ) ); - } - - // Customer last name. - if ( isset( $request['last_name'] ) ) { - $customer->set_last_name( wc_clean( $request['last_name'] ) ); - } - - // Customer billing address. - if ( isset( $request['billing'] ) ) { - foreach ( array_keys( $schema['properties']['billing']['properties'] ) as $field ) { - if ( isset( $request['billing'][ $field ] ) && is_callable( array( $customer, "set_billing_{$field}" ) ) ) { - $customer->{"set_billing_{$field}"}( $request['billing'][ $field ] ); - } - } - } - - // Customer shipping address. - if ( isset( $request['shipping'] ) ) { - foreach ( array_keys( $schema['properties']['shipping']['properties'] ) as $field ) { - if ( isset( $request['shipping'][ $field ] ) && is_callable( array( $customer, "set_shipping_{$field}" ) ) ) { - $customer->{"set_shipping_{$field}"}( $request['shipping'][ $field ] ); - } - } - } - } - - /** - * Prepare links for the request. - * - * @param WP_User $customer Customer object. - * @return array Links for the given customer. - */ - protected function prepare_links( $customer ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $customer->ID ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the Customer's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'customer', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( 'The date the customer was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( 'The date the customer was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'email' => array( - 'description' => __( 'The email address for the customer.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'first_name' => array( - 'description' => __( 'Customer first name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'last_name' => array( - 'description' => __( 'Customer last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'username' => array( - 'description' => __( 'Customer login name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_user', - ), - ), - 'password' => array( - 'description' => __( 'Customer password.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'edit' ), - ), - 'last_order' => array( - 'description' => __( 'Last order data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'properties' => array( - 'id' => array( - 'description' => __( 'Last order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date' => array( - 'description' => __( 'The date of the customer last order, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - 'orders_count' => array( - 'description' => __( 'Quantity of orders made by the customer.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_spent' => array( - 'description' => __( 'Total amount spent.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'avatar_url' => array( - 'description' => __( 'Avatar URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'billing' => array( - 'description' => __( 'List of billing address data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'ISO code of the country.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email' => array( - 'description' => __( 'Email address.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'phone' => array( - 'description' => __( 'Phone number.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping' => array( - 'description' => __( 'List of shipping address data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'ISO code of the country.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get role names. - * - * @return array - */ - protected function get_role_names() { - global $wp_roles; - - return array_keys( $wp_roles->role_names ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['context']['default'] = 'view'; - - $params['exclude'] = array( - 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['include'] = array( - 'description' => __( 'Limit result set to specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['offset'] = array( - 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['order'] = array( - 'default' => 'asc', - 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ), - 'enum' => array( 'asc', 'desc' ), - 'sanitize_callback' => 'sanitize_key', - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['orderby'] = array( - 'default' => 'name', - 'description' => __( 'Sort collection by object attribute.', 'woocommerce-rest-api' ), - 'enum' => array( - 'id', - 'include', - 'name', - 'registered_date', - ), - 'sanitize_callback' => 'sanitize_key', - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['email'] = array( - 'description' => __( 'Limit result set to resources with a specific email.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['role'] = array( - 'description' => __( 'Limit result set to resources with a specific role.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'customer', - 'enum' => array_merge( array( 'all' ), $this->get_role_names() ), - 'validate_callback' => 'rest_validate_request_arg', - ); - return $params; - } -} diff --git a/src/Controllers/Version1/class-wc-rest-order-notes-v1-controller.php b/src/Controllers/Version1/class-wc-rest-order-notes-v1-controller.php deleted file mode 100644 index 785ff4627b4..00000000000 --- a/src/Controllers/Version1/class-wc-rest-order-notes-v1-controller.php +++ /dev/null @@ -1,439 +0,0 @@ -/notes endpoint. - * - * @author WooThemes - * @category API - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * REST API Order Notes controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Controller - */ -class WC_REST_Order_Notes_V1_Controller extends WC_REST_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v1'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'orders/(?P[\d]+)/notes'; - - /** - * Post type. - * - * @var string - */ - protected $post_type = 'shop_order'; - - /** - * Register the routes for order notes. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'order_id' => array( - 'description' => __( 'The order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'note' => array( - 'type' => 'string', - 'description' => __( 'Order note content.', 'woocommerce-rest-api' ), - 'required' => true, - ), - ) ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'order_id' => array( - 'description' => __( 'The order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read order notes. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_post_permissions( $this->post_type, 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access create order notes. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_post_permissions( $this->post_type, 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a order note. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - $order = wc_get_order( (int) $request['order_id'] ); - - if ( $order && ! wc_rest_check_post_permissions( $this->post_type, 'read', $order->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access delete a order note. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function delete_item_permissions_check( $request ) { - $order = wc_get_order( (int) $request['order_id'] ); - - if ( $order && ! wc_rest_check_post_permissions( $this->post_type, 'delete', $order->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get order notes from an order. - * - * @param WP_REST_Request $request - * - * @return array|WP_Error - */ - public function get_items( $request ) { - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order || $this->post_type !== $order->get_type() ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid order ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $args = array( - 'post_id' => $order->get_id(), - 'approve' => 'approve', - 'type' => 'order_note', - ); - - remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 ); - - $notes = get_comments( $args ); - - add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 ); - - $data = array(); - foreach ( $notes as $note ) { - $order_note = $this->prepare_item_for_response( $note, $request ); - $order_note = $this->prepare_response_for_collection( $order_note ); - $data[] = $order_note; - } - - return rest_ensure_response( $data ); - } - - /** - * Create a single order note. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order || $this->post_type !== $order->get_type() ) { - return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - // Create the note. - $note_id = $order->add_order_note( $request['note'], $request['customer_note'] ); - - if ( ! $note_id ) { - return new WP_Error( 'woocommerce_api_cannot_create_order_note', __( 'Cannot create order note, please try again.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - $note = get_comment( $note_id ); - $this->update_additional_fields_for_object( $note, $request ); - - /** - * Fires after a order note is created or updated via the REST API. - * - * @param WP_Comment $note New order note object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( 'woocommerce_rest_insert_order_note', $note, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $note, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, str_replace( '(?P[\d]+)', $order->get_id(), $this->rest_base ), $note_id ) ) ); - - return $response; - } - - /** - * Get a single order note. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $id = (int) $request['id']; - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order || $this->post_type !== $order->get_type() ) { - return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $note = get_comment( $id ); - - if ( empty( $id ) || empty( $note ) || intval( $note->comment_post_ID ) !== intval( $order->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $order_note = $this->prepare_item_for_response( $note, $request ); - $response = rest_ensure_response( $order_note ); - - return $response; - } - - /** - * Delete a single order note. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $id = (int) $request['id']; - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out. - if ( ! $force ) { - return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Webhooks do not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order || $this->post_type !== $order->get_type() ) { - return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $note = get_comment( $id ); - - if ( empty( $id ) || empty( $note ) || intval( $note->comment_post_ID ) !== intval( $order->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $note, $request ); - - $result = wc_delete_order_note( $note->comment_ID ); - - if ( ! $result ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce-rest-api' ), 'order_note' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a order note is deleted or trashed via the REST API. - * - * @param WP_Comment $note The deleted or trashed order note. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'woocommerce_rest_delete_order_note', $note, $response, $request ); - - return $response; - } - - /** - * Prepare a single order note output for response. - * - * @param WP_Comment $note Order note object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $note, $request ) { - $data = array( - 'id' => (int) $note->comment_ID, - 'date_created' => wc_rest_prepare_date_response( $note->comment_date_gmt ), - 'note' => $note->comment_content, - 'customer_note' => (bool) get_comment_meta( $note->comment_ID, 'is_customer_note', true ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $note ) ); - - /** - * Filter order note object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_Comment $note Order note object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_order_note', $response, $note, $request ); - } - - /** - * Prepare links for the request. - * - * @param WP_Comment $note Delivery order_note object. - * @return array Links for the given order note. - */ - protected function prepare_links( $note ) { - $order_id = (int) $note->comment_post_ID; - $base = str_replace( '(?P[\d]+)', $order_id, $this->rest_base ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $note->comment_ID ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - 'up' => array( - 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $order_id ) ), - ), - ); - - return $links; - } - - /** - * Get the Order Notes schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'order_note', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the order note was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'note' => array( - 'description' => __( 'Order note.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'customer_note' => array( - 'description' => __( 'Shows/define if the note is only for reference or for the customer (the user will be notified).', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-order-refunds-v1-controller.php b/src/Controllers/Version1/class-wc-rest-order-refunds-v1-controller.php deleted file mode 100644 index 659ffa844ae..00000000000 --- a/src/Controllers/Version1/class-wc-rest-order-refunds-v1-controller.php +++ /dev/null @@ -1,530 +0,0 @@ -/refunds endpoint. - * - * @author WooThemes - * @category API - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * REST API Order Refunds controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Orders_V1_Controller - */ -class WC_REST_Order_Refunds_V1_Controller extends WC_REST_Orders_V1_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v1'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'orders/(?P[\d]+)/refunds'; - - /** - * Post type. - * - * @var string - */ - protected $post_type = 'shop_order_refund'; - - /** - * Order refunds actions. - */ - public function __construct() { - add_filter( "woocommerce_rest_{$this->post_type}_trashable", '__return_false' ); - add_filter( "woocommerce_rest_{$this->post_type}_query", array( $this, 'query_args' ), 10, 2 ); - } - - /** - * Register the routes for order refunds. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'order_id' => array( - 'description' => __( 'The order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'order_id' => array( - 'description' => __( 'The order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => true, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Prepare a single order refund output for response. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * - * @return WP_Error|WP_REST_Response - */ - public function prepare_item_for_response( $post, $request ) { - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order ) { - return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), 404 ); - } - - $refund = wc_get_order( $post ); - - if ( ! $refund || $refund->get_parent_id() !== $order->get_id() ) { - return new WP_Error( 'woocommerce_rest_invalid_order_refund_id', __( 'Invalid order refund ID.', 'woocommerce-rest-api' ), 404 ); - } - - $dp = is_null( $request['dp'] ) ? wc_get_price_decimals() : absint( $request['dp'] ); - - $data = array( - 'id' => $refund->get_id(), - 'date_created' => wc_rest_prepare_date_response( $refund->get_date_created() ), - 'amount' => wc_format_decimal( $refund->get_amount(), $dp ), - 'reason' => $refund->get_reason(), - 'line_items' => array(), - ); - - // Add line items. - foreach ( $refund->get_items() as $item_id => $item ) { - $product = $refund->get_product_from_item( $item ); - $product_id = 0; - $variation_id = 0; - $product_sku = null; - - // Check if the product exists. - if ( is_object( $product ) ) { - $product_id = $item->get_product_id(); - $variation_id = $item->get_variation_id(); - $product_sku = $product->get_sku(); - } - - $item_meta = array(); - - $hideprefix = 'true' === $request['all_item_meta'] ? null : '_'; - - foreach ( $item->get_formatted_meta_data( $hideprefix, true ) as $meta_key => $formatted_meta ) { - $item_meta[] = array( - 'key' => $formatted_meta->key, - 'label' => $formatted_meta->display_key, - 'value' => wc_clean( $formatted_meta->display_value ), - ); - } - - $line_item = array( - 'id' => $item_id, - 'name' => $item['name'], - 'sku' => $product_sku, - 'product_id' => (int) $product_id, - 'variation_id' => (int) $variation_id, - 'quantity' => wc_stock_amount( $item['qty'] ), - 'tax_class' => ! empty( $item['tax_class'] ) ? $item['tax_class'] : '', - 'price' => wc_format_decimal( $refund->get_item_total( $item, false, false ), $dp ), - 'subtotal' => wc_format_decimal( $refund->get_line_subtotal( $item, false, false ), $dp ), - 'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $dp ), - 'total' => wc_format_decimal( $refund->get_line_total( $item, false, false ), $dp ), - 'total_tax' => wc_format_decimal( $item['line_tax'], $dp ), - 'taxes' => array(), - 'meta' => $item_meta, - ); - - $item_line_taxes = maybe_unserialize( $item['line_tax_data'] ); - if ( isset( $item_line_taxes['total'] ) ) { - $line_tax = array(); - - foreach ( $item_line_taxes['total'] as $tax_rate_id => $tax ) { - $line_tax[ $tax_rate_id ] = array( - 'id' => $tax_rate_id, - 'total' => $tax, - 'subtotal' => '', - ); - } - - foreach ( $item_line_taxes['subtotal'] as $tax_rate_id => $tax ) { - $line_tax[ $tax_rate_id ]['subtotal'] = $tax; - } - - $line_item['taxes'] = array_values( $line_tax ); - } - - $data['line_items'][] = $line_item; - } - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $refund, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request ); - } - - /** - * Prepare links for the request. - * - * @param WC_Order_Refund $refund Comment object. - * @param WP_REST_Request $request Request object. - * @return array Links for the given order refund. - */ - protected function prepare_links( $refund, $request ) { - $order_id = $refund->get_parent_id(); - $base = str_replace( '(?P[\d]+)', $order_id, $this->rest_base ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $refund->get_id() ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - 'up' => array( - 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $order_id ) ), - ), - ); - - return $links; - } - - /** - * Query args. - * - * @param array $args Request args. - * @param WP_REST_Request $request Request object. - * @return array - */ - public function query_args( $args, $request ) { - $args['post_status'] = array_keys( wc_get_order_statuses() ); - $args['post_parent__in'] = array( absint( $request['order_id'] ) ); - - return $args; - } - - /** - * Create a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $order_data = get_post( (int) $request['order_id'] ); - - if ( empty( $order_data ) ) { - return new WP_Error( 'woocommerce_rest_invalid_order', __( 'Order is invalid', 'woocommerce-rest-api' ), 400 ); - } - - if ( 0 > $request['amount'] ) { - return new WP_Error( 'woocommerce_rest_invalid_order_refund', __( 'Refund amount must be greater than zero.', 'woocommerce-rest-api' ), 400 ); - } - - // Create the refund. - $refund = wc_create_refund( array( - 'order_id' => $order_data->ID, - 'amount' => $request['amount'], - 'reason' => empty( $request['reason'] ) ? null : $request['reason'], - 'refund_payment' => is_bool( $request['api_refund'] ) ? $request['api_refund'] : true, - 'restock_items' => true, - ) ); - - if ( is_wp_error( $refund ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', $refund->get_error_message(), 500 ); - } - - if ( ! $refund ) { - return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', __( 'Cannot create order refund, please try again.', 'woocommerce-rest-api' ), 500 ); - } - - $post = get_post( $refund->get_id() ); - $this->update_additional_fields_for_object( $post, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ) ); - - return $response; - } - - /** - * Get the Order's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the order refund was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'amount' => array( - 'description' => __( 'Refund amount.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'reason' => array( - 'description' => __( 'Reason for refund.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'line_items' => array( - 'description' => __( 'Line items data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sku' => array( - 'description' => __( 'Product SKU.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Product ID.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'variation_id' => array( - 'description' => __( 'Variation ID, if applicable.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'quantity' => array( - 'description' => __( 'Quantity ordered.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tax_class' => array( - 'description' => __( 'Tax class of product.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'price' => array( - 'description' => __( 'Product price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Line subtotal (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal_tax' => array( - 'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Tax subtotal.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'meta' => array( - 'description' => __( 'Line item meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'Meta label.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['dp'] = array( - 'default' => wc_get_price_decimals(), - 'description' => __( 'Number of decimal points to use in each resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version1/class-wc-rest-orders-v1-controller.php b/src/Controllers/Version1/class-wc-rest-orders-v1-controller.php deleted file mode 100644 index 502bc2eeb29..00000000000 --- a/src/Controllers/Version1/class-wc-rest-orders-v1-controller.php +++ /dev/null @@ -1,1631 +0,0 @@ -post_type}_query", array( $this, 'query_args' ), 10, 2 ); - } - - /** - * Register the routes for orders. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Prepare a single order output for response. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $data - */ - public function prepare_item_for_response( $post, $request ) { - $order = wc_get_order( $post ); - $dp = is_null( $request['dp'] ) ? wc_get_price_decimals() : absint( $request['dp'] ); - - $data = array( - 'id' => $order->get_id(), - 'parent_id' => $order->get_parent_id(), - 'status' => $order->get_status(), - 'order_key' => $order->get_order_key(), - 'number' => $order->get_order_number(), - 'currency' => $order->get_currency(), - 'version' => $order->get_version(), - 'prices_include_tax' => $order->get_prices_include_tax(), - 'date_created' => wc_rest_prepare_date_response( $order->get_date_created() ), // v1 API used UTC. - 'date_modified' => wc_rest_prepare_date_response( $order->get_date_modified() ), // v1 API used UTC. - 'customer_id' => $order->get_customer_id(), - 'discount_total' => wc_format_decimal( $order->get_total_discount(), $dp ), - 'discount_tax' => wc_format_decimal( $order->get_discount_tax(), $dp ), - 'shipping_total' => wc_format_decimal( $order->get_shipping_total(), $dp ), - 'shipping_tax' => wc_format_decimal( $order->get_shipping_tax(), $dp ), - 'cart_tax' => wc_format_decimal( $order->get_cart_tax(), $dp ), - 'total' => wc_format_decimal( $order->get_total(), $dp ), - 'total_tax' => wc_format_decimal( $order->get_total_tax(), $dp ), - 'billing' => array(), - 'shipping' => array(), - 'payment_method' => $order->get_payment_method(), - 'payment_method_title' => $order->get_payment_method_title(), - 'transaction_id' => $order->get_transaction_id(), - 'customer_ip_address' => $order->get_customer_ip_address(), - 'customer_user_agent' => $order->get_customer_user_agent(), - 'created_via' => $order->get_created_via(), - 'customer_note' => $order->get_customer_note(), - 'date_completed' => wc_rest_prepare_date_response( $order->get_date_completed(), false ), // v1 API used local time. - 'date_paid' => wc_rest_prepare_date_response( $order->get_date_paid(), false ), // v1 API used local time. - 'cart_hash' => $order->get_cart_hash(), - 'line_items' => array(), - 'tax_lines' => array(), - 'shipping_lines' => array(), - 'fee_lines' => array(), - 'coupon_lines' => array(), - 'refunds' => array(), - ); - - // Add addresses. - $data['billing'] = $order->get_address( 'billing' ); - $data['shipping'] = $order->get_address( 'shipping' ); - - // Add line items. - foreach ( $order->get_items() as $item_id => $item ) { - $product = $order->get_product_from_item( $item ); - $product_id = 0; - $variation_id = 0; - $product_sku = null; - - // Check if the product exists. - if ( is_object( $product ) ) { - $product_id = $item->get_product_id(); - $variation_id = $item->get_variation_id(); - $product_sku = $product->get_sku(); - } - - $item_meta = array(); - - $hideprefix = 'true' === $request['all_item_meta'] ? null : '_'; - - foreach ( $item->get_formatted_meta_data( $hideprefix, true ) as $meta_key => $formatted_meta ) { - $item_meta[] = array( - 'key' => $formatted_meta->key, - 'label' => $formatted_meta->display_key, - 'value' => wc_clean( $formatted_meta->display_value ), - ); - } - - $line_item = array( - 'id' => $item_id, - 'name' => $item['name'], - 'sku' => $product_sku, - 'product_id' => (int) $product_id, - 'variation_id' => (int) $variation_id, - 'quantity' => wc_stock_amount( $item['qty'] ), - 'tax_class' => ! empty( $item['tax_class'] ) ? $item['tax_class'] : '', - 'price' => wc_format_decimal( $order->get_item_total( $item, false, false ), $dp ), - 'subtotal' => wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp ), - 'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $dp ), - 'total' => wc_format_decimal( $order->get_line_total( $item, false, false ), $dp ), - 'total_tax' => wc_format_decimal( $item['line_tax'], $dp ), - 'taxes' => array(), - 'meta' => $item_meta, - ); - - $item_line_taxes = maybe_unserialize( $item['line_tax_data'] ); - if ( isset( $item_line_taxes['total'] ) ) { - $line_tax = array(); - - foreach ( $item_line_taxes['total'] as $tax_rate_id => $tax ) { - $line_tax[ $tax_rate_id ] = array( - 'id' => $tax_rate_id, - 'total' => $tax, - 'subtotal' => '', - ); - } - - foreach ( $item_line_taxes['subtotal'] as $tax_rate_id => $tax ) { - $line_tax[ $tax_rate_id ]['subtotal'] = $tax; - } - - $line_item['taxes'] = array_values( $line_tax ); - } - - $data['line_items'][] = $line_item; - } - - // Add taxes. - foreach ( $order->get_items( 'tax' ) as $key => $tax ) { - $tax_line = array( - 'id' => $key, - 'rate_code' => $tax['name'], - 'rate_id' => $tax['rate_id'], - 'label' => isset( $tax['label'] ) ? $tax['label'] : $tax['name'], - 'compound' => (bool) $tax['compound'], - 'tax_total' => wc_format_decimal( $tax['tax_amount'], $dp ), - 'shipping_tax_total' => wc_format_decimal( $tax['shipping_tax_amount'], $dp ), - ); - - $data['tax_lines'][] = $tax_line; - } - - // Add shipping. - foreach ( $order->get_shipping_methods() as $shipping_item_id => $shipping_item ) { - $shipping_line = array( - 'id' => $shipping_item_id, - 'method_title' => $shipping_item['name'], - 'method_id' => $shipping_item['method_id'], - 'total' => wc_format_decimal( $shipping_item['cost'], $dp ), - 'total_tax' => wc_format_decimal( '', $dp ), - 'taxes' => array(), - ); - - $shipping_taxes = $shipping_item->get_taxes(); - - if ( ! empty( $shipping_taxes['total'] ) ) { - $shipping_line['total_tax'] = wc_format_decimal( array_sum( $shipping_taxes['total'] ), $dp ); - - foreach ( $shipping_taxes['total'] as $tax_rate_id => $tax ) { - $shipping_line['taxes'][] = array( - 'id' => $tax_rate_id, - 'total' => $tax, - ); - } - } - - $data['shipping_lines'][] = $shipping_line; - } - - // Add fees. - foreach ( $order->get_fees() as $fee_item_id => $fee_item ) { - $fee_line = array( - 'id' => $fee_item_id, - 'name' => $fee_item['name'], - 'tax_class' => ! empty( $fee_item['tax_class'] ) ? $fee_item['tax_class'] : '', - 'tax_status' => 'taxable', - 'total' => wc_format_decimal( $order->get_line_total( $fee_item ), $dp ), - 'total_tax' => wc_format_decimal( $order->get_line_tax( $fee_item ), $dp ), - 'taxes' => array(), - ); - - $fee_line_taxes = maybe_unserialize( $fee_item['line_tax_data'] ); - if ( isset( $fee_line_taxes['total'] ) ) { - $fee_tax = array(); - - foreach ( $fee_line_taxes['total'] as $tax_rate_id => $tax ) { - $fee_tax[ $tax_rate_id ] = array( - 'id' => $tax_rate_id, - 'total' => $tax, - 'subtotal' => '', - ); - } - - if ( isset( $fee_line_taxes['subtotal'] ) ) { - foreach ( $fee_line_taxes['subtotal'] as $tax_rate_id => $tax ) { - $fee_tax[ $tax_rate_id ]['subtotal'] = $tax; - } - } - - $fee_line['taxes'] = array_values( $fee_tax ); - } - - $data['fee_lines'][] = $fee_line; - } - - // Add coupons. - foreach ( $order->get_items( 'coupon' ) as $coupon_item_id => $coupon_item ) { - $coupon_line = array( - 'id' => $coupon_item_id, - 'code' => $coupon_item['name'], - 'discount' => wc_format_decimal( $coupon_item['discount_amount'], $dp ), - 'discount_tax' => wc_format_decimal( $coupon_item['discount_amount_tax'], $dp ), - ); - - $data['coupon_lines'][] = $coupon_line; - } - - // Add refunds. - foreach ( $order->get_refunds() as $refund ) { - $data['refunds'][] = array( - 'id' => $refund->get_id(), - 'refund' => $refund->get_reason() ? $refund->get_reason() : '', - 'total' => '-' . wc_format_decimal( $refund->get_amount(), $dp ), - ); - } - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $order, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request ); - } - - /** - * Prepare links for the request. - * - * @param WC_Order $order Order object. - * @param WP_REST_Request $request Request object. - * @return array Links for the given order. - */ - protected function prepare_links( $order, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $order->get_id() ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - if ( 0 !== (int) $order->get_user_id() ) { - $links['customer'] = array( - 'href' => rest_url( sprintf( '/%s/customers/%d', $this->namespace, $order->get_user_id() ) ), - ); - } - if ( 0 !== (int) $order->get_parent_id() ) { - $links['up'] = array( - 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $order->get_parent_id() ) ), - ); - } - return $links; - } - - /** - * Query args. - * - * @param array $args - * @param WP_REST_Request $request - * @return array - */ - public function query_args( $args, $request ) { - global $wpdb; - - // Set post_status. - if ( 'any' !== $request['status'] ) { - $args['post_status'] = 'wc-' . $request['status']; - } else { - $args['post_status'] = 'any'; - } - - if ( isset( $request['customer'] ) ) { - if ( ! empty( $args['meta_query'] ) ) { - $args['meta_query'] = array(); - } - - $args['meta_query'][] = array( - 'key' => '_customer_user', - 'value' => $request['customer'], - 'type' => 'NUMERIC', - ); - } - - // Search by product. - if ( ! empty( $request['product'] ) ) { - $order_ids = $wpdb->get_col( $wpdb->prepare( " - SELECT order_id - FROM {$wpdb->prefix}woocommerce_order_items - WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = %d ) - AND order_item_type = 'line_item' - ", $request['product'] ) ); - - // Force WP_Query return empty if don't found any order. - $order_ids = ! empty( $order_ids ) ? $order_ids : array( 0 ); - - $args['post__in'] = $order_ids; - } - - // Search. - if ( ! empty( $args['s'] ) ) { - $order_ids = wc_order_search( $args['s'] ); - - if ( ! empty( $order_ids ) ) { - unset( $args['s'] ); - $args['post__in'] = array_merge( $order_ids, array( 0 ) ); - } - } - - return $args; - } - - /** - * Prepare a single order for create. - * - * @param WP_REST_Request $request Request object. - * @return WP_Error|WC_Order $data Object. - */ - protected function prepare_item_for_database( $request ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $order = new WC_Order( $id ); - $schema = $this->get_item_schema(); - $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); - - // Handle all writable props - foreach ( $data_keys as $key ) { - $value = $request[ $key ]; - - if ( ! is_null( $value ) ) { - switch ( $key ) { - case 'billing' : - case 'shipping' : - $this->update_address( $order, $value, $key ); - break; - case 'line_items' : - case 'shipping_lines' : - case 'fee_lines' : - case 'coupon_lines' : - if ( is_array( $value ) ) { - foreach ( $value as $item ) { - if ( is_array( $item ) ) { - if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) { - $order->remove_item( $item['id'] ); - } else { - $this->set_item( $order, $key, $item ); - } - } - } - } - break; - default : - if ( is_callable( array( $order, "set_{$key}" ) ) ) { - $order->{"set_{$key}"}( $value ); - } - break; - } - } - } - - /** - * Filter the data for the insert. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for the response. - * - * @param WC_Order $order The order object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $order, $request ); - } - - /** - * Create base WC Order object. - * @deprecated 3.0.0 - * @param array $data - * @return WC_Order - */ - protected function create_base_order( $data ) { - return wc_create_order( $data ); - } - - /** - * Only return writable props from schema. - * @param array $schema - * @return bool - */ - protected function filter_writable_props( $schema ) { - return empty( $schema['readonly'] ); - } - - /** - * Create order. - * - * @param WP_REST_Request $request Full details about the request. - * @return int|WP_Error - */ - protected function create_order( $request ) { - try { - // Make sure customer exists. - if ( ! is_null( $request['customer_id'] ) && 0 !== $request['customer_id'] && false === get_user_by( 'id', $request['customer_id'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id',__( 'Customer ID is invalid.', 'woocommerce-rest-api' ), 400 ); - } - - // Make sure customer is part of blog. - if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) { - add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' ); - } - - $order = $this->prepare_item_for_database( $request ); - $order->set_created_via( 'rest-api' ); - $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ); - $order->calculate_totals(); - $order->save(); - - // Handle set paid. - if ( true === $request['set_paid'] ) { - $order->payment_complete( $request['transaction_id'] ); - } - - return $order->get_id(); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Update order. - * - * @param WP_REST_Request $request Full details about the request. - * @return int|WP_Error - */ - protected function update_order( $request ) { - try { - $order = $this->prepare_item_for_database( $request ); - $order->save(); - - // Handle set paid. - if ( $order->needs_payment() && true === $request['set_paid'] ) { - $order->payment_complete( $request['transaction_id'] ); - } - - // If items have changed, recalculate order totals. - if ( isset( $request['billing'] ) || isset( $request['shipping'] ) || isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) { - $order->calculate_totals( true ); - } - - return $order->get_id(); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Update address. - * - * @param WC_Order $order - * @param array $posted - * @param string $type - */ - protected function update_address( $order, $posted, $type = 'billing' ) { - foreach ( $posted as $key => $value ) { - if ( is_callable( array( $order, "set_{$type}_{$key}" ) ) ) { - $order->{"set_{$type}_{$key}"}( $value ); - } - } - } - - /** - * Gets the product ID from the SKU or posted ID. - * - * @throws WC_REST_Exception When SKU or ID is not valid. - * @param array $posted Request data. - * @param string $action 'create' to add line item or 'update' to update it. - * @return int - */ - protected function get_product_id( $posted, $action = 'create' ) { - if ( ! empty( $posted['sku'] ) ) { - $product_id = (int) wc_get_product_id_by_sku( $posted['sku'] ); - } elseif ( ! empty( $posted['product_id'] ) && empty( $posted['variation_id'] ) ) { - $product_id = (int) $posted['product_id']; - } elseif ( ! empty( $posted['variation_id'] ) ) { - $product_id = (int) $posted['variation_id']; - } elseif ( 'update' === $action ) { - $product_id = 0; - } else { - throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or SKU is required.', 'woocommerce-rest-api' ), 400 ); - } - return $product_id; - } - - /** - * Maybe set an item prop if the value was posted. - * @param WC_Order_Item $item - * @param string $prop - * @param array $posted Request data. - */ - protected function maybe_set_item_prop( $item, $prop, $posted ) { - if ( isset( $posted[ $prop ] ) ) { - $item->{"set_$prop"}( $posted[ $prop ] ); - } - } - - /** - * Maybe set item props if the values were posted. - * @param WC_Order_Item $item - * @param string[] $props - * @param array $posted Request data. - */ - protected function maybe_set_item_props( $item, $props, $posted ) { - foreach ( $props as $prop ) { - $this->maybe_set_item_prop( $item, $prop, $posted ); - } - } - - /** - * Create or update a line item. - * - * @param array $posted Line item data. - * @param string $action 'create' to add line item or 'update' to update it. - * - * @return WC_Order_Item_Product - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_line_items( $posted, $action = 'create' ) { - $item = new WC_Order_Item_Product( ! empty( $posted['id'] ) ? $posted['id'] : '' ); - $product = wc_get_product( $this->get_product_id( $posted, $action ) ); - - if ( $product && $product !== $item->get_product() ) { - $item->set_product( $product ); - - if ( 'create' === $action ) { - $quantity = isset( $posted['quantity'] ) ? $posted['quantity'] : 1; - $total = wc_get_price_excluding_tax( $product, array( 'qty' => $quantity ) ); - $item->set_total( $total ); - $item->set_subtotal( $total ); - } - } - - $this->maybe_set_item_props( $item, array( 'name', 'quantity', 'total', 'subtotal', 'tax_class' ), $posted ); - - return $item; - } - - /** - * Create or update an order shipping method. - * - * @param $posted $shipping Item data. - * @param string $action 'create' to add shipping or 'update' to update it. - * - * @return WC_Order_Item_Shipping - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_shipping_lines( $posted, $action ) { - $item = new WC_Order_Item_Shipping( ! empty( $posted['id'] ) ? $posted['id'] : '' ); - - if ( 'create' === $action ) { - if ( empty( $posted['method_id'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_item', __( 'Shipping method ID is required.', 'woocommerce-rest-api' ), 400 ); - } - } - - $this->maybe_set_item_props( $item, array( 'method_id', 'method_title', 'total' ), $posted ); - - return $item; - } - - /** - * Create or update an order fee. - * - * @param array $posted Item data. - * @param string $action 'create' to add fee or 'update' to update it. - * - * @return WC_Order_Item_Fee - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_fee_lines( $posted, $action ) { - $item = new WC_Order_Item_Fee( ! empty( $posted['id'] ) ? $posted['id'] : '' ); - - if ( 'create' === $action ) { - if ( empty( $posted['name'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_fee_item', __( 'Fee name is required.', 'woocommerce-rest-api' ), 400 ); - } - } - - $this->maybe_set_item_props( $item, array( 'name', 'tax_class', 'tax_status', 'total' ), $posted ); - - return $item; - } - - /** - * Create or update an order coupon. - * - * @param array $posted Item data. - * @param string $action 'create' to add coupon or 'update' to update it. - * - * @return WC_Order_Item_Coupon - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_coupon_lines( $posted, $action ) { - $item = new WC_Order_Item_Coupon( ! empty( $posted['id'] ) ? $posted['id'] : '' ); - - if ( 'create' === $action ) { - if ( empty( $posted['code'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_coupon', __( 'Coupon code is required.', 'woocommerce-rest-api' ), 400 ); - } - } - - $this->maybe_set_item_props( $item, array( 'code', 'discount' ), $posted ); - - return $item; - } - - /** - * Wrapper method to create/update order items. - * When updating, the item ID provided is checked to ensure it is associated - * with the order. - * - * @param WC_Order $order order - * @param string $item_type - * @param array $posted item provided in the request body - * @throws WC_REST_Exception If item ID is not associated with order - */ - protected function set_item( $order, $item_type, $posted ) { - global $wpdb; - - if ( ! empty( $posted['id'] ) ) { - $action = 'update'; - } else { - $action = 'create'; - } - - $method = 'prepare_' . $item_type; - - // Verify provided line item ID is associated with order. - if ( 'update' === $action ) { - $result = $wpdb->get_row( - $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d AND order_id = %d", - absint( $posted['id'] ), - absint( $order->get_id() ) - ) ); - if ( is_null( $result ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_item_id', __( 'Order item ID provided is not associated with order.', 'woocommerce-rest-api' ), 400 ); - } - } - - // Prepare item data - $item = $this->$method( $posted, $action ); - - /** - * Action hook to adjust item before save. - * @since 3.0.0 - */ - do_action( 'woocommerce_rest_set_order_item', $item, $posted ); - - // Save or add to order - if ( 'create' === $action ) { - $order->add_item( $item ); - } else { - $item->save(); - } - } - - /** - * Helper method to check if the resource ID associated with the provided item is null. - * Items can be deleted by setting the resource ID to null. - * - * @param array $item Item provided in the request body. - * @return bool True if the item resource ID is null, false otherwise. - */ - protected function item_is_null( $item ) { - $keys = array( 'product_id', 'method_id', 'method_title', 'name', 'code' ); - - foreach ( $keys as $key ) { - if ( array_key_exists( $key, $item ) && is_null( $item[ $key ] ) ) { - return true; - } - } - - return false; - } - - /** - * Create a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $order_id = $this->create_order( $request ); - if ( is_wp_error( $order_id ) ) { - return $order_id; - } - - $post = get_post( $order_id ); - $this->update_additional_fields_for_object( $post, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true ); - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ) ); - - return $response; - } - - /** - * Update a single order. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - try { - $post_id = (int) $request['id']; - - if ( empty( $post_id ) || get_post_type( $post_id ) !== $this->post_type ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $order_id = $this->update_order( $request ); - if ( is_wp_error( $order_id ) ) { - return $order_id; - } - - $post = get_post( $order_id ); - $this->update_additional_fields_for_object( $post, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false ); - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - return rest_ensure_response( $response ); - - } catch ( Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Get order statuses without prefixes. - * @return array - */ - protected function get_order_statuses() { - $order_statuses = array(); - - foreach ( array_keys( wc_get_order_statuses() ) as $status ) { - $order_statuses[] = str_replace( 'wc-', '', $status ); - } - - return $order_statuses; - } - - /** - * Get the Order's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'parent_id' => array( - 'description' => __( 'Parent order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'status' => array( - 'description' => __( 'Order status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'pending', - 'enum' => $this->get_order_statuses(), - 'context' => array( 'view', 'edit' ), - ), - 'order_key' => array( - 'description' => __( 'Order key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'number' => array( - 'description' => __( 'Order number.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'currency' => array( - 'description' => __( 'Currency the order was created with, in ISO format.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => get_woocommerce_currency(), - 'enum' => array_keys( get_woocommerce_currencies() ), - 'context' => array( 'view', 'edit' ), - ), - 'version' => array( - 'description' => __( 'Version of WooCommerce which last updated the order.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'prices_include_tax' => array( - 'description' => __( 'True the prices included tax during checkout.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the order was created, as GMT.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the order was last modified, as GMT.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'customer_id' => array( - 'description' => __( 'User ID who owns the order. 0 for guests.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => 0, - 'context' => array( 'view', 'edit' ), - ), - 'discount_total' => array( - 'description' => __( 'Total discount amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'discount_tax' => array( - 'description' => __( 'Total discount tax amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_total' => array( - 'description' => __( 'Total shipping amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_tax' => array( - 'description' => __( 'Total shipping tax amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'cart_tax' => array( - 'description' => __( 'Sum of line item taxes only.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Grand total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_tax' => array( - 'description' => __( 'Sum of all taxes.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'billing' => array( - 'description' => __( 'Billing address.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email' => array( - 'description' => __( 'Email address.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'phone' => array( - 'description' => __( 'Phone number.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping' => array( - 'description' => __( 'Shipping address.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'payment_method' => array( - 'description' => __( 'Payment method ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'payment_method_title' => array( - 'description' => __( 'Payment method title.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'set_paid' => array( - 'description' => __( 'Define if the order is paid. It will set the status to processing and reduce stock items.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'edit' ), - ), - 'transaction_id' => array( - 'description' => __( 'Unique transaction ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'customer_ip_address' => array( - 'description' => __( "Customer's IP address.", 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'customer_user_agent' => array( - 'description' => __( 'User agent of the customer.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'created_via' => array( - 'description' => __( 'Shows where the order was created.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'customer_note' => array( - 'description' => __( 'Note left by customer during checkout.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_completed' => array( - 'description' => __( "The date the order was completed, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_paid' => array( - 'description' => __( "The date the order was paid, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'cart_hash' => array( - 'description' => __( 'MD5 hash of cart items to ensure orders are not modified.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'line_items' => array( - 'description' => __( 'Line items data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sku' => array( - 'description' => __( 'Product SKU.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Product ID.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'variation_id' => array( - 'description' => __( 'Variation ID, if applicable.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'quantity' => array( - 'description' => __( 'Quantity ordered.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class of product.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'price' => array( - 'description' => __( 'Product price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Line subtotal (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'subtotal_tax' => array( - 'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Tax subtotal.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'meta' => array( - 'description' => __( 'Line item meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'Meta label.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ), - ), - 'tax_lines' => array( - 'description' => __( 'Tax lines data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'rate_code' => array( - 'description' => __( 'Tax rate code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'rate_id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'Tax rate label.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'compound' => array( - 'description' => __( 'Show if is a compound tax rate.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tax_total' => array( - 'description' => __( 'Tax total (not including shipping taxes).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_tax_total' => array( - 'description' => __( 'Shipping tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'shipping_lines' => array( - 'description' => __( 'Shipping lines data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'method_title' => array( - 'description' => __( 'Shipping method name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'method_id' => array( - 'description' => __( 'Shipping method ID.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ), - ), - 'fee_lines' => array( - 'description' => __( 'Fee lines data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Fee name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class of fee.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status of fee.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'enum' => array( 'taxable', 'none' ), - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Tax subtotal.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ), - ), - 'coupon_lines' => array( - 'description' => __( 'Coupons line data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'code' => array( - 'description' => __( 'Coupon code.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'discount' => array( - 'description' => __( 'Discount total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'discount_tax' => array( - 'description' => __( 'Discount total tax.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'refunds' => array( - 'description' => __( 'List of refunds.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Refund ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'reason' => array( - 'description' => __( 'Refund reason.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Refund total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['status'] = array( - 'default' => 'any', - 'description' => __( 'Limit result set to orders assigned a specific status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_merge( array( 'any' ), $this->get_order_statuses() ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['customer'] = array( - 'description' => __( 'Limit result set to orders assigned a specific customer.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['product'] = array( - 'description' => __( 'Limit result set to orders assigned a specific product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['dp'] = array( - 'default' => wc_get_price_decimals(), - 'description' => __( 'Number of decimal points to use in each resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php b/src/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php deleted file mode 100644 index 361febd1dcf..00000000000 --- a/src/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php +++ /dev/null @@ -1,241 +0,0 @@ -/terms endpoint. - * - * @author WooThemes - * @category API - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * REST API Product Attribute Terms controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Terms_Controller - */ -class WC_REST_Product_Attribute_Terms_V1_Controller extends WC_REST_Terms_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v1'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'products/attributes/(?P[\d]+)/terms'; - - /** - * Register the routes for terms. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, - array( - 'args' => array( - 'attribute_id' => array( - 'description' => __( 'Unique identifier for the attribute of the terms.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'name' => array( - 'type' => 'string', - 'description' => __( 'Name for the resource.', 'woocommerce-rest-api' ), - 'required' => true, - ), - ) ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - )); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'attribute_id' => array( - 'description' => __( 'Unique identifier for the attribute of the terms.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - 'args' => array( - 'attribute_id' => array( - 'description' => __( 'Unique identifier for the attribute of the terms.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Prepare a single product attribute term output for response. - * - * @param WP_Term $item Term object. - * @param WP_REST_Request $request - * @return WP_REST_Response $response - */ - public function prepare_item_for_response( $item, $request ) { - // Get term order. - $menu_order = get_term_meta( $item->term_id, 'order_' . $this->taxonomy, true ); - - $data = array( - 'id' => (int) $item->term_id, - 'name' => $item->name, - 'slug' => $item->slug, - 'description' => $item->description, - 'menu_order' => (int) $menu_order, - 'count' => (int) $item->count, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item, $request ) ); - - /** - * Filter a term item returned from the API. - * - * Allows modification of the term data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $item The original term object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->taxonomy}", $response, $item, $request ); - } - - /** - * Update term meta fields. - * - * @param WP_Term $term - * @param WP_REST_Request $request - * @return bool|WP_Error - */ - protected function update_term_meta_fields( $term, $request ) { - $id = (int) $term->term_id; - - update_term_meta( $id, 'order_' . $this->taxonomy, $request['menu_order'] ); - - return true; - } - - /** - * Get the Attribute Term's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'product_attribute_term', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Term name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'description' => array( - 'description' => __( 'HTML description of the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'count' => array( - 'description' => __( 'Number of published products for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-product-attributes-v1-controller.php b/src/Controllers/Version1/class-wc-rest-product-attributes-v1-controller.php deleted file mode 100644 index 88e67708da9..00000000000 --- a/src/Controllers/Version1/class-wc-rest-product-attributes-v1-controller.php +++ /dev/null @@ -1,592 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'name' => array( - 'description' => __( 'Name for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'required' => true, - ), - ) ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - )); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => true, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Check if a given request has access to read the attributes. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'attributes', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to create a attribute. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'attributes', 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you cannot create new resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a attribute. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! $this->get_taxonomy( $request ) ) { - return new WP_Error( 'woocommerce_rest_taxonomy_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_manager_permissions( 'attributes', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to update a attribute. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - if ( ! $this->get_taxonomy( $request ) ) { - return new WP_Error( 'woocommerce_rest_taxonomy_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_manager_permissions( 'attributes', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot update resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to delete a attribute. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - if ( ! $this->get_taxonomy( $request ) ) { - return new WP_Error( 'woocommerce_rest_taxonomy_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_manager_permissions( 'attributes', 'delete' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access batch create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function batch_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'attributes', 'batch' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get all attributes. - * - * @param WP_REST_Request $request - * @return array - */ - public function get_items( $request ) { - $attributes = wc_get_attribute_taxonomies(); - $data = array(); - foreach ( $attributes as $attribute_obj ) { - $attribute = $this->prepare_item_for_response( $attribute_obj, $request ); - $attribute = $this->prepare_response_for_collection( $attribute ); - $data[] = $attribute; - } - - $response = rest_ensure_response( $data ); - - // This API call always returns all product attributes due to retrieval from the object cache. - $response->header( 'X-WP-Total', count( $data ) ); - $response->header( 'X-WP-TotalPages', 1 ); - - return $response; - } - - /** - * Create a single attribute. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function create_item( $request ) { - global $wpdb; - - $id = wc_create_attribute( array( - 'name' => $request['name'], - 'slug' => wc_sanitize_taxonomy_name( stripslashes( $request['slug'] ) ), - 'type' => ! empty( $request['type'] ) ? $request['type'] : 'select', - 'order_by' => ! empty( $request['order_by'] ) ? $request['order_by'] : 'menu_order', - 'has_archives' => true === $request['has_archives'], - ) ); - - // Checks for errors. - if ( is_wp_error( $id ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', $id->get_error_message(), array( 'status' => 400 ) ); - } - - $attribute = $this->get_attribute( $id ); - - if ( is_wp_error( $attribute ) ) { - return $attribute; - } - - $this->update_additional_fields_for_object( $attribute, $request ); - - /** - * Fires after a single product attribute is created or updated via the REST API. - * - * @param stdObject $attribute Inserted attribute object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating attribute, false when updating. - */ - do_action( 'woocommerce_rest_insert_product_attribute', $attribute, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $attribute, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( '/' . $this->namespace . '/' . $this->rest_base . '/' . $attribute->attribute_id ) ); - - return $response; - } - - /** - * Get a single attribute. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function get_item( $request ) { - $attribute = $this->get_attribute( (int) $request['id'] ); - - if ( is_wp_error( $attribute ) ) { - return $attribute; - } - - $response = $this->prepare_item_for_response( $attribute, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Update a single term from a taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function update_item( $request ) { - global $wpdb; - - $id = (int) $request['id']; - $edited = wc_update_attribute( $id, array( - 'name' => $request['name'], - 'slug' => wc_sanitize_taxonomy_name( stripslashes( $request['slug'] ) ), - 'type' => $request['type'], - 'order_by' => $request['order_by'], - 'has_archives' => $request['has_archives'], - ) ); - - // Checks for errors. - if ( is_wp_error( $edited ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', $edited->get_error_message(), array( 'status' => 400 ) ); - } - - $attribute = $this->get_attribute( $id ); - - if ( is_wp_error( $attribute ) ) { - return $attribute; - } - - $this->update_additional_fields_for_object( $attribute, $request ); - - /** - * Fires after a single product attribute is created or updated via the REST API. - * - * @param stdObject $attribute Inserted attribute object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating attribute, false when updating. - */ - do_action( 'woocommerce_rest_insert_product_attribute', $attribute, $request, false ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $attribute, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Delete a single attribute. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out. - if ( ! $force ) { - return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Resource does not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - $attribute = $this->get_attribute( (int) $request['id'] ); - - if ( is_wp_error( $attribute ) ) { - return $attribute; - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $attribute, $request ); - - $deleted = wc_delete_attribute( $attribute->attribute_id ); - - if ( false === $deleted ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a single attribute is deleted via the REST API. - * - * @param stdObject $attribute The deleted attribute. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'woocommerce_rest_delete_product_attribute', $attribute, $response, $request ); - - return $response; - } - - /** - * Prepare a single product attribute output for response. - * - * @param obj $item Term object. - * @param WP_REST_Request $request - * @return WP_REST_Response $response - */ - public function prepare_item_for_response( $item, $request ) { - $data = array( - 'id' => (int) $item->attribute_id, - 'name' => $item->attribute_label, - 'slug' => wc_attribute_taxonomy_name( $item->attribute_name ), - 'type' => $item->attribute_type, - 'order_by' => $item->attribute_orderby, - 'has_archives' => (bool) $item->attribute_public, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item ) ); - - /** - * Filter a attribute item returned from the API. - * - * Allows modification of the product attribute data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $item The original attribute object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_product_attribute', $response, $item, $request ); - } - - /** - * Prepare links for the request. - * - * @param object $attribute Attribute object. - * @return array Links for the given attribute. - */ - protected function prepare_links( $attribute ) { - $base = '/' . $this->namespace . '/' . $this->rest_base; - $links = array( - 'self' => array( - 'href' => rest_url( trailingslashit( $base ) . $attribute->attribute_id ), - ), - 'collection' => array( - 'href' => rest_url( $base ), - ), - ); - - return $links; - } - - /** - * Get the Attribute's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'product_attribute', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'type' => array( - 'description' => __( 'Type of attribute.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'select', - 'enum' => array_keys( wc_get_attribute_types() ), - 'context' => array( 'view', 'edit' ), - ), - 'order_by' => array( - 'description' => __( 'Default sort order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'menu_order', - 'enum' => array( 'menu_order', 'name', 'name_num', 'id' ), - 'context' => array( 'view', 'edit' ), - ), - 'has_archives' => array( - 'description' => __( 'Enable/Disable attribute archives.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections - * - * @return array - */ - public function get_collection_params() { - $params = array(); - $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); - - return $params; - } - - /** - * Get attribute name. - * - * @param WP_REST_Request $request Full details about the request. - * @return string - */ - protected function get_taxonomy( $request ) { - if ( '' !== $this->attribute ) { - return $this->attribute; - } - - if ( $request['id'] ) { - $name = wc_attribute_taxonomy_name_by_id( (int) $request['id'] ); - - $this->attribute = $name; - } - - return $this->attribute; - } - - /** - * Get attribute data. - * - * @param int $id Attribute ID. - * @return stdClass|WP_Error - */ - protected function get_attribute( $id ) { - global $wpdb; - - $attribute = $wpdb->get_row( $wpdb->prepare( " - SELECT * - FROM {$wpdb->prefix}woocommerce_attribute_taxonomies - WHERE attribute_id = %d - ", $id ) ); - - if ( is_wp_error( $attribute ) || is_null( $attribute ) ) { - return new WP_Error( 'woocommerce_rest_attribute_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - return $attribute; - } - - /** - * Validate attribute slug. - * - * @deprecated 3.2.0 - * @param string $slug - * @param bool $new_data - * @return bool|WP_Error - */ - protected function validate_attribute_slug( $slug, $new_data = true ) { - if ( strlen( $slug ) >= 28 ) { - return new WP_Error( 'woocommerce_rest_invalid_product_attribute_slug_too_long', sprintf( __( 'Slug "%s" is too long (28 characters max). Shorten it, please.', 'woocommerce-rest-api' ), $slug ), array( 'status' => 400 ) ); - } elseif ( wc_check_if_attribute_name_is_reserved( $slug ) ) { - return new WP_Error( 'woocommerce_rest_invalid_product_attribute_slug_reserved_name', sprintf( __( 'Slug "%s" is not allowed because it is a reserved term. Change it, please.', 'woocommerce-rest-api' ), $slug ), array( 'status' => 400 ) ); - } elseif ( $new_data && taxonomy_exists( wc_attribute_taxonomy_name( $slug ) ) ) { - return new WP_Error( 'woocommerce_rest_invalid_product_attribute_slug_already_exists', sprintf( __( 'Slug "%s" is already in use. Change it, please.', 'woocommerce-rest-api' ), $slug ), array( 'status' => 400 ) ); - } - - return true; - } - - /** - * Schedule to flush rewrite rules. - * - * @deprecated 3.2.0 - * @since 3.0.0 - */ - protected function flush_rewrite_rules() { - wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-product-categories-v1-controller.php b/src/Controllers/Version1/class-wc-rest-product-categories-v1-controller.php deleted file mode 100644 index 956d5cd43b3..00000000000 --- a/src/Controllers/Version1/class-wc-rest-product-categories-v1-controller.php +++ /dev/null @@ -1,271 +0,0 @@ -term_id, 'display_type', true ); - - // Get category order. - $menu_order = get_term_meta( $item->term_id, 'order', true ); - - $data = array( - 'id' => (int) $item->term_id, - 'name' => $item->name, - 'slug' => $item->slug, - 'parent' => (int) $item->parent, - 'description' => $item->description, - 'display' => $display_type ? $display_type : 'default', - 'image' => null, - 'menu_order' => (int) $menu_order, - 'count' => (int) $item->count, - ); - - // Get category image. - $image_id = get_term_meta( $item->term_id, 'thumbnail_id', true ); - if ( $image_id ) { - $attachment = get_post( $image_id ); - - $data['image'] = array( - 'id' => (int) $image_id, - 'date_created' => wc_rest_prepare_date_response( $attachment->post_date_gmt ), - 'date_modified' => wc_rest_prepare_date_response( $attachment->post_modified_gmt ), - 'src' => wp_get_attachment_url( $image_id ), - 'title' => get_the_title( $attachment ), - 'alt' => get_post_meta( $image_id, '_wp_attachment_image_alt', true ), - ); - } - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item, $request ) ); - - /** - * Filter a term item returned from the API. - * - * Allows modification of the term data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $item The original term object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->taxonomy}", $response, $item, $request ); - } - - /** - * Update term meta fields. - * - * @param WP_Term $term Term object. - * @param WP_REST_Request $request Request instance. - * @return bool|WP_Error - */ - protected function update_term_meta_fields( $term, $request ) { - $id = (int) $term->term_id; - - if ( isset( $request['display'] ) ) { - update_term_meta( $id, 'display_type', 'default' === $request['display'] ? '' : $request['display'] ); - } - - if ( isset( $request['menu_order'] ) ) { - update_term_meta( $id, 'order', $request['menu_order'] ); - } - - if ( isset( $request['image'] ) ) { - if ( empty( $request['image']['id'] ) && ! empty( $request['image']['src'] ) ) { - $upload = wc_rest_upload_image_from_url( esc_url_raw( $request['image']['src'] ) ); - - if ( is_wp_error( $upload ) ) { - return $upload; - } - - $image_id = wc_rest_set_uploaded_image_as_attachment( $upload ); - } else { - $image_id = isset( $request['image']['id'] ) ? absint( $request['image']['id'] ) : 0; - } - - // Check if image_id is a valid image attachment before updating the term meta. - if ( $image_id && wp_attachment_is_image( $image_id ) ) { - update_term_meta( $id, 'thumbnail_id', $image_id ); - - // Set the image alt. - if ( ! empty( $request['image']['alt'] ) ) { - update_post_meta( $image_id, '_wp_attachment_image_alt', wc_clean( $request['image']['alt'] ) ); - } - - // Set the image title. - if ( ! empty( $request['image']['title'] ) ) { - wp_update_post( array( - 'ID' => $image_id, - 'post_title' => wc_clean( $request['image']['title'] ), - ) ); - } - } else { - delete_term_meta( $id, 'thumbnail_id' ); - } - } - - return true; - } - - /** - * Get the Category schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->taxonomy, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Category name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'parent' => array( - 'description' => __( 'The ID for the parent of the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'HTML description of the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), - ), - 'display' => array( - 'description' => __( 'Category archive display type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'default', - 'enum' => array( 'default', 'products', 'subcategories', 'both' ), - 'context' => array( 'view', 'edit' ), - ), - 'image' => array( - 'description' => __( 'Image data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'title' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'count' => array( - 'description' => __( 'Number of published products for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php b/src/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php deleted file mode 100644 index e4d9b93075b..00000000000 --- a/src/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php +++ /dev/null @@ -1,578 +0,0 @@ -/reviews. - * - * @author WooThemes - * @category API - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * REST API Product Reviews Controller Class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Controller - */ -class WC_REST_Product_Reviews_V1_Controller extends WC_REST_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v1'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'products/(?P[\d]+)/reviews'; - - /** - * Register the routes for product reviews. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'product_id' => array( - 'description' => __( 'Unique identifier for the variable product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'id' => array( - 'description' => __( 'Unique identifier for the variation.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'review' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Review content.', 'woocommerce-rest-api' ), - ), - 'name' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Name of the reviewer.', 'woocommerce-rest-api' ), - ), - 'email' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Email of the reviewer.', 'woocommerce-rest-api' ), - ), - ) ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'product_id' => array( - 'description' => __( 'Unique identifier for the variable product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read webhook deliveries. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_post_permissions( 'product', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - $post = get_post( (int) $request['product_id'] ); - - if ( $post && ! wc_rest_check_post_permissions( 'product', 'read', $post->ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to create a new product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - $post = get_post( (int) $request['product_id'] ); - if ( $post && ! wc_rest_check_post_permissions( 'product', 'create', $post->ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to update a product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - $post = get_post( (int) $request['product_id'] ); - if ( $post && ! wc_rest_check_post_permissions( 'product', 'edit', $post->ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to delete a product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - $post = get_post( (int) $request['product_id'] ); - if ( $post && ! wc_rest_check_post_permissions( 'product', 'delete', $post->ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Get all reviews from a product. - * - * @param WP_REST_Request $request - * - * @return array|WP_Error - */ - public function get_items( $request ) { - $product_id = (int) $request['product_id']; - - if ( 'product' !== get_post_type( $product_id ) ) { - return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $reviews = get_approved_comments( $product_id ); - $data = array(); - foreach ( $reviews as $review_data ) { - $review = $this->prepare_item_for_response( $review_data, $request ); - $review = $this->prepare_response_for_collection( $review ); - $data[] = $review; - } - - return rest_ensure_response( $data ); - } - - /** - * Get a single product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $id = (int) $request['id']; - $product_id = (int) $request['product_id']; - - if ( 'product' !== get_post_type( $product_id ) ) { - return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $review = get_comment( $id ); - - if ( empty( $id ) || empty( $review ) || intval( $review->comment_post_ID ) !== $product_id ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $delivery = $this->prepare_item_for_response( $review, $request ); - $response = rest_ensure_response( $delivery ); - - return $response; - } - - - /** - * Create a product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - $product_id = (int) $request['product_id']; - - if ( 'product' !== get_post_type( $product_id ) ) { - return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $prepared_review = $this->prepare_item_for_database( $request ); - - /** - * Filter a product review (comment) before it is inserted via the REST API. - * - * Allows modification of the comment right before it is inserted via `wp_insert_comment`. - * - * @param array $prepared_review The prepared comment data for `wp_insert_comment`. - * @param WP_REST_Request $request Request used to insert the comment. - */ - $prepared_review = apply_filters( 'rest_pre_insert_product_review', $prepared_review, $request ); - - $product_review_id = wp_insert_comment( $prepared_review ); - if ( ! $product_review_id ) { - return new WP_Error( 'rest_product_review_failed_create', __( 'Creating product review failed.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - update_comment_meta( $product_review_id, 'rating', ( ! empty( $request['rating'] ) ? $request['rating'] : '0' ) ); - - $product_review = get_comment( $product_review_id ); - $this->update_additional_fields_for_object( $product_review, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Comment $product_review Inserted object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_product_review", $product_review, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $product_review, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $base = str_replace( '(?P[\d]+)', $product_id, $this->rest_base ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $product_review_id ) ) ); - - return $response; - } - - /** - * Update a single product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $product_review_id = (int) $request['id']; - $product_id = (int) $request['product_id']; - - if ( 'product' !== get_post_type( $product_id ) ) { - return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $review = get_comment( $product_review_id ); - - if ( empty( $product_review_id ) || empty( $review ) || intval( $review->comment_post_ID ) !== $product_id ) { - return new WP_Error( 'woocommerce_rest_product_review_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $prepared_review = $this->prepare_item_for_database( $request ); - - $updated = wp_update_comment( $prepared_review ); - if ( 0 === $updated ) { - return new WP_Error( 'rest_product_review_failed_edit', __( 'Updating product review failed.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - if ( ! empty( $request['rating'] ) ) { - update_comment_meta( $product_review_id, 'rating', $request['rating'] ); - } - - $product_review = get_comment( $product_review_id ); - $this->update_additional_fields_for_object( $product_review, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Comment $comment Inserted object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_product_review", $product_review, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $product_review, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Delete a product review. - * - * @param WP_REST_Request $request Full details about the request - * - * @return bool|WP_Error|WP_REST_Response - */ - public function delete_item( $request ) { - $product_review_id = absint( is_array( $request['id'] ) ? $request['id']['id'] : $request['id'] ); - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - $product_review = get_comment( $product_review_id ); - if ( empty( $product_review_id ) || empty( $product_review->comment_ID ) || empty( $product_review->comment_post_ID ) ) { - return new WP_Error( 'woocommerce_rest_product_review_invalid_id', __( 'Invalid product review ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - /** - * Filter whether a product review is trashable. - * - * Return false to disable trash support for the product review. - * - * @param boolean $supports_trash Whether the object supports trashing. - * @param WP_Post $product_review The object being considered for trashing support. - */ - $supports_trash = apply_filters( 'rest_product_review_trashable', ( EMPTY_TRASH_DAYS > 0 ), $product_review ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $product_review, $request ); - - if ( $force ) { - $result = wp_delete_comment( $product_review_id, true ); - } else { - if ( ! $supports_trash ) { - return new WP_Error( 'rest_trash_not_supported', __( 'The product review does not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - if ( 'trash' === $product_review->comment_approved ) { - return new WP_Error( 'rest_already_trashed', __( 'The comment has already been trashed.', 'woocommerce-rest-api' ), array( 'status' => 410 ) ); - } - - $result = wp_trash_comment( $product_review->comment_ID ); - } - - if ( ! $result ) { - return new WP_Error( 'rest_cannot_delete', __( 'The product review cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a product review is deleted via the REST API. - * - * @param object $product_review The deleted item. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'rest_delete_product_review', $product_review, $response, $request ); - - return $response; - } - - /** - * Prepare a single product review output for response. - * - * @param WP_Comment $review Product review object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $review, $request ) { - $data = array( - 'id' => (int) $review->comment_ID, - 'date_created' => wc_rest_prepare_date_response( $review->comment_date_gmt ), - 'review' => $review->comment_content, - 'rating' => (int) get_comment_meta( $review->comment_ID, 'rating', true ), - 'name' => $review->comment_author, - 'email' => $review->comment_author_email, - 'verified' => wc_review_is_from_verified_owner( $review->comment_ID ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $review, $request ) ); - - /** - * Filter product reviews object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_Comment $review Product review object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_product_review', $response, $review, $request ); - } - - /** - * Prepare a single product review to be inserted into the database. - * - * @param WP_REST_Request $request Request object. - * @return array|WP_Error $prepared_review - */ - protected function prepare_item_for_database( $request ) { - $prepared_review = array( 'comment_approved' => 1, 'comment_type' => 'review' ); - - if ( isset( $request['id'] ) ) { - $prepared_review['comment_ID'] = (int) $request['id']; - } - - if ( isset( $request['review'] ) ) { - $prepared_review['comment_content'] = $request['review']; - } - - if ( isset( $request['product_id'] ) ) { - $prepared_review['comment_post_ID'] = (int) $request['product_id']; - } - - if ( isset( $request['name'] ) ) { - $prepared_review['comment_author'] = $request['name']; - } - - if ( isset( $request['email'] ) ) { - $prepared_review['comment_author_email'] = $request['email']; - } - - if ( isset( $request['date_created'] ) ) { - $prepared_review['comment_date'] = $request['date_created']; - } - - if ( isset( $request['date_created_gmt'] ) ) { - $prepared_review['comment_date_gmt'] = $request['date_created_gmt']; - } - - return apply_filters( 'rest_preprocess_product_review', $prepared_review, $request ); - } - - /** - * Prepare links for the request. - * - * @param WP_Comment $review Product review object. - * @param WP_REST_Request $request Request object. - * @return array Links for the given product review. - */ - protected function prepare_links( $review, $request ) { - $product_id = (int) $request['product_id']; - $base = str_replace( '(?P[\d]+)', $product_id, $this->rest_base ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $review->comment_ID ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - 'up' => array( - 'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $product_id ) ), - ), - ); - - return $links; - } - - /** - * Get the Product Review's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'product_review', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'review' => array( - 'description' => __( 'The content of the review.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the review was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'rating' => array( - 'description' => __( 'Review rating (0 to 5).', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Reviewer name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email' => array( - 'description' => __( 'Reviewer email.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'verified' => array( - 'description' => __( 'Shows if the reviewer bought the product or not.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-product-shipping-classes-v1-controller.php b/src/Controllers/Version1/class-wc-rest-product-shipping-classes-v1-controller.php deleted file mode 100644 index 92ab292f1a0..00000000000 --- a/src/Controllers/Version1/class-wc-rest-product-shipping-classes-v1-controller.php +++ /dev/null @@ -1,134 +0,0 @@ - (int) $item->term_id, - 'name' => $item->name, - 'slug' => $item->slug, - 'description' => $item->description, - 'count' => (int) $item->count, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item, $request ) ); - - /** - * Filter a term item returned from the API. - * - * Allows modification of the term data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $item The original term object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->taxonomy}", $response, $item, $request ); - } - - /** - * Get the Shipping Class schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->taxonomy, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Shipping class name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'description' => array( - 'description' => __( 'HTML description of the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), - ), - 'count' => array( - 'description' => __( 'Number of published products for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-product-tags-v1-controller.php b/src/Controllers/Version1/class-wc-rest-product-tags-v1-controller.php deleted file mode 100644 index c4e587b44da..00000000000 --- a/src/Controllers/Version1/class-wc-rest-product-tags-v1-controller.php +++ /dev/null @@ -1,134 +0,0 @@ - (int) $item->term_id, - 'name' => $item->name, - 'slug' => $item->slug, - 'description' => $item->description, - 'count' => (int) $item->count, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item, $request ) ); - - /** - * Filter a term item returned from the API. - * - * Allows modification of the term data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $item The original term object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->taxonomy}", $response, $item, $request ); - } - - /** - * Get the Tag's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->taxonomy, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Tag name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'description' => array( - 'description' => __( 'HTML description of the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), - ), - 'count' => array( - 'description' => __( 'Number of published products for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-products-v1-controller.php b/src/Controllers/Version1/class-wc-rest-products-v1-controller.php deleted file mode 100644 index bf8629b027d..00000000000 --- a/src/Controllers/Version1/class-wc-rest-products-v1-controller.php +++ /dev/null @@ -1,2641 +0,0 @@ -post_type}_query", array( $this, 'query_args' ), 10, 2 ); - add_action( "woocommerce_rest_insert_{$this->post_type}", array( $this, 'clear_transients' ) ); - } - - /** - * Register the routes for products. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Get post types. - * - * @return array - */ - protected function get_post_types() { - return array( 'product', 'product_variation' ); - } - - /** - * Query args. - * - * @param array $args Request args. - * @param WP_REST_Request $request Request data. - * @return array - */ - public function query_args( $args, $request ) { - // Set post_status. - $args['post_status'] = $request['status']; - - // Taxonomy query to filter products by type, category, - // tag, shipping class, and attribute. - $tax_query = array(); - - // Map between taxonomy name and arg's key. - $taxonomies = array( - 'product_cat' => 'category', - 'product_tag' => 'tag', - 'product_shipping_class' => 'shipping_class', - ); - - // Set tax_query for each passed arg. - foreach ( $taxonomies as $taxonomy => $key ) { - if ( ! empty( $request[ $key ] ) && is_array( $request[ $key ] ) ) { - $request[ $key ] = array_filter( $request[ $key ] ); - } - - if ( ! empty( $request[ $key ] ) ) { - $tax_query[] = array( - 'taxonomy' => $taxonomy, - 'field' => 'term_id', - 'terms' => $request[ $key ], - ); - } - } - - // Filter product type by slug. - if ( ! empty( $request['type'] ) ) { - $tax_query[] = array( - 'taxonomy' => 'product_type', - 'field' => 'slug', - 'terms' => $request['type'], - ); - } - - // Filter by attribute and term. - if ( ! empty( $request['attribute'] ) && ! empty( $request['attribute_term'] ) ) { - if ( in_array( $request['attribute'], wc_get_attribute_taxonomy_names(), true ) ) { - $tax_query[] = array( - 'taxonomy' => $request['attribute'], - 'field' => 'term_id', - 'terms' => $request['attribute_term'], - ); - } - } - - if ( ! empty( $tax_query ) ) { - $args['tax_query'] = $tax_query; - } - - // Filter by sku. - if ( ! empty( $request['sku'] ) ) { - $skus = explode( ',', $request['sku'] ); - // Include the current string as a SKU too. - if ( 1 < count( $skus ) ) { - $skus[] = $request['sku']; - } - - $args['meta_query'] = $this->add_meta_query( $args, array( - 'key' => '_sku', - 'value' => $skus, - 'compare' => 'IN', - ) ); - } - - // Apply all WP_Query filters again. - if ( is_array( $request['filter'] ) ) { - $args = array_merge( $args, $request['filter'] ); - unset( $args['filter'] ); - } - - // Force the post_type argument, since it's not a user input variable. - if ( ! empty( $request['sku'] ) ) { - $args['post_type'] = array( 'product', 'product_variation' ); - } else { - $args['post_type'] = $this->post_type; - } - - return $args; - } - - /** - * Get the downloads for a product or product variation. - * - * @param WC_Product|WC_Product_Variation $product Product instance. - * @return array - */ - protected function get_downloads( $product ) { - $downloads = array(); - - if ( $product->is_downloadable() ) { - foreach ( $product->get_downloads() as $file_id => $file ) { - $downloads[] = array( - 'id' => $file_id, // MD5 hash. - 'name' => $file['name'], - 'file' => $file['file'], - ); - } - } - - return $downloads; - } - - /** - * Get taxonomy terms. - * - * @param WC_Product $product Product instance. - * @param string $taxonomy Taxonomy slug. - * @return array - */ - protected function get_taxonomy_terms( $product, $taxonomy = 'cat' ) { - $terms = array(); - - foreach ( wc_get_object_terms( $product->get_id(), 'product_' . $taxonomy ) as $term ) { - $terms[] = array( - 'id' => $term->term_id, - 'name' => $term->name, - 'slug' => $term->slug, - ); - } - - return $terms; - } - - /** - * Get the images for a product or product variation. - * - * @param WC_Product|WC_Product_Variation $product Product instance. - * @return array - */ - protected function get_images( $product ) { - $images = array(); - $attachment_ids = array(); - - // Add featured image. - if ( $product->get_image_id() ) { - $attachment_ids[] = $product->get_image_id(); - } - - // Add gallery images. - $attachment_ids = array_merge( $attachment_ids, $product->get_gallery_image_ids() ); - - // Build image data. - foreach ( $attachment_ids as $position => $attachment_id ) { - $attachment_post = get_post( $attachment_id ); - if ( is_null( $attachment_post ) ) { - continue; - } - - $attachment = wp_get_attachment_image_src( $attachment_id, 'full' ); - if ( ! is_array( $attachment ) ) { - continue; - } - - $images[] = array( - 'id' => (int) $attachment_id, - 'date_created' => wc_rest_prepare_date_response( $attachment_post->post_date_gmt ), - 'date_modified' => wc_rest_prepare_date_response( $attachment_post->post_modified_gmt ), - 'src' => current( $attachment ), - 'name' => get_the_title( $attachment_id ), - 'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ), - 'position' => (int) $position, - ); - } - - // Set a placeholder image if the product has no images set. - if ( empty( $images ) ) { - $images[] = array( - 'id' => 0, - 'date_created' => wc_rest_prepare_date_response( current_time( 'mysql' ) ), // Default to now. - 'date_modified' => wc_rest_prepare_date_response( current_time( 'mysql' ) ), - 'src' => wc_placeholder_img_src(), - 'name' => __( 'Placeholder', 'woocommerce-rest-api' ), - 'alt' => __( 'Placeholder', 'woocommerce-rest-api' ), - 'position' => 0, - ); - } - - return $images; - } - - /** - * Get attribute taxonomy label. - * - * @param string $name Taxonomy name. - * @return string - */ - protected function get_attribute_taxonomy_label( $name ) { - $tax = get_taxonomy( $name ); - $labels = get_taxonomy_labels( $tax ); - - return $labels->singular_name; - } - - /** - * Get default attributes. - * - * @param WC_Product $product Product instance. - * @return array - */ - protected function get_default_attributes( $product ) { - $default = array(); - - if ( $product->is_type( 'variable' ) ) { - foreach ( array_filter( (array) $product->get_default_attributes(), 'strlen' ) as $key => $value ) { - if ( 0 === strpos( $key, 'pa_' ) ) { - $default[] = array( - 'id' => wc_attribute_taxonomy_id_by_name( $key ), - 'name' => $this->get_attribute_taxonomy_label( $key ), - 'option' => $value, - ); - } else { - $default[] = array( - 'id' => 0, - 'name' => wc_attribute_taxonomy_slug( $key ), - 'option' => $value, - ); - } - } - } - - return $default; - } - - /** - * Get attribute options. - * - * @param int $product_id Product ID. - * @param array $attribute Attribute data. - * @return array - */ - protected function get_attribute_options( $product_id, $attribute ) { - if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) { - return wc_get_product_terms( $product_id, $attribute['name'], array( 'fields' => 'names' ) ); - } elseif ( isset( $attribute['value'] ) ) { - return array_map( 'trim', explode( '|', $attribute['value'] ) ); - } - - return array(); - } - - /** - * Get the attributes for a product or product variation. - * - * @param WC_Product|WC_Product_Variation $product Product instance. - * @return array - */ - protected function get_attributes( $product ) { - $attributes = array(); - - if ( $product->is_type( 'variation' ) ) { - // Variation attributes. - foreach ( $product->get_variation_attributes() as $attribute_name => $attribute ) { - $name = str_replace( 'attribute_', '', $attribute_name ); - - if ( ! $attribute ) { - continue; - } - - // Taxonomy-based attributes are prefixed with `pa_`, otherwise simply `attribute_`. - if ( 0 === strpos( $attribute_name, 'attribute_pa_' ) ) { - $option_term = get_term_by( 'slug', $attribute, $name ); - $attributes[] = array( - 'id' => wc_attribute_taxonomy_id_by_name( $name ), - 'name' => $this->get_attribute_taxonomy_label( $name ), - 'option' => $option_term && ! is_wp_error( $option_term ) ? $option_term->name : $attribute, - ); - } else { - $attributes[] = array( - 'id' => 0, - 'name' => $name, - 'option' => $attribute, - ); - } - } - } else { - foreach ( $product->get_attributes() as $attribute ) { - if ( $attribute['is_taxonomy'] ) { - $attributes[] = array( - 'id' => wc_attribute_taxonomy_id_by_name( $attribute['name'] ), - 'name' => $this->get_attribute_taxonomy_label( $attribute['name'] ), - 'position' => (int) $attribute['position'], - 'visible' => (bool) $attribute['is_visible'], - 'variation' => (bool) $attribute['is_variation'], - 'options' => $this->get_attribute_options( $product->get_id(), $attribute ), - ); - } else { - $attributes[] = array( - 'id' => 0, - 'name' => $attribute['name'], - 'position' => (int) $attribute['position'], - 'visible' => (bool) $attribute['is_visible'], - 'variation' => (bool) $attribute['is_variation'], - 'options' => $this->get_attribute_options( $product->get_id(), $attribute ), - ); - } - } - } - - return $attributes; - } - - /** - * Get product menu order. - * - * @deprecated 3.0.0 - * @param WC_Product $product Product instance. - * @return int - */ - protected function get_product_menu_order( $product ) { - return $product->get_menu_order(); - } - - /** - * Get product data. - * - * @param WC_Product $product Product instance. - * @return array - */ - protected function get_product_data( $product ) { - $data = array( - 'id' => $product->get_id(), - 'name' => $product->get_name(), - 'slug' => $product->get_slug(), - 'permalink' => $product->get_permalink(), - 'date_created' => wc_rest_prepare_date_response( $product->get_date_created() ), - 'date_modified' => wc_rest_prepare_date_response( $product->get_date_modified() ), - 'type' => $product->get_type(), - 'status' => $product->get_status(), - 'featured' => $product->is_featured(), - 'catalog_visibility' => $product->get_catalog_visibility(), - 'description' => wpautop( do_shortcode( $product->get_description() ) ), - 'short_description' => apply_filters( 'woocommerce_short_description', $product->get_short_description() ), - 'sku' => $product->get_sku(), - 'price' => $product->get_price(), - 'regular_price' => $product->get_regular_price(), - 'sale_price' => $product->get_sale_price() ? $product->get_sale_price() : '', - 'date_on_sale_from' => $product->get_date_on_sale_from() ? date( 'Y-m-d', $product->get_date_on_sale_from()->getTimestamp() ) : '', - 'date_on_sale_to' => $product->get_date_on_sale_to() ? date( 'Y-m-d', $product->get_date_on_sale_to()->getTimestamp() ) : '', - 'price_html' => $product->get_price_html(), - 'on_sale' => $product->is_on_sale(), - 'purchasable' => $product->is_purchasable(), - 'total_sales' => $product->get_total_sales(), - 'virtual' => $product->is_virtual(), - 'downloadable' => $product->is_downloadable(), - 'downloads' => $this->get_downloads( $product ), - 'download_limit' => $product->get_download_limit(), - 'download_expiry' => $product->get_download_expiry(), - 'download_type' => 'standard', - 'external_url' => $product->is_type( 'external' ) ? $product->get_product_url() : '', - 'button_text' => $product->is_type( 'external' ) ? $product->get_button_text() : '', - 'tax_status' => $product->get_tax_status(), - 'tax_class' => $product->get_tax_class(), - 'manage_stock' => $product->managing_stock(), - 'stock_quantity' => $product->get_stock_quantity(), - 'in_stock' => $product->is_in_stock(), - 'backorders' => $product->get_backorders(), - 'backorders_allowed' => $product->backorders_allowed(), - 'backordered' => $product->is_on_backorder(), - 'sold_individually' => $product->is_sold_individually(), - 'weight' => $product->get_weight(), - 'dimensions' => array( - 'length' => $product->get_length(), - 'width' => $product->get_width(), - 'height' => $product->get_height(), - ), - 'shipping_required' => $product->needs_shipping(), - 'shipping_taxable' => $product->is_shipping_taxable(), - 'shipping_class' => $product->get_shipping_class(), - 'shipping_class_id' => $product->get_shipping_class_id(), - 'reviews_allowed' => $product->get_reviews_allowed(), - 'average_rating' => wc_format_decimal( $product->get_average_rating(), 2 ), - 'rating_count' => $product->get_rating_count(), - 'related_ids' => array_map( 'absint', array_values( wc_get_related_products( $product->get_id() ) ) ), - 'upsell_ids' => array_map( 'absint', $product->get_upsell_ids() ), - 'cross_sell_ids' => array_map( 'absint', $product->get_cross_sell_ids() ), - 'parent_id' => $product->get_parent_id(), - 'purchase_note' => wpautop( do_shortcode( wp_kses_post( $product->get_purchase_note() ) ) ), - 'categories' => $this->get_taxonomy_terms( $product ), - 'tags' => $this->get_taxonomy_terms( $product, 'tag' ), - 'images' => $this->get_images( $product ), - 'attributes' => $this->get_attributes( $product ), - 'default_attributes' => $this->get_default_attributes( $product ), - 'variations' => array(), - 'grouped_products' => array(), - 'menu_order' => $product->get_menu_order(), - ); - - return $data; - } - - /** - * Get an individual variation's data. - * - * @param WC_Product $product Product instance. - * @return array - */ - protected function get_variation_data( $product ) { - $variations = array(); - - foreach ( $product->get_children() as $child_id ) { - $variation = wc_get_product( $child_id ); - if ( ! $variation || ! $variation->exists() ) { - continue; - } - - $variations[] = array( - 'id' => $variation->get_id(), - 'date_created' => wc_rest_prepare_date_response( $variation->get_date_created() ), - 'date_modified' => wc_rest_prepare_date_response( $variation->get_date_modified() ), - 'permalink' => $variation->get_permalink(), - 'sku' => $variation->get_sku(), - 'price' => $variation->get_price(), - 'regular_price' => $variation->get_regular_price(), - 'sale_price' => $variation->get_sale_price(), - 'date_on_sale_from' => $variation->get_date_on_sale_from() ? date( 'Y-m-d', $variation->get_date_on_sale_from()->getTimestamp() ) : '', - 'date_on_sale_to' => $variation->get_date_on_sale_to() ? date( 'Y-m-d', $variation->get_date_on_sale_to()->getTimestamp() ) : '', - 'on_sale' => $variation->is_on_sale(), - 'purchasable' => $variation->is_purchasable(), - 'visible' => $variation->is_visible(), - 'virtual' => $variation->is_virtual(), - 'downloadable' => $variation->is_downloadable(), - 'downloads' => $this->get_downloads( $variation ), - 'download_limit' => '' !== $variation->get_download_limit() ? (int) $variation->get_download_limit() : -1, - 'download_expiry' => '' !== $variation->get_download_expiry() ? (int) $variation->get_download_expiry() : -1, - 'tax_status' => $variation->get_tax_status(), - 'tax_class' => $variation->get_tax_class(), - 'manage_stock' => $variation->managing_stock(), - 'stock_quantity' => $variation->get_stock_quantity(), - 'in_stock' => $variation->is_in_stock(), - 'backorders' => $variation->get_backorders(), - 'backorders_allowed' => $variation->backorders_allowed(), - 'backordered' => $variation->is_on_backorder(), - 'weight' => $variation->get_weight(), - 'dimensions' => array( - 'length' => $variation->get_length(), - 'width' => $variation->get_width(), - 'height' => $variation->get_height(), - ), - 'shipping_class' => $variation->get_shipping_class(), - 'shipping_class_id' => $variation->get_shipping_class_id(), - 'image' => $this->get_images( $variation ), - 'attributes' => $this->get_attributes( $variation ), - ); - } - - return $variations; - } - - /** - * Prepare a single product output for response. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function prepare_item_for_response( $post, $request ) { - $product = wc_get_product( $post ); - $data = $this->get_product_data( $product ); - - // Add variations to variable products. - if ( $product->is_type( 'variable' ) && $product->has_child() ) { - $data['variations'] = $this->get_variation_data( $product ); - } - - // Add grouped products data. - if ( $product->is_type( 'grouped' ) && $product->has_child() ) { - $data['grouped_products'] = $product->get_children(); - } - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $product, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request ); - } - - /** - * Prepare links for the request. - * - * @param WC_Product $product Product object. - * @param WP_REST_Request $request Request object. - * @return array Links for the given product. - */ - protected function prepare_links( $product, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $product->get_id() ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - if ( $product->get_parent_id() ) { - $links['up'] = array( - 'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $product->get_parent_id() ) ), - ); - } - - return $links; - } - - /** - * Prepare a single product for create or update. - * - * @param WP_REST_Request $request Request object. - * @return WP_Error|stdClass $data Post object. - */ - protected function prepare_item_for_database( $request ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - - // Type is the most important part here because we need to be using the correct class and methods. - if ( isset( $request['type'] ) ) { - $classname = WC_Product_Factory::get_classname_from_product_type( $request['type'] ); - - if ( ! class_exists( $classname ) ) { - $classname = 'WC_Product_Simple'; - } - - $product = new $classname( $id ); - } elseif ( isset( $request['id'] ) ) { - $product = wc_get_product( $id ); - } else { - $product = new WC_Product_Simple(); - } - - // Post title. - if ( isset( $request['name'] ) ) { - $product->set_name( wp_filter_post_kses( $request['name'] ) ); - } - - // Post content. - if ( isset( $request['description'] ) ) { - $product->set_description( wp_filter_post_kses( $request['description'] ) ); - } - - // Post excerpt. - if ( isset( $request['short_description'] ) ) { - $product->set_short_description( wp_filter_post_kses( $request['short_description'] ) ); - } - - // Post status. - if ( isset( $request['status'] ) ) { - $product->set_status( get_post_status_object( $request['status'] ) ? $request['status'] : 'draft' ); - } - - // Post slug. - if ( isset( $request['slug'] ) ) { - $product->set_slug( $request['slug'] ); - } - - // Menu order. - if ( isset( $request['menu_order'] ) ) { - $product->set_menu_order( $request['menu_order'] ); - } - - // Comment status. - if ( isset( $request['reviews_allowed'] ) ) { - $product->set_reviews_allowed( $request['reviews_allowed'] ); - } - - /** - * Filter the query_vars used in `get_items` for the constructed query. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for insertion. - * - * @param WC_Product $product An object representing a single item prepared - * for inserting or updating the database. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $product, $request ); - } - - /** - * Create a single product. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $product_id = 0; - - try { - $product_id = $this->save_product( $request ); - $post = get_post( $product_id ); - $this->update_additional_fields_for_object( $post, $request ); - $this->update_post_meta_fields( $post, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post data. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( 'woocommerce_rest_insert_product', $post, $request, true ); - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ) ); - - return $response; - } catch ( WC_Data_Exception $e ) { - $this->delete_post( $product_id ); - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - $this->delete_post( $product_id ); - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Update a single product. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $post_id = (int) $request['id']; - - if ( empty( $post_id ) || get_post_type( $post_id ) !== $this->post_type ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - try { - $product_id = $this->save_product( $request ); - $post = get_post( $product_id ); - $this->update_additional_fields_for_object( $post, $request ); - $this->update_post_meta_fields( $post, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post data. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( 'woocommerce_rest_insert_product', $post, $request, false ); - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - - return rest_ensure_response( $response ); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Saves a product to the database. - * - * @param WP_REST_Request $request Full details about the request. - * @return int - */ - public function save_product( $request ) { - $product = $this->prepare_item_for_database( $request ); - return $product->save(); - } - - /** - * Save product images. - * - * @deprecated 3.0.0 - * @param int $product_id - * @param array $images - * @throws WC_REST_Exception - */ - protected function save_product_images( $product_id, $images ) { - $product = wc_get_product( $product_id ); - - return set_product_images( $product, $images ); - } - - /** - * Set product images. - * - * @throws WC_REST_Exception REST API exceptions. - * @param WC_Product $product Product instance. - * @param array $images Images data. - * @return WC_Product - */ - protected function set_product_images( $product, $images ) { - if ( is_array( $images ) ) { - $gallery = array(); - - foreach ( $images as $image ) { - $attachment_id = isset( $image['id'] ) ? absint( $image['id'] ) : 0; - - if ( 0 === $attachment_id && isset( $image['src'] ) ) { - $upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) ); - - if ( is_wp_error( $upload ) ) { - if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $product->get_id(), $images ) ) { - throw new WC_REST_Exception( 'woocommerce_product_image_upload_error', $upload->get_error_message(), 400 ); - } else { - continue; - } - } - - $attachment_id = wc_rest_set_uploaded_image_as_attachment( $upload, $product->get_id() ); - } - - if ( ! wp_attachment_is_image( $attachment_id ) ) { - throw new WC_REST_Exception( 'woocommerce_product_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce-rest-api' ), $attachment_id ), 400 ); - } - - if ( isset( $image['position'] ) && 0 === absint( $image['position'] ) ) { - $product->set_image_id( $attachment_id ); - } else { - $gallery[] = $attachment_id; - } - - // Set the image alt if present. - if ( ! empty( $image['alt'] ) ) { - update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) ); - } - - // Set the image name if present. - if ( ! empty( $image['name'] ) ) { - wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['name'] ) ); - } - } - - if ( ! empty( $gallery ) ) { - $product->set_gallery_image_ids( $gallery ); - } - } else { - $product->set_image_id( '' ); - $product->set_gallery_image_ids( array() ); - } - - return $product; - } - - /** - * Save product shipping data. - * - * @param WC_Product $product Product instance. - * @param array $data Shipping data. - * @return WC_Product - */ - protected function save_product_shipping_data( $product, $data ) { - // Virtual. - if ( isset( $data['virtual'] ) && true === $data['virtual'] ) { - $product->set_weight( '' ); - $product->set_height( '' ); - $product->set_length( '' ); - $product->set_width( '' ); - } else { - if ( isset( $data['weight'] ) ) { - $product->set_weight( $data['weight'] ); - } - - // Height. - if ( isset( $data['dimensions']['height'] ) ) { - $product->set_height( $data['dimensions']['height'] ); - } - - // Width. - if ( isset( $data['dimensions']['width'] ) ) { - $product->set_width( $data['dimensions']['width'] ); - } - - // Length. - if ( isset( $data['dimensions']['length'] ) ) { - $product->set_length( $data['dimensions']['length'] ); - } - } - - // Shipping class. - if ( isset( $data['shipping_class'] ) ) { - $data_store = $product->get_data_store(); - $shipping_class_id = $data_store->get_shipping_class_id_by_slug( wc_clean( $data['shipping_class'] ) ); - $product->set_shipping_class_id( $shipping_class_id ); - } - - return $product; - } - - /** - * Save downloadable files. - * - * @param WC_Product $product Product instance. - * @param array $downloads Downloads data. - * @param int $deprecated Deprecated since 3.0. - * @return WC_Product - */ - protected function save_downloadable_files( $product, $downloads, $deprecated = 0 ) { - if ( $deprecated ) { - wc_deprecated_argument( 'variation_id', '3.0', 'save_downloadable_files() not requires a variation_id anymore.' ); - } - - $files = array(); - foreach ( $downloads as $key => $file ) { - if ( empty( $file['file'] ) ) { - continue; - } - - $download = new WC_Product_Download(); - $download->set_id( ! empty( $file['id'] ) ? $file['id'] : wp_generate_uuid4() ); - $download->set_name( $file['name'] ? $file['name'] : wc_get_filename_from_url( $file['file'] ) ); - $download->set_file( apply_filters( 'woocommerce_file_download_path', $file['file'], $product, $key ) ); - $files[] = $download; - } - $product->set_downloads( $files ); - - return $product; - } - - /** - * Save taxonomy terms. - * - * @param WC_Product $product Product instance. - * @param array $terms Terms data. - * @param string $taxonomy Taxonomy name. - * @return WC_Product - */ - protected function save_taxonomy_terms( $product, $terms, $taxonomy = 'cat' ) { - $term_ids = wp_list_pluck( $terms, 'id' ); - - if ( 'cat' === $taxonomy ) { - $product->set_category_ids( $term_ids ); - } elseif ( 'tag' === $taxonomy ) { - $product->set_tag_ids( $term_ids ); - } - - return $product; - } - - /** - * Save default attributes. - * - * @since 3.0.0 - * - * @param WC_Product $product Product instance. - * @param WP_REST_Request $request Request data. - * @return WC_Product - */ - protected function save_default_attributes( $product, $request ) { - if ( isset( $request['default_attributes'] ) && is_array( $request['default_attributes'] ) ) { - $attributes = $product->get_attributes(); - $default_attributes = array(); - - foreach ( $request['default_attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $attribute_name = sanitize_title( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $attribute_name ) { - continue; - } - - if ( isset( $attributes[ $attribute_name ] ) ) { - $_attribute = $attributes[ $attribute_name ]; - - if ( $_attribute['is_variation'] ) { - $value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : ''; - - if ( ! empty( $_attribute['is_taxonomy'] ) ) { - // If dealing with a taxonomy, we need to get the slug from the name posted to the API. - $term = get_term_by( 'name', $value, $attribute_name ); - - if ( $term && ! is_wp_error( $term ) ) { - $value = $term->slug; - } else { - $value = sanitize_title( $value ); - } - } - - if ( $value ) { - $default_attributes[ $attribute_name ] = $value; - } - } - } - } - - $product->set_default_attributes( $default_attributes ); - } - - return $product; - } - - /** - * Save product meta. - * - * @deprecated 3.0.0 - * @param WC_Product $product - * @param WP_REST_Request $request - * @return bool - * @throws WC_REST_Exception - */ - protected function save_product_meta( $product, $request ) { - $product = $this->set_product_meta( $product, $request ); - $product->save(); - - return true; - } - - /** - * Set product meta. - * - * @throws WC_REST_Exception REST API exceptions. - * @param WC_Product $product Product instance. - * @param WP_REST_Request $request Request data. - * @return WC_Product - */ - protected function set_product_meta( $product, $request ) { - // Virtual. - if ( isset( $request['virtual'] ) ) { - $product->set_virtual( $request['virtual'] ); - } - - // Tax status. - if ( isset( $request['tax_status'] ) ) { - $product->set_tax_status( $request['tax_status'] ); - } - - // Tax Class. - if ( isset( $request['tax_class'] ) ) { - $product->set_tax_class( $request['tax_class'] ); - } - - // Catalog Visibility. - if ( isset( $request['catalog_visibility'] ) ) { - $product->set_catalog_visibility( $request['catalog_visibility'] ); - } - - // Purchase Note. - if ( isset( $request['purchase_note'] ) ) { - $product->set_purchase_note( wp_kses_post( wp_unslash( $request['purchase_note'] ) ) ); - } - - // Featured Product. - if ( isset( $request['featured'] ) ) { - $product->set_featured( $request['featured'] ); - } - - // Shipping data. - $product = $this->save_product_shipping_data( $product, $request ); - - // SKU. - if ( isset( $request['sku'] ) ) { - $product->set_sku( wc_clean( $request['sku'] ) ); - } - - // Attributes. - if ( isset( $request['attributes'] ) ) { - $attributes = array(); - - foreach ( $request['attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $attribute_name = wc_clean( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $attribute_name ) { - continue; - } - - if ( $attribute_id ) { - - if ( isset( $attribute['options'] ) ) { - $options = $attribute['options']; - - if ( ! is_array( $attribute['options'] ) ) { - // Text based attributes - Posted values are term names. - $options = explode( WC_DELIMITER, $options ); - } - - $values = array_map( 'wc_sanitize_term_text_based', $options ); - $values = array_filter( $values, 'strlen' ); - } else { - $values = array(); - } - - if ( ! empty( $values ) ) { - // Add attribute to array, but don't set values. - $attribute_object = new WC_Product_Attribute(); - $attribute_object->set_id( $attribute_id ); - $attribute_object->set_name( $attribute_name ); - $attribute_object->set_options( $values ); - $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' ); - $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 ); - $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 ); - $attributes[] = $attribute_object; - } - } elseif ( isset( $attribute['options'] ) ) { - // Custom attribute - Add attribute to array and set the values. - if ( is_array( $attribute['options'] ) ) { - $values = $attribute['options']; - } else { - $values = explode( WC_DELIMITER, $attribute['options'] ); - } - $attribute_object = new WC_Product_Attribute(); - $attribute_object->set_name( $attribute_name ); - $attribute_object->set_options( $values ); - $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' ); - $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 ); - $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 ); - $attributes[] = $attribute_object; - } - } - $product->set_attributes( $attributes ); - } - - // Sales and prices. - if ( in_array( $product->get_type(), array( 'variable', 'grouped' ), true ) ) { - $product->set_regular_price( '' ); - $product->set_sale_price( '' ); - $product->set_date_on_sale_to( '' ); - $product->set_date_on_sale_from( '' ); - $product->set_price( '' ); - } else { - // Regular Price. - if ( isset( $request['regular_price'] ) ) { - $product->set_regular_price( $request['regular_price'] ); - } - - // Sale Price. - if ( isset( $request['sale_price'] ) ) { - $product->set_sale_price( $request['sale_price'] ); - } - - if ( isset( $request['date_on_sale_from'] ) ) { - $product->set_date_on_sale_from( $request['date_on_sale_from'] ); - } - - if ( isset( $request['date_on_sale_to'] ) ) { - $product->set_date_on_sale_to( $request['date_on_sale_to'] ); - } - } - - // Product parent ID for groups. - if ( isset( $request['parent_id'] ) ) { - $product->set_parent_id( $request['parent_id'] ); - } - - // Sold individually. - if ( isset( $request['sold_individually'] ) ) { - $product->set_sold_individually( $request['sold_individually'] ); - } - - // Stock status. - if ( isset( $request['in_stock'] ) ) { - $stock_status = true === $request['in_stock'] ? 'instock' : 'outofstock'; - } else { - $stock_status = $product->get_stock_status(); - } - - // Stock data. - if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { - // Manage stock. - if ( isset( $request['manage_stock'] ) ) { - $product->set_manage_stock( $request['manage_stock'] ); - } - - // Backorders. - if ( isset( $request['backorders'] ) ) { - $product->set_backorders( $request['backorders'] ); - } - - if ( $product->is_type( 'grouped' ) ) { - $product->set_manage_stock( 'no' ); - $product->set_backorders( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } elseif ( $product->is_type( 'external' ) ) { - $product->set_manage_stock( 'no' ); - $product->set_backorders( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( 'instock' ); - } elseif ( $product->get_manage_stock() ) { - // Stock status is always determined by children so sync later. - if ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Stock quantity. - if ( isset( $request['stock_quantity'] ) ) { - $product->set_stock_quantity( wc_stock_amount( $request['stock_quantity'] ) ); - } elseif ( isset( $request['inventory_delta'] ) ) { - $stock_quantity = wc_stock_amount( $product->get_stock_quantity() ); - $stock_quantity += wc_stock_amount( $request['inventory_delta'] ); - $product->set_stock_quantity( wc_stock_amount( $stock_quantity ) ); - } - } else { - // Don't manage stock. - $product->set_manage_stock( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } - } elseif ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Upsells. - if ( isset( $request['upsell_ids'] ) ) { - $upsells = array(); - $ids = $request['upsell_ids']; - - if ( ! empty( $ids ) ) { - foreach ( $ids as $id ) { - if ( $id && $id > 0 ) { - $upsells[] = $id; - } - } - } - - $product->set_upsell_ids( $upsells ); - } - - // Cross sells. - if ( isset( $request['cross_sell_ids'] ) ) { - $crosssells = array(); - $ids = $request['cross_sell_ids']; - - if ( ! empty( $ids ) ) { - foreach ( $ids as $id ) { - if ( $id && $id > 0 ) { - $crosssells[] = $id; - } - } - } - - $product->set_cross_sell_ids( $crosssells ); - } - - // Product categories. - if ( isset( $request['categories'] ) && is_array( $request['categories'] ) ) { - $product = $this->save_taxonomy_terms( $product, $request['categories'] ); - } - - // Product tags. - if ( isset( $request['tags'] ) && is_array( $request['tags'] ) ) { - $product = $this->save_taxonomy_terms( $product, $request['tags'], 'tag' ); - } - - // Downloadable. - if ( isset( $request['downloadable'] ) ) { - $product->set_downloadable( $request['downloadable'] ); - } - - // Downloadable options. - if ( $product->get_downloadable() ) { - - // Downloadable files. - if ( isset( $request['downloads'] ) && is_array( $request['downloads'] ) ) { - $product = $this->save_downloadable_files( $product, $request['downloads'] ); - } - - // Download limit. - if ( isset( $request['download_limit'] ) ) { - $product->set_download_limit( $request['download_limit'] ); - } - - // Download expiry. - if ( isset( $request['download_expiry'] ) ) { - $product->set_download_expiry( $request['download_expiry'] ); - } - } - - // Product url and button text for external products. - if ( $product->is_type( 'external' ) ) { - if ( isset( $request['external_url'] ) ) { - $product->set_product_url( $request['external_url'] ); - } - - if ( isset( $request['button_text'] ) ) { - $product->set_button_text( $request['button_text'] ); - } - } - - // Save default attributes for variable products. - if ( $product->is_type( 'variable' ) ) { - $product = $this->save_default_attributes( $product, $request ); - } - - return $product; - } - - /** - * Save variations. - * - * @throws WC_REST_Exception REST API exceptions. - * @param WC_Product $product Product instance. - * @param WP_REST_Request $request Request data. - * @return bool - */ - protected function save_variations_data( $product, $request ) { - foreach ( $request['variations'] as $menu_order => $data ) { - $variation = new WC_Product_Variation( isset( $data['id'] ) ? absint( $data['id'] ) : 0 ); - - // Create initial name and status. - if ( ! $variation->get_slug() ) { - /* translators: 1: variation id 2: product name */ - $variation->set_name( sprintf( __( 'Variation #%1$s of %2$s', 'woocommerce-rest-api' ), $variation->get_id(), $product->get_name() ) ); - $variation->set_status( isset( $data['visible'] ) && false === $data['visible'] ? 'private' : 'publish' ); - } - - // Parent ID. - $variation->set_parent_id( $product->get_id() ); - - // Menu order. - $variation->set_menu_order( $menu_order ); - - // Status. - if ( isset( $data['visible'] ) ) { - $variation->set_status( false === $data['visible'] ? 'private' : 'publish' ); - } - - // SKU. - if ( isset( $data['sku'] ) ) { - $variation->set_sku( wc_clean( $data['sku'] ) ); - } - - // Thumbnail. - if ( isset( $data['image'] ) && is_array( $data['image'] ) ) { - $image = $data['image']; - $image = current( $image ); - if ( is_array( $image ) ) { - $image['position'] = 0; - } - - $variation = $this->set_product_images( $variation, array( $image ) ); - } - - // Virtual variation. - if ( isset( $data['virtual'] ) ) { - $variation->set_virtual( $data['virtual'] ); - } - - // Downloadable variation. - if ( isset( $data['downloadable'] ) ) { - $variation->set_downloadable( $data['downloadable'] ); - } - - // Downloads. - if ( $variation->get_downloadable() ) { - // Downloadable files. - if ( isset( $data['downloads'] ) && is_array( $data['downloads'] ) ) { - $variation = $this->save_downloadable_files( $variation, $data['downloads'] ); - } - - // Download limit. - if ( isset( $data['download_limit'] ) ) { - $variation->set_download_limit( $data['download_limit'] ); - } - - // Download expiry. - if ( isset( $data['download_expiry'] ) ) { - $variation->set_download_expiry( $data['download_expiry'] ); - } - } - - // Shipping data. - $variation = $this->save_product_shipping_data( $variation, $data ); - - // Stock handling. - if ( isset( $data['manage_stock'] ) ) { - $variation->set_manage_stock( $data['manage_stock'] ); - } - - if ( isset( $data['in_stock'] ) ) { - $variation->set_stock_status( true === $data['in_stock'] ? 'instock' : 'outofstock' ); - } - - if ( isset( $data['backorders'] ) ) { - $variation->set_backorders( $data['backorders'] ); - } - - if ( $variation->get_manage_stock() ) { - if ( isset( $data['stock_quantity'] ) ) { - $variation->set_stock_quantity( $data['stock_quantity'] ); - } elseif ( isset( $data['inventory_delta'] ) ) { - $stock_quantity = wc_stock_amount( $variation->get_stock_quantity() ); - $stock_quantity += wc_stock_amount( $data['inventory_delta'] ); - $variation->set_stock_quantity( $stock_quantity ); - } - } else { - $variation->set_backorders( 'no' ); - $variation->set_stock_quantity( '' ); - } - - // Regular Price. - if ( isset( $data['regular_price'] ) ) { - $variation->set_regular_price( $data['regular_price'] ); - } - - // Sale Price. - if ( isset( $data['sale_price'] ) ) { - $variation->set_sale_price( $data['sale_price'] ); - } - - if ( isset( $data['date_on_sale_from'] ) ) { - $variation->set_date_on_sale_from( $data['date_on_sale_from'] ); - } - - if ( isset( $data['date_on_sale_to'] ) ) { - $variation->set_date_on_sale_to( $data['date_on_sale_to'] ); - } - - // Tax class. - if ( isset( $data['tax_class'] ) ) { - $variation->set_tax_class( $data['tax_class'] ); - } - - // Description. - if ( isset( $data['description'] ) ) { - $variation->set_description( wp_kses_post( $data['description'] ) ); - } - - // Update taxonomies. - if ( isset( $data['attributes'] ) ) { - $attributes = array(); - $parent_attributes = $product->get_attributes(); - - foreach ( $data['attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $attribute_name = sanitize_title( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $attribute_name ) { - continue; - } - - if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) { - continue; - } - - $attribute_key = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() ); - $attribute_value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : ''; - - if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) { - // If dealing with a taxonomy, we need to get the slug from the name posted to the API. - $term = get_term_by( 'name', $attribute_value, $attribute_name ); - - if ( $term && ! is_wp_error( $term ) ) { - $attribute_value = $term->slug; - } else { - $attribute_value = sanitize_title( $attribute_value ); - } - } - - $attributes[ $attribute_key ] = $attribute_value; - } - - $variation->set_attributes( $attributes ); - } - - $variation->save(); - - do_action( 'woocommerce_rest_save_product_variation', $variation->get_id(), $menu_order, $data ); - } - - return true; - } - - /** - * Add post meta fields. - * - * @param WP_Post $post Post data. - * @param WP_REST_Request $request Request data. - * @return bool|WP_Error - */ - protected function add_post_meta_fields( $post, $request ) { - return $this->update_post_meta_fields( $post, $request ); - } - - /** - * Update post meta fields. - * - * @param WP_Post $post Post data. - * @param WP_REST_Request $request Request data. - * @return bool|WP_Error - */ - protected function update_post_meta_fields( $post, $request ) { - $product = wc_get_product( $post ); - - // Check for featured/gallery images, upload it and set it. - if ( isset( $request['images'] ) ) { - $product = $this->set_product_images( $product, $request['images'] ); - } - - // Save product meta fields. - $product = $this->set_product_meta( $product, $request ); - - // Save the product data. - $product->save(); - - // Save variations. - if ( $product->is_type( 'variable' ) ) { - if ( isset( $request['variations'] ) && is_array( $request['variations'] ) ) { - $this->save_variations_data( $product, $request ); - } - } - - // Clear caches here so in sync with any new variations/children. - wc_delete_product_transients( $product->get_id() ); - wp_cache_delete( 'product-' . $product->get_id(), 'products' ); - - return true; - } - - /** - * Clear cache/transients. - * - * @param WP_Post $post Post data. - */ - public function clear_transients( $post ) { - wc_delete_product_transients( $post->ID ); - } - - /** - * Delete post. - * - * @param int|WP_Post $id Post ID or WP_Post instance. - */ - protected function delete_post( $id ) { - if ( ! empty( $id->ID ) ) { - $id = $id->ID; - } elseif ( ! is_numeric( $id ) || 0 >= $id ) { - return; - } - - // Delete product attachments. - $attachments = get_posts( array( - 'post_parent' => $id, - 'post_status' => 'any', - 'post_type' => 'attachment', - ) ); - - foreach ( (array) $attachments as $attachment ) { - wp_delete_attachment( $attachment->ID, true ); - } - - // Delete product. - $product = wc_get_product( $id ); - $product->delete( true ); - } - - /** - * Delete a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $id = (int) $request['id']; - $force = (bool) $request['force']; - $post = get_post( $id ); - $product = wc_get_product( $id ); - - if ( ! empty( $post->post_type ) && 'product_variation' === $post->post_type && 'product' === $this->post_type ) { - return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } elseif ( empty( $id ) || empty( $post->ID ) || $post->post_type !== $this->post_type ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $supports_trash = EMPTY_TRASH_DAYS > 0; - - /** - * Filter whether an item is trashable. - * - * Return false to disable trash support for the item. - * - * @param boolean $supports_trash Whether the item type support trashing. - * @param WP_Post $post The Post object being considered for trashing support. - */ - $supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_trashable", $supports_trash, $post ); - - if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $post->ID ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - - // If we're forcing, then delete permanently. - if ( $force ) { - if ( $product->is_type( 'variable' ) ) { - foreach ( $product->get_children() as $child_id ) { - $child = wc_get_product( $child_id ); - if ( ! empty( $child ) ) { - $child->delete( true ); - } - } - } else { - // For other product types, if the product has children, remove the relationship. - foreach ( $product->get_children() as $child_id ) { - $child = wc_get_product( $child_id ); - if ( ! empty( $child ) ) { - $child->set_parent_id( 0 ); - $child->save(); - } - } - } - - $product->delete( true ); - $result = ! ( $product->get_id() > 0 ); - } else { - // If we don't support trashing for this type, error out. - if ( ! $supports_trash ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 501 ) ); - } - - // Otherwise, only trash if we haven't already. - if ( 'trash' === $post->post_status ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 410 ) ); - } - - // (Note that internally this falls through to `wp_delete_post` if - // the trash is disabled.) - $product->delete(); - $result = 'trash' === $product->get_status(); - } - - if ( ! $result ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 500 ) ); - } - - // Delete parent product transients. - if ( $parent_id = wp_get_post_parent_id( $id ) ) { - wc_delete_product_transients( $parent_id ); - } - - /** - * Fires after a single item is deleted or trashed via the REST API. - * - * @param object $post The deleted or trashed item. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( "woocommerce_rest_delete_{$this->post_type}", $post, $response, $request ); - - return $response; - } - - /** - * Get the Product's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $weight_unit = get_option( 'woocommerce_weight_unit' ); - $dimension_unit = get_option( 'woocommerce_dimension_unit' ); - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'slug' => array( - 'description' => __( 'Product slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'permalink' => array( - 'description' => __( 'Product URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the product was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the product was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Product type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'simple', - 'enum' => array_keys( wc_get_product_types() ), - 'context' => array( 'view', 'edit' ), - ), - 'status' => array( - 'description' => __( 'Product status (post status).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'publish', - 'enum' => array_merge( array_keys( get_post_statuses() ), array( 'future' ) ), - 'context' => array( 'view', 'edit' ), - ), - 'featured' => array( - 'description' => __( 'Featured product.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'catalog_visibility' => array( - 'description' => __( 'Catalog visibility.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'visible', - 'enum' => array( 'visible', 'catalog', 'search', 'hidden' ), - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'Product description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'short_description' => array( - 'description' => __( 'Product short description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sku' => array( - 'description' => __( 'Unique identifier.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'price' => array( - 'description' => __( 'Current product price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'regular_price' => array( - 'description' => __( 'Product regular price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sale_price' => array( - 'description' => __( 'Product sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from' => array( - 'description' => __( 'Start date of sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to' => array( - 'description' => __( 'End date of sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'price_html' => array( - 'description' => __( 'Price formatted in HTML.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'on_sale' => array( - 'description' => __( 'Shows if the product is on sale.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'purchasable' => array( - 'description' => __( 'Shows if the product can be bought.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_sales' => array( - 'description' => __( 'Amount of sales.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'virtual' => array( - 'description' => __( 'If the product is virtual.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloadable' => array( - 'description' => __( 'If the product is downloadable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloads' => array( - 'description' => __( 'List of downloadable files.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'File ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'download_limit' => array( - 'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'download_expiry' => array( - 'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'download_type' => array( - 'description' => __( 'Download type, this controls the schema on the front-end.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'standard', - 'enum' => array( 'standard' ), - 'context' => array( 'view', 'edit' ), - ), - 'external_url' => array( - 'description' => __( 'Product external URL. Only for external products.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'button_text' => array( - 'description' => __( 'Product external button text. Only for external products.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'taxable', - 'enum' => array( 'taxable', 'shipping', 'none' ), - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'manage_stock' => array( - 'description' => __( 'Stock management at product level.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'stock_quantity' => array( - 'description' => __( 'Stock quantity.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'in_stock' => array( - 'description' => __( 'Controls whether or not the product is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'backorders' => array( - 'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'no', - 'enum' => array( 'no', 'notify', 'yes' ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders_allowed' => array( - 'description' => __( 'Shows if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'backordered' => array( - 'description' => __( 'Shows if the product is on backordered.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sold_individually' => array( - 'description' => __( 'Allow one item to be bought in a single order.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'weight' => array( - /* translators: %s: weight unit */ - 'description' => sprintf( __( 'Product weight (%s).', 'woocommerce-rest-api' ), $weight_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'dimensions' => array( - 'description' => __( 'Product dimensions.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'length' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product length (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'width' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product width (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'height' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product height (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping_required' => array( - 'description' => __( 'Shows if the product need to be shipped.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_taxable' => array( - 'description' => __( 'Shows whether or not the product shipping is taxable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_class' => array( - 'description' => __( 'Shipping class slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'shipping_class_id' => array( - 'description' => __( 'Shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'reviews_allowed' => array( - 'description' => __( 'Allow reviews.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'average_rating' => array( - 'description' => __( 'Reviews average rating.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'rating_count' => array( - 'description' => __( 'Amount of reviews that the product have.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'related_ids' => array( - 'description' => __( 'List of related products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'upsell_ids' => array( - 'description' => __( 'List of upsell products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'cross_sell_ids' => array( - 'description' => __( 'List of cross-sell products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'parent_id' => array( - 'description' => __( 'Product parent ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'purchase_note' => array( - 'description' => __( 'Optional note to send the customer after purchase.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'categories' => array( - 'description' => __( 'List of categories.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Category ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Category name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'slug' => array( - 'description' => __( 'Category slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'tags' => array( - 'description' => __( 'List of tags.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tag ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Tag name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'slug' => array( - 'description' => __( 'Tag slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'images' => array( - 'description' => __( 'List of images.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'position' => array( - 'description' => __( 'Image position. 0 means that the image is featured.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'attributes' => array( - 'description' => __( 'List of attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'position' => array( - 'description' => __( 'Attribute position.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'visible' => array( - 'description' => __( "Define if the attribute is visible on the \"Additional information\" tab in the product's page.", 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'variation' => array( - 'description' => __( 'Define if the attribute can be used as variation.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'options' => array( - 'description' => __( 'List of available term names of the attribute.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'default_attributes' => array( - 'description' => __( 'Defaults variation attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'option' => array( - 'description' => __( 'Selected attribute term name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'variations' => array( - 'description' => __( 'List of variations.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Variation ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the variation was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the variation was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'permalink' => array( - 'description' => __( 'Variation URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sku' => array( - 'description' => __( 'Unique identifier.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'price' => array( - 'description' => __( 'Current variation price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'regular_price' => array( - 'description' => __( 'Variation regular price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sale_price' => array( - 'description' => __( 'Variation sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from' => array( - 'description' => __( 'Start date of sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to' => array( - 'description' => __( 'End date of sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'on_sale' => array( - 'description' => __( 'Shows if the variation is on sale.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'purchasable' => array( - 'description' => __( 'Shows if the variation can be bought.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'visible' => array( - 'description' => __( 'If the variation is visible.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - ), - 'virtual' => array( - 'description' => __( 'If the variation is virtual.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloadable' => array( - 'description' => __( 'If the variation is downloadable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloads' => array( - 'description' => __( 'List of downloadable files.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'File ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'download_limit' => array( - 'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => null, - 'context' => array( 'view', 'edit' ), - ), - 'download_expiry' => array( - 'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => null, - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'taxable', - 'enum' => array( 'taxable', 'shipping', 'none' ), - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'manage_stock' => array( - 'description' => __( 'Stock management at variation level.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'stock_quantity' => array( - 'description' => __( 'Stock quantity.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'in_stock' => array( - 'description' => __( 'Controls whether or not the variation is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'backorders' => array( - 'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'no', - 'enum' => array( 'no', 'notify', 'yes' ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders_allowed' => array( - 'description' => __( 'Shows if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'backordered' => array( - 'description' => __( 'Shows if the variation is on backordered.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'weight' => array( - /* translators: %s: weight unit */ - 'description' => sprintf( __( 'Variation weight (%s).', 'woocommerce-rest-api' ), $weight_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'dimensions' => array( - 'description' => __( 'Variation dimensions.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'length' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation length (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'width' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation width (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'height' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation height (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping_class' => array( - 'description' => __( 'Shipping class slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'shipping_class_id' => array( - 'description' => __( 'Shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'image' => array( - 'description' => __( 'Variation image data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'position' => array( - 'description' => __( 'Image position. 0 means that the image is featured.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'attributes' => array( - 'description' => __( 'List of attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'option' => array( - 'description' => __( 'Selected attribute term name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ), - ), - 'grouped_products' => array( - 'description' => __( 'List of grouped products ID.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort products.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['slug'] = array( - 'description' => __( 'Limit result set to products with a specific slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['status'] = array( - 'default' => 'any', - 'description' => __( 'Limit result set to products assigned a specific status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_merge( array( 'any', 'future' ), array_keys( get_post_statuses() ) ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['type'] = array( - 'description' => __( 'Limit result set to products assigned a specific type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_keys( wc_get_product_types() ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['category'] = array( - 'description' => __( 'Limit result set to products assigned a specific category ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['tag'] = array( - 'description' => __( 'Limit result set to products assigned a specific tag ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['shipping_class'] = array( - 'description' => __( 'Limit result set to products assigned a specific shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['attribute'] = array( - 'description' => __( 'Limit result set to products with a specific attribute.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['attribute_term'] = array( - 'description' => __( 'Limit result set to products with a specific attribute term ID (required an assigned attribute).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['sku'] = array( - 'description' => __( 'Limit result set to products with a specific SKU.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version1/class-wc-rest-report-sales-v1-controller.php b/src/Controllers/Version1/class-wc-rest-report-sales-v1-controller.php deleted file mode 100644 index 57bd5da4490..00000000000 --- a/src/Controllers/Version1/class-wc-rest-report-sales-v1-controller.php +++ /dev/null @@ -1,397 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read report. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'reports', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get sales reports. - * - * @param WP_REST_Request $request - * @return array|WP_Error - */ - public function get_items( $request ) { - $data = array(); - $item = $this->prepare_item_for_response( null, $request ); - $data[] = $this->prepare_response_for_collection( $item ); - - return rest_ensure_response( $data ); - } - - /** - * Prepare a report sales object for serialization. - * - * @param null $_ - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $_, $request ) { - // Set date filtering. - $filter = array( - 'period' => $request['period'], - 'date_min' => $request['date_min'], - 'date_max' => $request['date_max'], - ); - $this->setup_report( $filter ); - - // New customers. - $users_query = new WP_User_Query( - array( - 'fields' => array( 'user_registered' ), - 'role' => 'customer', - ) - ); - - $customers = $users_query->get_results(); - - foreach ( $customers as $key => $customer ) { - if ( strtotime( $customer->user_registered ) < $this->report->start_date || strtotime( $customer->user_registered ) > $this->report->end_date ) { - unset( $customers[ $key ] ); - } - } - - $total_customers = count( $customers ); - $report_data = $this->report->get_report_data(); - $period_totals = array(); - - // Setup period totals by ensuring each period in the interval has data. - for ( $i = 0; $i <= $this->report->chart_interval; $i++ ) { - - switch ( $this->report->chart_groupby ) { - case 'day' : - $time = date( 'Y-m-d', strtotime( "+{$i} DAY", $this->report->start_date ) ); - break; - default : - $time = date( 'Y-m', strtotime( "+{$i} MONTH", $this->report->start_date ) ); - break; - } - - // Set the customer signups for each period. - $customer_count = 0; - foreach ( $customers as $customer ) { - if ( date( ( 'day' == $this->report->chart_groupby ) ? 'Y-m-d' : 'Y-m', strtotime( $customer->user_registered ) ) == $time ) { - $customer_count++; - } - } - - $period_totals[ $time ] = array( - 'sales' => wc_format_decimal( 0.00, 2 ), - 'orders' => 0, - 'items' => 0, - 'tax' => wc_format_decimal( 0.00, 2 ), - 'shipping' => wc_format_decimal( 0.00, 2 ), - 'discount' => wc_format_decimal( 0.00, 2 ), - 'customers' => $customer_count, - ); - } - - // add total sales, total order count, total tax and total shipping for each period - foreach ( $report_data->orders as $order ) { - $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) ); - - if ( ! isset( $period_totals[ $time ] ) ) { - continue; - } - - $period_totals[ $time ]['sales'] = wc_format_decimal( $order->total_sales, 2 ); - $period_totals[ $time ]['tax'] = wc_format_decimal( $order->total_tax + $order->total_shipping_tax, 2 ); - $period_totals[ $time ]['shipping'] = wc_format_decimal( $order->total_shipping, 2 ); - } - - foreach ( $report_data->order_counts as $order ) { - $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) ); - - if ( ! isset( $period_totals[ $time ] ) ) { - continue; - } - - $period_totals[ $time ]['orders'] = (int) $order->count; - } - - // Add total order items for each period. - foreach ( $report_data->order_items as $order_item ) { - $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $order_item->post_date ) ) : date( 'Y-m', strtotime( $order_item->post_date ) ); - - if ( ! isset( $period_totals[ $time ] ) ) { - continue; - } - - $period_totals[ $time ]['items'] = (int) $order_item->order_item_count; - } - - // Add total discount for each period. - foreach ( $report_data->coupons as $discount ) { - $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $discount->post_date ) ) : date( 'Y-m', strtotime( $discount->post_date ) ); - - if ( ! isset( $period_totals[ $time ] ) ) { - continue; - } - - $period_totals[ $time ]['discount'] = wc_format_decimal( $discount->discount_amount, 2 ); - } - - $sales_data = array( - 'total_sales' => $report_data->total_sales, - 'net_sales' => $report_data->net_sales, - 'average_sales' => $report_data->average_sales, - 'total_orders' => $report_data->total_orders, - 'total_items' => $report_data->total_items, - 'total_tax' => wc_format_decimal( $report_data->total_tax + $report_data->total_shipping_tax, 2 ), - 'total_shipping' => $report_data->total_shipping, - 'total_refunds' => $report_data->total_refunds, - 'total_discount' => $report_data->total_coupons, - 'totals_grouped_by' => $this->report->chart_groupby, - 'totals' => $period_totals, - 'total_customers' => $total_customers, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $sales_data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - $response->add_links( array( - 'about' => array( - 'href' => rest_url( sprintf( '%s/reports', $this->namespace ) ), - ), - ) ); - - /** - * Filter a report sales returned from the API. - * - * Allows modification of the report sales data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param stdClass $data The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report_sales', $response, (object) $sales_data, $request ); - } - - /** - * Setup the report object and parse any date filtering. - * - * @param array $filter date filtering - */ - protected function setup_report( $filter ) { - include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' ); - include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-report-sales-by-date.php' ); - - $this->report = new WC_Report_Sales_By_Date(); - - if ( empty( $filter['period'] ) ) { - // Custom date range. - $filter['period'] = 'custom'; - - if ( ! empty( $filter['date_min'] ) || ! empty( $filter['date_max'] ) ) { - - // Overwrite _GET to make use of WC_Admin_Report::calculate_current_range() for custom date ranges. - $_GET['start_date'] = $filter['date_min']; - $_GET['end_date'] = isset( $filter['date_max'] ) ? $filter['date_max'] : null; - - } else { - - // Default custom range to today. - $_GET['start_date'] = $_GET['end_date'] = date( 'Y-m-d', current_time( 'timestamp' ) ); - } - } else { - $filter['period'] = empty( $filter['period'] ) ? 'week' : $filter['period']; - - // Change "week" period to "7day". - if ( 'week' === $filter['period'] ) { - $filter['period'] = '7day'; - } - } - - $this->report->calculate_current_range( $filter['period'] ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'sales_report', - 'type' => 'object', - 'properties' => array( - 'total_sales' => array( - 'description' => __( 'Gross sales in the period.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'net_sales' => array( - 'description' => __( 'Net sales in the period.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'average_sales' => array( - 'description' => __( 'Average net daily sales.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total_orders' => array( - 'description' => __( 'Total of orders placed.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total_items' => array( - 'description' => __( 'Total of items purchased.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total_tax' => array( - 'description' => __( 'Total charged for taxes.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total_shipping' => array( - 'description' => __( 'Total charged for shipping.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total_refunds' => array( - 'description' => __( 'Total of refunded orders.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total_discount' => array( - 'description' => __( 'Total of coupons used.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'totals_grouped_by' => array( - 'description' => __( 'Group type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'totals' => array( - 'description' => __( 'Totals.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'array', - ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - 'period' => array( - 'description' => __( 'Report period.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array( 'week', 'month', 'last_month', 'year' ), - 'validate_callback' => 'rest_validate_request_arg', - 'sanitize_callback' => 'sanitize_text_field', - ), - 'date_min' => array( - /* translators: %s: date format */ - 'description' => sprintf( __( 'Return sales for a specific start date, the date need to be in the %s format.', 'woocommerce-rest-api' ), 'YYYY-MM-DD' ), - 'type' => 'string', - 'format' => 'date', - 'validate_callback' => 'wc_rest_validate_reports_request_arg', - 'sanitize_callback' => 'sanitize_text_field', - ), - 'date_max' => array( - /* translators: %s: date format */ - 'description' => sprintf( __( 'Return sales for a specific end date, the date need to be in the %s format.', 'woocommerce-rest-api' ), 'YYYY-MM-DD' ), - 'type' => 'string', - 'format' => 'date', - 'validate_callback' => 'wc_rest_validate_reports_request_arg', - 'sanitize_callback' => 'sanitize_text_field', - ), - ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-report-top-sellers-v1-controller.php b/src/Controllers/Version1/class-wc-rest-report-top-sellers-v1-controller.php deleted file mode 100644 index 76d0aa9d2ae..00000000000 --- a/src/Controllers/Version1/class-wc-rest-report-top-sellers-v1-controller.php +++ /dev/null @@ -1,174 +0,0 @@ - $request['period'], - 'date_min' => $request['date_min'], - 'date_max' => $request['date_max'], - ); - $this->setup_report( $filter ); - - $report_data = $this->report->get_order_report_data( array( - 'data' => array( - '_product_id' => array( - 'type' => 'order_item_meta', - 'order_item_type' => 'line_item', - 'function' => '', - 'name' => 'product_id', - ), - '_qty' => array( - 'type' => 'order_item_meta', - 'order_item_type' => 'line_item', - 'function' => 'SUM', - 'name' => 'order_item_qty', - ), - ), - 'order_by' => 'order_item_qty DESC', - 'group_by' => 'product_id', - 'limit' => isset( $filter['limit'] ) ? absint( $filter['limit'] ) : 12, - 'query_type' => 'get_results', - 'filter_range' => true, - ) ); - - $top_sellers = array(); - - foreach ( $report_data as $item ) { - $product = wc_get_product( $item->product_id ); - - if ( $product ) { - $top_sellers[] = array( - 'name' => $product->get_name(), - 'product_id' => (int) $item->product_id, - 'quantity' => wc_stock_amount( $item->order_item_qty ), - ); - } - } - - $data = array(); - foreach ( $top_sellers as $top_seller ) { - $item = $this->prepare_item_for_response( (object) $top_seller, $request ); - $data[] = $this->prepare_response_for_collection( $item ); - } - - return rest_ensure_response( $data ); - } - - /** - * Prepare a report sales object for serialization. - * - * @param stdClass $top_seller - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $top_seller, $request ) { - $data = array( - 'name' => $top_seller->name, - 'product_id' => $top_seller->product_id, - 'quantity' => $top_seller->quantity, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - $response->add_links( array( - 'about' => array( - 'href' => rest_url( sprintf( '%s/reports', $this->namespace ) ), - ), - 'product' => array( - 'href' => rest_url( sprintf( '/%s/products/%s', $this->namespace, $top_seller->product_id ) ), - ), - ) ); - - /** - * Filter a report top sellers returned from the API. - * - * Allows modification of the report top sellers data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param stdClass $top_seller The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report_top_sellers', $response, $top_seller, $request ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'top_sellers_report', - 'type' => 'object', - 'properties' => array( - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Product ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'quantity' => array( - 'description' => __( 'Total number of purchases.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-reports-v1-controller.php b/src/Controllers/Version1/class-wc-rest-reports-v1-controller.php deleted file mode 100644 index 1f1463ae2b5..00000000000 --- a/src/Controllers/Version1/class-wc-rest-reports-v1-controller.php +++ /dev/null @@ -1,184 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read reports. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'reports', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get reports list. - * - * @since 3.5.0 - * @return array - */ - protected function get_reports() { - return array( - array( - 'slug' => 'sales', - 'description' => __( 'List of sales reports.', 'woocommerce-rest-api' ), - ), - array( - 'slug' => 'top_sellers', - 'description' => __( 'List of top sellers products.', 'woocommerce-rest-api' ), - ), - ); - } - - /** - * Get all reports. - * - * @param WP_REST_Request $request - * @return array|WP_Error - */ - public function get_items( $request ) { - $data = array(); - $reports = $this->get_reports(); - - foreach ( $reports as $report ) { - $item = $this->prepare_item_for_response( (object) $report, $request ); - $data[] = $this->prepare_response_for_collection( $item ); - } - - return rest_ensure_response( $data ); - } - - /** - * Prepare a report object for serialization. - * - * @param stdClass $report Report data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $report, $request ) { - $data = array( - 'slug' => $report->slug, - 'description' => $report->description, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - $response->add_links( array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $report->slug ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), - ), - ) ); - - /** - * Filter a report returned from the API. - * - * Allows modification of the report data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $report The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report', $response, $report, $request ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'report', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'A human-readable description of the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-tax-classes-v1-controller.php b/src/Controllers/Version1/class-wc-rest-tax-classes-v1-controller.php deleted file mode 100644 index 5a7206fb6a6..00000000000 --- a/src/Controllers/Version1/class-wc-rest-tax-classes-v1-controller.php +++ /dev/null @@ -1,321 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P\w[\w\s\-]*)', array( - 'args' => array( - 'slug' => array( - 'description' => __( 'Unique slug for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read tax classes. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access create tax classes. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access delete a tax. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function delete_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'delete' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get all tax classes. - * - * @param WP_REST_Request $request - * @return array - */ - public function get_items( $request ) { - $tax_classes = array(); - - // Add standard class. - $tax_classes[] = array( - 'slug' => 'standard', - 'name' => __( 'Standard rate', 'woocommerce-rest-api' ), - ); - - $classes = WC_Tax::get_tax_classes(); - - foreach ( $classes as $class ) { - $tax_classes[] = array( - 'slug' => sanitize_title( $class ), - 'name' => $class, - ); - } - - $data = array(); - foreach ( $tax_classes as $tax_class ) { - $class = $this->prepare_item_for_response( $tax_class, $request ); - $class = $this->prepare_response_for_collection( $class ); - $data[] = $class; - } - - return rest_ensure_response( $data ); - } - - /** - * Create a single tax class. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - $tax_class = WC_Tax::create_tax_class( $request['name'] ); - - if ( is_wp_error( $tax_class ) ) { - return new WP_Error( 'woocommerce_rest_' . $tax_class->get_error_code(), $tax_class->get_error_message(), array( 'status' => 400 ) ); - } - - $this->update_additional_fields_for_object( $tax_class, $request ); - - /** - * Fires after a tax class is created or updated via the REST API. - * - * @param stdClass $tax_class Data used to create the tax class. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating tax class, false when updating tax class. - */ - do_action( 'woocommerce_rest_insert_tax_class', (object) $tax_class, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $tax_class, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $tax_class['slug'] ) ) ); - - return $response; - } - - /** - * Delete a single tax class. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function delete_item( $request ) { - global $wpdb; - - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out. - if ( ! $force ) { - return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Taxes do not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - $tax_class = WC_Tax::get_tax_class_by( 'slug', sanitize_title( $request['slug'] ) ); - $deleted = WC_Tax::delete_tax_class_by( 'slug', sanitize_title( $request['slug'] ) ); - - if ( ! $deleted ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - if ( is_wp_error( $deleted ) ) { - return new WP_Error( 'woocommerce_rest_' . $deleted->get_error_code(), $deleted->get_error_message(), array( 'status' => 400 ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $tax_class, $request ); - - /** - * Fires after a tax class is deleted via the REST API. - * - * @param stdClass $tax_class The tax data. - * @param WP_REST_Response $response The response returned from the API. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'woocommerce_rest_delete_tax', (object) $tax_class, $response, $request ); - - return $response; - } - - /** - * Prepare a single tax class output for response. - * - * @param array $tax_class Tax class data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $tax_class, $request ) { - $data = $tax_class; - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links() ); - - /** - * Filter tax object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param stdClass $tax_class Tax object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_tax', $response, (object) $tax_class, $request ); - } - - /** - * Prepare links for the request. - * - * @return array Links for the given tax class. - */ - protected function prepare_links() { - $links = array( - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the Tax Classes schema, conforming to JSON Schema - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'tax_class', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Tax class name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'required' => true, - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-taxes-v1-controller.php b/src/Controllers/Version1/class-wc-rest-taxes-v1-controller.php deleted file mode 100644 index ae81985a3d2..00000000000 --- a/src/Controllers/Version1/class-wc-rest-taxes-v1-controller.php +++ /dev/null @@ -1,709 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read taxes. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access create taxes. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a tax. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access update a tax. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function update_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access delete a tax. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function delete_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'delete' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access batch create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function batch_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'batch' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get all taxes. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - global $wpdb; - - $prepared_args = array(); - $prepared_args['order'] = $request['order']; - $prepared_args['number'] = $request['per_page']; - if ( ! empty( $request['offset'] ) ) { - $prepared_args['offset'] = $request['offset']; - } else { - $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; - } - $orderby_possibles = array( - 'id' => 'tax_rate_id', - 'order' => 'tax_rate_order', - ); - $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ]; - $prepared_args['class'] = $request['class']; - - /** - * Filter arguments, before passing to $wpdb->get_results(), when querying taxes via the REST API. - * - * @param array $prepared_args Array of arguments for $wpdb->get_results(). - * @param WP_REST_Request $request The current request. - */ - $prepared_args = apply_filters( 'woocommerce_rest_tax_query', $prepared_args, $request ); - - $query = " - SELECT * - FROM {$wpdb->prefix}woocommerce_tax_rates - WHERE 1 = 1 - "; - - // Filter by tax class. - if ( ! empty( $prepared_args['class'] ) ) { - $class = 'standard' !== $prepared_args['class'] ? sanitize_title( $prepared_args['class'] ) : ''; - $query .= " AND tax_rate_class = '$class'"; - } - - // Order tax rates. - $order_by = sprintf( ' ORDER BY %s', sanitize_key( $prepared_args['orderby'] ) ); - - // Pagination. - $pagination = sprintf( ' LIMIT %d, %d', $prepared_args['offset'], $prepared_args['number'] ); - - // Query taxes. - $results = $wpdb->get_results( $query . $order_by . $pagination ); - - $taxes = array(); - foreach ( $results as $tax ) { - $data = $this->prepare_item_for_response( $tax, $request ); - $taxes[] = $this->prepare_response_for_collection( $data ); - } - - $response = rest_ensure_response( $taxes ); - - // Store pagination values for headers then unset for count query. - $per_page = (int) $prepared_args['number']; - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); - - // Query only for ids. - $wpdb->get_results( str_replace( 'SELECT *', 'SELECT tax_rate_id', $query ) ); - - // Calculate totals. - $total_taxes = (int) $wpdb->num_rows; - $response->header( 'X-WP-Total', (int) $total_taxes ); - $max_pages = ceil( $total_taxes / $per_page ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } - - return $response; - } - - /** - * Take tax data from the request and return the updated or newly created rate. - * - * @param WP_REST_Request $request Full details about the request. - * @param stdClass|null $current Existing tax object. - * @return object - */ - protected function create_or_update_tax( $request, $current = null ) { - $id = absint( isset( $request['id'] ) ? $request['id'] : 0 ); - $data = array(); - $fields = array( - 'tax_rate_country', - 'tax_rate_state', - 'tax_rate', - 'tax_rate_name', - 'tax_rate_priority', - 'tax_rate_compound', - 'tax_rate_shipping', - 'tax_rate_order', - 'tax_rate_class', - ); - - foreach ( $fields as $field ) { - // Keys via API differ from the stored names returned by _get_tax_rate. - $key = 'tax_rate' === $field ? 'rate' : str_replace( 'tax_rate_', '', $field ); - - // Remove data that was not posted. - if ( ! isset( $request[ $key ] ) ) { - continue; - } - - // Test new data against current data. - if ( $current && $current->$field === $request[ $key ] ) { - continue; - } - - // Add to data array. - switch ( $key ) { - case 'tax_rate_priority' : - case 'tax_rate_compound' : - case 'tax_rate_shipping' : - case 'tax_rate_order' : - $data[ $field ] = absint( $request[ $key ] ); - break; - case 'tax_rate_class' : - $data[ $field ] = 'standard' !== $request['tax_rate_class'] ? $request['tax_rate_class'] : ''; - break; - default : - $data[ $field ] = wc_clean( $request[ $key ] ); - break; - } - } - - if ( $id ) { - WC_Tax::_update_tax_rate( $id, $data ); - } else { - $id = WC_Tax::_insert_tax_rate( $data ); - } - - // Add locales. - if ( ! empty( $request['postcode'] ) ) { - WC_Tax::_update_tax_rate_postcodes( $id, wc_clean( $request['postcode'] ) ); - } - if ( ! empty( $request['city'] ) ) { - WC_Tax::_update_tax_rate_cities( $id, wc_clean( $request['city'] ) ); - } - - return WC_Tax::_get_tax_rate( $id, OBJECT ); - } - - /** - * Create a single tax. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - return new WP_Error( 'woocommerce_rest_tax_exists', __( 'Cannot create existing resource.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $tax = $this->create_or_update_tax( $request ); - - $this->update_additional_fields_for_object( $tax, $request ); - - /** - * Fires after a tax is created or updated via the REST API. - * - * @param stdClass $tax Data used to create the tax. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating tax, false when updating tax. - */ - do_action( 'woocommerce_rest_insert_tax', $tax, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $tax, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $tax->tax_rate_id ) ) ); - - return $response; - } - - /** - * Get a single tax. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $id = (int) $request['id']; - $tax_obj = WC_Tax::_get_tax_rate( $id, OBJECT ); - - if ( empty( $id ) || empty( $tax_obj ) ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $tax = $this->prepare_item_for_response( $tax_obj, $request ); - $response = rest_ensure_response( $tax ); - - return $response; - } - - /** - * Update a single tax. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $id = (int) $request['id']; - $tax_obj = WC_Tax::_get_tax_rate( $id, OBJECT ); - - if ( empty( $id ) || empty( $tax_obj ) ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $tax = $this->create_or_update_tax( $request, $tax_obj ); - - $this->update_additional_fields_for_object( $tax, $request ); - - /** - * Fires after a tax is created or updated via the REST API. - * - * @param stdClass $tax Data used to create the tax. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating tax, false when updating tax. - */ - do_action( 'woocommerce_rest_insert_tax', $tax, $request, false ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $tax, $request ); - $response = rest_ensure_response( $response ); - - return $response; - } - - /** - * Delete a single tax. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function delete_item( $request ) { - global $wpdb; - - $id = (int) $request['id']; - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out. - if ( ! $force ) { - return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Taxes do not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - $tax = WC_Tax::_get_tax_rate( $id, OBJECT ); - - if ( empty( $id ) || empty( $tax ) ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $tax, $request ); - - WC_Tax::_delete_tax_rate( $id ); - - if ( 0 === $wpdb->rows_affected ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a tax is deleted via the REST API. - * - * @param stdClass $tax The tax data. - * @param WP_REST_Response $response The response returned from the API. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'woocommerce_rest_delete_tax', $tax, $response, $request ); - - return $response; - } - - /** - * Prepare a single tax output for response. - * - * @param stdClass $tax Tax object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $tax, $request ) { - global $wpdb; - - $id = (int) $tax->tax_rate_id; - $data = array( - 'id' => $id, - 'country' => $tax->tax_rate_country, - 'state' => $tax->tax_rate_state, - 'postcode' => '', - 'city' => '', - 'rate' => $tax->tax_rate, - 'name' => $tax->tax_rate_name, - 'priority' => (int) $tax->tax_rate_priority, - 'compound' => (bool) $tax->tax_rate_compound, - 'shipping' => (bool) $tax->tax_rate_shipping, - 'order' => (int) $tax->tax_rate_order, - 'class' => $tax->tax_rate_class ? $tax->tax_rate_class : 'standard', - ); - - // Get locales from a tax rate. - $locales = $wpdb->get_results( $wpdb->prepare( " - SELECT location_code, location_type - FROM {$wpdb->prefix}woocommerce_tax_rate_locations - WHERE tax_rate_id = %d - ", $id ) ); - - if ( ! is_wp_error( $tax ) && ! is_null( $tax ) ) { - foreach ( $locales as $locale ) { - $data[ $locale->location_type ] = $locale->location_code; - } - } - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $tax ) ); - - /** - * Filter tax object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param stdClass $tax Tax object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_tax', $response, $tax, $request ); - } - - /** - * Prepare links for the request. - * - * @param stdClass $tax Tax object. - * @return array Links for the given tax. - */ - protected function prepare_links( $tax ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $tax->tax_rate_id ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the Taxes schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'tax', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'country' => array( - 'description' => __( 'Country ISO 3166 code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'State code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postcode / ZIP.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'rate' => array( - 'description' => __( 'Tax rate.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Tax rate name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'priority' => array( - 'description' => __( 'Tax priority.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => 1, - 'context' => array( 'view', 'edit' ), - ), - 'compound' => array( - 'description' => __( 'Whether or not this is a compound rate.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'shipping' => array( - 'description' => __( 'Whether or not this tax rate also gets applied to shipping.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'order' => array( - 'description' => __( 'Indicates the order that will appear in queries.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'class' => array( - 'description' => __( 'Tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'standard', - 'enum' => array_merge( array( 'standard' ), WC_Tax::get_tax_class_slugs() ), - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = array(); - $params['context'] = $this->get_context_param(); - $params['context']['default'] = 'view'; - - $params['page'] = array( - 'description' => __( 'Current page of the collection.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => 1, - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - 'minimum' => 1, - ); - $params['per_page'] = array( - 'description' => __( 'Maximum number of items to be returned in result set.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => 10, - 'minimum' => 1, - 'maximum' => 100, - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['offset'] = array( - 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['order'] = array( - 'default' => 'asc', - 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ), - 'enum' => array( 'asc', 'desc' ), - 'sanitize_callback' => 'sanitize_key', - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['orderby'] = array( - 'default' => 'order', - 'description' => __( 'Sort collection by object attribute.', 'woocommerce-rest-api' ), - 'enum' => array( - 'id', - 'order', - ), - 'sanitize_callback' => 'sanitize_key', - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['class'] = array( - 'description' => __( 'Sort by tax class.', 'woocommerce-rest-api' ), - 'enum' => array_merge( array( 'standard' ), WC_Tax::get_tax_class_slugs() ), - 'sanitize_callback' => 'sanitize_title', - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version1/class-wc-rest-webhook-deliveries-v1-controller.php b/src/Controllers/Version1/class-wc-rest-webhook-deliveries-v1-controller.php deleted file mode 100644 index adbd3f62b2f..00000000000 --- a/src/Controllers/Version1/class-wc-rest-webhook-deliveries-v1-controller.php +++ /dev/null @@ -1,314 +0,0 @@ -/deliveries endpoint. - * - * @author WooThemes - * @category API - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * REST API Webhook Deliveries controller class. - * - * @deprecated 3.3.0 Webhooks deliveries logs now uses logging system. - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Controller - */ -class WC_REST_Webhook_Deliveries_V1_Controller extends WC_REST_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v1'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'webhooks/(?P[\d]+)/deliveries'; - - /** - * Register the routes for webhook deliveries. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'webhook_id' => array( - 'description' => __( 'Unique identifier for the webhook.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'webhook_id' => array( - 'description' => __( 'Unique identifier for the webhook.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read taxes. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a tax. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get all webhook deliveries. - * - * @param WP_REST_Request $request - * - * @return array|WP_Error - */ - public function get_items( $request ) { - $webhook = wc_get_webhook( (int) $request['webhook_id'] ); - - if ( empty( $webhook ) || is_null( $webhook ) ) { - return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $logs = array(); - $data = array(); - foreach ( $logs as $log ) { - $delivery = $this->prepare_item_for_response( (object) $log, $request ); - $delivery = $this->prepare_response_for_collection( $delivery ); - $data[] = $delivery; - } - - return rest_ensure_response( $data ); - } - - /** - * Get a single webhook delivery. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $id = (int) $request['id']; - $webhook = wc_get_webhook( (int) $request['webhook_id'] ); - - if ( empty( $webhook ) || is_null( $webhook ) ) { - return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $log = array(); - - if ( empty( $id ) || empty( $log ) ) { - return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $delivery = $this->prepare_item_for_response( (object) $log, $request ); - $response = rest_ensure_response( $delivery ); - - return $response; - } - - /** - * Prepare a single webhook delivery output for response. - * - * @param stdClass $log Delivery log object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $log, $request ) { - $data = (array) $log; - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $log ) ); - - /** - * Filter webhook delivery object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param stdClass $log Delivery log object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_webhook_delivery', $response, $log, $request ); - } - - /** - * Prepare links for the request. - * - * @param stdClass $log Delivery log object. - * @return array Links for the given webhook delivery. - */ - protected function prepare_links( $log ) { - $webhook_id = (int) $log->request_headers['X-WC-Webhook-ID']; - $base = str_replace( '(?P[\d]+)', $webhook_id, $this->rest_base ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $log->id ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - 'up' => array( - 'href' => rest_url( sprintf( '/%s/webhooks/%d', $this->namespace, $webhook_id ) ), - ), - ); - - return $links; - } - - /** - * Get the Webhook's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'webhook_delivery', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'duration' => array( - 'description' => __( 'The delivery duration, in seconds.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'summary' => array( - 'description' => __( 'A friendly summary of the response including the HTTP response code, message, and body.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'request_url' => array( - 'description' => __( 'The URL where the webhook was delivered.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'request_headers' => array( - 'description' => __( 'Request headers.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'request_body' => array( - 'description' => __( 'Request body.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'response_code' => array( - 'description' => __( 'The HTTP response code from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'response_message' => array( - 'description' => __( 'The HTTP response message from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'response_headers' => array( - 'description' => __( 'Array of the response headers from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'response_body' => array( - 'description' => __( 'The response body from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the webhook delivery was logged, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } -} diff --git a/src/Controllers/Version1/class-wc-rest-webhooks-v1-controller.php b/src/Controllers/Version1/class-wc-rest-webhooks-v1-controller.php deleted file mode 100644 index d9f6c611c8a..00000000000 --- a/src/Controllers/Version1/class-wc-rest-webhooks-v1-controller.php +++ /dev/null @@ -1,763 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'topic' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Webhook topic.', 'woocommerce-rest-api' ), - ), - 'delivery_url' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Webhook delivery URL.', 'woocommerce-rest-api' ), - ), - ) ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - - register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Check whether a given request has permission to read webhooks. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access create webhooks. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a webhook. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access update a webhook. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function update_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access delete a webhook. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function delete_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'delete' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access batch create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error - */ - public function batch_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'webhooks', 'batch' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get the default REST API version. - * - * @since 3.0.0 - * @return string - */ - protected function get_default_api_version() { - return 'wp_api_v1'; - } - - /** - * Get all webhooks. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $args = array(); - $args['order'] = $request['order']; - $args['orderby'] = $request['orderby']; - $args['status'] = 'all' === $request['status'] ? '' : $request['status']; - $args['include'] = implode( ',', $request['include'] ); - $args['exclude'] = implode( ',', $request['exclude'] ); - $args['limit'] = $request['per_page']; - $args['search'] = $request['search']; - $args['before'] = $request['before']; - $args['after'] = $request['after']; - - if ( empty( $request['offset'] ) ) { - $args['offset'] = 1 < $request['page'] ? ( $request['page'] - 1 ) * $args['limit'] : 0; - } - - /** - * Filter arguments, before passing to WC_Webhook_Data_Store->search_webhooks, when querying webhooks via the REST API. - * - * @param array $args Array of arguments for $wpdb->get_results(). - * @param WP_REST_Request $request The current request. - */ - $prepared_args = apply_filters( 'woocommerce_rest_webhook_query', $args, $request ); - unset( $prepared_args['page'] ); - $prepared_args['paginate'] = true; - - // Get the webhooks. - $webhooks = array(); - $data_store = WC_Data_Store::load( 'webhook' ); - $results = $data_store->search_webhooks( $prepared_args ); - $webhook_ids = $results->webhooks; - - foreach ( $webhook_ids as $webhook_id ) { - $data = $this->prepare_item_for_response( $webhook_id, $request ); - $webhooks[] = $this->prepare_response_for_collection( $data ); - } - - $response = rest_ensure_response( $webhooks ); - $per_page = (int) $prepared_args['limit']; - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); - $total_webhooks = $results->total; - $max_pages = $results->max_num_pages; - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); - - $response->header( 'X-WP-Total', $total_webhooks ); - $response->header( 'X-WP-TotalPages', $max_pages ); - - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } - - return $response; - } - - /** - * Get a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $id = (int) $request['id']; - - if ( empty( $id ) ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $data = $this->prepare_item_for_response( $id, $request ); - $response = rest_ensure_response( $data ); - - return $response; - } - - /** - * Create a single webhook. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - // Validate topic. - if ( empty( $request['topic'] ) || ! wc_is_webhook_valid_topic( strtolower( $request['topic'] ) ) ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_topic", __( 'Webhook topic is required and must be valid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - // Validate delivery URL. - if ( empty( $request['delivery_url'] ) || ! wc_is_valid_url( $request['delivery_url'] ) ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_delivery_url", __( 'Webhook delivery URL must be a valid URL starting with http:// or https://.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $post = $this->prepare_item_for_database( $request ); - if ( is_wp_error( $post ) ) { - return $post; - } - - $webhook = new WC_Webhook(); - $webhook->set_name( $post->post_title ); - $webhook->set_user_id( $post->post_author ); - $webhook->set_status( 'publish' === $post->post_status ? 'active' : 'disabled' ); - $webhook->set_topic( $request['topic'] ); - $webhook->set_delivery_url( $request['delivery_url'] ); - $webhook->set_secret( ! empty( $request['secret'] ) ? $request['secret'] : wp_generate_password( 50, true, true ) ); - $webhook->set_api_version( $this->get_default_api_version() ); - $webhook->save(); - - $this->update_additional_fields_for_object( $webhook, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WC_Webhook $webhook Webhook data. - * @param WP_REST_Request $request Request object. - * @param bool $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_webhook_object", $webhook, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $webhook->get_id(), $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $webhook->get_id() ) ) ); - - // Send ping. - $webhook->deliver_ping(); - - return $response; - } - - /** - * Update a single webhook. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $id = (int) $request['id']; - $webhook = wc_get_webhook( $id ); - - if ( empty( $webhook ) || is_null( $webhook ) ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - // Update topic. - if ( ! empty( $request['topic'] ) ) { - if ( wc_is_webhook_valid_topic( strtolower( $request['topic'] ) ) ) { - $webhook->set_topic( $request['topic'] ); - } else { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_topic", __( 'Webhook topic must be valid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - } - - // Update delivery URL. - if ( ! empty( $request['delivery_url'] ) ) { - if ( wc_is_valid_url( $request['delivery_url'] ) ) { - $webhook->set_delivery_url( $request['delivery_url'] ); - } else { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_delivery_url", __( 'Webhook delivery URL must be a valid URL starting with http:// or https://.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - } - - // Update secret. - if ( ! empty( $request['secret'] ) ) { - $webhook->set_secret( $request['secret'] ); - } - - // Update status. - if ( ! empty( $request['status'] ) ) { - if ( wc_is_webhook_valid_status( strtolower( $request['status'] ) ) ) { - $webhook->set_status( $request['status'] ); - } else { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_status", __( 'Webhook status must be valid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - } - - $post = $this->prepare_item_for_database( $request ); - if ( is_wp_error( $post ) ) { - return $post; - } - - if ( isset( $post->post_title ) ) { - $webhook->set_name( $post->post_title ); - } - - $webhook->save(); - - $this->update_additional_fields_for_object( $webhook, $request ); - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WC_Webhook $webhook Webhook data. - * @param WP_REST_Request $request Request object. - * @param bool $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_webhook_object", $webhook, $request, false ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $webhook->get_id(), $request ); - - return rest_ensure_response( $response ); - } - - /** - * Delete a single webhook. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $id = (int) $request['id']; - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out. - if ( ! $force ) { - return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Webhooks do not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - $webhook = wc_get_webhook( $id ); - - if ( empty( $webhook ) || is_null( $webhook ) ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $webhook, $request ); - $result = $webhook->delete( true ); - - if ( ! $result ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 500 ) ); - } - - /** - * Fires after a single item is deleted or trashed via the REST API. - * - * @param WC_Webhook $webhook The deleted or trashed item. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( "woocommerce_rest_delete_webhook_object", $webhook, $response, $request ); - - return $response; - } - - /** - * Prepare a single webhook for create or update. - * - * @param WP_REST_Request $request Request object. - * @return WP_Error|stdClass $data Post object. - */ - protected function prepare_item_for_database( $request ) { - $data = new stdClass; - - // Post ID. - if ( isset( $request['id'] ) ) { - $data->ID = absint( $request['id'] ); - } - - // Validate required POST fields. - if ( 'POST' === $request->get_method() && empty( $data->ID ) ) { - $data->post_title = ! empty( $request['name'] ) ? $request['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce-rest-api' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce-rest-api' ) ) ); // @codingStandardsIgnoreLine - - // Post author. - $data->post_author = get_current_user_id(); - - // Post password. - $data->post_password = 'webhook_' . wp_generate_password(); - - // Post status. - $data->post_status = 'publish'; - } else { - - // Allow edit post title. - if ( ! empty( $request['name'] ) ) { - $data->post_title = $request['name']; - } - } - - // Comment status. - $data->comment_status = 'closed'; - - // Ping status. - $data->ping_status = 'closed'; - - /** - * Filter the query_vars used in `get_items` for the constructed query. - * - * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being - * prepared for insertion. - * - * @param stdClass $data An object representing a single item prepared - * for inserting or updating the database. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $data, $request ); - } - - /** - * Prepare a single webhook output for response. - * - * @param int $id Webhook ID or object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $id, $request ) { - $webhook = wc_get_webhook( $id ); - - if ( empty( $webhook ) || is_null( $webhook ) ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $data = array( - 'id' => $webhook->get_id(), - 'name' => $webhook->get_name(), - 'status' => $webhook->get_status(), - 'topic' => $webhook->get_topic(), - 'resource' => $webhook->get_resource(), - 'event' => $webhook->get_event(), - 'hooks' => $webhook->get_hooks(), - 'delivery_url' => $webhook->get_delivery_url(), - 'date_created' => wc_rest_prepare_date_response( $webhook->get_date_created() ), - 'date_modified' => wc_rest_prepare_date_response( $webhook->get_date_modified() ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $webhook->get_id() ) ); - - /** - * Filter webhook object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WC_Webhook $webhook Webhook object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $webhook, $request ); - } - - /** - * Prepare links for the request. - * - * @param int $id Webhook ID. - * @return array - */ - protected function prepare_links( $id ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $id ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the Webhook's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'webhook', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'A friendly name for the webhook.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'status' => array( - 'description' => __( 'Webhook status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'active', - 'enum' => array_keys( wc_get_webhook_statuses() ), - 'context' => array( 'view', 'edit' ), - ), - 'topic' => array( - 'description' => __( 'Webhook topic.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'resource' => array( - 'description' => __( 'Webhook resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'event' => array( - 'description' => __( 'Webhook event.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'hooks' => array( - 'description' => __( 'WooCommerce action names associated with the webhook.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'delivery_url' => array( - 'description' => __( 'The URL where the webhook payload is delivered.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'secret' => array( - 'description' => __( "Secret key used to generate a hash of the delivered webhook and provided in the request headers. This will default to a MD5 hash from the current user's ID|username if not provided.", 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the webhook was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the webhook was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['context']['default'] = 'view'; - - $params['after'] = array( - 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['before'] = array( - 'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['exclude'] = array( - 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['include'] = array( - 'description' => __( 'Limit result set to specific ids.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['offset'] = array( - 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['order'] = array( - 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'desc', - 'enum' => array( 'asc', 'desc' ), - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['orderby'] = array( - 'description' => __( 'Sort collection by object attribute.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'date', - 'enum' => array( - 'date', - 'id', - 'title', - ), - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['status'] = array( - 'default' => 'all', - 'description' => __( 'Limit result set to webhooks assigned a specific status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array( 'all', 'active', 'paused', 'disabled' ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version2/class-wc-rest-coupons-v2-controller.php b/src/Controllers/Version2/class-wc-rest-coupons-v2-controller.php deleted file mode 100644 index 7dbcaa1c2ae..00000000000 --- a/src/Controllers/Version2/class-wc-rest-coupons-v2-controller.php +++ /dev/null @@ -1,542 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( - $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'code' => array( - 'description' => __( 'Coupon code.', 'woocommerce-rest-api' ), - 'required' => true, - 'type' => 'string', - ), - ) - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - } - - /** - * Get object. - * - * @since 3.0.0 - * @param int $id Object ID. - * @return WC_Data - */ - protected function get_object( $id ) { - return new WC_Coupon( $id ); - } - - /** - * Get formatted item data. - * - * @since 3.0.0 - * @param WC_Data $object WC_Data instance. - * @return array - */ - protected function get_formatted_item_data( $object ) { - $data = $object->get_data(); - - $format_decimal = array( 'amount', 'minimum_amount', 'maximum_amount' ); - $format_date = array( 'date_created', 'date_modified', 'date_expires' ); - $format_null = array( 'usage_limit', 'usage_limit_per_user', 'limit_usage_to_x_items' ); - - // Format decimal values. - foreach ( $format_decimal as $key ) { - $data[ $key ] = wc_format_decimal( $data[ $key ], 2 ); - } - - // Format date values. - foreach ( $format_date as $key ) { - $datetime = $data[ $key ]; - $data[ $key ] = wc_rest_prepare_date_response( $datetime, false ); - $data[ $key . '_gmt' ] = wc_rest_prepare_date_response( $datetime ); - } - - // Format null values. - foreach ( $format_null as $key ) { - $data[ $key ] = $data[ $key ] ? $data[ $key ] : null; - } - - return array( - 'id' => $object->get_id(), - 'code' => $data['code'], - 'amount' => $data['amount'], - 'date_created' => $data['date_created'], - 'date_created_gmt' => $data['date_created_gmt'], - 'date_modified' => $data['date_modified'], - 'date_modified_gmt' => $data['date_modified_gmt'], - 'discount_type' => $data['discount_type'], - 'description' => $data['description'], - 'date_expires' => $data['date_expires'], - 'date_expires_gmt' => $data['date_expires_gmt'], - 'usage_count' => $data['usage_count'], - 'individual_use' => $data['individual_use'], - 'product_ids' => $data['product_ids'], - 'excluded_product_ids' => $data['excluded_product_ids'], - 'usage_limit' => $data['usage_limit'], - 'usage_limit_per_user' => $data['usage_limit_per_user'], - 'limit_usage_to_x_items' => $data['limit_usage_to_x_items'], - 'free_shipping' => $data['free_shipping'], - 'product_categories' => $data['product_categories'], - 'excluded_product_categories' => $data['excluded_product_categories'], - 'exclude_sale_items' => $data['exclude_sale_items'], - 'minimum_amount' => $data['minimum_amount'], - 'maximum_amount' => $data['maximum_amount'], - 'email_restrictions' => $data['email_restrictions'], - 'used_by' => $data['used_by'], - 'meta_data' => $data['meta_data'], - ); - } - - /** - * Prepare a single coupon output for response. - * - * @since 3.0.0 - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function prepare_object_for_response( $object, $request ) { - $data = $this->get_formatted_item_data( $object ); - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $object, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, - * refers to object type being prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request ); - } - - /** - * Prepare objects query. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array - */ - protected function prepare_objects_query( $request ) { - $args = parent::prepare_objects_query( $request ); - - if ( ! empty( $request['code'] ) ) { - $id = wc_get_coupon_id_by_code( $request['code'] ); - $args['post__in'] = array( $id ); - } - - // Get only ids. - $args['fields'] = 'ids'; - - return $args; - } - - /** - * Only return writable props from schema. - * - * @param array $schema Schema. - * @return bool - */ - protected function filter_writable_props( $schema ) { - return empty( $schema['readonly'] ); - } - - /** - * Prepare a single coupon for create or update. - * - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data - */ - protected function prepare_object_for_database( $request, $creating = false ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $coupon = new WC_Coupon( $id ); - $schema = $this->get_item_schema(); - $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); - - // Validate required POST fields. - if ( $creating && empty( $request['code'] ) ) { - return new WP_Error( 'woocommerce_rest_empty_coupon_code', sprintf( __( 'The coupon code cannot be empty.', 'woocommerce-rest-api' ), 'code' ), array( 'status' => 400 ) ); - } - - // Handle all writable props. - foreach ( $data_keys as $key ) { - $value = $request[ $key ]; - - if ( ! is_null( $value ) ) { - switch ( $key ) { - case 'code': - $coupon_code = wc_format_coupon_code( $value ); - $id = $coupon->get_id() ? $coupon->get_id() : 0; - $id_from_code = wc_get_coupon_id_by_code( $coupon_code, $id ); - - if ( $id_from_code ) { - return new WP_Error( 'woocommerce_rest_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $coupon->set_code( $coupon_code ); - break; - case 'meta_data': - if ( is_array( $value ) ) { - foreach ( $value as $meta ) { - $coupon->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - break; - case 'description': - $coupon->set_description( wp_filter_post_kses( $value ) ); - break; - default: - if ( is_callable( array( $coupon, "set_{$key}" ) ) ) { - $coupon->{"set_{$key}"}( $value ); - } - break; - } - } - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $coupon Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $coupon, $request, $creating ); - } - - /** - * Get the Coupon's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the object.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'code' => array( - 'description' => __( 'Coupon code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'amount' => array( - 'description' => __( 'The amount of discount. Should always be numeric, even if setting a percentage.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the coupon was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the coupon was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the coupon was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the coupon was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'discount_type' => array( - 'description' => __( 'Determines the type of discount that will be applied.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'fixed_cart', - 'enum' => array_keys( wc_get_coupon_types() ), - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'Coupon description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_expires' => array( - 'description' => __( "The date the coupon expires, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_expires_gmt' => array( - 'description' => __( 'The date the coupon expires, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'usage_count' => array( - 'description' => __( 'Number of times the coupon has been used already.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'individual_use' => array( - 'description' => __( 'If true, the coupon can only be used individually. Other applied coupons will be removed from the cart.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'product_ids' => array( - 'description' => __( 'List of product IDs the coupon can be used on.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'excluded_product_ids' => array( - 'description' => __( 'List of product IDs the coupon cannot be used on.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'usage_limit' => array( - 'description' => __( 'How many times the coupon can be used in total.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'usage_limit_per_user' => array( - 'description' => __( 'How many times the coupon can be used per customer.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'limit_usage_to_x_items' => array( - 'description' => __( 'Max number of items in the cart the coupon can be applied to.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'free_shipping' => array( - 'description' => __( 'If true and if the free shipping method requires a coupon, this coupon will enable free shipping.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'product_categories' => array( - 'description' => __( 'List of category IDs the coupon applies to.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'excluded_product_categories' => array( - 'description' => __( 'List of category IDs the coupon does not apply to.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'exclude_sale_items' => array( - 'description' => __( 'If true, this coupon will not be applied to items that have sale prices.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'minimum_amount' => array( - 'description' => __( 'Minimum order amount that needs to be in the cart before coupon applies.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'maximum_amount' => array( - 'description' => __( 'Maximum order amount allowed when using the coupon.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email_restrictions' => array( - 'description' => __( 'List of email addresses that can use this coupon.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'string', - ), - 'context' => array( 'view', 'edit' ), - ), - 'used_by' => array( - 'description' => __( 'List of user IDs (or guest email addresses) that have used the coupon.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ); - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['code'] = array( - 'description' => __( 'Limit result set to resources with a specific code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version2/class-wc-rest-customer-downloads-v2-controller.php b/src/Controllers/Version2/class-wc-rest-customer-downloads-v2-controller.php deleted file mode 100644 index 1b7c0de9fd6..00000000000 --- a/src/Controllers/Version2/class-wc-rest-customer-downloads-v2-controller.php +++ /dev/null @@ -1,165 +0,0 @@ -/downloads endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Customers controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Customer_Downloads_V1_Controller - */ -class WC_REST_Customer_Downloads_V2_Controller extends WC_REST_Customer_Downloads_V1_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v2'; - - /** - * Prepare a single download output for response. - * - * @param stdClass $download Download object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $download, $request ) { - $data = array( - 'download_id' => $download->download_id, - 'download_url' => $download->download_url, - 'product_id' => $download->product_id, - 'product_name' => $download->product_name, - 'download_name' => $download->download_name, - 'order_id' => $download->order_id, - 'order_key' => $download->order_key, - 'downloads_remaining' => '' === $download->downloads_remaining ? 'unlimited' : $download->downloads_remaining, - 'access_expires' => $download->access_expires ? wc_rest_prepare_date_response( $download->access_expires ) : 'never', - 'access_expires_gmt' => $download->access_expires ? wc_rest_prepare_date_response( get_gmt_from_date( $download->access_expires ) ) : 'never', - 'file' => $download->file, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $download, $request ) ); - - /** - * Filter customer download data returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param stdClass $download Download object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_customer_download', $response, $download, $request ); - } - - /** - * Get the Customer Download's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'customer_download', - 'type' => 'object', - 'properties' => array( - 'download_id' => array( - 'description' => __( 'Download ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'download_url' => array( - 'description' => __( 'Download file URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Downloadable product ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'product_name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'download_name' => array( - 'description' => __( 'Downloadable file name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'order_id' => array( - 'description' => __( 'Order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'order_key' => array( - 'description' => __( 'Order key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'downloads_remaining' => array( - 'description' => __( 'Number of downloads remaining.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'access_expires' => array( - 'description' => __( "The date when download access expires, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'access_expires_gmt' => array( - 'description' => __( 'The date when download access expires, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'file' => array( - 'description' => __( 'File details.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-customers-v2-controller.php b/src/Controllers/Version2/class-wc-rest-customers-v2-controller.php deleted file mode 100644 index 29d4e07d2e2..00000000000 --- a/src/Controllers/Version2/class-wc-rest-customers-v2-controller.php +++ /dev/null @@ -1,364 +0,0 @@ -get_data(); - $format_date = array( 'date_created', 'date_modified' ); - - // Format date values. - foreach ( $format_date as $key ) { - $datetime = 'date_created' === $key ? get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $data[ $key ]->getTimestamp() ) ) : $data[ $key ]; - $data[ $key ] = wc_rest_prepare_date_response( $datetime, false ); - $data[ $key . '_gmt' ] = wc_rest_prepare_date_response( $datetime ); - } - - return array( - 'id' => $object->get_id(), - 'date_created' => $data['date_created'], - 'date_created_gmt' => $data['date_created_gmt'], - 'date_modified' => $data['date_modified'], - 'date_modified_gmt' => $data['date_modified_gmt'], - 'email' => $data['email'], - 'first_name' => $data['first_name'], - 'last_name' => $data['last_name'], - 'role' => $data['role'], - 'username' => $data['username'], - 'billing' => $data['billing'], - 'shipping' => $data['shipping'], - 'is_paying_customer' => $data['is_paying_customer'], - 'orders_count' => $object->get_order_count(), - 'total_spent' => $object->get_total_spent(), - 'avatar_url' => $object->get_avatar_url(), - 'meta_data' => $data['meta_data'], - ); - } - - /** - * Prepare a single customer output for response. - * - * @param WP_User $user_data User object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $user_data, $request ) { - $customer = new WC_Customer( $user_data->ID ); - $data = $this->get_formatted_item_data( $customer ); - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $user_data ) ); - - /** - * Filter customer data returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_User $user_data User object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_customer', $response, $user_data, $request ); - } - - /** - * Update customer meta fields. - * - * @param WC_Customer $customer Customer data. - * @param WP_REST_Request $request Request data. - */ - protected function update_customer_meta_fields( $customer, $request ) { - parent::update_customer_meta_fields( $customer, $request ); - - // Meta data. - if ( isset( $request['meta_data'] ) ) { - if ( is_array( $request['meta_data'] ) ) { - foreach ( $request['meta_data'] as $meta ) { - $customer->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - } - } - - /** - * Get the Customer's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'customer', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the customer was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the customer was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the customer was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the customer was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'email' => array( - 'description' => __( 'The email address for the customer.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'first_name' => array( - 'description' => __( 'Customer first name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'last_name' => array( - 'description' => __( 'Customer last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'role' => array( - 'description' => __( 'Customer role.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'username' => array( - 'description' => __( 'Customer login name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_user', - ), - ), - 'password' => array( - 'description' => __( 'Customer password.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'edit' ), - ), - 'billing' => array( - 'description' => __( 'List of billing address data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'ISO code of the country.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email' => array( - 'description' => __( 'Email address.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'phone' => array( - 'description' => __( 'Phone number.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping' => array( - 'description' => __( 'List of shipping address data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'ISO code of the country.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'is_paying_customer' => array( - 'description' => __( 'Is the customer a paying customer?', 'woocommerce-rest-api' ), - 'type' => 'bool', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'orders_count' => array( - 'description' => __( 'Quantity of orders made by the customer.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_spent' => array( - 'description' => __( 'Total amount spent.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'avatar_url' => array( - 'description' => __( 'Avatar URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-network-orders-v2-controller.php b/src/Controllers/Version2/class-wc-rest-network-orders-v2-controller.php deleted file mode 100644 index 357082d1b65..00000000000 --- a/src/Controllers/Version2/class-wc-rest-network-orders-v2-controller.php +++ /dev/null @@ -1,174 +0,0 @@ -namespace, - '/' . $this->rest_base . '/network', - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'network_orders' ), - 'permission_callback' => array( $this, 'network_orders_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - } - - /** - * Retrieves the item's schema for display / public consumption purposes. - * - * @return array Public item schema data. - */ - public function get_public_item_schema() { - $schema = parent::get_public_item_schema(); - - $schema['properties']['blog'] = array( - 'description' => __( 'Blog id of the record on the multisite.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ); - $schema['properties']['edit_url'] = array( - 'description' => __( 'URL to edit the order', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ); - $schema['properties']['customer'][] = array( - 'description' => __( 'Name of the customer for the order', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ); - $schema['properties']['status_name'][] = array( - 'description' => __( 'Order Status', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ); - $schema['properties']['formatted_total'][] = array( - 'description' => __( 'Order total formatted for locale', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ); - - return $schema; - } - - /** - * Does a permissions check for the proper requested blog - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool $permission - */ - public function network_orders_permissions_check( $request ) { - $blog_id = $request->get_param( 'blog_id' ); - $blog_id = ! empty( $blog_id ) ? $blog_id : get_current_blog_id(); - - switch_to_blog( $blog_id ); - - $permission = $this->get_items_permissions_check( $request ); - - restore_current_blog(); - - return $permission; - } - - /** - * Get a collection of orders from the requested blog id - * - * @param WP_REST_Request $request Full details about the request. - * - * @return WP_REST_Response - */ - public function network_orders( $request ) { - $blog_id = $request->get_param( 'blog_id' ); - $blog_id = ! empty( $blog_id ) ? $blog_id : get_current_blog_id(); - $active_plugins = get_blog_option( $blog_id, 'active_plugins', array() ); - $network_active_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) ); - - $plugins = array_merge( $active_plugins, $network_active_plugins ); - $wc_active = false; - foreach ( $plugins as $plugin ) { - if ( substr_compare( $plugin, '/woocommerce.php', strlen( $plugin ) - strlen( '/woocommerce.php' ), strlen( '/woocommerce.php' ) ) === 0 ) { - $wc_active = true; - } - } - - // If WooCommerce not active for site, return an empty response. - if ( ! $wc_active ) { - $response = rest_ensure_response( array() ); - return $response; - } - - switch_to_blog( $blog_id ); - add_filter( 'woocommerce_rest_orders_prepare_object_query', array( $this, 'network_orders_filter_args' ) ); - $items = $this->get_items( $request ); - remove_filter( 'woocommerce_rest_orders_prepare_object_query', array( $this, 'network_orders_filter_args' ) ); - - foreach ( $items->data as &$current_order ) { - $order = wc_get_order( $current_order['id'] ); - - $current_order['blog'] = get_blog_details( get_current_blog_id() ); - $current_order['edit_url'] = get_admin_url( $blog_id, 'post.php?post=' . absint( $order->get_id() ) . '&action=edit' ); - /* translators: 1: first name 2: last name */ - $current_order['customer'] = trim( sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce-rest-api' ), $order->get_billing_first_name(), $order->get_billing_last_name() ) ); - $current_order['status_name'] = wc_get_order_status_name( $order->get_status() ); - $current_order['formatted_total'] = $order->get_formatted_order_total(); - } - - restore_current_blog(); - - return $items; - } - - /** - * Filters the post statuses to on hold and processing for the network order query. - * - * @param array $args Query args. - * - * @return array - */ - public function network_orders_filter_args( $args ) { - $args['post_status'] = array( - 'wc-on-hold', - 'wc-processing', - ); - - return $args; - } -} diff --git a/src/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php b/src/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php deleted file mode 100644 index 6ecd15e3165..00000000000 --- a/src/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php +++ /dev/null @@ -1,182 +0,0 @@ -/notes endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Order Notes controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Order_Notes_V1_Controller - */ -class WC_REST_Order_Notes_V2_Controller extends WC_REST_Order_Notes_V1_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v2'; - - /** - * Get order notes from an order. - * - * @param WP_REST_Request $request Request data. - * - * @return array|WP_Error - */ - public function get_items( $request ) { - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order || $this->post_type !== $order->get_type() ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid order ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $args = array( - 'post_id' => $order->get_id(), - 'approve' => 'approve', - 'type' => 'order_note', - ); - - // Allow filter by order note type. - if ( 'customer' === $request['type'] ) { - $args['meta_query'] = array( // WPCS: slow query ok. - array( - 'key' => 'is_customer_note', - 'value' => 1, - 'compare' => '=', - ), - ); - } elseif ( 'internal' === $request['type'] ) { - $args['meta_query'] = array( // WPCS: slow query ok. - array( - 'key' => 'is_customer_note', - 'compare' => 'NOT EXISTS', - ), - ); - } - - remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 ); - - $notes = get_comments( $args ); - - add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 ); - - $data = array(); - foreach ( $notes as $note ) { - $order_note = $this->prepare_item_for_response( $note, $request ); - $order_note = $this->prepare_response_for_collection( $order_note ); - $data[] = $order_note; - } - - return rest_ensure_response( $data ); - } - - /** - * Prepare a single order note output for response. - * - * @param WP_Comment $note Order note object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $note, $request ) { - $data = array( - 'id' => (int) $note->comment_ID, - 'date_created' => wc_rest_prepare_date_response( $note->comment_date ), - 'date_created_gmt' => wc_rest_prepare_date_response( $note->comment_date_gmt ), - 'note' => $note->comment_content, - 'customer_note' => (bool) get_comment_meta( $note->comment_ID, 'is_customer_note', true ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $note ) ); - - /** - * Filter order note object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_Comment $note Order note object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_order_note', $response, $note, $request ); - } - - /** - * Get the Order Notes schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'order_note', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the order note was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the order note was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'note' => array( - 'description' => __( 'Order note content.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'customer_note' => array( - 'description' => __( 'If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = array(); - $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); - $params['type'] = array( - 'default' => 'any', - 'description' => __( 'Limit result to customers or internal notes.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array( 'any', 'customer', 'internal' ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version2/class-wc-rest-order-refunds-v2-controller.php b/src/Controllers/Version2/class-wc-rest-order-refunds-v2-controller.php deleted file mode 100644 index dff06e2d063..00000000000 --- a/src/Controllers/Version2/class-wc-rest-order-refunds-v2-controller.php +++ /dev/null @@ -1,584 +0,0 @@ -/refunds endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Order Refunds controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Orders_V2_Controller - */ -class WC_REST_Order_Refunds_V2_Controller extends WC_REST_Orders_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v2'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'orders/(?P[\d]+)/refunds'; - - /** - * Post type. - * - * @var string - */ - protected $post_type = 'shop_order_refund'; - - /** - * Stores the request. - * - * @var array - */ - protected $request = array(); - - /** - * Order refunds actions. - */ - public function __construct() { - add_filter( "woocommerce_rest_{$this->post_type}_object_trashable", '__return_false' ); - } - - /** - * Register the routes for order refunds. - */ - public function register_routes() { - register_rest_route( - $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'order_id' => array( - 'description' => __( 'The order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'order_id' => array( - 'description' => __( 'The order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => true, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Get object. - * - * @since 3.0.0 - * @param int $id Object ID. - * @return WC_Data - */ - protected function get_object( $id ) { - return wc_get_order( $id ); - } - - /** - * Get formatted item data. - * - * @since 3.0.0 - * @param WC_Data $object WC_Data instance. - * @return array - */ - protected function get_formatted_item_data( $object ) { - $data = $object->get_data(); - $format_decimal = array( 'amount' ); - $format_date = array( 'date_created' ); - $format_line_items = array( 'line_items' ); - - // Format decimal values. - foreach ( $format_decimal as $key ) { - $data[ $key ] = wc_format_decimal( $data[ $key ], $this->request['dp'] ); - } - - // Format date values. - foreach ( $format_date as $key ) { - $datetime = $data[ $key ]; - $data[ $key ] = wc_rest_prepare_date_response( $datetime, false ); - $data[ $key . '_gmt' ] = wc_rest_prepare_date_response( $datetime ); - } - - // Format line items. - foreach ( $format_line_items as $key ) { - $data[ $key ] = array_values( array_map( array( $this, 'get_order_item_data' ), $data[ $key ] ) ); - } - - return array( - 'id' => $object->get_id(), - 'date_created' => $data['date_created'], - 'date_created_gmt' => $data['date_created_gmt'], - 'amount' => $data['amount'], - 'reason' => $data['reason'], - 'refunded_by' => $data['refunded_by'], - 'refunded_payment' => $data['refunded_payment'], - 'meta_data' => $data['meta_data'], - 'line_items' => $data['line_items'], - ); - } - - /** - * Prepare a single order output for response. - * - * @since 3.0.0 - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * - * @return WP_Error|WP_REST_Response - */ - public function prepare_object_for_response( $object, $request ) { - $this->request = $request; - $this->request['dp'] = is_null( $this->request['dp'] ) ? wc_get_price_decimals() : absint( $this->request['dp'] ); - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order ) { - return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), 404 ); - } - - if ( ! $object || $object->get_parent_id() !== $order->get_id() ) { - return new WP_Error( 'woocommerce_rest_invalid_order_refund_id', __( 'Invalid order refund ID.', 'woocommerce-rest-api' ), 404 ); - } - - $data = $this->get_formatted_item_data( $object ); - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $object, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, - * refers to object type being prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request ); - } - - /** - * Prepare links for the request. - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return array Links for the given post. - */ - protected function prepare_links( $object, $request ) { - $base = str_replace( '(?P[\d]+)', $object->get_parent_id(), $this->rest_base ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $object->get_id() ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - 'up' => array( - 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $object->get_parent_id() ) ), - ), - ); - - return $links; - } - - /** - * Prepare objects query. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array - */ - protected function prepare_objects_query( $request ) { - $args = parent::prepare_objects_query( $request ); - - $args['post_status'] = array_keys( wc_get_order_statuses() ); - $args['post_parent__in'] = array( absint( $request['order_id'] ) ); - - return $args; - } - - /** - * Prepares one object for create or update operation. - * - * @since 3.0.0 - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data The prepared item, or WP_Error object on failure. - */ - protected function prepare_object_for_database( $request, $creating = false ) { - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order ) { - return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), 404 ); - } - - if ( 0 > $request['amount'] ) { - return new WP_Error( 'woocommerce_rest_invalid_order_refund', __( 'Refund amount must be greater than zero.', 'woocommerce-rest-api' ), 400 ); - } - - // Create the refund. - $refund = wc_create_refund( - array( - 'order_id' => $order->get_id(), - 'amount' => $request['amount'], - 'reason' => empty( $request['reason'] ) ? null : $request['reason'], - 'refund_payment' => is_bool( $request['api_refund'] ) ? $request['api_refund'] : true, - 'restock_items' => true, - ) - ); - - if ( is_wp_error( $refund ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', $refund->get_error_message(), 500 ); - } - - if ( ! $refund ) { - return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', __( 'Cannot create order refund, please try again.', 'woocommerce-rest-api' ), 500 ); - } - - if ( ! empty( $request['meta_data'] ) && is_array( $request['meta_data'] ) ) { - foreach ( $request['meta_data'] as $meta ) { - $refund->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - $refund->save_meta_data(); - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $coupon Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $refund, $request, $creating ); - } - - /** - * Save an object data. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @param bool $creating If is creating a new object. - * @return WC_Data|WP_Error - */ - protected function save_object( $request, $creating = false ) { - try { - $object = $this->prepare_object_for_database( $request, $creating ); - - if ( is_wp_error( $object ) ) { - return $object; - } - - return $this->get_object( $object->get_id() ); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Get the Order's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the order refund was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the order refund was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'amount' => array( - 'description' => __( 'Refund amount.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'reason' => array( - 'description' => __( 'Reason for refund.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'refunded_by' => array( - 'description' => __( 'User ID of user who created the refund.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'refunded_payment' => array( - 'description' => __( 'If the payment was refunded via the API.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'line_items' => array( - 'description' => __( 'Line items data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Product ID.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'variation_id' => array( - 'description' => __( 'Variation ID, if applicable.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'quantity' => array( - 'description' => __( 'Quantity ordered.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tax_class' => array( - 'description' => __( 'Tax class of product.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Line subtotal (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal_tax' => array( - 'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Tax subtotal.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'sku' => array( - 'description' => __( 'Product SKU.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'price' => array( - 'description' => __( 'Product price.', 'woocommerce-rest-api' ), - 'type' => 'number', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'api_refund' => array( - 'description' => __( 'When true, the payment gateway API is used to generate the refund.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'edit' ), - 'default' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - unset( $params['status'], $params['customer'], $params['product'] ); - - return $params; - } -} diff --git a/src/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/src/Controllers/Version2/class-wc-rest-orders-v2-controller.php deleted file mode 100644 index a9422aec274..00000000000 --- a/src/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ /dev/null @@ -1,1711 +0,0 @@ -namespace, - '/' . $this->rest_base, - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/(?P[\d]+)', - array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/batch', - array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - } - - /** - * Get object. Return false if object is not of required type. - * - * @since 3.0.0 - * @param int $id Object ID. - * @return WC_Data|bool - */ - protected function get_object( $id ) { - $order = wc_get_order( $id ); - // In case id is a refund's id (or it's not an order at all), don't expose it via /orders/ path. - if ( ! $order || 'shop_order_refund' === $order->get_type() ) { - return false; - } - - return $order; - } - - /** - * Expands an order item to get its data. - * - * @param WC_Order_item $item Order item data. - * @return array - */ - protected function get_order_item_data( $item ) { - $data = $item->get_data(); - $format_decimal = array( 'subtotal', 'subtotal_tax', 'total', 'total_tax', 'tax_total', 'shipping_tax_total' ); - - // Format decimal values. - foreach ( $format_decimal as $key ) { - if ( isset( $data[ $key ] ) ) { - $data[ $key ] = wc_format_decimal( $data[ $key ], $this->request['dp'] ); - } - } - - // Add SKU and PRICE to products. - if ( is_callable( array( $item, 'get_product' ) ) ) { - $data['sku'] = $item->get_product() ? $item->get_product()->get_sku() : null; - $data['price'] = $item->get_quantity() ? $item->get_total() / $item->get_quantity() : 0; - } - - // Format taxes. - if ( ! empty( $data['taxes']['total'] ) ) { - $taxes = array(); - - foreach ( $data['taxes']['total'] as $tax_rate_id => $tax ) { - $taxes[] = array( - 'id' => $tax_rate_id, - 'total' => $tax, - 'subtotal' => isset( $data['taxes']['subtotal'][ $tax_rate_id ] ) ? $data['taxes']['subtotal'][ $tax_rate_id ] : '', - ); - } - $data['taxes'] = $taxes; - } elseif ( isset( $data['taxes'] ) ) { - $data['taxes'] = array(); - } - - // Remove names for coupons, taxes and shipping. - if ( isset( $data['code'] ) || isset( $data['rate_code'] ) || isset( $data['method_title'] ) ) { - unset( $data['name'] ); - } - - // Remove props we don't want to expose. - unset( $data['order_id'] ); - unset( $data['type'] ); - - return $data; - } - - /** - * Get formatted item data. - * - * @since 3.0.0 - * @param WC_Data $object WC_Data instance. - * @return array - */ - protected function get_formatted_item_data( $object ) { - $data = $object->get_data(); - $format_decimal = array( 'discount_total', 'discount_tax', 'shipping_total', 'shipping_tax', 'shipping_total', 'shipping_tax', 'cart_tax', 'total', 'total_tax' ); - $format_date = array( 'date_created', 'date_modified', 'date_completed', 'date_paid' ); - $format_line_items = array( 'line_items', 'tax_lines', 'shipping_lines', 'fee_lines', 'coupon_lines' ); - - // Format decimal values. - foreach ( $format_decimal as $key ) { - $data[ $key ] = wc_format_decimal( $data[ $key ], $this->request['dp'] ); - } - - // Format date values. - foreach ( $format_date as $key ) { - $datetime = $data[ $key ]; - $data[ $key ] = wc_rest_prepare_date_response( $datetime, false ); - $data[ $key . '_gmt' ] = wc_rest_prepare_date_response( $datetime ); - } - - // Format the order status. - $data['status'] = 'wc-' === substr( $data['status'], 0, 3 ) ? substr( $data['status'], 3 ) : $data['status']; - - // Format line items. - foreach ( $format_line_items as $key ) { - $data[ $key ] = array_values( array_map( array( $this, 'get_order_item_data' ), $data[ $key ] ) ); - } - - // Refunds. - $data['refunds'] = array(); - foreach ( $object->get_refunds() as $refund ) { - $data['refunds'][] = array( - 'id' => $refund->get_id(), - 'reason' => $refund->get_reason() ? $refund->get_reason() : '', - 'total' => '-' . wc_format_decimal( $refund->get_amount(), $this->request['dp'] ), - ); - } - - return array( - 'id' => $object->get_id(), - 'parent_id' => $data['parent_id'], - 'number' => $data['number'], - 'order_key' => $data['order_key'], - 'created_via' => $data['created_via'], - 'version' => $data['version'], - 'status' => $data['status'], - 'currency' => $data['currency'], - 'date_created' => $data['date_created'], - 'date_created_gmt' => $data['date_created_gmt'], - 'date_modified' => $data['date_modified'], - 'date_modified_gmt' => $data['date_modified_gmt'], - 'discount_total' => $data['discount_total'], - 'discount_tax' => $data['discount_tax'], - 'shipping_total' => $data['shipping_total'], - 'shipping_tax' => $data['shipping_tax'], - 'cart_tax' => $data['cart_tax'], - 'total' => $data['total'], - 'total_tax' => $data['total_tax'], - 'prices_include_tax' => $data['prices_include_tax'], - 'customer_id' => $data['customer_id'], - 'customer_ip_address' => $data['customer_ip_address'], - 'customer_user_agent' => $data['customer_user_agent'], - 'customer_note' => $data['customer_note'], - 'billing' => $data['billing'], - 'shipping' => $data['shipping'], - 'payment_method' => $data['payment_method'], - 'payment_method_title' => $data['payment_method_title'], - 'transaction_id' => $data['transaction_id'], - 'date_paid' => $data['date_paid'], - 'date_paid_gmt' => $data['date_paid_gmt'], - 'date_completed' => $data['date_completed'], - 'date_completed_gmt' => $data['date_completed_gmt'], - 'cart_hash' => $data['cart_hash'], - 'meta_data' => $data['meta_data'], - 'line_items' => $data['line_items'], - 'tax_lines' => $data['tax_lines'], - 'shipping_lines' => $data['shipping_lines'], - 'fee_lines' => $data['fee_lines'], - 'coupon_lines' => $data['coupon_lines'], - 'refunds' => $data['refunds'], - ); - } - - /** - * Prepare a single order output for response. - * - * @since 3.0.0 - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function prepare_object_for_response( $object, $request ) { - $this->request = $request; - $this->request['dp'] = is_null( $this->request['dp'] ) ? wc_get_price_decimals() : absint( $this->request['dp'] ); - $data = $this->get_formatted_item_data( $object ); - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $object, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, - * refers to object type being prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request ); - } - - /** - * Prepare links for the request. - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return array Links for the given post. - */ - protected function prepare_links( $object, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - if ( 0 !== (int) $object->get_customer_id() ) { - $links['customer'] = array( - 'href' => rest_url( sprintf( '/%s/customers/%d', $this->namespace, $object->get_customer_id() ) ), - ); - } - - if ( 0 !== (int) $object->get_parent_id() ) { - $links['up'] = array( - 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $object->get_parent_id() ) ), - ); - } - - return $links; - } - - /** - * Prepare objects query. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array - */ - protected function prepare_objects_query( $request ) { - global $wpdb; - - $args = parent::prepare_objects_query( $request ); - - // Set post_status. - if ( in_array( $request['status'], $this->get_order_statuses(), true ) ) { - $args['post_status'] = 'wc-' . $request['status']; - } elseif ( 'any' === $request['status'] ) { - $args['post_status'] = 'any'; - } else { - $args['post_status'] = $request['status']; - } - - if ( isset( $request['customer'] ) ) { - if ( ! empty( $args['meta_query'] ) ) { - $args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query - } - - $args['meta_query'][] = array( - 'key' => '_customer_user', - 'value' => $request['customer'], - 'type' => 'NUMERIC', - ); - } - - // Search by product. - if ( ! empty( $request['product'] ) ) { - $order_ids = $wpdb->get_col( - $wpdb->prepare( - "SELECT order_id - FROM {$wpdb->prefix}woocommerce_order_items - WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = %d ) - AND order_item_type = 'line_item'", - $request['product'] - ) - ); - - // Force WP_Query return empty if don't found any order. - $order_ids = ! empty( $order_ids ) ? $order_ids : array( 0 ); - - $args['post__in'] = $order_ids; - } - - // Search. - if ( ! empty( $args['s'] ) ) { - $order_ids = wc_order_search( $args['s'] ); - - if ( ! empty( $order_ids ) ) { - unset( $args['s'] ); - $args['post__in'] = array_merge( $order_ids, array( 0 ) ); - } - } - - /** - * Filter the query arguments for a request. - * - * Enables adding extra arguments or setting defaults for an order collection request. - * - * @param array $args Key value array of query var to query value. - * @param WP_REST_Request $request The request used. - */ - $args = apply_filters( 'woocommerce_rest_orders_prepare_object_query', $args, $request ); - - return $args; - } - - /** - * Only return writable props from schema. - * - * @param array $schema Schema. - * @return bool - */ - protected function filter_writable_props( $schema ) { - return empty( $schema['readonly'] ); - } - - /** - * Prepare a single order for create or update. - * - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data - */ - protected function prepare_object_for_database( $request, $creating = false ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $order = new WC_Order( $id ); - $schema = $this->get_item_schema(); - $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); - - // Handle all writable props. - foreach ( $data_keys as $key ) { - $value = $request[ $key ]; - - if ( ! is_null( $value ) ) { - switch ( $key ) { - case 'status': - // Status change should be done later so transitions have new data. - break; - case 'billing': - case 'shipping': - $this->update_address( $order, $value, $key ); - break; - case 'line_items': - case 'shipping_lines': - case 'fee_lines': - case 'coupon_lines': - if ( is_array( $value ) ) { - foreach ( $value as $item ) { - if ( is_array( $item ) ) { - if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) { - $order->remove_item( $item['id'] ); - } else { - $this->set_item( $order, $key, $item ); - } - } - } - } - break; - case 'meta_data': - if ( is_array( $value ) ) { - foreach ( $value as $meta ) { - $order->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - break; - default: - if ( is_callable( array( $order, "set_{$key}" ) ) ) { - $order->{"set_{$key}"}( $value ); - } - break; - } - } - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $order Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $order, $request, $creating ); - } - - /** - * Save an object data. - * - * @since 3.0.0 - * @throws WC_REST_Exception But all errors are validated before returning any data. - * @param WP_REST_Request $request Full details about the request. - * @param bool $creating If is creating a new object. - * @return WC_Data|WP_Error - */ - protected function save_object( $request, $creating = false ) { - try { - $object = $this->prepare_object_for_database( $request, $creating ); - - if ( is_wp_error( $object ) ) { - return $object; - } - - // Make sure gateways are loaded so hooks from gateways fire on save/create. - WC()->payment_gateways(); - - if ( ! is_null( $request['customer_id'] ) && 0 !== $request['customer_id'] ) { - // Make sure customer exists. - if ( false === get_user_by( 'id', $request['customer_id'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id', __( 'Customer ID is invalid.', 'woocommerce-rest-api' ), 400 ); - } - - // Make sure customer is part of blog. - if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) { - add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' ); - } - } - - if ( $creating ) { - $object->set_created_via( 'rest-api' ); - $object->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ); - $object->calculate_totals(); - } else { - // If items have changed, recalculate order totals. - if ( isset( $request['billing'] ) || isset( $request['shipping'] ) || isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) { - $object->calculate_totals( true ); - } - } - - // Set status. - if ( ! empty( $request['status'] ) ) { - $object->set_status( $request['status'] ); - } - - $object->save(); - - // Actions for after the order is saved. - if ( true === $request['set_paid'] ) { - if ( $creating || $object->needs_payment() ) { - $object->payment_complete( $request['transaction_id'] ); - } - } - - return $this->get_object( $object->get_id() ); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Update address. - * - * @param WC_Order $order Order data. - * @param array $posted Posted data. - * @param string $type Address type. - */ - protected function update_address( $order, $posted, $type = 'billing' ) { - foreach ( $posted as $key => $value ) { - if ( is_callable( array( $order, "set_{$type}_{$key}" ) ) ) { - $order->{"set_{$type}_{$key}"}( $value ); - } - } - } - - /** - * Gets the product ID from the SKU or posted ID. - * - * @throws WC_REST_Exception When SKU or ID is not valid. - * @param array $posted Request data. - * @param string $action 'create' to add line item or 'update' to update it. - * @return int - */ - protected function get_product_id( $posted, $action = 'create' ) { - if ( ! empty( $posted['sku'] ) ) { - $product_id = (int) wc_get_product_id_by_sku( $posted['sku'] ); - } elseif ( ! empty( $posted['product_id'] ) && empty( $posted['variation_id'] ) ) { - $product_id = (int) $posted['product_id']; - } elseif ( ! empty( $posted['variation_id'] ) ) { - $product_id = (int) $posted['variation_id']; - } elseif ( 'update' === $action ) { - $product_id = 0; - } else { - throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or SKU is required.', 'woocommerce-rest-api' ), 400 ); - } - return $product_id; - } - - /** - * Maybe set an item prop if the value was posted. - * - * @param WC_Order_Item $item Order item. - * @param string $prop Order property. - * @param array $posted Request data. - */ - protected function maybe_set_item_prop( $item, $prop, $posted ) { - if ( isset( $posted[ $prop ] ) ) { - $item->{"set_$prop"}( $posted[ $prop ] ); - } - } - - /** - * Maybe set item props if the values were posted. - * - * @param WC_Order_Item $item Order item data. - * @param string[] $props Properties. - * @param array $posted Request data. - */ - protected function maybe_set_item_props( $item, $props, $posted ) { - foreach ( $props as $prop ) { - $this->maybe_set_item_prop( $item, $prop, $posted ); - } - } - - /** - * Maybe set item meta if posted. - * - * @param WC_Order_Item $item Order item data. - * @param array $posted Request data. - */ - protected function maybe_set_item_meta_data( $item, $posted ) { - if ( ! empty( $posted['meta_data'] ) && is_array( $posted['meta_data'] ) ) { - foreach ( $posted['meta_data'] as $meta ) { - if ( isset( $meta['key'] ) ) { - $value = isset( $meta['value'] ) ? $meta['value'] : null; - $item->update_meta_data( $meta['key'], $value, isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - } - } - - /** - * Create or update a line item. - * - * @param array $posted Line item data. - * @param string $action 'create' to add line item or 'update' to update it. - * @param object $item Passed when updating an item. Null during creation. - * @return WC_Order_Item_Product - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_line_items( $posted, $action = 'create', $item = null ) { - $item = is_null( $item ) ? new WC_Order_Item_Product( ! empty( $posted['id'] ) ? $posted['id'] : '' ) : $item; - $product = wc_get_product( $this->get_product_id( $posted, $action ) ); - - if ( $product && $product !== $item->get_product() ) { - $item->set_product( $product ); - - if ( 'create' === $action ) { - $quantity = isset( $posted['quantity'] ) ? $posted['quantity'] : 1; - $total = wc_get_price_excluding_tax( $product, array( 'qty' => $quantity ) ); - $item->set_total( $total ); - $item->set_subtotal( $total ); - } - } - - $this->maybe_set_item_props( $item, array( 'name', 'quantity', 'total', 'subtotal', 'tax_class' ), $posted ); - $this->maybe_set_item_meta_data( $item, $posted ); - - return $item; - } - - /** - * Create or update an order shipping method. - * - * @param array $posted $shipping Item data. - * @param string $action 'create' to add shipping or 'update' to update it. - * @param object $item Passed when updating an item. Null during creation. - * @return WC_Order_Item_Shipping - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_shipping_lines( $posted, $action = 'create', $item = null ) { - $item = is_null( $item ) ? new WC_Order_Item_Shipping( ! empty( $posted['id'] ) ? $posted['id'] : '' ) : $item; - - if ( 'create' === $action ) { - if ( empty( $posted['method_id'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_item', __( 'Shipping method ID is required.', 'woocommerce-rest-api' ), 400 ); - } - } - - $this->maybe_set_item_props( $item, array( 'method_id', 'method_title', 'total', 'instance_id' ), $posted ); - $this->maybe_set_item_meta_data( $item, $posted ); - - return $item; - } - - /** - * Create or update an order fee. - * - * @param array $posted Item data. - * @param string $action 'create' to add fee or 'update' to update it. - * @param object $item Passed when updating an item. Null during creation. - * @return WC_Order_Item_Fee - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_fee_lines( $posted, $action = 'create', $item = null ) { - $item = is_null( $item ) ? new WC_Order_Item_Fee( ! empty( $posted['id'] ) ? $posted['id'] : '' ) : $item; - - if ( 'create' === $action ) { - if ( empty( $posted['name'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_fee_item', __( 'Fee name is required.', 'woocommerce-rest-api' ), 400 ); - } - } - - $this->maybe_set_item_props( $item, array( 'name', 'tax_class', 'tax_status', 'total' ), $posted ); - $this->maybe_set_item_meta_data( $item, $posted ); - - return $item; - } - - /** - * Create or update an order coupon. - * - * @param array $posted Item data. - * @param string $action 'create' to add coupon or 'update' to update it. - * @param object $item Passed when updating an item. Null during creation. - * @return WC_Order_Item_Coupon - * @throws WC_REST_Exception Invalid data, server error. - */ - protected function prepare_coupon_lines( $posted, $action = 'create', $item = null ) { - $item = is_null( $item ) ? new WC_Order_Item_Coupon( ! empty( $posted['id'] ) ? $posted['id'] : '' ) : $item; - - if ( 'create' === $action ) { - if ( empty( $posted['code'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_coupon', __( 'Coupon code is required.', 'woocommerce-rest-api' ), 400 ); - } - } - - $this->maybe_set_item_props( $item, array( 'code', 'discount' ), $posted ); - $this->maybe_set_item_meta_data( $item, $posted ); - - return $item; - } - - /** - * Wrapper method to create/update order items. - * When updating, the item ID provided is checked to ensure it is associated - * with the order. - * - * @param WC_Order $order order object. - * @param string $item_type The item type. - * @param array $posted item provided in the request body. - * @throws WC_REST_Exception If item ID is not associated with order. - */ - protected function set_item( $order, $item_type, $posted ) { - global $wpdb; - - if ( ! empty( $posted['id'] ) ) { - $action = 'update'; - } else { - $action = 'create'; - } - - $method = 'prepare_' . $item_type; - $item = null; - - // Verify provided line item ID is associated with order. - if ( 'update' === $action ) { - $item = $order->get_item( absint( $posted['id'] ), false ); - - if ( ! $item ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_item_id', __( 'Order item ID provided is not associated with order.', 'woocommerce-rest-api' ), 400 ); - } - } - - // Prepare item data. - $item = $this->$method( $posted, $action, $item ); - - do_action( 'woocommerce_rest_set_order_item', $item, $posted ); - - // If creating the order, add the item to it. - if ( 'create' === $action ) { - $order->add_item( $item ); - } else { - $item->save(); - } - } - - /** - * Helper method to check if the resource ID associated with the provided item is null. - * Items can be deleted by setting the resource ID to null. - * - * @param array $item Item provided in the request body. - * @return bool True if the item resource ID is null, false otherwise. - */ - protected function item_is_null( $item ) { - $keys = array( 'product_id', 'method_id', 'method_title', 'name', 'code' ); - - foreach ( $keys as $key ) { - if ( array_key_exists( $key, $item ) && is_null( $item[ $key ] ) ) { - return true; - } - } - - return false; - } - - /** - * Get order statuses without prefixes. - * - * @return array - */ - protected function get_order_statuses() { - $order_statuses = array(); - - foreach ( array_keys( wc_get_order_statuses() ) as $status ) { - $order_statuses[] = str_replace( 'wc-', '', $status ); - } - - return $order_statuses; - } - - /** - * Get the Order's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'parent_id' => array( - 'description' => __( 'Parent order ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'number' => array( - 'description' => __( 'Order number.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'order_key' => array( - 'description' => __( 'Order key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'created_via' => array( - 'description' => __( 'Shows where the order was created.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'version' => array( - 'description' => __( 'Version of WooCommerce which last updated the order.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'status' => array( - 'description' => __( 'Order status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'pending', - 'enum' => $this->get_order_statuses(), - 'context' => array( 'view', 'edit' ), - ), - 'currency' => array( - 'description' => __( 'Currency the order was created with, in ISO format.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => get_woocommerce_currency(), - 'enum' => array_keys( get_woocommerce_currencies() ), - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the order was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the order was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the order was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the order was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'discount_total' => array( - 'description' => __( 'Total discount amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'discount_tax' => array( - 'description' => __( 'Total discount tax amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_total' => array( - 'description' => __( 'Total shipping amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_tax' => array( - 'description' => __( 'Total shipping tax amount for the order.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'cart_tax' => array( - 'description' => __( 'Sum of line item taxes only.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Grand total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_tax' => array( - 'description' => __( 'Sum of all taxes.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'prices_include_tax' => array( - 'description' => __( 'True the prices included tax during checkout.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'customer_id' => array( - 'description' => __( 'User ID who owns the order. 0 for guests.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => 0, - 'context' => array( 'view', 'edit' ), - ), - 'customer_ip_address' => array( - 'description' => __( "Customer's IP address.", 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'customer_user_agent' => array( - 'description' => __( 'User agent of the customer.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'customer_note' => array( - 'description' => __( 'Note left by customer during checkout.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'billing' => array( - 'description' => __( 'Billing address.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email' => array( - 'description' => __( 'Email address.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'phone' => array( - 'description' => __( 'Phone number.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping' => array( - 'description' => __( 'Shipping address.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'payment_method' => array( - 'description' => __( 'Payment method ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'payment_method_title' => array( - 'description' => __( 'Payment method title.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'transaction_id' => array( - 'description' => __( 'Unique transaction ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_paid' => array( - 'description' => __( "The date the order was paid, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_paid_gmt' => array( - 'description' => __( 'The date the order was paid, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_completed' => array( - 'description' => __( "The date the order was completed, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_completed_gmt' => array( - 'description' => __( 'The date the order was completed, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'cart_hash' => array( - 'description' => __( 'MD5 hash of cart items to ensure orders are not modified.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'line_items' => array( - 'description' => __( 'Line items data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'product_id' => array( - 'description' => __( 'Product ID.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'variation_id' => array( - 'description' => __( 'Variation ID, if applicable.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'quantity' => array( - 'description' => __( 'Quantity ordered.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class of product.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'subtotal' => array( - 'description' => __( 'Line subtotal (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'subtotal_tax' => array( - 'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'subtotal' => array( - 'description' => __( 'Tax subtotal.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'sku' => array( - 'description' => __( 'Product SKU.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'price' => array( - 'description' => __( 'Product price.', 'woocommerce-rest-api' ), - 'type' => 'number', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'tax_lines' => array( - 'description' => __( 'Tax lines data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'rate_code' => array( - 'description' => __( 'Tax rate code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'rate_id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'Tax rate label.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'compound' => array( - 'description' => __( 'Show if is a compound tax rate.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tax_total' => array( - 'description' => __( 'Tax total (not including shipping taxes).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_tax_total' => array( - 'description' => __( 'Shipping tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ), - ), - 'shipping_lines' => array( - 'description' => __( 'Shipping lines data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'method_title' => array( - 'description' => __( 'Shipping method name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'method_id' => array( - 'description' => __( 'Shipping method ID.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'instance_id' => array( - 'description' => __( 'Shipping instance ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ), - ), - 'fee_lines' => array( - 'description' => __( 'Fee lines data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Fee name.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class of fee.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status of fee.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'enum' => array( 'taxable', 'none' ), - ), - 'total' => array( - 'description' => __( 'Line total (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'total_tax' => array( - 'description' => __( 'Line total tax (after discounts).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'taxes' => array( - 'description' => __( 'Line taxes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tax rate ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Tax total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'subtotal' => array( - 'description' => __( 'Tax subtotal.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ), - ), - 'coupon_lines' => array( - 'description' => __( 'Coupons line data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Item ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'code' => array( - 'description' => __( 'Coupon code.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'discount' => array( - 'description' => __( 'Discount total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'discount_tax' => array( - 'description' => __( 'Discount total tax.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ), - ), - 'refunds' => array( - 'description' => __( 'List of refunds.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Refund ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'reason' => array( - 'description' => __( 'Refund reason.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Refund total.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'set_paid' => array( - 'description' => __( 'Define if the order is paid. It will set the status to processing and reduce stock items.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['status'] = array( - 'default' => 'any', - 'description' => __( 'Limit result set to orders assigned a specific status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_merge( array( 'any', 'trash' ), $this->get_order_statuses() ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['customer'] = array( - 'description' => __( 'Limit result set to orders assigned a specific customer.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['product'] = array( - 'description' => __( 'Limit result set to orders assigned a specific product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['dp'] = array( - 'default' => wc_get_price_decimals(), - 'description' => __( 'Number of decimal points to use in each resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version2/class-wc-rest-payment-gateways-v2-controller.php b/src/Controllers/Version2/class-wc-rest-payment-gateways-v2-controller.php deleted file mode 100644 index a652ea1fab3..00000000000 --- a/src/Controllers/Version2/class-wc-rest-payment-gateways-v2-controller.php +++ /dev/null @@ -1,466 +0,0 @@ - - */ - public function register_routes() { - register_rest_route( - $this->namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Check whether a given request has permission to view payment gateways. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'payment_gateways', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to read a payment gateway. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'payment_gateways', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check whether a given request has permission to edit payment gateways. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'payment_gateways', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Get payment gateways. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $payment_gateways = WC()->payment_gateways->payment_gateways(); - $response = array(); - foreach ( $payment_gateways as $payment_gateway_id => $payment_gateway ) { - $payment_gateway->id = $payment_gateway_id; - $gateway = $this->prepare_item_for_response( $payment_gateway, $request ); - $gateway = $this->prepare_response_for_collection( $gateway ); - $response[] = $gateway; - } - return rest_ensure_response( $response ); - } - - /** - * Get a single payment gateway. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function get_item( $request ) { - $gateway = $this->get_gateway( $request ); - - if ( is_null( $gateway ) ) { - return new WP_Error( 'woocommerce_rest_payment_gateway_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $gateway = $this->prepare_item_for_response( $gateway, $request ); - return rest_ensure_response( $gateway ); - } - - /** - * Update A Single Payment Method. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function update_item( $request ) { - $gateway = $this->get_gateway( $request ); - - if ( is_null( $gateway ) ) { - return new WP_Error( 'woocommerce_rest_payment_gateway_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - // Get settings. - $gateway->init_form_fields(); - $settings = $gateway->settings; - - // Update settings. - if ( isset( $request['settings'] ) ) { - $errors_found = false; - foreach ( $gateway->form_fields as $key => $field ) { - if ( isset( $request['settings'][ $key ] ) ) { - if ( is_callable( array( $this, 'validate_setting_' . $field['type'] . '_field' ) ) ) { - $value = $this->{'validate_setting_' . $field['type'] . '_field'}( $request['settings'][ $key ], $field ); - } else { - $value = $this->validate_setting_text_field( $request['settings'][ $key ], $field ); - } - if ( is_wp_error( $value ) ) { - $errors_found = true; - break; - } - $settings[ $key ] = $value; - } - } - - if ( $errors_found ) { - return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - } - - // Update if this method is enabled or not. - if ( isset( $request['enabled'] ) ) { - $settings['enabled'] = wc_bool_to_string( $request['enabled'] ); - $gateway->enabled = $settings['enabled']; - } - - // Update title. - if ( isset( $request['title'] ) ) { - $settings['title'] = $request['title']; - $gateway->title = $settings['title']; - } - - // Update description. - if ( isset( $request['description'] ) ) { - $settings['description'] = $request['description']; - $gateway->description = $settings['description']; - } - - // Update options. - $gateway->settings = $settings; - update_option( $gateway->get_option_key(), apply_filters( 'woocommerce_gateway_' . $gateway->id . '_settings_values', $settings, $gateway ) ); - - // Update order. - if ( isset( $request['order'] ) ) { - $order = (array) get_option( 'woocommerce_gateway_order' ); - $order[ $gateway->id ] = $request['order']; - update_option( 'woocommerce_gateway_order', $order ); - $gateway->order = absint( $request['order'] ); - } - - $gateway = $this->prepare_item_for_response( $gateway, $request ); - return rest_ensure_response( $gateway ); - } - - /** - * Get a gateway based on the current request object. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|null - */ - public function get_gateway( $request ) { - $gateway = null; - $payment_gateways = WC()->payment_gateways->payment_gateways(); - foreach ( $payment_gateways as $payment_gateway_id => $payment_gateway ) { - if ( $request['id'] !== $payment_gateway_id ) { - continue; - } - $payment_gateway->id = $payment_gateway_id; - $gateway = $payment_gateway; - } - return $gateway; - } - - /** - * Prepare a payment gateway for response. - * - * @param WC_Payment_Gateway $gateway Payment gateway object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $gateway, $request ) { - $order = (array) get_option( 'woocommerce_gateway_order' ); - $item = array( - 'id' => $gateway->id, - 'title' => $gateway->title, - 'description' => $gateway->description, - 'order' => isset( $order[ $gateway->id ] ) ? $order[ $gateway->id ] : '', - 'enabled' => ( 'yes' === $gateway->enabled ), - 'method_title' => $gateway->get_method_title(), - 'method_description' => $gateway->get_method_description(), - 'settings' => $this->get_settings( $gateway ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $gateway, $request ) ); - - /** - * Filter payment gateway objects returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WC_Payment_Gateway $gateway Payment gateway object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_payment_gateway', $response, $gateway, $request ); - } - - /** - * Return settings associated with this payment gateway. - * - * @param WC_Payment_Gateway $gateway Gateway data. - * - * @return array - */ - public function get_settings( $gateway ) { - $settings = array(); - $gateway->init_form_fields(); - foreach ( $gateway->form_fields as $id => $field ) { - // Make sure we at least have a title and type. - if ( empty( $field['title'] ) || empty( $field['type'] ) ) { - continue; - } - // Ignore 'title' settings/fields -- they are UI only. - if ( 'title' === $field['type'] ) { - continue; - } - // Ignore 'enabled' and 'description' which get included elsewhere. - if ( in_array( $id, array( 'enabled', 'description' ), true ) ) { - continue; - } - $data = array( - 'id' => $id, - 'label' => empty( $field['label'] ) ? $field['title'] : $field['label'], - 'description' => empty( $field['description'] ) ? '' : $field['description'], - 'type' => $field['type'], - 'value' => empty( $gateway->settings[ $id ] ) ? '' : $gateway->settings[ $id ], - 'default' => empty( $field['default'] ) ? '' : $field['default'], - 'tip' => empty( $field['description'] ) ? '' : $field['description'], - 'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'], - ); - if ( ! empty( $field['options'] ) ) { - $data['options'] = $field['options']; - } - $settings[ $id ] = $data; - } - return $settings; - } - - /** - * Prepare links for the request. - * - * @param WC_Payment_Gateway $gateway Payment gateway object. - * @param WP_REST_Request $request Request object. - * @return array - */ - protected function prepare_links( $gateway, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $gateway->id ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the payment gateway schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'payment_gateway', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Payment gateway ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'title' => array( - 'description' => __( 'Payment gateway title on checkout.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'Payment gateway description on checkout.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'order' => array( - 'description' => __( 'Payment gateway sort order.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'absint', - ), - ), - 'enabled' => array( - 'description' => __( 'Payment gateway enabled status.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - ), - 'method_title' => array( - 'description' => __( 'Payment gateway method title.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'method_description' => array( - 'description' => __( 'Payment gateway method description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'settings' => array( - 'description' => __( 'Payment gateway settings.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Type of setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'enum' => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Setting value.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'default' => array( - 'description' => __( 'Default value for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tip' => array( - 'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'placeholder' => array( - 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get any query params needed. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } - -} diff --git a/src/Controllers/Version2/class-wc-rest-product-attribute-terms-v2-controller.php b/src/Controllers/Version2/class-wc-rest-product-attribute-terms-v2-controller.php deleted file mode 100644 index 27d71b11c10..00000000000 --- a/src/Controllers/Version2/class-wc-rest-product-attribute-terms-v2-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/terms endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Product Attribute Terms controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Product_Attribute_Terms_V1_Controller - */ -class WC_REST_Product_Attribute_Terms_V2_Controller extends WC_REST_Product_Attribute_Terms_V1_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v2'; -} diff --git a/src/Controllers/Version2/class-wc-rest-product-attributes-v2-controller.php b/src/Controllers/Version2/class-wc-rest-product-attributes-v2-controller.php deleted file mode 100644 index 3ff18b310a2..00000000000 --- a/src/Controllers/Version2/class-wc-rest-product-attributes-v2-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -term_id, 'display_type', true ); - - // Get category order. - $menu_order = get_term_meta( $item->term_id, 'order', true ); - - $data = array( - 'id' => (int) $item->term_id, - 'name' => $item->name, - 'slug' => $item->slug, - 'parent' => (int) $item->parent, - 'description' => $item->description, - 'display' => $display_type ? $display_type : 'default', - 'image' => null, - 'menu_order' => (int) $menu_order, - 'count' => (int) $item->count, - ); - - // Get category image. - $image_id = get_term_meta( $item->term_id, 'thumbnail_id', true ); - if ( $image_id ) { - $attachment = get_post( $image_id ); - - $data['image'] = array( - 'id' => (int) $image_id, - 'date_created' => wc_rest_prepare_date_response( $attachment->post_date ), - 'date_created_gmt' => wc_rest_prepare_date_response( $attachment->post_date_gmt ), - 'date_modified' => wc_rest_prepare_date_response( $attachment->post_modified ), - 'date_modified_gmt' => wc_rest_prepare_date_response( $attachment->post_modified_gmt ), - 'src' => wp_get_attachment_url( $image_id ), - 'title' => get_the_title( $attachment ), - 'alt' => get_post_meta( $image_id, '_wp_attachment_image_alt', true ), - ); - } - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item, $request ) ); - - /** - * Filter a term item returned from the API. - * - * Allows modification of the term data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $item The original term object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->taxonomy}", $response, $item, $request ); - } - - /** - * Get the Category schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->taxonomy, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Category name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'parent' => array( - 'description' => __( 'The ID for the parent of the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'HTML description of the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), - ), - 'display' => array( - 'description' => __( 'Category archive display type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'default', - 'enum' => array( 'default', 'products', 'subcategories', 'both' ), - 'context' => array( 'view', 'edit' ), - ), - 'image' => array( - 'description' => __( 'Image data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the image was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the image was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'title' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'count' => array( - 'description' => __( 'Number of published products for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-product-reviews-v2-controller.php b/src/Controllers/Version2/class-wc-rest-product-reviews-v2-controller.php deleted file mode 100644 index a90d4ad232e..00000000000 --- a/src/Controllers/Version2/class-wc-rest-product-reviews-v2-controller.php +++ /dev/null @@ -1,199 +0,0 @@ -/reviews. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Product Reviews Controller Class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Product_Reviews_V1_Controller - */ -class WC_REST_Product_Reviews_V2_Controller extends WC_REST_Product_Reviews_V1_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v2'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'products/(?P[\d]+)/reviews'; - - /** - * Register the routes for product reviews. - */ - public function register_routes() { - parent::register_routes(); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/batch', array( - 'args' => array( - 'product_id' => array( - 'description' => __( 'Unique identifier for the variable product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - } - - /** - * Check if a given request has access to batch manage product reviews. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function batch_items_permissions_check( $request ) { - if ( ! wc_rest_check_post_permissions( 'product', 'batch' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Prepare a single product review output for response. - * - * @param WP_Comment $review Product review object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $review, $request ) { - $data = array( - 'id' => (int) $review->comment_ID, - 'date_created' => wc_rest_prepare_date_response( $review->comment_date ), - 'date_created_gmt' => wc_rest_prepare_date_response( $review->comment_date_gmt ), - 'review' => $review->comment_content, - 'rating' => (int) get_comment_meta( $review->comment_ID, 'rating', true ), - 'name' => $review->comment_author, - 'email' => $review->comment_author_email, - 'verified' => wc_review_is_from_verified_owner( $review->comment_ID ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $review, $request ) ); - - /** - * Filter product reviews object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_Comment $review Product review object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_product_review', $response, $review, $request ); - } - - - /** - * Bulk create, update and delete items. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array Of WP_Error or WP_REST_Response. - */ - public function batch_items( $request ) { - $items = array_filter( $request->get_params() ); - $params = $request->get_url_params(); - $product_id = $params['product_id']; - $body_params = array(); - - foreach ( array( 'update', 'create', 'delete' ) as $batch_type ) { - if ( ! empty( $items[ $batch_type ] ) ) { - $injected_items = array(); - foreach ( $items[ $batch_type ] as $item ) { - $injected_items[] = is_array( $item ) ? array_merge( array( 'product_id' => $product_id ), $item ) : $item; - } - $body_params[ $batch_type ] = $injected_items; - } - } - - $request = new WP_REST_Request( $request->get_method() ); - $request->set_body_params( $body_params ); - - return parent::batch_items( $request ); - } - - /** - * Get the Product Review's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'product_review', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'review' => array( - 'description' => __( 'The content of the review.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the review was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the review was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'rating' => array( - 'description' => __( 'Review rating (0 to 5).', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Reviewer name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email' => array( - 'description' => __( 'Reviewer email.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'verified' => array( - 'description' => __( 'Shows if the reviewer bought the product or not.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-product-shipping-classes-v2-controller.php b/src/Controllers/Version2/class-wc-rest-product-shipping-classes-v2-controller.php deleted file mode 100644 index 6430ded093f..00000000000 --- a/src/Controllers/Version2/class-wc-rest-product-shipping-classes-v2-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/variations endpoints. - * - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API variations controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Products_V2_Controller - */ -class WC_REST_Product_Variations_V2_Controller extends WC_REST_Products_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v2'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = 'products/(?P[\d]+)/variations'; - - /** - * Post type. - * - * @var string - */ - protected $post_type = 'product_variation'; - - /** - * Register the routes for products. - */ - public function register_routes() { - register_rest_route( - $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'product_id' => array( - 'description' => __( 'Unique identifier for the variable product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'product_id' => array( - 'description' => __( 'Unique identifier for the variable product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'id' => array( - 'description' => __( 'Unique identifier for the variation.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( - array( - 'default' => 'view', - ) - ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/batch', array( - 'args' => array( - 'product_id' => array( - 'description' => __( 'Unique identifier for the variable product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - } - - /** - * Get object. - * - * @since 3.0.0 - * @param int $id Object ID. - * @return WC_Data - */ - protected function get_object( $id ) { - return wc_get_product( $id ); - } - - /** - * Check if a given request has access to update an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - $object = $this->get_object( (int) $request['id'] ); - - if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'edit', $object->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - // Check if variation belongs to the correct parent product. - if ( $object && 0 !== $object->get_parent_id() && absint( $request['product_id'] ) !== $object->get_parent_id() ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Parent product does not match current variation.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Prepare a single variation output for response. - * - * @since 3.0.0 - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function prepare_object_for_response( $object, $request ) { - $data = array( - 'id' => $object->get_id(), - 'date_created' => wc_rest_prepare_date_response( $object->get_date_created(), false ), - 'date_created_gmt' => wc_rest_prepare_date_response( $object->get_date_created() ), - 'date_modified' => wc_rest_prepare_date_response( $object->get_date_modified(), false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( $object->get_date_modified() ), - 'description' => wc_format_content( $object->get_description() ), - 'permalink' => $object->get_permalink(), - 'sku' => $object->get_sku(), - 'price' => $object->get_price(), - 'regular_price' => $object->get_regular_price(), - 'sale_price' => $object->get_sale_price(), - 'date_on_sale_from' => wc_rest_prepare_date_response( $object->get_date_on_sale_from(), false ), - 'date_on_sale_from_gmt' => wc_rest_prepare_date_response( $object->get_date_on_sale_from() ), - 'date_on_sale_to' => wc_rest_prepare_date_response( $object->get_date_on_sale_to(), false ), - 'date_on_sale_to_gmt' => wc_rest_prepare_date_response( $object->get_date_on_sale_to() ), - 'on_sale' => $object->is_on_sale(), - 'visible' => $object->is_visible(), - 'purchasable' => $object->is_purchasable(), - 'virtual' => $object->is_virtual(), - 'downloadable' => $object->is_downloadable(), - 'downloads' => $this->get_downloads( $object ), - 'download_limit' => '' !== $object->get_download_limit() ? (int) $object->get_download_limit() : -1, - 'download_expiry' => '' !== $object->get_download_expiry() ? (int) $object->get_download_expiry() : -1, - 'tax_status' => $object->get_tax_status(), - 'tax_class' => $object->get_tax_class(), - 'manage_stock' => $object->managing_stock(), - 'stock_quantity' => $object->get_stock_quantity(), - 'in_stock' => $object->is_in_stock(), - 'backorders' => $object->get_backorders(), - 'backorders_allowed' => $object->backorders_allowed(), - 'backordered' => $object->is_on_backorder(), - 'weight' => $object->get_weight(), - 'dimensions' => array( - 'length' => $object->get_length(), - 'width' => $object->get_width(), - 'height' => $object->get_height(), - ), - 'shipping_class' => $object->get_shipping_class(), - 'shipping_class_id' => $object->get_shipping_class_id(), - 'image' => current( $this->get_images( $object ) ), - 'attributes' => $this->get_attributes( $object ), - 'menu_order' => $object->get_menu_order(), - 'meta_data' => $object->get_meta_data(), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $object, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, - * refers to object type being prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request ); - } - - /** - * Prepare objects query. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array - */ - protected function prepare_objects_query( $request ) { - $args = parent::prepare_objects_query( $request ); - - $args['post_parent'] = $request['product_id']; - - return $args; - } - - /** - * Prepare a single variation for create or update. - * - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data - */ - protected function prepare_object_for_database( $request, $creating = false ) { - if ( isset( $request['id'] ) ) { - $variation = wc_get_product( absint( $request['id'] ) ); - } else { - $variation = new WC_Product_Variation(); - } - - // Update parent ID just once. - if ( 0 === $variation->get_parent_id() ) { - $variation->set_parent_id( absint( $request['product_id'] ) ); - } - - // Status. - if ( isset( $request['visible'] ) ) { - $variation->set_status( false === $request['visible'] ? 'private' : 'publish' ); - } - - // SKU. - if ( isset( $request['sku'] ) ) { - $variation->set_sku( wc_clean( $request['sku'] ) ); - } - - // Thumbnail. - if ( isset( $request['image'] ) ) { - if ( is_array( $request['image'] ) && ! empty( $request['image'] ) ) { - $image = $request['image']; - if ( is_array( $image ) ) { - $image['position'] = 0; - } - - $variation = $this->set_product_images( $variation, array( $image ) ); - } else { - $variation->set_image_id( '' ); - } - } - - // Virtual variation. - if ( isset( $request['virtual'] ) ) { - $variation->set_virtual( $request['virtual'] ); - } - - // Downloadable variation. - if ( isset( $request['downloadable'] ) ) { - $variation->set_downloadable( $request['downloadable'] ); - } - - // Downloads. - if ( $variation->get_downloadable() ) { - // Downloadable files. - if ( isset( $request['downloads'] ) && is_array( $request['downloads'] ) ) { - $variation = $this->save_downloadable_files( $variation, $request['downloads'] ); - } - - // Download limit. - if ( isset( $request['download_limit'] ) ) { - $variation->set_download_limit( $request['download_limit'] ); - } - - // Download expiry. - if ( isset( $request['download_expiry'] ) ) { - $variation->set_download_expiry( $request['download_expiry'] ); - } - } - - // Shipping data. - $variation = $this->save_product_shipping_data( $variation, $request ); - - // Stock handling. - if ( isset( $request['manage_stock'] ) ) { - if ( 'parent' === $request['manage_stock'] ) { - $variation->set_manage_stock( false ); // This just indicates the variation does not manage stock, but the parent does. - } else { - $variation->set_manage_stock( wc_string_to_bool( $request['manage_stock'] ) ); - } - } - - if ( isset( $request['in_stock'] ) ) { - $variation->set_stock_status( true === $request['in_stock'] ? 'instock' : 'outofstock' ); - } - - if ( isset( $request['backorders'] ) ) { - $variation->set_backorders( $request['backorders'] ); - } - - if ( $variation->get_manage_stock() ) { - if ( isset( $request['stock_quantity'] ) ) { - $variation->set_stock_quantity( $request['stock_quantity'] ); - } elseif ( isset( $request['inventory_delta'] ) ) { - $stock_quantity = wc_stock_amount( $variation->get_stock_quantity() ); - $stock_quantity += wc_stock_amount( $request['inventory_delta'] ); - $variation->set_stock_quantity( $stock_quantity ); - } - } else { - $variation->set_backorders( 'no' ); - $variation->set_stock_quantity( '' ); - } - - // Regular Price. - if ( isset( $request['regular_price'] ) ) { - $variation->set_regular_price( $request['regular_price'] ); - } - - // Sale Price. - if ( isset( $request['sale_price'] ) ) { - $variation->set_sale_price( $request['sale_price'] ); - } - - if ( isset( $request['date_on_sale_from'] ) ) { - $variation->set_date_on_sale_from( $request['date_on_sale_from'] ); - } - - if ( isset( $request['date_on_sale_from_gmt'] ) ) { - $variation->set_date_on_sale_from( $request['date_on_sale_from_gmt'] ? strtotime( $request['date_on_sale_from_gmt'] ) : null ); - } - - if ( isset( $request['date_on_sale_to'] ) ) { - $variation->set_date_on_sale_to( $request['date_on_sale_to'] ); - } - - if ( isset( $request['date_on_sale_to_gmt'] ) ) { - $variation->set_date_on_sale_to( $request['date_on_sale_to_gmt'] ? strtotime( $request['date_on_sale_to_gmt'] ) : null ); - } - - // Tax class. - if ( isset( $request['tax_class'] ) ) { - $variation->set_tax_class( $request['tax_class'] ); - } - - // Description. - if ( isset( $request['description'] ) ) { - $variation->set_description( wp_kses_post( $request['description'] ) ); - } - - // Update taxonomies. - if ( isset( $request['attributes'] ) ) { - $attributes = array(); - $parent = wc_get_product( $variation->get_parent_id() ); - $parent_attributes = $parent->get_attributes(); - - foreach ( $request['attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $raw_attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $raw_attribute_name = sanitize_title( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $raw_attribute_name ) { - continue; - } - - $attribute_name = sanitize_title( $raw_attribute_name ); - - if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) { - continue; - } - - $attribute_key = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() ); - $attribute_value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : ''; - - if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) { - // If dealing with a taxonomy, we need to get the slug from the name posted to the API. - $term = get_term_by( 'name', $attribute_value, $raw_attribute_name ); // @codingStandardsIgnoreLine - - if ( $term && ! is_wp_error( $term ) ) { - $attribute_value = $term->slug; - } else { - $attribute_value = sanitize_title( $attribute_value ); - } - } - - $attributes[ $attribute_key ] = $attribute_value; - } - - $variation->set_attributes( $attributes ); - } - - // Menu order. - if ( $request['menu_order'] ) { - $variation->set_menu_order( $request['menu_order'] ); - } - - // Meta data. - if ( is_array( $request['meta_data'] ) ) { - foreach ( $request['meta_data'] as $meta ) { - $variation->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $variation Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $variation, $request, $creating ); - } - - /** - * Clear caches here so in sync with any new variations. - * - * @param WC_Data $object Object data. - */ - public function clear_transients( $object ) { - wc_delete_product_transients( $object->get_parent_id() ); - wp_cache_delete( 'product-' . $object->get_parent_id(), 'products' ); - } - - /** - * Delete a variation. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return bool|WP_Error|WP_REST_Response - */ - public function delete_item( $request ) { - $force = (bool) $request['force']; - $object = $this->get_object( (int) $request['id'] ); - $result = false; - - if ( ! $object || 0 === $object->get_id() ) { - return new WP_Error( - "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce-rest-api' ), array( - 'status' => 404, - ) - ); - } - - $supports_trash = EMPTY_TRASH_DAYS > 0 && is_callable( array( $object, 'get_status' ) ); - - /** - * Filter whether an object is trashable. - * - * Return false to disable trash support for the object. - * - * @param boolean $supports_trash Whether the object type support trashing. - * @param WC_Data $object The object being considered for trashing support. - */ - $supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object ); - - if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) { - return new WP_Error( - /* translators: %s: post type */ - "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce-rest-api' ), $this->post_type ), array( - 'status' => rest_authorization_required_code(), - ) - ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_object_for_response( $object, $request ); - - // If we're forcing, then delete permanently. - if ( $force ) { - $object->delete( true ); - $result = 0 === $object->get_id(); - } else { - // If we don't support trashing for this type, error out. - if ( ! $supports_trash ) { - return new WP_Error( - /* translators: %s: post type */ - 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce-rest-api' ), $this->post_type ), array( - 'status' => 501, - ) - ); - } - - // Otherwise, only trash if we haven't already. - if ( is_callable( array( $object, 'get_status' ) ) ) { - if ( 'trash' === $object->get_status() ) { - return new WP_Error( - /* translators: %s: post type */ - 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( - 'status' => 410, - ) - ); - } - - $object->delete(); - $result = 'trash' === $object->get_status(); - } - } - - if ( ! $result ) { - return new WP_Error( - /* translators: %s: post type */ - 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( - 'status' => 500, - ) - ); - } - - // Delete parent product transients. - if ( 0 !== $object->get_parent_id() ) { - wc_delete_product_transients( $object->get_parent_id() ); - } - - /** - * Fires after a single object is deleted or trashed via the REST API. - * - * @param WC_Data $object The deleted or trashed object. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( "woocommerce_rest_delete_{$this->post_type}_object", $object, $response, $request ); - - return $response; - } - - /** - * Bulk create, update and delete items. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array Of WP_Error or WP_REST_Response. - */ - public function batch_items( $request ) { - $items = array_filter( $request->get_params() ); - $params = $request->get_url_params(); - $query = $request->get_query_params(); - $product_id = $params['product_id']; - $body_params = array(); - - foreach ( array( 'update', 'create', 'delete' ) as $batch_type ) { - if ( ! empty( $items[ $batch_type ] ) ) { - $injected_items = array(); - foreach ( $items[ $batch_type ] as $item ) { - $injected_items[] = is_array( $item ) ? array_merge( - array( - 'product_id' => $product_id, - ), $item - ) : $item; - } - $body_params[ $batch_type ] = $injected_items; - } - } - - $request = new WP_REST_Request( $request->get_method() ); - $request->set_body_params( $body_params ); - $request->set_query_params( $query ); - - return parent::batch_items( $request ); - } - - /** - * Prepare links for the request. - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return array Links for the given post. - */ - protected function prepare_links( $object, $request ) { - $product_id = (int) $request['product_id']; - $base = str_replace( '(?P[\d]+)', $product_id, $this->rest_base ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $object->get_id() ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - 'up' => array( - 'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $product_id ) ), - ), - ); - return $links; - } - - /** - * Get the Variation's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $weight_unit = get_option( 'woocommerce_weight_unit' ); - $dimension_unit = get_option( 'woocommerce_dimension_unit' ); - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the variation was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the variation was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'Variation description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'permalink' => array( - 'description' => __( 'Variation URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sku' => array( - 'description' => __( 'Unique identifier.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'price' => array( - 'description' => __( 'Current variation price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'regular_price' => array( - 'description' => __( 'Variation regular price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sale_price' => array( - 'description' => __( 'Variation sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from' => array( - 'description' => __( "Start date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from_gmt' => array( - 'description' => __( 'Start date of sale price, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to' => array( - 'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to_gmt' => array( - 'description' => __( 'End date of sale price, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'on_sale' => array( - 'description' => __( 'Shows if the variation is on sale.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'visible' => array( - 'description' => __( "Define if the variation is visible on the product's page.", 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'purchasable' => array( - 'description' => __( 'Shows if the variation can be bought.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'virtual' => array( - 'description' => __( 'If the variation is virtual.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloadable' => array( - 'description' => __( 'If the variation is downloadable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloads' => array( - 'description' => __( 'List of downloadable files.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'File ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'download_limit' => array( - 'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'download_expiry' => array( - 'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'taxable', - 'enum' => array( 'taxable', 'shipping', 'none' ), - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'manage_stock' => array( - 'description' => __( 'Stock management at variation level.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'stock_quantity' => array( - 'description' => __( 'Stock quantity.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'in_stock' => array( - 'description' => __( 'Controls whether or not the variation is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'backorders' => array( - 'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'no', - 'enum' => array( 'no', 'notify', 'yes' ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders_allowed' => array( - 'description' => __( 'Shows if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'backordered' => array( - 'description' => __( 'Shows if the variation is on backordered.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'weight' => array( - /* translators: %s: weight unit */ - 'description' => sprintf( __( 'Variation weight (%s).', 'woocommerce-rest-api' ), $weight_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'dimensions' => array( - 'description' => __( 'Variation dimensions.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'length' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation length (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'width' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation width (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'height' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation height (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping_class' => array( - 'description' => __( 'Shipping class slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'shipping_class_id' => array( - 'description' => __( 'Shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'image' => array( - 'description' => __( 'Variation image data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the image was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the image was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'position' => array( - 'description' => __( 'Image position. 0 means that the image is featured.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'attributes' => array( - 'description' => __( 'List of attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'option' => array( - 'description' => __( 'Selected attribute term name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort products.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-products-v2-controller.php b/src/Controllers/Version2/class-wc-rest-products-v2-controller.php deleted file mode 100644 index f38ecb7dfb9..00000000000 --- a/src/Controllers/Version2/class-wc-rest-products-v2-controller.php +++ /dev/null @@ -1,2209 +0,0 @@ -post_type}_object", array( $this, 'clear_transients' ) ); - } - - /** - * Register the routes for products. - */ - public function register_routes() { - register_rest_route( - $this->namespace, - '/' . $this->rest_base, - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/(?P[\d]+)', - array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( - array( - 'default' => 'view', - ) - ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/batch', - array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - } - - /** - * Get object. - * - * @param int $id Object ID. - * - * @since 3.0.0 - * @return WC_Data - */ - protected function get_object( $id ) { - return wc_get_product( $id ); - } - - /** - * Prepare a single product output for response. - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * - * @since 3.0.0 - * @return WP_REST_Response - */ - public function prepare_object_for_response( $object, $request ) { - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->get_product_data( $object, $context ); - - // Add variations to variable products. - if ( $object->is_type( 'variable' ) && $object->has_child() ) { - $data['variations'] = $object->get_children(); - } - - // Add grouped products data. - if ( $object->is_type( 'grouped' ) && $object->has_child() ) { - $data['grouped_products'] = $object->get_children(); - } - - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $object, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, - * refers to object type being prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request ); - } - - /** - * Prepare objects query. - * - * @param WP_REST_Request $request Full details about the request. - * - * @since 3.0.0 - * @return array - */ - protected function prepare_objects_query( $request ) { - $args = parent::prepare_objects_query( $request ); - - // Set post_status. - $args['post_status'] = $request['status']; - - // Taxonomy query to filter products by type, category, - // tag, shipping class, and attribute. - $tax_query = array(); - - // Map between taxonomy name and arg's key. - $taxonomies = array( - 'product_cat' => 'category', - 'product_tag' => 'tag', - 'product_shipping_class' => 'shipping_class', - ); - - // Set tax_query for each passed arg. - foreach ( $taxonomies as $taxonomy => $key ) { - if ( ! empty( $request[ $key ] ) ) { - $tax_query[] = array( - 'taxonomy' => $taxonomy, - 'field' => 'term_id', - 'terms' => $request[ $key ], - ); - } - } - - // Filter product type by slug. - if ( ! empty( $request['type'] ) ) { - $tax_query[] = array( - 'taxonomy' => 'product_type', - 'field' => 'slug', - 'terms' => $request['type'], - ); - } - - // Filter by attribute and term. - if ( ! empty( $request['attribute'] ) && ! empty( $request['attribute_term'] ) ) { - if ( in_array( $request['attribute'], wc_get_attribute_taxonomy_names(), true ) ) { - $tax_query[] = array( - 'taxonomy' => $request['attribute'], - 'field' => 'term_id', - 'terms' => $request['attribute_term'], - ); - } - } - - if ( ! empty( $tax_query ) ) { - $args['tax_query'] = $tax_query; // WPCS: slow query ok. - } - - // Filter featured. - if ( is_bool( $request['featured'] ) ) { - $args['tax_query'][] = array( - 'taxonomy' => 'product_visibility', - 'field' => 'name', - 'terms' => 'featured', - 'operator' => true === $request['featured'] ? 'IN' : 'NOT IN', - ); - } - - // Filter by sku. - if ( ! empty( $request['sku'] ) ) { - $skus = explode( ',', $request['sku'] ); - // Include the current string as a SKU too. - if ( 1 < count( $skus ) ) { - $skus[] = $request['sku']; - } - - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, - array( - 'key' => '_sku', - 'value' => $skus, - 'compare' => 'IN', - ) - ); - } - - // Filter by tax class. - if ( ! empty( $request['tax_class'] ) ) { - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, - array( - 'key' => '_tax_class', - 'value' => 'standard' !== $request['tax_class'] ? $request['tax_class'] : '', - ) - ); - } - - // Price filter. - if ( ! empty( $request['min_price'] ) || ! empty( $request['max_price'] ) ) { - $args['meta_query'] = $this->add_meta_query( $args, wc_get_min_max_price_meta_query( $request ) ); // WPCS: slow query ok. - } - - // Filter product in stock or out of stock. - if ( is_bool( $request['in_stock'] ) ) { - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, - array( - 'key' => '_stock_status', - 'value' => true === $request['in_stock'] ? 'instock' : 'outofstock', - ) - ); - } - - // Filter by on sale products. - if ( is_bool( $request['on_sale'] ) ) { - $on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in'; - $on_sale_ids = wc_get_product_ids_on_sale(); - - // Use 0 when there's no on sale products to avoid return all products. - $on_sale_ids = empty( $on_sale_ids ) ? array( 0 ) : $on_sale_ids; - - $args[ $on_sale_key ] += $on_sale_ids; - } - - // Force the post_type argument, since it's not a user input variable. - if ( ! empty( $request['sku'] ) ) { - $args['post_type'] = array( 'product', 'product_variation' ); - } else { - $args['post_type'] = $this->post_type; - } - - return $args; - } - - /** - * Get the downloads for a product or product variation. - * - * @param WC_Product|WC_Product_Variation $product Product instance. - * - * @return array - */ - protected function get_downloads( $product ) { - $downloads = array(); - - if ( $product->is_downloadable() ) { - foreach ( $product->get_downloads() as $file_id => $file ) { - $downloads[] = array( - 'id' => $file_id, // MD5 hash. - 'name' => $file['name'], - 'file' => $file['file'], - ); - } - } - - return $downloads; - } - - /** - * Get taxonomy terms. - * - * @param WC_Product $product Product instance. - * @param string $taxonomy Taxonomy slug. - * - * @return array - */ - protected function get_taxonomy_terms( $product, $taxonomy = 'cat' ) { - $terms = array(); - - foreach ( wc_get_object_terms( $product->get_id(), 'product_' . $taxonomy ) as $term ) { - $terms[] = array( - 'id' => $term->term_id, - 'name' => $term->name, - 'slug' => $term->slug, - ); - } - - return $terms; - } - - /** - * Get the images for a product or product variation. - * - * @param WC_Product|WC_Product_Variation $product Product instance. - * - * @return array - */ - protected function get_images( $product ) { - $images = array(); - $attachment_ids = array(); - - // Add featured image. - if ( $product->get_image_id() ) { - $attachment_ids[] = $product->get_image_id(); - } - - // Add gallery images. - $attachment_ids = array_merge( $attachment_ids, $product->get_gallery_image_ids() ); - - // Build image data. - foreach ( $attachment_ids as $position => $attachment_id ) { - $attachment_post = get_post( $attachment_id ); - if ( is_null( $attachment_post ) ) { - continue; - } - - $attachment = wp_get_attachment_image_src( $attachment_id, 'full' ); - if ( ! is_array( $attachment ) ) { - continue; - } - - $images[] = array( - 'id' => (int) $attachment_id, - 'date_created' => wc_rest_prepare_date_response( $attachment_post->post_date, false ), - 'date_created_gmt' => wc_rest_prepare_date_response( strtotime( $attachment_post->post_date_gmt ) ), - 'date_modified' => wc_rest_prepare_date_response( $attachment_post->post_modified, false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( strtotime( $attachment_post->post_modified_gmt ) ), - 'src' => current( $attachment ), - 'name' => get_the_title( $attachment_id ), - 'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ), - 'position' => (int) $position, - ); - } - - // Set a placeholder image if the product has no images set. - if ( empty( $images ) ) { - $images[] = array( - 'id' => 0, - 'date_created' => wc_rest_prepare_date_response( current_time( 'mysql' ), false ), // Default to now. - 'date_created_gmt' => wc_rest_prepare_date_response( time() ), // Default to now. - 'date_modified' => wc_rest_prepare_date_response( current_time( 'mysql' ), false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( time() ), - 'src' => wc_placeholder_img_src(), - 'name' => __( 'Placeholder', 'woocommerce-rest-api' ), - 'alt' => __( 'Placeholder', 'woocommerce-rest-api' ), - 'position' => 0, - ); - } - - return $images; - } - - /** - * Get attribute taxonomy label. - * - * @param string $name Taxonomy name. - * - * @deprecated 3.0.0 - * @return string - */ - protected function get_attribute_taxonomy_label( $name ) { - $tax = get_taxonomy( $name ); - $labels = get_taxonomy_labels( $tax ); - - return $labels->singular_name; - } - - /** - * Get product attribute taxonomy name. - * - * @param string $slug Taxonomy name. - * @param WC_Product $product Product data. - * - * @since 3.0.0 - * @return string - */ - protected function get_attribute_taxonomy_name( $slug, $product ) { - // Format slug so it matches attributes of the product. - $slug = wc_attribute_taxonomy_slug( $slug ); - $attributes = $product->get_attributes(); - $attribute = false; - - // pa_ attributes. - if ( isset( $attributes[ wc_attribute_taxonomy_name( $slug ) ] ) ) { - $attribute = $attributes[ wc_attribute_taxonomy_name( $slug ) ]; - } elseif ( isset( $attributes[ $slug ] ) ) { - $attribute = $attributes[ $slug ]; - } - - if ( ! $attribute ) { - return $slug; - } - - // Taxonomy attribute name. - if ( $attribute->is_taxonomy() ) { - $taxonomy = $attribute->get_taxonomy_object(); - return $taxonomy->attribute_label; - } - - // Custom product attribute name. - return $attribute->get_name(); - } - - /** - * Get default attributes. - * - * @param WC_Product $product Product instance. - * - * @return array - */ - protected function get_default_attributes( $product ) { - $default = array(); - - if ( $product->is_type( 'variable' ) ) { - foreach ( array_filter( (array) $product->get_default_attributes(), 'strlen' ) as $key => $value ) { - if ( 0 === strpos( $key, 'pa_' ) ) { - $default[] = array( - 'id' => wc_attribute_taxonomy_id_by_name( $key ), - 'name' => $this->get_attribute_taxonomy_name( $key, $product ), - 'option' => $value, - ); - } else { - $default[] = array( - 'id' => 0, - 'name' => $this->get_attribute_taxonomy_name( $key, $product ), - 'option' => $value, - ); - } - } - } - - return $default; - } - - /** - * Get attribute options. - * - * @param int $product_id Product ID. - * @param array $attribute Attribute data. - * - * @return array - */ - protected function get_attribute_options( $product_id, $attribute ) { - if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) { - return wc_get_product_terms( - $product_id, - $attribute['name'], - array( - 'fields' => 'names', - ) - ); - } elseif ( isset( $attribute['value'] ) ) { - return array_map( 'trim', explode( '|', $attribute['value'] ) ); - } - - return array(); - } - - /** - * Get the attributes for a product or product variation. - * - * @param WC_Product|WC_Product_Variation $product Product instance. - * - * @return array - */ - protected function get_attributes( $product ) { - $attributes = array(); - - if ( $product->is_type( 'variation' ) ) { - $_product = wc_get_product( $product->get_parent_id() ); - foreach ( $product->get_variation_attributes() as $attribute_name => $attribute ) { - $name = str_replace( 'attribute_', '', $attribute_name ); - - if ( empty( $attribute ) && '0' !== $attribute ) { - continue; - } - - // Taxonomy-based attributes are prefixed with `pa_`, otherwise simply `attribute_`. - if ( 0 === strpos( $attribute_name, 'attribute_pa_' ) ) { - $option_term = get_term_by( 'slug', $attribute, $name ); - $attributes[] = array( - 'id' => wc_attribute_taxonomy_id_by_name( $name ), - 'name' => $this->get_attribute_taxonomy_name( $name, $_product ), - 'option' => $option_term && ! is_wp_error( $option_term ) ? $option_term->name : $attribute, - ); - } else { - $attributes[] = array( - 'id' => 0, - 'name' => $this->get_attribute_taxonomy_name( $name, $_product ), - 'option' => $attribute, - ); - } - } - } else { - foreach ( $product->get_attributes() as $attribute ) { - $attributes[] = array( - 'id' => $attribute['is_taxonomy'] ? wc_attribute_taxonomy_id_by_name( $attribute['name'] ) : 0, - 'name' => $this->get_attribute_taxonomy_name( $attribute['name'], $product ), - 'position' => (int) $attribute['position'], - 'visible' => (bool) $attribute['is_visible'], - 'variation' => (bool) $attribute['is_variation'], - 'options' => $this->get_attribute_options( $product->get_id(), $attribute ), - ); - } - } - - return $attributes; - } - - /** - * Get product data. - * - * @param WC_Product $product Product instance. - * @param string $context Request context. - * Options: 'view' and 'edit'. - * - * @return array - */ - protected function get_product_data( $product, $context = 'view' ) { - $data = array( - 'id' => $product->get_id(), - 'name' => $product->get_name( $context ), - 'slug' => $product->get_slug( $context ), - 'permalink' => $product->get_permalink(), - 'date_created' => wc_rest_prepare_date_response( $product->get_date_created( $context ), false ), - 'date_created_gmt' => wc_rest_prepare_date_response( $product->get_date_created( $context ) ), - 'date_modified' => wc_rest_prepare_date_response( $product->get_date_modified( $context ), false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( $product->get_date_modified( $context ) ), - 'type' => $product->get_type(), - 'status' => $product->get_status( $context ), - 'featured' => $product->is_featured(), - 'catalog_visibility' => $product->get_catalog_visibility( $context ), - 'description' => 'view' === $context ? wpautop( do_shortcode( $product->get_description() ) ) : $product->get_description( $context ), - 'short_description' => 'view' === $context ? apply_filters( 'woocommerce_short_description', $product->get_short_description() ) : $product->get_short_description( $context ), - 'sku' => $product->get_sku( $context ), - 'price' => $product->get_price( $context ), - 'regular_price' => $product->get_regular_price( $context ), - 'sale_price' => $product->get_sale_price( $context ) ? $product->get_sale_price( $context ) : '', - 'date_on_sale_from' => wc_rest_prepare_date_response( $product->get_date_on_sale_from( $context ), false ), - 'date_on_sale_from_gmt' => wc_rest_prepare_date_response( $product->get_date_on_sale_from( $context ) ), - 'date_on_sale_to' => wc_rest_prepare_date_response( $product->get_date_on_sale_to( $context ), false ), - 'date_on_sale_to_gmt' => wc_rest_prepare_date_response( $product->get_date_on_sale_to( $context ) ), - 'price_html' => $product->get_price_html(), - 'on_sale' => $product->is_on_sale( $context ), - 'purchasable' => $product->is_purchasable(), - 'total_sales' => $product->get_total_sales( $context ), - 'virtual' => $product->is_virtual(), - 'downloadable' => $product->is_downloadable(), - 'downloads' => $this->get_downloads( $product ), - 'download_limit' => $product->get_download_limit( $context ), - 'download_expiry' => $product->get_download_expiry( $context ), - 'external_url' => $product->is_type( 'external' ) ? $product->get_product_url( $context ) : '', - 'button_text' => $product->is_type( 'external' ) ? $product->get_button_text( $context ) : '', - 'tax_status' => $product->get_tax_status( $context ), - 'tax_class' => $product->get_tax_class( $context ), - 'manage_stock' => $product->managing_stock(), - 'stock_quantity' => $product->get_stock_quantity( $context ), - 'in_stock' => $product->is_in_stock(), - 'backorders' => $product->get_backorders( $context ), - 'backorders_allowed' => $product->backorders_allowed(), - 'backordered' => $product->is_on_backorder(), - 'sold_individually' => $product->is_sold_individually(), - 'weight' => $product->get_weight( $context ), - 'dimensions' => array( - 'length' => $product->get_length( $context ), - 'width' => $product->get_width( $context ), - 'height' => $product->get_height( $context ), - ), - 'shipping_required' => $product->needs_shipping(), - 'shipping_taxable' => $product->is_shipping_taxable(), - 'shipping_class' => $product->get_shipping_class(), - 'shipping_class_id' => $product->get_shipping_class_id( $context ), - 'reviews_allowed' => $product->get_reviews_allowed( $context ), - 'average_rating' => 'view' === $context ? wc_format_decimal( $product->get_average_rating(), 2 ) : $product->get_average_rating( $context ), - 'rating_count' => $product->get_rating_count(), - 'related_ids' => array_map( 'absint', array_values( wc_get_related_products( $product->get_id() ) ) ), - 'upsell_ids' => array_map( 'absint', $product->get_upsell_ids( $context ) ), - 'cross_sell_ids' => array_map( 'absint', $product->get_cross_sell_ids( $context ) ), - 'parent_id' => $product->get_parent_id( $context ), - 'purchase_note' => 'view' === $context ? wpautop( do_shortcode( wp_kses_post( $product->get_purchase_note() ) ) ) : $product->get_purchase_note( $context ), - 'categories' => $this->get_taxonomy_terms( $product ), - 'tags' => $this->get_taxonomy_terms( $product, 'tag' ), - 'images' => $this->get_images( $product ), - 'attributes' => $this->get_attributes( $product ), - 'default_attributes' => $this->get_default_attributes( $product ), - 'variations' => array(), - 'grouped_products' => array(), - 'menu_order' => $product->get_menu_order( $context ), - 'meta_data' => $product->get_meta_data(), - ); - - return $data; - } - - /** - * Prepare links for the request. - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * - * @return array Links for the given post. - */ - protected function prepare_links( $object, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ), // @codingStandardsIgnoreLine. - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), // @codingStandardsIgnoreLine. - ), - ); - - if ( $object->get_parent_id() ) { - $links['up'] = array( - 'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $object->get_parent_id() ) ), // @codingStandardsIgnoreLine. - ); - } - - return $links; - } - - /** - * Prepare a single product for create or update. - * - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * - * @return WP_Error|WC_Data - */ - protected function prepare_object_for_database( $request, $creating = false ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - - // Type is the most important part here because we need to be using the correct class and methods. - if ( isset( $request['type'] ) ) { - $classname = WC_Product_Factory::get_classname_from_product_type( $request['type'] ); - - if ( ! class_exists( $classname ) ) { - $classname = 'WC_Product_Simple'; - } - - $product = new $classname( $id ); - } elseif ( isset( $request['id'] ) ) { - $product = wc_get_product( $id ); - } else { - $product = new WC_Product_Simple(); - } - - if ( 'variation' === $product->get_type() ) { - return new WP_Error( - "woocommerce_rest_invalid_{$this->post_type}_id", - __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce-rest-api' ), - array( - 'status' => 404, - ) - ); - } - - // Post title. - if ( isset( $request['name'] ) ) { - $product->set_name( wp_filter_post_kses( $request['name'] ) ); - } - - // Post content. - if ( isset( $request['description'] ) ) { - $product->set_description( wp_filter_post_kses( $request['description'] ) ); - } - - // Post excerpt. - if ( isset( $request['short_description'] ) ) { - $product->set_short_description( wp_filter_post_kses( $request['short_description'] ) ); - } - - // Post status. - if ( isset( $request['status'] ) ) { - $product->set_status( get_post_status_object( $request['status'] ) ? $request['status'] : 'draft' ); - } - - // Post slug. - if ( isset( $request['slug'] ) ) { - $product->set_slug( $request['slug'] ); - } - - // Menu order. - if ( isset( $request['menu_order'] ) ) { - $product->set_menu_order( $request['menu_order'] ); - } - - // Comment status. - if ( isset( $request['reviews_allowed'] ) ) { - $product->set_reviews_allowed( $request['reviews_allowed'] ); - } - - // Virtual. - if ( isset( $request['virtual'] ) ) { - $product->set_virtual( $request['virtual'] ); - } - - // Tax status. - if ( isset( $request['tax_status'] ) ) { - $product->set_tax_status( $request['tax_status'] ); - } - - // Tax Class. - if ( isset( $request['tax_class'] ) ) { - $product->set_tax_class( $request['tax_class'] ); - } - - // Catalog Visibility. - if ( isset( $request['catalog_visibility'] ) ) { - $product->set_catalog_visibility( $request['catalog_visibility'] ); - } - - // Purchase Note. - if ( isset( $request['purchase_note'] ) ) { - $product->set_purchase_note( wp_kses_post( wp_unslash( $request['purchase_note'] ) ) ); - } - - // Featured Product. - if ( isset( $request['featured'] ) ) { - $product->set_featured( $request['featured'] ); - } - - // Shipping data. - $product = $this->save_product_shipping_data( $product, $request ); - - // SKU. - if ( isset( $request['sku'] ) ) { - $product->set_sku( wc_clean( $request['sku'] ) ); - } - - // Attributes. - if ( isset( $request['attributes'] ) ) { - $attributes = array(); - - foreach ( $request['attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $attribute_name = wc_clean( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $attribute_name ) { - continue; - } - - if ( $attribute_id ) { - - if ( isset( $attribute['options'] ) ) { - $options = $attribute['options']; - - if ( ! is_array( $attribute['options'] ) ) { - // Text based attributes - Posted values are term names. - $options = explode( WC_DELIMITER, $options ); - } - - $values = array_map( 'wc_sanitize_term_text_based', $options ); - $values = array_filter( $values, 'strlen' ); - } else { - $values = array(); - } - - if ( ! empty( $values ) ) { - // Add attribute to array, but don't set values. - $attribute_object = new WC_Product_Attribute(); - $attribute_object->set_id( $attribute_id ); - $attribute_object->set_name( $attribute_name ); - $attribute_object->set_options( $values ); - $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' ); - $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 ); - $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 ); - $attributes[] = $attribute_object; - } - } elseif ( isset( $attribute['options'] ) ) { - // Custom attribute - Add attribute to array and set the values. - if ( is_array( $attribute['options'] ) ) { - $values = $attribute['options']; - } else { - $values = explode( WC_DELIMITER, $attribute['options'] ); - } - $attribute_object = new WC_Product_Attribute(); - $attribute_object->set_name( $attribute_name ); - $attribute_object->set_options( $values ); - $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' ); - $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 ); - $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 ); - $attributes[] = $attribute_object; - } - } - $product->set_attributes( $attributes ); - } - - // Sales and prices. - if ( in_array( $product->get_type(), array( 'variable', 'grouped' ), true ) ) { - $product->set_regular_price( '' ); - $product->set_sale_price( '' ); - $product->set_date_on_sale_to( '' ); - $product->set_date_on_sale_from( '' ); - $product->set_price( '' ); - } else { - // Regular Price. - if ( isset( $request['regular_price'] ) ) { - $product->set_regular_price( $request['regular_price'] ); - } - - // Sale Price. - if ( isset( $request['sale_price'] ) ) { - $product->set_sale_price( $request['sale_price'] ); - } - - if ( isset( $request['date_on_sale_from'] ) ) { - $product->set_date_on_sale_from( $request['date_on_sale_from'] ); - } - - if ( isset( $request['date_on_sale_from_gmt'] ) ) { - $product->set_date_on_sale_from( $request['date_on_sale_from_gmt'] ? strtotime( $request['date_on_sale_from_gmt'] ) : null ); - } - - if ( isset( $request['date_on_sale_to'] ) ) { - $product->set_date_on_sale_to( $request['date_on_sale_to'] ); - } - - if ( isset( $request['date_on_sale_to_gmt'] ) ) { - $product->set_date_on_sale_to( $request['date_on_sale_to_gmt'] ? strtotime( $request['date_on_sale_to_gmt'] ) : null ); - } - } - - // Product parent ID. - if ( isset( $request['parent_id'] ) ) { - $product->set_parent_id( $request['parent_id'] ); - } - - // Sold individually. - if ( isset( $request['sold_individually'] ) ) { - $product->set_sold_individually( $request['sold_individually'] ); - } - - // Stock status. - if ( isset( $request['in_stock'] ) ) { - $stock_status = true === $request['in_stock'] ? 'instock' : 'outofstock'; - } else { - $stock_status = $product->get_stock_status(); - } - - // Stock data. - if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { - // Manage stock. - if ( isset( $request['manage_stock'] ) ) { - $product->set_manage_stock( $request['manage_stock'] ); - } - - // Backorders. - if ( isset( $request['backorders'] ) ) { - $product->set_backorders( $request['backorders'] ); - } - - if ( $product->is_type( 'grouped' ) ) { - $product->set_manage_stock( 'no' ); - $product->set_backorders( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } elseif ( $product->is_type( 'external' ) ) { - $product->set_manage_stock( 'no' ); - $product->set_backorders( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( 'instock' ); - } elseif ( $product->get_manage_stock() ) { - // Stock status is always determined by children so sync later. - if ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Stock quantity. - if ( isset( $request['stock_quantity'] ) ) { - $product->set_stock_quantity( wc_stock_amount( $request['stock_quantity'] ) ); - } elseif ( isset( $request['inventory_delta'] ) ) { - $stock_quantity = wc_stock_amount( $product->get_stock_quantity() ); - $stock_quantity += wc_stock_amount( $request['inventory_delta'] ); - $product->set_stock_quantity( wc_stock_amount( $stock_quantity ) ); - } - } else { - // Don't manage stock. - $product->set_manage_stock( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } - } elseif ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Upsells. - if ( isset( $request['upsell_ids'] ) ) { - $upsells = array(); - $ids = $request['upsell_ids']; - - if ( ! empty( $ids ) ) { - foreach ( $ids as $id ) { - if ( $id && $id > 0 ) { - $upsells[] = $id; - } - } - } - - $product->set_upsell_ids( $upsells ); - } - - // Cross sells. - if ( isset( $request['cross_sell_ids'] ) ) { - $crosssells = array(); - $ids = $request['cross_sell_ids']; - - if ( ! empty( $ids ) ) { - foreach ( $ids as $id ) { - if ( $id && $id > 0 ) { - $crosssells[] = $id; - } - } - } - - $product->set_cross_sell_ids( $crosssells ); - } - - // Product categories. - if ( isset( $request['categories'] ) && is_array( $request['categories'] ) ) { - $product = $this->save_taxonomy_terms( $product, $request['categories'] ); - } - - // Product tags. - if ( isset( $request['tags'] ) && is_array( $request['tags'] ) ) { - $product = $this->save_taxonomy_terms( $product, $request['tags'], 'tag' ); - } - - // Downloadable. - if ( isset( $request['downloadable'] ) ) { - $product->set_downloadable( $request['downloadable'] ); - } - - // Downloadable options. - if ( $product->get_downloadable() ) { - - // Downloadable files. - if ( isset( $request['downloads'] ) && is_array( $request['downloads'] ) ) { - $product = $this->save_downloadable_files( $product, $request['downloads'] ); - } - - // Download limit. - if ( isset( $request['download_limit'] ) ) { - $product->set_download_limit( $request['download_limit'] ); - } - - // Download expiry. - if ( isset( $request['download_expiry'] ) ) { - $product->set_download_expiry( $request['download_expiry'] ); - } - } - - // Product url and button text for external products. - if ( $product->is_type( 'external' ) ) { - if ( isset( $request['external_url'] ) ) { - $product->set_product_url( $request['external_url'] ); - } - - if ( isset( $request['button_text'] ) ) { - $product->set_button_text( $request['button_text'] ); - } - } - - // Save default attributes for variable products. - if ( $product->is_type( 'variable' ) ) { - $product = $this->save_default_attributes( $product, $request ); - } - - // Set children for a grouped product. - if ( $product->is_type( 'grouped' ) && isset( $request['grouped_products'] ) ) { - $product->set_children( $request['grouped_products'] ); - } - - // Check for featured/gallery images, upload it and set it. - if ( isset( $request['images'] ) ) { - $product = $this->set_product_images( $product, $request['images'] ); - } - - // Allow set meta_data. - if ( is_array( $request['meta_data'] ) ) { - foreach ( $request['meta_data'] as $meta ) { - $product->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $product Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $product, $request, $creating ); - } - - /** - * Set product images. - * - * @param WC_Product $product Product instance. - * @param array $images Images data. - * - * @throws WC_REST_Exception REST API exceptions. - * @return WC_Product - */ - protected function set_product_images( $product, $images ) { - $images = is_array( $images ) ? array_filter( $images ) : array(); - - if ( ! empty( $images ) ) { - $gallery_positions = array(); - - foreach ( $images as $index => $image ) { - $attachment_id = isset( $image['id'] ) ? absint( $image['id'] ) : 0; - - if ( 0 === $attachment_id && isset( $image['src'] ) ) { - $upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) ); - - if ( is_wp_error( $upload ) ) { - if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $product->get_id(), $images ) ) { - throw new WC_REST_Exception( 'woocommerce_product_image_upload_error', $upload->get_error_message(), 400 ); - } else { - continue; - } - } - - $attachment_id = wc_rest_set_uploaded_image_as_attachment( $upload, $product->get_id() ); - } - - if ( ! wp_attachment_is_image( $attachment_id ) ) { - /* translators: %s: attachment id */ - throw new WC_REST_Exception( 'woocommerce_product_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce-rest-api' ), $attachment_id ), 400 ); - } - - $gallery_positions[ $attachment_id ] = absint( isset( $image['position'] ) ? $image['position'] : $index ); - - // Set the image alt if present. - if ( ! empty( $image['alt'] ) ) { - update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) ); - } - - // Set the image name if present. - if ( ! empty( $image['name'] ) ) { - wp_update_post( - array( - 'ID' => $attachment_id, - 'post_title' => $image['name'], - ) - ); - } - - // Set the image source if present, for future reference. - if ( ! empty( $image['src'] ) ) { - update_post_meta( $attachment_id, '_wc_attachment_source', esc_url_raw( $image['src'] ) ); - } - } - - // Sort images and get IDs in correct order. - asort( $gallery_positions ); - - // Get gallery in correct order. - $gallery = array_keys( $gallery_positions ); - - // Featured image is in position 0. - $image_id = array_shift( $gallery ); - - // Set images. - $product->set_image_id( $image_id ); - $product->set_gallery_image_ids( $gallery ); - } else { - $product->set_image_id( '' ); - $product->set_gallery_image_ids( array() ); - } - - return $product; - } - - /** - * Save product shipping data. - * - * @param WC_Product $product Product instance. - * @param array $data Shipping data. - * - * @return WC_Product - */ - protected function save_product_shipping_data( $product, $data ) { - // Virtual. - if ( isset( $data['virtual'] ) && true === $data['virtual'] ) { - $product->set_weight( '' ); - $product->set_height( '' ); - $product->set_length( '' ); - $product->set_width( '' ); - } else { - if ( isset( $data['weight'] ) ) { - $product->set_weight( $data['weight'] ); - } - - // Height. - if ( isset( $data['dimensions']['height'] ) ) { - $product->set_height( $data['dimensions']['height'] ); - } - - // Width. - if ( isset( $data['dimensions']['width'] ) ) { - $product->set_width( $data['dimensions']['width'] ); - } - - // Length. - if ( isset( $data['dimensions']['length'] ) ) { - $product->set_length( $data['dimensions']['length'] ); - } - } - - // Shipping class. - if ( isset( $data['shipping_class'] ) ) { - $data_store = $product->get_data_store(); - $shipping_class_id = $data_store->get_shipping_class_id_by_slug( wc_clean( $data['shipping_class'] ) ); - $product->set_shipping_class_id( $shipping_class_id ); - } - - return $product; - } - - /** - * Save downloadable files. - * - * @param WC_Product $product Product instance. - * @param array $downloads Downloads data. - * @param int $deprecated Deprecated since 3.0. - * - * @return WC_Product - */ - protected function save_downloadable_files( $product, $downloads, $deprecated = 0 ) { - if ( $deprecated ) { - wc_deprecated_argument( 'variation_id', '3.0', 'save_downloadable_files() not requires a variation_id anymore.' ); - } - - $files = array(); - foreach ( $downloads as $key => $file ) { - if ( empty( $file['file'] ) ) { - continue; - } - - $download = new WC_Product_Download(); - $download->set_id( ! empty( $file['id'] ) ? $file['id'] : wp_generate_uuid4() ); - $download->set_name( $file['name'] ? $file['name'] : wc_get_filename_from_url( $file['file'] ) ); - $download->set_file( apply_filters( 'woocommerce_file_download_path', $file['file'], $product, $key ) ); - $files[] = $download; - } - $product->set_downloads( $files ); - - return $product; - } - - /** - * Save taxonomy terms. - * - * @param WC_Product $product Product instance. - * @param array $terms Terms data. - * @param string $taxonomy Taxonomy name. - * - * @return WC_Product - */ - protected function save_taxonomy_terms( $product, $terms, $taxonomy = 'cat' ) { - $term_ids = wp_list_pluck( $terms, 'id' ); - - if ( 'cat' === $taxonomy ) { - $product->set_category_ids( $term_ids ); - } elseif ( 'tag' === $taxonomy ) { - $product->set_tag_ids( $term_ids ); - } - - return $product; - } - - /** - * Save default attributes. - * - * @param WC_Product $product Product instance. - * @param WP_REST_Request $request Request data. - * - * @since 3.0.0 - * @return WC_Product - */ - protected function save_default_attributes( $product, $request ) { - if ( isset( $request['default_attributes'] ) && is_array( $request['default_attributes'] ) ) { - - $attributes = $product->get_attributes(); - $default_attributes = array(); - - foreach ( $request['default_attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $attribute_name = sanitize_title( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $attribute_name ) { - continue; - } - - if ( isset( $attributes[ $attribute_name ] ) ) { - $_attribute = $attributes[ $attribute_name ]; - - if ( $_attribute['is_variation'] ) { - $value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : ''; - - if ( ! empty( $_attribute['is_taxonomy'] ) ) { - // If dealing with a taxonomy, we need to get the slug from the name posted to the API. - $term = get_term_by( 'name', $value, $attribute_name ); - - if ( $term && ! is_wp_error( $term ) ) { - $value = $term->slug; - } else { - $value = sanitize_title( $value ); - } - } - - if ( $value ) { - $default_attributes[ $attribute_name ] = $value; - } - } - } - } - - $product->set_default_attributes( $default_attributes ); - } - - return $product; - } - - /** - * Clear caches here so in sync with any new variations/children. - * - * @param WC_Data $object Object data. - */ - public function clear_transients( $object ) { - wc_delete_product_transients( $object->get_id() ); - wp_cache_delete( 'product-' . $object->get_id(), 'products' ); - } - - /** - * Delete a single item. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $id = (int) $request['id']; - $force = (bool) $request['force']; - $object = $this->get_object( (int) $request['id'] ); - $result = false; - - if ( ! $object || 0 === $object->get_id() ) { - return new WP_Error( - "woocommerce_rest_{$this->post_type}_invalid_id", - __( 'Invalid ID.', 'woocommerce-rest-api' ), - array( - 'status' => 404, - ) - ); - } - - if ( 'variation' === $object->get_type() ) { - return new WP_Error( - "woocommerce_rest_invalid_{$this->post_type}_id", - __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce-rest-api' ), - array( - 'status' => 404, - ) - ); - } - - $supports_trash = EMPTY_TRASH_DAYS > 0 && is_callable( array( $object, 'get_status' ) ); - - /** - * Filter whether an object is trashable. - * - * Return false to disable trash support for the object. - * - * @param boolean $supports_trash Whether the object type support trashing. - * @param WC_Data $object The object being considered for trashing support. - */ - $supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object ); - - if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) { - return new WP_Error( - "woocommerce_rest_user_cannot_delete_{$this->post_type}", - /* translators: %s: post type */ - sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce-rest-api' ), $this->post_type ), - array( - 'status' => rest_authorization_required_code(), - ) - ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_object_for_response( $object, $request ); - - // If we're forcing, then delete permanently. - if ( $force ) { - if ( $object->is_type( 'variable' ) ) { - foreach ( $object->get_children() as $child_id ) { - $child = wc_get_product( $child_id ); - if ( ! empty( $child ) ) { - $child->delete( true ); - } - } - } else { - // For other product types, if the product has children, remove the relationship. - foreach ( $object->get_children() as $child_id ) { - $child = wc_get_product( $child_id ); - if ( ! empty( $child ) ) { - $child->set_parent_id( 0 ); - $child->save(); - } - } - } - - $object->delete( true ); - $result = 0 === $object->get_id(); - } else { - // If we don't support trashing for this type, error out. - if ( ! $supports_trash ) { - return new WP_Error( - 'woocommerce_rest_trash_not_supported', - /* translators: %s: post type */ - sprintf( __( 'The %s does not support trashing.', 'woocommerce-rest-api' ), $this->post_type ), - array( - 'status' => 501, - ) - ); - } - - // Otherwise, only trash if we haven't already. - if ( is_callable( array( $object, 'get_status' ) ) ) { - if ( 'trash' === $object->get_status() ) { - return new WP_Error( - 'woocommerce_rest_already_trashed', - /* translators: %s: post type */ - sprintf( __( 'The %s has already been deleted.', 'woocommerce-rest-api' ), $this->post_type ), - array( - 'status' => 410, - ) - ); - } - - $object->delete(); - $result = 'trash' === $object->get_status(); - } - } - - if ( ! $result ) { - return new WP_Error( - 'woocommerce_rest_cannot_delete', - /* translators: %s: post type */ - sprintf( __( 'The %s cannot be deleted.', 'woocommerce-rest-api' ), $this->post_type ), - array( - 'status' => 500, - ) - ); - } - - // Delete parent product transients. - if ( 0 !== $object->get_parent_id() ) { - wc_delete_product_transients( $object->get_parent_id() ); - } - - /** - * Fires after a single object is deleted or trashed via the REST API. - * - * @param WC_Data $object The deleted or trashed object. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( "woocommerce_rest_delete_{$this->post_type}_object", $object, $response, $request ); - - return $response; - } - - /** - * Get the Product's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $weight_unit = get_option( 'woocommerce_weight_unit' ); - $dimension_unit = get_option( 'woocommerce_dimension_unit' ); - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'slug' => array( - 'description' => __( 'Product slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'permalink' => array( - 'description' => __( 'Product URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the product was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the product was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the product was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the product was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Product type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'simple', - 'enum' => array_keys( wc_get_product_types() ), - 'context' => array( 'view', 'edit' ), - ), - 'status' => array( - 'description' => __( 'Product status (post status).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'publish', - 'enum' => array_merge( array_keys( get_post_statuses() ), array( 'future' ) ), - 'context' => array( 'view', 'edit' ), - ), - 'featured' => array( - 'description' => __( 'Featured product.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'catalog_visibility' => array( - 'description' => __( 'Catalog visibility.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'visible', - 'enum' => array( 'visible', 'catalog', 'search', 'hidden' ), - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'Product description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'short_description' => array( - 'description' => __( 'Product short description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sku' => array( - 'description' => __( 'Unique identifier.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'price' => array( - 'description' => __( 'Current product price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'regular_price' => array( - 'description' => __( 'Product regular price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sale_price' => array( - 'description' => __( 'Product sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from' => array( - 'description' => __( "Start date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from_gmt' => array( - 'description' => __( 'Start date of sale price, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to' => array( - 'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to_gmt' => array( - 'description' => __( 'End date of sale price, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'price_html' => array( - 'description' => __( 'Price formatted in HTML.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'on_sale' => array( - 'description' => __( 'Shows if the product is on sale.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'purchasable' => array( - 'description' => __( 'Shows if the product can be bought.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_sales' => array( - 'description' => __( 'Amount of sales.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'virtual' => array( - 'description' => __( 'If the product is virtual.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloadable' => array( - 'description' => __( 'If the product is downloadable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloads' => array( - 'description' => __( 'List of downloadable files.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'File ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'download_limit' => array( - 'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'download_expiry' => array( - 'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'external_url' => array( - 'description' => __( 'Product external URL. Only for external products.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'button_text' => array( - 'description' => __( 'Product external button text. Only for external products.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'taxable', - 'enum' => array( 'taxable', 'shipping', 'none' ), - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'manage_stock' => array( - 'description' => __( 'Stock management at product level.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'stock_quantity' => array( - 'description' => __( 'Stock quantity.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'in_stock' => array( - 'description' => __( 'Controls whether or not the product is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'backorders' => array( - 'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'no', - 'enum' => array( 'no', 'notify', 'yes' ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders_allowed' => array( - 'description' => __( 'Shows if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'backordered' => array( - 'description' => __( 'Shows if the product is on backordered.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sold_individually' => array( - 'description' => __( 'Allow one item to be bought in a single order.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'weight' => array( - /* translators: %s: weight unit */ - 'description' => sprintf( __( 'Product weight (%s).', 'woocommerce-rest-api' ), $weight_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'dimensions' => array( - 'description' => __( 'Product dimensions.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'length' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product length (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'width' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product width (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'height' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product height (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping_required' => array( - 'description' => __( 'Shows if the product need to be shipped.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_taxable' => array( - 'description' => __( 'Shows whether or not the product shipping is taxable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_class' => array( - 'description' => __( 'Shipping class slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'shipping_class_id' => array( - 'description' => __( 'Shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'reviews_allowed' => array( - 'description' => __( 'Allow reviews.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'average_rating' => array( - 'description' => __( 'Reviews average rating.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'rating_count' => array( - 'description' => __( 'Amount of reviews that the product have.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'related_ids' => array( - 'description' => __( 'List of related products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'upsell_ids' => array( - 'description' => __( 'List of up-sell products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'cross_sell_ids' => array( - 'description' => __( 'List of cross-sell products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'parent_id' => array( - 'description' => __( 'Product parent ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'purchase_note' => array( - 'description' => __( 'Optional note to send the customer after purchase.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'categories' => array( - 'description' => __( 'List of categories.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Category ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Category name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'slug' => array( - 'description' => __( 'Category slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'tags' => array( - 'description' => __( 'List of tags.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tag ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Tag name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'slug' => array( - 'description' => __( 'Tag slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'images' => array( - 'description' => __( 'List of images.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the image was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the image was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'position' => array( - 'description' => __( 'Image position. 0 means that the image is featured.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'attributes' => array( - 'description' => __( 'List of attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'position' => array( - 'description' => __( 'Attribute position.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'visible' => array( - 'description' => __( "Define if the attribute is visible on the \"Additional information\" tab in the product's page.", 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'variation' => array( - 'description' => __( 'Define if the attribute can be used as variation.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'options' => array( - 'description' => __( 'List of available term names of the attribute.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'string', - ), - ), - ), - ), - ), - 'default_attributes' => array( - 'description' => __( 'Defaults variation attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'option' => array( - 'description' => __( 'Selected attribute term name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'variations' => array( - 'description' => __( 'List of variations IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'integer', - ), - 'readonly' => true, - ), - 'grouped_products' => array( - 'description' => __( 'List of grouped products ID.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort products.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['orderby']['enum'] = array_merge( $params['orderby']['enum'], array( 'menu_order' ) ); - - $params['slug'] = array( - 'description' => __( 'Limit result set to products with a specific slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['status'] = array( - 'default' => 'any', - 'description' => __( 'Limit result set to products assigned a specific status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_merge( array( 'any', 'future', 'trash' ), array_keys( get_post_statuses() ) ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['type'] = array( - 'description' => __( 'Limit result set to products assigned a specific type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_keys( wc_get_product_types() ), - 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['sku'] = array( - 'description' => __( 'Limit result set to products with specific SKU(s). Use commas to separate.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['featured'] = array( - 'description' => __( 'Limit result set to featured products.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'sanitize_callback' => 'wc_string_to_bool', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['category'] = array( - 'description' => __( 'Limit result set to products assigned a specific category ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['tag'] = array( - 'description' => __( 'Limit result set to products assigned a specific tag ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['shipping_class'] = array( - 'description' => __( 'Limit result set to products assigned a specific shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['attribute'] = array( - 'description' => __( 'Limit result set to products with a specific attribute. Use the taxonomy name/attribute slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['attribute_term'] = array( - 'description' => __( 'Limit result set to products with a specific attribute term ID (required an assigned attribute).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'wp_parse_id_list', - 'validate_callback' => 'rest_validate_request_arg', - ); - - if ( wc_tax_enabled() ) { - $params['tax_class'] = array( - 'description' => __( 'Limit result set to products with a specific tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_merge( array( 'standard' ), WC_Tax::get_tax_class_slugs() ), - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - } - - $params['in_stock'] = array( - 'description' => __( 'Limit result set to products in stock or out of stock.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'sanitize_callback' => 'wc_string_to_bool', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['on_sale'] = array( - 'description' => __( 'Limit result set to products on sale.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'sanitize_callback' => 'wc_string_to_bool', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['min_price'] = array( - 'description' => __( 'Limit result set to products based on a minimum price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['max_price'] = array( - 'description' => __( 'Limit result set to products based on a maximum price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version2/class-wc-rest-report-sales-v2-controller.php b/src/Controllers/Version2/class-wc-rest-report-sales-v2-controller.php deleted file mode 100644 index 4c5a873f351..00000000000 --- a/src/Controllers/Version2/class-wc-rest-report-sales-v2-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -[\w-]+)'; - - /** - * Register routes. - * - * @since 3.0.0 - */ - public function register_routes() { - register_rest_route( - $this->namespace, '/' . $this->rest_base, array( - 'args' => array( - 'group' => array( - 'description' => __( 'Settings group ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/batch', array( - 'args' => array( - 'group' => array( - 'description' => __( 'Settings group ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'update_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( - 'args' => array( - 'group' => array( - 'description' => __( 'Settings group ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Return a single setting. - * - * @since 3.0.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $setting = $this->get_setting( $request['group_id'], $request['id'] ); - - if ( is_wp_error( $setting ) ) { - return $setting; - } - - $response = $this->prepare_item_for_response( $setting, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Return all settings in a group. - * - * @since 3.0.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $settings = $this->get_group_settings( $request['group_id'] ); - - if ( is_wp_error( $settings ) ) { - return $settings; - } - - $data = array(); - - foreach ( $settings as $setting_obj ) { - $setting = $this->prepare_item_for_response( $setting_obj, $request ); - $setting = $this->prepare_response_for_collection( $setting ); - if ( $this->is_setting_type_valid( $setting['type'] ) ) { - $data[] = $setting; - } - } - - return rest_ensure_response( $data ); - } - - /** - * Get all settings in a group. - * - * @since 3.0.0 - * @param string $group_id Group ID. - * @return array|WP_Error - */ - public function get_group_settings( $group_id ) { - if ( empty( $group_id ) ) { - return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $settings = apply_filters( 'woocommerce_settings-' . $group_id, array() ); - - if ( empty( $settings ) ) { - return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $filtered_settings = array(); - foreach ( $settings as $setting ) { - $option_key = $setting['option_key']; - $setting = $this->filter_setting( $setting ); - $default = isset( $setting['default'] ) ? $setting['default'] : ''; - // Get the option value. - if ( is_array( $option_key ) ) { - $option = get_option( $option_key[0] ); - $setting['value'] = isset( $option[ $option_key[1] ] ) ? $option[ $option_key[1] ] : $default; - } else { - $admin_setting_value = WC_Admin_Settings::get_option( $option_key, $default ); - $setting['value'] = $admin_setting_value; - } - - if ( 'multi_select_countries' === $setting['type'] ) { - $setting['options'] = WC()->countries->get_countries(); - $setting['type'] = 'multiselect'; - } elseif ( 'single_select_country' === $setting['type'] ) { - $setting['type'] = 'select'; - $setting['options'] = $this->get_countries_and_states(); - } - - $filtered_settings[] = $setting; - } - - return $filtered_settings; - } - - /** - * Returns a list of countries and states for use in the base location setting. - * - * @since 3.0.7 - * @return array Array of states and countries. - */ - private function get_countries_and_states() { - $countries = WC()->countries->get_countries(); - if ( ! $countries ) { - return array(); - } - - $output = array(); - - foreach ( $countries as $key => $value ) { - $states = WC()->countries->get_states( $key ); - if ( $states ) { - foreach ( $states as $state_key => $state_value ) { - $output[ $key . ':' . $state_key ] = $value . ' - ' . $state_value; - } - } else { - $output[ $key ] = $value; - } - } - - return $output; - } - - /** - * Get setting data. - * - * @since 3.0.0 - * @param string $group_id Group ID. - * @param string $setting_id Setting ID. - * @return stdClass|WP_Error - */ - public function get_setting( $group_id, $setting_id ) { - if ( empty( $setting_id ) ) { - return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $settings = $this->get_group_settings( $group_id ); - - if ( is_wp_error( $settings ) ) { - return $settings; - } - - $array_key = array_keys( wp_list_pluck( $settings, 'id' ), $setting_id ); - - if ( empty( $array_key ) ) { - return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $setting = $settings[ $array_key[0] ]; - - if ( ! $this->is_setting_type_valid( $setting['type'] ) ) { - return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - return $setting; - } - - /** - * Bulk create, update and delete items. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array Of WP_Error or WP_REST_Response. - */ - public function batch_items( $request ) { - // Get the request params. - $items = array_filter( $request->get_params() ); - - /* - * Since our batch settings update is group-specific and matches based on the route, - * we inject the URL parameters (containing group) into the batch items - */ - if ( ! empty( $items['update'] ) ) { - $to_update = array(); - foreach ( $items['update'] as $item ) { - $to_update[] = array_merge( $request->get_url_params(), $item ); - } - $request = new WP_REST_Request( $request->get_method() ); - $request->set_body_params( array( 'update' => $to_update ) ); - } - - return parent::batch_items( $request ); - } - - /** - * Update a single setting in a group. - * - * @since 3.0.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $setting = $this->get_setting( $request['group_id'], $request['id'] ); - - if ( is_wp_error( $setting ) ) { - return $setting; - } - - if ( is_callable( array( $this, 'validate_setting_' . $setting['type'] . '_field' ) ) ) { - $value = $this->{'validate_setting_' . $setting['type'] . '_field'}( $request['value'], $setting ); - } else { - $value = $this->validate_setting_text_field( $request['value'], $setting ); - } - - if ( is_wp_error( $value ) ) { - return $value; - } - - if ( is_array( $setting['option_key'] ) ) { - $setting['value'] = $value; - $option_key = $setting['option_key']; - $prev = get_option( $option_key[0] ); - $prev[ $option_key[1] ] = $request['value']; - update_option( $option_key[0], $prev ); - } else { - $update_data = array(); - $update_data[ $setting['option_key'] ] = $value; - $setting['value'] = $value; - WC_Admin_Settings::save_fields( array( $setting ), $update_data ); - } - - $response = $this->prepare_item_for_response( $setting, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Prepare a single setting object for response. - * - * @since 3.0.0 - * @param object $item Setting object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $item, $request ) { - unset( $item['option_key'] ); - $data = $this->filter_setting( $item ); - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, empty( $request['context'] ) ? 'view' : $request['context'] ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $data['id'], $request['group_id'] ) ); - return $response; - } - - /** - * Prepare links for the request. - * - * @since 3.0.0 - * @param string $setting_id Setting ID. - * @param string $group_id Group ID. - * @return array Links for the given setting. - */ - protected function prepare_links( $setting_id, $group_id ) { - $base = str_replace( '(?P[\w-]+)', $group_id, $this->rest_base ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $base, $setting_id ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ), - ), - ); - - return $links; - } - - /** - * Makes sure the current user has access to READ the settings APIs. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Makes sure the current user has access to WRITE the settings APIs. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function update_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Filters out bad values from the settings array/filter so we - * only return known values via the API. - * - * @since 3.0.0 - * @param array $setting Settings. - * @return array - */ - public function filter_setting( $setting ) { - $setting = array_intersect_key( - $setting, - array_flip( array_filter( array_keys( $setting ), array( $this, 'allowed_setting_keys' ) ) ) - ); - - if ( empty( $setting['options'] ) ) { - unset( $setting['options'] ); - } - - if ( 'image_width' === $setting['type'] ) { - $setting = $this->cast_image_width( $setting ); - } - - return $setting; - } - - /** - * For image_width, Crop can return "0" instead of false -- so we want - * to make sure we return these consistently the same we accept them. - * - * @todo remove in 4.0 - * @since 3.0.0 - * @param array $setting Settings. - * @return array - */ - public function cast_image_width( $setting ) { - foreach ( array( 'default', 'value' ) as $key ) { - if ( isset( $setting[ $key ] ) ) { - $setting[ $key ]['width'] = intval( $setting[ $key ]['width'] ); - $setting[ $key ]['height'] = intval( $setting[ $key ]['height'] ); - $setting[ $key ]['crop'] = (bool) $setting[ $key ]['crop']; - } - } - return $setting; - } - - /** - * Callback for allowed keys for each setting response. - * - * @since 3.0.0 - * @param string $key Key to check. - * @return boolean - */ - public function allowed_setting_keys( $key ) { - return in_array( - $key, array( - 'id', - 'label', - 'description', - 'default', - 'tip', - 'placeholder', - 'type', - 'options', - 'value', - 'option_key', - ) - ); - } - - /** - * Boolean for if a setting type is a valid supported setting type. - * - * @since 3.0.0 - * @param string $type Type. - * @return bool - */ - public function is_setting_type_valid( $type ) { - return in_array( - $type, array( - 'text', // Validates with validate_setting_text_field. - 'email', // Validates with validate_setting_text_field. - 'number', // Validates with validate_setting_text_field. - 'color', // Validates with validate_setting_text_field. - 'password', // Validates with validate_setting_text_field. - 'textarea', // Validates with validate_setting_textarea_field. - 'select', // Validates with validate_setting_select_field. - 'multiselect', // Validates with validate_setting_multiselect_field. - 'radio', // Validates with validate_setting_radio_field (-> validate_setting_select_field). - 'checkbox', // Validates with validate_setting_checkbox_field. - 'image_width', // Validates with validate_setting_image_width_field. - 'thumbnail_cropping', // Validates with validate_setting_text_field. - ) - ); - } - - /** - * Get the settings schema, conforming to JSON Schema. - * - * @since 3.0.0 - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'setting', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Setting value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'default' => array( - 'description' => __( 'Default value for the setting.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tip' => array( - 'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'placeholder' => array( - 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Type of setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'enum' => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox', 'thumbnail_cropping' ), - 'readonly' => true, - ), - 'options' => array( - 'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-settings-v2-controller.php b/src/Controllers/Version2/class-wc-rest-settings-v2-controller.php deleted file mode 100644 index 1ca5f153b40..00000000000 --- a/src/Controllers/Version2/class-wc-rest-settings-v2-controller.php +++ /dev/null @@ -1,232 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Get all settings groups items. - * - * @since 3.0.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $groups = apply_filters( 'woocommerce_settings_groups', array() ); - if ( empty( $groups ) ) { - return new WP_Error( 'rest_setting_groups_empty', __( 'No setting groups have been registered.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - $defaults = $this->group_defaults(); - $filtered_groups = array(); - foreach ( $groups as $group ) { - $sub_groups = array(); - foreach ( $groups as $_group ) { - if ( ! empty( $_group['parent_id'] ) && $group['id'] === $_group['parent_id'] ) { - $sub_groups[] = $_group['id']; - } - } - $group['sub_groups'] = $sub_groups; - - $group = wp_parse_args( $group, $defaults ); - if ( ! is_null( $group['id'] ) && ! is_null( $group['label'] ) ) { - $group_obj = $this->filter_group( $group ); - $group_data = $this->prepare_item_for_response( $group_obj, $request ); - $group_data = $this->prepare_response_for_collection( $group_data ); - - $filtered_groups[] = $group_data; - } - } - - $response = rest_ensure_response( $filtered_groups ); - return $response; - } - - /** - * Prepare links for the request. - * - * @param string $group_id Group ID. - * @return array Links for the given group. - */ - protected function prepare_links( $group_id ) { - $base = '/' . $this->namespace . '/' . $this->rest_base; - $links = array( - 'options' => array( - 'href' => rest_url( trailingslashit( $base ) . $group_id ), - ), - ); - - return $links; - } - - /** - * Prepare a report sales object for serialization. - * - * @since 3.0.0 - * @param array $item Group object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $item, $request ) { - $context = empty( $request['context'] ) ? 'view' : $request['context']; - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item['id'] ) ); - - return $response; - } - - /** - * Filters out bad values from the groups array/filter so we - * only return known values via the API. - * - * @since 3.0.0 - * @param array $group Group. - * @return array - */ - public function filter_group( $group ) { - return array_intersect_key( - $group, - array_flip( array_filter( array_keys( $group ), array( $this, 'allowed_group_keys' ) ) ) - ); - } - - /** - * Callback for allowed keys for each group response. - * - * @since 3.0.0 - * @param string $key Key to check. - * @return boolean - */ - public function allowed_group_keys( $key ) { - return in_array( $key, array( 'id', 'label', 'description', 'parent_id', 'sub_groups' ) ); - } - - /** - * Returns default settings for groups. null means the field is required. - * - * @since 3.0.0 - * @return array - */ - protected function group_defaults() { - return array( - 'id' => null, - 'label' => null, - 'description' => '', - 'parent_id' => '', - 'sub_groups' => array(), - ); - } - - /** - * Makes sure the current user has access to READ the settings APIs. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get the groups schema, conforming to JSON Schema. - * - * @since 3.0.0 - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'setting_group', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier that can be used to link settings together.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'parent_id' => array( - 'description' => __( 'ID of parent grouping.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'sub_groups' => array( - 'description' => __( 'IDs for settings sub groups.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-shipping-methods-v2-controller.php b/src/Controllers/Version2/class-wc-rest-shipping-methods-v2-controller.php deleted file mode 100644 index 0c4a0ff8fcd..00000000000 --- a/src/Controllers/Version2/class-wc-rest-shipping-methods-v2-controller.php +++ /dev/null @@ -1,231 +0,0 @@ - - */ - public function register_routes() { - register_rest_route( - $this->namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Check whether a given request has permission to view shipping methods. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'shipping_methods', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to read a shipping method. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'shipping_methods', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Get shipping methods. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $wc_shipping = WC_Shipping::instance(); - $response = array(); - foreach ( $wc_shipping->get_shipping_methods() as $id => $shipping_method ) { - $method = $this->prepare_item_for_response( $shipping_method, $request ); - $method = $this->prepare_response_for_collection( $method ); - $response[] = $method; - } - return rest_ensure_response( $response ); - } - - /** - * Get a single Shipping Method. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function get_item( $request ) { - $wc_shipping = WC_Shipping::instance(); - $methods = $wc_shipping->get_shipping_methods(); - if ( empty( $methods[ $request['id'] ] ) ) { - return new WP_Error( 'woocommerce_rest_shipping_method_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $method = $methods[ $request['id'] ]; - $response = $this->prepare_item_for_response( $method, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Prepare a shipping method for response. - * - * @param WC_Shipping_Method $method Shipping method object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $method, $request ) { - $data = array( - 'id' => $method->id, - 'title' => $method->method_title, - 'description' => $method->method_description, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $method, $request ) ); - - /** - * Filter shipping methods object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WC_Shipping_Method $method Shipping method object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_shipping_method', $response, $method, $request ); - } - - /** - * Prepare links for the request. - * - * @param WC_Shipping_Method $method Shipping method object. - * @param WP_REST_Request $request Request object. - * @return array - */ - protected function prepare_links( $method, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $method->id ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the shipping method schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'shipping_method', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Method ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'title' => array( - 'description' => __( 'Shipping method title.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'Shipping method description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get any query params needed. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-shipping-zone-locations-v2-controller.php b/src/Controllers/Version2/class-wc-rest-shipping-zone-locations-v2-controller.php deleted file mode 100644 index 434906709c7..00000000000 --- a/src/Controllers/Version2/class-wc-rest-shipping-zone-locations-v2-controller.php +++ /dev/null @@ -1,190 +0,0 @@ -/locations endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Shipping Zone Locations class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Shipping_Zones_Controller_Base - */ -class WC_REST_Shipping_Zone_Locations_V2_Controller extends WC_REST_Shipping_Zones_Controller_Base { - - /** - * Register the routes for Shipping Zone Locations. - */ - public function register_routes() { - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/locations', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique ID for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_items' ), - 'permission_callback' => array( $this, 'update_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Get all Shipping Zone Locations. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function get_items( $request ) { - $zone = $this->get_zone( (int) $request['id'] ); - - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $locations = $zone->get_zone_locations(); - $data = array(); - - foreach ( $locations as $location_obj ) { - $location = $this->prepare_item_for_response( $location_obj, $request ); - $location = $this->prepare_response_for_collection( $location ); - $data[] = $location; - } - - return rest_ensure_response( $data ); - } - - /** - * Update all Shipping Zone Locations. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function update_items( $request ) { - $zone = $this->get_zone( (int) $request['id'] ); - - if ( is_wp_error( $zone ) ) { - return $zone; - } - - if ( 0 === $zone->get_id() ) { - return new WP_Error( 'woocommerce_rest_shipping_zone_locations_invalid_zone', __( 'The "locations not covered by your other zones" zone cannot be updated.', 'woocommerce-rest-api' ), array( 'status' => 403 ) ); - } - - $raw_locations = $request->get_json_params(); - $locations = array(); - - foreach ( (array) $raw_locations as $raw_location ) { - if ( empty( $raw_location['code'] ) ) { - continue; - } - - $type = ! empty( $raw_location['type'] ) ? sanitize_text_field( $raw_location['type'] ) : 'country'; - - if ( ! in_array( $type, array( 'postcode', 'state', 'country', 'continent' ), true ) ) { - continue; - } - - $locations[] = array( - 'code' => sanitize_text_field( $raw_location['code'] ), - 'type' => sanitize_text_field( $type ), - ); - } - - $zone->set_locations( $locations ); - $zone->save(); - - return $this->get_items( $request ); - } - - /** - * Prepare the Shipping Zone Location for the REST response. - * - * @param array $item Shipping Zone Location. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response - */ - public function prepare_item_for_response( $item, $request ) { - $context = empty( $request['context'] ) ? 'view' : $request['context']; - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( (int) $request['id'] ) ); - - return $response; - } - - /** - * Prepare links for the request. - * - * @param int $zone_id Given Shipping Zone ID. - * @return array Links for the given Shipping Zone Location. - */ - protected function prepare_links( $zone_id ) { - $base = '/' . $this->namespace . '/' . $this->rest_base . '/' . $zone_id; - $links = array( - 'collection' => array( - 'href' => rest_url( $base . '/locations' ), - ), - 'describes' => array( - 'href' => rest_url( $base ), - ), - ); - - return $links; - } - - /** - * Get the Shipping Zone Locations schema, conforming to JSON Schema - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'shipping_zone_location', - 'type' => 'object', - 'properties' => array( - 'code' => array( - 'description' => __( 'Shipping zone location code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'type' => array( - 'description' => __( 'Shipping zone location type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'country', - 'enum' => array( - 'postcode', - 'state', - 'country', - 'continent', - ), - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-shipping-zone-methods-v2-controller.php b/src/Controllers/Version2/class-wc-rest-shipping-zone-methods-v2-controller.php deleted file mode 100644 index 67ad37bfd26..00000000000 --- a/src/Controllers/Version2/class-wc-rest-shipping-zone-methods-v2-controller.php +++ /dev/null @@ -1,541 +0,0 @@ -/methods endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Shipping Zone Methods class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Shipping_Zones_Controller_Base - */ -class WC_REST_Shipping_Zone_Methods_V2_Controller extends WC_REST_Shipping_Zones_Controller_Base { - - /** - * Register the routes for Shipping Zone Methods. - */ - public function register_routes() { - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/methods', array( - 'args' => array( - 'zone_id' => array( - 'description' => __( 'Unique ID for the zone.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( - $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'method_id' => array( - 'required' => true, - 'readonly' => false, - 'description' => __( 'Shipping method ID.', 'woocommerce-rest-api' ), - ), - ) - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/methods/(?P[\d]+)', array( - 'args' => array( - 'zone_id' => array( - 'description' => __( 'Unique ID for the zone.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'instance_id' => array( - 'description' => __( 'Unique ID for the instance.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_items_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Get a single Shipping Zone Method. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function get_item( $request ) { - $zone = $this->get_zone( $request['zone_id'] ); - - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $instance_id = (int) $request['instance_id']; - $methods = $zone->get_shipping_methods(); - $method = false; - - foreach ( $methods as $method_obj ) { - if ( $instance_id === $method_obj->instance_id ) { - $method = $method_obj; - break; - } - } - - if ( false === $method ) { - return new WP_Error( 'woocommerce_rest_shipping_zone_method_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $data = $this->prepare_item_for_response( $method, $request ); - - return rest_ensure_response( $data ); - } - - /** - * Get all Shipping Zone Methods. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function get_items( $request ) { - $zone = $this->get_zone( $request['zone_id'] ); - - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $methods = $zone->get_shipping_methods(); - $data = array(); - - foreach ( $methods as $method_obj ) { - $method = $this->prepare_item_for_response( $method_obj, $request ); - $data[] = $method; - } - - return rest_ensure_response( $data ); - } - - /** - * Create a new shipping zone method instance. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function create_item( $request ) { - $method_id = $request['method_id']; - $zone = $this->get_zone( $request['zone_id'] ); - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $instance_id = $zone->add_shipping_method( $method_id ); - $methods = $zone->get_shipping_methods(); - $method = false; - foreach ( $methods as $method_obj ) { - if ( $instance_id === $method_obj->instance_id ) { - $method = $method_obj; - break; - } - } - - if ( false === $method ) { - return new WP_Error( 'woocommerce_rest_shipping_zone_not_created', __( 'Resource cannot be created.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - $method = $this->update_fields( $instance_id, $method, $request ); - if ( is_wp_error( $method ) ) { - return $method; - } - - $data = $this->prepare_item_for_response( $method, $request ); - return rest_ensure_response( $data ); - } - - /** - * Delete a shipping method instance. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item( $request ) { - $zone = $this->get_zone( $request['zone_id'] ); - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $instance_id = (int) $request['instance_id']; - $force = $request['force']; - - $methods = $zone->get_shipping_methods(); - $method = false; - - foreach ( $methods as $method_obj ) { - if ( $instance_id === $method_obj->instance_id ) { - $method = $method_obj; - break; - } - } - - if ( false === $method ) { - return new WP_Error( 'woocommerce_rest_shipping_zone_method_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $method = $this->update_fields( $instance_id, $method, $request ); - if ( is_wp_error( $method ) ) { - return $method; - } - - $request->set_param( 'context', 'view' ); - $response = $this->prepare_item_for_response( $method, $request ); - - // Actually delete. - if ( $force ) { - $zone->delete_shipping_method( $instance_id ); - } else { - return new WP_Error( 'rest_trash_not_supported', __( 'Shipping methods do not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - /** - * Fires after a product review is deleted via the REST API. - * - * @param object $method - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'rest_delete_product_review', $method, $response, $request ); - - return $response; - } - - /** - * Update A Single Shipping Zone Method. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function update_item( $request ) { - $zone = $this->get_zone( $request['zone_id'] ); - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $instance_id = (int) $request['instance_id']; - $methods = $zone->get_shipping_methods(); - $method = false; - - foreach ( $methods as $method_obj ) { - if ( $instance_id === $method_obj->instance_id ) { - $method = $method_obj; - break; - } - } - - if ( false === $method ) { - return new WP_Error( 'woocommerce_rest_shipping_zone_method_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $method = $this->update_fields( $instance_id, $method, $request ); - if ( is_wp_error( $method ) ) { - return $method; - } - - $data = $this->prepare_item_for_response( $method, $request ); - return rest_ensure_response( $data ); - } - - /** - * Updates settings, order, and enabled status on create. - * - * @param int $instance_id Instance ID. - * @param WC_Shipping_Method $method Shipping method data. - * @param WP_REST_Request $request Request data. - * - * @return WC_Shipping_Method - */ - public function update_fields( $instance_id, $method, $request ) { - global $wpdb; - - // Update settings if present. - if ( isset( $request['settings'] ) ) { - $method->init_instance_settings(); - $instance_settings = $method->instance_settings; - $errors_found = false; - foreach ( $method->get_instance_form_fields() as $key => $field ) { - if ( isset( $request['settings'][ $key ] ) ) { - if ( is_callable( array( $this, 'validate_setting_' . $field['type'] . '_field' ) ) ) { - $value = $this->{'validate_setting_' . $field['type'] . '_field'}( $request['settings'][ $key ], $field ); - } else { - $value = $this->validate_setting_text_field( $request['settings'][ $key ], $field ); - } - if ( is_wp_error( $value ) ) { - $errors_found = true; - break; - } - $instance_settings[ $key ] = $value; - } - } - - if ( $errors_found ) { - return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - update_option( $method->get_instance_option_key(), apply_filters( 'woocommerce_shipping_' . $method->id . '_instance_settings_values', $instance_settings, $method ) ); - } - - // Update order. - if ( isset( $request['order'] ) ) { - $wpdb->update( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'method_order' => absint( $request['order'] ) ), array( 'instance_id' => absint( $instance_id ) ) ); - $method->method_order = absint( $request['order'] ); - } - - // Update if this method is enabled or not. - if ( isset( $request['enabled'] ) ) { - if ( $wpdb->update( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'is_enabled' => $request['enabled'] ), array( 'instance_id' => absint( $instance_id ) ) ) ) { - do_action( 'woocommerce_shipping_zone_method_status_toggled', $instance_id, $method->id, $request['zone_id'], $request['enabled'] ); - $method->enabled = ( true === $request['enabled'] ? 'yes' : 'no' ); - } - } - - return $method; - } - - /** - * Prepare the Shipping Zone Method for the REST response. - * - * @param array $item Shipping Zone Method. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response - */ - public function prepare_item_for_response( $item, $request ) { - $method = array( - 'id' => $item->instance_id, - 'instance_id' => $item->instance_id, - 'title' => $item->instance_settings['title'], - 'order' => $item->method_order, - 'enabled' => ( 'yes' === $item->enabled ), - 'method_id' => $item->id, - 'method_title' => $item->method_title, - 'method_description' => $item->method_description, - 'settings' => $this->get_settings( $item ), - ); - - $context = empty( $request['context'] ) ? 'view' : $request['context']; - $data = $this->add_additional_fields_to_object( $method, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $request['zone_id'], $item->instance_id ) ); - - $response = $this->prepare_response_for_collection( $response ); - - return $response; - } - - /** - * Return settings associated with this shipping zone method instance. - * - * @param WC_Shipping_Method $item Shipping method data. - * - * @return array - */ - public function get_settings( $item ) { - $item->init_instance_settings(); - $settings = array(); - foreach ( $item->get_instance_form_fields() as $id => $field ) { - $data = array( - 'id' => $id, - 'label' => $field['title'], - 'description' => empty( $field['description'] ) ? '' : $field['description'], - 'type' => $field['type'], - 'value' => $item->instance_settings[ $id ], - 'default' => empty( $field['default'] ) ? '' : $field['default'], - 'tip' => empty( $field['description'] ) ? '' : $field['description'], - 'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'], - ); - if ( ! empty( $field['options'] ) ) { - $data['options'] = $field['options']; - } - $settings[ $id ] = $data; - } - return $settings; - } - - /** - * Prepare links for the request. - * - * @param int $zone_id Given Shipping Zone ID. - * @param int $instance_id Given Shipping Zone Method Instance ID. - * @return array Links for the given Shipping Zone Method. - */ - protected function prepare_links( $zone_id, $instance_id ) { - $base = '/' . $this->namespace . '/' . $this->rest_base . '/' . $zone_id; - $links = array( - 'self' => array( - 'href' => rest_url( $base . '/methods/' . $instance_id ), - ), - 'collection' => array( - 'href' => rest_url( $base . '/methods' ), - ), - 'describes' => array( - 'href' => rest_url( $base ), - ), - ); - - return $links; - } - - /** - * Get the Shipping Zone Methods schema, conforming to JSON Schema - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'shipping_zone_method', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Shipping method instance ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'instance_id' => array( - 'description' => __( 'Shipping method instance ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'title' => array( - 'description' => __( 'Shipping method customer facing title.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'order' => array( - 'description' => __( 'Shipping method sort order.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'enabled' => array( - 'description' => __( 'Shipping method enabled status.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - ), - 'method_id' => array( - 'description' => __( 'Shipping method ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'method_title' => array( - 'description' => __( 'Shipping method title.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'method_description' => array( - 'description' => __( 'Shipping method description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'settings' => array( - 'description' => __( 'Shipping method settings.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Type of setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'enum' => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Setting value.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'default' => array( - 'description' => __( 'Default value for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tip' => array( - 'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'placeholder' => array( - 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-shipping-zones-v2-controller.php b/src/Controllers/Version2/class-wc-rest-shipping-zones-v2-controller.php deleted file mode 100644 index cd8a6b75ccf..00000000000 --- a/src/Controllers/Version2/class-wc-rest-shipping-zones-v2-controller.php +++ /dev/null @@ -1,304 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( - $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'name' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Shipping zone name.', 'woocommerce-rest-api' ), - ), - ) - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique ID for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_items_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Get a single Shipping Zone. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response|WP_Error - */ - public function get_item( $request ) { - $zone = $this->get_zone( $request->get_param( 'id' ) ); - - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $data = $zone->get_data(); - $data = $this->prepare_item_for_response( $data, $request ); - $data = $this->prepare_response_for_collection( $data ); - - return rest_ensure_response( $data ); - } - - /** - * Get all Shipping Zones. - * - * @param WP_REST_Request $request Request data. - * @return WP_REST_Response - */ - public function get_items( $request ) { - $rest_of_the_world = WC_Shipping_Zones::get_zone_by( 'zone_id', 0 ); - - $zones = WC_Shipping_Zones::get_zones(); - array_unshift( $zones, $rest_of_the_world->get_data() ); - $data = array(); - - foreach ( $zones as $zone_obj ) { - $zone = $this->prepare_item_for_response( $zone_obj, $request ); - $zone = $this->prepare_response_for_collection( $zone ); - $data[] = $zone; - } - - return rest_ensure_response( $data ); - } - - /** - * Create a single Shipping Zone. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function create_item( $request ) { - $zone = new WC_Shipping_Zone( null ); - - if ( ! is_null( $request->get_param( 'name' ) ) ) { - $zone->set_zone_name( $request->get_param( 'name' ) ); - } - - if ( ! is_null( $request->get_param( 'order' ) ) ) { - $zone->set_zone_order( $request->get_param( 'order' ) ); - } - - $zone->save(); - - if ( $zone->get_id() !== 0 ) { - $request->set_param( 'id', $zone->get_id() ); - $response = $this->get_item( $request ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $zone->get_id() ) ) ); - return $response; - } else { - return new WP_Error( 'woocommerce_rest_shipping_zone_not_created', __( "Resource cannot be created. Check to make sure 'order' and 'name' are present.", 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - } - - /** - * Update a single Shipping Zone. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function update_item( $request ) { - $zone = $this->get_zone( $request->get_param( 'id' ) ); - - if ( is_wp_error( $zone ) ) { - return $zone; - } - - if ( 0 === $zone->get_id() ) { - return new WP_Error( 'woocommerce_rest_shipping_zone_invalid_zone', __( 'The "locations not covered by your other zones" zone cannot be updated.', 'woocommerce-rest-api' ), array( 'status' => 403 ) ); - } - - $zone_changed = false; - - if ( ! is_null( $request->get_param( 'name' ) ) ) { - $zone->set_zone_name( $request->get_param( 'name' ) ); - $zone_changed = true; - } - - if ( ! is_null( $request->get_param( 'order' ) ) ) { - $zone->set_zone_order( $request->get_param( 'order' ) ); - $zone_changed = true; - } - - if ( $zone_changed ) { - $zone->save(); - } - - return $this->get_item( $request ); - } - - /** - * Delete a single Shipping Zone. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function delete_item( $request ) { - $zone = $this->get_zone( $request->get_param( 'id' ) ); - - if ( is_wp_error( $zone ) ) { - return $zone; - } - - $force = $request['force']; - - $response = $this->get_item( $request ); - - if ( $force ) { - $zone->delete(); - } else { - return new WP_Error( 'rest_trash_not_supported', __( 'Shipping zones do not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - return $response; - } - - /** - * Prepare the Shipping Zone for the REST response. - * - * @param array $item Shipping Zone. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response - */ - public function prepare_item_for_response( $item, $request ) { - $data = array( - 'id' => (int) $item['id'], - 'name' => $item['zone_name'], - 'order' => (int) $item['zone_order'], - ); - - $context = empty( $request['context'] ) ? 'view' : $request['context']; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $data['id'] ) ); - - return $response; - } - - /** - * Prepare links for the request. - * - * @param int $zone_id Given Shipping Zone ID. - * @return array Links for the given Shipping Zone. - */ - protected function prepare_links( $zone_id ) { - $base = '/' . $this->namespace . '/' . $this->rest_base; - $links = array( - 'self' => array( - 'href' => rest_url( trailingslashit( $base ) . $zone_id ), - ), - 'collection' => array( - 'href' => rest_url( $base ), - ), - 'describedby' => array( - 'href' => rest_url( trailingslashit( $base ) . $zone_id . '/locations' ), - ), - ); - - return $links; - } - - /** - * Get the Shipping Zones schema, conforming to JSON Schema - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'shipping_zone', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Shipping zone name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'order' => array( - 'description' => __( 'Shipping zone order.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-system-status-tools-v2-controller.php b/src/Controllers/Version2/class-wc-rest-system-status-tools-v2-controller.php deleted file mode 100644 index ee62d186b82..00000000000 --- a/src/Controllers/Version2/class-wc-rest-system-status-tools-v2-controller.php +++ /dev/null @@ -1,618 +0,0 @@ -namespace, - '/' . $this->rest_base, - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/(?P[\w-]+)', - array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Check whether a given request has permission to view system status tools. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check whether a given request has permission to view a specific system status tool. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check whether a given request has permission to execute a specific system status tool. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'system_status', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot update resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * A list of available tools for use in the system status section. - * 'button' becomes 'action' in the API. - * - * @return array - */ - public function get_tools() { - $tools = array( - 'clear_transients' => array( - 'name' => __( 'WooCommerce transients', 'woocommerce-rest-api' ), - 'button' => __( 'Clear transients', 'woocommerce-rest-api' ), - 'desc' => __( 'This tool will clear the product/shop transients cache.', 'woocommerce-rest-api' ), - ), - 'clear_expired_transients' => array( - 'name' => __( 'Expired transients', 'woocommerce-rest-api' ), - 'button' => __( 'Clear transients', 'woocommerce-rest-api' ), - 'desc' => __( 'This tool will clear ALL expired transients from WordPress.', 'woocommerce-rest-api' ), - ), - 'delete_orphaned_variations' => array( - 'name' => __( 'Orphaned variations', 'woocommerce-rest-api' ), - 'button' => __( 'Delete orphaned variations', 'woocommerce-rest-api' ), - 'desc' => __( 'This tool will delete all variations which have no parent.', 'woocommerce-rest-api' ), - ), - 'clear_expired_download_permissions' => array( - 'name' => __( 'Used-up download permissions', 'woocommerce-rest-api' ), - 'button' => __( 'Clean up download permissions', 'woocommerce-rest-api' ), - 'desc' => __( 'This tool will delete expired download permissions and permissions with 0 remaining downloads.', 'woocommerce-rest-api' ), - ), - 'regenerate_product_lookup_tables' => array( - 'name' => __( 'Product lookup tables', 'woocommerce-rest-api' ), - 'button' => __( 'Regenerate', 'woocommerce-rest-api' ), - 'desc' => __( 'This tool will regenerate product lookup table data. This process may take a while.', 'woocommerce-rest-api' ), - ), - 'recount_terms' => array( - 'name' => __( 'Term counts', 'woocommerce-rest-api' ), - 'button' => __( 'Recount terms', 'woocommerce-rest-api' ), - 'desc' => __( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', 'woocommerce-rest-api' ), - ), - 'reset_roles' => array( - 'name' => __( 'Capabilities', 'woocommerce-rest-api' ), - 'button' => __( 'Reset capabilities', 'woocommerce-rest-api' ), - 'desc' => __( 'This tool will reset the admin, customer and shop_manager roles to default. Use this if your users cannot access all of the WooCommerce admin pages.', 'woocommerce-rest-api' ), - ), - 'clear_sessions' => array( - 'name' => __( 'Clear customer sessions', 'woocommerce-rest-api' ), - 'button' => __( 'Clear', 'woocommerce-rest-api' ), - 'desc' => sprintf( - '%1$s %2$s', - __( 'Note:', 'woocommerce-rest-api' ), - __( 'This tool will delete all customer session data from the database, including current carts and saved carts in the database.', 'woocommerce-rest-api' ) - ), - ), - 'clear_template_cache' => array( - 'name' => __( 'Clear template cache', 'woocommerce-rest-api' ), - 'button' => __( 'Clear', 'woocommerce-rest-api' ), - 'desc' => sprintf( - '%1$s %2$s', - __( 'Note:', 'woocommerce-rest-api' ), - __( 'This tool will empty the template cache.', 'woocommerce-rest-api' ) - ), - ), - 'install_pages' => array( - 'name' => __( 'Create default WooCommerce pages', 'woocommerce-rest-api' ), - 'button' => __( 'Create pages', 'woocommerce-rest-api' ), - 'desc' => sprintf( - '%1$s %2$s', - __( 'Note:', 'woocommerce-rest-api' ), - __( 'This tool will install all the missing WooCommerce pages. Pages already defined and set up will not be replaced.', 'woocommerce-rest-api' ) - ), - ), - 'delete_taxes' => array( - 'name' => __( 'Delete WooCommerce tax rates', 'woocommerce-rest-api' ), - 'button' => __( 'Delete tax rates', 'woocommerce-rest-api' ), - 'desc' => sprintf( - '%1$s %2$s', - __( 'Note:', 'woocommerce-rest-api' ), - __( 'This option will delete ALL of your tax rates, use with caution. This action cannot be reversed.', 'woocommerce-rest-api' ) - ), - ), - 'regenerate_thumbnails' => array( - 'name' => __( 'Regenerate shop thumbnails', 'woocommerce-rest-api' ), - 'button' => __( 'Regenerate', 'woocommerce-rest-api' ), - 'desc' => __( 'This will regenerate all shop thumbnails to match your theme and/or image settings.', 'woocommerce-rest-api' ), - ), - 'db_update_routine' => array( - 'name' => __( 'Update database', 'woocommerce-rest-api' ), - 'button' => __( 'Update database', 'woocommerce-rest-api' ), - 'desc' => sprintf( - '%1$s %2$s', - __( 'Note:', 'woocommerce-rest-api' ), - __( 'This tool will update your WooCommerce database to the latest version. Please ensure you make sufficient backups before proceeding.', 'woocommerce-rest-api' ) - ), - ), - ); - if ( method_exists( 'WC_Install', 'verify_base_tables' ) ) { - $tools['verify_db_tables'] = array( - 'name' => __( 'Verify base database tables', 'woocommerce-rest-api' ), - 'button' => __( 'Verify database', 'woocommerce-rest-api' ), - 'desc' => sprintf( - __( 'Verify if all base database tables are present.', 'woocommerce-rest-api' ) - ), - ); - } - - // Jetpack does the image resizing heavy lifting so you don't have to. - if ( ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) || ! apply_filters( 'woocommerce_background_image_regeneration', true ) ) { - unset( $tools['regenerate_thumbnails'] ); - } - - if ( ! function_exists( 'wc_clear_template_cache' ) ) { - unset( $tools['clear_template_cache'] ); - } - - return apply_filters( 'woocommerce_debug_tools', $tools ); - } - - /** - * Get a list of system status tools. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $tools = array(); - foreach ( $this->get_tools() as $id => $tool ) { - $tools[] = $this->prepare_response_for_collection( - $this->prepare_item_for_response( - array( - 'id' => $id, - 'name' => $tool['name'], - 'action' => $tool['button'], - 'description' => $tool['desc'], - ), - $request - ) - ); - } - - $response = rest_ensure_response( $tools ); - return $response; - } - - /** - * Return a single tool. - * - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $tools = $this->get_tools(); - if ( empty( $tools[ $request['id'] ] ) ) { - return new WP_Error( 'woocommerce_rest_system_status_tool_invalid_id', __( 'Invalid tool ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - $tool = $tools[ $request['id'] ]; - return rest_ensure_response( - $this->prepare_item_for_response( - array( - 'id' => $request['id'], - 'name' => $tool['name'], - 'action' => $tool['button'], - 'description' => $tool['desc'], - ), - $request - ) - ); - } - - /** - * Update (execute) a tool. - * - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $tools = $this->get_tools(); - if ( empty( $tools[ $request['id'] ] ) ) { - return new WP_Error( 'woocommerce_rest_system_status_tool_invalid_id', __( 'Invalid tool ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $tool = $tools[ $request['id'] ]; - $tool = array( - 'id' => $request['id'], - 'name' => $tool['name'], - 'action' => $tool['button'], - 'description' => $tool['desc'], - ); - - $execute_return = $this->execute_tool( $request['id'] ); - $tool = array_merge( $tool, $execute_return ); - - /** - * Fires after a WooCommerce REST system status tool has been executed. - * - * @param array $tool Details about the tool that has been executed. - * @param WP_REST_Request $request The current WP_REST_Request object. - */ - do_action( 'woocommerce_rest_insert_system_status_tool', $tool, $request ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $tool, $request ); - return rest_ensure_response( $response ); - } - - /** - * Prepare a tool item for serialization. - * - * @param array $item Object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $item, $request ) { - $context = empty( $request['context'] ) ? 'view' : $request['context']; - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item['id'] ) ); - - return $response; - } - - /** - * Get the system status tools schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'system_status_tool', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier for the tool.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'name' => array( - 'description' => __( 'Tool name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'action' => array( - 'description' => __( 'What running the tool will do.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'description' => array( - 'description' => __( 'Tool description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'success' => array( - 'description' => __( 'Did the tool run successfully?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'edit' ), - ), - 'message' => array( - 'description' => __( 'Tool return message.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Prepare links for the request. - * - * @param string $id ID. - * @return array - */ - protected function prepare_links( $id ) { - $base = '/' . $this->namespace . '/' . $this->rest_base; - $links = array( - 'item' => array( - 'href' => rest_url( trailingslashit( $base ) . $id ), - 'embeddable' => true, - ), - ); - - return $links; - } - - /** - * Get any query params needed. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } - - /** - * Actually executes a tool. - * - * @param string $tool Tool. - * @return array - */ - public function execute_tool( $tool ) { - global $wpdb; - $ran = true; - switch ( $tool ) { - case 'clear_transients': - wc_delete_product_transients(); - wc_delete_shop_order_transients(); - delete_transient( 'wc_count_comments' ); - delete_transient( 'as_comment_count' ); - - $attribute_taxonomies = wc_get_attribute_taxonomies(); - - if ( $attribute_taxonomies ) { - foreach ( $attribute_taxonomies as $attribute ) { - delete_transient( 'wc_layered_nav_counts_pa_' . $attribute->attribute_name ); - } - } - - WC_Cache_Helper::get_transient_version( 'shipping', true ); - $message = __( 'Product transients cleared', 'woocommerce-rest-api' ); - break; - - case 'clear_expired_transients': - /* translators: %d: amount of expired transients */ - $message = sprintf( __( '%d transients rows cleared', 'woocommerce-rest-api' ), wc_delete_expired_transients() ); - break; - - case 'delete_orphaned_variations': - // Delete orphans. - $result = absint( - $wpdb->query( - "DELETE products - FROM {$wpdb->posts} products - LEFT JOIN {$wpdb->posts} wp ON wp.ID = products.post_parent - WHERE wp.ID IS NULL AND products.post_type = 'product_variation';" - ) - ); - /* translators: %d: amount of orphaned variations */ - $message = sprintf( __( '%d orphaned variations deleted', 'woocommerce-rest-api' ), $result ); - break; - - case 'clear_expired_download_permissions': - // Delete expired download permissions and ones with 0 downloads remaining. - $result = absint( - $wpdb->query( - $wpdb->prepare( - "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions - WHERE ( downloads_remaining != '' AND downloads_remaining = 0 ) OR ( access_expires IS NOT NULL AND access_expires < %s )", - gmdate( 'Y-m-d', current_time( 'timestamp' ) ) - ) - ) - ); - /* translators: %d: amount of permissions */ - $message = sprintf( __( '%d permissions deleted', 'woocommerce-rest-api' ), $result ); - break; - - case 'regenerate_product_lookup_tables': - if ( ! wc_update_product_lookup_tables_is_running() ) { - wc_update_product_lookup_tables(); - } - $message = __( 'Lookup tables are regenerating', 'woocommerce-rest-api' ); - break; - case 'reset_roles': - // Remove then re-add caps and roles. - WC_Install::remove_roles(); - WC_Install::create_roles(); - $message = __( 'Roles successfully reset', 'woocommerce-rest-api' ); - break; - - case 'recount_terms': - $product_cats = get_terms( - 'product_cat', - array( - 'hide_empty' => false, - 'fields' => 'id=>parent', - ) - ); - _wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), true, false ); - $product_tags = get_terms( - 'product_tag', - array( - 'hide_empty' => false, - 'fields' => 'id=>parent', - ) - ); - _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), true, false ); - $message = __( 'Terms successfully recounted', 'woocommerce-rest-api' ); - break; - - case 'clear_sessions': - $wpdb->query( "TRUNCATE {$wpdb->prefix}woocommerce_sessions" ); - $result = absint( $wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key='_woocommerce_persistent_cart_" . get_current_blog_id() . "';" ) ); // WPCS: unprepared SQL ok. - wp_cache_flush(); - /* translators: %d: amount of sessions */ - $message = sprintf( __( 'Deleted all active sessions, and %d saved carts.', 'woocommerce-rest-api' ), absint( $result ) ); - break; - - case 'install_pages': - WC_Install::create_pages(); - $message = __( 'All missing WooCommerce pages successfully installed', 'woocommerce-rest-api' ); - break; - - case 'delete_taxes': - $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rates;" ); - $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations;" ); - - if ( method_exists( 'WC_Cache_Helper', 'invalidate_cache_group' ) ) { - WC_Cache_Helper::invalidate_cache_group( 'taxes' ); - } else { - WC_Cache_Helper::incr_cache_prefix( 'taxes' ); - } - $message = __( 'Tax rates successfully deleted', 'woocommerce-rest-api' ); - break; - - case 'regenerate_thumbnails': - WC_Regenerate_Images::queue_image_regeneration(); - $message = __( 'Thumbnail regeneration has been scheduled to run in the background.', 'woocommerce-rest-api' ); - break; - - case 'db_update_routine': - $blog_id = get_current_blog_id(); - // Used to fire an action added in WP_Background_Process::_construct() that calls WP_Background_Process::handle_cron_healthcheck(). - // This method will make sure the database updates are executed even if cron is disabled. Nothing will happen if the updates are already running. - do_action( 'wp_' . $blog_id . '_wc_updater_cron' ); - $message = __( 'Database upgrade routine has been scheduled to run in the background.', 'woocommerce-rest-api' ); - break; - - case 'clear_template_cache': - if ( function_exists( 'wc_clear_template_cache' ) ) { - wc_clear_template_cache(); - $message = __( 'Template cache cleared.', 'woocommerce-rest-api' ); - } else { - $message = __( 'The active version of WooCommerce does not support template cache clearing.', 'woocommerce-rest-api' ); - $ran = false; - } - break; - - case 'verify_db_tables': - if ( ! method_exists( 'WC_Install', 'verify_base_tables' ) ) { - $message = __( 'You need WooCommerce 4.2 or newer to run this tool.', 'woocommerce-rest-api' ); - $ran = false; - break; - } - // Try to manually create table again. - $missing_tables = WC_Install::verify_base_tables( true, true ); - if ( 0 === count( $missing_tables ) ) { - $message = __( 'Database verified successfully.', 'woocommerce-rest-api' ); - } else { - $message = __( 'Verifying database... One or more tables are still missing: ', 'woocommerce-rest-api' ); - $message .= implode( ', ', $missing_tables ); - $ran = false; - } - break; - - default: - $tools = $this->get_tools(); - if ( isset( $tools[ $tool ]['callback'] ) ) { - $callback = $tools[ $tool ]['callback']; - $return = call_user_func( $callback ); - if ( is_string( $return ) ) { - $message = $return; - } elseif ( false === $return ) { - $callback_string = is_array( $callback ) ? get_class( $callback[0] ) . '::' . $callback[1] : $callback; - $ran = false; - /* translators: %s: callback string */ - $message = sprintf( __( 'There was an error calling %s', 'woocommerce-rest-api' ), $callback_string ); - } else { - $message = __( 'Tool ran.', 'woocommerce-rest-api' ); - } - } else { - $ran = false; - $message = __( 'There was an error calling this tool. There is no callback present.', 'woocommerce-rest-api' ); - } - break; - } - - return array( - 'success' => $ran, - 'message' => $message, - ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-system-status-v2-controller.php b/src/Controllers/Version2/class-wc-rest-system-status-v2-controller.php deleted file mode 100644 index 448f30f0725..00000000000 --- a/src/Controllers/Version2/class-wc-rest-system-status-v2-controller.php +++ /dev/null @@ -1,1259 +0,0 @@ -namespace, - '/' . $this->rest_base, - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Check whether a given request has permission to view system status. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'system_status', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Get a system status info, by section. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $fields = $this->get_fields_for_response( $request ); - $mappings = $this->get_item_mappings_per_fields( $fields ); - $response = $this->prepare_item_for_response( $mappings, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Get the system status schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'system_status', - 'type' => 'object', - 'properties' => array( - 'environment' => array( - 'description' => __( 'Environment.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'home_url' => array( - 'description' => __( 'Home URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'site_url' => array( - 'description' => __( 'Site URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'version' => array( - 'description' => __( 'WooCommerce version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'log_directory' => array( - 'description' => __( 'Log directory.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'log_directory_writable' => array( - 'description' => __( 'Is log directory writable?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'wp_version' => array( - 'description' => __( 'WordPress version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'wp_multisite' => array( - 'description' => __( 'Is WordPress multisite?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'wp_memory_limit' => array( - 'description' => __( 'WordPress memory limit.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'wp_debug_mode' => array( - 'description' => __( 'Is WordPress debug mode active?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'wp_cron' => array( - 'description' => __( 'Are WordPress cron jobs enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'language' => array( - 'description' => __( 'WordPress language.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'server_info' => array( - 'description' => __( 'Server info.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'php_version' => array( - 'description' => __( 'PHP version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'php_post_max_size' => array( - 'description' => __( 'PHP post max size.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'php_max_execution_time' => array( - 'description' => __( 'PHP max execution time.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'php_max_input_vars' => array( - 'description' => __( 'PHP max input vars.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'curl_version' => array( - 'description' => __( 'cURL version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'suhosin_installed' => array( - 'description' => __( 'Is SUHOSIN installed?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'max_upload_size' => array( - 'description' => __( 'Max upload size.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'mysql_version' => array( - 'description' => __( 'MySQL version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'mysql_version_string' => array( - 'description' => __( 'MySQL version string.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'default_timezone' => array( - 'description' => __( 'Default timezone.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'fsockopen_or_curl_enabled' => array( - 'description' => __( 'Is fsockopen/cURL enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'soapclient_enabled' => array( - 'description' => __( 'Is SoapClient class enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'domdocument_enabled' => array( - 'description' => __( 'Is DomDocument class enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'gzip_enabled' => array( - 'description' => __( 'Is GZip enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'mbstring_enabled' => array( - 'description' => __( 'Is mbstring enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'remote_post_successful' => array( - 'description' => __( 'Remote POST successful?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'remote_post_response' => array( - 'description' => __( 'Remote POST response.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'remote_get_successful' => array( - 'description' => __( 'Remote GET successful?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'remote_get_response' => array( - 'description' => __( 'Remote GET response.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - 'database' => array( - 'description' => __( 'Database.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'wc_database_version' => array( - 'description' => __( 'WC database version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'database_prefix' => array( - 'description' => __( 'Database prefix.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'maxmind_geoip_database' => array( - 'description' => __( 'MaxMind GeoIP database.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'database_tables' => array( - 'description' => __( 'Database tables.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - ), - ), - 'active_plugins' => array( - 'description' => __( 'Active plugins.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'inactive_plugins' => array( - 'description' => __( 'Inactive plugins.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'dropins_mu_plugins' => array( - 'description' => __( 'Dropins & MU plugins.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'theme' => array( - 'description' => __( 'Theme.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'name' => array( - 'description' => __( 'Theme name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'version' => array( - 'description' => __( 'Theme version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'version_latest' => array( - 'description' => __( 'Latest version of theme.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'author_url' => array( - 'description' => __( 'Theme author URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'is_child_theme' => array( - 'description' => __( 'Is this theme a child theme?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'has_woocommerce_support' => array( - 'description' => __( 'Does the theme declare WooCommerce support?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'has_woocommerce_file' => array( - 'description' => __( 'Does the theme have a woocommerce.php file?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'has_outdated_templates' => array( - 'description' => __( 'Does this theme have outdated templates?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'overrides' => array( - 'description' => __( 'Template overrides.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'parent_name' => array( - 'description' => __( 'Parent theme name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'parent_version' => array( - 'description' => __( 'Parent theme version.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'parent_author_url' => array( - 'description' => __( 'Parent theme author URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - 'settings' => array( - 'description' => __( 'Settings.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'api_enabled' => array( - 'description' => __( 'REST API enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'force_ssl' => array( - 'description' => __( 'SSL forced?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'currency' => array( - 'description' => __( 'Currency.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'currency_symbol' => array( - 'description' => __( 'Currency symbol.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'currency_position' => array( - 'description' => __( 'Currency position.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'thousand_separator' => array( - 'description' => __( 'Thousand separator.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'decimal_separator' => array( - 'description' => __( 'Decimal separator.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'number_of_decimals' => array( - 'description' => __( 'Number of decimals.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'geolocation_enabled' => array( - 'description' => __( 'Geolocation enabled?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'taxonomies' => array( - 'description' => __( 'Taxonomy terms for product/order statuses.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'product_visibility_terms' => array( - 'description' => __( 'Terms in the product visibility taxonomy.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - ), - ), - 'security' => array( - 'description' => __( 'Security.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'secure_connection' => array( - 'description' => __( 'Is the connection to your store secure?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'hide_errors' => array( - 'description' => __( 'Hide errors from visitors?', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - 'pages' => array( - 'description' => __( 'WooCommerce pages.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'post_type_counts' => array( - 'description' => __( 'Total post count.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Return an array of sections and the data associated with each. - * - * @deprecated 3.9.0 - * @return array - */ - public function get_item_mappings() { - return array( - 'environment' => $this->get_environment_info(), - 'database' => $this->get_database_info(), - 'active_plugins' => $this->get_active_plugins(), - 'inactive_plugins' => $this->get_inactive_plugins(), - 'dropins_mu_plugins' => $this->get_dropins_mu_plugins(), - 'theme' => $this->get_theme_info(), - 'settings' => $this->get_settings(), - 'security' => $this->get_security_info(), - 'pages' => $this->get_pages(), - 'post_type_counts' => $this->get_post_type_counts(), - ); - } - - /** - * Return an array of sections and the data associated with each. - * - * @since 3.9.0 - * @param array $fields List of fields to be included on the response. - * @return array - */ - public function get_item_mappings_per_fields( $fields ) { - return array( - 'environment' => $this->get_environment_info_per_fields( $fields ), - 'database' => $this->get_database_info(), - 'active_plugins' => $this->get_active_plugins(), - 'inactive_plugins' => $this->get_inactive_plugins(), - 'dropins_mu_plugins' => $this->get_dropins_mu_plugins(), - 'theme' => $this->get_theme_info(), - 'settings' => $this->get_settings(), - 'security' => $this->get_security_info(), - 'pages' => $this->get_pages(), - 'post_type_counts' => $this->get_post_type_counts(), - ); - } - - /** - * Get array of environment information. Includes thing like software - * versions, and various server settings. - * - * @deprecated 3.9.0 - * @return array - */ - public function get_environment_info() { - return $this->get_environment_info_per_fields( array( 'environment' ) ); - } - - /** - * Check if field item exists. - * - * @since 3.9.0 - * @param string $section Fields section. - * @param array $items List of items to check for. - * @param array $fields List of fields to be included on the response. - * @return bool - */ - private function check_if_field_item_exists( $section, $items, $fields ) { - if ( ! in_array( $section, $fields, true ) ) { - return false; - } - - $exclude = array(); - foreach ( $fields as $field ) { - $values = explode( '.', $field ); - - if ( $section !== $values[0] || empty( $values[1] ) ) { - continue; - } - - $exclude[] = $values[1]; - } - - return 0 <= count( array_intersect( $items, $exclude ) ); - } - - /** - * Get array of environment information. Includes thing like software - * versions, and various server settings. - * - * @param array $fields List of fields to be included on the response. - * @return array - */ - public function get_environment_info_per_fields( $fields ) { - global $wpdb; - - $enable_remote_post = $this->check_if_field_item_exists( 'environment', array( 'remote_post_successful', 'remote_post_response' ), $fields ); - $enable_remote_get = $this->check_if_field_item_exists( 'environment', array( 'remote_get_successful', 'remote_get_response' ), $fields ); - - // Figure out cURL version, if installed. - $curl_version = ''; - if ( function_exists( 'curl_version' ) ) { - $curl_version = curl_version(); - $curl_version = $curl_version['version'] . ', ' . $curl_version['ssl_version']; - } elseif ( extension_loaded( 'curl' ) ) { - $curl_version = __( 'cURL installed but unable to retrieve version.', 'woocommerce-rest-api' ); - } - - // WP memory limit. - $wp_memory_limit = wc_let_to_num( WP_MEMORY_LIMIT ); - if ( function_exists( 'memory_get_usage' ) ) { - $wp_memory_limit = max( $wp_memory_limit, wc_let_to_num( @ini_get( 'memory_limit' ) ) ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged - } - - // Test POST requests. - $post_response_successful = null; - $post_response_code = null; - if ( $enable_remote_post ) { - $post_response_code = get_transient( 'woocommerce_test_remote_post' ); - - if ( false === $post_response_code || is_wp_error( $post_response_code ) ) { - $response = wp_safe_remote_post( - 'https://www.paypal.com/cgi-bin/webscr', - array( - 'timeout' => 10, - 'user-agent' => 'WooCommerce/' . WC()->version, - 'httpversion' => '1.1', - 'body' => array( - 'cmd' => '_notify-validate', - ), - ) - ); - if ( ! is_wp_error( $response ) ) { - $post_response_code = $response['response']['code']; - } - set_transient( 'woocommerce_test_remote_post', $post_response_code, HOUR_IN_SECONDS ); - } - - $post_response_successful = ! is_wp_error( $post_response_code ) && $post_response_code >= 200 && $post_response_code < 300; - } - - // Test GET requests. - $get_response_successful = null; - $get_response_code = null; - if ( $enable_remote_get ) { - $get_response_code = get_transient( 'woocommerce_test_remote_get' ); - - if ( false === $get_response_code || is_wp_error( $get_response_code ) ) { - $response = wp_safe_remote_get( 'https://woocommerce.com/wc-api/product-key-api?request=ping&network=' . ( is_multisite() ? '1' : '0' ) ); - if ( ! is_wp_error( $response ) ) { - $get_response_code = $response['response']['code']; - } - set_transient( 'woocommerce_test_remote_get', $get_response_code, HOUR_IN_SECONDS ); - } - - $get_response_successful = ! is_wp_error( $get_response_code ) && $get_response_code >= 200 && $get_response_code < 300; - } - - $database_version = wc_get_server_database_version(); - - // Return all environment info. Described by JSON Schema. - return array( - 'home_url' => get_option( 'home' ), - 'site_url' => get_option( 'siteurl' ), - 'version' => WC()->version, - 'log_directory' => WC_LOG_DIR, - 'log_directory_writable' => (bool) @fopen( WC_LOG_DIR . 'test-log.log', 'a' ), // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fopen - 'wp_version' => get_bloginfo( 'version' ), - 'wp_multisite' => is_multisite(), - 'wp_memory_limit' => $wp_memory_limit, - 'wp_debug_mode' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ), - 'wp_cron' => ! ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ), - 'language' => get_locale(), - 'external_object_cache' => wp_using_ext_object_cache(), - 'server_info' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? wc_clean( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '', - 'php_version' => phpversion(), - 'php_post_max_size' => wc_let_to_num( ini_get( 'post_max_size' ) ), - 'php_max_execution_time' => (int) ini_get( 'max_execution_time' ), - 'php_max_input_vars' => (int) ini_get( 'max_input_vars' ), - 'curl_version' => $curl_version, - 'suhosin_installed' => extension_loaded( 'suhosin' ), - 'max_upload_size' => wp_max_upload_size(), - 'mysql_version' => $database_version['number'], - 'mysql_version_string' => $database_version['string'], - 'default_timezone' => date_default_timezone_get(), - 'fsockopen_or_curl_enabled' => ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) ), - 'soapclient_enabled' => class_exists( 'SoapClient' ), - 'domdocument_enabled' => class_exists( 'DOMDocument' ), - 'gzip_enabled' => is_callable( 'gzopen' ), - 'mbstring_enabled' => extension_loaded( 'mbstring' ), - 'remote_post_successful' => $post_response_successful, - 'remote_post_response' => is_wp_error( $post_response_code ) ? $post_response_code->get_error_message() : $post_response_code, - 'remote_get_successful' => $get_response_successful, - 'remote_get_response' => is_wp_error( $get_response_code ) ? $get_response_code->get_error_message() : $get_response_code, - ); - } - - /** - * Add prefix to table. - * - * @param string $table Table name. - * @return stromg - */ - protected function add_db_table_prefix( $table ) { - global $wpdb; - return $wpdb->prefix . $table; - } - - /** - * Get array of database information. Version, prefix, and table existence. - * - * @return array - */ - public function get_database_info() { - global $wpdb; - - $tables = array(); - $database_size = array(); - - // It is not possible to get the database name from some classes that replace wpdb (e.g., HyperDB) - // and that is why this if condition is needed. - if ( defined( 'DB_NAME' ) ) { - $database_table_information = $wpdb->get_results( - $wpdb->prepare( - "SELECT - table_name AS 'name', - engine AS 'engine', - round( ( data_length / 1024 / 1024 ), 2 ) 'data', - round( ( index_length / 1024 / 1024 ), 2 ) 'index' - FROM information_schema.TABLES - WHERE table_schema = %s - ORDER BY name ASC;", - DB_NAME - ) - ); - - // WC Core tables to check existence of. - $core_tables = apply_filters( - 'woocommerce_database_tables', - array( - 'woocommerce_sessions', - 'woocommerce_api_keys', - 'woocommerce_attribute_taxonomies', - 'woocommerce_downloadable_product_permissions', - 'woocommerce_order_items', - 'woocommerce_order_itemmeta', - 'woocommerce_tax_rates', - 'woocommerce_tax_rate_locations', - 'woocommerce_shipping_zones', - 'woocommerce_shipping_zone_locations', - 'woocommerce_shipping_zone_methods', - 'woocommerce_payment_tokens', - 'woocommerce_payment_tokenmeta', - 'woocommerce_log', - ) - ); - - /** - * Adding the prefix to the tables array, for backwards compatibility. - * - * If we changed the tables above to include the prefix, then any filters against that table could break. - */ - $core_tables = array_map( array( $this, 'add_db_table_prefix' ), $core_tables ); - - /** - * Organize WooCommerce and non-WooCommerce tables separately for display purposes later. - * - * To ensure we include all WC tables, even if they do not exist, pre-populate the WC array with all the tables. - */ - $tables = array( - 'woocommerce' => array_fill_keys( $core_tables, false ), - 'other' => array(), - ); - - $database_size = array( - 'data' => 0, - 'index' => 0, - ); - - $site_tables_prefix = $wpdb->get_blog_prefix( get_current_blog_id() ); - $global_tables = $wpdb->tables( 'global', true ); - foreach ( $database_table_information as $table ) { - // Only include tables matching the prefix of the current site, this is to prevent displaying all tables on a MS install not relating to the current. - if ( is_multisite() && 0 !== strpos( $table->name, $site_tables_prefix ) && ! in_array( $table->name, $global_tables, true ) ) { - continue; - } - $table_type = in_array( $table->name, $core_tables, true ) ? 'woocommerce' : 'other'; - - $tables[ $table_type ][ $table->name ] = array( - 'data' => $table->data, - 'index' => $table->index, - 'engine' => $table->engine, - ); - - $database_size['data'] += $table->data; - $database_size['index'] += $table->index; - } - } - - // Return all database info. Described by JSON Schema. - return array( - 'wc_database_version' => get_option( 'woocommerce_db_version' ), - 'database_prefix' => $wpdb->prefix, - 'maxmind_geoip_database' => '', - 'database_tables' => $tables, - 'database_size' => $database_size, - ); - } - - /** - * Get array of counts of objects. Orders, products, etc. - * - * @return array - */ - public function get_post_type_counts() { - global $wpdb; - - $post_type_counts = $wpdb->get_results( "SELECT post_type AS 'type', count(1) AS 'count' FROM {$wpdb->posts} GROUP BY post_type;" ); - - return is_array( $post_type_counts ) ? $post_type_counts : array(); - } - - /** - * Get a list of plugins active on the site. - * - * @return array - */ - public function get_active_plugins() { - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - - if ( ! function_exists( 'get_plugin_data' ) ) { - return array(); - } - - $active_plugins = (array) get_option( 'active_plugins', array() ); - if ( is_multisite() ) { - $network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) ); - $active_plugins = array_merge( $active_plugins, $network_activated_plugins ); - } - - $active_plugins_data = array(); - - foreach ( $active_plugins as $plugin ) { - $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); - $active_plugins_data[] = $this->format_plugin_data( $plugin, $data ); - } - - return $active_plugins_data; - } - - /** - * Get a list of inplugins active on the site. - * - * @return array - */ - public function get_inactive_plugins() { - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - - if ( ! function_exists( 'get_plugins' ) ) { - return array(); - } - - $plugins = get_plugins(); - $active_plugins = (array) get_option( 'active_plugins', array() ); - - if ( is_multisite() ) { - $network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) ); - $active_plugins = array_merge( $active_plugins, $network_activated_plugins ); - } - - $plugins_data = array(); - - foreach ( $plugins as $plugin => $data ) { - if ( in_array( $plugin, $active_plugins, true ) ) { - continue; - } - $plugins_data[] = $this->format_plugin_data( $plugin, $data ); - } - - return $plugins_data; - } - - /** - * Format plugin data, including data on updates, into a standard format. - * - * @since 3.6.0 - * @param string $plugin Plugin directory/file. - * @param array $data Plugin data from WP. - * @return array Formatted data. - */ - protected function format_plugin_data( $plugin, $data ) { - require_once ABSPATH . 'wp-admin/includes/update.php'; - - if ( ! function_exists( 'get_plugin_updates' ) ) { - return array(); - } - - // Use WP API to lookup latest updates for plugins. WC_Helper injects updates for premium plugins. - if ( empty( $this->available_updates ) ) { - $this->available_updates = get_plugin_updates(); - } - - $version_latest = $data['Version']; - - // Find latest version. - if ( isset( $this->available_updates[ $plugin ]->update->new_version ) ) { - $version_latest = $this->available_updates[ $plugin ]->update->new_version; - } - - return array( - 'plugin' => $plugin, - 'name' => $data['Name'], - 'version' => $data['Version'], - 'version_latest' => $version_latest, - 'url' => $data['PluginURI'], - 'author_name' => $data['AuthorName'], - 'author_url' => esc_url_raw( $data['AuthorURI'] ), - 'network_activated' => $data['Network'], - ); - } - - /** - * Get a list of Dropins and MU plugins. - * - * @since 3.6.0 - * @return array - */ - public function get_dropins_mu_plugins() { - $dropins = get_dropins(); - $plugins = array( - 'dropins' => array(), - 'mu_plugins' => array(), - ); - foreach ( $dropins as $key => $dropin ) { - $plugins['dropins'][] = array( - 'plugin' => $key, - 'name' => $dropin['Name'], - ); - } - - $mu_plugins = get_mu_plugins(); - foreach ( $mu_plugins as $plugin => $mu_plugin ) { - $plugins['mu_plugins'][] = array( - 'plugin' => $plugin, - 'name' => $mu_plugin['Name'], - 'version' => $mu_plugin['Version'], - 'url' => $mu_plugin['PluginURI'], - 'author_name' => $mu_plugin['AuthorName'], - 'author_url' => esc_url_raw( $mu_plugin['AuthorURI'] ), - ); - } - return $plugins; - } - - /** - * Get info on the current active theme, info on parent theme (if presnet) - * and a list of template overrides. - * - * @return array - */ - public function get_theme_info() { - $active_theme = wp_get_theme(); - - // Get parent theme info if this theme is a child theme, otherwise - // pass empty info in the response. - if ( is_child_theme() ) { - $parent_theme = wp_get_theme( $active_theme->template ); - $parent_theme_info = array( - 'parent_name' => $parent_theme->name, - 'parent_version' => $parent_theme->version, - 'parent_version_latest' => WC_Admin_Status::get_latest_theme_version( $parent_theme ), - 'parent_author_url' => $parent_theme->{'Author URI'}, - ); - } else { - $parent_theme_info = array( - 'parent_name' => '', - 'parent_version' => '', - 'parent_version_latest' => '', - 'parent_author_url' => '', - ); - } - - /** - * Scan the theme directory for all WC templates to see if our theme - * overrides any of them. - */ - $override_files = array(); - $outdated_templates = false; - $scan_files = WC_Admin_Status::scan_template_files( WC()->plugin_path() . '/templates/' ); - foreach ( $scan_files as $file ) { - $located = apply_filters( 'wc_get_template', $file, $file, array(), WC()->template_path(), WC()->plugin_path() . '/templates/' ); - - if ( file_exists( $located ) ) { - $theme_file = $located; - } elseif ( file_exists( get_stylesheet_directory() . '/' . $file ) ) { - $theme_file = get_stylesheet_directory() . '/' . $file; - } elseif ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . $file ) ) { - $theme_file = get_stylesheet_directory() . '/' . WC()->template_path() . $file; - } elseif ( file_exists( get_template_directory() . '/' . $file ) ) { - $theme_file = get_template_directory() . '/' . $file; - } elseif ( file_exists( get_template_directory() . '/' . WC()->template_path() . $file ) ) { - $theme_file = get_template_directory() . '/' . WC()->template_path() . $file; - } else { - $theme_file = false; - } - - if ( ! empty( $theme_file ) ) { - $core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file ); - $theme_version = WC_Admin_Status::get_file_version( $theme_file ); - if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) { - if ( ! $outdated_templates ) { - $outdated_templates = true; - } - } - $override_files[] = array( - 'file' => str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ), - 'version' => $theme_version, - 'core_version' => $core_version, - ); - } - } - - $active_theme_info = array( - 'name' => $active_theme->name, - 'version' => $active_theme->version, - 'version_latest' => WC_Admin_Status::get_latest_theme_version( $active_theme ), - 'author_url' => esc_url_raw( $active_theme->{'Author URI'} ), - 'is_child_theme' => is_child_theme(), - 'has_woocommerce_support' => current_theme_supports( 'woocommerce' ), - 'has_woocommerce_file' => ( file_exists( get_stylesheet_directory() . '/woocommerce.php' ) || file_exists( get_template_directory() . '/woocommerce.php' ) ), - 'has_outdated_templates' => $outdated_templates, - 'overrides' => $override_files, - ); - - return array_merge( $active_theme_info, $parent_theme_info ); - } - - /** - * Get some setting values for the site that are useful for debugging - * purposes. For full settings access, use the settings api. - * - * @return array - */ - public function get_settings() { - // Get a list of terms used for product/order taxonomies. - $term_response = array(); - $terms = get_terms( 'product_type', array( 'hide_empty' => 0 ) ); - foreach ( $terms as $term ) { - $term_response[ $term->slug ] = strtolower( $term->name ); - } - - // Get a list of terms used for product visibility. - $product_visibility_terms = array(); - $terms = get_terms( 'product_visibility', array( 'hide_empty' => 0 ) ); - foreach ( $terms as $term ) { - $product_visibility_terms[ $term->slug ] = strtolower( $term->name ); - } - - // Check if WooCommerce.com account is connected. - $woo_com_connected = 'no'; - $helper_options = get_option( 'woocommerce_helper_data', array() ); - if ( array_key_exists( 'auth', $helper_options ) && ! empty( $helper_options['auth'] ) ) { - $woo_com_connected = 'yes'; - } - - // Return array of useful settings for debugging. - return array( - 'api_enabled' => 'yes' === get_option( 'woocommerce_api_enabled' ), - 'force_ssl' => 'yes' === get_option( 'woocommerce_force_ssl_checkout' ), - 'currency' => get_woocommerce_currency(), - 'currency_symbol' => get_woocommerce_currency_symbol(), - 'currency_position' => get_option( 'woocommerce_currency_pos' ), - 'thousand_separator' => wc_get_price_thousand_separator(), - 'decimal_separator' => wc_get_price_decimal_separator(), - 'number_of_decimals' => wc_get_price_decimals(), - 'geolocation_enabled' => in_array( get_option( 'woocommerce_default_customer_address' ), array( 'geolocation_ajax', 'geolocation' ), true ), - 'taxonomies' => $term_response, - 'product_visibility_terms' => $product_visibility_terms, - 'woocommerce_com_connected' => $woo_com_connected, - ); - } - - /** - * Returns security tips. - * - * @return array - */ - public function get_security_info() { - $check_page = wc_get_page_permalink( 'shop' ); - return array( - 'secure_connection' => 'https' === substr( $check_page, 0, 5 ), - 'hide_errors' => ! ( defined( 'WP_DEBUG' ) && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG && WP_DEBUG_DISPLAY ) || 0 === intval( ini_get( 'display_errors' ) ), - ); - } - - /** - * Returns a mini-report on WC pages and if they are configured correctly: - * Present, visible, and including the correct shortcode. - * - * @return array - */ - public function get_pages() { - // WC pages to check against. - $check_pages = array( - _x( 'Shop base', 'Page setting', 'woocommerce-rest-api' ) => array( - 'option' => 'woocommerce_shop_page_id', - 'shortcode' => '', - ), - _x( 'Cart', 'Page setting', 'woocommerce-rest-api' ) => array( - 'option' => 'woocommerce_cart_page_id', - 'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']', - ), - _x( 'Checkout', 'Page setting', 'woocommerce-rest-api' ) => array( - 'option' => 'woocommerce_checkout_page_id', - 'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']', - ), - _x( 'My account', 'Page setting', 'woocommerce-rest-api' ) => array( - 'option' => 'woocommerce_myaccount_page_id', - 'shortcode' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']', - ), - _x( 'Terms and conditions', 'Page setting', 'woocommerce-rest-api' ) => array( - 'option' => 'woocommerce_terms_page_id', - 'shortcode' => '', - ), - ); - - $pages_output = array(); - foreach ( $check_pages as $page_name => $values ) { - $page_id = get_option( $values['option'] ); - $page_set = false; - $page_exists = false; - $page_visible = false; - $shortcode_present = false; - $shortcode_required = false; - - // Page checks. - if ( $page_id ) { - $page_set = true; - } - if ( get_post( $page_id ) ) { - $page_exists = true; - } - if ( 'publish' === get_post_status( $page_id ) ) { - $page_visible = true; - } - - // Shortcode checks. - if ( $values['shortcode'] && get_post( $page_id ) ) { - $shortcode_required = true; - $page = get_post( $page_id ); - if ( strstr( $page->post_content, $values['shortcode'] ) ) { - $shortcode_present = true; - } - } - - // Wrap up our findings into an output array. - $pages_output[] = array( - 'page_name' => $page_name, - 'page_id' => $page_id, - 'page_set' => $page_set, - 'page_exists' => $page_exists, - 'page_visible' => $page_visible, - 'shortcode' => $values['shortcode'], - 'shortcode_required' => $shortcode_required, - 'shortcode_present' => $shortcode_present, - ); - } - - return $pages_output; - } - - /** - * Get any query params needed. - * - * @return array - */ - public function get_collection_params() { - return array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ); - } - - /** - * Prepare the system status response - * - * @param array $system_status System status data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function prepare_item_for_response( $system_status, $request ) { - $data = $this->add_additional_fields_to_object( $system_status, $request ); - $data = $this->filter_response_by_context( $data, 'view' ); - - $response = rest_ensure_response( $data ); - - /** - * Filter the system status returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param mixed $system_status System status - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_system_status', $response, $system_status, $request ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-tax-classes-v2-controller.php b/src/Controllers/Version2/class-wc-rest-tax-classes-v2-controller.php deleted file mode 100644 index dc1cdd24bd3..00000000000 --- a/src/Controllers/Version2/class-wc-rest-tax-classes-v2-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/deliveries endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Webhook Deliveries controller class. - * - * @deprecated 3.3.0 Webhooks deliveries logs now uses logging system. - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Webhook_Deliveries_V1_Controller - */ -class WC_REST_Webhook_Deliveries_V2_Controller extends WC_REST_Webhook_Deliveries_V1_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v2'; - - /** - * Prepare a single webhook delivery output for response. - * - * @param stdClass $log Delivery log object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function prepare_item_for_response( $log, $request ) { - $data = (array) $log; - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $log ) ); - - /** - * Filter webhook delivery object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param stdClass $log Delivery log object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_webhook_delivery', $response, $log, $request ); - } - - /** - * Get the Webhook's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'webhook_delivery', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'duration' => array( - 'description' => __( 'The delivery duration, in seconds.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'summary' => array( - 'description' => __( 'A friendly summary of the response including the HTTP response code, message, and body.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'request_url' => array( - 'description' => __( 'The URL where the webhook was delivered.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'request_headers' => array( - 'description' => __( 'Request headers.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'request_body' => array( - 'description' => __( 'Request body.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'response_code' => array( - 'description' => __( 'The HTTP response code from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'response_message' => array( - 'description' => __( 'The HTTP response message from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'response_headers' => array( - 'description' => __( 'Array of the response headers from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'response_body' => array( - 'description' => __( 'The response body from the receiving server.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the webhook delivery was logged, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the webhook delivery was logged, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version2/class-wc-rest-webhooks-v2-controller.php b/src/Controllers/Version2/class-wc-rest-webhooks-v2-controller.php deleted file mode 100644 index d30967f2392..00000000000 --- a/src/Controllers/Version2/class-wc-rest-webhooks-v2-controller.php +++ /dev/null @@ -1,182 +0,0 @@ -post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $data = array( - 'id' => $webhook->get_id(), - 'name' => $webhook->get_name(), - 'status' => $webhook->get_status(), - 'topic' => $webhook->get_topic(), - 'resource' => $webhook->get_resource(), - 'event' => $webhook->get_event(), - 'hooks' => $webhook->get_hooks(), - 'delivery_url' => $webhook->get_delivery_url(), - 'date_created' => wc_rest_prepare_date_response( $webhook->get_date_created(), false ), - 'date_created_gmt' => wc_rest_prepare_date_response( $webhook->get_date_created() ), - 'date_modified' => wc_rest_prepare_date_response( $webhook->get_date_modified(), false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( $webhook->get_date_modified() ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $webhook->get_id(), $request ) ); - - /** - * Filter webhook object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WC_Webhook $webhook Webhook object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $webhook, $request ); - } - - /** - * Get the default REST API version. - * - * @since 3.0.0 - * @return string - */ - protected function get_default_api_version() { - return 'wp_api_v2'; - } - - /** - * Get the Webhook's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'webhook', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'A friendly name for the webhook.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'status' => array( - 'description' => __( 'Webhook status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'active', - 'enum' => array_keys( wc_get_webhook_statuses() ), - 'context' => array( 'view', 'edit' ), - ), - 'topic' => array( - 'description' => __( 'Webhook topic.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'resource' => array( - 'description' => __( 'Webhook resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'event' => array( - 'description' => __( 'Webhook event.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'hooks' => array( - 'description' => __( 'WooCommerce action names associated with the webhook.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'delivery_url' => array( - 'description' => __( 'The URL where the webhook payload is delivered.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'secret' => array( - 'description' => __( "Secret key used to generate a hash of the delivered webhook and provided in the request headers. This will default to a MD5 hash from the current user's ID|username if not provided.", 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the webhook was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the webhook was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the webhook was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the webhook was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-controller.php b/src/Controllers/Version3/class-wc-rest-controller.php deleted file mode 100644 index 5ee0bc41122..00000000000 --- a/src/Controllers/Version3/class-wc-rest-controller.php +++ /dev/null @@ -1,503 +0,0 @@ - - * - * NOTE THAT ONLY CODE RELEVANT FOR MOST ENDPOINTS SHOULD BE INCLUDED INTO THIS CLASS. - * If necessary extend this class and create new abstract classes like `WC_REST_CRUD_Controller` or `WC_REST_Terms_Controller`. - * - * @class WC_REST_Controller - * @package Automattic/WooCommerce/RestApi - * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/controller-classes/ - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * Abstract Rest Controller Class - * - * @package Automattic/WooCommerce/RestApi - * @extends WP_REST_Controller - * @version 2.6.0 - */ -abstract class WC_REST_Controller extends WP_REST_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v1'; - - /** - * Route base. - * - * @var string - */ - protected $rest_base = ''; - - /** - * Add the schema from additional fields to an schema array. - * - * The type of object is inferred from the passed schema. - * - * @param array $schema Schema array. - * - * @return array - */ - protected function add_additional_fields_schema( $schema ) { - if ( empty( $schema['title'] ) ) { - return $schema; - } - - /** - * Can't use $this->get_object_type otherwise we cause an inf loop. - */ - $object_type = $schema['title']; - - $additional_fields = $this->get_additional_fields( $object_type ); - - foreach ( $additional_fields as $field_name => $field_options ) { - if ( ! $field_options['schema'] ) { - continue; - } - - $schema['properties'][ $field_name ] = $field_options['schema']; - } - - $schema['properties'] = apply_filters( 'woocommerce_rest_' . $object_type . '_schema', $schema['properties'] ); - - return $schema; - } - - /** - * Get normalized rest base. - * - * @return string - */ - protected function get_normalized_rest_base() { - return preg_replace( '/\(.*\)\//i', '', $this->rest_base ); - } - - /** - * Check batch limit. - * - * @param array $items Request items. - * @return bool|WP_Error - */ - protected function check_batch_limit( $items ) { - $limit = apply_filters( 'woocommerce_rest_batch_items_limit', 100, $this->get_normalized_rest_base() ); - $total = 0; - - if ( ! empty( $items['create'] ) ) { - $total += count( $items['create'] ); - } - - if ( ! empty( $items['update'] ) ) { - $total += count( $items['update'] ); - } - - if ( ! empty( $items['delete'] ) ) { - $total += count( $items['delete'] ); - } - - if ( $total > $limit ) { - /* translators: %s: items limit */ - return new WP_Error( 'woocommerce_rest_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce-rest-api' ), $limit ), array( 'status' => 413 ) ); - } - - return true; - } - - /** - * Bulk create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * @return array Of WP_Error or WP_REST_Response. - */ - public function batch_items( $request ) { - /** - * REST Server - * - * @var WP_REST_Server $wp_rest_server - */ - global $wp_rest_server; - - // Get the request params. - $items = array_filter( $request->get_params() ); - $query = $request->get_query_params(); - $response = array(); - - // Check batch limit. - $limit = $this->check_batch_limit( $items ); - if ( is_wp_error( $limit ) ) { - return $limit; - } - - if ( ! empty( $items['create'] ) ) { - foreach ( $items['create'] as $item ) { - $_item = new WP_REST_Request( 'POST' ); - - // Default parameters. - $defaults = array(); - $schema = $this->get_public_item_schema(); - foreach ( $schema['properties'] as $arg => $options ) { - if ( isset( $options['default'] ) ) { - $defaults[ $arg ] = $options['default']; - } - } - $_item->set_default_params( $defaults ); - - // Set request parameters. - $_item->set_body_params( $item ); - - // Set query (GET) parameters. - $_item->set_query_params( $query ); - - $_response = $this->create_item( $_item ); - - if ( is_wp_error( $_response ) ) { - $response['create'][] = array( - 'id' => 0, - 'error' => array( - 'code' => $_response->get_error_code(), - 'message' => $_response->get_error_message(), - 'data' => $_response->get_error_data(), - ), - ); - } else { - $response['create'][] = $wp_rest_server->response_to_data( $_response, '' ); - } - } - } - - if ( ! empty( $items['update'] ) ) { - foreach ( $items['update'] as $item ) { - $_item = new WP_REST_Request( 'PUT' ); - $_item->set_body_params( $item ); - $_response = $this->update_item( $_item ); - - if ( is_wp_error( $_response ) ) { - $response['update'][] = array( - 'id' => $item['id'], - 'error' => array( - 'code' => $_response->get_error_code(), - 'message' => $_response->get_error_message(), - 'data' => $_response->get_error_data(), - ), - ); - } else { - $response['update'][] = $wp_rest_server->response_to_data( $_response, '' ); - } - } - } - - if ( ! empty( $items['delete'] ) ) { - foreach ( $items['delete'] as $id ) { - $id = (int) $id; - - if ( 0 === $id ) { - continue; - } - - $_item = new WP_REST_Request( 'DELETE' ); - $_item->set_query_params( - array( - 'id' => $id, - 'force' => true, - ) - ); - $_response = $this->delete_item( $_item ); - - if ( is_wp_error( $_response ) ) { - $response['delete'][] = array( - 'id' => $id, - 'error' => array( - 'code' => $_response->get_error_code(), - 'message' => $_response->get_error_message(), - 'data' => $_response->get_error_data(), - ), - ); - } else { - $response['delete'][] = $wp_rest_server->response_to_data( $_response, '' ); - } - } - } - - return $response; - } - - /** - * Validate a text value for a text based setting. - * - * @since 3.0.0 - * @param string $value Value. - * @param array $setting Setting. - * @return string - */ - public function validate_setting_text_field( $value, $setting ) { - $value = is_null( $value ) ? '' : $value; - return wp_kses_post( trim( stripslashes( $value ) ) ); - } - - /** - * Validate select based settings. - * - * @since 3.0.0 - * @param string $value Value. - * @param array $setting Setting. - * @return string|WP_Error - */ - public function validate_setting_select_field( $value, $setting ) { - if ( array_key_exists( $value, $setting['options'] ) ) { - return $value; - } else { - return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - } - - /** - * Validate multiselect based settings. - * - * @since 3.0.0 - * @param array $values Values. - * @param array $setting Setting. - * @return array|WP_Error - */ - public function validate_setting_multiselect_field( $values, $setting ) { - if ( empty( $values ) ) { - return array(); - } - - if ( ! is_array( $values ) ) { - return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $final_values = array(); - foreach ( $values as $value ) { - if ( array_key_exists( $value, $setting['options'] ) ) { - $final_values[] = $value; - } - } - - return $final_values; - } - - /** - * Validate image_width based settings. - * - * @since 3.0.0 - * @param array $values Values. - * @param array $setting Setting. - * @return string|WP_Error - */ - public function validate_setting_image_width_field( $values, $setting ) { - if ( ! is_array( $values ) ) { - return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $current = $setting['value']; - if ( isset( $values['width'] ) ) { - $current['width'] = intval( $values['width'] ); - } - if ( isset( $values['height'] ) ) { - $current['height'] = intval( $values['height'] ); - } - if ( isset( $values['crop'] ) ) { - $current['crop'] = (bool) $values['crop']; - } - return $current; - } - - /** - * Validate radio based settings. - * - * @since 3.0.0 - * @param string $value Value. - * @param array $setting Setting. - * @return string|WP_Error - */ - public function validate_setting_radio_field( $value, $setting ) { - return $this->validate_setting_select_field( $value, $setting ); - } - - /** - * Validate checkbox based settings. - * - * @since 3.0.0 - * @param string $value Value. - * @param array $setting Setting. - * @return string|WP_Error - */ - public function validate_setting_checkbox_field( $value, $setting ) { - if ( in_array( $value, array( 'yes', 'no' ) ) ) { - return $value; - } elseif ( empty( $value ) ) { - $value = isset( $setting['default'] ) ? $setting['default'] : 'no'; - return $value; - } else { - return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - } - - /** - * Validate textarea based settings. - * - * @since 3.0.0 - * @param string $value Value. - * @param array $setting Setting. - * @return string - */ - public function validate_setting_textarea_field( $value, $setting ) { - $value = is_null( $value ) ? '' : $value; - return wp_kses( - trim( stripslashes( $value ) ), - array_merge( - array( - 'iframe' => array( - 'src' => true, - 'style' => true, - 'id' => true, - 'class' => true, - ), - ), - wp_kses_allowed_html( 'post' ) - ) - ); - } - - /** - * Add meta query. - * - * @since 3.0.0 - * @param array $args Query args. - * @param array $meta_query Meta query. - * @return array - */ - protected function add_meta_query( $args, $meta_query ) { - if ( empty( $args['meta_query'] ) ) { - $args['meta_query'] = array(); - } - - $args['meta_query'][] = $meta_query; - - return $args['meta_query']; - } - - /** - * Get the batch schema, conforming to JSON Schema. - * - * @return array - */ - public function get_public_batch_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'batch', - 'type' => 'object', - 'properties' => array( - 'create' => array( - 'description' => __( 'List of created resources.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - ), - ), - 'update' => array( - 'description' => __( 'List of updated resources.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - ), - ), - 'delete' => array( - 'description' => __( 'List of delete resources.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'integer', - ), - ), - ), - ); - - return $schema; - } - - /** - * Gets an array of fields to be included on the response. - * - * Included fields are based on item schema and `_fields=` request argument. - * Updated from WordPress 5.3, included into this class to support old versions. - * - * @since 3.5.0 - * @param WP_REST_Request $request Full details about the request. - * @return array Fields to be included in the response. - */ - public function get_fields_for_response( $request ) { - $schema = $this->get_item_schema(); - $properties = isset( $schema['properties'] ) ? $schema['properties'] : array(); - - $additional_fields = $this->get_additional_fields(); - foreach ( $additional_fields as $field_name => $field_options ) { - // For back-compat, include any field with an empty schema - // because it won't be present in $this->get_item_schema(). - if ( is_null( $field_options['schema'] ) ) { - $properties[ $field_name ] = $field_options; - } - } - - // Exclude fields that specify a different context than the request context. - $context = $request['context']; - if ( $context ) { - foreach ( $properties as $name => $options ) { - if ( ! empty( $options['context'] ) && ! in_array( $context, $options['context'], true ) ) { - unset( $properties[ $name ] ); - } - } - } - - $fields = array_keys( $properties ); - - if ( ! isset( $request['_fields'] ) ) { - return $fields; - } - $requested_fields = wp_parse_list( $request['_fields'] ); - if ( 0 === count( $requested_fields ) ) { - return $fields; - } - // Trim off outside whitespace from the comma delimited list. - $requested_fields = array_map( 'trim', $requested_fields ); - // Always persist 'id', because it can be needed for add_additional_fields_to_object(). - if ( in_array( 'id', $fields, true ) ) { - $requested_fields[] = 'id'; - } - // Return the list of all requested fields which appear in the schema. - return array_reduce( - $requested_fields, - function( $response_fields, $field ) use ( $fields ) { - if ( in_array( $field, $fields, true ) ) { - $response_fields[] = $field; - return $response_fields; - } - // Check for nested fields if $field is not a direct match. - $nested_fields = explode( '.', $field ); - // A nested field is included so long as its top-level property is - // present in the schema. - if ( in_array( $nested_fields[0], $fields, true ) ) { - $response_fields[] = $field; - } - return $response_fields; - }, - array() - ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-coupons-controller.php b/src/Controllers/Version3/class-wc-rest-coupons-controller.php deleted file mode 100644 index 0df4a6a3395..00000000000 --- a/src/Controllers/Version3/class-wc-rest-coupons-controller.php +++ /dev/null @@ -1,27 +0,0 @@ - 405 ) ); - } - - /** - * Check if a given request has access to read an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - $object = $this->get_object( (int) $request['id'] ); - - if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'read', $object->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to update an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - $object = $this->get_object( (int) $request['id'] ); - - if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'edit', $object->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to delete an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return bool|WP_Error - */ - public function delete_item_permissions_check( $request ) { - $object = $this->get_object( (int) $request['id'] ); - - if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get object permalink. - * - * @param object $object Object. - * @return string - */ - protected function get_permalink( $object ) { - return ''; - } - - /** - * Prepares the object for the REST response. - * - * @since 3.0.0 - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. - */ - protected function prepare_object_for_response( $object, $request ) { - // translators: %s: Class method name. - return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'woocommerce-rest-api' ), __METHOD__ ), array( 'status' => 405 ) ); - } - - /** - * Prepares one object for create or update operation. - * - * @since 3.0.0 - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data The prepared item, or WP_Error object on failure. - */ - protected function prepare_object_for_database( $request, $creating = false ) { - // translators: %s: Class method name. - return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'woocommerce-rest-api' ), __METHOD__ ), array( 'status' => 405 ) ); - } - - /** - * Get a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $object = $this->get_object( (int) $request['id'] ); - - if ( ! $object || 0 === $object->get_id() ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $data = $this->prepare_object_for_response( $object, $request ); - $response = rest_ensure_response( $data ); - - if ( $this->public ) { - $response->link_header( 'alternate', $this->get_permalink( $object ), array( 'type' => 'text/html' ) ); - } - - return $response; - } - - /** - * Save an object data. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @param bool $creating If is creating a new object. - * @return WC_Data|WP_Error - */ - protected function save_object( $request, $creating = false ) { - try { - $object = $this->prepare_object_for_database( $request, $creating ); - - if ( is_wp_error( $object ) ) { - return $object; - } - - $object->save(); - - return $this->get_object( $object->get_id() ); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Create a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $object = $this->save_object( $request, true ); - - if ( is_wp_error( $object ) ) { - return $object; - } - - try { - $this->update_additional_fields_for_object( $object, $request ); - - /** - * Fires after a single object is created or updated via the REST API. - * - * @param WC_Data $object Inserted object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating object, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}_object", $object, $request, true ); - } catch ( WC_Data_Exception $e ) { - $object->delete(); - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - $object->delete(); - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_object_for_response( $object, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ) ); - - return $response; - } - - /** - * Update a single post. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $object = $this->get_object( (int) $request['id'] ); - - if ( ! $object || 0 === $object->get_id() ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $object = $this->save_object( $request, false ); - - if ( is_wp_error( $object ) ) { - return $object; - } - - try { - $this->update_additional_fields_for_object( $object, $request ); - - /** - * Fires after a single object is created or updated via the REST API. - * - * @param WC_Data $object Inserted object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating object, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}_object", $object, $request, false ); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_object_for_response( $object, $request ); - return rest_ensure_response( $response ); - } - - /** - * Prepare objects query. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array - */ - protected function prepare_objects_query( $request ) { - $args = array(); - $args['offset'] = $request['offset']; - $args['order'] = $request['order']; - $args['orderby'] = $request['orderby']; - $args['paged'] = $request['page']; - $args['post__in'] = $request['include']; - $args['post__not_in'] = $request['exclude']; - $args['posts_per_page'] = $request['per_page']; - $args['name'] = $request['slug']; - $args['post_parent__in'] = $request['parent']; - $args['post_parent__not_in'] = $request['parent_exclude']; - $args['s'] = $request['search']; - - if ( 'date' === $args['orderby'] ) { - $args['orderby'] = 'date ID'; - } - - $args['date_query'] = array(); - // Set before into date query. Date query must be specified as an array of an array. - if ( isset( $request['before'] ) ) { - $args['date_query'][0]['before'] = $request['before']; - } - - // Set after into date query. Date query must be specified as an array of an array. - if ( isset( $request['after'] ) ) { - $args['date_query'][0]['after'] = $request['after']; - } - - // Force the post_type argument, since it's not a user input variable. - $args['post_type'] = $this->post_type; - - /** - * Filter the query arguments for a request. - * - * Enables adding extra arguments or setting defaults for a post - * collection request. - * - * @param array $args Key value array of query var to query value. - * @param WP_REST_Request $request The request used. - */ - $args = apply_filters( "woocommerce_rest_{$this->post_type}_object_query", $args, $request ); - - return $this->prepare_items_query( $args, $request ); - } - - /** - * Get objects. - * - * @since 3.0.0 - * @param array $query_args Query args. - * @return array - */ - protected function get_objects( $query_args ) { - $query = new WP_Query(); - $result = $query->query( $query_args ); - - $total_posts = $query->found_posts; - if ( $total_posts < 1 ) { - // Out-of-bounds, run the query again without LIMIT for total count. - unset( $query_args['paged'] ); - $count_query = new WP_Query(); - $count_query->query( $query_args ); - $total_posts = $count_query->found_posts; - } - - return array( - 'objects' => array_filter( array_map( array( $this, 'get_object' ), $result ) ), - 'total' => (int) $total_posts, - 'pages' => (int) ceil( $total_posts / (int) $query->query_vars['posts_per_page'] ), - ); - } - - /** - * Get a collection of posts. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $query_args = $this->prepare_objects_query( $request ); - $query_results = $this->get_objects( $query_args ); - - $objects = array(); - foreach ( $query_results['objects'] as $object ) { - if ( ! wc_rest_check_post_permissions( $this->post_type, 'read', $object->get_id() ) ) { - continue; - } - - $data = $this->prepare_object_for_response( $object, $request ); - $objects[] = $this->prepare_response_for_collection( $data ); - } - - $page = (int) $query_args['paged']; - $max_pages = $query_results['pages']; - - $response = rest_ensure_response( $objects ); - $response->header( 'X-WP-Total', $query_results['total'] ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - - $base = $this->rest_base; - $attrib_prefix = '(?P<'; - if ( strpos( $base, $attrib_prefix ) !== false ) { - $attrib_names = array(); - preg_match( '/\(\?P<[^>]+>.*\)/', $base, $attrib_names, PREG_OFFSET_CAPTURE ); - foreach ( $attrib_names as $attrib_name_match ) { - $beginning_offset = strlen( $attrib_prefix ); - $attrib_name_end = strpos( $attrib_name_match[0], '>', $attrib_name_match[1] ); - $attrib_name = substr( $attrib_name_match[0], $beginning_offset, $attrib_name_end - $beginning_offset ); - if ( isset( $request[ $attrib_name ] ) ) { - $base = str_replace( "(?P<$attrib_name>[\d]+)", $request[ $attrib_name ], $base ); - } - } - } - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ) ); - - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } - - return $response; - } - - /** - * Delete a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $force = (bool) $request['force']; - $object = $this->get_object( (int) $request['id'] ); - $result = false; - - if ( ! $object || 0 === $object->get_id() ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $supports_trash = EMPTY_TRASH_DAYS > 0 && is_callable( array( $object, 'get_status' ) ); - - /** - * Filter whether an object is trashable. - * - * Return false to disable trash support for the object. - * - * @param boolean $supports_trash Whether the object type support trashing. - * @param WC_Data $object The object being considered for trashing support. - */ - $supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object ); - - if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_object_for_response( $object, $request ); - - // If we're forcing, then delete permanently. - if ( $force ) { - $object->delete( true ); - $result = 0 === $object->get_id(); - } else { - // If we don't support trashing for this type, error out. - if ( ! $supports_trash ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 501 ) ); - } - - // Otherwise, only trash if we haven't already. - if ( is_callable( array( $object, 'get_status' ) ) ) { - if ( 'trash' === $object->get_status() ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 410 ) ); - } - - $object->delete(); - $result = 'trash' === $object->get_status(); - } - } - - if ( ! $result ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 500 ) ); - } - - /** - * Fires after a single object is deleted or trashed via the REST API. - * - * @param WC_Data $object The deleted or trashed object. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( "woocommerce_rest_delete_{$this->post_type}_object", $object, $response, $request ); - - return $response; - } - - /** - * Prepare links for the request. - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return array Links for the given post. - */ - protected function prepare_links( $object, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = array(); - $params['context'] = $this->get_context_param(); - $params['context']['default'] = 'view'; - - $params['page'] = array( - 'description' => __( 'Current page of the collection.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => 1, - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - 'minimum' => 1, - ); - $params['per_page'] = array( - 'description' => __( 'Maximum number of items to be returned in result set.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => 10, - 'minimum' => 1, - 'maximum' => 100, - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['search'] = array( - 'description' => __( 'Limit results to those matching a string.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['after'] = array( - 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['before'] = array( - 'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['exclude'] = array( - 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['include'] = array( - 'description' => __( 'Limit result set to specific ids.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['offset'] = array( - 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['order'] = array( - 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'desc', - 'enum' => array( 'asc', 'desc' ), - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['orderby'] = array( - 'description' => __( 'Sort collection by object attribute.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'date', - 'enum' => array( - 'date', - 'id', - 'include', - 'title', - 'slug', - 'modified', - ), - 'validate_callback' => 'rest_validate_request_arg', - ); - - if ( $this->hierarchical ) { - $params['parent'] = array( - 'description' => __( 'Limit result set to those of particular parent IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'sanitize_callback' => 'wp_parse_id_list', - 'default' => array(), - ); - $params['parent_exclude'] = array( - 'description' => __( 'Limit result set to all items except those of a particular parent ID.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'sanitize_callback' => 'wp_parse_id_list', - 'default' => array(), - ); - } - - /** - * Filter collection parameters for the posts controller. - * - * The dynamic part of the filter `$this->post_type` refers to the post - * type slug for the controller. - * - * This filter registers the collection parameter, but does not map the - * collection parameter to an internal WP_Query parameter. Use the - * `rest_{$this->post_type}_query` filter to set WP_Query parameters. - * - * @param array $query_params JSON Schema-formatted collection parameters. - * @param WP_Post_Type $post_type Post type object. - */ - return apply_filters( "rest_{$this->post_type}_collection_params", $params, $this->post_type ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-customer-downloads-controller.php b/src/Controllers/Version3/class-wc-rest-customer-downloads-controller.php deleted file mode 100644 index 78147fe9301..00000000000 --- a/src/Controllers/Version3/class-wc-rest-customer-downloads-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/downloads endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Customers controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Customer_Downloads_V2_Controller - */ -class WC_REST_Customer_Downloads_Controller extends WC_REST_Customer_Downloads_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v3'; -} diff --git a/src/Controllers/Version3/class-wc-rest-customers-controller.php b/src/Controllers/Version3/class-wc-rest-customers-controller.php deleted file mode 100644 index 65ce592cd55..00000000000 --- a/src/Controllers/Version3/class-wc-rest-customers-controller.php +++ /dev/null @@ -1,307 +0,0 @@ -get_data(); - $format_date = array( 'date_created', 'date_modified' ); - - // Format date values. - foreach ( $format_date as $key ) { - // Date created is stored UTC, date modified is stored WP local time. - $datetime = 'date_created' === $key ? get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $data[ $key ]->getTimestamp() ) ) : $data[ $key ]; - $data[ $key ] = wc_rest_prepare_date_response( $datetime, false ); - $data[ $key . '_gmt' ] = wc_rest_prepare_date_response( $datetime ); - } - - return array( - 'id' => $object->get_id(), - 'date_created' => $data['date_created'], - 'date_created_gmt' => $data['date_created_gmt'], - 'date_modified' => $data['date_modified'], - 'date_modified_gmt' => $data['date_modified_gmt'], - 'email' => $data['email'], - 'first_name' => $data['first_name'], - 'last_name' => $data['last_name'], - 'role' => $data['role'], - 'username' => $data['username'], - 'billing' => $data['billing'], - 'shipping' => $data['shipping'], - 'is_paying_customer' => $data['is_paying_customer'], - 'avatar_url' => $object->get_avatar_url(), - 'meta_data' => $data['meta_data'], - ); - } - - /** - * Get the Customer's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'customer', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the customer was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the customer was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the customer was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the customer was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'email' => array( - 'description' => __( 'The email address for the customer.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'first_name' => array( - 'description' => __( 'Customer first name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'last_name' => array( - 'description' => __( 'Customer last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'role' => array( - 'description' => __( 'Customer role.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'username' => array( - 'description' => __( 'Customer login name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_user', - ), - ), - 'password' => array( - 'description' => __( 'Customer password.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'edit' ), - ), - 'billing' => array( - 'description' => __( 'List of billing address data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'ISO code of the country.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'email' => array( - 'description' => __( 'Email address.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'phone' => array( - 'description' => __( 'Phone number.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping' => array( - 'description' => __( 'List of shipping address data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'first_name' => array( - 'description' => __( 'First name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'last_name' => array( - 'description' => __( 'Last name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'company' => array( - 'description' => __( 'Company name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_1' => array( - 'description' => __( 'Address line 1', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'address_2' => array( - 'description' => __( 'Address line 2', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'city' => array( - 'description' => __( 'City name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'state' => array( - 'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'postcode' => array( - 'description' => __( 'Postal code.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'country' => array( - 'description' => __( 'ISO code of the country.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'is_paying_customer' => array( - 'description' => __( 'Is the customer a paying customer?', 'woocommerce-rest-api' ), - 'type' => 'bool', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'avatar_url' => array( - 'description' => __( 'Avatar URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-data-continents-controller.php b/src/Controllers/Version3/class-wc-rest-data-continents-controller.php deleted file mode 100644 index 7b79f969397..00000000000 --- a/src/Controllers/Version3/class-wc-rest-data-continents-controller.php +++ /dev/null @@ -1,357 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => array( - 'continent' => array( - 'description' => __( '2 character continent code.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Return the list of countries and states for a given continent. - * - * @since 3.5.0 - * @param string $continent_code Continent code. - * @param WP_REST_Request $request Request data. - * @return array|mixed Response data, ready for insertion into collection data. - */ - public function get_continent( $continent_code = false, $request ) { - $continents = WC()->countries->get_continents(); - $countries = WC()->countries->get_countries(); - $states = WC()->countries->get_states(); - $locale_info = include WC()->plugin_path() . '/i18n/locale-info.php'; - $data = array(); - - if ( ! array_key_exists( $continent_code, $continents ) ) { - return false; - } - - $continent_list = $continents[ $continent_code ]; - - $continent = array( - 'code' => $continent_code, - 'name' => $continent_list['name'], - ); - - $local_countries = array(); - foreach ( $continent_list['countries'] as $country_code ) { - if ( isset( $countries[ $country_code ] ) ) { - $country = array( - 'code' => $country_code, - 'name' => $countries[ $country_code ], - ); - - // If we have detailed locale information include that in the response. - if ( array_key_exists( $country_code, $locale_info ) ) { - // Defensive programming against unexpected changes in locale-info.php. - $country_data = wp_parse_args( - $locale_info[ $country_code ], array( - 'currency_code' => 'USD', - 'currency_pos' => 'left', - 'decimal_sep' => '.', - 'dimension_unit' => 'in', - 'num_decimals' => 2, - 'thousand_sep' => ',', - 'weight_unit' => 'lbs', - ) - ); - - $country = array_merge( $country, $country_data ); - } - - $local_states = array(); - if ( isset( $states[ $country_code ] ) ) { - foreach ( $states[ $country_code ] as $state_code => $state_name ) { - $local_states[] = array( - 'code' => $state_code, - 'name' => $state_name, - ); - } - } - $country['states'] = $local_states; - - // Allow only desired keys (e.g. filter out tax rates). - $allowed = array( - 'code', - 'currency_code', - 'currency_pos', - 'decimal_sep', - 'dimension_unit', - 'name', - 'num_decimals', - 'states', - 'thousand_sep', - 'weight_unit', - ); - $country = array_intersect_key( $country, array_flip( $allowed ) ); - - $local_countries[] = $country; - } - } - - $continent['countries'] = $local_countries; - return $continent; - } - - /** - * Return the list of states for all continents. - * - * @since 3.5.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $continents = WC()->countries->get_continents(); - $data = array(); - - foreach ( array_keys( $continents ) as $continent_code ) { - $continent = $this->get_continent( $continent_code, $request ); - $response = $this->prepare_item_for_response( $continent, $request ); - $data[] = $this->prepare_response_for_collection( $response ); - } - - return rest_ensure_response( $data ); - } - - /** - * Return the list of locations for a given continent. - * - * @since 3.5.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $data = $this->get_continent( strtoupper( $request['location'] ), $request ); - if ( empty( $data ) ) { - return new WP_Error( 'woocommerce_rest_data_invalid_location', __( 'There are no locations matching these parameters.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - return $this->prepare_item_for_response( $data, $request ); - } - - /** - * Prepare the data object for response. - * - * @since 3.5.0 - * @param object $item Data object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $item, $request ) { - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, 'view' ); - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item ) ); - - /** - * Filter the location list returned from the API. - * - * Allows modification of the loction data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param array $item The original list of continent(s), countries, and states. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_data_continent', $response, $item, $request ); - } - - /** - * Prepare links for the request. - * - * @param object $item Data object. - * @return array Links for the given continent. - */ - protected function prepare_links( $item ) { - $continent_code = strtolower( $item['code'] ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $continent_code ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - return $links; - } - - /** - * Get the location schema, conforming to JSON Schema. - * - * @since 3.5.0 - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'data_continents', - 'type' => 'object', - 'properties' => array( - 'code' => array( - 'type' => 'string', - 'description' => __( '2 character continent code.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'type' => 'string', - 'description' => __( 'Full name of continent.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'countries' => array( - 'type' => 'array', - 'description' => __( 'List of countries on this continent.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'code' => array( - 'type' => 'string', - 'description' => __( 'ISO3166 alpha-2 country code.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'currency_code' => array( - 'type' => 'string', - 'description' => __( 'Default ISO4127 alpha-3 currency code for the country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'currency_pos' => array( - 'type' => 'string', - 'description' => __( 'Currency symbol position for this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'decimal_sep' => array( - 'type' => 'string', - 'description' => __( 'Decimal separator for displayed prices for this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'dimension_unit' => array( - 'type' => 'string', - 'description' => __( 'The unit lengths are defined in for this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'type' => 'string', - 'description' => __( 'Full name of country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'num_decimals' => array( - 'type' => 'integer', - 'description' => __( 'Number of decimal points shown in displayed prices for this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'states' => array( - 'type' => 'array', - 'description' => __( 'List of states in this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'code' => array( - 'type' => 'string', - 'description' => __( 'State code.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'type' => 'string', - 'description' => __( 'Full name of state.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - ), - 'thousand_sep' => array( - 'type' => 'string', - 'description' => __( 'Thousands separator for displayed prices in this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'weight_unit' => array( - 'type' => 'string', - 'description' => __( 'The unit weights are defined in for this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-data-controller.php b/src/Controllers/Version3/class-wc-rest-data-controller.php deleted file mode 100644 index e6b794a2ba7..00000000000 --- a/src/Controllers/Version3/class-wc-rest-data-controller.php +++ /dev/null @@ -1,184 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Check whether a given request has permission to read site data. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check whether a given request has permission to read site settings. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Return the list of data resources. - * - * @since 3.5.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $data = array(); - $resources = array( - array( - 'slug' => 'continents', - 'description' => __( 'List of supported continents, countries, and states.', 'woocommerce-rest-api' ), - ), - array( - 'slug' => 'countries', - 'description' => __( 'List of supported states in a given country.', 'woocommerce-rest-api' ), - ), - array( - 'slug' => 'currencies', - 'description' => __( 'List of supported currencies.', 'woocommerce-rest-api' ), - ), - ); - - foreach ( $resources as $resource ) { - $item = $this->prepare_item_for_response( (object) $resource, $request ); - $data[] = $this->prepare_response_for_collection( $item ); - } - - return rest_ensure_response( $data ); - } - - /** - * Prepare a data resource object for serialization. - * - * @param stdClass $resource Resource data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $resource, $request ) { - $data = array( - 'slug' => $resource->slug, - 'description' => $resource->description, - ); - - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, 'view' ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $resource ) ); - - return $response; - } - - /** - * Prepare links for the request. - * - * @param object $item Data object. - * @return array Links for the given country. - */ - protected function prepare_links( $item ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $item->slug ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Get the data index schema, conforming to JSON Schema. - * - * @since 3.5.0 - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'data_index', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'Data resource ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'Data resource description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-data-countries-controller.php b/src/Controllers/Version3/class-wc-rest-data-countries-controller.php deleted file mode 100644 index aaed5e2f30d..00000000000 --- a/src/Controllers/Version3/class-wc-rest-data-countries-controller.php +++ /dev/null @@ -1,240 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => array( - 'location' => array( - 'description' => __( 'ISO3166 alpha-2 country code.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Get a list of countries and states. - * - * @param string $country_code Country code. - * @param WP_REST_Request $request Request data. - * @return array|mixed Response data, ready for insertion into collection data. - */ - public function get_country( $country_code = false, $request ) { - $countries = WC()->countries->get_countries(); - $states = WC()->countries->get_states(); - $data = array(); - - if ( ! array_key_exists( $country_code, $countries ) ) { - return false; - } - - $country = array( - 'code' => $country_code, - 'name' => $countries[ $country_code ], - ); - - $local_states = array(); - if ( isset( $states[ $country_code ] ) ) { - foreach ( $states[ $country_code ] as $state_code => $state_name ) { - $local_states[] = array( - 'code' => $state_code, - 'name' => $state_name, - ); - } - } - $country['states'] = $local_states; - return $country; - } - - /** - * Return the list of states for all countries. - * - * @since 3.5.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $countries = WC()->countries->get_countries(); - $data = array(); - - foreach ( array_keys( $countries ) as $country_code ) { - $country = $this->get_country( $country_code, $request ); - $response = $this->prepare_item_for_response( $country, $request ); - $data[] = $this->prepare_response_for_collection( $response ); - } - - return rest_ensure_response( $data ); - } - - /** - * Return the list of states for a given country. - * - * @since 3.5.0 - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $data = $this->get_country( strtoupper( $request['location'] ), $request ); - if ( empty( $data ) ) { - return new WP_Error( 'woocommerce_rest_data_invalid_location', __( 'There are no locations matching these parameters.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - return $this->prepare_item_for_response( $data, $request ); - } - - /** - * Prepare the data object for response. - * - * @since 3.5.0 - * @param object $item Data object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $item, $request ) { - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, 'view' ); - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item ) ); - - /** - * Filter the states list for a country returned from the API. - * - * Allows modification of the loction data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param array $data The original country's states list. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_data_country', $response, $item, $request ); - } - - /** - * Prepare links for the request. - * - * @param object $item Data object. - * @return array Links for the given country. - */ - protected function prepare_links( $item ) { - $country_code = strtolower( $item['code'] ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $country_code ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - - /** - * Get the location schema, conforming to JSON Schema. - * - * @since 3.5.0 - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'data_countries', - 'type' => 'object', - 'properties' => array( - 'code' => array( - 'type' => 'string', - 'description' => __( 'ISO3166 alpha-2 country code.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'type' => 'string', - 'description' => __( 'Full name of country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'states' => array( - 'type' => 'array', - 'description' => __( 'List of states in this country.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - 'items' => array( - 'type' => 'object', - 'context' => array( 'view' ), - 'readonly' => true, - 'properties' => array( - 'code' => array( - 'type' => 'string', - 'description' => __( 'State code.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'type' => 'string', - 'description' => __( 'Full name of state.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-data-currencies-controller.php b/src/Controllers/Version3/class-wc-rest-data-currencies-controller.php deleted file mode 100644 index eb62a89f048..00000000000 --- a/src/Controllers/Version3/class-wc-rest-data-currencies-controller.php +++ /dev/null @@ -1,221 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/current', array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_current_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\w-]{3})', array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'location' => array( - 'description' => __( 'ISO4217 currency code.', 'woocommerce-rest-api' ), - 'type' => 'string', - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - } - - /** - * Get currency information. - * - * @param string $code Currency code. - * @param WP_REST_Request $request Request data. - * @return array|mixed Response data, ready for insertion into collection data. - */ - public function get_currency( $code = false, $request ) { - $currencies = get_woocommerce_currencies(); - $data = array(); - - if ( ! array_key_exists( $code, $currencies ) ) { - return false; - } - - $currency = array( - 'code' => $code, - 'name' => $currencies[ $code ], - 'symbol' => get_woocommerce_currency_symbol( $code ), - ); - - return $currency; - } - - /** - * Return the list of currencies. - * - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $currencies = get_woocommerce_currencies(); - foreach ( array_keys( $currencies ) as $code ) { - $currency = $this->get_currency( $code, $request ); - $response = $this->prepare_item_for_response( $currency, $request ); - $data[] = $this->prepare_response_for_collection( $response ); - } - - return rest_ensure_response( $data ); - } - - /** - * Return information for a specific currency. - * - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $data = $this->get_currency( strtoupper( $request['currency'] ), $request ); - if ( empty( $data ) ) { - return new WP_Error( 'woocommerce_rest_data_invalid_currency', __( 'There are no currencies matching these parameters.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - return $this->prepare_item_for_response( $data, $request ); - } - - /** - * Return information for the current site currency. - * - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function get_current_item( $request ) { - $currency = get_option( 'woocommerce_currency' ); - return $this->prepare_item_for_response( $this->get_currency( $currency, $request ), $request ); - } - - /** - * Prepare the data object for response. - * - * @param object $item Data object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $item, $request ) { - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, 'view' ); - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item ) ); - - /** - * Filter currency returned from the API. - * - * @param WP_REST_Response $response The response object. - * @param array $item Currency data. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_data_currency', $response, $item, $request ); - } - - /** - * Prepare links for the request. - * - * @param object $item Data object. - * @return array Links for the given currency. - */ - protected function prepare_links( $item ) { - $code = strtoupper( $item['code'] ); - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $code ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - - /** - * Get the currency schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'data_currencies', - 'type' => 'object', - 'properties' => array( - 'code' => array( - 'type' => 'string', - 'description' => __( 'ISO4217 currency code.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'type' => 'string', - 'description' => __( 'Full name of currency.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'symbol' => array( - 'type' => 'string', - 'description' => __( 'Currency symbol.', 'woocommerce-rest-api' ), - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-network-orders-controller.php b/src/Controllers/Version3/class-wc-rest-network-orders-controller.php deleted file mode 100644 index 5b327a54bce..00000000000 --- a/src/Controllers/Version3/class-wc-rest-network-orders-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/notes endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Order Notes controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Order_Notes_V2_Controller - */ -class WC_REST_Order_Notes_Controller extends WC_REST_Order_Notes_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v3'; - - /** - * Prepare a single order note output for response. - * - * @param WP_Comment $note Order note object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $note, $request ) { - $data = array( - 'id' => (int) $note->comment_ID, - 'author' => __( 'woocommerce', 'woocommerce-rest-api' ) === $note->comment_author ? 'system' : $note->comment_author, - 'date_created' => wc_rest_prepare_date_response( $note->comment_date ), - 'date_created_gmt' => wc_rest_prepare_date_response( $note->comment_date_gmt ), - 'note' => $note->comment_content, - 'customer_note' => (bool) get_comment_meta( $note->comment_ID, 'is_customer_note', true ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $note ) ); - - /** - * Filter order note object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_Comment $note Order note object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_order_note', $response, $note, $request ); - } - - /** - * Create a single order note. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order || $this->post_type !== $order->get_type() ) { - return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - // Create the note. - $note_id = $order->add_order_note( $request['note'], $request['customer_note'], $request['added_by_user'] ); - - if ( ! $note_id ) { - return new WP_Error( 'woocommerce_api_cannot_create_order_note', __( 'Cannot create order note, please try again.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - $note = get_comment( $note_id ); - $this->update_additional_fields_for_object( $note, $request ); - - /** - * Fires after a order note is created or updated via the REST API. - * - * @param WP_Comment $note New order note object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( 'woocommerce_rest_insert_order_note', $note, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $note, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, str_replace( '(?P[\d]+)', $order->get_id(), $this->rest_base ), $note_id ) ) ); - - return $response; - } - - /** - * Get the Order Notes schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'order_note', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'author' => array( - 'description' => __( 'Order note author.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the order note was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the order note was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'note' => array( - 'description' => __( 'Order note content.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'customer_note' => array( - 'description' => __( 'If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'added_by_user' => array( - 'description' => __( 'If true, this note will be attributed to the current user. If false, the note will be attributed to the system.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-order-refunds-controller.php b/src/Controllers/Version3/class-wc-rest-order-refunds-controller.php deleted file mode 100644 index 865634affe0..00000000000 --- a/src/Controllers/Version3/class-wc-rest-order-refunds-controller.php +++ /dev/null @@ -1,86 +0,0 @@ -/refunds endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Order Refunds controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Order_Refunds_V2_Controller - */ -class WC_REST_Order_Refunds_Controller extends WC_REST_Order_Refunds_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v3'; - - /** - * Prepares one object for create or update operation. - * - * @since 3.0.0 - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data The prepared item, or WP_Error object on failure. - */ - protected function prepare_object_for_database( $request, $creating = false ) { - $order = wc_get_order( (int) $request['order_id'] ); - - if ( ! $order ) { - return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce-rest-api' ), 404 ); - } - - if ( 0 > $request['amount'] ) { - return new WP_Error( 'woocommerce_rest_invalid_order_refund', __( 'Refund amount must be greater than zero.', 'woocommerce-rest-api' ), 400 ); - } - - // Create the refund. - $refund = wc_create_refund( - array( - 'order_id' => $order->get_id(), - 'amount' => $request['amount'], - 'reason' => empty( $request['reason'] ) ? null : $request['reason'], - 'line_items' => empty( $request['line_items'] ) ? array() : $request['line_items'], - 'refund_payment' => is_bool( $request['api_refund'] ) ? $request['api_refund'] : true, - 'restock_items' => true, - ) - ); - - if ( is_wp_error( $refund ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', $refund->get_error_message(), 500 ); - } - - if ( ! $refund ) { - return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', __( 'Cannot create order refund, please try again.', 'woocommerce-rest-api' ), 500 ); - } - - if ( ! empty( $request['meta_data'] ) && is_array( $request['meta_data'] ) ) { - foreach ( $request['meta_data'] as $meta ) { - $refund->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - $refund->save_meta_data(); - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $coupon Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $refund, $request, $creating ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-orders-controller.php b/src/Controllers/Version3/class-wc-rest-orders-controller.php deleted file mode 100644 index 1d2ad09d5d7..00000000000 --- a/src/Controllers/Version3/class-wc-rest-orders-controller.php +++ /dev/null @@ -1,271 +0,0 @@ -get_items( 'coupon' ) as $coupon ) { - $order->remove_coupon( $coupon->get_code() ); - } - - foreach ( $request['coupon_lines'] as $item ) { - if ( is_array( $item ) ) { - if ( empty( $item['id'] ) ) { - if ( empty( $item['code'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon', __( 'Coupon code is required.', 'woocommerce-rest-api' ), 400 ); - } - - $results = $order->apply_coupon( wc_clean( $item['code'] ) ); - - if ( is_wp_error( $results ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_' . $results->get_error_code(), $results->get_error_message(), 400 ); - } - } - } - } - - return true; - } - - /** - * Prepare a single order for create or update. - * - * @throws WC_REST_Exception When fails to set any item. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data - */ - protected function prepare_object_for_database( $request, $creating = false ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $order = new WC_Order( $id ); - $schema = $this->get_item_schema(); - $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); - - // Handle all writable props. - foreach ( $data_keys as $key ) { - $value = $request[ $key ]; - - if ( ! is_null( $value ) ) { - switch ( $key ) { - case 'coupon_lines': - case 'status': - // Change should be done later so transitions have new data. - break; - case 'billing': - case 'shipping': - $this->update_address( $order, $value, $key ); - break; - case 'line_items': - case 'shipping_lines': - case 'fee_lines': - if ( is_array( $value ) ) { - foreach ( $value as $item ) { - if ( is_array( $item ) ) { - if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) { - $order->remove_item( $item['id'] ); - } else { - $this->set_item( $order, $key, $item ); - } - } - } - } - break; - case 'meta_data': - if ( is_array( $value ) ) { - foreach ( $value as $meta ) { - $order->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - break; - default: - if ( is_callable( array( $order, "set_{$key}" ) ) ) { - $order->{"set_{$key}"}( $value ); - } - break; - } - } - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $order Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $order, $request, $creating ); - } - - /** - * Save an object data. - * - * @since 3.0.0 - * @throws WC_REST_Exception But all errors are validated before returning any data. - * @param WP_REST_Request $request Full details about the request. - * @param bool $creating If is creating a new object. - * @return WC_Data|WP_Error - */ - protected function save_object( $request, $creating = false ) { - try { - $object = $this->prepare_object_for_database( $request, $creating ); - - if ( is_wp_error( $object ) ) { - return $object; - } - - // Make sure gateways are loaded so hooks from gateways fire on save/create. - WC()->payment_gateways(); - - if ( ! is_null( $request['customer_id'] ) && 0 !== $request['customer_id'] ) { - // Make sure customer exists. - if ( false === get_user_by( 'id', $request['customer_id'] ) ) { - throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id', __( 'Customer ID is invalid.', 'woocommerce-rest-api' ), 400 ); - } - - // Make sure customer is part of blog. - if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) { - add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' ); - } - } - - if ( $creating ) { - $object->set_created_via( 'rest-api' ); - $object->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ); - $object->calculate_totals(); - } else { - // If items have changed, recalculate order totals. - if ( isset( $request['billing'] ) || isset( $request['shipping'] ) || isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) { - $object->calculate_totals( true ); - } - } - - // Set coupons. - $this->calculate_coupons( $request, $object ); - - // Set status. - if ( ! empty( $request['status'] ) ) { - $object->set_status( $request['status'] ); - } - - $object->save(); - - // Actions for after the order is saved. - if ( true === $request['set_paid'] ) { - if ( $creating || $object->needs_payment() ) { - $object->payment_complete( $request['transaction_id'] ); - } - } - - return $this->get_object( $object->get_id() ); - } catch ( WC_Data_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); - } catch ( WC_REST_Exception $e ) { - return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); - } - } - - /** - * Prepare objects query. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array - */ - protected function prepare_objects_query( $request ) { - // This is needed to get around an array to string notice in WC_REST_Orders_V2_Controller::prepare_objects_query. - $statuses = $request['status']; - unset( $request['status'] ); - $args = parent::prepare_objects_query( $request ); - - $args['post_status'] = array(); - foreach ( $statuses as $status ) { - if ( in_array( $status, $this->get_order_statuses(), true ) ) { - $args['post_status'][] = 'wc-' . $status; - } elseif ( 'any' === $status ) { - // Set status to "any" and short-circuit out. - $args['post_status'] = 'any'; - break; - } else { - $args['post_status'][] = $status; - } - } - - // Put the statuses back for further processing (next/prev links, etc). - $request['status'] = $statuses; - - return $args; - } - - /** - * Get the Order's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = parent::get_item_schema(); - - $schema['properties']['coupon_lines']['items']['properties']['discount']['readonly'] = true; - - return $schema; - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['status'] = array( - 'default' => 'any', - 'description' => __( 'Limit result set to orders which have specific statuses.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'string', - 'enum' => array_merge( array( 'any', 'trash' ), $this->get_order_statuses() ), - ), - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-payment-gateways-controller.php b/src/Controllers/Version3/class-wc-rest-payment-gateways-controller.php deleted file mode 100644 index f48b155f3dd..00000000000 --- a/src/Controllers/Version3/class-wc-rest-payment-gateways-controller.php +++ /dev/null @@ -1,226 +0,0 @@ - $gateway->id, - 'title' => $gateway->title, - 'description' => $gateway->description, - 'order' => isset( $order[ $gateway->id ] ) ? $order[ $gateway->id ] : '', - 'enabled' => ( 'yes' === $gateway->enabled ), - 'method_title' => $gateway->get_method_title(), - 'method_description' => $gateway->get_method_description(), - 'method_supports' => $gateway->supports, - 'settings' => $this->get_settings( $gateway ), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $item, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $gateway, $request ) ); - - /** - * Filter payment gateway objects returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WC_Payment_Gateway $gateway Payment gateway object. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_payment_gateway', $response, $gateway, $request ); - } - - /** - * Return settings associated with this payment gateway. - * - * @param WC_Payment_Gateway $gateway Gateway instance. - * - * @return array - */ - public function get_settings( $gateway ) { - $settings = array(); - $gateway->init_form_fields(); - foreach ( $gateway->form_fields as $id => $field ) { - // Make sure we at least have a title and type. - if ( empty( $field['title'] ) || empty( $field['type'] ) ) { - continue; - } - - // Ignore 'enabled' and 'description' which get included elsewhere. - if ( in_array( $id, array( 'enabled', 'description' ), true ) ) { - continue; - } - - $data = array( - 'id' => $id, - 'label' => empty( $field['label'] ) ? $field['title'] : $field['label'], - 'description' => empty( $field['description'] ) ? '' : $field['description'], - 'type' => $field['type'], - 'value' => empty( $gateway->settings[ $id ] ) ? '' : $gateway->settings[ $id ], - 'default' => empty( $field['default'] ) ? '' : $field['default'], - 'tip' => empty( $field['description'] ) ? '' : $field['description'], - 'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'], - ); - if ( ! empty( $field['options'] ) ) { - $data['options'] = $field['options']; - } - $settings[ $id ] = $data; - } - return $settings; - } - - /** - * Get the payment gateway schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'payment_gateway', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Payment gateway ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'title' => array( - 'description' => __( 'Payment gateway title on checkout.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'Payment gateway description on checkout.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'order' => array( - 'description' => __( 'Payment gateway sort order.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'absint', - ), - ), - 'enabled' => array( - 'description' => __( 'Payment gateway enabled status.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - ), - 'method_title' => array( - 'description' => __( 'Payment gateway method title.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'method_description' => array( - 'description' => __( 'Payment gateway method description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'method_supports' => array( - 'description' => __( 'Supported features for this payment gateway.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'items' => array( - 'type' => 'string', - ), - ), - 'settings' => array( - 'description' => __( 'Payment gateway settings.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Type of setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'enum' => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Setting value.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'default' => array( - 'description' => __( 'Default value for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tip' => array( - 'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'placeholder' => array( - 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-posts-controller.php b/src/Controllers/Version3/class-wc-rest-posts-controller.php deleted file mode 100644 index 0db471b87a3..00000000000 --- a/src/Controllers/Version3/class-wc-rest-posts-controller.php +++ /dev/null @@ -1,724 +0,0 @@ -post_type, 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to create an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_post_permissions( $this->post_type, 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - $post = get_post( (int) $request['id'] ); - - if ( $post && ! wc_rest_check_post_permissions( $this->post_type, 'read', $post->ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to update an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - $post = get_post( (int) $request['id'] ); - - if ( $post && ! wc_rest_check_post_permissions( $this->post_type, 'edit', $post->ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to delete an item. - * - * @param WP_REST_Request $request Full details about the request. - * @return bool|WP_Error - */ - public function delete_item_permissions_check( $request ) { - $post = get_post( (int) $request['id'] ); - - if ( $post && ! wc_rest_check_post_permissions( $this->post_type, 'delete', $post->ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access batch create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * - * @return boolean|WP_Error - */ - public function batch_items_permissions_check( $request ) { - if ( ! wc_rest_check_post_permissions( $this->post_type, 'batch' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $id = (int) $request['id']; - $post = get_post( $id ); - - if ( ! empty( $post->post_type ) && 'product_variation' === $post->post_type && 'product' === $this->post_type ) { - return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } elseif ( empty( $id ) || empty( $post->ID ) || $post->post_type !== $this->post_type ) { - return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'Invalid ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $data = $this->prepare_item_for_response( $post, $request ); - $response = rest_ensure_response( $data ); - - if ( $this->public ) { - $response->link_header( 'alternate', get_permalink( $id ), array( 'type' => 'text/html' ) ); - } - - return $response; - } - - /** - * Create a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 400 ) ); - } - - $post = $this->prepare_item_for_database( $request ); - if ( is_wp_error( $post ) ) { - return $post; - } - - $post->post_type = $this->post_type; - $post_id = wp_insert_post( $post, true ); - - if ( is_wp_error( $post_id ) ) { - - if ( in_array( $post_id->get_error_code(), array( 'db_insert_error' ) ) ) { - $post_id->add_data( array( 'status' => 500 ) ); - } else { - $post_id->add_data( array( 'status' => 400 ) ); - } - return $post_id; - } - $post->ID = $post_id; - $post = get_post( $post_id ); - - $this->update_additional_fields_for_object( $post, $request ); - - // Add meta fields. - $meta_fields = $this->add_post_meta_fields( $post, $request ); - if ( is_wp_error( $meta_fields ) ) { - // Remove post. - $this->delete_post( $post ); - - return $meta_fields; - } - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) ); - - return $response; - } - - /** - * Add post meta fields. - * - * @param WP_Post $post Post Object. - * @param WP_REST_Request $request WP_REST_Request Object. - * @return bool|WP_Error - */ - protected function add_post_meta_fields( $post, $request ) { - return true; - } - - /** - * Delete post. - * - * @param WP_Post $post Post object. - */ - protected function delete_post( $post ) { - wp_delete_post( $post->ID, true ); - } - - /** - * Update a single post. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $id = (int) $request['id']; - $post = get_post( $id ); - - if ( ! empty( $post->post_type ) && 'product_variation' === $post->post_type && 'product' === $this->post_type ) { - return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } elseif ( empty( $id ) || empty( $post->ID ) || $post->post_type !== $this->post_type ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $post = $this->prepare_item_for_database( $request ); - if ( is_wp_error( $post ) ) { - return $post; - } - // Convert the post object to an array, otherwise wp_update_post will expect non-escaped input. - $post_id = wp_update_post( (array) $post, true ); - if ( is_wp_error( $post_id ) ) { - if ( in_array( $post_id->get_error_code(), array( 'db_update_error' ) ) ) { - $post_id->add_data( array( 'status' => 500 ) ); - } else { - $post_id->add_data( array( 'status' => 400 ) ); - } - return $post_id; - } - - $post = get_post( $post_id ); - $this->update_additional_fields_for_object( $post, $request ); - - // Update meta fields. - $meta_fields = $this->update_post_meta_fields( $post, $request ); - if ( is_wp_error( $meta_fields ) ) { - return $meta_fields; - } - - /** - * Fires after a single item is created or updated via the REST API. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating item, false when updating. - */ - do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - return rest_ensure_response( $response ); - } - - /** - * Get a collection of posts. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_items( $request ) { - $args = array(); - $args['offset'] = $request['offset']; - $args['order'] = $request['order']; - $args['orderby'] = $request['orderby']; - $args['paged'] = $request['page']; - $args['post__in'] = $request['include']; - $args['post__not_in'] = $request['exclude']; - $args['posts_per_page'] = $request['per_page']; - $args['name'] = $request['slug']; - $args['post_parent__in'] = $request['parent']; - $args['post_parent__not_in'] = $request['parent_exclude']; - $args['s'] = $request['search']; - - $args['date_query'] = array(); - // Set before into date query. Date query must be specified as an array of an array. - if ( isset( $request['before'] ) ) { - $args['date_query'][0]['before'] = $request['before']; - } - - // Set after into date query. Date query must be specified as an array of an array. - if ( isset( $request['after'] ) ) { - $args['date_query'][0]['after'] = $request['after']; - } - - if ( 'wc/v1' === $this->namespace ) { - if ( is_array( $request['filter'] ) ) { - $args = array_merge( $args, $request['filter'] ); - unset( $args['filter'] ); - } - } - - // Force the post_type argument, since it's not a user input variable. - $args['post_type'] = $this->post_type; - - /** - * Filter the query arguments for a request. - * - * Enables adding extra arguments or setting defaults for a post - * collection request. - * - * @param array $args Key value array of query var to query value. - * @param WP_REST_Request $request The request used. - */ - $args = apply_filters( "woocommerce_rest_{$this->post_type}_query", $args, $request ); - $query_args = $this->prepare_items_query( $args, $request ); - - $posts_query = new WP_Query(); - $query_result = $posts_query->query( $query_args ); - - $posts = array(); - foreach ( $query_result as $post ) { - if ( ! wc_rest_check_post_permissions( $this->post_type, 'read', $post->ID ) ) { - continue; - } - - $data = $this->prepare_item_for_response( $post, $request ); - $posts[] = $this->prepare_response_for_collection( $data ); - } - - $page = (int) $query_args['paged']; - $total_posts = $posts_query->found_posts; - - if ( $total_posts < 1 ) { - // Out-of-bounds, run the query again without LIMIT for total count. - unset( $query_args['paged'] ); - $count_query = new WP_Query(); - $count_query->query( $query_args ); - $total_posts = $count_query->found_posts; - } - - $max_pages = ceil( $total_posts / (int) $query_args['posts_per_page'] ); - - $response = rest_ensure_response( $posts ); - $response->header( 'X-WP-Total', (int) $total_posts ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - - $request_params = $request->get_query_params(); - if ( ! empty( $request_params['filter'] ) ) { - // Normalize the pagination params. - unset( $request_params['filter']['posts_per_page'] ); - unset( $request_params['filter']['paged'] ); - } - $base = add_query_arg( $request_params, rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); - - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } - - return $response; - } - - /** - * Delete a single item. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $id = (int) $request['id']; - $force = (bool) $request['force']; - $post = get_post( $id ); - - if ( empty( $id ) || empty( $post->ID ) || $post->post_type !== $this->post_type ) { - return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $supports_trash = EMPTY_TRASH_DAYS > 0; - - /** - * Filter whether an item is trashable. - * - * Return false to disable trash support for the item. - * - * @param boolean $supports_trash Whether the item type support trashing. - * @param WP_Post $post The Post object being considered for trashing support. - */ - $supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_trashable", $supports_trash, $post ); - - if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $post->ID ) ) { - /* translators: %s: post type */ - return new WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $post, $request ); - - // If we're forcing, then delete permanently. - if ( $force ) { - $result = wp_delete_post( $id, true ); - } else { - // If we don't support trashing for this type, error out. - if ( ! $supports_trash ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 501 ) ); - } - - // Otherwise, only trash if we haven't already. - if ( 'trash' === $post->post_status ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 410 ) ); - } - - // (Note that internally this falls through to `wp_delete_post` if - // the trash is disabled.) - $result = wp_trash_post( $id ); - } - - if ( ! $result ) { - /* translators: %s: post type */ - return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce-rest-api' ), $this->post_type ), array( 'status' => 500 ) ); - } - - /** - * Fires after a single item is deleted or trashed via the REST API. - * - * @param object $post The deleted or trashed item. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( "woocommerce_rest_delete_{$this->post_type}", $post, $response, $request ); - - return $response; - } - - /** - * Prepare links for the request. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @return array Links for the given post. - */ - protected function prepare_links( $post, $request ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - return $links; - } - - /** - * Determine the allowed query_vars for a get_items() response and - * prepare for WP_Query. - * - * @param array $prepared_args Prepared arguments. - * @param WP_REST_Request $request Request object. - * @return array $query_args - */ - protected function prepare_items_query( $prepared_args = array(), $request = null ) { - - $valid_vars = array_flip( $this->get_allowed_query_vars() ); - $query_args = array(); - foreach ( $valid_vars as $var => $index ) { - if ( isset( $prepared_args[ $var ] ) ) { - /** - * Filter the query_vars used in `get_items` for the constructed query. - * - * The dynamic portion of the hook name, $var, refers to the query_var key. - * - * @param mixed $prepared_args[ $var ] The query_var value. - */ - $query_args[ $var ] = apply_filters( "woocommerce_rest_query_var-{$var}", $prepared_args[ $var ] ); - } - } - - $query_args['ignore_sticky_posts'] = true; - - if ( 'include' === $query_args['orderby'] ) { - $query_args['orderby'] = 'post__in'; - } elseif ( 'id' === $query_args['orderby'] ) { - $query_args['orderby'] = 'ID'; // ID must be capitalized. - } elseif ( 'slug' === $query_args['orderby'] ) { - $query_args['orderby'] = 'name'; - } - - return $query_args; - } - - /** - * Get all the WP Query vars that are allowed for the API request. - * - * @return array - */ - protected function get_allowed_query_vars() { - global $wp; - - /** - * Filter the publicly allowed query vars. - * - * Allows adjusting of the default query vars that are made public. - * - * @param array Array of allowed WP_Query query vars. - */ - $valid_vars = apply_filters( 'query_vars', $wp->public_query_vars ); - - $post_type_obj = get_post_type_object( $this->post_type ); - if ( current_user_can( $post_type_obj->cap->edit_posts ) ) { - /** - * Filter the allowed 'private' query vars for authorized users. - * - * If the user has the `edit_posts` capability, we also allow use of - * private query parameters, which are only undesirable on the - * frontend, but are safe for use in query strings. - * - * To disable anyway, use - * `add_filter( 'woocommerce_rest_private_query_vars', '__return_empty_array' );` - * - * @param array $private_query_vars Array of allowed query vars for authorized users. - * } - */ - $private = apply_filters( 'woocommerce_rest_private_query_vars', $wp->private_query_vars ); - $valid_vars = array_merge( $valid_vars, $private ); - } - // Define our own in addition to WP's normal vars. - $rest_valid = array( - 'date_query', - 'ignore_sticky_posts', - 'offset', - 'post__in', - 'post__not_in', - 'post_parent', - 'post_parent__in', - 'post_parent__not_in', - 'posts_per_page', - 'meta_query', - 'tax_query', - 'meta_key', - 'meta_value', - 'meta_compare', - 'meta_value_num', - ); - $valid_vars = array_merge( $valid_vars, $rest_valid ); - - /** - * Filter allowed query vars for the REST API. - * - * This filter allows you to add or remove query vars from the final allowed - * list for all requests, including unauthenticated ones. To alter the - * vars for editors only. - * - * @param array { - * Array of allowed WP_Query query vars. - * - * @param string $allowed_query_var The query var to allow. - * } - */ - $valid_vars = apply_filters( 'woocommerce_rest_query_vars', $valid_vars ); - - return $valid_vars; - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['context']['default'] = 'view'; - - $params['after'] = array( - 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['before'] = array( - 'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['exclude'] = array( - 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['include'] = array( - 'description' => __( 'Limit result set to specific ids.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['offset'] = array( - 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['order'] = array( - 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'desc', - 'enum' => array( 'asc', 'desc' ), - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['orderby'] = array( - 'description' => __( 'Sort collection by object attribute.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'date', - 'enum' => array( - 'date', - 'id', - 'include', - 'title', - 'slug', - 'modified', - ), - 'validate_callback' => 'rest_validate_request_arg', - ); - - $post_type_obj = get_post_type_object( $this->post_type ); - - if ( isset( $post_type_obj->hierarchical ) && $post_type_obj->hierarchical ) { - $params['parent'] = array( - 'description' => __( 'Limit result set to those of particular parent IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'sanitize_callback' => 'wp_parse_id_list', - 'default' => array(), - ); - $params['parent_exclude'] = array( - 'description' => __( 'Limit result set to all items except those of a particular parent ID.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'sanitize_callback' => 'wp_parse_id_list', - 'default' => array(), - ); - } - - if ( 'wc/v1' === $this->namespace ) { - $params['filter'] = array( - 'type' => 'object', - 'description' => __( 'Use WP Query arguments to modify the response; private query vars require appropriate authorization.', 'woocommerce-rest-api' ), - ); - } - - return $params; - } - - /** - * Update post meta fields. - * - * @param WP_Post $post Post object. - * @param WP_REST_Request $request Request object. - * @return bool|WP_Error - */ - protected function update_post_meta_fields( $post, $request ) { - return true; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-product-attribute-terms-controller.php b/src/Controllers/Version3/class-wc-rest-product-attribute-terms-controller.php deleted file mode 100644 index bbbdb6eb822..00000000000 --- a/src/Controllers/Version3/class-wc-rest-product-attribute-terms-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/terms endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 2.6.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Product Attribute Terms controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Product_Attribute_Terms_V2_Controller - */ -class WC_REST_Product_Attribute_Terms_Controller extends WC_REST_Product_Attribute_Terms_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v3'; -} diff --git a/src/Controllers/Version3/class-wc-rest-product-attributes-controller.php b/src/Controllers/Version3/class-wc-rest-product-attributes-controller.php deleted file mode 100644 index 3506306c130..00000000000 --- a/src/Controllers/Version3/class-wc-rest-product-attributes-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -term_id, 'display_type', true ); - - // Get category order. - $menu_order = get_term_meta( $item->term_id, 'order', true ); - - $data = array( - 'id' => (int) $item->term_id, - 'name' => $item->name, - 'slug' => $item->slug, - 'parent' => (int) $item->parent, - 'description' => $item->description, - 'display' => $display_type ? $display_type : 'default', - 'image' => null, - 'menu_order' => (int) $menu_order, - 'count' => (int) $item->count, - ); - - // Get category image. - $image_id = get_term_meta( $item->term_id, 'thumbnail_id', true ); - if ( $image_id ) { - $attachment = get_post( $image_id ); - - $data['image'] = array( - 'id' => (int) $image_id, - 'date_created' => wc_rest_prepare_date_response( $attachment->post_date ), - 'date_created_gmt' => wc_rest_prepare_date_response( $attachment->post_date_gmt ), - 'date_modified' => wc_rest_prepare_date_response( $attachment->post_modified ), - 'date_modified_gmt' => wc_rest_prepare_date_response( $attachment->post_modified_gmt ), - 'src' => wp_get_attachment_url( $image_id ), - 'name' => get_the_title( $attachment ), - 'alt' => get_post_meta( $image_id, '_wp_attachment_image_alt', true ), - ); - } - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $item, $request ) ); - - /** - * Filter a term item returned from the API. - * - * Allows modification of the term data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $item The original term object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->taxonomy}", $response, $item, $request ); - } - - /** - * Get the Category schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->taxonomy, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Category name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - ), - 'parent' => array( - 'description' => __( 'The ID for the parent of the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'HTML description of the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), - ), - 'display' => array( - 'description' => __( 'Category archive display type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'default', - 'enum' => array( 'default', 'products', 'subcategories', 'both' ), - 'context' => array( 'view', 'edit' ), - ), - 'image' => array( - 'description' => __( 'Image data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the image was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the image was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'count' => array( - 'description' => __( 'Number of published products for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Update term meta fields. - * - * @param WP_Term $term Term object. - * @param WP_REST_Request $request Request instance. - * @return bool|WP_Error - * - * @since 3.5.5 - */ - protected function update_term_meta_fields( $term, $request ) { - $id = (int) $term->term_id; - - if ( isset( $request['display'] ) ) { - update_term_meta( $id, 'display_type', 'default' === $request['display'] ? '' : $request['display'] ); - } - - if ( isset( $request['menu_order'] ) ) { - update_term_meta( $id, 'order', $request['menu_order'] ); - } - - if ( isset( $request['image'] ) ) { - if ( empty( $request['image']['id'] ) && ! empty( $request['image']['src'] ) ) { - $upload = wc_rest_upload_image_from_url( esc_url_raw( $request['image']['src'] ) ); - - if ( is_wp_error( $upload ) ) { - return $upload; - } - - $image_id = wc_rest_set_uploaded_image_as_attachment( $upload ); - } else { - $image_id = isset( $request['image']['id'] ) ? absint( $request['image']['id'] ) : 0; - } - - // Check if image_id is a valid image attachment before updating the term meta. - if ( $image_id && wp_attachment_is_image( $image_id ) ) { - update_term_meta( $id, 'thumbnail_id', $image_id ); - - // Set the image alt. - if ( ! empty( $request['image']['alt'] ) ) { - update_post_meta( $image_id, '_wp_attachment_image_alt', wc_clean( $request['image']['alt'] ) ); - } - - // Set the image title. - if ( ! empty( $request['image']['name'] ) ) { - wp_update_post( - array( - 'ID' => $image_id, - 'post_title' => wc_clean( $request['image']['name'] ), - ) - ); - } - } else { - delete_term_meta( $id, 'thumbnail_id' ); - } - } - - return true; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-product-reviews-controller.php b/src/Controllers/Version3/class-wc-rest-product-reviews-controller.php deleted file mode 100644 index aee1016454f..00000000000 --- a/src/Controllers/Version3/class-wc-rest-product-reviews-controller.php +++ /dev/null @@ -1,1164 +0,0 @@ -namespace, '/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( - $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( - 'product_id' => array( - 'required' => true, - 'description' => __( 'Unique identifier for the product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - 'review' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Review content.', 'woocommerce-rest-api' ), - ), - 'reviewer' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Name of the reviewer.', 'woocommerce-rest-api' ), - ), - 'reviewer_email' => array( - 'required' => true, - 'type' => 'string', - 'description' => __( 'Email of the reviewer.', 'woocommerce-rest-api' ), - ), - ) - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - } - - /** - * Check whether a given request has permission to read webhook deliveries. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_rest_check_product_reviews_permissions( 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - $id = (int) $request['id']; - $review = get_comment( $id ); - - if ( $review && ! wc_rest_check_product_reviews_permissions( 'read', $review->comment_ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to create a new product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_rest_check_product_reviews_permissions( 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to update a product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - $id = (int) $request['id']; - $review = get_comment( $id ); - - if ( $review && ! wc_rest_check_product_reviews_permissions( 'edit', $review->comment_ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to delete a product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - $id = (int) $request['id']; - $review = get_comment( $id ); - - if ( $review && ! wc_rest_check_product_reviews_permissions( 'delete', $review->comment_ID ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access batch create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * @return boolean|WP_Error - */ - public function batch_items_permissions_check( $request ) { - if ( ! wc_rest_check_product_reviews_permissions( 'create' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Get all reviews. - * - * @param WP_REST_Request $request Full details about the request. - * @return array|WP_Error - */ - public function get_items( $request ) { - // Retrieve the list of registered collection query parameters. - $registered = $this->get_collection_params(); - - /* - * This array defines mappings between public API query parameters whose - * values are accepted as-passed, and their internal WP_Query parameter - * name equivalents (some are the same). Only values which are also - * present in $registered will be set. - */ - $parameter_mappings = array( - 'reviewer' => 'author__in', - 'reviewer_email' => 'author_email', - 'reviewer_exclude' => 'author__not_in', - 'exclude' => 'comment__not_in', - 'include' => 'comment__in', - 'offset' => 'offset', - 'order' => 'order', - 'per_page' => 'number', - 'product' => 'post__in', - 'search' => 'search', - 'status' => 'status', - ); - - $prepared_args = array(); - - /* - * For each known parameter which is both registered and present in the request, - * set the parameter's value on the query $prepared_args. - */ - foreach ( $parameter_mappings as $api_param => $wp_param ) { - if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { - $prepared_args[ $wp_param ] = $request[ $api_param ]; - } - } - - // Ensure certain parameter values default to empty strings. - foreach ( array( 'author_email', 'search' ) as $param ) { - if ( ! isset( $prepared_args[ $param ] ) ) { - $prepared_args[ $param ] = ''; - } - } - - if ( isset( $registered['orderby'] ) ) { - $prepared_args['orderby'] = $this->normalize_query_param( $request['orderby'] ); - } - - if ( isset( $prepared_args['status'] ) ) { - $prepared_args['status'] = 'approved' === $prepared_args['status'] ? 'approve' : $prepared_args['status']; - } - - $prepared_args['no_found_rows'] = false; - $prepared_args['date_query'] = array(); - - // Set before into date query. Date query must be specified as an array of an array. - if ( isset( $registered['before'], $request['before'] ) ) { - $prepared_args['date_query'][0]['before'] = $request['before']; - } - - // Set after into date query. Date query must be specified as an array of an array. - if ( isset( $registered['after'], $request['after'] ) ) { - $prepared_args['date_query'][0]['after'] = $request['after']; - } - - if ( isset( $registered['page'] ) && empty( $request['offset'] ) ) { - $prepared_args['offset'] = $prepared_args['number'] * ( absint( $request['page'] ) - 1 ); - } - - /** - * Filters arguments, before passing to WP_Comment_Query, when querying reviews via the REST API. - * - * @since 3.5.0 - * @link https://developer.wordpress.org/reference/classes/wp_comment_query/ - * @param array $prepared_args Array of arguments for WP_Comment_Query. - * @param WP_REST_Request $request The current request. - */ - $prepared_args = apply_filters( 'woocommerce_rest_product_review_query', $prepared_args, $request ); - - // Make sure that returns only reviews. - $prepared_args['type'] = 'review'; - - // Query reviews. - $query = new WP_Comment_Query(); - $query_result = $query->query( $prepared_args ); - $reviews = array(); - - foreach ( $query_result as $review ) { - if ( ! wc_rest_check_product_reviews_permissions( 'read', $review->comment_ID ) ) { - continue; - } - - $data = $this->prepare_item_for_response( $review, $request ); - $reviews[] = $this->prepare_response_for_collection( $data ); - } - - $total_reviews = (int) $query->found_comments; - $max_pages = (int) $query->max_num_pages; - - if ( $total_reviews < 1 ) { - // Out-of-bounds, run the query again without LIMIT for total count. - unset( $prepared_args['number'], $prepared_args['offset'] ); - - $query = new WP_Comment_Query(); - $prepared_args['count'] = true; - - $total_reviews = $query->query( $prepared_args ); - $max_pages = ceil( $total_reviews / $request['per_page'] ); - } - - $response = rest_ensure_response( $reviews ); - $response->header( 'X-WP-Total', $total_reviews ); - $response->header( 'X-WP-TotalPages', $max_pages ); - - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); - - if ( $request['page'] > 1 ) { - $prev_page = $request['page'] - 1; - - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - - if ( $max_pages > $request['page'] ) { - $next_page = $request['page'] + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - - $response->link_header( 'next', $next_link ); - } - - return $response; - } - - /** - * Create a single review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function create_item( $request ) { - if ( ! empty( $request['id'] ) ) { - return new WP_Error( 'woocommerce_rest_review_exists', __( 'Cannot create existing product review.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $product_id = (int) $request['product_id']; - - if ( 'product' !== get_post_type( $product_id ) ) { - return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $prepared_review = $this->prepare_item_for_database( $request ); - if ( is_wp_error( $prepared_review ) ) { - return $prepared_review; - } - - $prepared_review['comment_type'] = 'review'; - - /* - * Do not allow a comment to be created with missing or empty comment_content. See wp_handle_comment_submission(). - */ - if ( empty( $prepared_review['comment_content'] ) ) { - return new WP_Error( 'woocommerce_rest_review_content_invalid', __( 'Invalid review content.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - // Setting remaining values before wp_insert_comment so we can use wp_allow_comment(). - if ( ! isset( $prepared_review['comment_date_gmt'] ) ) { - $prepared_review['comment_date_gmt'] = current_time( 'mysql', true ); - } - - if ( ! empty( $_SERVER['REMOTE_ADDR'] ) && rest_is_ip_address( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) ) { // WPCS: input var ok, sanitization ok. - $prepared_review['comment_author_IP'] = wc_clean( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); // WPCS: input var ok. - } else { - $prepared_review['comment_author_IP'] = '127.0.0.1'; - } - - if ( ! empty( $request['author_user_agent'] ) ) { - $prepared_review['comment_agent'] = $request['author_user_agent']; - } elseif ( $request->get_header( 'user_agent' ) ) { - $prepared_review['comment_agent'] = $request->get_header( 'user_agent' ); - } else { - $prepared_review['comment_agent'] = ''; - } - - $check_comment_lengths = wp_check_comment_data_max_lengths( $prepared_review ); - if ( is_wp_error( $check_comment_lengths ) ) { - $error_code = str_replace( array( 'comment_author', 'comment_content' ), array( 'reviewer', 'review_content' ), $check_comment_lengths->get_error_code() ); - return new WP_Error( 'woocommerce_rest_' . $error_code, __( 'Product review field exceeds maximum length allowed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $prepared_review['comment_parent'] = 0; - $prepared_review['comment_author_url'] = ''; - $prepared_review['comment_approved'] = wp_allow_comment( $prepared_review, true ); - - if ( is_wp_error( $prepared_review['comment_approved'] ) ) { - $error_code = $prepared_review['comment_approved']->get_error_code(); - $error_message = $prepared_review['comment_approved']->get_error_message(); - - if ( 'comment_duplicate' === $error_code ) { - return new WP_Error( 'woocommerce_rest_' . $error_code, $error_message, array( 'status' => 409 ) ); - } - - if ( 'comment_flood' === $error_code ) { - return new WP_Error( 'woocommerce_rest_' . $error_code, $error_message, array( 'status' => 400 ) ); - } - - return $prepared_review['comment_approved']; - } - - /** - * Filters a review before it is inserted via the REST API. - * - * Allows modification of the review right before it is inserted via wp_insert_comment(). - * Returning a WP_Error value from the filter will shortcircuit insertion and allow - * skipping further processing. - * - * @since 3.5.0 - * @param array|WP_Error $prepared_review The prepared review data for wp_insert_comment(). - * @param WP_REST_Request $request Request used to insert the review. - */ - $prepared_review = apply_filters( 'woocommerce_rest_pre_insert_product_review', $prepared_review, $request ); - if ( is_wp_error( $prepared_review ) ) { - return $prepared_review; - } - - $review_id = wp_insert_comment( wp_filter_comment( wp_slash( (array) $prepared_review ) ) ); - - if ( ! $review_id ) { - return new WP_Error( 'woocommerce_rest_review_failed_create', __( 'Creating product review failed.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - if ( isset( $request['status'] ) ) { - $this->handle_status_param( $request['status'], $review_id ); - } - - update_comment_meta( $review_id, 'rating', ! empty( $request['rating'] ) ? $request['rating'] : '0' ); - - $review = get_comment( $review_id ); - - /** - * Fires after a comment is created or updated via the REST API. - * - * @param WP_Comment $review Inserted or updated comment object. - * @param WP_REST_Request $request Request object. - * @param bool $creating True when creating a comment, false when updating. - */ - do_action( 'woocommerce_rest_insert_product_review', $review, $request, true ); - - $fields_update = $this->update_additional_fields_for_object( $review, $request ); - if ( is_wp_error( $fields_update ) ) { - return $fields_update; - } - - $context = current_user_can( 'moderate_comments' ) ? 'edit' : 'view'; - $request->set_param( 'context', $context ); - - $response = $this->prepare_item_for_response( $review, $request ); - $response = rest_ensure_response( $response ); - - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $review_id ) ) ); - - return $response; - } - - /** - * Get a single product review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response - */ - public function get_item( $request ) { - $review = $this->get_review( $request['id'] ); - if ( is_wp_error( $review ) ) { - return $review; - } - - $data = $this->prepare_item_for_response( $review, $request ); - $response = rest_ensure_response( $data ); - - return $response; - } - - /** - * Updates a review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response Response object on success, or error object on failure. - */ - public function update_item( $request ) { - $review = $this->get_review( $request['id'] ); - if ( is_wp_error( $review ) ) { - return $review; - } - - $id = (int) $review->comment_ID; - - if ( isset( $request['type'] ) && 'review' !== get_comment_type( $id ) ) { - return new WP_Error( 'woocommerce_rest_review_invalid_type', __( 'Sorry, you are not allowed to change the comment type.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $prepared_args = $this->prepare_item_for_database( $request ); - if ( is_wp_error( $prepared_args ) ) { - return $prepared_args; - } - - if ( ! empty( $prepared_args['comment_post_ID'] ) ) { - if ( 'product' !== get_post_type( (int) $prepared_args['comment_post_ID'] ) ) { - return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - } - - if ( empty( $prepared_args ) && isset( $request['status'] ) ) { - // Only the comment status is being changed. - $change = $this->handle_status_param( $request['status'], $id ); - - if ( ! $change ) { - return new WP_Error( 'woocommerce_rest_review_failed_edit', __( 'Updating review status failed.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - } elseif ( ! empty( $prepared_args ) ) { - if ( is_wp_error( $prepared_args ) ) { - return $prepared_args; - } - - if ( isset( $prepared_args['comment_content'] ) && empty( $prepared_args['comment_content'] ) ) { - return new WP_Error( 'woocommerce_rest_review_content_invalid', __( 'Invalid review content.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $prepared_args['comment_ID'] = $id; - - $check_comment_lengths = wp_check_comment_data_max_lengths( $prepared_args ); - if ( is_wp_error( $check_comment_lengths ) ) { - $error_code = str_replace( array( 'comment_author', 'comment_content' ), array( 'reviewer', 'review_content' ), $check_comment_lengths->get_error_code() ); - return new WP_Error( 'woocommerce_rest_' . $error_code, __( 'Product review field exceeds maximum length allowed.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - - $updated = wp_update_comment( wp_slash( (array) $prepared_args ) ); - - if ( false === $updated ) { - return new WP_Error( 'woocommerce_rest_comment_failed_edit', __( 'Updating review failed.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - if ( isset( $request['status'] ) ) { - $this->handle_status_param( $request['status'], $id ); - } - } - - if ( ! empty( $request['rating'] ) ) { - update_comment_meta( $id, 'rating', $request['rating'] ); - } - - $review = get_comment( $id ); - - /** This action is documented in includes/api/class-wc-rest-product-reviews-controller.php */ - do_action( 'woocommerce_rest_insert_product_review', $review, $request, false ); - - $fields_update = $this->update_additional_fields_for_object( $review, $request ); - - if ( is_wp_error( $fields_update ) ) { - return $fields_update; - } - - $request->set_param( 'context', 'edit' ); - - $response = $this->prepare_item_for_response( $review, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Deletes a review. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|WP_REST_Response Response object on success, or error object on failure. - */ - public function delete_item( $request ) { - $review = $this->get_review( $request['id'] ); - if ( is_wp_error( $review ) ) { - return $review; - } - - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - /** - * Filters whether a review can be trashed. - * - * Return false to disable trash support for the post. - * - * @since 3.5.0 - * @param bool $supports_trash Whether the post type support trashing. - * @param WP_Comment $review The review object being considered for trashing support. - */ - $supports_trash = apply_filters( 'woocommerce_rest_product_review_trashable', ( EMPTY_TRASH_DAYS > 0 ), $review ); - - $request->set_param( 'context', 'edit' ); - - if ( $force ) { - $previous = $this->prepare_item_for_response( $review, $request ); - $result = wp_delete_comment( $review->comment_ID, true ); - $response = new WP_REST_Response(); - $response->set_data( - array( - 'deleted' => true, - 'previous' => $previous->get_data(), - ) - ); - } else { - // If this type doesn't support trashing, error out. - if ( ! $supports_trash ) { - /* translators: %s: force=true */ - return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( "The object does not support trashing. Set '%s' to delete.", 'woocommerce-rest-api' ), 'force=true' ), array( 'status' => 501 ) ); - } - - if ( 'trash' === $review->comment_approved ) { - return new WP_Error( 'woocommerce_rest_already_trashed', __( 'The object has already been trashed.', 'woocommerce-rest-api' ), array( 'status' => 410 ) ); - } - - $result = wp_trash_comment( $review->comment_ID ); - $review = get_comment( $review->comment_ID ); - $response = $this->prepare_item_for_response( $review, $request ); - } - - if ( ! $result ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The object cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a review is deleted via the REST API. - * - * @param WP_Comment $review The deleted review data. - * @param WP_REST_Response $response The response returned from the API. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'woocommerce_rest_delete_review', $review, $response, $request ); - - return $response; - } - - /** - * Prepare a single product review output for response. - * - * @param WP_Comment $review Product review object. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $review, $request ) { - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $fields = $this->get_fields_for_response( $request ); - $data = array(); - - if ( in_array( 'id', $fields, true ) ) { - $data['id'] = (int) $review->comment_ID; - } - if ( in_array( 'date_created', $fields, true ) ) { - $data['date_created'] = wc_rest_prepare_date_response( $review->comment_date ); - } - if ( in_array( 'date_created_gmt', $fields, true ) ) { - $data['date_created_gmt'] = wc_rest_prepare_date_response( $review->comment_date_gmt ); - } - if ( in_array( 'product_id', $fields, true ) ) { - $data['product_id'] = (int) $review->comment_post_ID; - } - if ( in_array( 'status', $fields, true ) ) { - $data['status'] = $this->prepare_status_response( (string) $review->comment_approved ); - } - if ( in_array( 'reviewer', $fields, true ) ) { - $data['reviewer'] = $review->comment_author; - } - if ( in_array( 'reviewer_email', $fields, true ) ) { - $data['reviewer_email'] = $review->comment_author_email; - } - if ( in_array( 'review', $fields, true ) ) { - $data['review'] = 'view' === $context ? wpautop( $review->comment_content ) : $review->comment_content; - } - if ( in_array( 'rating', $fields, true ) ) { - $data['rating'] = (int) get_comment_meta( $review->comment_ID, 'rating', true ); - } - if ( in_array( 'verified', $fields, true ) ) { - $data['verified'] = wc_review_is_from_verified_owner( $review->comment_ID ); - } - if ( in_array( 'reviewer_avatar_urls', $fields, true ) ) { - $data['reviewer_avatar_urls'] = rest_get_avatar_urls( $review->comment_author_email ); - } - - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - $response->add_links( $this->prepare_links( $review ) ); - - /** - * Filter product reviews object returned from the REST API. - * - * @param WP_REST_Response $response The response object. - * @param WP_Comment $review Product review object used to create response. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( 'woocommerce_rest_prepare_product_review', $response, $review, $request ); - } - - /** - * Prepare a single product review to be inserted into the database. - * - * @param WP_REST_Request $request Request object. - * @return array|WP_Error $prepared_review - */ - protected function prepare_item_for_database( $request ) { - if ( isset( $request['id'] ) ) { - $prepared_review['comment_ID'] = (int) $request['id']; - } - - if ( isset( $request['review'] ) ) { - $prepared_review['comment_content'] = $request['review']; - } - - if ( isset( $request['product_id'] ) ) { - $prepared_review['comment_post_ID'] = (int) $request['product_id']; - } - - if ( isset( $request['reviewer'] ) ) { - $prepared_review['comment_author'] = $request['reviewer']; - } - - if ( isset( $request['reviewer_email'] ) ) { - $prepared_review['comment_author_email'] = $request['reviewer_email']; - } - - if ( ! empty( $request['date_created'] ) ) { - $date_data = rest_get_date_with_gmt( $request['date_created'] ); - - if ( ! empty( $date_data ) ) { - list( $prepared_review['comment_date'], $prepared_review['comment_date_gmt'] ) = $date_data; - } - } elseif ( ! empty( $request['date_created_gmt'] ) ) { - $date_data = rest_get_date_with_gmt( $request['date_created_gmt'], true ); - - if ( ! empty( $date_data ) ) { - list( $prepared_review['comment_date'], $prepared_review['comment_date_gmt'] ) = $date_data; - } - } - - /** - * Filters a review after it is prepared for the database. - * - * Allows modification of the review right after it is prepared for the database. - * - * @since 3.5.0 - * @param array $prepared_review The prepared review data for `wp_insert_comment`. - * @param WP_REST_Request $request The current request. - */ - return apply_filters( 'woocommerce_rest_preprocess_product_review', $prepared_review, $request ); - } - - /** - * Prepare links for the request. - * - * @param WP_Comment $review Product review object. - * @return array Links for the given product review. - */ - protected function prepare_links( $review ) { - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $review->comment_ID ) ), - ), - 'collection' => array( - 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), - ), - ); - - if ( 0 !== (int) $review->comment_post_ID ) { - $links['up'] = array( - 'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $review->comment_post_ID ) ), - ); - } - - if ( 0 !== (int) $review->user_id ) { - $links['reviewer'] = array( - 'href' => rest_url( 'wp/v2/users/' . $review->user_id ), - 'embeddable' => true, - ); - } - - return $links; - } - - /** - * Get the Product Review's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'product_review', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the review was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the review was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'product_id' => array( - 'description' => __( 'Unique identifier for the product that the review belongs to.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'status' => array( - 'description' => __( 'Status of the review.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'approved', - 'enum' => array( 'approved', 'hold', 'spam', 'unspam', 'trash', 'untrash' ), - 'context' => array( 'view', 'edit' ), - ), - 'reviewer' => array( - 'description' => __( 'Reviewer name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'reviewer_email' => array( - 'description' => __( 'Reviewer email.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'email', - 'context' => array( 'view', 'edit' ), - ), - 'review' => array( - 'description' => __( 'The content of the review.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'arg_options' => array( - 'sanitize_callback' => 'wp_filter_post_kses', - ), - ), - 'rating' => array( - 'description' => __( 'Review rating (0 to 5).', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'verified' => array( - 'description' => __( 'Shows if the reviewer bought the product or not.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - if ( get_option( 'show_avatars' ) ) { - $avatar_properties = array(); - $avatar_sizes = rest_get_avatar_sizes(); - - foreach ( $avatar_sizes as $size ) { - $avatar_properties[ $size ] = array( - /* translators: %d: avatar image size in pixels */ - 'description' => sprintf( __( 'Avatar URL with image size of %d pixels.', 'woocommerce-rest-api' ), $size ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'embed', 'view', 'edit' ), - ); - } - $schema['properties']['reviewer_avatar_urls'] = array( - 'description' => __( 'Avatar URLs for the object reviewer.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - 'properties' => $avatar_properties, - ); - } - - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Get the query params for collections. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - $params['context']['default'] = 'view'; - - $params['after'] = array( - 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - ); - $params['before'] = array( - 'description' => __( 'Limit response to reviews published before a given ISO8601 compliant date.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'date-time', - ); - $params['exclude'] = array( - 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - ); - $params['include'] = array( - 'description' => __( 'Limit result set to specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - ); - $params['offset'] = array( - 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ); - $params['order'] = array( - 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'desc', - 'enum' => array( - 'asc', - 'desc', - ), - ); - $params['orderby'] = array( - 'description' => __( 'Sort collection by object attribute.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'date_gmt', - 'enum' => array( - 'date', - 'date_gmt', - 'id', - 'include', - 'product', - ), - ); - $params['reviewer'] = array( - 'description' => __( 'Limit result set to reviews assigned to specific user IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - ); - $params['reviewer_exclude'] = array( - 'description' => __( 'Ensure result set excludes reviews assigned to specific user IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - ); - $params['reviewer_email'] = array( - 'default' => null, - 'description' => __( 'Limit result set to that from a specific author email.', 'woocommerce-rest-api' ), - 'format' => 'email', - 'type' => 'string', - ); - $params['product'] = array( - 'default' => array(), - 'description' => __( 'Limit result set to reviews assigned to specific product IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - ); - $params['status'] = array( - 'default' => 'approved', - 'description' => __( 'Limit result set to reviews assigned a specific status.', 'woocommerce-rest-api' ), - 'sanitize_callback' => 'sanitize_key', - 'type' => 'string', - 'enum' => array( - 'all', - 'hold', - 'approved', - 'spam', - 'trash', - ), - ); - - /** - * Filter collection parameters for the reviews controller. - * - * This filter registers the collection parameter, but does not map the - * collection parameter to an internal WP_Comment_Query parameter. Use the - * `wc_rest_review_query` filter to set WP_Comment_Query parameters. - * - * @since 3.5.0 - * @param array $params JSON Schema-formatted collection parameters. - */ - return apply_filters( 'woocommerce_rest_product_review_collection_params', $params ); - } - - /** - * Get the reivew, if the ID is valid. - * - * @since 3.5.0 - * @param int $id Supplied ID. - * @return WP_Comment|WP_Error Comment object if ID is valid, WP_Error otherwise. - */ - protected function get_review( $id ) { - $id = (int) $id; - $error = new WP_Error( 'woocommerce_rest_review_invalid_id', __( 'Invalid review ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - - if ( 0 >= $id ) { - return $error; - } - - $review = get_comment( $id ); - if ( empty( $review ) ) { - return $error; - } - - if ( ! empty( $review->comment_post_ID ) ) { - $post = get_post( (int) $review->comment_post_ID ); - - if ( 'product' !== get_post_type( (int) $review->comment_post_ID ) ) { - return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - } - - return $review; - } - - /** - * Prepends internal property prefix to query parameters to match our response fields. - * - * @since 3.5.0 - * @param string $query_param Query parameter. - * @return string - */ - protected function normalize_query_param( $query_param ) { - $prefix = 'comment_'; - - switch ( $query_param ) { - case 'id': - $normalized = $prefix . 'ID'; - break; - case 'product': - $normalized = $prefix . 'post_ID'; - break; - case 'include': - $normalized = 'comment__in'; - break; - default: - $normalized = $prefix . $query_param; - break; - } - - return $normalized; - } - - /** - * Checks comment_approved to set comment status for single comment output. - * - * @since 3.5.0 - * @param string|int $comment_approved comment status. - * @return string Comment status. - */ - protected function prepare_status_response( $comment_approved ) { - switch ( $comment_approved ) { - case 'hold': - case '0': - $status = 'hold'; - break; - case 'approve': - case '1': - $status = 'approved'; - break; - case 'spam': - case 'trash': - default: - $status = $comment_approved; - break; - } - - return $status; - } - - /** - * Sets the comment_status of a given review object when creating or updating a review. - * - * @since 3.5.0 - * @param string|int $new_status New review status. - * @param int $id Review ID. - * @return bool Whether the status was changed. - */ - protected function handle_status_param( $new_status, $id ) { - $old_status = wp_get_comment_status( $id ); - - if ( $new_status === $old_status ) { - return false; - } - - switch ( $new_status ) { - case 'approved': - case 'approve': - case '1': - $changed = wp_set_comment_status( $id, 'approve' ); - break; - case 'hold': - case '0': - $changed = wp_set_comment_status( $id, 'hold' ); - break; - case 'spam': - $changed = wp_spam_comment( $id ); - break; - case 'unspam': - $changed = wp_unspam_comment( $id ); - break; - case 'trash': - $changed = wp_trash_comment( $id ); - break; - case 'untrash': - $changed = wp_untrash_comment( $id ); - break; - default: - $changed = false; - break; - } - - return $changed; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-product-shipping-classes-controller.php b/src/Controllers/Version3/class-wc-rest-product-shipping-classes-controller.php deleted file mode 100644 index 716e40db7f4..00000000000 --- a/src/Controllers/Version3/class-wc-rest-product-shipping-classes-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/variations endpoints. - * - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API variations controller class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Product_Variations_V2_Controller - */ -class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v3'; - - /** - * Prepare a single variation output for response. - * - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function prepare_object_for_response( $object, $request ) { - $data = array( - 'id' => $object->get_id(), - 'date_created' => wc_rest_prepare_date_response( $object->get_date_created(), false ), - 'date_created_gmt' => wc_rest_prepare_date_response( $object->get_date_created() ), - 'date_modified' => wc_rest_prepare_date_response( $object->get_date_modified(), false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( $object->get_date_modified() ), - 'description' => wc_format_content( $object->get_description() ), - 'permalink' => $object->get_permalink(), - 'sku' => $object->get_sku(), - 'price' => $object->get_price(), - 'regular_price' => $object->get_regular_price(), - 'sale_price' => $object->get_sale_price(), - 'date_on_sale_from' => wc_rest_prepare_date_response( $object->get_date_on_sale_from(), false ), - 'date_on_sale_from_gmt' => wc_rest_prepare_date_response( $object->get_date_on_sale_from() ), - 'date_on_sale_to' => wc_rest_prepare_date_response( $object->get_date_on_sale_to(), false ), - 'date_on_sale_to_gmt' => wc_rest_prepare_date_response( $object->get_date_on_sale_to() ), - 'on_sale' => $object->is_on_sale(), - 'status' => $object->get_status(), - 'purchasable' => $object->is_purchasable(), - 'virtual' => $object->is_virtual(), - 'downloadable' => $object->is_downloadable(), - 'downloads' => $this->get_downloads( $object ), - 'download_limit' => '' !== $object->get_download_limit() ? (int) $object->get_download_limit() : -1, - 'download_expiry' => '' !== $object->get_download_expiry() ? (int) $object->get_download_expiry() : -1, - 'tax_status' => $object->get_tax_status(), - 'tax_class' => $object->get_tax_class(), - 'manage_stock' => $object->managing_stock(), - 'stock_quantity' => $object->get_stock_quantity(), - 'stock_status' => $object->get_stock_status(), - 'backorders' => $object->get_backorders(), - 'backorders_allowed' => $object->backorders_allowed(), - 'backordered' => $object->is_on_backorder(), - 'weight' => $object->get_weight(), - 'dimensions' => array( - 'length' => $object->get_length(), - 'width' => $object->get_width(), - 'height' => $object->get_height(), - ), - 'shipping_class' => $object->get_shipping_class(), - 'shipping_class_id' => $object->get_shipping_class_id(), - 'image' => $this->get_image( $object ), - 'attributes' => $this->get_attributes( $object ), - 'menu_order' => $object->get_menu_order(), - 'meta_data' => $object->get_meta_data(), - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $object, $request ) ); - - /** - * Filter the data for a response. - * - * The dynamic portion of the hook name, $this->post_type, - * refers to object type being prepared for the response. - * - * @param WP_REST_Response $response The response object. - * @param WC_Data $object Object data. - * @param WP_REST_Request $request Request object. - */ - return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request ); - } - - /** - * Prepare a single variation for create or update. - * - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data - */ - protected function prepare_object_for_database( $request, $creating = false ) { - if ( isset( $request['id'] ) ) { - $variation = wc_get_product( absint( $request['id'] ) ); - } else { - $variation = new WC_Product_Variation(); - } - - $variation->set_parent_id( absint( $request['product_id'] ) ); - - // Status. - if ( isset( $request['status'] ) ) { - $variation->set_status( get_post_status_object( $request['status'] ) ? $request['status'] : 'draft' ); - } - - // SKU. - if ( isset( $request['sku'] ) ) { - $variation->set_sku( wc_clean( $request['sku'] ) ); - } - - // Thumbnail. - if ( isset( $request['image'] ) ) { - if ( is_array( $request['image'] ) ) { - $variation = $this->set_variation_image( $variation, $request['image'] ); - } else { - $variation->set_image_id( '' ); - } - } - - // Virtual variation. - if ( isset( $request['virtual'] ) ) { - $variation->set_virtual( $request['virtual'] ); - } - - // Downloadable variation. - if ( isset( $request['downloadable'] ) ) { - $variation->set_downloadable( $request['downloadable'] ); - } - - // Downloads. - if ( $variation->get_downloadable() ) { - // Downloadable files. - if ( isset( $request['downloads'] ) && is_array( $request['downloads'] ) ) { - $variation = $this->save_downloadable_files( $variation, $request['downloads'] ); - } - - // Download limit. - if ( isset( $request['download_limit'] ) ) { - $variation->set_download_limit( $request['download_limit'] ); - } - - // Download expiry. - if ( isset( $request['download_expiry'] ) ) { - $variation->set_download_expiry( $request['download_expiry'] ); - } - } - - // Shipping data. - $variation = $this->save_product_shipping_data( $variation, $request ); - - // Stock handling. - if ( isset( $request['manage_stock'] ) ) { - $variation->set_manage_stock( $request['manage_stock'] ); - } - - if ( isset( $request['stock_status'] ) ) { - $variation->set_stock_status( $request['stock_status'] ); - } - - if ( isset( $request['backorders'] ) ) { - $variation->set_backorders( $request['backorders'] ); - } - - if ( $variation->get_manage_stock() ) { - if ( isset( $request['stock_quantity'] ) ) { - $variation->set_stock_quantity( $request['stock_quantity'] ); - } elseif ( isset( $request['inventory_delta'] ) ) { - $stock_quantity = wc_stock_amount( $variation->get_stock_quantity() ); - $stock_quantity += wc_stock_amount( $request['inventory_delta'] ); - $variation->set_stock_quantity( $stock_quantity ); - } - } else { - $variation->set_backorders( 'no' ); - $variation->set_stock_quantity( '' ); - } - - // Regular Price. - if ( isset( $request['regular_price'] ) ) { - $variation->set_regular_price( $request['regular_price'] ); - } - - // Sale Price. - if ( isset( $request['sale_price'] ) ) { - $variation->set_sale_price( $request['sale_price'] ); - } - - if ( isset( $request['date_on_sale_from'] ) ) { - $variation->set_date_on_sale_from( $request['date_on_sale_from'] ); - } - - if ( isset( $request['date_on_sale_from_gmt'] ) ) { - $variation->set_date_on_sale_from( $request['date_on_sale_from_gmt'] ? strtotime( $request['date_on_sale_from_gmt'] ) : null ); - } - - if ( isset( $request['date_on_sale_to'] ) ) { - $variation->set_date_on_sale_to( $request['date_on_sale_to'] ); - } - - if ( isset( $request['date_on_sale_to_gmt'] ) ) { - $variation->set_date_on_sale_to( $request['date_on_sale_to_gmt'] ? strtotime( $request['date_on_sale_to_gmt'] ) : null ); - } - - // Tax class. - if ( isset( $request['tax_class'] ) ) { - $variation->set_tax_class( $request['tax_class'] ); - } - - // Description. - if ( isset( $request['description'] ) ) { - $variation->set_description( wp_kses_post( $request['description'] ) ); - } - - // Update taxonomies. - if ( isset( $request['attributes'] ) ) { - $attributes = array(); - $parent = wc_get_product( $variation->get_parent_id() ); - - if ( ! $parent ) { - return new WP_Error( - // Translators: %d parent ID. - "woocommerce_rest_{$this->post_type}_invalid_parent", sprintf( __( 'Cannot set attributes due to invalid parent product.', 'woocommerce-rest-api' ), $variation->get_parent_id() ), array( - 'status' => 404, - ) - ); - } - - $parent_attributes = $parent->get_attributes(); - - foreach ( $request['attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $attribute_name = sanitize_title( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $attribute_name ) { - continue; - } - - if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) { - continue; - } - - $attribute_key = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() ); - $attribute_value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : ''; - - if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) { - // If dealing with a taxonomy, we need to get the slug from the name posted to the API. - $term = get_term_by( 'name', $attribute_value, $attribute_name ); - - if ( $term && ! is_wp_error( $term ) ) { - $attribute_value = $term->slug; - } else { - $attribute_value = sanitize_title( $attribute_value ); - } - } - - $attributes[ $attribute_key ] = $attribute_value; - } - - $variation->set_attributes( $attributes ); - } - - // Menu order. - if ( $request['menu_order'] ) { - $variation->set_menu_order( $request['menu_order'] ); - } - - // Meta data. - if ( is_array( $request['meta_data'] ) ) { - foreach ( $request['meta_data'] as $meta ) { - $variation->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $variation Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $variation, $request, $creating ); - } - - /** - * Get the image for a product variation. - * - * @param WC_Product_Variation $variation Variation data. - * @return array - */ - protected function get_image( $variation ) { - if ( ! $variation->get_image_id() ) { - return; - } - - $attachment_id = $variation->get_image_id(); - $attachment_post = get_post( $attachment_id ); - if ( is_null( $attachment_post ) ) { - return; - } - - $attachment = wp_get_attachment_image_src( $attachment_id, 'full' ); - if ( ! is_array( $attachment ) ) { - return; - } - - if ( ! isset( $image ) ) { - return array( - 'id' => (int) $attachment_id, - 'date_created' => wc_rest_prepare_date_response( $attachment_post->post_date, false ), - 'date_created_gmt' => wc_rest_prepare_date_response( strtotime( $attachment_post->post_date_gmt ) ), - 'date_modified' => wc_rest_prepare_date_response( $attachment_post->post_modified, false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( strtotime( $attachment_post->post_modified_gmt ) ), - 'src' => current( $attachment ), - 'name' => get_the_title( $attachment_id ), - 'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ), - ); - } - } - - /** - * Set variation image. - * - * @throws WC_REST_Exception REST API exceptions. - * @param WC_Product_Variation $variation Variation instance. - * @param array $image Image data. - * @return WC_Product_Variation - */ - protected function set_variation_image( $variation, $image ) { - $attachment_id = isset( $image['id'] ) ? absint( $image['id'] ) : 0; - - if ( 0 === $attachment_id && isset( $image['src'] ) ) { - $upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) ); - - if ( is_wp_error( $upload ) ) { - if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $variation->get_id(), array( $image ) ) ) { - throw new WC_REST_Exception( 'woocommerce_variation_image_upload_error', $upload->get_error_message(), 400 ); - } - } - - $attachment_id = wc_rest_set_uploaded_image_as_attachment( $upload, $variation->get_id() ); - } - - if ( ! wp_attachment_is_image( $attachment_id ) ) { - /* translators: %s: attachment ID */ - throw new WC_REST_Exception( 'woocommerce_variation_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce-rest-api' ), $attachment_id ), 400 ); - } - - $variation->set_image_id( $attachment_id ); - - // Set the image alt if present. - if ( ! empty( $image['alt'] ) ) { - update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) ); - } - - // Set the image name if present. - if ( ! empty( $image['name'] ) ) { - wp_update_post( - array( - 'ID' => $attachment_id, - 'post_title' => $image['name'], - ) - ); - } - - return $variation; - } - - /** - * Get the Variation's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $weight_unit = get_option( 'woocommerce_weight_unit' ); - $dimension_unit = get_option( 'woocommerce_dimension_unit' ); - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the variation was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the variation was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'Variation description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'permalink' => array( - 'description' => __( 'Variation URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sku' => array( - 'description' => __( 'Unique identifier.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'price' => array( - 'description' => __( 'Current variation price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'regular_price' => array( - 'description' => __( 'Variation regular price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sale_price' => array( - 'description' => __( 'Variation sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from' => array( - 'description' => __( "Start date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from_gmt' => array( - 'description' => __( 'Start date of sale price, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to' => array( - 'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to_gmt' => array( - 'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'on_sale' => array( - 'description' => __( 'Shows if the variation is on sale.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'status' => array( - 'description' => __( 'Variation status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'publish', - 'enum' => array_keys( get_post_statuses() ), - 'context' => array( 'view', 'edit' ), - ), - 'purchasable' => array( - 'description' => __( 'Shows if the variation can be bought.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'virtual' => array( - 'description' => __( 'If the variation is virtual.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloadable' => array( - 'description' => __( 'If the variation is downloadable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloads' => array( - 'description' => __( 'List of downloadable files.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'File ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'download_limit' => array( - 'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'download_expiry' => array( - 'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'taxable', - 'enum' => array( 'taxable', 'shipping', 'none' ), - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'manage_stock' => array( - 'description' => __( 'Stock management at variation level.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'stock_quantity' => array( - 'description' => __( 'Stock quantity.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'stock_status' => array( - 'description' => __( 'Controls the stock status of the product.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'instock', - 'enum' => array_keys( wc_get_product_stock_status_options() ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders' => array( - 'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'no', - 'enum' => array( 'no', 'notify', 'yes' ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders_allowed' => array( - 'description' => __( 'Shows if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'backordered' => array( - 'description' => __( 'Shows if the variation is on backordered.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'weight' => array( - /* translators: %s: weight unit */ - 'description' => sprintf( __( 'Variation weight (%s).', 'woocommerce-rest-api' ), $weight_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'dimensions' => array( - 'description' => __( 'Variation dimensions.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'length' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation length (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'width' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation width (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'height' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Variation height (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping_class' => array( - 'description' => __( 'Shipping class slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'shipping_class_id' => array( - 'description' => __( 'Shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'image' => array( - 'description' => __( 'Variation image data.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the image was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the image was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'attributes' => array( - 'description' => __( 'List of attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'option' => array( - 'description' => __( 'Selected attribute term name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort products.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ); - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Prepare objects query. - * - * @since 3.0.0 - * @param WP_REST_Request $request Full details about the request. - * @return array - */ - protected function prepare_objects_query( $request ) { - $args = WC_REST_CRUD_Controller::prepare_objects_query( $request ); - - // Set post_status. - $args['post_status'] = $request['status']; - - // Filter by sku. - if ( ! empty( $request['sku'] ) ) { - $skus = explode( ',', $request['sku'] ); - // Include the current string as a SKU too. - if ( 1 < count( $skus ) ) { - $skus[] = $request['sku']; - } - - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, - array( - 'key' => '_sku', - 'value' => $skus, - 'compare' => 'IN', - ) - ); - } - - // Filter by tax class. - if ( ! empty( $request['tax_class'] ) ) { - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, - array( - 'key' => '_tax_class', - 'value' => 'standard' !== $request['tax_class'] ? $request['tax_class'] : '', - ) - ); - } - - // Price filter. - if ( ! empty( $request['min_price'] ) || ! empty( $request['max_price'] ) ) { - $args['meta_query'] = $this->add_meta_query( $args, wc_get_min_max_price_meta_query( $request ) ); // WPCS: slow query ok. - } - - // Filter product based on stock_status. - if ( ! empty( $request['stock_status'] ) ) { - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, - array( - 'key' => '_stock_status', - 'value' => $request['stock_status'], - ) - ); - } - - // Filter by on sale products. - if ( is_bool( $request['on_sale'] ) ) { - $on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in'; - $on_sale_ids = wc_get_product_ids_on_sale(); - - // Use 0 when there's no on sale products to avoid return all products. - $on_sale_ids = empty( $on_sale_ids ) ? array( 0 ) : $on_sale_ids; - - $args[ $on_sale_key ] += $on_sale_ids; - } - - // Force the post_type argument, since it's not a user input variable. - if ( ! empty( $request['sku'] ) ) { - $args['post_type'] = array( 'product', 'product_variation' ); - } else { - $args['post_type'] = $this->post_type; - } - - $args['post_parent'] = $request['product_id']; - - return $args; - } - - /** - * Get the query params for collections of attachments. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - unset( - $params['in_stock'], - $params['type'], - $params['featured'], - $params['category'], - $params['tag'], - $params['shipping_class'], - $params['attribute'], - $params['attribute_term'] - ); - - $params['stock_status'] = array( - 'description' => __( 'Limit result set to products with specified stock status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_keys( wc_get_product_stock_status_options() ), - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-products-controller.php b/src/Controllers/Version3/class-wc-rest-products-controller.php deleted file mode 100644 index a6401bf6d91..00000000000 --- a/src/Controllers/Version3/class-wc-rest-products-controller.php +++ /dev/null @@ -1,1341 +0,0 @@ -get_image_id() ) { - $attachment_ids[] = $product->get_image_id(); - } - - // Add gallery images. - $attachment_ids = array_merge( $attachment_ids, $product->get_gallery_image_ids() ); - - // Build image data. - foreach ( $attachment_ids as $attachment_id ) { - $attachment_post = get_post( $attachment_id ); - if ( is_null( $attachment_post ) ) { - continue; - } - - $attachment = wp_get_attachment_image_src( $attachment_id, 'full' ); - if ( ! is_array( $attachment ) ) { - continue; - } - - $images[] = array( - 'id' => (int) $attachment_id, - 'date_created' => wc_rest_prepare_date_response( $attachment_post->post_date, false ), - 'date_created_gmt' => wc_rest_prepare_date_response( strtotime( $attachment_post->post_date_gmt ) ), - 'date_modified' => wc_rest_prepare_date_response( $attachment_post->post_modified, false ), - 'date_modified_gmt' => wc_rest_prepare_date_response( strtotime( $attachment_post->post_modified_gmt ) ), - 'src' => current( $attachment ), - 'name' => get_the_title( $attachment_id ), - 'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ), - ); - } - - return $images; - } - - /** - * Make extra product orderby features supported by WooCommerce available to the WC API. - * This includes 'price', 'popularity', and 'rating'. - * - * @param WP_REST_Request $request Request data. - * @return array - */ - protected function prepare_objects_query( $request ) { - $args = WC_REST_CRUD_Controller::prepare_objects_query( $request ); - - // Set post_status. - $args['post_status'] = $request['status']; - - // Taxonomy query to filter products by type, category, - // tag, shipping class, and attribute. - $tax_query = array(); - - // Map between taxonomy name and arg's key. - $taxonomies = array( - 'product_cat' => 'category', - 'product_tag' => 'tag', - 'product_shipping_class' => 'shipping_class', - ); - - // Set tax_query for each passed arg. - foreach ( $taxonomies as $taxonomy => $key ) { - if ( ! empty( $request[ $key ] ) ) { - $tax_query[] = array( - 'taxonomy' => $taxonomy, - 'field' => 'term_id', - 'terms' => $request[ $key ], - ); - } - } - - // Filter product type by slug. - if ( ! empty( $request['type'] ) ) { - $tax_query[] = array( - 'taxonomy' => 'product_type', - 'field' => 'slug', - 'terms' => $request['type'], - ); - } - - // Filter by attribute and term. - if ( ! empty( $request['attribute'] ) && ! empty( $request['attribute_term'] ) ) { - if ( in_array( $request['attribute'], wc_get_attribute_taxonomy_names(), true ) ) { - $tax_query[] = array( - 'taxonomy' => $request['attribute'], - 'field' => 'term_id', - 'terms' => $request['attribute_term'], - ); - } - } - - // Build tax_query if taxonomies are set. - if ( ! empty( $tax_query ) ) { - if ( ! empty( $args['tax_query'] ) ) { - $args['tax_query'] = array_merge( $tax_query, $args['tax_query'] ); // WPCS: slow query ok. - } else { - $args['tax_query'] = $tax_query; // WPCS: slow query ok. - } - } - - // Filter featured. - if ( is_bool( $request['featured'] ) ) { - $args['tax_query'][] = array( - 'taxonomy' => 'product_visibility', - 'field' => 'name', - 'terms' => 'featured', - 'operator' => true === $request['featured'] ? 'IN' : 'NOT IN', - ); - } - - // Filter by sku. - if ( ! empty( $request['sku'] ) ) { - $skus = explode( ',', $request['sku'] ); - // Include the current string as a SKU too. - if ( 1 < count( $skus ) ) { - $skus[] = $request['sku']; - } - - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, array( - 'key' => '_sku', - 'value' => $skus, - 'compare' => 'IN', - ) - ); - } - - // Filter by tax class. - if ( ! empty( $request['tax_class'] ) ) { - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, array( - 'key' => '_tax_class', - 'value' => 'standard' !== $request['tax_class'] ? $request['tax_class'] : '', - ) - ); - } - - // Price filter. - if ( ! empty( $request['min_price'] ) || ! empty( $request['max_price'] ) ) { - $args['meta_query'] = $this->add_meta_query( $args, wc_get_min_max_price_meta_query( $request ) ); // WPCS: slow query ok. - } - - // Filter product by stock_status. - if ( ! empty( $request['stock_status'] ) ) { - $args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok. - $args, array( - 'key' => '_stock_status', - 'value' => $request['stock_status'], - ) - ); - } - - // Filter by on sale products. - if ( is_bool( $request['on_sale'] ) ) { - $on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in'; - $on_sale_ids = wc_get_product_ids_on_sale(); - - // Use 0 when there's no on sale products to avoid return all products. - $on_sale_ids = empty( $on_sale_ids ) ? array( 0 ) : $on_sale_ids; - - $args[ $on_sale_key ] += $on_sale_ids; - } - - // Force the post_type argument, since it's not a user input variable. - if ( ! empty( $request['sku'] ) ) { - $args['post_type'] = array( 'product', 'product_variation' ); - } else { - $args['post_type'] = $this->post_type; - } - - $orderby = $request->get_param( 'orderby' ); - $order = $request->get_param( 'order' ); - - $ordering_args = WC()->query->get_catalog_ordering_args( $orderby, $order ); - $args['orderby'] = $ordering_args['orderby']; - $args['order'] = $ordering_args['order']; - if ( $ordering_args['meta_key'] ) { - $args['meta_key'] = $ordering_args['meta_key']; // WPCS: slow query ok. - } - - return $args; - } - - /** - * Set product images. - * - * @throws WC_REST_Exception REST API exceptions. - * @param WC_Product $product Product instance. - * @param array $images Images data. - * @return WC_Product - */ - protected function set_product_images( $product, $images ) { - $images = is_array( $images ) ? array_filter( $images ) : array(); - - if ( ! empty( $images ) ) { - $gallery = array(); - - foreach ( $images as $index => $image ) { - $attachment_id = isset( $image['id'] ) ? absint( $image['id'] ) : 0; - - if ( 0 === $attachment_id && isset( $image['src'] ) ) { - $upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) ); - - if ( is_wp_error( $upload ) ) { - if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $product->get_id(), $images ) ) { - throw new WC_REST_Exception( 'woocommerce_product_image_upload_error', $upload->get_error_message(), 400 ); - } else { - continue; - } - } - - $attachment_id = wc_rest_set_uploaded_image_as_attachment( $upload, $product->get_id() ); - } - - if ( ! wp_attachment_is_image( $attachment_id ) ) { - /* translators: %s: image ID */ - throw new WC_REST_Exception( 'woocommerce_product_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce-rest-api' ), $attachment_id ), 400 ); - } - - $featured_image = $product->get_image_id(); - - if ( 0 === $index ) { - $product->set_image_id( $attachment_id ); - } else { - $gallery[] = $attachment_id; - } - - // Set the image alt if present. - if ( ! empty( $image['alt'] ) ) { - update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) ); - } - - // Set the image name if present. - if ( ! empty( $image['name'] ) ) { - wp_update_post( - array( - 'ID' => $attachment_id, - 'post_title' => $image['name'], - ) - ); - } - } - - $product->set_gallery_image_ids( $gallery ); - } else { - $product->set_image_id( '' ); - $product->set_gallery_image_ids( array() ); - } - - return $product; - } - - /** - * Prepare a single product for create or update. - * - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - * @return WP_Error|WC_Data - */ - protected function prepare_object_for_database( $request, $creating = false ) { - $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - - // Type is the most important part here because we need to be using the correct class and methods. - if ( isset( $request['type'] ) ) { - $classname = WC_Product_Factory::get_classname_from_product_type( $request['type'] ); - - if ( ! class_exists( $classname ) ) { - $classname = 'WC_Product_Simple'; - } - - $product = new $classname( $id ); - } elseif ( isset( $request['id'] ) ) { - $product = wc_get_product( $id ); - } else { - $product = new WC_Product_Simple(); - } - - if ( 'variation' === $product->get_type() ) { - return new WP_Error( - "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce-rest-api' ), array( - 'status' => 404, - ) - ); - } - - // Post title. - if ( isset( $request['name'] ) ) { - $product->set_name( wp_filter_post_kses( $request['name'] ) ); - } - - // Post content. - if ( isset( $request['description'] ) ) { - $product->set_description( wp_filter_post_kses( $request['description'] ) ); - } - - // Post excerpt. - if ( isset( $request['short_description'] ) ) { - $product->set_short_description( wp_filter_post_kses( $request['short_description'] ) ); - } - - // Post status. - if ( isset( $request['status'] ) ) { - $product->set_status( get_post_status_object( $request['status'] ) ? $request['status'] : 'draft' ); - } - - // Post slug. - if ( isset( $request['slug'] ) ) { - $product->set_slug( $request['slug'] ); - } - - // Menu order. - if ( isset( $request['menu_order'] ) ) { - $product->set_menu_order( $request['menu_order'] ); - } - - // Comment status. - if ( isset( $request['reviews_allowed'] ) ) { - $product->set_reviews_allowed( $request['reviews_allowed'] ); - } - - // Virtual. - if ( isset( $request['virtual'] ) ) { - $product->set_virtual( $request['virtual'] ); - } - - // Tax status. - if ( isset( $request['tax_status'] ) ) { - $product->set_tax_status( $request['tax_status'] ); - } - - // Tax Class. - if ( isset( $request['tax_class'] ) ) { - $product->set_tax_class( $request['tax_class'] ); - } - - // Catalog Visibility. - if ( isset( $request['catalog_visibility'] ) ) { - $product->set_catalog_visibility( $request['catalog_visibility'] ); - } - - // Purchase Note. - if ( isset( $request['purchase_note'] ) ) { - $product->set_purchase_note( wp_kses_post( wp_unslash( $request['purchase_note'] ) ) ); - } - - // Featured Product. - if ( isset( $request['featured'] ) ) { - $product->set_featured( $request['featured'] ); - } - - // Shipping data. - $product = $this->save_product_shipping_data( $product, $request ); - - // SKU. - if ( isset( $request['sku'] ) ) { - $product->set_sku( wc_clean( $request['sku'] ) ); - } - - // Attributes. - if ( isset( $request['attributes'] ) ) { - $attributes = array(); - - foreach ( $request['attributes'] as $attribute ) { - $attribute_id = 0; - $attribute_name = ''; - - // Check ID for global attributes or name for product attributes. - if ( ! empty( $attribute['id'] ) ) { - $attribute_id = absint( $attribute['id'] ); - $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id ); - } elseif ( ! empty( $attribute['name'] ) ) { - $attribute_name = wc_clean( $attribute['name'] ); - } - - if ( ! $attribute_id && ! $attribute_name ) { - continue; - } - - if ( $attribute_id ) { - - if ( isset( $attribute['options'] ) ) { - $options = $attribute['options']; - - if ( ! is_array( $attribute['options'] ) ) { - // Text based attributes - Posted values are term names. - $options = explode( WC_DELIMITER, $options ); - } - - $values = array_map( 'wc_sanitize_term_text_based', $options ); - $values = array_filter( $values, 'strlen' ); - } else { - $values = array(); - } - - if ( ! empty( $values ) ) { - // Add attribute to array, but don't set values. - $attribute_object = new WC_Product_Attribute(); - $attribute_object->set_id( $attribute_id ); - $attribute_object->set_name( $attribute_name ); - $attribute_object->set_options( $values ); - $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' ); - $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 ); - $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 ); - $attributes[] = $attribute_object; - } - } elseif ( isset( $attribute['options'] ) ) { - // Custom attribute - Add attribute to array and set the values. - if ( is_array( $attribute['options'] ) ) { - $values = $attribute['options']; - } else { - $values = explode( WC_DELIMITER, $attribute['options'] ); - } - $attribute_object = new WC_Product_Attribute(); - $attribute_object->set_name( $attribute_name ); - $attribute_object->set_options( $values ); - $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' ); - $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 ); - $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 ); - $attributes[] = $attribute_object; - } - } - $product->set_attributes( $attributes ); - } - - // Sales and prices. - if ( in_array( $product->get_type(), array( 'variable', 'grouped' ), true ) ) { - $product->set_regular_price( '' ); - $product->set_sale_price( '' ); - $product->set_date_on_sale_to( '' ); - $product->set_date_on_sale_from( '' ); - $product->set_price( '' ); - } else { - // Regular Price. - if ( isset( $request['regular_price'] ) ) { - $product->set_regular_price( $request['regular_price'] ); - } - - // Sale Price. - if ( isset( $request['sale_price'] ) ) { - $product->set_sale_price( $request['sale_price'] ); - } - - if ( isset( $request['date_on_sale_from'] ) ) { - $product->set_date_on_sale_from( $request['date_on_sale_from'] ); - } - - if ( isset( $request['date_on_sale_from_gmt'] ) ) { - $product->set_date_on_sale_from( $request['date_on_sale_from_gmt'] ? strtotime( $request['date_on_sale_from_gmt'] ) : null ); - } - - if ( isset( $request['date_on_sale_to'] ) ) { - $product->set_date_on_sale_to( $request['date_on_sale_to'] ); - } - - if ( isset( $request['date_on_sale_to_gmt'] ) ) { - $product->set_date_on_sale_to( $request['date_on_sale_to_gmt'] ? strtotime( $request['date_on_sale_to_gmt'] ) : null ); - } - } - - // Product parent ID. - if ( isset( $request['parent_id'] ) ) { - $product->set_parent_id( $request['parent_id'] ); - } - - // Sold individually. - if ( isset( $request['sold_individually'] ) ) { - $product->set_sold_individually( $request['sold_individually'] ); - } - - // Stock status; stock_status has priority over in_stock. - if ( isset( $request['stock_status'] ) ) { - $stock_status = $request['stock_status']; - } else { - $stock_status = $product->get_stock_status(); - } - - // Stock data. - if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { - // Manage stock. - if ( isset( $request['manage_stock'] ) ) { - $product->set_manage_stock( $request['manage_stock'] ); - } - - // Backorders. - if ( isset( $request['backorders'] ) ) { - $product->set_backorders( $request['backorders'] ); - } - - if ( $product->is_type( 'grouped' ) ) { - $product->set_manage_stock( 'no' ); - $product->set_backorders( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } elseif ( $product->is_type( 'external' ) ) { - $product->set_manage_stock( 'no' ); - $product->set_backorders( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( 'instock' ); - } elseif ( $product->get_manage_stock() ) { - // Stock status is always determined by children so sync later. - if ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Stock quantity. - if ( isset( $request['stock_quantity'] ) ) { - $product->set_stock_quantity( wc_stock_amount( $request['stock_quantity'] ) ); - } elseif ( isset( $request['inventory_delta'] ) ) { - $stock_quantity = wc_stock_amount( $product->get_stock_quantity() ); - $stock_quantity += wc_stock_amount( $request['inventory_delta'] ); - $product->set_stock_quantity( wc_stock_amount( $stock_quantity ) ); - } - } else { - // Don't manage stock. - $product->set_manage_stock( 'no' ); - $product->set_stock_quantity( '' ); - $product->set_stock_status( $stock_status ); - } - } elseif ( ! $product->is_type( 'variable' ) ) { - $product->set_stock_status( $stock_status ); - } - - // Upsells. - if ( isset( $request['upsell_ids'] ) ) { - $upsells = array(); - $ids = $request['upsell_ids']; - - if ( ! empty( $ids ) ) { - foreach ( $ids as $id ) { - if ( $id && $id > 0 ) { - $upsells[] = $id; - } - } - } - - $product->set_upsell_ids( $upsells ); - } - - // Cross sells. - if ( isset( $request['cross_sell_ids'] ) ) { - $crosssells = array(); - $ids = $request['cross_sell_ids']; - - if ( ! empty( $ids ) ) { - foreach ( $ids as $id ) { - if ( $id && $id > 0 ) { - $crosssells[] = $id; - } - } - } - - $product->set_cross_sell_ids( $crosssells ); - } - - // Product categories. - if ( isset( $request['categories'] ) && is_array( $request['categories'] ) ) { - $product = $this->save_taxonomy_terms( $product, $request['categories'] ); - } - - // Product tags. - if ( isset( $request['tags'] ) && is_array( $request['tags'] ) ) { - $product = $this->save_taxonomy_terms( $product, $request['tags'], 'tag' ); - } - - // Downloadable. - if ( isset( $request['downloadable'] ) ) { - $product->set_downloadable( $request['downloadable'] ); - } - - // Downloadable options. - if ( $product->get_downloadable() ) { - - // Downloadable files. - if ( isset( $request['downloads'] ) && is_array( $request['downloads'] ) ) { - $product = $this->save_downloadable_files( $product, $request['downloads'] ); - } - - // Download limit. - if ( isset( $request['download_limit'] ) ) { - $product->set_download_limit( $request['download_limit'] ); - } - - // Download expiry. - if ( isset( $request['download_expiry'] ) ) { - $product->set_download_expiry( $request['download_expiry'] ); - } - } - - // Product url and button text for external products. - if ( $product->is_type( 'external' ) ) { - if ( isset( $request['external_url'] ) ) { - $product->set_product_url( $request['external_url'] ); - } - - if ( isset( $request['button_text'] ) ) { - $product->set_button_text( $request['button_text'] ); - } - } - - // Save default attributes for variable products. - if ( $product->is_type( 'variable' ) ) { - $product = $this->save_default_attributes( $product, $request ); - } - - // Set children for a grouped product. - if ( $product->is_type( 'grouped' ) && isset( $request['grouped_products'] ) ) { - $product->set_children( $request['grouped_products'] ); - } - - // Check for featured/gallery images, upload it and set it. - if ( isset( $request['images'] ) ) { - $product = $this->set_product_images( $product, $request['images'] ); - } - - // Allow set meta_data. - if ( is_array( $request['meta_data'] ) ) { - foreach ( $request['meta_data'] as $meta ) { - $product->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' ); - } - } - - if ( ! empty( $request['date_created'] ) ) { - $date = rest_parse_date( $request['date_created'] ); - - if ( $date ) { - $product->set_date_created( $date ); - } - } - - if ( ! empty( $request['date_created_gmt'] ) ) { - $date = rest_parse_date( $request['date_created_gmt'], true ); - - if ( $date ) { - $product->set_date_created( $date ); - } - } - - /** - * Filters an object before it is inserted via the REST API. - * - * The dynamic portion of the hook name, `$this->post_type`, - * refers to the object type slug. - * - * @param WC_Data $product Object object. - * @param WP_REST_Request $request Request object. - * @param bool $creating If is creating a new object. - */ - return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $product, $request, $creating ); - } - - /** - * Get the Product's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $weight_unit = get_option( 'woocommerce_weight_unit' ); - $dimension_unit = get_option( 'woocommerce_dimension_unit' ); - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => $this->post_type, - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'slug' => array( - 'description' => __( 'Product slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'permalink' => array( - 'description' => __( 'Product URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created' => array( - 'description' => __( "The date the product was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the product was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_modified' => array( - 'description' => __( "The date the product was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the product was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Product type.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'simple', - 'enum' => array_keys( wc_get_product_types() ), - 'context' => array( 'view', 'edit' ), - ), - 'status' => array( - 'description' => __( 'Product status (post status).', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'publish', - 'enum' => array_merge( array_keys( get_post_statuses() ), array( 'future' ) ), - 'context' => array( 'view', 'edit' ), - ), - 'featured' => array( - 'description' => __( 'Featured product.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'catalog_visibility' => array( - 'description' => __( 'Catalog visibility.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'visible', - 'enum' => array( 'visible', 'catalog', 'search', 'hidden' ), - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'Product description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'short_description' => array( - 'description' => __( 'Product short description.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sku' => array( - 'description' => __( 'Unique identifier.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'price' => array( - 'description' => __( 'Current product price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'regular_price' => array( - 'description' => __( 'Product regular price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sale_price' => array( - 'description' => __( 'Product sale price.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from' => array( - 'description' => __( "Start date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_from_gmt' => array( - 'description' => __( 'Start date of sale price, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to' => array( - 'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'date_on_sale_to_gmt' => array( - 'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - ), - 'price_html' => array( - 'description' => __( 'Price formatted in HTML.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'on_sale' => array( - 'description' => __( 'Shows if the product is on sale.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'purchasable' => array( - 'description' => __( 'Shows if the product can be bought.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'total_sales' => array( - 'description' => __( 'Amount of sales.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'virtual' => array( - 'description' => __( 'If the product is virtual.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloadable' => array( - 'description' => __( 'If the product is downloadable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'downloads' => array( - 'description' => __( 'List of downloadable files.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'File ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'File name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'file' => array( - 'description' => __( 'File URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'download_limit' => array( - 'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'download_expiry' => array( - 'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => -1, - 'context' => array( 'view', 'edit' ), - ), - 'external_url' => array( - 'description' => __( 'Product external URL. Only for external products.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'button_text' => array( - 'description' => __( 'Product external button text. Only for external products.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'tax_status' => array( - 'description' => __( 'Tax status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'taxable', - 'enum' => array( 'taxable', 'shipping', 'none' ), - 'context' => array( 'view', 'edit' ), - ), - 'tax_class' => array( - 'description' => __( 'Tax class.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'manage_stock' => array( - 'description' => __( 'Stock management at product level.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'stock_quantity' => array( - 'description' => __( 'Stock quantity.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'stock_status' => array( - 'description' => __( 'Controls the stock status of the product.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'instock', - 'enum' => array_keys( wc_get_product_stock_status_options() ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders' => array( - 'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'default' => 'no', - 'enum' => array( 'no', 'notify', 'yes' ), - 'context' => array( 'view', 'edit' ), - ), - 'backorders_allowed' => array( - 'description' => __( 'Shows if backorders are allowed.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'backordered' => array( - 'description' => __( 'Shows if the product is on backordered.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'sold_individually' => array( - 'description' => __( 'Allow one item to be bought in a single order.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'weight' => array( - /* translators: %s: weight unit */ - 'description' => sprintf( __( 'Product weight (%s).', 'woocommerce-rest-api' ), $weight_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'dimensions' => array( - 'description' => __( 'Product dimensions.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'properties' => array( - 'length' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product length (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'width' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product width (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'height' => array( - /* translators: %s: dimension unit */ - 'description' => sprintf( __( 'Product height (%s).', 'woocommerce-rest-api' ), $dimension_unit ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - 'shipping_required' => array( - 'description' => __( 'Shows if the product need to be shipped.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_taxable' => array( - 'description' => __( 'Shows whether or not the product shipping is taxable.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'shipping_class' => array( - 'description' => __( 'Shipping class slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'shipping_class_id' => array( - 'description' => __( 'Shipping class ID.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'reviews_allowed' => array( - 'description' => __( 'Allow reviews.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => true, - 'context' => array( 'view', 'edit' ), - ), - 'average_rating' => array( - 'description' => __( 'Reviews average rating.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'rating_count' => array( - 'description' => __( 'Amount of reviews that the product have.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'related_ids' => array( - 'description' => __( 'List of related products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'upsell_ids' => array( - 'description' => __( 'List of up-sell products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'cross_sell_ids' => array( - 'description' => __( 'List of cross-sell products IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - ), - 'parent_id' => array( - 'description' => __( 'Product parent ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'purchase_note' => array( - 'description' => __( 'Optional note to send the customer after purchase.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'categories' => array( - 'description' => __( 'List of categories.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Category ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Category name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'slug' => array( - 'description' => __( 'Category slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'tags' => array( - 'description' => __( 'List of tags.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Tag ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Tag name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'slug' => array( - 'description' => __( 'Tag slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ), - ), - 'images' => array( - 'description' => __( 'List of images.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Image ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'date_created' => array( - 'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_created_gmt' => array( - 'description' => __( 'The date the image was created, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified' => array( - 'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'date_modified_gmt' => array( - 'description' => __( 'The date the image was last modified, as GMT.', 'woocommerce-rest-api' ), - 'type' => 'date-time', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'src' => array( - 'description' => __( 'Image URL.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'format' => 'uri', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Image name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'alt' => array( - 'description' => __( 'Image alternative text.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'attributes' => array( - 'description' => __( 'List of attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'position' => array( - 'description' => __( 'Attribute position.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'visible' => array( - 'description' => __( "Define if the attribute is visible on the \"Additional information\" tab in the product's page.", 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'variation' => array( - 'description' => __( 'Define if the attribute can be used as variation.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'context' => array( 'view', 'edit' ), - ), - 'options' => array( - 'description' => __( 'List of available term names of the attribute.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'string', - ), - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'default_attributes' => array( - 'description' => __( 'Defaults variation attributes.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Attribute ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'name' => array( - 'description' => __( 'Attribute name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'option' => array( - 'description' => __( 'Selected attribute term name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - 'variations' => array( - 'description' => __( 'List of variations IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'integer', - ), - 'readonly' => true, - ), - 'grouped_products' => array( - 'description' => __( 'List of grouped products ID.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'menu_order' => array( - 'description' => __( 'Menu order, used to custom sort products.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - ), - 'meta_data' => array( - 'description' => __( 'Meta data.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'context' => array( 'view', 'edit' ), - 'items' => array( - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'Meta ID.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'Meta key.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'value' => array( - 'description' => __( 'Meta value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - ), - ), - ), - ), - ); - return $this->add_additional_fields_schema( $schema ); - } - - /** - * Add new options for 'orderby' to the collection params. - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - $params['orderby']['enum'] = array_merge( $params['orderby']['enum'], array( 'price', 'popularity', 'rating' ) ); - - unset( $params['in_stock'] ); - $params['stock_status'] = array( - 'description' => __( 'Limit result set to products with specified stock status.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'enum' => array_keys( wc_get_product_stock_status_options() ), - 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } - - /** - * Get product data. - * - * @param WC_Product $product Product instance. - * @param string $context Request context. - * Options: 'view' and 'edit'. - * @return array - */ - protected function get_product_data( $product, $context = 'view' ) { - $data = parent::get_product_data( $product, $context ); - - // Replace in_stock with stock_status. - $pos = array_search( 'in_stock', array_keys( $data ), true ); - $array_section_1 = array_slice( $data, 0, $pos, true ); - $array_section_2 = array_slice( $data, $pos + 1, null, true ); - - return $array_section_1 + array( 'stock_status' => $product->get_stock_status( $context ) ) + $array_section_2; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-report-coupons-totals-controller.php b/src/Controllers/Version3/class-wc-rest-report-coupons-totals-controller.php deleted file mode 100644 index 85d4ae34795..00000000000 --- a/src/Controllers/Version3/class-wc-rest-report-coupons-totals-controller.php +++ /dev/null @@ -1,143 +0,0 @@ - $name ) { - $results = $wpdb->get_results( - $wpdb->prepare( " - SELECT count(meta_id) AS total - FROM $wpdb->postmeta - WHERE meta_key = 'discount_type' - AND meta_value = %s - ", $slug ) - ); - - $total = isset( $results[0] ) ? (int) $results[0]->total : 0; - - $data[] = array( - 'slug' => $slug, - 'name' => $name, - 'total' => $total, - ); - } - - set_transient( 'rest_api_coupons_type_count', $data, YEAR_IN_SECONDS ); - - return $data; - } - - /** - * Prepare a report object for serialization. - * - * @param stdClass $report Report data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $report, $request ) { - $data = array( - 'slug' => $report->slug, - 'name' => $report->name, - 'total' => $report->total, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - /** - * Filter a report returned from the API. - * - * Allows modification of the report data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $report The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report_coupons_count', $response, $report, $request ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'report_coupon_total', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Coupon type name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Amount of coupons.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-report-customers-totals-controller.php b/src/Controllers/Version3/class-wc-rest-report-customers-totals-controller.php deleted file mode 100644 index 38867bd7135..00000000000 --- a/src/Controllers/Version3/class-wc-rest-report-customers-totals-controller.php +++ /dev/null @@ -1,154 +0,0 @@ - $total ) { - if ( in_array( $role, array( 'administrator', 'shop_manager' ), true ) ) { - continue; - } - - $total_customers += (int) $total; - } - - $customers_query = new WP_User_Query( - array( - 'role__not_in' => array( 'administrator', 'shop_manager' ), - 'number' => 0, - 'fields' => 'ID', - 'count_total' => true, - 'meta_query' => array( // WPCS: slow query ok. - array( - 'key' => 'paying_customer', - 'value' => 1, - 'compare' => '=', - ), - ), - ) - ); - - $total_paying = (int) $customers_query->get_total(); - - $data = array( - array( - 'slug' => 'paying', - 'name' => __( 'Paying customer', 'woocommerce-rest-api' ), - 'total' => $total_paying, - ), - array( - 'slug' => 'non_paying', - 'name' => __( 'Non-paying customer', 'woocommerce-rest-api' ), - 'total' => $total_customers - $total_paying, - ), - ); - - return $data; - } - - /** - * Prepare a report object for serialization. - * - * @param stdClass $report Report data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $report, $request ) { - $data = array( - 'slug' => $report->slug, - 'name' => $report->name, - 'total' => $report->total, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - /** - * Filter a report returned from the API. - * - * Allows modification of the report data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $report The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report_customers_count', $response, $report, $request ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'report_customer_total', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Customer type name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Amount of customers.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-report-orders-totals-controller.php b/src/Controllers/Version3/class-wc-rest-report-orders-totals-controller.php deleted file mode 100644 index 4c7c9289806..00000000000 --- a/src/Controllers/Version3/class-wc-rest-report-orders-totals-controller.php +++ /dev/null @@ -1,127 +0,0 @@ - $name ) { - if ( ! isset( $totals->$slug ) ) { - continue; - } - - $data[] = array( - 'slug' => str_replace( 'wc-', '', $slug ), - 'name' => $name, - 'total' => (int) $totals->$slug, - ); - } - - return $data; - } - - /** - * Prepare a report object for serialization. - * - * @param stdClass $report Report data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $report, $request ) { - $data = array( - 'slug' => $report->slug, - 'name' => $report->name, - 'total' => $report->total, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - /** - * Filter a report returned from the API. - * - * Allows modification of the report data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $report The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report_orders_count', $response, $report, $request ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'report_order_total', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Order status name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Amount of orders.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-report-products-totals-controller.php b/src/Controllers/Version3/class-wc-rest-report-products-totals-controller.php deleted file mode 100644 index d855b6298b9..00000000000 --- a/src/Controllers/Version3/class-wc-rest-report-products-totals-controller.php +++ /dev/null @@ -1,133 +0,0 @@ - 'product_type', - 'hide_empty' => false, - ) - ); - $data = array(); - - foreach ( $terms as $product_type ) { - if ( ! isset( $types[ $product_type->name ] ) ) { - continue; - } - - $data[] = array( - 'slug' => $product_type->name, - 'name' => $types[ $product_type->name ], - 'total' => (int) $product_type->count, - ); - } - - return $data; - } - - /** - * Prepare a report object for serialization. - * - * @param stdClass $report Report data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $report, $request ) { - $data = array( - 'slug' => $report->slug, - 'name' => $report->name, - 'total' => $report->total, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - /** - * Filter a report returned from the API. - * - * Allows modification of the report data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $report The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report_products_count', $response, $report, $request ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'report_product_total', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Product type name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Amount of products.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-report-reviews-totals-controller.php b/src/Controllers/Version3/class-wc-rest-report-reviews-totals-controller.php deleted file mode 100644 index d585d586d27..00000000000 --- a/src/Controllers/Version3/class-wc-rest-report-reviews-totals-controller.php +++ /dev/null @@ -1,132 +0,0 @@ - true, - 'post_type' => 'product', - 'meta_key' => 'rating', // WPCS: slow query ok. - 'meta_value' => '', // WPCS: slow query ok. - ); - - for ( $i = 1; $i <= 5; $i++ ) { - $query_data['meta_value'] = $i; - - $data[] = array( - 'slug' => 'rated_' . $i . '_out_of_5', - /* translators: %s: average rating */ - 'name' => sprintf( __( 'Rated %s out of 5', 'woocommerce-rest-api' ), $i ), - 'total' => (int) get_comments( $query_data ), - ); - } - - return $data; - } - - /** - * Prepare a report object for serialization. - * - * @param stdClass $report Report data. - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response $response Response data. - */ - public function prepare_item_for_response( $report, $request ) { - $data = array( - 'slug' => $report->slug, - 'name' => $report->name, - 'total' => $report->total, - ); - - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - - // Wrap the data in a response object. - $response = rest_ensure_response( $data ); - - /** - * Filter a report returned from the API. - * - * Allows modification of the report data right before it is returned. - * - * @param WP_REST_Response $response The response object. - * @param object $report The original report object. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'woocommerce_rest_prepare_report_reviews_count', $response, $report, $request ); - } - - /** - * Get the Report's schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'report_review_total', - 'type' => 'object', - 'properties' => array( - 'slug' => array( - 'description' => __( 'An alphanumeric identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'name' => array( - 'description' => __( 'Review type name.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - 'total' => array( - 'description' => __( 'Amount of reviews.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-report-sales-controller.php b/src/Controllers/Version3/class-wc-rest-report-sales-controller.php deleted file mode 100644 index bde4bd0ae51..00000000000 --- a/src/Controllers/Version3/class-wc-rest-report-sales-controller.php +++ /dev/null @@ -1,27 +0,0 @@ - 'orders/totals', - 'description' => __( 'Orders totals.', 'woocommerce-rest-api' ), - ); - $reports[] = array( - 'slug' => 'products/totals', - 'description' => __( 'Products totals.', 'woocommerce-rest-api' ), - ); - $reports[] = array( - 'slug' => 'customers/totals', - 'description' => __( 'Customers totals.', 'woocommerce-rest-api' ), - ); - $reports[] = array( - 'slug' => 'coupons/totals', - 'description' => __( 'Coupons totals.', 'woocommerce-rest-api' ), - ); - $reports[] = array( - 'slug' => 'reviews/totals', - 'description' => __( 'Reviews totals.', 'woocommerce-rest-api' ), - ); - $reports[] = array( - 'slug' => 'categories/totals', - 'description' => __( 'Categories totals.', 'woocommerce-rest-api' ), - ); - $reports[] = array( - 'slug' => 'tags/totals', - 'description' => __( 'Tags totals.', 'woocommerce-rest-api' ), - ); - $reports[] = array( - 'slug' => 'attributes/totals', - 'description' => __( 'Attributes totals.', 'woocommerce-rest-api' ), - ); - - return $reports; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-setting-options-controller.php b/src/Controllers/Version3/class-wc-rest-setting-options-controller.php deleted file mode 100644 index b7255694912..00000000000 --- a/src/Controllers/Version3/class-wc-rest-setting-options-controller.php +++ /dev/null @@ -1,250 +0,0 @@ - 404 ) ); - } - - $settings = apply_filters( 'woocommerce_settings-' . $group_id, array() ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores - - if ( empty( $settings ) ) { - return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - $filtered_settings = array(); - foreach ( $settings as $setting ) { - $option_key = $setting['option_key']; - $setting = $this->filter_setting( $setting ); - $default = isset( $setting['default'] ) ? $setting['default'] : ''; - // Get the option value. - if ( is_array( $option_key ) ) { - $option = get_option( $option_key[0] ); - $setting['value'] = isset( $option[ $option_key[1] ] ) ? $option[ $option_key[1] ] : $default; - } else { - $admin_setting_value = WC_Admin_Settings::get_option( $option_key, $default ); - $setting['value'] = $admin_setting_value; - } - - if ( 'multi_select_countries' === $setting['type'] ) { - $setting['options'] = WC()->countries->get_countries(); - $setting['type'] = 'multiselect'; - } elseif ( 'single_select_country' === $setting['type'] ) { - $setting['type'] = 'select'; - $setting['options'] = $this->get_countries_and_states(); - } elseif ( 'single_select_page' === $setting['type'] ) { - $pages = get_pages( - array( - 'sort_column' => 'menu_order', - 'sort_order' => 'ASC', - 'hierarchical' => 0, - ) - ); - $options = array(); - foreach ( $pages as $page ) { - $options[ $page->ID ] = ! empty( $page->post_title ) ? $page->post_title : '#' . $page->ID; - } - $setting['type'] = 'select'; - $setting['options'] = $options; - } - - $filtered_settings[] = $setting; - } - - return $filtered_settings; - } - - /** - * Returns a list of countries and states for use in the base location setting. - * - * @since 3.0.7 - * @return array Array of states and countries. - */ - private function get_countries_and_states() { - $countries = WC()->countries->get_countries(); - if ( ! $countries ) { - return array(); - } - $output = array(); - foreach ( $countries as $key => $value ) { - $states = WC()->countries->get_states( $key ); - - if ( $states ) { - foreach ( $states as $state_key => $state_value ) { - $output[ $key . ':' . $state_key ] = $value . ' - ' . $state_value; - } - } else { - $output[ $key ] = $value; - } - } - return $output; - } - - /** - * Get the settings schema, conforming to JSON Schema. - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'setting', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier for the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'group_id' => array( - 'description' => __( 'An identifier for the group this setting belongs to.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_title', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'label' => array( - 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'description' => array( - 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'value' => array( - 'description' => __( 'Setting value.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - ), - 'default' => array( - 'description' => __( 'Default value for the setting.', 'woocommerce-rest-api' ), - 'type' => 'mixed', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'tip' => array( - 'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'placeholder' => array( - 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - 'type' => array( - 'description' => __( 'Type of setting.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - 'context' => array( 'view', 'edit' ), - 'enum' => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox' ), - 'readonly' => true, - ), - 'options' => array( - 'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'woocommerce-rest-api' ), - 'type' => 'object', - 'context' => array( 'view', 'edit' ), - 'readonly' => true, - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-settings-controller.php b/src/Controllers/Version3/class-wc-rest-settings-controller.php deleted file mode 100644 index 0762c090fd4..00000000000 --- a/src/Controllers/Version3/class-wc-rest-settings-controller.php +++ /dev/null @@ -1,112 +0,0 @@ -namespace, '/' . $this->rest_base . '/batch', array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'update_items_permissions_check' ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) ); - } - - /** - * Makes sure the current user has access to WRITE the settings APIs. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|bool - */ - public function update_items_permissions_check( $request ) { - if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Update a setting. - * - * @param WP_REST_Request $request Request data. - * @return WP_Error|WP_REST_Response - */ - public function update_item( $request ) { - $options_controller = new WC_REST_Setting_Options_Controller(); - $response = $options_controller->update_item( $request ); - - return $response; - } - - /** - * Get the groups schema, conforming to JSON Schema. - * - * @since 3.0.0 - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'setting_group', - 'type' => 'object', - 'properties' => array( - 'id' => array( - 'description' => __( 'A unique identifier that can be used to link settings together.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'label' => array( - 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'description' => array( - 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'parent_id' => array( - 'description' => __( 'ID of parent grouping.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - 'sub_groups' => array( - 'description' => __( 'IDs for settings sub groups.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'context' => array( 'view', 'edit' ), - ), - ), - ); - - return $this->add_additional_fields_schema( $schema ); - } -} diff --git a/src/Controllers/Version3/class-wc-rest-shipping-methods-controller.php b/src/Controllers/Version3/class-wc-rest-shipping-methods-controller.php deleted file mode 100644 index 297943ae544..00000000000 --- a/src/Controllers/Version3/class-wc-rest-shipping-methods-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/locations endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Shipping Zone Locations class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Shipping_Zone_Locations_V2_Controller - */ -class WC_REST_Shipping_Zone_Locations_Controller extends WC_REST_Shipping_Zone_Locations_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v3'; -} diff --git a/src/Controllers/Version3/class-wc-rest-shipping-zone-methods-controller.php b/src/Controllers/Version3/class-wc-rest-shipping-zone-methods-controller.php deleted file mode 100644 index efb56f49afd..00000000000 --- a/src/Controllers/Version3/class-wc-rest-shipping-zone-methods-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -/methods endpoint. - * - * @package Automattic/WooCommerce/RestApi - * @since 3.0.0 - */ - -defined( 'ABSPATH' ) || exit; - -/** - * REST API Shipping Zone Methods class. - * - * @package Automattic/WooCommerce/RestApi - * @extends WC_REST_Shipping_Zone_Methods_V2_Controller - */ -class WC_REST_Shipping_Zone_Methods_Controller extends WC_REST_Shipping_Zone_Methods_V2_Controller { - - /** - * Endpoint namespace. - * - * @var string - */ - protected $namespace = 'wc/v3'; -} diff --git a/src/Controllers/Version3/class-wc-rest-shipping-zones-controller-base.php b/src/Controllers/Version3/class-wc-rest-shipping-zones-controller-base.php deleted file mode 100644 index 250269663d0..00000000000 --- a/src/Controllers/Version3/class-wc-rest-shipping-zones-controller-base.php +++ /dev/null @@ -1,125 +0,0 @@ - 404 ) ); - } - - return $zone; - } - - /** - * Check whether a given request has permission to read Shipping Zones. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - if ( ! wc_shipping_enabled() ) { - return new WP_Error( 'rest_no_route', __( 'Shipping is disabled.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to create Shipping Zones. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - if ( ! wc_shipping_enabled() ) { - return new WP_Error( 'rest_no_route', __( 'Shipping is disabled.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check whether a given request has permission to edit Shipping Zones. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_items_permissions_check( $request ) { - if ( ! wc_shipping_enabled() ) { - return new WP_Error( 'rest_no_route', __( 'Shipping is disabled.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check whether a given request has permission to delete Shipping Zones. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_items_permissions_check( $request ) { - if ( ! wc_shipping_enabled() ) { - return new WP_Error( 'rest_no_route', __( 'Shipping is disabled.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - if ( ! wc_rest_check_manager_permissions( 'settings', 'delete' ) ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - -} diff --git a/src/Controllers/Version3/class-wc-rest-shipping-zones-controller.php b/src/Controllers/Version3/class-wc-rest-shipping-zones-controller.php deleted file mode 100644 index 881d18dc3c1..00000000000 --- a/src/Controllers/Version3/class-wc-rest-shipping-zones-controller.php +++ /dev/null @@ -1,27 +0,0 @@ -namespace, - '/' . $this->rest_base, - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => array_merge( - $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - array( - 'name' => array( - 'type' => 'string', - 'description' => __( 'Name for the resource.', 'woocommerce-rest-api' ), - 'required' => true, - ), - ) - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/(?P[\d]+)', - array( - 'args' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ), - 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'view' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'type' => 'boolean', - 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ), - ), - ), - ), - 'schema' => array( $this, 'get_public_item_schema' ), - ) - ); - - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/batch', - array( - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'batch_items' ), - 'permission_callback' => array( $this, 'batch_items_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), - ), - 'schema' => array( $this, 'get_public_batch_schema' ), - ) - ); - } - - /** - * Check if a given request has access to read the terms. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - $permissions = $this->check_permissions( $request, 'read' ); - if ( is_wp_error( $permissions ) ) { - return $permissions; - } - - if ( ! $permissions ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to create a term. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - $permissions = $this->check_permissions( $request, 'create' ); - if ( is_wp_error( $permissions ) ) { - return $permissions; - } - - if ( ! $permissions ) { - return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to read a term. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - $permissions = $this->check_permissions( $request, 'read' ); - if ( is_wp_error( $permissions ) ) { - return $permissions; - } - - if ( ! $permissions ) { - return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to update a term. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - $permissions = $this->check_permissions( $request, 'edit' ); - if ( is_wp_error( $permissions ) ) { - return $permissions; - } - - if ( ! $permissions ) { - return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access to delete a term. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - $permissions = $this->check_permissions( $request, 'delete' ); - if ( is_wp_error( $permissions ) ) { - return $permissions; - } - - if ( ! $permissions ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check if a given request has access batch create, update and delete items. - * - * @param WP_REST_Request $request Full details about the request. - * @return boolean|WP_Error - */ - public function batch_items_permissions_check( $request ) { - $permissions = $this->check_permissions( $request, 'batch' ); - if ( is_wp_error( $permissions ) ) { - return $permissions; - } - - if ( ! $permissions ) { - return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce-rest-api' ), array( 'status' => rest_authorization_required_code() ) ); - } - - return true; - } - - /** - * Check permissions. - * - * @param WP_REST_Request $request Full details about the request. - * @param string $context Request context. - * @return bool|WP_Error - */ - protected function check_permissions( $request, $context = 'read' ) { - // Get taxonomy. - $taxonomy = $this->get_taxonomy( $request ); - if ( ! $taxonomy || ! taxonomy_exists( $taxonomy ) ) { - return new WP_Error( 'woocommerce_rest_taxonomy_invalid', __( 'Taxonomy does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - // Check permissions for a single term. - $id = intval( $request['id'] ); - if ( $id ) { - $term = get_term( $id, $taxonomy ); - - if ( is_wp_error( $term ) || ! $term || $term->taxonomy !== $taxonomy ) { - return new WP_Error( 'woocommerce_rest_term_invalid', __( 'Resource does not exist.', 'woocommerce-rest-api' ), array( 'status' => 404 ) ); - } - - return wc_rest_check_product_term_permissions( $taxonomy, $context, $term->term_id ); - } - - return wc_rest_check_product_term_permissions( $taxonomy, $context ); - } - - /** - * Get terms associated with a taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function get_items( $request ) { - $taxonomy = $this->get_taxonomy( $request ); - $prepared_args = array( - 'exclude' => $request['exclude'], - 'include' => $request['include'], - 'order' => $request['order'], - 'orderby' => $request['orderby'], - 'product' => $request['product'], - 'hide_empty' => $request['hide_empty'], - 'number' => $request['per_page'], - 'search' => $request['search'], - 'slug' => $request['slug'], - ); - - if ( ! empty( $request['offset'] ) ) { - $prepared_args['offset'] = $request['offset']; - } else { - $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; - } - - $taxonomy_obj = get_taxonomy( $taxonomy ); - - if ( $taxonomy_obj->hierarchical && isset( $request['parent'] ) ) { - if ( 0 === $request['parent'] ) { - // Only query top-level terms. - $prepared_args['parent'] = 0; - } else { - if ( $request['parent'] ) { - $prepared_args['parent'] = $request['parent']; - } - } - } - - /** - * Filter the query arguments, before passing them to `get_terms()`. - * - * Enables adding extra arguments or setting defaults for a terms - * collection request. - * - * @see https://developer.wordpress.org/reference/functions/get_terms/ - * - * @param array $prepared_args Array of arguments to be - * passed to get_terms. - * @param WP_REST_Request $request The current request. - */ - $prepared_args = apply_filters( "woocommerce_rest_{$taxonomy}_query", $prepared_args, $request ); - - if ( ! empty( $prepared_args['product'] ) ) { - $query_result = $this->get_terms_for_product( $prepared_args, $request ); - $total_terms = $this->total_terms; - } else { - $query_result = get_terms( $taxonomy, $prepared_args ); - - $count_args = $prepared_args; - unset( $count_args['number'] ); - unset( $count_args['offset'] ); - $total_terms = wp_count_terms( $taxonomy, $count_args ); - - // Ensure we don't return results when offset is out of bounds. - // See https://core.trac.wordpress.org/ticket/35935. - if ( $prepared_args['offset'] && $prepared_args['offset'] >= $total_terms ) { - $query_result = array(); - } - - // wp_count_terms can return a falsy value when the term has no children. - if ( ! $total_terms ) { - $total_terms = 0; - } - } - $response = array(); - foreach ( $query_result as $term ) { - $data = $this->prepare_item_for_response( $term, $request ); - $response[] = $this->prepare_response_for_collection( $data ); - } - - $response = rest_ensure_response( $response ); - - // Store pagination values for headers then unset for count query. - $per_page = (int) $prepared_args['number']; - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); - - $response->header( 'X-WP-Total', (int) $total_terms ); - $max_pages = ceil( $total_terms / $per_page ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - - $base = str_replace( '(?P[\d]+)', $request['attribute_id'], $this->rest_base ); - $base = add_query_arg( $request->get_query_params(), rest_url( '/' . $this->namespace . '/' . $base ) ); - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } - - return $response; - } - - /** - * Create a single term for a taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function create_item( $request ) { - $taxonomy = $this->get_taxonomy( $request ); - $name = $request['name']; - $args = array(); - $schema = $this->get_item_schema(); - - if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) { - $args['description'] = $request['description']; - } - if ( isset( $request['slug'] ) ) { - $args['slug'] = $request['slug']; - } - if ( isset( $request['parent'] ) ) { - if ( ! is_taxonomy_hierarchical( $taxonomy ) ) { - return new WP_Error( 'woocommerce_rest_taxonomy_not_hierarchical', __( 'Can not set resource parent, taxonomy is not hierarchical.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - $args['parent'] = $request['parent']; - } - - $term = wp_insert_term( $name, $taxonomy, $args ); - if ( is_wp_error( $term ) ) { - $error_data = array( 'status' => 400 ); - - // If we're going to inform the client that the term exists, - // give them the identifier they can actually use. - $term_id = $term->get_error_data( 'term_exists' ); - if ( $term_id ) { - $error_data['resource_id'] = $term_id; - } - - return new WP_Error( $term->get_error_code(), $term->get_error_message(), $error_data ); - } - - $term = get_term( $term['term_id'], $taxonomy ); - - $this->update_additional_fields_for_object( $term, $request ); - - // Add term data. - $meta_fields = $this->update_term_meta_fields( $term, $request ); - if ( is_wp_error( $meta_fields ) ) { - wp_delete_term( $term->term_id, $taxonomy ); - - return $meta_fields; - } - - /** - * Fires after a single term is created or updated via the REST API. - * - * @param WP_Term $term Inserted Term object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating term, false when updating. - */ - do_action( "woocommerce_rest_insert_{$taxonomy}", $term, $request, true ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $term, $request ); - $response = rest_ensure_response( $response ); - $response->set_status( 201 ); - - $base = '/' . $this->namespace . '/' . $this->rest_base; - if ( ! empty( $request['attribute_id'] ) ) { - $base = str_replace( '(?P[\d]+)', (int) $request['attribute_id'], $base ); - } - - $response->header( 'Location', rest_url( $base . '/' . $term->term_id ) ); - - return $response; - } - - /** - * Get a single term from a taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function get_item( $request ) { - $taxonomy = $this->get_taxonomy( $request ); - $term = get_term( (int) $request['id'], $taxonomy ); - - if ( is_wp_error( $term ) ) { - return $term; - } - - $response = $this->prepare_item_for_response( $term, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Update a single term from a taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Request|WP_Error - */ - public function update_item( $request ) { - $taxonomy = $this->get_taxonomy( $request ); - $term = get_term( (int) $request['id'], $taxonomy ); - $schema = $this->get_item_schema(); - $prepared_args = array(); - - if ( isset( $request['name'] ) ) { - $prepared_args['name'] = $request['name']; - } - if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) { - $prepared_args['description'] = $request['description']; - } - if ( isset( $request['slug'] ) ) { - $prepared_args['slug'] = $request['slug']; - } - if ( isset( $request['parent'] ) ) { - if ( ! is_taxonomy_hierarchical( $taxonomy ) ) { - return new WP_Error( 'woocommerce_rest_taxonomy_not_hierarchical', __( 'Can not set resource parent, taxonomy is not hierarchical.', 'woocommerce-rest-api' ), array( 'status' => 400 ) ); - } - $prepared_args['parent'] = $request['parent']; - } - - // Only update the term if we haz something to update. - if ( ! empty( $prepared_args ) ) { - $update = wp_update_term( $term->term_id, $term->taxonomy, $prepared_args ); - if ( is_wp_error( $update ) ) { - return $update; - } - } - - $term = get_term( (int) $request['id'], $taxonomy ); - - $this->update_additional_fields_for_object( $term, $request ); - - // Update term data. - $meta_fields = $this->update_term_meta_fields( $term, $request ); - if ( is_wp_error( $meta_fields ) ) { - return $meta_fields; - } - - /** - * Fires after a single term is created or updated via the REST API. - * - * @param WP_Term $term Inserted Term object. - * @param WP_REST_Request $request Request object. - * @param boolean $creating True when creating term, false when updating. - */ - do_action( "woocommerce_rest_insert_{$taxonomy}", $term, $request, false ); - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $term, $request ); - return rest_ensure_response( $response ); - } - - /** - * Delete a single term from a taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error - */ - public function delete_item( $request ) { - $taxonomy = $this->get_taxonomy( $request ); - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out. - if ( ! $force ) { - return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Resource does not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) ); - } - - $term = get_term( (int) $request['id'], $taxonomy ); - // Get default category id. - $default_category_id = absint( get_option( 'default_product_cat', 0 ) ); - - // Prevent deleting the default product category. - if ( $default_category_id === (int) $request['id'] ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Default product category cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - $request->set_param( 'context', 'edit' ); - $response = $this->prepare_item_for_response( $term, $request ); - - $retval = wp_delete_term( $term->term_id, $term->taxonomy ); - if ( ! $retval ) { - return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a single term is deleted via the REST API. - * - * @param WP_Term $term The deleted term. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( "woocommerce_rest_delete_{$taxonomy}", $term, $response, $request ); - - return $response; - } - - /** - * Prepare links for the request. - * - * @param object $term Term object. - * @param WP_REST_Request $request Full details about the request. - * @return array Links for the given term. - */ - protected function prepare_links( $term, $request ) { - $base = '/' . $this->namespace . '/' . $this->rest_base; - - if ( ! empty( $request['attribute_id'] ) ) { - $base = str_replace( '(?P[\d]+)', (int) $request['attribute_id'], $base ); - } - - $links = array( - 'self' => array( - 'href' => rest_url( trailingslashit( $base ) . $term->term_id ), - ), - 'collection' => array( - 'href' => rest_url( $base ), - ), - ); - - if ( $term->parent ) { - $parent_term = get_term( (int) $term->parent, $term->taxonomy ); - if ( $parent_term ) { - $links['up'] = array( - 'href' => rest_url( trailingslashit( $base ) . $parent_term->term_id ), - ); - } - } - - return $links; - } - - /** - * Update term meta fields. - * - * @param WP_Term $term Term object. - * @param WP_REST_Request $request Full details about the request. - * @return bool|WP_Error - */ - protected function update_term_meta_fields( $term, $request ) { - return true; - } - - /** - * Get the terms attached to a product. - * - * This is an alternative to `get_terms()` that uses `get_the_terms()` - * instead, which hits the object cache. There are a few things not - * supported, notably `include`, `exclude`. In `self::get_items()` these - * are instead treated as a full query. - * - * @param array $prepared_args Arguments for `get_terms()`. - * @param WP_REST_Request $request Full details about the request. - * @return array List of term objects. (Total count in `$this->total_terms`). - */ - protected function get_terms_for_product( $prepared_args, $request ) { - $taxonomy = $this->get_taxonomy( $request ); - - $query_result = get_the_terms( $prepared_args['product'], $taxonomy ); - if ( empty( $query_result ) ) { - $this->total_terms = 0; - return array(); - } - - // get_items() verifies that we don't have `include` set, and default. - // ordering is by `name`. - if ( ! in_array( $prepared_args['orderby'], array( 'name', 'none', 'include' ), true ) ) { - switch ( $prepared_args['orderby'] ) { - case 'id': - $this->sort_column = 'term_id'; - break; - case 'slug': - case 'term_group': - case 'description': - case 'count': - $this->sort_column = $prepared_args['orderby']; - break; - } - usort( $query_result, array( $this, 'compare_terms' ) ); - } - if ( strtolower( $prepared_args['order'] ) !== 'asc' ) { - $query_result = array_reverse( $query_result ); - } - - // Pagination. - $this->total_terms = count( $query_result ); - $query_result = array_slice( $query_result, $prepared_args['offset'], $prepared_args['number'] ); - - return $query_result; - } - - /** - * Comparison function for sorting terms by a column. - * - * Uses `$this->sort_column` to determine field to sort by. - * - * @param stdClass $left Term object. - * @param stdClass $right Term object. - * @return int <0 if left is higher "priority" than right, 0 if equal, >0 if right is higher "priority" than left. - */ - protected function compare_terms( $left, $right ) { - $col = $this->sort_column; - $left_val = $left->$col; - $right_val = $right->$col; - - if ( is_int( $left_val ) && is_int( $right_val ) ) { - return $left_val - $right_val; - } - - return strcmp( $left_val, $right_val ); - } - - /** - * Get the query params for collections - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - - if ( '' !== $this->taxonomy && taxonomy_exists( $this->taxonomy ) ) { - $taxonomy = get_taxonomy( $this->taxonomy ); - } else { - $taxonomy = new stdClass(); - $taxonomy->hierarchical = true; - } - - $params['context']['default'] = 'view'; - - $params['exclude'] = array( - 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - $params['include'] = array( - 'description' => __( 'Limit result set to specific ids.', 'woocommerce-rest-api' ), - 'type' => 'array', - 'items' => array( - 'type' => 'integer', - ), - 'default' => array(), - 'sanitize_callback' => 'wp_parse_id_list', - ); - if ( ! $taxonomy->hierarchical ) { - $params['offset'] = array( - 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - } - $params['order'] = array( - 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_key', - 'default' => 'asc', - 'enum' => array( - 'asc', - 'desc', - ), - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['orderby'] = array( - 'description' => __( 'Sort collection by resource attribute.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'sanitize_callback' => 'sanitize_key', - 'default' => 'name', - 'enum' => array( - 'id', - 'include', - 'name', - 'slug', - 'term_group', - 'description', - 'count', - ), - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['hide_empty'] = array( - 'description' => __( 'Whether to hide resources not assigned to any products.', 'woocommerce-rest-api' ), - 'type' => 'boolean', - 'default' => false, - 'validate_callback' => 'rest_validate_request_arg', - ); - if ( $taxonomy->hierarchical ) { - $params['parent'] = array( - 'description' => __( 'Limit result set to resources assigned to a specific parent.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'sanitize_callback' => 'absint', - 'validate_callback' => 'rest_validate_request_arg', - ); - } - $params['product'] = array( - 'description' => __( 'Limit result set to resources assigned to a specific product.', 'woocommerce-rest-api' ), - 'type' => 'integer', - 'default' => null, - 'validate_callback' => 'rest_validate_request_arg', - ); - $params['slug'] = array( - 'description' => __( 'Limit result set to resources with a specific slug.', 'woocommerce-rest-api' ), - 'type' => 'string', - 'validate_callback' => 'rest_validate_request_arg', - ); - - return $params; - } - - /** - * Get taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return int|WP_Error - */ - protected function get_taxonomy( $request ) { - // Check if taxonomy is defined. - // Prevents check for attribute taxonomy more than one time for each query. - if ( '' !== $this->taxonomy ) { - return $this->taxonomy; - } - - if ( ! empty( $request['attribute_id'] ) ) { - $taxonomy = wc_attribute_taxonomy_name_by_id( (int) $request['attribute_id'] ); - - $this->taxonomy = $taxonomy; - } - - return $this->taxonomy; - } -} diff --git a/src/Controllers/Version3/class-wc-rest-webhooks-controller.php b/src/Controllers/Version3/class-wc-rest-webhooks-controller.php deleted file mode 100644 index 7b2817290fa..00000000000 --- a/src/Controllers/Version3/class-wc-rest-webhooks-controller.php +++ /dev/null @@ -1,37 +0,0 @@ -init(); - } - - /** - * Return the version of the package. - * - * @return string - */ - public static function get_version() { - return self::VERSION; - } - - /** - * Return the path to the package. - * - * @return string - */ - public static function get_path() { - return dirname( __DIR__ ); - } -} diff --git a/src/Server.php b/src/Server.php deleted file mode 100644 index 1c589c0da75..00000000000 --- a/src/Server.php +++ /dev/null @@ -1,181 +0,0 @@ -get_rest_namespaces() as $namespace => $controllers ) { - foreach ( $controllers as $controller_name => $controller_class ) { - $this->controllers[ $namespace ][ $controller_name ] = new $controller_class(); - $this->controllers[ $namespace ][ $controller_name ]->register_routes(); - } - } - } - - /** - * Get API namespaces - new namespaces should be registered here. - * - * @return array List of Namespaces and Main controller classes. - */ - protected function get_rest_namespaces() { - return apply_filters( - 'woocommerce_rest_api_get_rest_namespaces', - [ - 'wc/v1' => $this->get_v1_controllers(), - 'wc/v2' => $this->get_v2_controllers(), - 'wc/v3' => $this->get_v3_controllers(), - ] - ); - } - - /** - * List of controllers in the wc/v1 namespace. - * - * @return array - */ - protected function get_v1_controllers() { - return [ - 'coupons' => 'WC_REST_Coupons_V1_Controller', - 'customer-downloads' => 'WC_REST_Customer_Downloads_V1_Controller', - 'customers' => 'WC_REST_Customers_V1_Controller', - 'order-notes' => 'WC_REST_Order_Notes_V1_Controller', - 'order-refunds' => 'WC_REST_Order_Refunds_V1_Controller', - 'orders' => 'WC_REST_Orders_V1_Controller', - 'product-attribute-terms' => 'WC_REST_Product_Attribute_Terms_V1_Controller', - 'product-attributes' => 'WC_REST_Product_Attributes_V1_Controller', - 'product-categories' => 'WC_REST_Product_Categories_V1_Controller', - 'product-reviews' => 'WC_REST_Product_Reviews_V1_Controller', - 'product-shipping-classes' => 'WC_REST_Product_Shipping_Classes_V1_Controller', - 'product-tags' => 'WC_REST_Product_Tags_V1_Controller', - 'products' => 'WC_REST_Products_V1_Controller', - 'reports-sales' => 'WC_REST_Report_Sales_V1_Controller', - 'reports-top-sellers' => 'WC_REST_Report_Top_Sellers_V1_Controller', - 'reports' => 'WC_REST_Reports_V1_Controller', - 'tax-classes' => 'WC_REST_Tax_Classes_V1_Controller', - 'taxes' => 'WC_REST_Taxes_V1_Controller', - 'webhooks' => 'WC_REST_Webhooks_V1_Controller', - 'webhook-deliveries' => 'WC_REST_Webhook_Deliveries_V1_Controller', - ]; - } - - /** - * List of controllers in the wc/v2 namespace. - * - * @return array - */ - protected function get_v2_controllers() { - return [ - 'coupons' => 'WC_REST_Coupons_V2_Controller', - 'customer-downloads' => 'WC_REST_Customer_Downloads_V2_Controller', - 'customers' => 'WC_REST_Customers_V2_Controller', - 'network-orders' => 'WC_REST_Network_Orders_V2_Controller', - 'order-notes' => 'WC_REST_Order_Notes_V2_Controller', - 'order-refunds' => 'WC_REST_Order_Refunds_V2_Controller', - 'orders' => 'WC_REST_Orders_V2_Controller', - 'product-attribute-terms' => 'WC_REST_Product_Attribute_Terms_V2_Controller', - 'product-attributes' => 'WC_REST_Product_Attributes_V2_Controller', - 'product-categories' => 'WC_REST_Product_Categories_V2_Controller', - 'product-reviews' => 'WC_REST_Product_Reviews_V2_Controller', - 'product-shipping-classes' => 'WC_REST_Product_Shipping_Classes_V2_Controller', - 'product-tags' => 'WC_REST_Product_Tags_V2_Controller', - 'products' => 'WC_REST_Products_V2_Controller', - 'product-variations' => 'WC_REST_Product_Variations_V2_Controller', - 'reports-sales' => 'WC_REST_Report_Sales_V2_Controller', - 'reports-top-sellers' => 'WC_REST_Report_Top_Sellers_V2_Controller', - 'reports' => 'WC_REST_Reports_V2_Controller', - 'settings' => 'WC_REST_Settings_V2_Controller', - 'settings-options' => 'WC_REST_Setting_Options_V2_Controller', - 'shipping-zones' => 'WC_REST_Shipping_Zones_V2_Controller', - 'shipping-zone-locations' => 'WC_REST_Shipping_Zone_Locations_V2_Controller', - 'shipping-zone-methods' => 'WC_REST_Shipping_Zone_Methods_V2_Controller', - 'tax-classes' => 'WC_REST_Tax_Classes_V2_Controller', - 'taxes' => 'WC_REST_Taxes_V2_Controller', - 'webhooks' => 'WC_REST_Webhooks_V2_Controller', - 'webhook-deliveries' => 'WC_REST_Webhook_Deliveries_V2_Controller', - 'system-status' => 'WC_REST_System_Status_V2_Controller', - 'system-status-tools' => 'WC_REST_System_Status_Tools_V2_Controller', - 'shipping-methods' => 'WC_REST_Shipping_Methods_V2_Controller', - 'payment-gateways' => 'WC_REST_Payment_Gateways_V2_Controller', - ]; - } - - /** - * List of controllers in the wc/v3 namespace. - * - * @return array - */ - protected function get_v3_controllers() { - return [ - 'coupons' => 'WC_REST_Coupons_Controller', - 'customer-downloads' => 'WC_REST_Customer_Downloads_Controller', - 'customers' => 'WC_REST_Customers_Controller', - 'network-orders' => 'WC_REST_Network_Orders_Controller', - 'order-notes' => 'WC_REST_Order_Notes_Controller', - 'order-refunds' => 'WC_REST_Order_Refunds_Controller', - 'orders' => 'WC_REST_Orders_Controller', - 'product-attribute-terms' => 'WC_REST_Product_Attribute_Terms_Controller', - 'product-attributes' => 'WC_REST_Product_Attributes_Controller', - 'product-categories' => 'WC_REST_Product_Categories_Controller', - 'product-reviews' => 'WC_REST_Product_Reviews_Controller', - 'product-shipping-classes' => 'WC_REST_Product_Shipping_Classes_Controller', - 'product-tags' => 'WC_REST_Product_Tags_Controller', - 'products' => 'WC_REST_Products_Controller', - 'product-variations' => 'WC_REST_Product_Variations_Controller', - 'reports-sales' => 'WC_REST_Report_Sales_Controller', - 'reports-top-sellers' => 'WC_REST_Report_Top_Sellers_Controller', - 'reports-orders-totals' => 'WC_REST_Report_Orders_Totals_Controller', - 'reports-products-totals' => 'WC_REST_Report_Products_Totals_Controller', - 'reports-customers-totals' => 'WC_REST_Report_Customers_Totals_Controller', - 'reports-coupons-totals' => 'WC_REST_Report_Coupons_Totals_Controller', - 'reports-reviews-totals' => 'WC_REST_Report_Reviews_Totals_Controller', - 'reports' => 'WC_REST_Reports_Controller', - 'settings' => 'WC_REST_Settings_Controller', - 'settings-options' => 'WC_REST_Setting_Options_Controller', - 'shipping-zones' => 'WC_REST_Shipping_Zones_Controller', - 'shipping-zone-locations' => 'WC_REST_Shipping_Zone_Locations_Controller', - 'shipping-zone-methods' => 'WC_REST_Shipping_Zone_Methods_Controller', - 'tax-classes' => 'WC_REST_Tax_Classes_Controller', - 'taxes' => 'WC_REST_Taxes_Controller', - 'webhooks' => 'WC_REST_Webhooks_Controller', - 'system-status' => 'WC_REST_System_Status_Controller', - 'system-status-tools' => 'WC_REST_System_Status_Tools_Controller', - 'shipping-methods' => 'WC_REST_Shipping_Methods_Controller', - 'payment-gateways' => 'WC_REST_Payment_Gateways_Controller', - 'data' => 'WC_REST_Data_Controller', - 'data-continents' => 'WC_REST_Data_Continents_Controller', - 'data-countries' => 'WC_REST_Data_Countries_Controller', - 'data-currencies' => 'WC_REST_Data_Currencies_Controller', - ]; - } -} diff --git a/src/Utilities/ImageAttachment.php b/src/Utilities/ImageAttachment.php deleted file mode 100644 index 115aa7d0279..00000000000 --- a/src/Utilities/ImageAttachment.php +++ /dev/null @@ -1,93 +0,0 @@ -id = (int) $id; - $this->object_id = (int) $object_id; - } - - /** - * Upload an attachment file. - * - * @throws \WC_REST_Exception REST API exceptions. - * @param string $src URL to file. - */ - public function upload_image_from_src( $src ) { - $upload = wc_rest_upload_image_from_url( esc_url_raw( $src ) ); - - if ( is_wp_error( $upload ) ) { - if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $this->object_id, $images ) ) { - throw new \WC_REST_Exception( 'woocommerce_product_image_upload_error', $upload->get_error_message(), 400 ); - } else { - return; - } - } - - $this->id = wc_rest_set_uploaded_image_as_attachment( $upload, $this->object_id ); - - if ( ! wp_attachment_is_image( $this->id ) ) { - /* translators: %s: image ID */ - throw new \WC_REST_Exception( 'woocommerce_product_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce-rest-api' ), $this->id ), 400 ); - } - } - - /** - * Update attachment alt text. - * - * @param string $text Text to set. - */ - public function update_alt_text( $text ) { - if ( ! $this->id ) { - return; - } - update_post_meta( $this->id, '_wp_attachment_image_alt', wc_clean( $text ) ); - } - - /** - * Update attachment name. - * - * @param string $text Text to set. - */ - public function update_name( $text ) { - if ( ! $this->id ) { - return; - } - wp_update_post( - array( - 'ID' => $this->id, - 'post_title' => $text, - ) - ); - } -} diff --git a/src/Utilities/SingletonTrait.php b/src/Utilities/SingletonTrait.php deleted file mode 100644 index 37aef2e35c7..00000000000 --- a/src/Utilities/SingletonTrait.php +++ /dev/null @@ -1,49 +0,0 @@ -wp_tests_dir = getenv( 'WP_TESTS_DIR' ) ? getenv( 'WP_TESTS_DIR' ) : rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib'; - $this->tests_dir = dirname( __FILE__ ); - $this->plugin_dir = dirname( $this->tests_dir ); - - if ( file_exists( dirname( $this->plugin_dir ) . '/woocommerce/woocommerce.php' ) ) { - // From plugin directory. - $this->plugins_dir = dirname( $this->plugin_dir ); - } else { - // Travis. - $this->plugins_dir = getenv( 'WP_CORE_DIR' ) . '/wp-content/plugins'; - } - - $this->wc_tests_dir = $this->plugins_dir . '/woocommerce/tests'; - - $this->setup_hooks(); - $this->load_framework(); - } - - /** - * Get tests dir. - * - * @return string - */ - public function get_dir() { - return dirname( __FILE__ ); - } - - /** - * Setup hooks. - */ - protected function setup_hooks() { - // Give access to tests_add_filter() function. - require_once $this->wp_tests_dir . '/includes/functions.php'; - - \tests_add_filter( 'muplugins_loaded', function() { - require_once $this->plugins_dir . '/woocommerce/woocommerce.php'; - require_once $this->plugin_dir . '/woocommerce-rest-api.php'; - } ); - - \tests_add_filter( 'setup_theme', function() { - echo \esc_html( 'Installing WooCommerce...' . PHP_EOL ); - - define( 'WP_UNINSTALL_PLUGIN', true ); - define( 'WC_REMOVE_ALL_DATA', true ); - include $this->plugins_dir . '/woocommerce/uninstall.php'; - - \WC_Install::install(); - - $GLOBALS['wp_roles'] = null; // WPCS: override ok. - \wp_roles(); - } ); - } - - /** - * Load the testing framework. - */ - protected function load_framework() { - // Start up the WP testing environment. - require_once $this->wp_tests_dir . '/includes/bootstrap.php'; - - // WooCommerce Core Testing Framework. - require_once $this->wc_tests_dir . '/legacy/framework/class-wc-unit-test-factory.php'; - require_once $this->wc_tests_dir . '/legacy/framework/vendor/class-wp-test-spy-rest-server.php'; - require_once $this->wc_tests_dir . '/legacy/includes/wp-http-testcase.php'; - require_once $this->wc_tests_dir . '/legacy/framework/class-wc-unit-test-case.php'; - require_once $this->wc_tests_dir . '/legacy/framework/class-wc-rest-unit-test-case.php'; - - require_once $this->tests_dir . '/Helpers/AdminNotesHelper.php'; - require_once $this->tests_dir . '/Helpers/CouponHelper.php'; - require_once $this->tests_dir . '/Helpers/CustomerHelper.php'; - require_once $this->tests_dir . '/Helpers/OrderHelper.php'; - require_once $this->tests_dir . '/Helpers/ProductHelper.php'; - require_once $this->tests_dir . '/Helpers/ShippingHelper.php'; - require_once $this->tests_dir . '/Helpers/SettingsHelper.php'; - require_once $this->tests_dir . '/Helpers/QueueHelper.php'; - require_once $this->tests_dir . '/AbstractRestApiTest.php'; - } -} - -Bootstrap::instance()->init(); diff --git a/unit-tests/bin/install.sh b/unit-tests/bin/install.sh deleted file mode 100755 index 8ab83ff1a13..00000000000 --- a/unit-tests/bin/install.sh +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -lt 3 ]; then - echo "usage: $0 [db-host] [wp-version] [skip-database-creation]" - exit 1 -fi - -DB_NAME=$1 -DB_USER=$2 -DB_PASS=$3 -DB_HOST=${4-localhost} -WP_VERSION=${5-latest} -SKIP_DB_CREATE=${6-false} - -TMPDIR=${TMPDIR-/tmp} -TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//") -WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib} -WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/} - -# Error if WP < 5 -if [[ $WP_VERSION =~ ^([0-9]+)[0-9\.]+\-? ]]; then - if [ "5" -gt "${BASH_REMATCH[1]}" ]; then - echo "You must use WordPress 5.0 or greater." - exit 1 - fi -fi - -download() { - if [ `which curl` ]; then - curl -s "$1" > "$2"; - elif [ `which wget` ]; then - wget -nv -O "$2" "$1" - fi -} - -if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then - WP_TESTS_TAG="branches/$WP_VERSION" -elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then - if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then - # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x - WP_TESTS_TAG="tags/${WP_VERSION%??}" - else - WP_TESTS_TAG="tags/$WP_VERSION" - fi -elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then - WP_TESTS_TAG="trunk" -else - # http serves a single offer, whereas https serves multiple. we only want one - download http://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json - grep '[0-9]+\.[0-9]+(\.[0-9]+)?' $TMPDIR/wp-latest.json - LATEST_VERSION=$(grep -o '"version":"[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//') - if [[ -z "$LATEST_VERSION" ]]; then - echo "Latest WordPress version could not be found" - exit 1 - fi - WP_TESTS_TAG="tags/$LATEST_VERSION" -fi - -set -ex - -install_wp() { - - if [ -d $WP_CORE_DIR ]; then - return; - fi - - mkdir -p $WP_CORE_DIR - - if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then - mkdir -p $TMPDIR/wordpress-nightly - download https://wordpress.org/nightly-builds/wordpress-latest.zip $TMPDIR/wordpress-nightly/wordpress-nightly.zip - unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/ - mv $TMPDIR/wordpress-nightly/wordpress/* $WP_CORE_DIR - else - if [ $WP_VERSION == 'latest' ]; then - local ARCHIVE_NAME='latest' - elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then - # https serves multiple offers, whereas http serves single. - download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json - if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then - # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x - LATEST_VERSION=${WP_VERSION%??} - else - # otherwise, scan the releases and get the most up to date minor version of the major release - local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'` - LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1) - fi - if [[ -z "$LATEST_VERSION" ]]; then - local ARCHIVE_NAME="wordpress-$WP_VERSION" - else - local ARCHIVE_NAME="wordpress-$LATEST_VERSION" - fi - else - local ARCHIVE_NAME="wordpress-$WP_VERSION" - fi - download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz - tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR - fi - - download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php -} - -install_test_suite() { - # portable in-place argument for both GNU sed and Mac OSX sed - if [[ $(uname -s) == 'Darwin' ]]; then - local ioption='-i .bak' - else - local ioption='-i' - fi - - # set up testing suite if it doesn't yet exist - if [ ! -d $WP_TESTS_DIR ]; then - # set up testing suite - mkdir -p $WP_TESTS_DIR - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data - fi - - if [ ! -f wp-tests-config.php ]; then - download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php - # remove all forward slashes in the end - WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php - fi - -} - -install_db() { - - if [ ${SKIP_DB_CREATE} = "true" ]; then - return 0 - fi - - # parse DB_HOST for port or socket references - local PARTS=(${DB_HOST//\:/ }) - local DB_HOSTNAME=${PARTS[0]}; - local DB_SOCK_OR_PORT=${PARTS[1]}; - local EXTRA="" - - if ! [ -z $DB_HOSTNAME ] ; then - if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then - EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" - elif ! [ -z $DB_SOCK_OR_PORT ] ; then - EXTRA=" --socket=$DB_SOCK_OR_PORT" - elif ! [ -z $DB_HOSTNAME ] ; then - EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" - fi - fi - - # create database - mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA -} - -install_deps() { - - # Script Variables - WP_SITE_URL="http://local.wordpress.test" - BRANCH=$TRAVIS_BRANCH - REPO=$TRAVIS_REPO_SLUG - WORKING_DIR="$PWD" - - if [ "$TRAVIS_PULL_REQUEST_BRANCH" != "" ]; then - BRANCH=$TRAVIS_PULL_REQUEST_BRANCH - REPO=$TRAVIS_PULL_REQUEST_SLUG - fi - - # Set up WordPress using wp-cli - mkdir -p "$WP_CORE_DIR" - cd "$WP_CORE_DIR" - - curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar - php wp-cli.phar core config --dbname=$DB_NAME --dbuser=$DB_USER --dbpass=$DB_PASS --dbhost=$DB_HOST --dbprefix=wptests_ - php wp-cli.phar core install --url="$WP_SITE_URL" --title="Example" --admin_user=admin --admin_password=password --admin_email=info@example.com --path=$WP_CORE_DIR --skip-email - - # Install WooCommerce and WooCommerce Admin - cd "wp-content/plugins/" - - git clone --depth 1 https://github.com/woocommerce/woocommerce.git - - cd "woocommerce" - composer install - - cd "$WP_CORE_DIR" - php wp-cli.phar plugin activate woocommerce - - if [ "$BRANCH" != "" ]; then - # Install the correct branch of the plugin, if running from Travis CI. - php wp-cli.phar plugin install https://github.com/$REPO/archive/$BRANCH.zip --activate - fi - - # Back to original dir - cd "$WORKING_DIR" -} - -install_wp -install_test_suite -install_db -install_deps diff --git a/unit-tests/bin/phpcs.sh b/unit-tests/bin/phpcs.sh deleted file mode 100755 index 5a2c8b48a05..00000000000 --- a/unit-tests/bin/phpcs.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -if [[ ${RUN_PHPCS} == 1 ]]; then - CHANGED_FILES=`git diff --name-only --diff-filter=ACMR $TRAVIS_COMMIT_RANGE | grep \\\\.php | awk '{print}' ORS=' '` - IGNORE="" - - if [ "$CHANGED_FILES" != "" ]; then - echo "Running Code Sniffer." - ./vendor/bin/phpcs --ignore=$IGNORE --encoding=utf-8 -s -n -p $CHANGED_FILES - fi -fi diff --git a/unit-tests/bin/phpunit.sh b/unit-tests/bin/phpunit.sh deleted file mode 100755 index 12e95676881..00000000000 --- a/unit-tests/bin/phpunit.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -$HOME/.composer/vendor/bin/phpunit -c phpunit.xml $@ \ No newline at end of file diff --git a/woocommerce-rest-api.php b/woocommerce-rest-api.php deleted file mode 100644 index 075a160c555..00000000000 --- a/woocommerce-rest-api.php +++ /dev/null @@ -1,68 +0,0 @@ - - - - composer install', - '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '' - ); - ?> - - -
- composer install', - '' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '' - ); - ?> -
' . esc_html( str_replace( ABSPATH, '', __DIR__ ) ) . '