├── assets
├── icon-128x128.png
└── icon-256x256.png
├── composer.json
├── README.md
├── .gitignore
├── phpunit.xml
├── api
├── class-wc-rest-dev-system-status-controller.php
├── class-wc-rest-dev-taxes-controller.php
├── class-wc-rest-dev-reports-controller.php
├── class-wc-rest-dev-webhooks-controller.php
├── class-wc-rest-dev-tax-classes-controller.php
├── class-wc-rest-dev-product-tags-controller.php
├── class-wc-rest-dev-shipping-methods-controller.php
├── class-wc-rest-dev-shipping-zones-controller.php
├── class-wc-rest-dev-product-reviews-controller.php
├── class-wc-rest-dev-system-status-tools-controller.php
├── class-wc-rest-dev-product-attributes-controller.php
├── class-wc-rest-dev-product-categories-controller.php
├── class-wc-rest-dev-customer-downloads-controller.php
├── class-wc-rest-dev-shipping-zone-methods-controller.php
├── class-wc-rest-dev-shipping-zone-locations-controller.php
├── class-wc-rest-dev-product-shipping-classes-controller.php
├── class-wc-rest-dev-product-attribute-terms-controller.php
├── class-wc-rest-dev-report-sales-controller.php
├── class-wc-rest-dev-report-top-sellers-controller.php
├── class-wc-rest-dev-coupons-controller.php
├── class-wc-rest-dev-customers-controller.php
├── class-wc-rest-dev-settings-controller.php
├── class-wc-rest-dev-orders-controller.php
├── class-wc-rest-dev-order-refunds-controller.php
├── class-wc-rest-dev-order-notes-controller.php
├── class-wc-rest-dev-data-controller.php
├── class-wc-rest-dev-data-currencies-controller.php
├── class-wc-rest-dev-data-countries-controller.php
├── class-wc-rest-dev-payment-gateways-controller.php
├── class-wc-rest-dev-setting-options-controller.php
└── class-wc-rest-dev-data-continents-controller.php
├── tests
├── framework
│ └── helpers
│ │ ├── class-wc-helper-order-note.php
│ │ └── class-wc-helper-order-refund.php
├── unit-tests
│ ├── data-counts.php
│ ├── functions.php
│ ├── shipping-methods.php
│ ├── order-refunds.php
│ ├── order-notes.php
│ ├── payment-gateways.php
│ ├── data.php
│ ├── system-status.php
│ ├── orders.php
│ ├── coupons.php
│ └── product-variations.php
└── bootstrap.php
├── wc-api-dev.php
├── readme.txt
└── wc-api-dev-class.php
/assets/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woocommerce/wc-api-dev/HEAD/assets/icon-128x128.png
--------------------------------------------------------------------------------
/assets/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woocommerce/wc-api-dev/HEAD/assets/icon-256x256.png
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "woocommerce/wc-api-dev",
3 | "version": "v1.0.0",
4 | "autoload": {
5 | "files": [ "wc-api-dev.php" ]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WooCommerce API Dev
2 |
3 | This is a repository is obsolete, WooCommerce REST API is now located in https://github.com/woocommerce/woocommerce-rest-api
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Editors
2 | project.xml
3 | project.properties
4 | /nbproject/private/
5 | .buildpath
6 | .project
7 | .settings*
8 | .idea
9 |
10 | # OS X metadata
11 | .DS_Store
12 |
13 | # Windows junk
14 | Thumbs.db
15 |
16 | # Unit tests
17 | /tmp
18 | /tests/bin/tmp
19 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | ./tests/unit-tests
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-system-status-controller.php:
--------------------------------------------------------------------------------
1 | /reviews.
6 | *
7 | * @author WooThemes
8 | * @category API
9 | * @package WooCommerce/API
10 | * @since 2.6.0
11 | */
12 |
13 | if ( ! defined( 'ABSPATH' ) ) {
14 | exit;
15 | }
16 |
17 | /**
18 | * REST API Product Reviews Controller Class.
19 | *
20 | * @package WooCommerce/API
21 | */
22 | class WC_REST_Dev_Product_Reviews_Controller extends WC_REST_Product_Reviews_Controller {
23 |
24 | /**
25 | * Endpoint namespace.
26 | *
27 | * @var string
28 | */
29 | protected $namespace = 'wc/v3';
30 | }
31 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-system-status-tools-controller.php:
--------------------------------------------------------------------------------
1 | /downloads endpoint.
6 | *
7 | * @author WooThemes
8 | * @category API
9 | * @package WooCommerce/API
10 | * @since 2.6.0
11 | */
12 |
13 | if ( ! defined( 'ABSPATH' ) ) {
14 | exit;
15 | }
16 |
17 | /**
18 | * REST API Customers controller class.
19 | *
20 | * @package WooCommerce/API
21 | */
22 | class WC_REST_Dev_Customer_Downloads_Controller extends WC_REST_Customer_Downloads_Controller {
23 |
24 | /**
25 | * Endpoint namespace.
26 | *
27 | * @var string
28 | */
29 | protected $namespace = 'wc/v3';
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-shipping-zone-methods-controller.php:
--------------------------------------------------------------------------------
1 | /methods endpoint.
6 | *
7 | * @author WooThemes
8 | * @category API
9 | * @package WooCommerce/API
10 | * @since 3.0.0
11 | */
12 |
13 | if ( ! defined( 'ABSPATH' ) ) {
14 | exit;
15 | }
16 |
17 | /**
18 | * REST API Shipping Zone Methods class.
19 | *
20 | * @package WooCommerce/API
21 | */
22 | class WC_REST_Dev_Shipping_Zone_Methods_Controller extends WC_REST_Shipping_Zone_Methods_Controller {
23 |
24 | /**
25 | * Endpoint namespace.
26 | *
27 | * @var string
28 | */
29 | protected $namespace = 'wc/v3';
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-shipping-zone-locations-controller.php:
--------------------------------------------------------------------------------
1 | /locations endpoint.
6 | *
7 | * @author WooThemes
8 | * @category API
9 | * @package WooCommerce/API
10 | * @since 3.0.0
11 | */
12 |
13 | if ( ! defined( 'ABSPATH' ) ) {
14 | exit;
15 | }
16 |
17 | /**
18 | * REST API Shipping Zone Locations class.
19 | *
20 | * @package WooCommerce/API
21 | */
22 | class WC_REST_Dev_Shipping_Zone_Locations_Controller extends WC_REST_Shipping_Zone_Locations_Controller {
23 | /**
24 | * Endpoint namespace.
25 | *
26 | * @var string
27 | */
28 | protected $namespace = 'wc/v3';
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-product-shipping-classes-controller.php:
--------------------------------------------------------------------------------
1 | /terms endpoint.
6 | *
7 | * @author WooThemes
8 | * @category API
9 | * @package WooCommerce/API
10 | * @since 2.6.0
11 | */
12 |
13 | if ( ! defined( 'ABSPATH' ) ) {
14 | exit;
15 | }
16 |
17 | /**
18 | * REST API Product Attribute Terms controller class.
19 | *
20 | * @package WooCommerce/API
21 | */
22 | class WC_REST_Dev_Product_Attribute_Terms_Controller extends WC_REST_Product_Attribute_Terms_Controller {
23 |
24 | /**
25 | * Endpoint namespace.
26 | *
27 | * @var string
28 | */
29 | protected $namespace = 'wc/v3';
30 | }
31 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-report-sales-controller.php:
--------------------------------------------------------------------------------
1 | add_order_note( 'This is an order note.', false );
29 |
30 | if ( ! $note_id ) {
31 | return false;
32 | }
33 |
34 | $note = get_comment( $note_id );
35 | return $note;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-coupons-controller.php:
--------------------------------------------------------------------------------
1 | namespace, '/' . $this->rest_base . '/batch', array(
35 | array(
36 | 'methods' => WP_REST_Server::EDITABLE,
37 | 'callback' => array( $this, 'batch_items' ),
38 | 'permission_callback' => array( $this, 'update_items_permissions_check' ),
39 | ),
40 | 'schema' => array( $this, 'get_public_batch_schema' ),
41 | ) );
42 | }
43 |
44 | /**
45 | * Makes sure the current user has access to WRITE the settings APIs.
46 | *
47 | * @param WP_REST_Request $request Full data about the request.
48 | * @return WP_Error|boolean
49 | */
50 | public function update_items_permissions_check( $request ) {
51 | if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) {
52 | return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
53 | }
54 |
55 | return true;
56 | }
57 |
58 | /**
59 | * Update a setting.
60 | *
61 | * @param WP_REST_Request $request
62 | * @return WP_Error|WP_REST_Response
63 | */
64 | public function update_item( $request ) {
65 | $options_controller = new WC_REST_Dev_Setting_Options_Controller;
66 | $response = $options_controller->update_item( $request );
67 | return $response;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/tests/unit-tests/data-counts.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Orders_Controller();
21 | $this->user = $this->factory->user->create( array(
22 | 'role' => 'administrator',
23 | ) );
24 | }
25 |
26 |
27 | /**
28 | * Test route registration.
29 | */
30 | public function test_register_routes() {
31 | $routes = $this->server->get_routes();
32 | $this->assertArrayHasKey( '/wc/v3/data', $routes );
33 | $this->assertArrayHasKey( '/wc/v3/data/counts', $routes );
34 | }
35 |
36 | /**
37 | * Cleanup.
38 | */
39 | public function stoppit_and_tidyup() {
40 | foreach ( $this->orders as $order ) {
41 | wp_delete_post( $order->get_id(), true );
42 | }
43 | $this->orders = array();
44 | }
45 |
46 | /**
47 | * Test getting counts.
48 | */
49 | public function test_get_counts() {
50 | wp_set_current_user( $this->user );
51 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/counts' ) );
52 | $counts = $response->get_data();
53 | $this->assertEquals( 200, $response->get_status() );
54 | $this->assertTrue( is_array( $counts ) );
55 | $this->assertGreaterThan( 1, count( $counts ) );
56 | $this->assertNotEmpty( $counts['orders'] );
57 | $this->assertNotEmpty( $counts['products'] );
58 | $this->assertEquals( $counts['products']['all'], 0 );
59 | $this->assertNotEmpty( $counts['reviews'] );
60 | $this->assertEquals( $counts['reviews']['all'], 0 );
61 | }
62 |
63 | /**
64 | * Test getting counts using the site's data.
65 | */
66 | public function test_get_order_counts() {
67 | wp_set_current_user( $this->user );
68 | // Create 10 orders.
69 | for ( $i = 0; $i < 10; $i++ ) {
70 | $this->orders[] = WC_Helper_Order::create_order( $this->user );
71 | }
72 |
73 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/counts' ) );
74 | $counts = $response->get_data();
75 | $this->assertEquals( 200, $response->get_status() );
76 | $this->assertNotEmpty( $counts['orders'] );
77 | $this->assertEquals( $counts['orders']['wc-pending'], 10 );
78 |
79 | $this->stoppit_and_tidyup();
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/tests/framework/helpers/class-wc-helper-order-refund.php:
--------------------------------------------------------------------------------
1 | 5.0,
30 | 'reason' => 'Testing',
31 | 'order_id' => $order_id,
32 | );
33 | $refund_obj = wc_create_refund( $refund );
34 |
35 | if ( ! $refund_obj || is_wp_error( $refund_obj ) ) {
36 | return false;
37 | }
38 |
39 | return $refund_obj;
40 | }
41 |
42 | /**
43 | * Create an order refund with line_items.
44 | *
45 | * @since 2.4
46 | *
47 | * @param int $order_id
48 | * @param int $customer_id
49 | *
50 | * @return WC_Order_Refund
51 | */
52 | public static function create_refund_with_items( $order_id, $customer_id = 1 ) {
53 | $order = wc_get_order( $order_id );
54 |
55 | if ( ! $order ) {
56 | return false;
57 | }
58 | $items = $order->get_items();
59 | $item_id = key( $items );
60 | // Create the refund.
61 | $refund = array(
62 | 'amount' => 5.0,
63 | 'reason' => 'Testing',
64 | 'order_id' => $order_id,
65 | 'line_items' => array(),
66 | );
67 | $refund['line_items'][ $item_id ] = array(
68 | 'qty' => 1,
69 | 'refund_total' => 5.0,
70 | );
71 | $refund_obj = wc_create_refund( $refund );
72 |
73 | if ( ! $refund_obj || is_wp_error( $refund_obj ) ) {
74 | return false;
75 | }
76 |
77 | return $refund_obj;
78 | }
79 |
80 |
81 | /**
82 | * Create an array of line_items based on a given order.
83 | *
84 | * @since 2.4
85 | *
86 | * @param int $order_id
87 | * @param int $count
88 | *
89 | * @return array
90 | */
91 | public static function create_refund_line_items( $order_id, $count ) {
92 | $order = wc_get_order( $order_id );
93 | $items = $order->get_items();
94 | $line_items = array();
95 |
96 | // Create line items up to count, as long as there are items to use.
97 | $item_id = key( $items );
98 | $i = 0;
99 | while ( $item_id && ( $i < $count ) ) {
100 | $line_items[ $item_id ] = array(
101 | 'qty' => 1,
102 | 'refund_total' => 5.0,
103 | );
104 | // Next loop…
105 | $item_id = key( $items );
106 | $i++;
107 | }
108 | return $line_items;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/tests/unit-tests/functions.php:
--------------------------------------------------------------------------------
1 | assertEquals( '2016-06-06T06:06:06', wc_rest_prepare_date_response( '2016-06-06 06:06:06' ) );
17 | }
18 |
19 | /**
20 | * Test wc_rest_upload_image_from_url().
21 | *
22 | * @since 2.6.0
23 | */
24 | public function test_wc_rest_upload_image_from_url() {
25 | // Only test the error, no need to upload images.
26 | $this->assertIsWPError( wc_rest_upload_image_from_url( 'thing' ) );
27 | }
28 |
29 | /**
30 | * Test wc_rest_set_uploaded_image_as_attachment().
31 | *
32 | * @since 2.6.0
33 | */
34 | public function test_wc_rest_set_uploaded_image_as_attachment() {
35 | $this->assertInternalType( 'int', wc_rest_set_uploaded_image_as_attachment( array( 'file' => '', 'url' => '' ) ) );
36 | }
37 |
38 | /**
39 | * Test wc_rest_validate_reports_request_arg().
40 | *
41 | * @since 2.6.0
42 | */
43 | public function test_wc_rest_validate_reports_request_arg() {
44 | $request = new WP_REST_Request( 'GET', '/wc/v2/foo', array(
45 | 'args' => array(
46 | 'date' => array(
47 | 'type' => 'string',
48 | 'format' => 'date',
49 | ),
50 | ),
51 | ) );
52 |
53 | // Success.
54 | $this->assertTrue( wc_rest_validate_reports_request_arg( '2016-06-06', $request, 'date' ) );
55 |
56 | // Error.
57 | $error = wc_rest_validate_reports_request_arg( 'foo', $request, 'date' );
58 | $this->assertEquals( 'The date you provided is invalid.', $error->get_error_message() );
59 | }
60 |
61 | /**
62 | * Test wc_rest_urlencode_rfc3986().
63 | *
64 | * @since 2.6.0
65 | */
66 | public function test_wc_rest_urlencode_rfc3986() {
67 | $this->assertEquals( 'https%3A%2F%2Fwoocommerce.com%2F', wc_rest_urlencode_rfc3986( 'https://woocommerce.com/' ) );
68 | }
69 |
70 | /**
71 | * Test wc_rest_check_post_permissions().
72 | *
73 | * @since 2.6.0
74 | */
75 | public function test_wc_rest_check_post_permissions() {
76 | $this->isFalse( wc_rest_check_post_permissions( 'shop_order' ) );
77 | }
78 |
79 | /**
80 | * Test wc_rest_check_user_permissions().
81 | *
82 | * @since 2.6.0
83 | */
84 | public function test_wc_rest_check_user_permissions() {
85 | $this->isFalse( wc_rest_check_user_permissions() );
86 | }
87 |
88 | /**
89 | * Test wc_rest_check_product_term_permissions().
90 | *
91 | * @since 2.6.0
92 | */
93 | public function test_wc_rest_check_product_term_permissions() {
94 | $this->isFalse( wc_rest_check_product_term_permissions( 'product_cat' ) );
95 | }
96 |
97 | /**
98 | * Test wc_rest_check_manager_permissions().
99 | *
100 | * @since 2.6.0
101 | */
102 | public function test_wc_rest_check_manager_permissions() {
103 | $this->isFalse( wc_rest_check_manager_permissions( 'reports' ) );
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-orders-controller.php:
--------------------------------------------------------------------------------
1 | 'any',
67 | 'description' => __( 'Limit result set to orders assigned a specific status.', 'woocommerce' ),
68 | 'type' => 'array',
69 | 'items' => array(
70 | 'type' => 'string',
71 | 'enum' => array_merge( array( 'any' ), $this->get_order_statuses() ),
72 | ),
73 | 'validate_callback' => 'rest_validate_request_arg',
74 | );
75 |
76 | return $params;
77 | }
78 |
79 | /**
80 | * Get the Order's schema, conforming to JSON Schema.
81 | *
82 | * @return array
83 | */
84 | public function get_item_schema() {
85 | $params = parent::get_item_schema();
86 |
87 | $params['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
88 |
89 | $params['properties']['line_items']['items']['properties']['name']['type'] = 'mixed';
90 | $params['properties']['line_items']['items']['properties']['product_id']['type'] = 'mixed';
91 | $params['properties']['line_items']['items']['properties']['tax_class']['type'] = 'string';
92 | $params['properties']['line_items']['items']['properties']['price']['type'] = 'number';
93 | $params['properties']['line_items']['items']['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
94 |
95 | $params['properties']['tax_lines']['items']['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
96 |
97 | $params['properties']['shipping_lines']['items']['properties']['method_title']['type'] = 'mixed';
98 | $params['properties']['shipping_lines']['items']['properties']['method_id']['type'] = 'mixed';
99 | $params['properties']['shipping_lines']['items']['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
100 |
101 | $params['properties']['fee_lines']['items']['properties']['name']['type'] = 'mixed';
102 | $params['properties']['fee_lines']['items']['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
103 |
104 | $params['properties']['coupon_lines']['items']['properties']['code']['type'] = 'mixed';
105 | $params['properties']['coupon_lines']['items']['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
106 |
107 | return $params;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-order-refunds-controller.php:
--------------------------------------------------------------------------------
1 | /refunds endpoint.
6 | *
7 | * @author WooThemes
8 | * @category API
9 | * @package WooCommerce/API
10 | * @since 2.6.0
11 | */
12 |
13 | if ( ! defined( 'ABSPATH' ) ) {
14 | exit;
15 | }
16 |
17 | /**
18 | * REST API Order Refunds controller class.
19 | *
20 | * @package WooCommerce/API
21 | */
22 | class WC_REST_Dev_Order_Refunds_Controller extends WC_REST_Order_Refunds_Controller {
23 |
24 | /**
25 | * Endpoint namespace.
26 | *
27 | * @var string
28 | */
29 | protected $namespace = 'wc/v3';
30 |
31 | /**
32 | * Prepares one object for create or update operation.
33 | *
34 | * @since 3.0.0
35 | * @param WP_REST_Request $request Request object.
36 | * @param bool $creating If is creating a new object.
37 | * @return WP_Error|WC_Data The prepared item, or WP_Error object on failure.
38 | */
39 | protected function prepare_object_for_database( $request, $creating = false ) {
40 | $order = wc_get_order( (int) $request['order_id'] );
41 |
42 | if ( ! $order ) {
43 | return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce' ), 404 );
44 | }
45 |
46 | if ( 0 > $request['amount'] ) {
47 | return new WP_Error( 'woocommerce_rest_invalid_order_refund', __( 'Refund amount must be greater than zero.', 'woocommerce' ), 400 );
48 | }
49 |
50 | // Create the refund.
51 | $refund = wc_create_refund(
52 | array(
53 | 'order_id' => $order->get_id(),
54 | 'amount' => $request['amount'],
55 | 'reason' => empty( $request['reason'] ) ? null : $request['reason'],
56 | 'line_items' => empty( $request['line_items'] ) ? array() : $request['line_items'],
57 | 'refund_payment' => is_bool( $request['api_refund'] ) ? $request['api_refund'] : true,
58 | 'restock_items' => true,
59 | )
60 | );
61 |
62 | if ( is_wp_error( $refund ) ) {
63 | return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', $refund->get_error_message(), 500 );
64 | }
65 |
66 | if ( ! $refund ) {
67 | return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', __( 'Cannot create order refund, please try again.', 'woocommerce' ), 500 );
68 | }
69 |
70 | if ( ! empty( $request['meta_data'] ) && is_array( $request['meta_data'] ) ) {
71 | foreach ( $request['meta_data'] as $meta ) {
72 | $refund->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' );
73 | }
74 | $refund->save_meta_data();
75 | }
76 |
77 | /**
78 | * Filters an object before it is inserted via the REST API.
79 | *
80 | * The dynamic portion of the hook name, `$this->post_type`,
81 | * refers to the object type slug.
82 | *
83 | * @param WC_Data $coupon Object object.
84 | * @param WP_REST_Request $request Request object.
85 | * @param bool $creating If is creating a new object.
86 | */
87 | return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $refund, $request, $creating );
88 | }
89 |
90 | /**
91 | * Get the Order refund's schema, conforming to JSON Schema.
92 | *
93 | * @return array
94 | */
95 | public function get_item_schema() {
96 | $params = parent::get_item_schema();
97 |
98 | $params['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
99 |
100 | $params['properties']['line_items']['items']['properties']['name']['type'] = 'mixed';
101 | $params['properties']['line_items']['items']['properties']['product_id']['type'] = 'mixed';
102 | $params['properties']['line_items']['items']['properties']['tax_class']['type'] = 'string';
103 | $params['properties']['line_items']['items']['properties']['price']['type'] = 'number';
104 | $params['properties']['line_items']['items']['properties']['meta_data']['items']['properties']['value']['type'] = 'mixed';
105 |
106 | return $params;
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === WooCommerce API Dev ===
2 | Contributors: automattic, woothemes
3 | Tags: woocommerce, rest-api, api
4 | Requires at least: 4.6
5 | Tested up to: 4.9
6 | Stable tag: 1.0.0
7 | License: GPLv2 or later
8 | License URI: http://www.gnu.org/licenses/gpl-2.0.html
9 |
10 | A feature plugin providing a bleeding edge version of the WooCommerce REST API.
11 |
12 | == Description ==
13 |
14 | This is a repository for the development version of the WooCommerce REST API. This feature plugin provides a place where the next version of the WooCommerce REST API can be worked on, independent of the current WooCommerce release cycle. These changes are brought over to [WooCommerce core](https://github.com/woocommerce/woocommerce) when they are ready for release.
15 |
16 | * Current stable API version: [**v2**](https://github.com/woocommerce/woocommerce/tree/master/includes/api).
17 | * Current development version: **v3**.
18 |
19 | == Installation ==
20 |
21 | This section describes how to install the plugin and get it working.
22 |
23 | 1. Upload the plugin files to the `/wp-content/plugins/plugin-name` directory, or install the plugin through the WordPress plugins screen directly.
24 | 1. Activate the plugin through the 'Plugins' screen in WordPress
25 |
26 | == Changelog ==
27 |
28 | = 1.0.0 =
29 | * Bug fixes for WooCommerce 3.6 compatability
30 |
31 | = 0.9.9 =
32 | * More bug fixes for WooCommerce 3.5 compatability
33 |
34 | = 0.9.8 =
35 | * Bug fixes for WooCommerce 3.5 compatability
36 |
37 | = 0.9.7 =
38 | * `data/counts` endpoint removed (moved to wc-calypso-bridge)
39 | * `products/reviews` endpoint removed (moved to wc-calypso-bridge)
40 |
41 | = 0.9.6 =
42 | * new `data/counts` endpoint added
43 |
44 | = 0.9.5 =
45 | * Fixes `single_select_page` settings (like `woocommerce_shop_page_id`) not showing up in responses.
46 |
47 | = 0.9.4 =
48 | * Added currency and dimensions to selected countries in the data/continents response
49 |
50 | = 0.9.3 =
51 | * Removed MailChimp files which are now in wc-calypso-bridge
52 | * Fixed regex issue that caused gutenberg to crash
53 | * Removed webhook test dependencies which are being removed in WooCommerce 3.3
54 |
55 | = 0.9.2 =
56 | * Rest API: Backport woocommerce/woocommerce#17849 to fix schema types in WP 4.9
57 |
58 | = 0.9.1 =
59 | * Rest API: Update the schema types for tax_class and price
60 |
61 | = 0.9.0 =
62 | * Removed all non core wc API logic from the plugin.
63 | * Added Author to note orders/{orderId}/notes responses
64 |
65 | = 0.8.9 =
66 | * Added MailChimp API endpoints for Store on .com
67 | * Added auto db upgrade handling
68 |
69 | = 0.8.8 =
70 | * Added customizer guided tour for nux.
71 | * Added Store menu link to Jetpack Masterbar.
72 |
73 | = 0.8.4 =
74 | * Remove auto-install via github as it is not reliable.
75 | * Add composer autoload support.
76 | * Add check for existing installs to avoid conflicts.
77 |
78 | = 0.8.3 =
79 | * Fix - Update order link in order details emails.
80 |
81 | = 0.8.2 =
82 | * Fix - Don't auto enable the PayPal payment method.
83 |
84 | = 0.8.1 =
85 | * Fix - Fix auto plugin update logic
86 | * Fix - Don't auto enable the cheque payment method.
87 | * Adds a new config constant (WC_API_DEV_ENABLE_HOTFIXES) to make it easy to disable hotfixes.
88 |
89 | = 0.8.0 =
90 | * Update orders endpoint to accept multiple statuses
91 | * Fix - Email subject and footers becoming out of sync
92 |
93 | = 0.7.1 =
94 | * Fix - add another URI to watch for when disabling sync during API requests
95 |
96 | = 0.7.0 =
97 | * Fix - disable jetpack sync during rest api requests to avoid slow responses
98 |
99 | = 0.6.0 =
100 | * Fix value default return on settings endpoints
101 | * Fix broken variation image set
102 | * Add a method supports response to payment methods
103 | * Added the ability to keep this plugin up to date
104 |
105 | = 0.5.0 =
106 | * Added a /settings/batch endpoint
107 | * Fixed broken orders refund endpoint
108 |
109 | = 0.4.0 =
110 | * Adds store address (two lines), city and postcode to the settings/general endpoint
111 |
112 | = 0.3.0 =
113 | * Adds endpoints for getting a list of supported currencies, along with their name and symbol.
114 | * Limit regex check for currency code to 3 characters.
115 |
116 | = 0.2.0 =
117 | * Removes the 'visible' property from the variations endpoint and adds 'status'. (See https://github.com/woocommerce/woocommerce/pull/15216)
118 | * Don't return parent image when no variation image is set.
119 |
120 | = 0.1.0 =
121 | * Initial release
122 |
--------------------------------------------------------------------------------
/tests/unit-tests/shipping-methods.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Shipping_Methods_Controller();
17 | $this->user = $this->factory->user->create( array(
18 | 'role' => 'administrator',
19 | ) );
20 | }
21 |
22 | /**
23 | * Test route registration.
24 | *
25 | * @since 3.0.0
26 | */
27 | public function test_register_routes() {
28 | $routes = $this->server->get_routes();
29 | $this->assertArrayHasKey( '/wc/v3/shipping_methods', $routes );
30 | $this->assertArrayHasKey( '/wc/v3/shipping_methods/(?P[\w-]+)', $routes );
31 | }
32 |
33 | /**
34 | * Test getting all shipping methods.
35 | *
36 | * @since 3.0.0
37 | */
38 | public function test_get_shipping_methods() {
39 | wp_set_current_user( $this->user );
40 |
41 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/shipping_methods' ) );
42 | $methods = $response->get_data();
43 |
44 | $this->assertEquals( 200, $response->get_status() );
45 | $this->assertContains( array(
46 | 'id' => 'free_shipping',
47 | 'title' => 'Free shipping',
48 | 'description' => 'Free shipping is a special method which can be triggered with coupons and minimum spends.',
49 | '_links' => array(
50 | 'self' => array(
51 | array(
52 | 'href' => rest_url( '/wc/v3/shipping_methods/free_shipping' ),
53 | ),
54 | ),
55 | 'collection' => array(
56 | array(
57 | 'href' => rest_url( '/wc/v3/shipping_methods' ),
58 | ),
59 | ),
60 | ),
61 | ), $methods );
62 | }
63 |
64 | /**
65 | * Tests to make sure shipping methods cannot viewed without valid permissions.
66 | *
67 | * @since 3.0.0
68 | */
69 | public function test_get_shipping_methods_without_permission() {
70 | wp_set_current_user( 0 );
71 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/shipping_methods' ) );
72 | $this->assertEquals( 401, $response->get_status() );
73 | }
74 |
75 | /**
76 | * Tests getting a single shipping method.
77 | *
78 | * @since 3.0.0
79 | */
80 | public function test_get_shipping_method() {
81 | wp_set_current_user( $this->user );
82 |
83 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/shipping_methods/local_pickup' ) );
84 | $method = $response->get_data();
85 |
86 | $this->assertEquals( 200, $response->get_status() );
87 | $this->assertEquals( array(
88 | 'id' => 'local_pickup',
89 | 'title' => 'Local pickup',
90 | 'description' => 'Allow customers to pick up orders themselves. By default, when using local pickup store base taxes will apply regardless of customer address.',
91 | ), $method );
92 | }
93 |
94 | /**
95 | * Tests getting a single shipping method without the correct permissions.
96 | *
97 | * @since 3.0.0
98 | */
99 | public function test_get_shipping_method_without_permission() {
100 | wp_set_current_user( 0 );
101 |
102 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/shipping_methods/local_pickup' ) );
103 | $this->assertEquals( 401, $response->get_status() );
104 | }
105 |
106 | /**
107 | * Tests getting a shipping method with an invalid ID.
108 | *
109 | * @since 3.0.0
110 | */
111 | public function test_get_shipping_method_invalid_id() {
112 | wp_set_current_user( $this->user );
113 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/shipping_methods/fake_method' ) );
114 | $this->assertEquals( 404, $response->get_status() );
115 | }
116 |
117 | /**
118 | * Test the shipping method schema.
119 | *
120 | * @since 3.0.0
121 | */
122 | public function test_shipping_method_schema() {
123 | wp_set_current_user( $this->user );
124 |
125 | $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/shipping_methods' );
126 | $response = $this->server->dispatch( $request );
127 | $data = $response->get_data();
128 | $properties = $data['schema']['properties'];
129 |
130 | $this->assertEquals( 3, count( $properties ) );
131 | $this->assertArrayHasKey( 'id', $properties );
132 | $this->assertArrayHasKey( 'title', $properties );
133 | $this->assertArrayHasKey( 'description', $properties );
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-order-notes-controller.php:
--------------------------------------------------------------------------------
1 | /notes endpoint.
6 | *
7 | * @author WooThemes
8 | * @category API
9 | * @package WooCommerce/API
10 | * @since 2.6.0
11 | */
12 |
13 | if ( ! defined( 'ABSPATH' ) ) {
14 | exit;
15 | }
16 |
17 | /**
18 | * REST API Order Notes controller class.
19 | *
20 | * @package WooCommerce/API
21 | */
22 | class WC_REST_Dev_Order_Notes_Controller extends WC_REST_Order_Notes_Controller {
23 |
24 | /**
25 | * Endpoint namespace.
26 | *
27 | * @var string
28 | */
29 | protected $namespace = 'wc/v3';
30 |
31 | /**
32 | * Prepare a single order note output for response.
33 | *
34 | * @param WP_Comment $note Order note object.
35 | * @param WP_REST_Request $request Request object.
36 | * @return WP_REST_Response $response Response data.
37 | */
38 | public function prepare_item_for_response( $note, $request ) {
39 | $data = array(
40 | 'id' => (int) $note->comment_ID,
41 | 'author' => __( 'WooCommerce', 'woocommerce' ) === $note->comment_author ? 'system' : $note->comment_author,
42 | 'date_created' => wc_rest_prepare_date_response( $note->comment_date ),
43 | 'date_created_gmt' => wc_rest_prepare_date_response( $note->comment_date_gmt ),
44 | 'note' => $note->comment_content,
45 | 'customer_note' => (bool) get_comment_meta( $note->comment_ID, 'is_customer_note', true ),
46 | );
47 |
48 | $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
49 | $data = $this->add_additional_fields_to_object( $data, $request );
50 | $data = $this->filter_response_by_context( $data, $context );
51 |
52 | // Wrap the data in a response object.
53 | $response = rest_ensure_response( $data );
54 |
55 | $response->add_links( $this->prepare_links( $note ) );
56 |
57 | /**
58 | * Filter order note object returned from the REST API.
59 | *
60 | * @param WP_REST_Response $response The response object.
61 | * @param WP_Comment $note Order note object used to create response.
62 | * @param WP_REST_Request $request Request object.
63 | */
64 | return apply_filters( 'woocommerce_rest_prepare_order_note', $response, $note, $request );
65 | }
66 |
67 | /**
68 | * Create a single order note.
69 | *
70 | * @param WP_REST_Request $request Full details about the request.
71 | * @return WP_Error|WP_REST_Response
72 | */
73 | public function create_item( $request ) {
74 | if ( ! empty( $request['id'] ) ) {
75 | /* translators: %s: post type */
76 | return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) );
77 | }
78 |
79 | $order = wc_get_order( (int) $request['order_id'] );
80 |
81 | if ( ! $order || $this->post_type !== $order->get_type() ) {
82 | return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce' ), array( 'status' => 404 ) );
83 | }
84 |
85 | // Create the note.
86 | $note_id = $order->add_order_note( $request['note'], $request['customer_note'], $request['added_by_user'] );
87 |
88 | if ( ! $note_id ) {
89 | return new WP_Error( 'woocommerce_api_cannot_create_order_note', __( 'Cannot create order note, please try again.', 'woocommerce' ), array( 'status' => 500 ) );
90 | }
91 |
92 | $note = get_comment( $note_id );
93 | $this->update_additional_fields_for_object( $note, $request );
94 |
95 | /**
96 | * Fires after a order note is created or updated via the REST API.
97 | *
98 | * @param WP_Comment $note New order note object.
99 | * @param WP_REST_Request $request Request object.
100 | * @param boolean $creating True when creating item, false when updating.
101 | */
102 | do_action( 'woocommerce_rest_insert_order_note', $note, $request, true );
103 |
104 | $request->set_param( 'context', 'edit' );
105 | $response = $this->prepare_item_for_response( $note, $request );
106 | $response = rest_ensure_response( $response );
107 | $response->set_status( 201 );
108 | $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, str_replace( '(?P[\d]+)', $order->get_id(), $this->rest_base ), $note_id ) ) );
109 |
110 | return $response;
111 | }
112 |
113 | /**
114 | * Get the Order Notes schema, conforming to JSON Schema.
115 | *
116 | * @return array
117 | */
118 | public function get_item_schema() {
119 | $schema = parent::get_item_schema();
120 | $schema['properties']['author'] = array(
121 | 'description' => __( 'Order note author.', 'woocommerce' ),
122 | 'type' => 'string',
123 | 'readonly' => true,
124 | 'context' => array( 'view', 'edit' ),
125 | );
126 | $schema['properties']['added_by_user'] = array(
127 | 'description' => __( 'If true, this note will be attributed to the current user. If false, the note will be attributed to the system.', 'woocommerce' ),
128 | 'type' => 'boolean',
129 | 'default' => false,
130 | 'context' => array( 'edit' ),
131 | );
132 | return $schema;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | tests_dir = dirname( __FILE__ );
38 | $this->plugin_dir = dirname( $this->tests_dir );
39 | $this->wc_dir = dirname( $this->plugin_dir ) . '/woocommerce';
40 | $this->wc_tests_dir = dirname( $this->plugin_dir ) . '/woocommerce/tests';
41 | $this->wp_tests_dir = getenv( 'WP_TESTS_DIR' ) ? getenv( 'WP_TESTS_DIR' ) : '/tmp/wordpress-tests-lib';
42 |
43 | // load test function so tests_add_filter() is available
44 | require_once( $this->wp_tests_dir . '/includes/functions.php' );
45 |
46 | // load WC
47 | tests_add_filter( 'muplugins_loaded', array( $this, 'load_wc' ) );
48 |
49 | // load WC API Dev
50 | tests_add_filter( 'muplugins_loaded', array( $this, 'load_wc_api_dev' ) );
51 |
52 | // install WC
53 | tests_add_filter( 'setup_theme', array( $this, 'install_wc' ) );
54 |
55 | // load the WP testing environment
56 | require_once( $this->wp_tests_dir . '/includes/bootstrap.php' );
57 |
58 | // load WC testing framework
59 | $this->includes();
60 | }
61 |
62 | /**
63 | * Load WooCommerce.
64 | */
65 | public function load_wc() {
66 | require_once( $this->wc_dir . '/woocommerce.php' );
67 | }
68 |
69 | /**
70 | * Load WC API Dev.
71 | */
72 | public function load_wc_api_dev() {
73 | define( 'WC_API_DEV_ENABLE_HOTFIXES', false );
74 | require_once( $this->plugin_dir . '/wc-api-dev-class.php' );
75 | }
76 |
77 | /**
78 | * Install WooCommerce after the test environment and WC have been loaded.
79 | */
80 | public function install_wc() {
81 |
82 | // Clean existing install first.
83 | define( 'WP_UNINSTALL_PLUGIN', true );
84 | define( 'WC_REMOVE_ALL_DATA', true );
85 | include( $this->wc_dir . '/uninstall.php' );
86 |
87 | WC_Install::install();
88 |
89 | // Reload capabilities after install, see https://core.trac.wordpress.org/ticket/28374
90 | if ( version_compare( $GLOBALS['wp_version'], '4.7', '<' ) ) {
91 | $GLOBALS['wp_roles']->reinit();
92 | } else {
93 | $GLOBALS['wp_roles'] = null;
94 | wp_roles();
95 | }
96 |
97 | echo 'Installing WooCommerce...' . PHP_EOL;
98 | }
99 |
100 | /**
101 | * Load WC-specific test cases and factories.
102 | * If needed, these can also be shipped with the dev plugin and a local copy can be called.
103 | */
104 | public function includes() {
105 |
106 | // framework
107 | require_once( $this->wc_tests_dir . '/framework/class-wc-unit-test-factory.php' );
108 | require_once( $this->wc_tests_dir . '/framework/class-wc-mock-session-handler.php' );
109 | require_once( $this->wc_tests_dir . '/framework/class-wc-mock-wc-data.php' );
110 | require_once( $this->wc_tests_dir . '/framework/class-wc-mock-wc-object-query.php' );
111 | require_once( $this->wc_tests_dir . '/framework/class-wc-payment-token-stub.php' );
112 | require_once( $this->wc_tests_dir . '/framework/vendor/class-wp-test-spy-rest-server.php' );
113 |
114 | // test cases
115 | require_once( $this->wc_tests_dir . '/framework/class-wc-unit-test-case.php' );
116 | require_once( $this->wc_tests_dir . '/framework/class-wc-api-unit-test-case.php' );
117 | require_once( $this->wc_tests_dir . '/framework/class-wc-rest-unit-test-case.php' );
118 |
119 | // Helpers
120 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-product.php' );
121 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-coupon.php' );
122 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-fee.php' );
123 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-shipping.php' );
124 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-customer.php' );
125 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-order.php' );
126 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-shipping-zones.php' );
127 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-payment-token.php' );
128 | require_once( $this->wc_tests_dir . '/framework/helpers/class-wc-helper-settings.php' );
129 |
130 | // Added helpers
131 | require_once( $this->tests_dir . '/framework/helpers/class-wc-helper-order-note.php' );
132 | require_once( $this->tests_dir . '/framework/helpers/class-wc-helper-order-refund.php' );
133 | }
134 |
135 | /**
136 | * Gets the single class instance.
137 | */
138 | public static function instance() {
139 | if ( is_null( self::$instance ) ) {
140 | self::$instance = new self();
141 | }
142 |
143 | return self::$instance;
144 | }
145 | }
146 |
147 | WC_API_Dev_Unit_Tests_Bootstrap::instance();
148 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-data-controller.php:
--------------------------------------------------------------------------------
1 | namespace, '/' . $this->rest_base, array(
46 | array(
47 | 'methods' => WP_REST_Server::READABLE,
48 | 'callback' => array( $this, 'get_items' ),
49 | 'permission_callback' => array( $this, 'get_items_permissions_check' ),
50 | ),
51 | 'schema' => array( $this, 'get_public_item_schema' ),
52 | ) );
53 | }
54 |
55 | /**
56 | * Check whether a given request has permission to read site data.
57 | *
58 | * @param WP_REST_Request $request Full details about the request.
59 | * @return WP_Error|boolean
60 | */
61 | public function get_items_permissions_check( $request ) {
62 | if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) {
63 | return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
64 | }
65 |
66 | return true;
67 | }
68 |
69 | /**
70 | * Check whether a given request has permission to read site settings.
71 | *
72 | * @param WP_REST_Request $request Full details about the request.
73 | * @return WP_Error|boolean
74 | */
75 | public function get_item_permissions_check( $request ) {
76 | if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) {
77 | return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
78 | }
79 |
80 | return true;
81 | }
82 |
83 | /**
84 | * Return the list of data resources.
85 | *
86 | * @since 3.1.0
87 | * @param WP_REST_Request $request
88 | * @return WP_Error|WP_REST_Response
89 | */
90 | public function get_items( $request ) {
91 | $data = array();
92 | $resources = array(
93 | array(
94 | 'slug' => 'continents',
95 | 'description' => __( 'List of supported continents, countries, and states.', 'woocommerce' ),
96 | ),
97 | array(
98 | 'slug' => 'countries',
99 | 'description' => __( 'List of supported states in a given country.', 'woocommerce' ),
100 | ),
101 | array(
102 | 'slug' => 'currencies',
103 | 'description' => __( 'List of supported currencies.', 'woocommerce' ),
104 | ),
105 | );
106 |
107 | foreach ( $resources as $resource ) {
108 | $item = $this->prepare_item_for_response( (object) $resource, $request );
109 | $data[] = $this->prepare_response_for_collection( $item );
110 | }
111 |
112 | return rest_ensure_response( $data );
113 | }
114 |
115 | /**
116 | * Prepare a data resource object for serialization.
117 | *
118 | * @param stdClass $report Report data.
119 | * @param WP_REST_Request $request Request object.
120 | * @return WP_REST_Response $response Response data.
121 | */
122 | public function prepare_item_for_response( $resource, $request ) {
123 | $data = array(
124 | 'slug' => $resource->slug,
125 | 'description' => $resource->description,
126 | );
127 |
128 | $data = $this->add_additional_fields_to_object( $data, $request );
129 | $data = $this->filter_response_by_context( $data, 'view' );
130 |
131 | // Wrap the data in a response object.
132 | $response = rest_ensure_response( $data );
133 | $response->add_links( $this->prepare_links( $resource ) );
134 |
135 | return $response;
136 | }
137 |
138 | /**
139 | * Prepare links for the request.
140 | *
141 | * @param object $item Data object.
142 | * @return array Links for the given country.
143 | */
144 | protected function prepare_links( $item ) {
145 | $links = array(
146 | 'self' => array(
147 | 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $item->slug ) ),
148 | ),
149 | 'collection' => array(
150 | 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
151 | ),
152 | );
153 |
154 | return $links;
155 | }
156 |
157 | /**
158 | * Get the data index schema, conforming to JSON Schema.
159 | *
160 | * @since 3.1.0
161 | * @return array
162 | */
163 | public function get_item_schema() {
164 | $schema = array(
165 | '$schema' => 'http://json-schema.org/draft-04/schema#',
166 | 'title' => 'data_index',
167 | 'type' => 'object',
168 | 'properties' => array(
169 | 'slug' => array(
170 | 'description' => __( 'Data resource ID.', 'woocommerce' ),
171 | 'type' => 'string',
172 | 'context' => array( 'view' ),
173 | 'readonly' => true,
174 | ),
175 | 'description' => array(
176 | 'description' => __( 'Data resource description.', 'woocommerce' ),
177 | 'type' => 'string',
178 | 'context' => array( 'view' ),
179 | 'readonly' => true,
180 | ),
181 | ),
182 | );
183 |
184 | return $this->add_additional_fields_schema( $schema );
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/tests/unit-tests/order-refunds.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Orders_Controller();
28 | $this->user = $this->factory->user->create( array(
29 | 'role' => 'administrator',
30 | ) );
31 | $order = WC_Helper_Order::create_order();
32 | $this->order_id = $order->get_id();
33 | }
34 |
35 | /**
36 | * Cleanup.
37 | */
38 | public function stoppit_and_tidyup() {
39 | wp_delete_post( $this->order_id, true );
40 | foreach ( $this->refunds as $refund ) {
41 | $refund->delete();
42 | }
43 | $this->refunds = array();
44 | }
45 |
46 | /**
47 | * Test route registration.
48 | * @since 3.0.0
49 | */
50 | public function test_register_routes() {
51 | $routes = $this->server->get_routes();
52 | $this->assertArrayHasKey( '/wc/v3/orders/(?P[\d]+)/refunds', $routes );
53 | $this->assertArrayHasKey( '/wc/v3/orders/(?P[\d]+)/refunds/(?P[\d]+)', $routes );
54 | }
55 |
56 | /**
57 | * Test getting all refunds for an order.
58 | * @since 3.0.0
59 | */
60 | public function test_get_items() {
61 | wp_set_current_user( $this->user );
62 |
63 | // Create 2 partial order refunds.
64 | for ( $i = 0; $i < 2; $i++ ) {
65 | $this->refunds[] = WC_Helper_Order_Refund::create_refund( $this->order_id, $this->user );
66 | }
67 |
68 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', "/wc/v3/orders/$this->order_id/refunds" ) );
69 | $refunds = $response->get_data();
70 |
71 | $this->assertEquals( 200, $response->get_status() );
72 | $this->assertEquals( 2, count( $refunds ) );
73 | $this->stoppit_and_tidyup();
74 | }
75 |
76 | /**
77 | * Tests getting a single order refund.
78 | * @since 3.0.0
79 | */
80 | public function test_get_item() {
81 | wp_set_current_user( $this->user );
82 | $refund = WC_Helper_Order_Refund::create_refund_with_items( $this->order_id, $this->user );
83 | $this->refunds[] = $refund;
84 |
85 | $request = new WP_REST_Request( 'GET', "/wc/v3/orders/$this->order_id/refunds/" . $refund->get_id() );
86 | $response = $this->server->dispatch( $request );
87 | $data = $response->get_data();
88 |
89 | $this->assertEquals( 200, $response->get_status() );
90 | $this->assertArrayHasKey( 'date_created', $data );
91 | $this->assertEquals( $data['amount'], '5.00' );
92 | $this->assertEquals( $data['reason'], 'Testing' );
93 | $this->assertArrayHasKey( 'line_items', $data );
94 | $this->assertEquals( 1, count( $data['line_items'] ) );
95 |
96 | $this->stoppit_and_tidyup();
97 | }
98 |
99 | /**
100 | * Tests creating an order refund by a given user.
101 | * @since 3.0.0
102 | */
103 | public function test_create_refund() {
104 | wp_set_current_user( $this->user );
105 | $request = new WP_REST_Request( 'POST', "/wc/v3/orders/$this->order_id/refunds" );
106 | $request->set_body_params( array(
107 | 'amount' => '5.0',
108 | 'reason' => 'This is testing content.',
109 | 'api_refund' => false,
110 | ) );
111 | $response = $this->server->dispatch( $request );
112 | $data = $response->get_data();
113 | $refund = new WC_Order_Refund( $data['id'] );
114 |
115 | $this->assertEquals( 201, $response->get_status() );
116 | // Verify the API response has correct data
117 | $this->assertArrayHasKey( 'date_created', $data );
118 | $this->assertEquals( $data['amount'], '5.00' );
119 | $this->assertEquals( $data['reason'], 'This is testing content.' );
120 | $this->assertEquals( $data['refunded_by'], get_current_user_id() );
121 |
122 | // Verify that Note object has correct data
123 | $this->assertEquals( $refund->get_amount(), '5.00' );
124 | $this->assertEquals( $refund->get_reason(), 'This is testing content.' );
125 |
126 | $refund->delete();
127 | }
128 |
129 | /**
130 | * Tests creating an order refund by a given user.
131 | * @since 3.0.0
132 | */
133 | public function test_create_refund_with_items() {
134 | wp_set_current_user( $this->user );
135 | $line_items = WC_Helper_Order_Refund::create_refund_line_items( $this->order_id, 1 );
136 | $request = new WP_REST_Request( 'POST', "/wc/v3/orders/$this->order_id/refunds" );
137 | $request->set_body_params( array(
138 | 'amount' => '5.0',
139 | 'reason' => 'This is testing content.',
140 | 'api_refund' => false,
141 | 'line_items' => $line_items,
142 | ) );
143 | $response = $this->server->dispatch( $request );
144 | $data = $response->get_data();
145 | $refund = new WC_Order_Refund( $data['id'] );
146 |
147 | $this->assertEquals( 201, $response->get_status() );
148 | // Verify the API response has correct data
149 | $this->assertArrayHasKey( 'date_created', $data );
150 | $this->assertArrayHasKey( 'line_items', $data );
151 | $this->assertEquals( $data['amount'], '5.00' );
152 | $this->assertEquals( $data['reason'], 'This is testing content.' );
153 | $this->assertEquals( $data['refunded_by'], get_current_user_id() );
154 | $this->assertEquals( 1, count( $data['line_items'] ) );
155 |
156 | // Verify that Note object has correct data
157 | $this->assertEquals( $refund->get_amount(), '5.00' );
158 | $this->assertEquals( $refund->get_reason(), 'This is testing content.' );
159 | $items = $refund->get_items();
160 | $this->assertEquals( 1, count( $items ) );
161 |
162 | $refund->delete();
163 | }
164 | }
--------------------------------------------------------------------------------
/wc-api-dev-class.php:
--------------------------------------------------------------------------------
1 | is_woocommerce_valid() ) {
35 | add_action( 'rest_api_init', array( $this, 'register_routes' ), 10 );
36 | }
37 | }
38 |
39 | /**
40 | * Makes sure WooCommerce is installed and up to date.
41 | */
42 | public function is_woocommerce_valid() {
43 | return (
44 | class_exists( 'woocommerce' ) &&
45 | version_compare(
46 | get_option( 'woocommerce_db_version' ),
47 | WC_API_Dev::WC_MIN_VERSION,
48 | '>='
49 | )
50 | );
51 | }
52 |
53 | /**
54 | * REST API includes.
55 | * New endpoints/controllers can be added here.
56 | *
57 | * Controllers for the feature plugin are prefixed with WC_REST_DEV (rather than WC_REST)
58 | * so that this plugin can play nice with the WooCommerce Core classes.
59 | * They would be renamed on future sync to WooCommerce.
60 | */
61 | public function includes() {
62 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-coupons-controller.php' );
63 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-customer-downloads-controller.php' );
64 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-customers-controller.php' );
65 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-controller.php' );
66 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-continents-controller.php' );
67 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-countries-controller.php' );
68 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-data-currencies-controller.php' );
69 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-orders-controller.php' );
70 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-order-notes-controller.php' );
71 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-order-refunds-controller.php' );
72 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-product-attribute-terms-controller.php' );
73 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-product-attributes-controller.php' );
74 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-product-categories-controller.php' );
75 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-product-reviews-controller.php' );
76 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-product-shipping-classes-controller.php' );
77 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-product-tags-controller.php' );
78 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-products-controller.php' );
79 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-product-variations-controller.php' );
80 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-report-sales-controller.php' );
81 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-report-top-sellers-controller.php' );
82 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-reports-controller.php' );
83 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-settings-controller.php' );
84 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-setting-options-controller.php' );
85 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-shipping-zones-controller.php' );
86 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-shipping-zone-locations-controller.php' );
87 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-shipping-zone-methods-controller.php' );
88 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-tax-classes-controller.php' );
89 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-taxes-controller.php' );
90 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-webhooks-controller.php' );
91 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-system-status-controller.php' );
92 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-system-status-tools-controller.php' );
93 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-shipping-methods-controller.php' );
94 | include_once( dirname( __FILE__ ) . '/api/class-wc-rest-dev-payment-gateways-controller.php' );
95 | }
96 |
97 | /**
98 | * Register REST API routes.
99 | *
100 | * New endpoints/controllers can be added here.
101 | */
102 | public function register_routes() {
103 | $this->includes();
104 | $controllers = array(
105 | 'WC_REST_Dev_Coupons_Controller',
106 | 'WC_REST_Dev_Customer_Downloads_Controller',
107 | 'WC_REST_Dev_Customers_Controller',
108 | 'WC_REST_Dev_Data_Controller',
109 | 'WC_REST_Dev_Data_Continents_Controller',
110 | 'WC_REST_Dev_Data_Countries_Controller',
111 | 'WC_REST_Dev_Data_Currencies_Controller',
112 | 'WC_REST_Dev_Order_Notes_Controller',
113 | 'WC_REST_Dev_Order_Refunds_Controller',
114 | 'WC_REST_Dev_Orders_Controller',
115 | 'WC_REST_Dev_Product_Attribute_Terms_Controller',
116 | 'WC_REST_Dev_Product_Attributes_Controller',
117 | 'WC_REST_Dev_Product_Categories_Controller',
118 | 'WC_REST_Dev_Product_Reviews_Controller',
119 | 'WC_REST_Dev_Product_Shipping_Classes_Controller',
120 | 'WC_REST_Dev_Product_Tags_Controller',
121 | 'WC_REST_Dev_Products_Controller',
122 | 'WC_REST_Dev_Product_Variations_Controller',
123 | 'WC_REST_Dev_Report_Sales_Controller',
124 | 'WC_REST_Dev_Report_Top_Sellers_Controller',
125 | 'WC_REST_Dev_Reports_Controller',
126 | 'WC_REST_Dev_Settings_Controller',
127 | 'WC_REST_Dev_Setting_Options_Controller',
128 | 'WC_REST_Dev_Shipping_Zones_Controller',
129 | 'WC_REST_Dev_Shipping_Zone_Locations_Controller',
130 | 'WC_REST_Dev_Shipping_Zone_Methods_Controller',
131 | 'WC_REST_Dev_Tax_Classes_Controller',
132 | 'WC_REST_Dev_Taxes_Controller',
133 | 'WC_REST_Dev_Webhooks_Controller',
134 | 'WC_REST_Dev_System_Status_Controller',
135 | 'WC_REST_Dev_System_Status_Tools_Controller',
136 | 'WC_REST_Dev_Shipping_Methods_Controller',
137 | 'WC_REST_Dev_Payment_Gateways_Controller',
138 | );
139 |
140 | foreach ( $controllers as $controller ) {
141 | $this->$controller = new $controller();
142 | $this->$controller->register_routes();
143 | }
144 |
145 | }
146 |
147 | /**
148 | * Class instance.
149 | */
150 | public static function instance() {
151 | if ( is_null( self::$instance ) ) {
152 | self::$instance = new self();
153 | }
154 |
155 | return self::$instance;
156 | }
157 | }
158 |
159 | WC_API_Dev::instance();
160 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-data-currencies-controller.php:
--------------------------------------------------------------------------------
1 | namespace, '/' . $this->rest_base, array(
42 | array(
43 | 'methods' => WP_REST_Server::READABLE,
44 | 'callback' => array( $this, 'get_items' ),
45 | 'permission_callback' => array( $this, 'get_items_permissions_check' ),
46 | ),
47 | 'schema' => array( $this, 'get_public_item_schema' ),
48 | ) );
49 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/current', array(
50 | array(
51 | 'methods' => WP_REST_Server::READABLE,
52 | 'callback' => array( $this, 'get_current_item' ),
53 | 'permission_callback' => array( $this, 'get_item_permissions_check' ),
54 | ),
55 | 'schema' => array( $this, 'get_public_item_schema' ),
56 | ) );
57 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]{3})', array(
58 | array(
59 | 'methods' => WP_REST_Server::READABLE,
60 | 'callback' => array( $this, 'get_item' ),
61 | 'permission_callback' => array( $this, 'get_item_permissions_check' ),
62 | 'args' => array(
63 | 'location' => array(
64 | 'description' => __( 'ISO4217 currency code.', 'woocommerce' ),
65 | 'type' => 'string',
66 | ),
67 | ),
68 | ),
69 | 'schema' => array( $this, 'get_public_item_schema' ),
70 | ) );
71 | }
72 |
73 | /**
74 | * Get currency information.
75 | *
76 | * @param string $code
77 | * @param WP_REST_Request $request
78 | * @return array|mixed Response data, ready for insertion into collection data.
79 | */
80 | public function get_currency( $code = false, $request ) {
81 | $currencies = get_woocommerce_currencies();
82 | $data = array();
83 |
84 | if ( ! array_key_exists( $code, $currencies ) ) {
85 | return false;
86 | }
87 |
88 | $currency = array(
89 | 'code' => $code,
90 | 'name' => $currencies[ $code ],
91 | 'symbol' => get_woocommerce_currency_symbol( $code ),
92 | );
93 |
94 | return $currency;
95 | }
96 |
97 | /**
98 | * Return the list of currencies.
99 | *
100 | * @param WP_REST_Request $request
101 | * @return WP_Error|WP_REST_Response
102 | */
103 | public function get_items( $request ) {
104 | $currencies = get_woocommerce_currencies();
105 | foreach ( array_keys( $currencies ) as $code ) {
106 | $currency = $this->get_currency( $code, $request );
107 | $response = $this->prepare_item_for_response( $currency, $request );
108 | $data[] = $this->prepare_response_for_collection( $response );
109 | }
110 |
111 | return rest_ensure_response( $data );
112 | }
113 |
114 | /**
115 | * Return information for a specific currency.
116 | *
117 | * @param WP_REST_Request $request
118 | * @return WP_Error|WP_REST_Response
119 | */
120 | public function get_item( $request ) {
121 | $data = $this->get_currency( strtoupper( $request['currency'] ), $request );
122 | if ( empty( $data ) ) {
123 | return new WP_Error( 'woocommerce_rest_data_invalid_currency', __( 'There are no currencies matching these parameters.', 'woocommerce' ), array( 'status' => 404 ) );
124 | }
125 | return $this->prepare_item_for_response( $data, $request );
126 | }
127 |
128 | /**
129 | * Return information for the current site currency.
130 | *
131 | * @param WP_REST_Request $request
132 | * @return WP_Error|WP_REST_Response
133 | */
134 | public function get_current_item( $request ) {
135 | $currency = get_option( 'woocommerce_currency' );
136 | return $this->prepare_item_for_response( $this->get_currency( $currency, $request ), $request );
137 | }
138 |
139 | /**
140 | * Prepare the data object for response.
141 | *
142 | * @param object $item Data object.
143 | * @param WP_REST_Request $request Request object.
144 | * @return WP_REST_Response $response Response data.
145 | */
146 | public function prepare_item_for_response( $item, $request ) {
147 | $data = $this->add_additional_fields_to_object( $item, $request );
148 | $data = $this->filter_response_by_context( $data, 'view' );
149 | $response = rest_ensure_response( $data );
150 |
151 | $response->add_links( $this->prepare_links( $item ) );
152 |
153 | /**
154 | * Filter currency returned from the API.
155 | *
156 | * @param WP_REST_Response $response The response object.
157 | * @param array $item Currency data.
158 | * @param WP_REST_Request $request Request used to generate the response.
159 | */
160 | return apply_filters( 'woocommerce_rest_prepare_data_currency', $response, $item, $request );
161 | }
162 |
163 | /**
164 | * Prepare links for the request.
165 | *
166 | * @param object $item Data object.
167 | * @return array Links for the given currency.
168 | */
169 | protected function prepare_links( $item ) {
170 | $code = strtoupper( $item['code'] );
171 | $links = array(
172 | 'self' => array(
173 | 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $code ) ),
174 | ),
175 | 'collection' => array(
176 | 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
177 | ),
178 | );
179 |
180 | return $links;
181 | }
182 |
183 |
184 | /**
185 | * Get the currency schema, conforming to JSON Schema.
186 | *
187 | * @return array
188 | */
189 | public function get_item_schema() {
190 | $schema = array(
191 | '$schema' => 'http://json-schema.org/draft-04/schema#',
192 | 'title' => 'data_currencies',
193 | 'type' => 'object',
194 | 'properties' => array(
195 | 'code' => array(
196 | 'type' => 'string',
197 | 'description' => __( 'ISO4217 currency code.', 'woocommerce' ),
198 | 'context' => array( 'view' ),
199 | 'readonly' => true,
200 | ),
201 | 'name' => array(
202 | 'type' => 'string',
203 | 'description' => __( 'Full name of currency.', 'woocommerce' ),
204 | 'context' => array( 'view' ),
205 | 'readonly' => true,
206 | ),
207 | 'symbol' => array(
208 | 'type' => 'string',
209 | 'description' => __( 'Currency symbol.', 'woocommerce' ),
210 | 'context' => array( 'view' ),
211 | 'readonly' => true,
212 | ),
213 | ),
214 | );
215 |
216 | return $this->add_additional_fields_schema( $schema );
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-data-countries-controller.php:
--------------------------------------------------------------------------------
1 | namespace, '/' . $this->rest_base, array(
46 | array(
47 | 'methods' => WP_REST_Server::READABLE,
48 | 'callback' => array( $this, 'get_items' ),
49 | 'permission_callback' => array( $this, 'get_items_permissions_check' ),
50 | ),
51 | 'schema' => array( $this, 'get_public_item_schema' ),
52 | ) );
53 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array(
54 | array(
55 | 'methods' => WP_REST_Server::READABLE,
56 | 'callback' => array( $this, 'get_item' ),
57 | 'permission_callback' => array( $this, 'get_items_permissions_check' ),
58 | 'args' => array(
59 | 'location' => array(
60 | 'description' => __( 'ISO3166 alpha-2 country code.', 'woocommerce' ),
61 | 'type' => 'string',
62 | ),
63 | ),
64 | ),
65 | 'schema' => array( $this, 'get_public_item_schema' ),
66 | ) );
67 | }
68 |
69 | /**
70 | * Get a list of countries and states.
71 | *
72 | * @param string $country_code
73 | * @param WP_REST_Request $request
74 | * @return array|mixed Response data, ready for insertion into collection data.
75 | */
76 | public function get_country( $country_code = false, $request ) {
77 | $countries = WC()->countries->get_countries();
78 | $states = WC()->countries->get_states();
79 | $data = array();
80 |
81 | if ( ! array_key_exists( $country_code, $countries ) ) {
82 | return false;
83 | }
84 |
85 | $country = array(
86 | 'code' => $country_code,
87 | 'name' => $countries[ $country_code ],
88 | );
89 |
90 | $local_states = array();
91 | if ( isset( $states[ $country_code ] ) ) {
92 | foreach ( $states[ $country_code ] as $state_code => $state_name ) {
93 | $local_states[] = array(
94 | 'code' => $state_code,
95 | 'name' => $state_name,
96 | );
97 | }
98 | }
99 | $country['states'] = $local_states;
100 | return $country;
101 | }
102 |
103 | /**
104 | * Return the list of states for all countries.
105 | *
106 | * @since 3.1.0
107 | * @param WP_REST_Request $request
108 | * @return WP_Error|WP_REST_Response
109 | */
110 | public function get_items( $request ) {
111 | $countries = WC()->countries->get_countries();
112 | $data = array();
113 |
114 | foreach ( array_keys( $countries ) as $country_code ) {
115 | $country = $this->get_country( $country_code, $request );
116 | $response = $this->prepare_item_for_response( $country, $request );
117 | $data[] = $this->prepare_response_for_collection( $response );
118 | }
119 |
120 | return rest_ensure_response( $data );
121 | }
122 |
123 | /**
124 | * Return the list of states for a given country.
125 | *
126 | * @since 3.1.0
127 | * @param WP_REST_Request $request
128 | * @return WP_Error|WP_REST_Response
129 | */
130 | public function get_item( $request ) {
131 | $data = $this->get_country( strtoupper( $request['location'] ), $request );
132 | if ( empty( $data ) ) {
133 | return new WP_Error( 'woocommerce_rest_data_invalid_location', __( 'There are no locations matching these parameters.', 'woocommerce' ), array( 'status' => 404 ) );
134 | }
135 | return $this->prepare_item_for_response( $data, $request );
136 | }
137 |
138 | /**
139 | * Prepare the data object for response.
140 | *
141 | * @since 3.1.0
142 | * @param object $item Data object.
143 | * @param WP_REST_Request $request Request object.
144 | * @return WP_REST_Response $response Response data.
145 | */
146 | public function prepare_item_for_response( $item, $request ) {
147 | $data = $this->add_additional_fields_to_object( $item, $request );
148 | $data = $this->filter_response_by_context( $data, 'view' );
149 | $response = rest_ensure_response( $data );
150 |
151 | $response->add_links( $this->prepare_links( $item ) );
152 |
153 | /**
154 | * Filter the states list for a country returned from the API.
155 | *
156 | * Allows modification of the loction data right before it is returned.
157 | *
158 | * @param WP_REST_Response $response The response object.
159 | * @param array $data The original country's states list.
160 | * @param WP_REST_Request $request Request used to generate the response.
161 | */
162 | return apply_filters( 'woocommerce_rest_prepare_data_country', $response, $item, $request );
163 | }
164 |
165 | /**
166 | * Prepare links for the request.
167 | *
168 | * @param object $item Data object.
169 | * @return array Links for the given country.
170 | */
171 | protected function prepare_links( $item ) {
172 | $country_code = strtolower( $item['code'] );
173 | $links = array(
174 | 'self' => array(
175 | 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $country_code ) ),
176 | ),
177 | 'collection' => array(
178 | 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
179 | ),
180 | );
181 |
182 | return $links;
183 | }
184 |
185 |
186 | /**
187 | * Get the location schema, conforming to JSON Schema.
188 | *
189 | * @since 3.1.0
190 | * @return array
191 | */
192 | public function get_item_schema() {
193 | $schema = array(
194 | '$schema' => 'http://json-schema.org/draft-04/schema#',
195 | 'title' => 'data_countries',
196 | 'type' => 'object',
197 | 'properties' => array(
198 | 'code' => array(
199 | 'type' => 'string',
200 | 'description' => __( 'ISO3166 alpha-2 country code.', 'woocommerce' ),
201 | 'context' => array( 'view' ),
202 | 'readonly' => true,
203 | ),
204 | 'name' => array(
205 | 'type' => 'string',
206 | 'description' => __( 'Full name of country.', 'woocommerce' ),
207 | 'context' => array( 'view' ),
208 | 'readonly' => true,
209 | ),
210 | 'states' => array(
211 | 'type' => 'array',
212 | 'description' => __( 'List of states in this country.', 'woocommerce' ),
213 | 'context' => array( 'view' ),
214 | 'readonly' => true,
215 | 'items' => array(
216 | 'type' => 'object',
217 | 'context' => array( 'view' ),
218 | 'readonly' => true,
219 | 'properties' => array(
220 | 'code' => array(
221 | 'type' => 'string',
222 | 'description' => __( 'State code.', 'woocommerce' ),
223 | 'context' => array( 'view' ),
224 | 'readonly' => true,
225 | ),
226 | 'name' => array(
227 | 'type' => 'string',
228 | 'description' => __( 'Full name of state.', 'woocommerce' ),
229 | 'context' => array( 'view' ),
230 | 'readonly' => true,
231 | ),
232 | ),
233 | ),
234 | ),
235 | ),
236 | );
237 |
238 | return $this->add_additional_fields_schema( $schema );
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/tests/unit-tests/order-notes.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Orders_Controller();
28 | $this->user = $this->factory->user->create( array(
29 | 'role' => 'administrator',
30 | ) );
31 | $order = WC_Helper_Order::create_order();
32 | $this->order_id = $order->get_id();
33 | }
34 |
35 | /**
36 | * Cleanup.
37 | */
38 | public function stoppit_and_tidyup() {
39 | wp_delete_post( $this->order_id, true );
40 | foreach ( $this->notes as $note ) {
41 | wc_delete_order_note( $note->comment_ID );
42 | }
43 | $this->notes = array();
44 | }
45 |
46 | /**
47 | * Test route registration.
48 | * @since 3.0.0
49 | */
50 | public function test_register_routes() {
51 | $routes = $this->server->get_routes();
52 | $this->assertArrayHasKey( '/wc/v3/orders/(?P[\d]+)/notes', $routes );
53 | $this->assertArrayHasKey( '/wc/v3/orders/(?P[\d]+)/notes/(?P[\d]+)', $routes );
54 | }
55 |
56 | /**
57 | * Test getting all notes for an order.
58 | * @since 3.0.0
59 | */
60 | public function test_get_items() {
61 | wp_set_current_user( $this->user );
62 |
63 | // Create 3 order notes.
64 | for ( $i = 0; $i < 3; $i++ ) {
65 | $this->notes[] = WC_Helper_Order_Note::create_note( $this->order_id, $this->user );
66 | }
67 |
68 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', "/wc/v3/orders/$this->order_id/notes" ) );
69 | $notes = $response->get_data();
70 |
71 | $this->assertEquals( 200, $response->get_status() );
72 | $this->assertEquals( 3, count( $notes ) );
73 | $this->stoppit_and_tidyup();
74 | }
75 |
76 | /**
77 | * Tests to make sure order notes cannot be viewed without valid permissions.
78 | *
79 | * @since 3.0.0
80 | */
81 | public function test_get_items_without_permission() {
82 | wp_set_current_user( 0 );
83 | $this->notes[] = WC_Helper_Order_Note::create_note( $this->order_id );
84 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', "/wc/v3/orders/$this->order_id/notes" ) );
85 | $this->assertEquals( 401, $response->get_status() );
86 | $this->stoppit_and_tidyup();
87 | }
88 |
89 | /**
90 | * Tests getting a single order note.
91 | * @since 3.0.0
92 | */
93 | public function test_get_item() {
94 | wp_set_current_user( $this->user );
95 | $note = WC_Helper_Order_Note::create_note( $this->order_id, $this->user );
96 | $this->notes[] = $note;
97 | $request = new WP_REST_Request( 'GET', "/wc/v3/orders/$this->order_id/notes/$note->comment_ID" );
98 | $response = $this->server->dispatch( $request );
99 | $data = $response->get_data();
100 |
101 | $this->assertEquals( 200, $response->get_status() );
102 | $this->assertEquals( $note->comment_ID, $data['id'] );
103 | $this->assertArrayHasKey( 'customer_note', $data );
104 | $this->assertArrayHasKey( 'date_created', $data );
105 | $this->assertArrayHasKey( 'author', $data );
106 | $this->assertArrayHasKey( 'note', $data );
107 | $this->assertEquals( $data['author'], 'system' );
108 | $this->assertEquals( $data['note'], 'This is an order note.' );
109 | $this->stoppit_and_tidyup();
110 | }
111 |
112 | /**
113 | * Tests creating an order note by a given user.
114 | * @since 3.0.0
115 | */
116 | public function test_create_note() {
117 | wp_set_current_user( $this->user );
118 | $request = new WP_REST_Request( 'POST', "/wc/v3/orders/$this->order_id/notes" );
119 | $request->set_body_params( array(
120 | 'customer_note' => false,
121 | 'added_by_user' => true,
122 | 'note' => 'This is testing content.',
123 | ) );
124 | $response = $this->server->dispatch( $request );
125 | $data = $response->get_data();
126 | $note = wc_get_order_note( $data['id'] );
127 | $user = get_user_by( 'id', get_current_user_id() );
128 |
129 | $this->assertEquals( 201, $response->get_status() );
130 | // Verify the API response has correct data
131 | $this->assertArrayHasKey( 'customer_note', $data );
132 | $this->assertArrayHasKey( 'date_created', $data );
133 | $this->assertArrayHasKey( 'note', $data );
134 | $this->assertArrayHasKey( 'author', $data );
135 | $this->assertEquals( $data['note'], 'This is testing content.' );
136 | $this->assertEquals( $data['author'], $user->display_name );
137 |
138 | // Verify that Note object has correct data
139 | $this->assertEquals( $note->customer_note, false );
140 | $this->assertEquals( $note->added_by, $user->display_name );
141 | $this->assertEquals( $note->content, 'This is testing content.' );
142 |
143 | wc_delete_order_note( $data['id'] );
144 | }
145 |
146 | /**
147 | * Tests creating an order note by the "system".
148 | * @since 3.0.0
149 | */
150 | public function test_create_system_note() {
151 | wp_set_current_user( $this->user );
152 | $request = new WP_REST_Request( 'POST', "/wc/v3/orders/$this->order_id/notes" );
153 | $request->set_body_params( array(
154 | 'customer_note' => true,
155 | 'note' => 'This is testing content.',
156 | ) );
157 | $response = $this->server->dispatch( $request );
158 | $data = $response->get_data();
159 | $note = wc_get_order_note( $data['id'] );
160 |
161 | $this->assertEquals( 201, $response->get_status() );
162 | // Verify the API response has correct data
163 | $this->assertArrayHasKey( 'customer_note', $data );
164 | $this->assertArrayHasKey( 'date_created', $data );
165 | $this->assertArrayHasKey( 'note', $data );
166 | $this->assertArrayHasKey( 'author', $data );
167 | $this->assertEquals( $data['note'], 'This is testing content.' );
168 | $this->assertEquals( $data['author'], 'system' );
169 |
170 | // Verify that Note object has correct data
171 | $this->assertEquals( $note->customer_note, true );
172 | $this->assertEquals( $note->added_by, 'system' );
173 | $this->assertEquals( $note->content, 'This is testing content.' );
174 |
175 | wc_delete_order_note( $data['id'] );
176 | }
177 |
178 | /**
179 | * Tests creating an order note without required fields.
180 | * @since 3.0.0
181 | */
182 | public function test_create_order_note_invalid_fields() {
183 | wp_set_current_user( $this->user );
184 | $request = new WP_REST_Request( 'POST', "/wc/v3/orders/$this->order_id/notes" );
185 | $request->set_body_params( array(
186 | 'customer_note' => false,
187 | ) );
188 | $response = $this->server->dispatch( $request );
189 | $this->assertEquals( 400, $response->get_status() );
190 | }
191 |
192 | /**
193 | * Test deleting an order note.
194 | * @since 3.0.0
195 | */
196 | public function test_delete_order_note() {
197 | wp_set_current_user( $this->user );
198 | $note = WC_Helper_Order_Note::create_note( $this->order_id, $this->user );
199 | $request = new WP_REST_Request( 'DELETE', "/wc/v3/orders/$this->order_id/notes/$note->comment_ID" );
200 | $request->set_param( 'force', true );
201 | $response = $this->server->dispatch( $request );
202 | $this->assertEquals( 200, $response->get_status() );
203 | $this->assertEquals( null, wc_get_order_note( $note->comment_ID ) );
204 | }
205 |
206 | /**
207 | * Test deleting an order note without permission/creds.
208 | * @since 3.0.0
209 | */
210 | public function test_delete_order_note_without_permission() {
211 | wp_set_current_user( 0 );
212 | $note = WC_Helper_Order_Note::create_note( $this->order_id );
213 | $request = new WP_REST_Request( 'DELETE', "/wc/v3/orders/$this->order_id/notes/$note->comment_ID" );
214 | $request->set_param( 'force', true );
215 | $response = $this->server->dispatch( $request );
216 | $this->assertEquals( 401, $response->get_status() );
217 | wc_delete_order_note( $note->comment_ID );
218 | }
219 |
220 | /**
221 | * Test deleting an order note with an invalid id.
222 | *
223 | * @since 3.0.0
224 | */
225 | public function test_delete_order_note_invalid_id() {
226 | wp_set_current_user( $this->user );
227 | $request = new WP_REST_Request( 'DELETE', "/wc/v3/orders/$this->order_id/notes/9999999" );
228 | $request->set_param( 'force', true );
229 | $response = $this->server->dispatch( $request );
230 | $this->assertEquals( 404, $response->get_status() );
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-payment-gateways-controller.php:
--------------------------------------------------------------------------------
1 | $gateway->id,
40 | 'title' => $gateway->title,
41 | 'description' => $gateway->description,
42 | 'order' => isset( $order[ $gateway->id ] ) ? $order[ $gateway->id ] : '',
43 | 'enabled' => ( 'yes' === $gateway->enabled ),
44 | 'method_title' => $gateway->get_method_title(),
45 | 'method_description' => $gateway->get_method_description(),
46 | 'method_supports' => $gateway->supports,
47 | 'settings' => $this->get_settings( $gateway ),
48 | );
49 |
50 | $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
51 | $data = $this->add_additional_fields_to_object( $item, $request );
52 | $data = $this->filter_response_by_context( $data, $context );
53 |
54 | $response = rest_ensure_response( $data );
55 | $response->add_links( $this->prepare_links( $gateway, $request ) );
56 |
57 | /**
58 | * Filter payment gateway objects returned from the REST API.
59 | *
60 | * @param WP_REST_Response $response The response object.
61 | * @param WC_Payment_Gateway $gateway Payment gateway object.
62 | * @param WP_REST_Request $request Request object.
63 | */
64 | return apply_filters( 'woocommerce_rest_prepare_payment_gateway', $response, $gateway, $request );
65 | }
66 |
67 | /**
68 | * Return settings associated with this payment gateway.
69 | *
70 | * @param WC_Payment_Gateway $gateway
71 | *
72 | * @return array
73 | */
74 | public function get_settings( $gateway ) {
75 | $settings = array();
76 | $gateway->init_form_fields();
77 | foreach ( $gateway->form_fields as $id => $field ) {
78 | // Make sure we at least have a title and type
79 | if ( empty( $field['title'] ) || empty( $field['type'] ) ) {
80 | continue;
81 | }
82 | // Ignore 'enabled' and 'description' which get included elsewhere.
83 | if ( in_array( $id, array( 'enabled', 'description' ) ) ) {
84 | continue;
85 | }
86 | $data = array(
87 | 'id' => $id,
88 | 'label' => empty( $field['label'] ) ? $field['title'] : $field['label'],
89 | 'description' => empty( $field['description'] ) ? '' : $field['description'],
90 | 'type' => $field['type'],
91 | 'value' => empty( $gateway->settings[ $id ] ) ? '' : $gateway->settings[ $id ],
92 | 'default' => empty( $field['default'] ) ? '' : $field['default'],
93 | 'tip' => empty( $field['description'] ) ? '' : $field['description'],
94 | 'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'],
95 | );
96 | if ( ! empty( $field['options'] ) ) {
97 | $data['options'] = $field['options'];
98 | }
99 | $settings[ $id ] = $data;
100 | }
101 | return $settings;
102 | }
103 |
104 | /**
105 | * Get the payment gateway schema, conforming to JSON Schema.
106 | *
107 | * @return array
108 | */
109 | public function get_item_schema() {
110 | $schema = array(
111 | '$schema' => 'http://json-schema.org/draft-04/schema#',
112 | 'title' => 'payment_gateway',
113 | 'type' => 'object',
114 | 'properties' => array(
115 | 'id' => array(
116 | 'description' => __( 'Payment gateway ID.', 'woocommerce' ),
117 | 'type' => 'string',
118 | 'context' => array( 'view', 'edit' ),
119 | 'readonly' => true,
120 | ),
121 | 'title' => array(
122 | 'description' => __( 'Payment gateway title on checkout.', 'woocommerce' ),
123 | 'type' => 'string',
124 | 'context' => array( 'view', 'edit' ),
125 | ),
126 | 'description' => array(
127 | 'description' => __( 'Payment gateway description on checkout.', 'woocommerce' ),
128 | 'type' => 'string',
129 | 'context' => array( 'view', 'edit' ),
130 | ),
131 | 'order' => array(
132 | 'description' => __( 'Payment gateway sort order.', 'woocommerce' ),
133 | 'type' => 'integer',
134 | 'context' => array( 'view', 'edit' ),
135 | 'arg_options' => array(
136 | 'sanitize_callback' => 'absint',
137 | ),
138 | ),
139 | 'enabled' => array(
140 | 'description' => __( 'Payment gateway enabled status.', 'woocommerce' ),
141 | 'type' => 'boolean',
142 | 'context' => array( 'view', 'edit' ),
143 | ),
144 | 'method_title' => array(
145 | 'description' => __( 'Payment gateway method title.', 'woocommerce' ),
146 | 'type' => 'string',
147 | 'context' => array( 'view', 'edit' ),
148 | 'readonly' => true,
149 | ),
150 | 'method_description' => array(
151 | 'description' => __( 'Payment gateway method description.', 'woocommerce' ),
152 | 'type' => 'string',
153 | 'context' => array( 'view', 'edit' ),
154 | 'readonly' => true,
155 | ),
156 | 'method_supports' => array(
157 | 'description' => __( 'Supported features for this payment gateway.', 'woocommerce' ),
158 | 'type' => 'array',
159 | 'context' => array( 'view', 'edit' ),
160 | 'readonly' => true,
161 | 'items' => array(
162 | 'type' => 'string',
163 | ),
164 | ),
165 | 'settings' => array(
166 | 'description' => __( 'Payment gateway settings.', 'woocommerce' ),
167 | 'type' => 'object',
168 | 'context' => array( 'view', 'edit' ),
169 | 'properties' => array(
170 | 'id' => array(
171 | 'description' => __( 'A unique identifier for the setting.', 'woocommerce' ),
172 | 'type' => 'string',
173 | 'context' => array( 'view', 'edit' ),
174 | 'readonly' => true,
175 | ),
176 | 'label' => array(
177 | 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce' ),
178 | 'type' => 'string',
179 | 'context' => array( 'view', 'edit' ),
180 | 'readonly' => true,
181 | ),
182 | 'description' => array(
183 | 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce' ),
184 | 'type' => 'string',
185 | 'context' => array( 'view', 'edit' ),
186 | 'readonly' => true,
187 | ),
188 | 'type' => array(
189 | 'description' => __( 'Type of setting.', 'woocommerce' ),
190 | 'type' => 'string',
191 | 'context' => array( 'view', 'edit' ),
192 | 'enum' => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox' ),
193 | 'readonly' => true,
194 | ),
195 | 'value' => array(
196 | 'description' => __( 'Setting value.', 'woocommerce' ),
197 | 'type' => 'string',
198 | 'context' => array( 'view', 'edit' ),
199 | ),
200 | 'default' => array(
201 | 'description' => __( 'Default value for the setting.', 'woocommerce' ),
202 | 'type' => 'string',
203 | 'context' => array( 'view', 'edit' ),
204 | 'readonly' => true,
205 | ),
206 | 'tip' => array(
207 | 'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce' ),
208 | 'type' => 'string',
209 | 'context' => array( 'view', 'edit' ),
210 | 'readonly' => true,
211 | ),
212 | 'placeholder' => array(
213 | 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce' ),
214 | 'type' => 'string',
215 | 'context' => array( 'view', 'edit' ),
216 | 'readonly' => true,
217 | ),
218 | ),
219 | ),
220 | ),
221 | );
222 |
223 | return $this->add_additional_fields_schema( $schema );
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-setting-options-controller.php:
--------------------------------------------------------------------------------
1 | 'woocommerce_store_address',
31 | 'type' => 'text',
32 | 'option_key' => 'woocommerce_store_address',
33 | 'default' => '',
34 | ),
35 | array(
36 | 'id' => 'woocommerce_store_address_2',
37 | 'type' => 'text',
38 | 'option_key' => 'woocommerce_store_address_2',
39 | 'default' => '',
40 | ),
41 | array(
42 | 'id' => 'woocommerce_store_city',
43 | 'type' => 'text',
44 | 'option_key' => 'woocommerce_store_city',
45 | 'default' => '',
46 | ),
47 | array(
48 | 'id' => 'woocommerce_store_postcode',
49 | 'type' => 'text',
50 | 'option_key' => 'woocommerce_store_postcode',
51 | 'default' => '',
52 | ),
53 | );
54 |
55 | // For each of the new settings, make sure the setting id doesn't
56 | // already exist in the settings array and then add it
57 | $ids = array_column( $settings, 'id' );
58 | foreach ( $new_settings as $new_setting ) {
59 | if ( ! in_array( $new_setting['id'], $ids ) ) {
60 | $settings[] = $new_setting;
61 | }
62 | }
63 |
64 | return $settings;
65 | }
66 | add_filter( 'woocommerce_settings-general', 'wc_rest_dev_add_address_settings_to_settings_general', 999 );
67 |
68 | /**
69 | * REST API Setting Options controller class.
70 | *
71 | * @package WooCommerce/API
72 | */
73 | class WC_REST_Dev_Setting_Options_Controller extends WC_REST_Setting_Options_Controller {
74 |
75 | /**
76 | * WP REST API namespace/version.
77 | */
78 | protected $namespace = 'wc/v3';
79 |
80 | /**
81 | * Get setting data.
82 | *
83 | * @param string $group_id Group ID.
84 | * @param string $setting_id Setting ID.
85 | * @return stdClass|WP_Error
86 | */
87 | public function get_setting( $group_id, $setting_id ) {
88 | $setting = parent::get_setting( $group_id, $setting_id );
89 | if ( is_wp_error( $setting ) ) {
90 | return $setting;
91 | }
92 | $setting['group_id'] = $group_id;
93 | return $setting;
94 | }
95 |
96 | /**
97 | * Callback for allowed keys for each setting response.
98 | *
99 | * @param string $key Key to check
100 | * @return boolean
101 | */
102 | public function allowed_setting_keys( $key ) {
103 | return in_array( $key, array(
104 | 'id',
105 | 'group_id',
106 | 'label',
107 | 'description',
108 | 'default',
109 | 'tip',
110 | 'placeholder',
111 | 'type',
112 | 'options',
113 | 'value',
114 | 'option_key',
115 | ) );
116 | }
117 |
118 | /**
119 | * Get all settings in a group.
120 | *
121 | * @param string $group_id Group ID.
122 | * @return array|WP_Error
123 | */
124 | public function get_group_settings( $group_id ) {
125 | if ( empty( $group_id ) ) {
126 | return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'woocommerce' ), array( 'status' => 404 ) );
127 | }
128 |
129 | $settings = apply_filters( 'woocommerce_settings-' . $group_id, array() );
130 |
131 | if ( empty( $settings ) ) {
132 | return new WP_Error( 'rest_setting_setting_group_invalid', __( 'Invalid setting group.', 'woocommerce' ), array( 'status' => 404 ) );
133 | }
134 |
135 | $filtered_settings = array();
136 | foreach ( $settings as $setting ) {
137 | $option_key = $setting['option_key'];
138 | $setting = $this->filter_setting( $setting );
139 | $default = isset( $setting['default'] ) ? $setting['default'] : '';
140 | // Get the option value
141 | if ( is_array( $option_key ) ) {
142 | $option = get_option( $option_key[0] );
143 | $setting['value'] = isset( $option[ $option_key[1] ] ) ? $option[ $option_key[1] ] : $default;
144 | } else {
145 | $admin_setting_value = WC_Admin_Settings::get_option( $option_key, $default );
146 | $setting['value'] = $admin_setting_value;
147 | }
148 |
149 | if ( 'multi_select_countries' === $setting['type'] ) {
150 | $setting['options'] = WC()->countries->get_countries();
151 | $setting['type'] = 'multiselect';
152 | } elseif ( 'single_select_country' === $setting['type'] ) {
153 | $setting['type'] = 'select';
154 | $setting['options'] = $this->get_countries_and_states();
155 | } elseif ( 'single_select_page' === $setting['type'] ) {
156 | $pages = get_pages( array( 'sort_column' => 'menu_order', 'sort_order' => 'ASC', 'hierarchical' => 0 ) );
157 | $options = array();
158 | foreach ( $pages as $page ) {
159 | $options[ $page->ID ] = ! empty( $page->post_title ) ? $page->post_title : '#' . $page->ID;
160 | }
161 | $setting['type'] = 'select';
162 | $setting['options'] = $options;
163 | }
164 |
165 |
166 | $filtered_settings[] = $setting;
167 | }
168 |
169 | return $filtered_settings;
170 | }
171 |
172 | /**
173 | * Returns a list of countries and states for use in the base location setting.
174 | *
175 | * @since 3.0.7
176 | * @return array Array of states and countries.
177 | */
178 | private function get_countries_and_states() {
179 | $countries = WC()->countries->get_countries();
180 | if ( ! $countries ) {
181 | return array();
182 | }
183 | $output = array();
184 | foreach ( $countries as $key => $value ) {
185 | if ( $states = WC()->countries->get_states( $key ) ) {
186 | foreach ( $states as $state_key => $state_value ) {
187 | $output[ $key . ':' . $state_key ] = $value . ' - ' . $state_value;
188 | }
189 | } else {
190 | $output[ $key ] = $value;
191 | }
192 | }
193 | return $output;
194 | }
195 |
196 | /**
197 | * Get the settings schema, conforming to JSON Schema.
198 | *
199 | * @return array
200 | */
201 | public function get_item_schema() {
202 | $schema = array(
203 | '$schema' => 'http://json-schema.org/draft-04/schema#',
204 | 'title' => 'setting',
205 | 'type' => 'object',
206 | 'properties' => array(
207 | 'id' => array(
208 | 'description' => __( 'A unique identifier for the setting.', 'woocommerce' ),
209 | 'type' => 'string',
210 | 'arg_options' => array(
211 | 'sanitize_callback' => 'sanitize_title',
212 | ),
213 | 'context' => array( 'view', 'edit' ),
214 | 'readonly' => true,
215 | ),
216 | 'group_id' => array(
217 | 'description' => __( 'An identifier for the group this setting belongs to.', 'woocommerce' ),
218 | 'type' => 'string',
219 | 'arg_options' => array(
220 | 'sanitize_callback' => 'sanitize_title',
221 | ),
222 | 'context' => array( 'view', 'edit' ),
223 | 'readonly' => true,
224 | ),
225 | 'label' => array(
226 | 'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce' ),
227 | 'type' => 'string',
228 | 'arg_options' => array(
229 | 'sanitize_callback' => 'sanitize_text_field',
230 | ),
231 | 'context' => array( 'view', 'edit' ),
232 | 'readonly' => true,
233 | ),
234 | 'description' => array(
235 | 'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce' ),
236 | 'type' => 'string',
237 | 'arg_options' => array(
238 | 'sanitize_callback' => 'sanitize_text_field',
239 | ),
240 | 'context' => array( 'view', 'edit' ),
241 | 'readonly' => true,
242 | ),
243 | 'value' => array(
244 | 'description' => __( 'Setting value.', 'woocommerce' ),
245 | 'type' => 'mixed',
246 | 'context' => array( 'view', 'edit' ),
247 | ),
248 | 'default' => array(
249 | 'description' => __( 'Default value for the setting.', 'woocommerce' ),
250 | 'type' => 'mixed',
251 | 'context' => array( 'view', 'edit' ),
252 | 'readonly' => true,
253 | ),
254 | 'tip' => array(
255 | 'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce' ),
256 | 'type' => 'string',
257 | 'arg_options' => array(
258 | 'sanitize_callback' => 'sanitize_text_field',
259 | ),
260 | 'context' => array( 'view', 'edit' ),
261 | 'readonly' => true,
262 | ),
263 | 'placeholder' => array(
264 | 'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce' ),
265 | 'type' => 'string',
266 | 'arg_options' => array(
267 | 'sanitize_callback' => 'sanitize_text_field',
268 | ),
269 | 'context' => array( 'view', 'edit' ),
270 | 'readonly' => true,
271 | ),
272 | 'type' => array(
273 | 'description' => __( 'Type of setting.', 'woocommerce' ),
274 | 'type' => 'string',
275 | 'arg_options' => array(
276 | 'sanitize_callback' => 'sanitize_text_field',
277 | ),
278 | 'context' => array( 'view', 'edit' ),
279 | 'enum' => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox' ),
280 | 'readonly' => true,
281 | ),
282 | 'options' => array(
283 | 'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'woocommerce' ),
284 | 'type' => 'object',
285 | 'context' => array( 'view', 'edit' ),
286 | 'readonly' => true,
287 | ),
288 | ),
289 | );
290 |
291 | return $this->add_additional_fields_schema( $schema );
292 | }
293 |
294 | }
295 |
--------------------------------------------------------------------------------
/tests/unit-tests/payment-gateways.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Payment_Gateways_Controller();
17 | $this->user = $this->factory->user->create( array(
18 | 'role' => 'administrator',
19 | ) );
20 | }
21 |
22 | /**
23 | * Test route registration.
24 | *
25 | * @since 3.0.0
26 | */
27 | public function test_register_routes() {
28 | $routes = $this->server->get_routes();
29 | $this->assertArrayHasKey( '/wc/v3/payment_gateways', $routes );
30 | $this->assertArrayHasKey( '/wc/v3/payment_gateways/(?P[\w-]+)', $routes );
31 | }
32 |
33 | /**
34 | * Test getting all payment gateways.
35 | *
36 | * @since 3.0.0
37 | */
38 | public function test_get_payment_gateways() {
39 | wp_set_current_user( $this->user );
40 |
41 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways' ) );
42 | $gateways = $response->get_data();
43 |
44 | $wc_gateways = WC()->payment_gateways->payment_gateways();
45 |
46 | $this->assertEquals( 200, $response->get_status() );
47 | $this->assertEquals( count( $wc_gateways ), count( $gateways ) );
48 | $this->assertNotEmpty( $gateways[0]['id'] );
49 | }
50 |
51 | /**
52 | * Tests to make sure payment gateways cannot viewed without valid permissions.
53 | *
54 | * @since 3.0.0
55 | */
56 | public function test_get_payment_gateways_without_permission() {
57 | wp_set_current_user( 0 );
58 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways' ) );
59 | $this->assertEquals( 401, $response->get_status() );
60 | }
61 |
62 | /**
63 | * Test getting a single payment gateway.
64 | *
65 | * @since 3.0.0
66 | */
67 | public function test_get_payment_gateway() {
68 | wp_set_current_user( $this->user );
69 |
70 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways/paypal' ) );
71 | $paypal = $response->get_data();
72 |
73 | $this->assertEquals( 200, $response->get_status() );
74 | $this->assertEquals( 'paypal', $paypal['id'] );
75 | $this->assertEquals( 'PayPal', $paypal['title'] );
76 | }
77 |
78 | /**
79 | * Test getting a payment gateway without valid permissions.
80 | *
81 | * @since 3.0.0
82 | */
83 | public function test_get_payment_gateway_without_permission() {
84 | wp_set_current_user( 0 );
85 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways/paypal' ) );
86 | $this->assertEquals( 401, $response->get_status() );
87 | }
88 |
89 | /**
90 | * Test getting a payment gateway with an invalid id.
91 | *
92 | * @since 3.0.0
93 | */
94 | public function test_get_payment_gateway_invalid_id() {
95 | wp_set_current_user( $this->user );
96 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways/totally_fake_method' ) );
97 | $this->assertEquals( 404, $response->get_status() );
98 | }
99 |
100 | /**
101 | * Test updating a single payment gateway.
102 | *
103 | * @since 3.0.0
104 | */
105 | public function test_update_payment_gateway() {
106 | wp_set_current_user( $this->user );
107 |
108 | // Test defaults
109 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways/paypal' ) );
110 | $paypal = $response->get_data();
111 |
112 | $this->assertEquals( 'PayPal', $paypal['settings']['title']['value'] );
113 | $this->assertEquals( 'admin@example.org', $paypal['settings']['email']['value'] );
114 | $this->assertEquals( 'no', $paypal['settings']['testmode']['value'] );
115 |
116 | // test updating single setting
117 | $request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
118 | $request->set_body_params( array(
119 | 'settings' => array(
120 | 'email' => 'woo@woo.local',
121 | ),
122 | ) );
123 | $response = $this->server->dispatch( $request );
124 | $paypal = $response->get_data();
125 |
126 | $this->assertEquals( 200, $response->get_status() );
127 | $this->assertEquals( 'PayPal', $paypal['settings']['title']['value'] );
128 | $this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
129 | $this->assertEquals( 'no', $paypal['settings']['testmode']['value'] );
130 |
131 | // test updating multiple settings
132 | $request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
133 | $request->set_body_params( array(
134 | 'settings' => array(
135 | 'testmode' => 'yes',
136 | 'title' => 'PayPal - New Title',
137 | ),
138 | ) );
139 | $response = $this->server->dispatch( $request );
140 | $paypal = $response->get_data();
141 |
142 | $this->assertEquals( 200, $response->get_status() );
143 | $this->assertEquals( 'PayPal - New Title', $paypal['settings']['title']['value'] );
144 | $this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
145 | $this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] );
146 |
147 | // Test other parameters, and recheck settings
148 | $request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
149 | $request->set_body_params( array(
150 | 'enabled' => false,
151 | 'order' => 2,
152 | ) );
153 | $response = $this->server->dispatch( $request );
154 | $paypal = $response->get_data();
155 |
156 | $this->assertFalse( $paypal['enabled'] );
157 | $this->assertEquals( 2, $paypal['order'] );
158 | $this->assertEquals( 'PayPal - New Title', $paypal['settings']['title']['value'] );
159 | $this->assertEquals( 'woo@woo.local', $paypal['settings']['email']['value'] );
160 | $this->assertEquals( 'yes', $paypal['settings']['testmode']['value'] );
161 |
162 | // test bogus
163 | $request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
164 | $request->set_body_params( array(
165 | 'settings' => array(
166 | 'paymentaction' => 'afasfasf',
167 | ),
168 | ) );
169 | $response = $this->server->dispatch( $request );
170 | $this->assertEquals( 400, $response->get_status() );
171 |
172 | $request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
173 | $request->set_body_params( array(
174 | 'settings' => array(
175 | 'paymentaction' => 'authorization',
176 | ),
177 | ) );
178 | $response = $this->server->dispatch( $request );
179 | $paypal = $response->get_data();
180 | $this->assertEquals( 'authorization', $paypal['settings']['paymentaction']['value'] );
181 | }
182 |
183 | /**
184 | * Test updating a payment gateway without valid permissions.
185 | *
186 | * @since 3.0.0
187 | */
188 | public function test_update_payment_gateway_without_permission() {
189 | wp_set_current_user( 0 );
190 | $request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/paypal' );
191 | $request->set_body_params( array(
192 | 'settings' => array(
193 | 'testmode' => 'yes',
194 | 'title' => 'PayPal - New Title',
195 | ),
196 | ) );
197 | $response = $this->server->dispatch( $request );
198 | $this->assertEquals( 401, $response->get_status() );
199 | }
200 |
201 | /**
202 | * Test updating a payment gateway with an invalid id.
203 | *
204 | * @since 3.0.0
205 | */
206 | public function test_update_payment_gateway_invalid_id() {
207 | wp_set_current_user( $this->user );
208 | $request = new WP_REST_Request( 'POST', '/wc/v3/payment_gateways/totally_fake_method' );
209 | $request->set_body_params( array(
210 | 'enabled' => true,
211 | ) );
212 | $response = $this->server->dispatch( $request );
213 | $this->assertEquals( 404, $response->get_status() );
214 | }
215 |
216 | /**
217 | * Test the payment gateway schema.
218 | *
219 | * @since 3.0.0
220 | */
221 | public function test_payment_gateway_schema() {
222 | wp_set_current_user( $this->user );
223 |
224 | $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/payment_gateways' );
225 | $response = $this->server->dispatch( $request );
226 | $data = $response->get_data();
227 | $properties = $data['schema']['properties'];
228 |
229 | $this->assertEquals( 9, count( $properties ) );
230 | $this->assertArrayHasKey( 'id', $properties );
231 | $this->assertArrayHasKey( 'title', $properties );
232 | $this->assertArrayHasKey( 'description', $properties );
233 | $this->assertArrayHasKey( 'order', $properties );
234 | $this->assertArrayHasKey( 'enabled', $properties );
235 | $this->assertArrayHasKey( 'method_title', $properties );
236 | $this->assertArrayHasKey( 'method_description', $properties );
237 | $this->assertArrayHasKey( 'method_supports', $properties );
238 | $this->assertArrayHasKey( 'settings', $properties );
239 | }
240 |
241 | /**
242 | * Loads a particular gateway's settings so we can correctly test API output.
243 | *
244 | * @since 3.0.0
245 | * @param string $gateway_class Name of WC_Payment_Gateway class.
246 | */
247 | private function get_settings( $gateway_class ) {
248 | $gateway = new $gateway_class;
249 | $settings = array();
250 | $gateway->init_form_fields();
251 | foreach ( $gateway->form_fields as $id => $field ) {
252 | // Make sure we at least have a title and type
253 | if ( empty( $field['title'] ) || empty( $field['type'] ) ) {
254 | continue;
255 | }
256 | // Ignore 'title' settings/fields -- they are UI only
257 | if ( 'title' === $field['type'] ) {
258 | continue;
259 | }
260 | $data = array(
261 | 'id' => $id,
262 | 'label' => empty( $field['label'] ) ? $field['title'] : $field['label'],
263 | 'description' => empty( $field['description'] ) ? '' : $field['description'],
264 | 'type' => $field['type'],
265 | 'value' => $gateway->settings[ $id ],
266 | 'default' => empty( $field['default'] ) ? '' : $field['default'],
267 | 'tip' => empty( $field['description'] ) ? '' : $field['description'],
268 | 'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'],
269 | );
270 | if ( ! empty( $field['options'] ) ) {
271 | $data['options'] = $field['options'];
272 | }
273 | $settings[ $id ] = $data;
274 | }
275 | return $settings;
276 | }
277 |
278 | }
279 |
--------------------------------------------------------------------------------
/tests/unit-tests/data.php:
--------------------------------------------------------------------------------
1 | user = $this->factory->user->create( array(
16 | 'role' => 'administrator',
17 | ) );
18 | }
19 |
20 | /**
21 | * Test route registration.
22 | *
23 | * @since 3.1.0
24 | */
25 | public function test_register_routes() {
26 | $routes = $this->server->get_routes();
27 | $this->assertArrayHasKey( '/wc/v3/data', $routes );
28 | $this->assertArrayHasKey( '/wc/v3/data/continents', $routes );
29 | $this->assertArrayHasKey( '/wc/v3/data/countries', $routes );
30 | $this->assertArrayHasKey( '/wc/v3/data/currencies', $routes );
31 | $this->assertArrayHasKey( '/wc/v3/data/currencies/current', $routes );
32 | $this->assertArrayHasKey( '/wc/v3/data/currencies/(?P[\w-]{3})', $routes );
33 | }
34 |
35 | /**
36 | * Test getting the data index.
37 | * @since 3.1.0
38 | */
39 | public function test_get_index() {
40 | wp_set_current_user( $this->user );
41 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data' ) );
42 | $index = $response->get_data();
43 | $this->assertEquals( 200, $response->get_status() );
44 | $this->assertCount( 4, $index );
45 | $this->assertEquals( 'continents', $index[0]['slug'] );
46 | $this->assertEquals( 'countries', $index[1]['slug'] );
47 | $this->assertEquals( 'counts', $index[2]['slug'] );
48 | $this->assertEquals( 'currencies', $index[3]['slug'] );
49 | }
50 |
51 | /**
52 | * Test getting locations.
53 | * @since 3.1.0
54 | */
55 | public function test_get_locations() {
56 | wp_set_current_user( $this->user );
57 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/continents' ) );
58 | $locations = $response->get_data();
59 | $this->assertEquals( 200, $response->get_status() );
60 | $this->assertTrue( is_array( $locations ) );
61 | $this->assertGreaterThan( 1, count( $locations ) );
62 | $this->assertNotEmpty( $locations[0]['code'] );
63 | $this->assertNotEmpty( $locations[0]['name'] );
64 | $this->assertNotEmpty( $locations[0]['countries'] );
65 | $this->assertNotEmpty( $locations[0]['_links'] );
66 |
67 | // Make sure North America is in the response
68 | $NA_index = -1;
69 | foreach( $locations as $index => $continent ) {
70 | if ( "NA" === $continent['code'] ) {
71 | $NA_index = $index;
72 | }
73 | }
74 | $this->assertGreaterThan( -1, $NA_index );
75 |
76 | // Make sure the United States is in the North America part of the response
77 | $US_index = -1;
78 | foreach( $locations[ $NA_index ]['countries'] as $index => $country ) {
79 | if ( "US" === $country['code'] ) {
80 | $US_index = $index;
81 | }
82 | }
83 | $this->assertGreaterThan( -1, $US_index );
84 |
85 | // Lastly, assertNotEmpty US has currency, dimensions, etc.
86 | $this->assertNotEmpty( $locations[ $NA_index ]['countries'][ $US_index ]['currency_code'] );
87 | $this->assertNotEmpty( $locations[ $NA_index ]['countries'][ $US_index ]['currency_pos'] );
88 | $this->assertNotEmpty( $locations[ $NA_index ]['countries'][ $US_index ]['thousand_sep'] );
89 | $this->assertNotEmpty( $locations[ $NA_index ]['countries'][ $US_index ]['decimal_sep'] );
90 | $this->assertNotEmpty( $locations[ $NA_index ]['countries'][ $US_index ]['num_decimals'] );
91 | $this->assertNotEmpty( $locations[ $NA_index ]['countries'][ $US_index ]['dimension_unit'] );
92 | $this->assertNotEmpty( $locations[ $NA_index ]['countries'][ $US_index ]['weight_unit'] );
93 | }
94 |
95 | /**
96 | * Test getting locations restricted to one continent.
97 | * @since 3.1.0
98 | */
99 | public function test_get_locations_from_continent() {
100 | wp_set_current_user( $this->user );
101 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/continents/na' ) );
102 | $locations = $response->get_data();
103 | $this->assertEquals( 200, $response->get_status() );
104 | $this->assertTrue( is_array( $locations ) );
105 | $this->assertEquals( 'NA', $locations['code'] );
106 | $this->assertNotEmpty( $locations['name'] );
107 | $this->assertNotEmpty( $locations['countries'] );
108 | $links = $response->get_links();
109 | $this->assertCount( 2, $links );
110 | }
111 |
112 | /**
113 | * Test getting locations with no country specified
114 | * @since 3.1.0
115 | */
116 | public function test_get_locations_all_countries() {
117 | wp_set_current_user( $this->user );
118 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/countries' ) );
119 | $locations = $response->get_data();
120 | $this->assertEquals( 200, $response->get_status() );
121 | $this->assertGreaterThan( 1, count( $locations ) );
122 | $this->assertNotEmpty( $locations[0]['code'] );
123 | $this->assertNotEmpty( $locations[0]['name'] );
124 | $this->assertArrayHasKey( 'states', $locations[0] );
125 | $this->assertNotEmpty( $locations[0]['_links'] );
126 | }
127 |
128 | /**
129 | * Test getting locations restricted to one country.
130 | * Use a country (US) that includes locale info
131 | * @since 3.1.0
132 | */
133 | public function test_get_locations_from_country() {
134 | wp_set_current_user( $this->user );
135 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/countries/us' ) );
136 | $locations = $response->get_data();
137 | $this->assertEquals( 200, $response->get_status() );
138 | $this->assertTrue( is_array( $locations ) );
139 | $this->assertEquals( 'US', $locations['code'] );
140 | $this->assertNotEmpty( $locations['name'] );
141 | $this->assertCount( 54, $locations['states'] );
142 | $links = $response->get_links();
143 | $this->assertCount( 2, $links );
144 | }
145 |
146 | /**
147 | * Test getting locations from an invalid code.
148 | * @since 3.1.0
149 | */
150 | public function test_get_locations_from_invalid_continent() {
151 | wp_set_current_user( $this->user );
152 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/continents/xx' ) );
153 | $this->assertEquals( 404, $response->get_status() );
154 | }
155 |
156 | /**
157 | * Test getting locations from an invalid code.
158 | * @since 3.1.0
159 | */
160 | public function test_get_locations_from_invalid_country() {
161 | wp_set_current_user( $this->user );
162 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/countries/xx' ) );
163 | $this->assertEquals( 404, $response->get_status() );
164 | }
165 |
166 | /**
167 | * Test getting locations without permissions.
168 | * @since 3.1.0
169 | */
170 | public function test_get_continents_without_permission() {
171 | wp_set_current_user( 0 );
172 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/continents' ) );
173 | $this->assertEquals( 401, $response->get_status() );
174 | }
175 |
176 | /**
177 | * Test getting locations without permissions.
178 | * @since 3.1.0
179 | */
180 | public function test_get_countries_without_permission() {
181 | wp_set_current_user( 0 );
182 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/countries' ) );
183 | $this->assertEquals( 401, $response->get_status() );
184 | }
185 |
186 | /**
187 | * Test getting currencies.
188 | */
189 | public function test_get_currencies() {
190 | wp_set_current_user( $this->user );
191 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies' ) );
192 | $currencies = $response->get_data();
193 | $this->assertEquals( 200, $response->get_status() );
194 | $this->assertTrue( is_array( $currencies ) );
195 | $this->assertGreaterThan( 1, count( $currencies ) );
196 | $this->assertNotEmpty( $currencies[0]['code'] );
197 | $this->assertNotEmpty( $currencies[0]['name'] );
198 | $this->assertNotEmpty( $currencies[0]['symbol'] );
199 | $this->assertNotEmpty( $currencies[0]['_links'] );
200 | }
201 |
202 | /**
203 | * Test getting a single currency.
204 | */
205 | public function test_get_currency() {
206 | wp_set_current_user( $this->user );
207 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/CAD' ) );
208 | $currency = $response->get_data();
209 | $this->assertEquals( 200, $response->get_status() );
210 | $this->assertEquals( 'CAD', $currency['code'] );
211 | $this->assertEquals( 'Canadian dollar', $currency['name'] );
212 | $this->assertEquals( '$', $currency['symbol'] );
213 | $links = $response->get_links();
214 | $this->assertCount( 2, $links );
215 | }
216 |
217 | /**
218 | * Test getting current currency.
219 | */
220 | public function test_get_current_currency() {
221 | $current = get_option( 'woocommerce_currency' );
222 | update_option( 'woocommerce_currency', 'BTC' );
223 |
224 | wp_set_current_user( $this->user );
225 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/current' ) );
226 | $currency = $response->get_data();
227 | $this->assertEquals( 200, $response->get_status() );
228 | $this->assertEquals( 'BTC', $currency['code'] );
229 | $this->assertEquals( 'Bitcoin', $currency['name'] );
230 | $this->assertEquals( '฿', $currency['symbol'] );
231 | $links = $response->get_links();
232 | $this->assertCount( 2, $links );
233 |
234 | update_option( 'woocommerce_currency', $current );
235 | }
236 |
237 | /**
238 | * Test getting currency from an invalid code.
239 | */
240 | public function test_get_currency_from_invalid_code() {
241 | wp_set_current_user( $this->user );
242 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/xxy' ) );
243 | $this->assertEquals( 404, $response->get_status() );
244 | $this->assertEquals( 'woocommerce_rest_data_invalid_currency', $response->data['code'] );
245 | }
246 |
247 | /**
248 | * Test getting currency from an code that is too long.
249 | */
250 | public function test_get_currency_from_long_code() {
251 | wp_set_current_user( $this->user );
252 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies/xxyy' ) );
253 | $this->assertEquals( 404, $response->get_status() );
254 | $this->assertEquals( 'rest_no_route', $response->data['code'] );
255 | }
256 |
257 | /**
258 | * Test getting currencies without permissions.
259 | */
260 | public function test_get_currency_without_permission() {
261 | wp_set_current_user( 0 );
262 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/data/currencies' ) );
263 | $this->assertEquals( 401, $response->get_status() );
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/api/class-wc-rest-dev-data-continents-controller.php:
--------------------------------------------------------------------------------
1 | namespace, '/' . $this->rest_base, array(
46 | array(
47 | 'methods' => WP_REST_Server::READABLE,
48 | 'callback' => array( $this, 'get_items' ),
49 | 'permission_callback' => array( $this, 'get_items_permissions_check' ),
50 | ),
51 | 'schema' => array( $this, 'get_public_item_schema' ),
52 | ) );
53 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array(
54 | array(
55 | 'methods' => WP_REST_Server::READABLE,
56 | 'callback' => array( $this, 'get_item' ),
57 | 'permission_callback' => array( $this, 'get_items_permissions_check' ),
58 | 'args' => array(
59 | 'continent' => array(
60 | 'description' => __( '2 character continent code.', 'woocommerce' ),
61 | 'type' => 'string',
62 | ),
63 | ),
64 | ),
65 | 'schema' => array( $this, 'get_public_item_schema' ),
66 | ) );
67 | }
68 |
69 | /**
70 | * Return the list of countries and states for a given continent.
71 | *
72 | * @since 3.1.0
73 | * @param string $continent_code
74 | * @param WP_REST_Request $request
75 | * @return array|mixed Response data, ready for insertion into collection data.
76 | */
77 | public function get_continent( $continent_code = false, $request ) {
78 | $continents = WC()->countries->get_continents();
79 | $countries = WC()->countries->get_countries();
80 | $states = WC()->countries->get_states();
81 | $locale_info = include WC()->plugin_path() . '/i18n/locale-info.php';
82 | $data = array();
83 |
84 | if ( ! array_key_exists( $continent_code, $continents ) ) {
85 | return false;
86 | }
87 |
88 | $continent_list = $continents[ $continent_code ];
89 |
90 | $continent = array(
91 | 'code' => $continent_code,
92 | 'name' => $continent_list['name'],
93 | );
94 |
95 | $local_countries = array();
96 | foreach ( $continent_list['countries'] as $country_code ) {
97 | if ( isset( $countries[ $country_code ] ) ) {
98 | $country = array(
99 | 'code' => $country_code,
100 | 'name' => $countries[ $country_code ],
101 | );
102 |
103 | // If we have detailed locale information include that in the response
104 | if ( array_key_exists( $country_code, $locale_info ) ) {
105 | // Defensive programming against unexpected changes in locale-info.php
106 | $country_data = wp_parse_args( $locale_info[ $country_code ], array(
107 | 'currency_code' => 'USD',
108 | 'currency_pos' => 'left',
109 | 'decimal_sep' => '.',
110 | 'dimension_unit' => 'in',
111 | 'num_decimals' => 2,
112 | 'thousand_sep' => ',',
113 | 'weight_unit' => 'lbs',
114 | ) );
115 |
116 | $country = array_merge( $country, $country_data );
117 | }
118 |
119 | $local_states = array();
120 | if ( isset( $states[ $country_code ] ) ) {
121 | foreach ( $states[ $country_code ] as $state_code => $state_name ) {
122 | $local_states[] = array(
123 | 'code' => $state_code,
124 | 'name' => $state_name,
125 | );
126 | }
127 | }
128 | $country['states'] = $local_states;
129 |
130 | // Allow only desired keys (e.g. filter out tax rates)
131 | $allowed = array(
132 | 'code',
133 | 'currency_code',
134 | 'currency_pos',
135 | 'decimal_sep',
136 | 'dimension_unit',
137 | 'name',
138 | 'num_decimals',
139 | 'states',
140 | 'thousand_sep',
141 | 'weight_unit',
142 | );
143 | $country = array_intersect_key( $country, array_flip( $allowed ) );
144 |
145 | $local_countries[] = $country;
146 | }
147 | }
148 |
149 | $continent['countries'] = $local_countries;
150 | return $continent;
151 | }
152 |
153 | /**
154 | * Return the list of states for all continents.
155 | *
156 | * @since 3.1.0
157 | * @param WP_REST_Request $request
158 | * @return WP_Error|WP_REST_Response
159 | */
160 | public function get_items( $request ) {
161 | $continents = WC()->countries->get_continents();
162 | $data = array();
163 |
164 | foreach ( array_keys( $continents ) as $continent_code ) {
165 | $continent = $this->get_continent( $continent_code, $request );
166 | $response = $this->prepare_item_for_response( $continent, $request );
167 | $data[] = $this->prepare_response_for_collection( $response );
168 | }
169 |
170 | return rest_ensure_response( $data );
171 | }
172 |
173 | /**
174 | * Return the list of locations for a given continent.
175 | *
176 | * @since 3.1.0
177 | * @param WP_REST_Request $request
178 | * @return WP_Error|WP_REST_Response
179 | */
180 | public function get_item( $request ) {
181 | $data = $this->get_continent( strtoupper( $request['location'] ), $request );
182 | if ( empty( $data ) ) {
183 | return new WP_Error( 'woocommerce_rest_data_invalid_location', __( 'There are no locations matching these parameters.', 'woocommerce' ), array( 'status' => 404 ) );
184 | }
185 | return $this->prepare_item_for_response( $data, $request );
186 | }
187 |
188 | /**
189 | * Prepare the data object for response.
190 | *
191 | * @since 3.1.0
192 | * @param object $item Data object.
193 | * @param WP_REST_Request $request Request object.
194 | * @return WP_REST_Response $response Response data.
195 | */
196 | public function prepare_item_for_response( $item, $request ) {
197 | $data = $this->add_additional_fields_to_object( $item, $request );
198 | $data = $this->filter_response_by_context( $data, 'view' );
199 | $response = rest_ensure_response( $data );
200 |
201 | $response->add_links( $this->prepare_links( $item ) );
202 |
203 | /**
204 | * Filter the location list returned from the API.
205 | *
206 | * Allows modification of the loction data right before it is returned.
207 | *
208 | * @param WP_REST_Response $response The response object.
209 | * @param array $item The original list of continent(s), countries, and states.
210 | * @param WP_REST_Request $request Request used to generate the response.
211 | */
212 | return apply_filters( 'woocommerce_rest_prepare_data_continent', $response, $item, $request );
213 | }
214 |
215 | /**
216 | * Prepare links for the request.
217 | *
218 | * @param object $item Data object.
219 | * @return array Links for the given continent.
220 | */
221 | protected function prepare_links( $item ) {
222 | $continent_code = strtolower( $item['code'] );
223 | $links = array(
224 | 'self' => array(
225 | 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $continent_code ) ),
226 | ),
227 | 'collection' => array(
228 | 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
229 | ),
230 | );
231 | return $links;
232 | }
233 |
234 | /**
235 | * Get the location schema, conforming to JSON Schema.
236 | *
237 | * @since 3.1.0
238 | * @return array
239 | */
240 | public function get_item_schema() {
241 | $schema = array(
242 | '$schema' => 'http://json-schema.org/draft-04/schema#',
243 | 'title' => 'data_continents',
244 | 'type' => 'object',
245 | 'properties' => array(
246 | 'code' => array(
247 | 'type' => 'string',
248 | 'description' => __( '2 character continent code.', 'woocommerce' ),
249 | 'context' => array( 'view' ),
250 | 'readonly' => true,
251 | ),
252 | 'name' => array(
253 | 'type' => 'string',
254 | 'description' => __( 'Full name of continent.', 'woocommerce' ),
255 | 'context' => array( 'view' ),
256 | 'readonly' => true,
257 | ),
258 | 'countries' => array(
259 | 'type' => 'array',
260 | 'description' => __( 'List of countries on this continent.', 'woocommerce' ),
261 | 'context' => array( 'view' ),
262 | 'readonly' => true,
263 | 'items' => array(
264 | 'type' => 'object',
265 | 'context' => array( 'view' ),
266 | 'readonly' => true,
267 | 'properties' => array(
268 | 'code' => array(
269 | 'type' => 'string',
270 | 'description' => __( 'ISO3166 alpha-2 country code.', 'woocommerce' ),
271 | 'context' => array( 'view' ),
272 | 'readonly' => true,
273 | ),
274 | 'currency_code' => array(
275 | 'type' => 'string',
276 | 'description' => __( 'Default ISO4127 alpha-3 currency code for the country.', 'woocommerce' ),
277 | 'context' => array( 'view' ),
278 | 'readonly' => true,
279 | ),
280 | 'currency_pos' => array(
281 | 'type' => 'string',
282 | 'description' => __( 'Currency symbol position for this country.', 'woocommerce' ),
283 | 'context' => array( 'view' ),
284 | 'readonly' => true,
285 | ),
286 | 'decimal_sep' => array(
287 | 'type' => 'string',
288 | 'description' => __( 'Decimal separator for displayed prices for this country.', 'woocommerce' ),
289 | 'context' => array( 'view' ),
290 | 'readonly' => true,
291 | ),
292 | 'dimension_unit' => array(
293 | 'type' => 'string',
294 | 'description' => __( 'The unit lengths are defined in for this country.', 'woocommerce' ),
295 | 'context' => array( 'view' ),
296 | 'readonly' => true,
297 | ),
298 | 'name' => array(
299 | 'type' => 'string',
300 | 'description' => __( 'Full name of country.', 'woocommerce' ),
301 | 'context' => array( 'view' ),
302 | 'readonly' => true,
303 | ),
304 | 'num_decimals' => array(
305 | 'type' => 'integer',
306 | 'description' => __( 'Number of decimal points shown in displayed prices for this country.', 'woocommerce' ),
307 | 'context' => array( 'view' ),
308 | 'readonly' => true,
309 | ),
310 | 'states' => array(
311 | 'type' => 'array',
312 | 'description' => __( 'List of states in this country.', 'woocommerce' ),
313 | 'context' => array( 'view' ),
314 | 'readonly' => true,
315 | 'items' => array(
316 | 'type' => 'object',
317 | 'context' => array( 'view' ),
318 | 'readonly' => true,
319 | 'properties' => array(
320 | 'code' => array(
321 | 'type' => 'string',
322 | 'description' => __( 'State code.', 'woocommerce' ),
323 | 'context' => array( 'view' ),
324 | 'readonly' => true,
325 | ),
326 | 'name' => array(
327 | 'type' => 'string',
328 | 'description' => __( 'Full name of state.', 'woocommerce' ),
329 | 'context' => array( 'view' ),
330 | 'readonly' => true,
331 | ),
332 | ),
333 | ),
334 | ),
335 | 'thousand_sep' => array(
336 | 'type' => 'string',
337 | 'description' => __( 'Thousands separator for displayed prices in this country.', 'woocommerce' ),
338 | 'context' => array( 'view' ),
339 | 'readonly' => true,
340 | ),
341 | 'weight_unit' => array(
342 | 'type' => 'string',
343 | 'description' => __( 'The unit weights are defined in for this country.', 'woocommerce' ),
344 | 'context' => array( 'view' ),
345 | 'readonly' => true,
346 | ),
347 | ),
348 | ),
349 | ),
350 | ),
351 | );
352 |
353 | return $this->add_additional_fields_schema( $schema );
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/tests/unit-tests/system-status.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_System_Status_Controller();
15 | $this->user = $this->factory->user->create( array(
16 | 'role' => 'administrator',
17 | ) );
18 | }
19 |
20 | /**
21 | * Test route registration.
22 | */
23 | public function test_register_routes() {
24 | $routes = $this->server->get_routes();
25 | $this->assertArrayHasKey( '/wc/v3/system_status', $routes );
26 | $this->assertArrayHasKey( '/wc/v3/system_status/tools', $routes );
27 | $this->assertArrayHasKey( '/wc/v3/system_status/tools/(?P[\w-]+)', $routes );
28 | }
29 |
30 | /**
31 | * Test to make sure system status cannot be accessed without valid creds
32 | *
33 | * @since 3.0.0
34 | */
35 | public function test_get_system_status_info_without_permission() {
36 | wp_set_current_user( 0 );
37 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
38 | $this->assertEquals( 401, $response->get_status() );
39 | }
40 |
41 | /**
42 | * Test to make sure root properties are present.
43 | * (environment, theme, database, etc).
44 | *
45 | * @since 3.0.0
46 | */
47 | public function test_get_system_status_info_returns_root_properties() {
48 | wp_set_current_user( $this->user );
49 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
50 | $data = $response->get_data();
51 |
52 | $this->assertArrayHasKey( 'environment', $data );
53 | $this->assertArrayHasKey( 'database', $data );
54 | $this->assertArrayHasKey( 'active_plugins', $data );
55 | $this->assertArrayHasKey( 'theme', $data );
56 | $this->assertArrayHasKey( 'settings', $data );
57 | $this->assertArrayHasKey( 'security', $data );
58 | $this->assertArrayHasKey( 'pages', $data );
59 | }
60 |
61 | /**
62 | * Test to make sure environment response is correct.
63 | *
64 | * @since 3.0.0
65 | */
66 | public function test_get_system_status_info_environment() {
67 | wp_set_current_user( $this->user );
68 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
69 | $data = $response->get_data();
70 | $environment = (array) $data['environment'];
71 |
72 | $system_status = new WC_REST_System_Status_Controller;
73 | $environment_rows = count( $system_status->get_environment_info() );
74 |
75 | // Make sure all expected data is present
76 | $this->assertEquals( $environment_rows, count( $environment ) );
77 |
78 | // Test some responses to make sure they match up
79 | $this->assertEquals( get_option( 'home' ), $environment['home_url'] );
80 | $this->assertEquals( get_option( 'siteurl' ), $environment['site_url'] );
81 | $this->assertEquals( WC()->version, $environment['version'] );
82 | }
83 |
84 | /**
85 | * Test to make sure database response is correct.
86 | *
87 | * @since 3.0.0
88 | */
89 | public function test_get_system_status_info_database() {
90 | global $wpdb;
91 | wp_set_current_user( $this->user );
92 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
93 | $data = $response->get_data();
94 | $database = (array) $data['database'];
95 |
96 | $this->assertEquals( get_option( 'woocommerce_db_version' ), $database['wc_database_version'] );
97 | $this->assertEquals( $wpdb->prefix, $database['database_prefix'] );
98 | $this->assertEquals( WC_Geolocation::get_local_database_path(), $database['maxmind_geoip_database'] );
99 | $this->assertArrayHasKey( $wpdb->prefix . 'woocommerce_payment_tokens', $database['database_tables']['woocommerce'] );
100 | }
101 |
102 | /**
103 | * Test to make sure active plugins response is correct.
104 | *
105 | * @since 3.0.0
106 | */
107 | public function test_get_system_status_info_active_plugins() {
108 | wp_set_current_user( $this->user );
109 |
110 | $actual_plugins = array( 'hello.php' );
111 | update_option( 'active_plugins', $actual_plugins );
112 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
113 | update_option( 'active_plugins', array() );
114 |
115 | $data = $response->get_data();
116 | $plugins = (array) $data['active_plugins'];
117 |
118 | $this->assertEquals( 1, count( $plugins ) );
119 | $this->assertEquals( 'Hello Dolly', $plugins[0]['name'] );
120 | }
121 |
122 | /**
123 | * Test to make sure theme response is correct.
124 | *
125 | * @since 3.0.0
126 | */
127 | public function test_get_system_status_info_theme() {
128 | wp_set_current_user( $this->user );
129 | $active_theme = wp_get_theme();
130 |
131 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
132 | $data = $response->get_data();
133 | $theme = (array) $data['theme'];
134 |
135 | $this->assertEquals( 13, count( $theme ) );
136 | $this->assertEquals( $active_theme->Name, $theme['name'] );
137 | }
138 |
139 | /**
140 | * Test to make sure settings response is correct.
141 | *
142 | * @since 3.0.0
143 | */
144 | public function test_get_system_status_info_settings() {
145 | wp_set_current_user( $this->user );
146 |
147 | $term_response = array();
148 | $terms = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
149 | foreach ( $terms as $term ) {
150 | $term_response[ $term->slug ] = strtolower( $term->name );
151 | }
152 |
153 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
154 | $data = $response->get_data();
155 | $settings = (array) $data['settings'];
156 |
157 | $this->assertEquals( 11, count( $settings ) );
158 | $this->assertEquals( ( 'yes' === get_option( 'woocommerce_api_enabled' ) ), $settings['api_enabled'] );
159 | $this->assertEquals( get_woocommerce_currency(), $settings['currency'] );
160 | $this->assertEquals( $term_response, $settings['taxonomies'] );
161 | }
162 |
163 | /**
164 | * Test to make sure security response is correct.
165 | *
166 | * @since 3.0.0
167 | */
168 | public function test_get_system_status_info_security() {
169 | wp_set_current_user( $this->user );
170 |
171 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
172 | $data = $response->get_data();
173 | $settings = (array) $data['security'];
174 |
175 | $this->assertEquals( 2, count( $settings ) );
176 | $this->assertEquals( 'https' === substr( get_permalink( wc_get_page_id( 'shop' ) ), 0, 5 ), $settings['secure_connection'] );
177 | $this->assertEquals( ! ( defined( 'WP_DEBUG' ) && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG && WP_DEBUG_DISPLAY ) || 0 === intval( ini_get( 'display_errors' ) ), $settings['hide_errors'] );
178 | }
179 |
180 | /**
181 | * Test to make sure pages response is correct.
182 | *
183 | * @since 3.0.0
184 | */
185 | public function test_get_system_status_info_pages() {
186 | wp_set_current_user( $this->user );
187 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
188 | $data = $response->get_data();
189 | $pages = $data['pages'];
190 | $this->assertEquals( 5, count( $pages ) );
191 | }
192 |
193 | /**
194 | * Test system status schema.
195 | *
196 | * @since 3.0.0
197 | */
198 | public function test_system_status_schema() {
199 | $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/system_status' );
200 | $response = $this->server->dispatch( $request );
201 | $data = $response->get_data();
202 | $properties = $data['schema']['properties'];
203 | $this->assertEquals( 7, count( $properties ) );
204 | $this->assertArrayHasKey( 'environment', $properties );
205 | $this->assertArrayHasKey( 'database', $properties );
206 | $this->assertArrayHasKey( 'active_plugins', $properties );
207 | $this->assertArrayHasKey( 'theme', $properties );
208 | $this->assertArrayHasKey( 'settings', $properties );
209 | $this->assertArrayHasKey( 'security', $properties );
210 | $this->assertArrayHasKey( 'pages', $properties );
211 | }
212 |
213 | /**
214 | * Test to make sure get_items (all tools) response is correct.
215 | *
216 | * @since 3.0.0
217 | */
218 | public function test_get_system_tools() {
219 | wp_set_current_user( $this->user );
220 |
221 | $tools_controller = new WC_REST_System_Status_Tools_Controller;
222 | $raw_tools = $tools_controller->get_tools();
223 |
224 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status/tools' ) );
225 | $data = $response->get_data();
226 |
227 | $this->assertEquals( 200, $response->get_status() );
228 | $this->assertEquals( count( $raw_tools ), count( $data ) );
229 |
230 | $this->assertContains( array(
231 | 'id' => 'reset_tracking',
232 | 'name' => 'Reset usage tracking',
233 | 'action' => 'Reset',
234 | 'description' => 'This will reset your usage tracking settings, causing it to show the opt-in banner again and not sending any data.',
235 | '_links' => array(
236 | 'item' => array(
237 | array(
238 | 'href' => rest_url( '/wc/v3/system_status/tools/reset_tracking' ),
239 | 'embeddable' => true,
240 | ),
241 | ),
242 | ),
243 | ), $data );
244 | }
245 |
246 | /**
247 | * Test to make sure system status tools cannot be accessed without valid creds
248 | *
249 | * @since 3.0.0
250 | */
251 | public function test_get_system_status_tools_without_permission() {
252 | wp_set_current_user( 0 );
253 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status/tools' ) );
254 | $this->assertEquals( 401, $response->get_status() );
255 | }
256 |
257 | /**
258 | * Test to make sure we can load a single tool correctly.
259 | *
260 | * @since 3.0.0
261 | */
262 | public function test_get_system_tool() {
263 | wp_set_current_user( $this->user );
264 |
265 | $tools_controller = new WC_REST_System_Status_Tools_Controller;
266 | $raw_tools = $tools_controller->get_tools();
267 | $raw_tool = $raw_tools['recount_terms'];
268 |
269 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status/tools/recount_terms' ) );
270 | $data = $response->get_data();
271 |
272 | $this->assertEquals( 200, $response->get_status() );
273 |
274 | $this->assertEquals( 'recount_terms', $data['id'] );
275 | $this->assertEquals( 'Term counts', $data['name'] );
276 | $this->assertEquals( 'Recount terms', $data['action'] );
277 | $this->assertEquals( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', $data['description'] );
278 | }
279 |
280 | /**
281 | * Test to make sure a single system status toolscannot be accessed without valid creds.
282 | *
283 | * @since 3.0.0
284 | */
285 | public function test_get_system_status_tool_without_permission() {
286 | wp_set_current_user( 0 );
287 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status/tools/recount_terms' ) );
288 | $this->assertEquals( 401, $response->get_status() );
289 | }
290 |
291 | /**
292 | * Test to make sure we can RUN a tool correctly.
293 | *
294 | * @since 3.0.0
295 | */
296 | public function test_execute_system_tool() {
297 | wp_set_current_user( $this->user );
298 |
299 | $tools_controller = new WC_REST_System_Status_Tools_Controller;
300 | $raw_tools = $tools_controller->get_tools();
301 | $raw_tool = $raw_tools['recount_terms'];
302 |
303 | $response = $this->server->dispatch( new WP_REST_Request( 'POST', '/wc/v3/system_status/tools/recount_terms' ) );
304 | $data = $response->get_data();
305 |
306 | $this->assertEquals( 'recount_terms', $data['id'] );
307 | $this->assertEquals( 'Term counts', $data['name'] );
308 | $this->assertEquals( 'Recount terms', $data['action'] );
309 | $this->assertEquals( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', $data['description'] );
310 | $this->assertTrue( $data['success'] );
311 |
312 | $response = $this->server->dispatch( new WP_REST_Request( 'POST', '/wc/v3/system_status/tools/not_a_real_tool' ) );
313 | $this->assertEquals( 404, $response->get_status() );
314 | }
315 |
316 | /**
317 | * Test to make sure a tool cannot be run without valid creds.
318 | *
319 | * @since 3.0.0
320 | */
321 | public function test_execute_system_status_tool_without_permission() {
322 | wp_set_current_user( 0 );
323 | $response = $this->server->dispatch( new WP_REST_Request( 'POST', '/wc/v3/system_status/tools/recount_terms' ) );
324 | $this->assertEquals( 401, $response->get_status() );
325 | }
326 |
327 | /**
328 | * Test system status schema.
329 | *
330 | * @since 3.0.0
331 | */
332 | public function test_system_status_tool_schema() {
333 | $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/system_status/tools' );
334 | $response = $this->server->dispatch( $request );
335 | $data = $response->get_data();
336 | $properties = $data['schema']['properties'];
337 | $this->assertEquals( 6, count( $properties ) );
338 | $this->assertArrayHasKey( 'id', $properties );
339 | $this->assertArrayHasKey( 'name', $properties );
340 | $this->assertArrayHasKey( 'action', $properties );
341 | $this->assertArrayHasKey( 'description', $properties );
342 | $this->assertArrayHasKey( 'success', $properties );
343 | $this->assertArrayHasKey( 'message', $properties );
344 | }
345 | }
346 |
--------------------------------------------------------------------------------
/tests/unit-tests/orders.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Orders_Controller();
22 | $this->user = $this->factory->user->create( array(
23 | 'role' => 'administrator',
24 | ) );
25 | }
26 |
27 | /**
28 | * Test route registration.
29 | * @since 3.0.0
30 | */
31 | public function test_register_routes() {
32 | $routes = $this->server->get_routes();
33 | $this->assertArrayHasKey( '/wc/v3/orders', $routes );
34 | $this->assertArrayHasKey( '/wc/v3/orders/batch', $routes );
35 | $this->assertArrayHasKey( '/wc/v3/orders/(?P[\d]+)', $routes );
36 | }
37 |
38 | /**
39 | * Cleanup.
40 | */
41 | public function stoppit_and_tidyup() {
42 | foreach ( $this->orders as $order ) {
43 | wp_delete_post( $order->get_id(), true );
44 | }
45 | $this->orders = array();
46 | }
47 |
48 | /**
49 | * Test getting all orders.
50 | * @since 3.0.0
51 | */
52 | public function test_get_items() {
53 | wp_set_current_user( $this->user );
54 |
55 | // Create 10 orders.
56 | for ( $i = 0; $i < 10; $i++ ) {
57 | $this->orders[] = WC_Helper_Order::create_order( $this->user );
58 | }
59 |
60 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
61 | $orders = $response->get_data();
62 |
63 | $this->assertEquals( 200, $response->get_status() );
64 | $this->assertEquals( 10, count( $orders ) );
65 | $this->stoppit_and_tidyup();
66 | }
67 |
68 | /**
69 | * Tests to make sure orders cannot be viewed without valid permissions.
70 | *
71 | * @since 3.0.0
72 | */
73 | public function test_get_items_without_permission() {
74 | wp_set_current_user( 0 );
75 | $this->orders[] = WC_Helper_Order::create_order();
76 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
77 | $this->assertEquals( 401, $response->get_status() );
78 | $this->stoppit_and_tidyup();
79 | }
80 |
81 | /**
82 | * Tests getting a single order.
83 | * @since 3.0.0
84 | */
85 | public function test_get_item() {
86 | wp_set_current_user( $this->user );
87 | $order = WC_Helper_Order::create_order();
88 | $this->orders[] = $order;
89 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
90 | $data = $response->get_data();
91 |
92 | $this->assertEquals( 200, $response->get_status() );
93 | $this->assertEquals( $order->get_id(), $data['id'] );
94 | $this->stoppit_and_tidyup();
95 | }
96 |
97 | /**
98 | * Tests getting a single order without the correct permissions.
99 | * @since 3.0.0
100 | */
101 | public function test_get_item_without_permission() {
102 | wp_set_current_user( 0 );
103 | $order = WC_Helper_Order::create_order();
104 | $this->orders[] = $order;
105 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
106 | $this->assertEquals( 401, $response->get_status() );
107 | $this->stoppit_and_tidyup();
108 | }
109 |
110 | /**
111 | * Tests getting an order with an invalid ID.
112 | * @since 3.0.0
113 | */
114 | public function test_get_item_invalid_id() {
115 | wp_set_current_user( $this->user );
116 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/99999999' ) );
117 | $this->assertEquals( 404, $response->get_status() );
118 | }
119 |
120 | /**
121 | * Tests creating an order.
122 | * @since 3.0.0
123 | */
124 | public function test_create_order() {
125 | wp_set_current_user( $this->user );
126 | $product = WC_Helper_Product::create_simple_product();
127 | $request = new WP_REST_Request( 'POST', '/wc/v3/orders' );
128 | $request->set_body_params( array(
129 | 'payment_method' => 'bacs',
130 | 'payment_method_title' => 'Direct Bank Transfer',
131 | 'set_paid' => true,
132 | 'billing' => array(
133 | 'first_name' => 'John',
134 | 'last_name' => 'Doe',
135 | 'address_1' => '969 Market',
136 | 'address_2' => '',
137 | 'city' => 'San Francisco',
138 | 'state' => 'CA',
139 | 'postcode' => '94103',
140 | 'country' => 'US',
141 | 'email' => 'john.doe@example.com',
142 | 'phone' => '(555) 555-5555',
143 | ),
144 | 'shipping' => array(
145 | 'first_name' => 'John',
146 | 'last_name' => 'Doe',
147 | 'address_1' => '969 Market',
148 | 'address_2' => '',
149 | 'city' => 'San Francisco',
150 | 'state' => 'CA',
151 | 'postcode' => '94103',
152 | 'country' => 'US',
153 | ),
154 | 'line_items' => array(
155 | array(
156 | 'product_id' => $product->get_id(),
157 | 'quantity' => 2,
158 | ),
159 | ),
160 | 'shipping_lines' => array(
161 | array(
162 | 'method_id' => 'flat_rate',
163 | 'method_title' => 'Flat rate',
164 | 'total' => '10',
165 | ),
166 | ),
167 | ) );
168 | $response = $this->server->dispatch( $request );
169 | $data = $response->get_data();
170 |
171 | $this->assertNotEmpty( $data['id'] );
172 |
173 | $order = wc_get_order( $data['id'] );
174 | $this->assertEquals( 201, $response->get_status() );
175 | $this->assertEquals( $order->get_payment_method(), $data['payment_method'] );
176 | $this->assertEquals( $order->get_payment_method_title(), $data['payment_method_title'] );
177 | $this->assertEquals( $order->get_billing_first_name(), $data['billing']['first_name'] );
178 | $this->assertEquals( $order->get_billing_last_name(), $data['billing']['last_name'] );
179 | $this->assertEquals( '', $data['billing']['company'] );
180 | $this->assertEquals( $order->get_billing_address_1(), $data['billing']['address_1'] );
181 | $this->assertEquals( $order->get_billing_address_2(), $data['billing']['address_2'] );
182 | $this->assertEquals( $order->get_billing_city(), $data['billing']['city'] );
183 | $this->assertEquals( $order->get_billing_state(), $data['billing']['state'] );
184 | $this->assertEquals( $order->get_billing_postcode(), $data['billing']['postcode'] );
185 | $this->assertEquals( $order->get_billing_country(), $data['billing']['country'] );
186 | $this->assertEquals( $order->get_billing_email(), $data['billing']['email'] );
187 | $this->assertEquals( $order->get_billing_phone(), $data['billing']['phone'] );
188 | $this->assertEquals( $order->get_shipping_first_name(), $data['shipping']['first_name'] );
189 | $this->assertEquals( $order->get_shipping_last_name(), $data['shipping']['last_name'] );
190 | $this->assertEquals( '', $data['shipping']['company'] );
191 | $this->assertEquals( $order->get_shipping_address_1(), $data['shipping']['address_1'] );
192 | $this->assertEquals( $order->get_shipping_address_2(), $data['shipping']['address_2'] );
193 | $this->assertEquals( $order->get_shipping_city(), $data['shipping']['city'] );
194 | $this->assertEquals( $order->get_shipping_state(), $data['shipping']['state'] );
195 | $this->assertEquals( $order->get_shipping_postcode(), $data['shipping']['postcode'] );
196 | $this->assertEquals( $order->get_shipping_country(), $data['shipping']['country'] );
197 | $this->assertEquals( 1, count( $data['line_items'] ) );
198 | $this->assertEquals( 1, count( $data['shipping_lines'] ) );
199 |
200 | wp_delete_post( $product->get_id(), true );
201 | wp_delete_post( $data['id'], true );
202 | }
203 |
204 | /**
205 | * Tests creating an order without required fields.
206 | * @since 3.0.0
207 | */
208 | public function test_create_order_invalid_fields() {
209 | wp_set_current_user( $this->user );
210 | $product = WC_Helper_Product::create_simple_product();
211 |
212 | // non-existant customer
213 | $request = new WP_REST_Request( 'POST', '/wc/v3/orders' );
214 | $request->set_body_params( array(
215 | 'payment_method' => 'bacs',
216 | 'payment_method_title' => 'Direct Bank Transfer',
217 | 'set_paid' => true,
218 | 'customer_id' => 99999,
219 | 'billing' => array(
220 | 'first_name' => 'John',
221 | 'last_name' => 'Doe',
222 | 'address_1' => '969 Market',
223 | 'address_2' => '',
224 | 'city' => 'San Francisco',
225 | 'state' => 'CA',
226 | 'postcode' => '94103',
227 | 'country' => 'US',
228 | 'email' => 'john.doe@example.com',
229 | 'phone' => '(555) 555-5555',
230 | ),
231 | 'shipping' => array(
232 | 'first_name' => 'John',
233 | 'last_name' => 'Doe',
234 | 'address_1' => '969 Market',
235 | 'address_2' => '',
236 | 'city' => 'San Francisco',
237 | 'state' => 'CA',
238 | 'postcode' => '94103',
239 | 'country' => 'US',
240 | ),
241 | 'line_items' => array(
242 | array(
243 | 'product_id' => $product->get_id(),
244 | 'quantity' => 2,
245 | ),
246 | ),
247 | 'shipping_lines' => array(
248 | array(
249 | 'method_id' => 'flat_rate',
250 | 'method_title' => 'Flat rate',
251 | 'total' => '10',
252 | ),
253 | ),
254 | ) );
255 | $response = $this->server->dispatch( $request );
256 | $data = $response->get_data();
257 | $this->assertEquals( 400, $response->get_status() );
258 | wp_delete_post( $product->get_id(), true );
259 | }
260 |
261 | /**
262 | * Tests updating an order.
263 | * @since 3.0.0
264 | */
265 | public function test_update_order() {
266 | wp_set_current_user( $this->user );
267 | $order = WC_Helper_Order::create_order();
268 | $request = new WP_REST_Request( 'POST', '/wc/v3/orders/' . $order->get_id() );
269 | $request->set_body_params( array(
270 | 'payment_method' => 'test-update',
271 | 'billing' => array(
272 | 'first_name' => 'Fish',
273 | 'last_name' => 'Face',
274 | ),
275 | ) );
276 | $response = $this->server->dispatch( $request );
277 | $data = $response->get_data();
278 |
279 | $this->assertEquals( 200, $response->get_status() );
280 | $this->assertEquals( 'test-update', $data['payment_method'] );
281 | $this->assertEquals( 'Fish', $data['billing']['first_name'] );
282 | $this->assertEquals( 'Face', $data['billing']['last_name'] );
283 |
284 | wp_delete_post( $order->get_id(), true );
285 | }
286 |
287 | /**
288 | * Tests updating an order without the correct permissions.
289 | * @since 3.0.0
290 | */
291 | public function test_update_order_without_permission() {
292 | wp_set_current_user( 0 );
293 | $order = WC_Helper_Order::create_order();
294 | $request = new WP_REST_Request( 'POST', '/wc/v3/orders/' . $order->get_id() );
295 | $request->set_body_params( array(
296 | 'payment_method' => 'test-update',
297 | 'billing' => array(
298 | 'first_name' => 'Fish',
299 | 'last_name' => 'Face',
300 | ),
301 | ) );
302 | $response = $this->server->dispatch( $request );
303 | $this->assertEquals( 401, $response->get_status() );
304 | }
305 |
306 | /**
307 | * Tests that updating an order with an invalid id fails.
308 | * @since 3.0.0
309 | */
310 | public function test_update_order_invalid_id() {
311 | wp_set_current_user( $this->user );
312 | $request = new WP_REST_Request( 'POST', '/wc/v3/orders/999999' );
313 | $request->set_body_params( array(
314 | 'payment_method' => 'test-update',
315 | 'billing' => array(
316 | 'first_name' => 'Fish',
317 | 'last_name' => 'Face',
318 | ),
319 | ) );
320 | $response = $this->server->dispatch( $request );
321 | $this->assertEquals( 400, $response->get_status() );
322 | }
323 |
324 | /**
325 | * Test deleting an order.
326 | * @since 3.0.0
327 | */
328 | public function test_delete_order() {
329 | wp_set_current_user( $this->user );
330 | $order = WC_Helper_Order::create_order();
331 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
332 | $request->set_param( 'force', true );
333 | $response = $this->server->dispatch( $request );
334 | $this->assertEquals( 200, $response->get_status() );
335 | $this->assertEquals( null, get_post( $order->get_id() ) );
336 | }
337 |
338 | /**
339 | * Test deleting an order without permission/creds.
340 | * @since 3.0.0
341 | */
342 | public function test_delete_order_without_permission() {
343 | wp_set_current_user( 0 );
344 | $order = WC_Helper_Order::create_order();
345 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
346 | $request->set_param( 'force', true );
347 | $response = $this->server->dispatch( $request );
348 | $this->assertEquals( 401, $response->get_status() );
349 | wp_delete_post( $order->get_id(), true );
350 | }
351 |
352 | /**
353 | * Test deleting an order with an invalid id.
354 | *
355 | * @since 3.0.0
356 | */
357 | public function test_delete_order_invalid_id() {
358 | wp_set_current_user( $this->user );
359 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/9999999' );
360 | $request->set_param( 'force', true );
361 | $response = $this->server->dispatch( $request );
362 | $this->assertEquals( 404, $response->get_status() );
363 | }
364 |
365 | /**
366 | * Test batch managing product reviews.
367 | */
368 | public function test_orders_batch() {
369 | wp_set_current_user( $this->user );
370 |
371 | // Delete any existing orders
372 | $request = new WP_REST_Request( 'GET', '/wc/v3/orders' );
373 | $response = $this->server->dispatch( $request );
374 | $orders = $response->get_data();
375 | foreach ( $orders as $order ) {
376 | wp_delete_post( $order['id'], true );
377 | }
378 |
379 | $order1 = WC_Helper_Order::create_order();
380 | $order2 = WC_Helper_Order::create_order();
381 | $order3 = WC_Helper_Order::create_order();
382 |
383 | $request = new WP_REST_Request( 'POST', '/wc/v3/orders/batch' );
384 | $request->set_body_params( array(
385 | 'update' => array(
386 | array(
387 | 'id' => $order1->get_id(),
388 | 'payment_method' => 'updated',
389 | ),
390 | ),
391 | 'delete' => array(
392 | $order2->get_id(),
393 | $order3->get_id(),
394 | ),
395 | ) );
396 | $response = $this->server->dispatch( $request );
397 | $data = $response->get_data();
398 |
399 | $this->assertEquals( 'updated', $data['update'][0]['payment_method'] );
400 | $this->assertEquals( $order2->get_id(), $data['delete'][0]['id'] );
401 | $this->assertEquals( $order3->get_id(), $data['delete'][1]['id'] );
402 |
403 | $request = new WP_REST_Request( 'GET', '/wc/v3/orders' );
404 | $response = $this->server->dispatch( $request );
405 | $data = $response->get_data();
406 | $this->assertEquals( 1, count( $data ) );
407 |
408 | wp_delete_post( $order1->get_id(), true );
409 | wp_delete_post( $order2->get_id(), true );
410 | wp_delete_post( $order3->get_id(), true );
411 | }
412 |
413 | /**
414 | * Test the order schema.
415 | * @since 3.0.0
416 | */
417 | public function test_order_schema() {
418 | wp_set_current_user( $this->user );
419 | $order = WC_Helper_Order::create_order();
420 | $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
421 | $response = $this->server->dispatch( $request );
422 | $data = $response->get_data();
423 | $properties = $data['schema']['properties'];
424 |
425 | $this->assertEquals( 42, count( $properties ) );
426 | $this->assertArrayHasKey( 'id', $properties );
427 | wp_delete_post( $order->get_id(), true );
428 | }
429 | }
430 |
--------------------------------------------------------------------------------
/tests/unit-tests/coupons.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Coupons_Controller();
18 | $this->user = $this->factory->user->create( array(
19 | 'role' => 'administrator',
20 | ) );
21 | }
22 |
23 | /**
24 | * Test route registration.
25 | * @since 3.0.0
26 | */
27 | public function test_register_routes() {
28 | $routes = $this->server->get_routes();
29 | $this->assertArrayHasKey( '/wc/v3/coupons', $routes );
30 | $this->assertArrayHasKey( '/wc/v3/coupons/(?P[\d]+)', $routes );
31 | $this->assertArrayHasKey( '/wc/v3/coupons/batch', $routes );
32 | }
33 |
34 | /**
35 | * Test getting coupons.
36 | * @since 3.0.0
37 | */
38 | public function test_get_coupons() {
39 | wp_set_current_user( $this->user );
40 |
41 | $coupon_1 = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
42 | $post_1 = get_post( $coupon_1->get_id() );
43 | $coupon_2 = WC_Helper_Coupon::create_coupon( 'dummycoupon-2' );
44 |
45 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/coupons' ) );
46 | $coupons = $response->get_data();
47 |
48 | $this->assertEquals( 200, $response->get_status() );
49 | $this->assertEquals( 2, count( $coupons ) );
50 | $this->assertContains( array(
51 | 'id' => $coupon_1->get_id(),
52 | 'code' => 'dummycoupon-1',
53 | 'amount' => '1.00',
54 | 'date_created' => wc_rest_prepare_date_response( $post_1->post_date_gmt, false ),
55 | 'date_created_gmt' => wc_rest_prepare_date_response( $post_1->post_date_gmt ),
56 | 'date_modified' => wc_rest_prepare_date_response( $post_1->post_modified_gmt, false ),
57 | 'date_modified_gmt' => wc_rest_prepare_date_response( $post_1->post_modified_gmt ),
58 | 'discount_type' => 'fixed_cart',
59 | 'description' => 'This is a dummy coupon',
60 | 'date_expires' => '',
61 | 'date_expires_gmt' => '',
62 | 'usage_count' => 0,
63 | 'individual_use' => false,
64 | 'product_ids' => array(),
65 | 'excluded_product_ids' => array(),
66 | 'usage_limit' => '',
67 | 'usage_limit_per_user' => '',
68 | 'limit_usage_to_x_items' => null,
69 | 'free_shipping' => false,
70 | 'product_categories' => array(),
71 | 'excluded_product_categories' => array(),
72 | 'exclude_sale_items' => false,
73 | 'minimum_amount' => '0.00',
74 | 'maximum_amount' => '0.00',
75 | 'email_restrictions' => array(),
76 | 'used_by' => array(),
77 | 'meta_data' => array(),
78 | '_links' => array(
79 | 'self' => array(
80 | array(
81 | 'href' => rest_url( '/wc/v3/coupons/' . $coupon_1->get_id() ),
82 | ),
83 | ),
84 | 'collection' => array(
85 | array(
86 | 'href' => rest_url( '/wc/v3/coupons' ),
87 | ),
88 | ),
89 | ),
90 | ), $coupons );
91 | }
92 |
93 | /**
94 | * Test getting coupons without valid permissions.
95 | * @since 3.0.0
96 | */
97 | public function test_get_coupons_without_permission() {
98 | wp_set_current_user( 0 );
99 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/coupons' ) );
100 | $this->assertEquals( 401, $response->get_status() );
101 | }
102 |
103 | /**
104 | * Test getting a single coupon.
105 | * @since 3.0.0
106 | */
107 | public function test_get_coupon() {
108 | wp_set_current_user( $this->user );
109 | $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
110 | $post = get_post( $coupon->get_id() );
111 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/coupons/' . $coupon->get_id() ) );
112 | $data = $response->get_data();
113 |
114 | $this->assertEquals( 200, $response->get_status() );
115 | $this->assertEquals( array(
116 | 'id' => $coupon->get_id(),
117 | 'code' => 'dummycoupon-1',
118 | 'amount' => '1.00',
119 | 'date_created' => wc_rest_prepare_date_response( $post->post_date_gmt, false ),
120 | 'date_created_gmt' => wc_rest_prepare_date_response( $post->post_date_gmt ),
121 | 'date_modified' => wc_rest_prepare_date_response( $post->post_modified_gmt, false ),
122 | 'date_modified_gmt' => wc_rest_prepare_date_response( $post->post_modified_gmt ),
123 | 'discount_type' => 'fixed_cart',
124 | 'description' => 'This is a dummy coupon',
125 | 'date_expires' => null,
126 | 'date_expires_gmt' => null,
127 | 'usage_count' => 0,
128 | 'individual_use' => false,
129 | 'product_ids' => array(),
130 | 'excluded_product_ids' => array(),
131 | 'usage_limit' => null,
132 | 'usage_limit_per_user' => null,
133 | 'limit_usage_to_x_items' => null,
134 | 'free_shipping' => false,
135 | 'product_categories' => array(),
136 | 'excluded_product_categories' => array(),
137 | 'exclude_sale_items' => false,
138 | 'minimum_amount' => '0.00',
139 | 'maximum_amount' => '0.00',
140 | 'email_restrictions' => array(),
141 | 'used_by' => array(),
142 | 'meta_data' => array(),
143 | ), $data );
144 | }
145 |
146 | /**
147 | * Test getting a single coupon with an invalid ID.
148 | * @since 3.0.0
149 | */
150 | public function test_get_coupon_invalid_id() {
151 | wp_set_current_user( $this->user );
152 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/coupons/0' ) );
153 | $this->assertEquals( 404, $response->get_status() );
154 | }
155 |
156 | /**
157 | * Test getting a single coupon without valid permissions.
158 | * @since 3.0.0
159 | */
160 | public function test_get_coupon_without_permission() {
161 | wp_set_current_user( 0 );
162 | $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
163 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/coupons/' . $coupon->get_id() ) );
164 | $this->assertEquals( 401, $response->get_status() );
165 | }
166 |
167 | /**
168 | * Test creating a single coupon.
169 | * @since 3.0.0
170 | */
171 | public function test_create_coupon() {
172 | wp_set_current_user( $this->user );
173 | $request = new WP_REST_Request( 'POST', '/wc/v3/coupons' );
174 | $request->set_body_params( array(
175 | 'code' => 'test',
176 | 'amount' => '5.00',
177 | 'discount_type' => 'fixed_product',
178 | 'description' => 'Test',
179 | 'usage_limit' => 10,
180 | ) );
181 | $response = $this->server->dispatch( $request );
182 | $data = $response->get_data();
183 |
184 | $this->assertEquals( 201, $response->get_status() );
185 | $this->assertEquals( array(
186 | 'id' => $data['id'],
187 | 'code' => 'test',
188 | 'amount' => '5.00',
189 | 'date_created' => $data['date_created'],
190 | 'date_created_gmt' => $data['date_created_gmt'],
191 | 'date_modified' => $data['date_modified'],
192 | 'date_modified_gmt' => $data['date_modified_gmt'],
193 | 'discount_type' => 'fixed_product',
194 | 'description' => 'Test',
195 | 'date_expires' => null,
196 | 'date_expires_gmt' => null,
197 | 'usage_count' => 0,
198 | 'individual_use' => false,
199 | 'product_ids' => array(),
200 | 'excluded_product_ids' => array(),
201 | 'usage_limit' => 10,
202 | 'usage_limit_per_user' => null,
203 | 'limit_usage_to_x_items' => null,
204 | 'free_shipping' => false,
205 | 'product_categories' => array(),
206 | 'excluded_product_categories' => array(),
207 | 'exclude_sale_items' => false,
208 | 'minimum_amount' => '0.00',
209 | 'maximum_amount' => '0.00',
210 | 'email_restrictions' => array(),
211 | 'used_by' => array(),
212 | 'meta_data' => array(),
213 | ), $data );
214 | }
215 |
216 | /**
217 | * Test creating a single coupon with invalid fields.
218 | * @since 3.0.0
219 | */
220 | public function test_create_coupon_invalid_fields() {
221 | wp_set_current_user( $this->user );
222 |
223 | // test no code...
224 | $request = new WP_REST_Request( 'POST', '/wc/v3/coupons' );
225 | $request->set_body_params( array(
226 | 'amount' => '5.00',
227 | 'discount_type' => 'fixed_product',
228 | ) );
229 | $response = $this->server->dispatch( $request );
230 | $data = $response->get_data();
231 |
232 | $this->assertEquals( 400, $response->get_status() );
233 | }
234 |
235 | /**
236 | * Test creating a single coupon without valid permissions.
237 | * @since 3.0.0
238 | */
239 | public function test_create_coupon_without_permission() {
240 | wp_set_current_user( 0 );
241 |
242 | // test no code...
243 | $request = new WP_REST_Request( 'POST', '/wc/v3/coupons' );
244 | $request->set_body_params( array(
245 | 'code' => 'fail',
246 | 'amount' => '5.00',
247 | 'discount_type' => 'fixed_product',
248 | ) );
249 | $response = $this->server->dispatch( $request );
250 | $data = $response->get_data();
251 |
252 | $this->assertEquals( 401, $response->get_status() );
253 | }
254 |
255 | /**
256 | * Test updating a single coupon.
257 | * @since 3.0.0
258 | */
259 | public function test_update_coupon() {
260 | wp_set_current_user( $this->user );
261 | $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
262 | $post = get_post( $coupon->get_id() );
263 |
264 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/coupons/' . $coupon->get_id() ) );
265 | $data = $response->get_data();
266 | $this->assertEquals( 'This is a dummy coupon', $data['description'] );
267 | $this->assertEquals( 'fixed_cart', $data['discount_type'] );
268 | $this->assertEquals( '1.00', $data['amount'] );
269 |
270 | $request = new WP_REST_Request( 'PUT', '/wc/v3/coupons/' . $coupon->get_id() );
271 | $request->set_body_params( array(
272 | 'amount' => '10.00',
273 | 'description' => 'New description',
274 | ) );
275 | $response = $this->server->dispatch( $request );
276 | $data = $response->get_data();
277 |
278 | $this->assertEquals( '10.00', $data['amount'] );
279 | $this->assertEquals( 'New description', $data['description'] );
280 | $this->assertEquals( 'fixed_cart', $data['discount_type'] );
281 | }
282 |
283 | /**
284 | * Test updating a single coupon with an invalid ID.
285 | * @since 3.0.0
286 | */
287 | public function test_update_coupon_invalid_id() {
288 | wp_set_current_user( $this->user );
289 |
290 | $request = new WP_REST_Request( 'PUT', '/wc/v3/coupons/0' );
291 | $request->set_body_params( array(
292 | 'code' => 'tester',
293 | 'amount' => '10.00',
294 | 'description' => 'New description',
295 | ) );
296 | $response = $this->server->dispatch( $request );
297 | $data = $response->get_data();
298 |
299 | $this->assertEquals( 400, $response->get_status() );
300 | }
301 |
302 | /**
303 | * Test updating a single coupon without valid permissions.
304 | * @since 3.0.0
305 | */
306 | public function test_update_coupon_without_permission() {
307 | wp_set_current_user( 0 );
308 | $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
309 | $post = get_post( $coupon->get_id() );
310 |
311 | $request = new WP_REST_Request( 'PUT', '/wc/v3/coupons/' . $coupon->get_id() );
312 | $request->set_body_params( array(
313 | 'amount' => '10.00',
314 | 'description' => 'New description',
315 | ) );
316 | $response = $this->server->dispatch( $request );
317 |
318 | $this->assertEquals( 401, $response->get_status() );
319 | }
320 |
321 | /**
322 | * Test deleting a single coupon.
323 | * @since 3.0.0
324 | */
325 | public function test_delete_coupon() {
326 | wp_set_current_user( $this->user );
327 | $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
328 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/coupons/' . $coupon->get_id() );
329 | $request->set_param( 'force', true );
330 | $response = $this->server->dispatch( $request );
331 | $this->assertEquals( 200, $response->get_status() );
332 | }
333 |
334 | /**
335 | * Test deleting a single coupon with an invalid ID.
336 | * @since 3.0.0
337 | */
338 | public function test_delete_coupon_invalid_id() {
339 | wp_set_current_user( $this->user );
340 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/coupons/0' );
341 | $request->set_param( 'force', true );
342 | $response = $this->server->dispatch( $request );
343 |
344 | $this->assertEquals( 404, $response->get_status() );
345 | }
346 |
347 | /**
348 | * Test deleting a single coupon without valid permissions.
349 | * @since 3.0.0
350 | */
351 | public function test_delete_coupon_without_permission() {
352 | wp_set_current_user( 0 );
353 | $coupon = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
354 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/coupons/' . $coupon->get_id() );
355 | $response = $this->server->dispatch( $request );
356 |
357 | $this->assertEquals( 401, $response->get_status() );
358 | }
359 |
360 | /**
361 | * Test batch operations on coupons.
362 | * @since 3.0.0
363 | */
364 | public function test_batch_coupon() {
365 | wp_set_current_user( $this->user );
366 |
367 | $coupon_1 = WC_Helper_Coupon::create_coupon( 'dummycoupon-1' );
368 | $coupon_2 = WC_Helper_Coupon::create_coupon( 'dummycoupon-2' );
369 | $coupon_3 = WC_Helper_Coupon::create_coupon( 'dummycoupon-3' );
370 | $coupon_4 = WC_Helper_Coupon::create_coupon( 'dummycoupon-4' );
371 |
372 | $request = new WP_REST_Request( 'POST', '/wc/v3/coupons/batch' );
373 | $request->set_body_params( array(
374 | 'update' => array(
375 | array(
376 | 'id' => $coupon_1->get_id(),
377 | 'amount' => '5.15',
378 | ),
379 | ),
380 | 'delete' => array(
381 | $coupon_2->get_id(),
382 | $coupon_3->get_id(),
383 | ),
384 | 'create' => array(
385 | array(
386 | 'code' => 'new-coupon',
387 | 'amount' => '11.00',
388 | ),
389 | ),
390 | ) );
391 | $response = $this->server->dispatch( $request );
392 | $data = $response->get_data();
393 |
394 | $this->assertEquals( '5.15', $data['update'][0]['amount'] );
395 | $this->assertEquals( '11.00', $data['create'][0]['amount'] );
396 | $this->assertEquals( 'new-coupon', $data['create'][0]['code'] );
397 | $this->assertEquals( $coupon_2->get_id(), $data['delete'][0]['id'] );
398 | $this->assertEquals( $coupon_3->get_id(), $data['delete'][1]['id'] );
399 |
400 | $request = new WP_REST_Request( 'GET', '/wc/v3/coupons' );
401 | $response = $this->server->dispatch( $request );
402 | $data = $response->get_data();
403 |
404 | $this->assertEquals( 3, count( $data ) );
405 | }
406 |
407 | /**
408 | * Test coupon schema.
409 | * @since 3.0.0
410 | */
411 | public function test_coupon_schema() {
412 | wp_set_current_user( $this->user );
413 | $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/coupons' );
414 | $response = $this->server->dispatch( $request );
415 | $data = $response->get_data();
416 | $properties = $data['schema']['properties'];
417 |
418 | $this->assertEquals( 27, count( $properties ) );
419 | $this->assertArrayHasKey( 'id', $properties );
420 | $this->assertArrayHasKey( 'code', $properties );
421 | $this->assertArrayHasKey( 'date_created', $properties );
422 | $this->assertArrayHasKey( 'date_created_gmt', $properties );
423 | $this->assertArrayHasKey( 'date_modified', $properties );
424 | $this->assertArrayHasKey( 'date_modified_gmt', $properties );
425 | $this->assertArrayHasKey( 'description', $properties );
426 | $this->assertArrayHasKey( 'discount_type', $properties );
427 | $this->assertArrayHasKey( 'amount', $properties );
428 | $this->assertArrayHasKey( 'date_expires', $properties );
429 | $this->assertArrayHasKey( 'date_expires_gmt', $properties );
430 | $this->assertArrayHasKey( 'usage_count', $properties );
431 | $this->assertArrayHasKey( 'individual_use', $properties );
432 | $this->assertArrayHasKey( 'product_ids', $properties );
433 | $this->assertArrayHasKey( 'excluded_product_ids', $properties );
434 | $this->assertArrayHasKey( 'usage_limit', $properties );
435 | $this->assertArrayHasKey( 'usage_limit_per_user', $properties );
436 | $this->assertArrayHasKey( 'limit_usage_to_x_items', $properties );
437 | $this->assertArrayHasKey( 'free_shipping', $properties );
438 | $this->assertArrayHasKey( 'product_categories', $properties );
439 | $this->assertArrayHasKey( 'excluded_product_categories', $properties );
440 | $this->assertArrayHasKey( 'exclude_sale_items', $properties );
441 | $this->assertArrayHasKey( 'minimum_amount', $properties );
442 | $this->assertArrayHasKey( 'maximum_amount', $properties );
443 | $this->assertArrayHasKey( 'email_restrictions', $properties );
444 | $this->assertArrayHasKey( 'used_by', $properties );
445 | }
446 | }
447 |
--------------------------------------------------------------------------------
/tests/unit-tests/product-variations.php:
--------------------------------------------------------------------------------
1 | endpoint = new WC_REST_DEV_Product_Variations_Controller();
17 | $this->user = $this->factory->user->create( array(
18 | 'role' => 'administrator',
19 | ) );
20 | }
21 |
22 | /**
23 | * Test route registration.
24 | *
25 | * @since 3.0.0
26 | */
27 | public function test_register_routes() {
28 | $routes = $this->server->get_routes();
29 | $this->assertArrayHasKey( '/wc/v3/products/(?P[\d]+)/variations', $routes );
30 | $this->assertArrayHasKey( '/wc/v3/products/(?P[\d]+)/variations/(?P[\d]+)', $routes );
31 | $this->assertArrayHasKey( '/wc/v3/products/(?P[\d]+)/variations/batch', $routes );
32 | }
33 |
34 | /**
35 | * Test getting variations.
36 | *
37 | * @since 3.0.0
38 | */
39 | public function test_get_variations() {
40 | wp_set_current_user( $this->user );
41 | $product = WC_Helper_Product::create_variation_product();
42 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations' ) );
43 | $variations = $response->get_data();
44 | $this->assertEquals( 200, $response->get_status() );
45 | $this->assertEquals( 2, count( $variations ) );
46 | $this->assertEquals( 'DUMMY SKU VARIABLE LARGE', $variations[0]['sku'] );
47 | $this->assertEquals( 'size', $variations[0]['attributes'][0]['name'] );
48 | $product->delete( true );
49 | }
50 |
51 | /**
52 | * Test getting variations without permission.
53 | *
54 | * @since 3.0.0
55 | */
56 | public function test_get_variations_without_permission() {
57 | wp_set_current_user( 0 );
58 | $product = WC_Helper_Product::create_variation_product();
59 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations' ) );
60 | $this->assertEquals( 401, $response->get_status() );
61 | $product->delete( true );
62 | }
63 |
64 | /**
65 | * Test getting a single variation.
66 | *
67 | * @since 3.0.0
68 | */
69 | public function test_get_variation() {
70 | wp_set_current_user( $this->user );
71 | $product = WC_Helper_Product::create_variation_product();
72 | $children = $product->get_children();
73 | $variation_id = $children[0];
74 |
75 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id ) );
76 | $variation = $response->get_data();
77 |
78 | $this->assertEquals( 200, $response->get_status() );
79 | $this->assertEquals( $variation_id, $variation['id'] );
80 | $this->assertEquals( 'size', $variation['attributes'][0]['name'] );
81 | $product->delete( true );
82 | }
83 |
84 | /**
85 | * Test getting single variation without permission.
86 | *
87 | * @since 3.0.0
88 | */
89 | public function test_get_variation_without_permission() {
90 | wp_set_current_user( 0 );
91 | $product = WC_Helper_Product::create_variation_product();
92 | $children = $product->get_children();
93 | $variation_id = $children[0];
94 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id ) );
95 | $this->assertEquals( 401, $response->get_status() );
96 | $product->delete( true );
97 | }
98 |
99 | /**
100 | * Test deleting a single variation.
101 | *
102 | * @since 3.0.0
103 | */
104 | public function test_delete_variation() {
105 | wp_set_current_user( $this->user );
106 | $product = WC_Helper_Product::create_variation_product();
107 | $children = $product->get_children();
108 | $variation_id = $children[0];
109 |
110 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id );
111 | $request->set_param( 'force', true );
112 | $response = $this->server->dispatch( $request );
113 | $this->assertEquals( 200, $response->get_status() );
114 |
115 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations' ) );
116 | $variations = $response->get_data();
117 | $this->assertEquals( 1, count( $variations ) );
118 | $product->delete( true );
119 | }
120 |
121 | /**
122 | * Test deleting a single variation without permission.
123 | *
124 | * @since 3.0.0
125 | */
126 | public function test_delete_variation_without_permission() {
127 | wp_set_current_user( 0 );
128 | $product = WC_Helper_Product::create_variation_product();
129 | $children = $product->get_children();
130 | $variation_id = $children[0];
131 |
132 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id );
133 | $request->set_param( 'force', true );
134 | $response = $this->server->dispatch( $request );
135 | $this->assertEquals( 401, $response->get_status() );
136 | $product->delete( true );
137 | }
138 |
139 | /**
140 | * Test deleting a single variation with an invalid ID.
141 | *
142 | * @since 3.0.0
143 | */
144 | public function test_delete_variation_with_invalid_id() {
145 | wp_set_current_user( 0 );
146 | $product = WC_Helper_Product::create_variation_product();
147 | $request = new WP_REST_Request( 'DELETE', '/wc/v3/products/' . $product->get_id() . '/variations/0' );
148 | $request->set_param( 'force', true );
149 | $response = $this->server->dispatch( $request );
150 | $this->assertEquals( 404, $response->get_status() );
151 | $product->delete( true );
152 | }
153 |
154 | /**
155 | * Test editing a single variation.
156 | *
157 | * @since 3.0.0
158 | */
159 | public function test_update_variation() {
160 | wp_set_current_user( $this->user );
161 | $product = WC_Helper_Product::create_variation_product();
162 | $children = $product->get_children();
163 | $variation_id = $children[0];
164 |
165 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id ) );
166 | $variation = $response->get_data();
167 |
168 | $this->assertEquals( 'DUMMY SKU VARIABLE SMALL', $variation['sku'] );
169 | $this->assertEquals( 10, $variation['regular_price'] );
170 | $this->assertEmpty( $variation['sale_price'] );
171 | $this->assertEquals( 'small', $variation['attributes'][0]['option'] );
172 | $this->assertEquals( 'publish', $variation['status'] );
173 |
174 | $request = new WP_REST_Request( 'PUT', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id );
175 | $request->set_body_params( array(
176 | 'sku' => 'FIXED-SKU',
177 | 'sale_price' => '8',
178 | 'description' => 'O_O',
179 | 'image' => array( 'position' => 0, 'src' => 'https://cldup.com/Dr1Bczxq4q.png', 'alt' => 'test upload image' ),
180 | 'attributes' => array( array( 'name' => 'pa_size', 'option' => 'medium' ) ),
181 | 'status' => 'private',
182 | ) );
183 | $response = $this->server->dispatch( $request );
184 | $variation = $response->get_data();
185 |
186 | $this->assertContains( 'O_O', $variation['description'] );
187 | $this->assertEquals( '8', $variation['price'] );
188 | $this->assertEquals( '8', $variation['sale_price'] );
189 | $this->assertEquals( '10', $variation['regular_price'] );
190 | $this->assertEquals( 'FIXED-SKU', $variation['sku'] );
191 | $this->assertEquals( 'medium', $variation['attributes'][0]['option'] );
192 | $this->assertContains( 'Dr1Bczxq4q', $variation['image']['src'] );
193 | $this->assertContains( 'test upload image', $variation['image']['alt'] );
194 | $this->assertEquals( 'private', $variation['status'] );
195 | $product->delete( true );
196 | }
197 |
198 | /**
199 | * Test setting variation image from ID. (src is tested in `test_update_variation`)
200 | */
201 | public function test_set_variation_image_from_id() {
202 | wp_set_current_user( $this->user );
203 |
204 | $orig_file = dirname( __FILE__ ) . '/../../assets/icon-128x128.png';
205 | $this->test_file = '/tmp/icon.png';
206 | copy( $orig_file, $this->test_file );
207 |
208 | $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
209 | $request->set_header( 'Content-Type', 'image/png' );
210 | $request->set_header( 'Content-Disposition', 'attachment; filename=icon.png' );
211 | $request->set_body( file_get_contents( $this->test_file ) );
212 | $response = $this->server->dispatch( $request );
213 | $image = $response->get_data();
214 |
215 | $product = WC_Helper_Product::create_variation_product();
216 | $children = $product->get_children();
217 | $variation_id = $children[0];
218 |
219 | $request = new WP_REST_Request( 'PUT', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id );
220 | $request->set_body_params( array(
221 | 'image' => array( 'id' => $image['id'] ),
222 | ) );
223 | $response = $this->server->dispatch( $request );
224 | $variation = $response->get_data();
225 |
226 | $this->assertNotEmpty( $variation['image'] );
227 | $this->assertEquals( $image['id'], $variation['image']['id'] );
228 |
229 | $product->delete( true );
230 | if ( file_exists( $this->test_file ) ) {
231 | unlink( $this->test_file );
232 | }
233 | }
234 |
235 | /**
236 | * Test updating a single variation without permission.
237 | *
238 | * @since 3.0.0
239 | */
240 | public function test_update_variation_without_permission() {
241 | wp_set_current_user( 0 );
242 | $product = WC_Helper_Product::create_variation_product();
243 | $children = $product->get_children();
244 | $variation_id = $children[0];
245 |
246 | $request = new WP_REST_Request( 'PUT', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id );
247 | $request->set_body_params( array(
248 | 'sku' => 'FIXED-SKU-NO-PERMISSION',
249 | ) );
250 | $response = $this->server->dispatch( $request );
251 | $this->assertEquals( 401, $response->get_status() );
252 | $product->delete( true );
253 | }
254 |
255 | /**
256 | * Test updating a single variation with an invalid ID.
257 | *
258 | * @since 3.0.0
259 | */
260 | public function test_update_variation_with_invalid_id() {
261 | wp_set_current_user( $this->user );
262 | $product = WC_Helper_Product::create_variation_product();
263 | $request = new WP_REST_Request( 'PUT', '/wc/v3/products/' . $product->get_id() . '/variations/0' );
264 | $request->set_body_params( array(
265 | 'sku' => 'FIXED-SKU-NO-PERMISSION',
266 | ) );
267 | $response = $this->server->dispatch( $request );
268 | $this->assertEquals( 400, $response->get_status() );
269 | $product->delete( true );
270 | }
271 |
272 | /**
273 | * Test creating a single variation.
274 | *
275 | * @since 3.0.0
276 | */
277 | public function test_create_variation() {
278 | wp_set_current_user( $this->user );
279 | $product = WC_Helper_Product::create_variation_product();
280 |
281 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations' ) );
282 | $variations = $response->get_data();
283 | $this->assertEquals( 2, count( $variations ) );
284 |
285 | $request = new WP_REST_Request( 'POST', '/wc/v3/products/' . $product->get_id() . '/variations' );
286 | $request->set_body_params( array(
287 | 'sku' => 'DUMMY SKU VARIABLE MEDIUM',
288 | 'regular_price' => '12',
289 | 'description' => 'A medium size.',
290 | 'attributes' => array( array( 'name' => 'pa_size', 'option' => 'medium' ) ),
291 | ) );
292 | $response = $this->server->dispatch( $request );
293 | $variation = $response->get_data();
294 |
295 | $this->assertContains( 'A medium size.', $variation['description'] );
296 | $this->assertEquals( '12', $variation['price'] );
297 | $this->assertEquals( '12', $variation['regular_price'] );
298 | $this->assertTrue( $variation['purchasable'] );
299 | $this->assertEquals( 'DUMMY SKU VARIABLE MEDIUM', $variation['sku'] );
300 | $this->assertEquals( 'medium', $variation['attributes'][0]['option'] );
301 |
302 | $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations' ) );
303 | $variations = $response->get_data();
304 | $this->assertEquals( 3, count( $variations ) );
305 | $product->delete( true );
306 | }
307 |
308 | /**
309 | * Test creating a single variation without permission.
310 | *
311 | * @since 3.0.0
312 | */
313 | public function test_create_variation_without_permission() {
314 | wp_set_current_user( 0 );
315 | $product = WC_Helper_Product::create_variation_product();
316 |
317 | $request = new WP_REST_Request( 'POST', '/wc/v3/products/' . $product->get_id() . '/variations' );
318 | $request->set_body_params( array(
319 | 'sku' => 'DUMMY SKU VARIABLE MEDIUM',
320 | 'regular_price' => '12',
321 | 'description' => 'A medium size.',
322 | 'attributes' => array( array( 'name' => 'pa_size', 'option' => 'medium' ) ),
323 | ) );
324 | $response = $this->server->dispatch( $request );
325 | $this->assertEquals( 401, $response->get_status() );
326 | $product->delete( true );
327 | }
328 |
329 | /**
330 | * Test batch managing product variations.
331 | */
332 | public function test_product_variations_batch() {
333 | wp_set_current_user( $this->user );
334 | $product = WC_Helper_Product::create_variation_product();
335 | $children = $product->get_children();
336 | $request = new WP_REST_Request( 'POST', '/wc/v3/products/' . $product->get_id() . '/variations/batch' );
337 | $request->set_body_params( array(
338 | 'update' => array(
339 | array(
340 | 'id' => $children[0],
341 | 'description' => 'Updated description.',
342 | 'image' => array( 'position' => 0, 'src' => 'https://cldup.com/Dr1Bczxq4q.png', 'alt' => 'test upload image' ),
343 | ),
344 | ),
345 | 'delete' => array(
346 | $children[1],
347 | ),
348 | 'create' => array(
349 | array(
350 | 'sku' => 'DUMMY SKU VARIABLE MEDIUM',
351 | 'regular_price' => '12',
352 | 'description' => 'A medium size.',
353 | 'attributes' => array( array( 'name' => 'pa_size', 'option' => 'medium' ) ),
354 | ),
355 | ),
356 | ) );
357 | $response = $this->server->dispatch( $request );
358 | $data = $response->get_data();
359 |
360 | $this->assertContains( 'Updated description.', $data['update'][0]['description'] );
361 | $this->assertEquals( 'DUMMY SKU VARIABLE MEDIUM', $data['create'][0]['sku'] );
362 | $this->assertEquals( 'medium', $data['create'][0]['attributes'][0]['option'] );
363 | $this->assertEquals( $children[1], $data['delete'][0]['id'] );
364 |
365 | $request = new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() . '/variations' );
366 | $response = $this->server->dispatch( $request );
367 | $data = $response->get_data();
368 |
369 | $this->assertEquals( 2, count( $data ) );
370 | $product->delete( true );
371 | }
372 |
373 | /**
374 | * Test variation schema.
375 | *
376 | * @since 3.0.0
377 | */
378 | public function test_variation_schema() {
379 | wp_set_current_user( $this->user );
380 | $product = WC_Helper_Product::create_simple_product();
381 | $request = new WP_REST_Request( 'OPTIONS', '/wc/v3/products/' . $product->get_id() . '/variations' );
382 | $response = $this->server->dispatch( $request );
383 | $data = $response->get_data();
384 | $properties = $data['schema']['properties'];
385 |
386 | $this->assertEquals( 37, count( $properties ) );
387 | $this->assertArrayHasKey( 'id', $properties );
388 | $this->assertArrayHasKey( 'date_created', $properties );
389 | $this->assertArrayHasKey( 'date_modified', $properties );
390 | $this->assertArrayHasKey( 'description', $properties );
391 | $this->assertArrayHasKey( 'permalink', $properties );
392 | $this->assertArrayHasKey( 'sku', $properties );
393 | $this->assertArrayHasKey( 'price', $properties );
394 | $this->assertArrayHasKey( 'regular_price', $properties );
395 | $this->assertArrayHasKey( 'sale_price', $properties );
396 | $this->assertArrayHasKey( 'date_on_sale_from', $properties );
397 | $this->assertArrayHasKey( 'date_on_sale_to', $properties );
398 | $this->assertArrayHasKey( 'on_sale', $properties );
399 | $this->assertArrayHasKey( 'purchasable', $properties );
400 | $this->assertArrayHasKey( 'virtual', $properties );
401 | $this->assertArrayHasKey( 'downloadable', $properties );
402 | $this->assertArrayHasKey( 'downloads', $properties );
403 | $this->assertArrayHasKey( 'download_limit', $properties );
404 | $this->assertArrayHasKey( 'download_expiry', $properties );
405 | $this->assertArrayHasKey( 'status', $properties );
406 | $this->assertArrayHasKey( 'tax_status', $properties );
407 | $this->assertArrayHasKey( 'tax_class', $properties );
408 | $this->assertArrayHasKey( 'manage_stock', $properties );
409 | $this->assertArrayHasKey( 'stock_quantity', $properties );
410 | $this->assertArrayHasKey( 'in_stock', $properties );
411 | $this->assertArrayHasKey( 'backorders', $properties );
412 | $this->assertArrayHasKey( 'backorders_allowed', $properties );
413 | $this->assertArrayHasKey( 'backordered', $properties );
414 | $this->assertArrayHasKey( 'weight', $properties );
415 | $this->assertArrayHasKey( 'dimensions', $properties );
416 | $this->assertArrayHasKey( 'shipping_class', $properties );
417 | $this->assertArrayHasKey( 'shipping_class_id', $properties );
418 | $this->assertArrayHasKey( 'image', $properties );
419 | $this->assertArrayHasKey( 'attributes', $properties );
420 | $this->assertArrayHasKey( 'menu_order', $properties );
421 | $this->assertArrayHasKey( 'meta_data', $properties );
422 | $product->delete( true );
423 | }
424 |
425 | }
426 |
--------------------------------------------------------------------------------