PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.3
WooCommerce v10.9.3
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / rest-api / Controllers / Version3 / class-wc-rest-controller.php
woocommerce / includes / rest-api / Controllers / Version3 Last commit date
class-wc-rest-controller.php 1 year ago class-wc-rest-coupons-controller.php 4 years ago class-wc-rest-crud-controller.php 7 months ago class-wc-rest-customer-downloads-controller.php 5 years ago class-wc-rest-customers-controller.php 3 years ago class-wc-rest-data-continents-controller.php 4 months ago class-wc-rest-data-controller.php 5 years ago class-wc-rest-data-countries-controller.php 4 months ago class-wc-rest-data-currencies-controller.php 4 months ago class-wc-rest-layout-templates-controller.php 2 years ago class-wc-rest-network-orders-controller.php 5 years ago class-wc-rest-order-notes-controller.php 5 years ago class-wc-rest-order-refunds-controller.php 2 months ago class-wc-rest-orders-controller.php 2 months ago class-wc-rest-payment-gateways-controller.php 1 year ago class-wc-rest-paypal-buttons-controller.php 5 months ago class-wc-rest-paypal-standard-controller.php 3 months ago class-wc-rest-paypal-webhooks-controller.php 3 months ago class-wc-rest-posts-controller.php 2 years ago class-wc-rest-product-attribute-terms-controller.php 5 years ago class-wc-rest-product-attributes-controller.php 2 years ago class-wc-rest-product-brands-controller.php 1 year ago class-wc-rest-product-categories-controller.php 3 months ago class-wc-rest-product-custom-fields-controller.php 1 year ago class-wc-rest-product-reviews-controller.php 1 year ago class-wc-rest-product-shipping-classes-controller.php 1 year ago class-wc-rest-product-tags-controller.php 5 years ago class-wc-rest-product-variations-controller.php 1 month ago class-wc-rest-products-catalog-controller.php 7 months ago class-wc-rest-products-controller.php 2 months ago class-wc-rest-refunds-controller.php 2 years ago class-wc-rest-report-coupons-totals-controller.php 5 years ago class-wc-rest-report-customers-totals-controller.php 5 years ago class-wc-rest-report-orders-totals-controller.php 2 years ago class-wc-rest-report-products-totals-controller.php 5 years ago class-wc-rest-report-reviews-totals-controller.php 5 years ago class-wc-rest-report-sales-controller.php 5 years ago class-wc-rest-report-top-sellers-controller.php 5 years ago class-wc-rest-reports-controller.php 5 years ago class-wc-rest-setting-options-controller.php 4 months ago class-wc-rest-settings-controller.php 5 years ago class-wc-rest-shipping-methods-controller.php 5 years ago class-wc-rest-shipping-zone-locations-controller.php 5 years ago class-wc-rest-shipping-zone-methods-controller.php 5 years ago class-wc-rest-shipping-zones-controller-base.php 5 years ago class-wc-rest-shipping-zones-controller.php 5 years ago class-wc-rest-system-status-controller.php 5 years ago class-wc-rest-system-status-tools-controller.php 5 years ago class-wc-rest-tax-classes-controller.php 5 years ago class-wc-rest-taxes-controller.php 5 years ago class-wc-rest-terms-controller.php 1 month ago class-wc-rest-variations-controller.php 9 months ago class-wc-rest-webhooks-controller.php 5 years ago
class-wc-rest-controller.php
676 lines
1 <?php
2 /**
3 * REST Controller
4 *
5 * This class extend `WP_REST_Controller` in order to include /batch endpoint
6 * for almost all endpoints in WooCommerce REST API.
7 *
8 * It's required to follow "Controller Classes" guide before extending this class:
9 * <https://developer.wordpress.org/rest-api/extending-the-rest-api/controller-classes/>
10 *
11 * NOTE THAT ONLY CODE RELEVANT FOR MOST ENDPOINTS SHOULD BE INCLUDED INTO THIS CLASS.
12 * If necessary extend this class and create new abstract classes like `WC_REST_CRUD_Controller` or `WC_REST_Terms_Controller`.
13 *
14 * @class WC_REST_Controller
15 * @package WooCommerce\RestApi
16 * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/controller-classes/
17 */
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 /**
24 * Abstract Rest Controller Class
25 *
26 * @package WooCommerce\RestApi
27 * @extends WP_REST_Controller
28 * @version 2.6.0
29 */
30 abstract class WC_REST_Controller extends WP_REST_Controller {
31
32 /**
33 * Endpoint namespace.
34 *
35 * @var string
36 */
37 protected $namespace = 'wc/v1';
38
39 /**
40 * Route base.
41 *
42 * @var string
43 */
44 protected $rest_base = '';
45
46 /**
47 * Used to cache computed return fields.
48 *
49 * @var null|array
50 */
51 private $_fields = null;
52
53 /**
54 * Used to verify if cached fields are for correct request object.
55 *
56 * @var null|WP_REST_Request
57 */
58 private $_request = null;
59
60 /**
61 * Add the schema from additional fields to an schema array.
62 *
63 * The type of object is inferred from the passed schema.
64 *
65 * @param array $schema Schema array.
66 *
67 * @return array
68 */
69 protected function add_additional_fields_schema( $schema ) {
70 if ( empty( $schema['title'] ) ) {
71 return $schema;
72 }
73
74 /**
75 * Can't use $this->get_object_type otherwise we cause an inf loop.
76 */
77 $object_type = $schema['title'];
78
79 $additional_fields = $this->get_additional_fields( $object_type );
80
81 foreach ( $additional_fields as $field_name => $field_options ) {
82 if ( ! $field_options['schema'] ) {
83 continue;
84 }
85
86 $schema['properties'][ $field_name ] = $field_options['schema'];
87 }
88
89 $schema['properties'] = apply_filters( 'woocommerce_rest_' . $object_type . '_schema', $schema['properties'] );
90
91 return $schema;
92 }
93
94 /**
95 * Compatibility functions for WP 5.5, since custom types are not supported anymore.
96 * See @link https://core.trac.wordpress.org/changeset/48306
97 *
98 * @param string $method Optional. HTTP method of the request.
99 *
100 * @return array Endpoint arguments.
101 */
102 public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
103
104 $endpoint_args = parent::get_endpoint_args_for_item_schema( $method );
105
106 if ( false === strpos( WP_REST_Server::EDITABLE, $method ) ) {
107 return $endpoint_args;
108 }
109
110 $endpoint_args = $this->adjust_wp_5_5_datatype_compatibility( $endpoint_args );
111
112 return $endpoint_args;
113 }
114
115 /**
116 * Change datatypes `date-time` to string, and `mixed` to composite of all built in types. This is required for maintaining forward compatibility with WP 5.5 since custom post types are not supported anymore.
117 *
118 * See @link https://core.trac.wordpress.org/changeset/48306
119 *
120 * We still use the 'mixed' type, since if we convert to composite type everywhere, it won't work in 5.4 anymore because they require to define the full schema.
121 *
122 * @param array $endpoint_args Schema with datatypes to convert.
123
124 * @return mixed Schema with converted datatype.
125 */
126 protected function adjust_wp_5_5_datatype_compatibility( $endpoint_args ) {
127 if ( version_compare( get_bloginfo( 'version' ), '5.5', '<' ) ) {
128 return $endpoint_args;
129 }
130
131 foreach ( $endpoint_args as $field_id => $params ) {
132
133 if ( ! isset( $params['type'] ) ) {
134 continue;
135 }
136
137 /**
138 * Custom types are not supported as of WP 5.5, this translates type => 'date-time' to type => 'string'.
139 */
140 if ( 'date-time' === $params['type'] ) {
141 $params['type'] = array( 'null', 'string' );
142 }
143
144 /**
145 * WARNING: Order of fields here is important, types of fields are ordered from most specific to least specific as perceived by core's built-in type validation methods.
146 */
147 if ( 'mixed' === $params['type'] ) {
148 $params['type'] = array( 'null', 'object', 'string', 'number', 'boolean', 'integer', 'array' );
149 }
150
151 if ( isset( $params['properties'] ) ) {
152 $params['properties'] = $this->adjust_wp_5_5_datatype_compatibility( $params['properties'] );
153 }
154
155 if ( isset( $params['items'] ) && isset( $params['items']['properties'] ) ) {
156 $params['items']['properties'] = $this->adjust_wp_5_5_datatype_compatibility( $params['items']['properties'] );
157 }
158
159 $endpoint_args[ $field_id ] = $params;
160 }
161 return $endpoint_args;
162 }
163
164 /**
165 * Get normalized rest base.
166 *
167 * @return string
168 */
169 protected function get_normalized_rest_base() {
170 return preg_replace( '/\(.*\)\//i', '', $this->rest_base );
171 }
172
173 /**
174 * Check batch limit.
175 *
176 * @param array $items Request items.
177 * @return bool|WP_Error
178 */
179 protected function check_batch_limit( $items ) {
180 $limit = apply_filters( 'woocommerce_rest_batch_items_limit', 100, $this->get_normalized_rest_base() );
181 $total = 0;
182
183 if ( ! empty( $items['create'] ) && is_countable( $items['create'] ) ) {
184 $total += count( $items['create'] );
185 }
186
187 if ( ! empty( $items['update'] ) && is_countable( $items['update'] ) ) {
188 $total += count( $items['update'] );
189 }
190
191 if ( ! empty( $items['delete'] ) && is_countable( $items['delete'] ) ) {
192 $total += count( $items['delete'] );
193 }
194
195 if ( $total > $limit ) {
196 /* translators: %s: items limit */
197 return new WP_Error( 'woocommerce_rest_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce' ), $limit ), array( 'status' => 413 ) );
198 }
199
200 return true;
201 }
202
203 /**
204 * Bulk create, update and delete items.
205 *
206 * @param WP_REST_Request $request Full details about the request.
207 * @return array Of WP_Error or WP_REST_Response.
208 */
209 public function batch_items( $request ) {
210 /**
211 * REST Server
212 *
213 * @var WP_REST_Server $wp_rest_server
214 */
215 global $wp_rest_server;
216
217 // Get the request params.
218 $items = array_filter( $request->get_params() );
219 $query = $request->get_query_params();
220 $response = array();
221
222 // Check batch limit.
223 $limit = $this->check_batch_limit( $items );
224 if ( is_wp_error( $limit ) ) {
225 return $limit;
226 }
227
228 if ( ! empty( $items['create'] ) ) {
229 foreach ( $items['create'] as $item ) {
230 $_item = new WP_REST_Request( 'POST', $request->get_route() );
231
232 // Default parameters.
233 $defaults = array();
234 $schema = $this->get_public_item_schema();
235 foreach ( $schema['properties'] as $arg => $options ) {
236 if ( isset( $options['default'] ) ) {
237 $defaults[ $arg ] = $options['default'];
238 }
239 }
240 $_item->set_default_params( $defaults );
241
242 // Set request parameters.
243 $_item->set_body_params( $item );
244
245 // Set query (GET) parameters.
246 $_item->set_query_params( $query );
247
248 $allowed = $this->create_item_permissions_check( $_item );
249 if ( is_wp_error( $allowed ) ) {
250 $response['create'][] = array(
251 'id' => 0,
252 'error' => array(
253 'code' => $allowed->get_error_code(),
254 'message' => $allowed->get_error_message(),
255 'data' => $allowed->get_error_data(),
256 ),
257 );
258 continue;
259 }
260
261 $_response = $this->create_item( $_item );
262
263 if ( is_wp_error( $_response ) ) {
264 $response['create'][] = array(
265 'id' => 0,
266 'error' => array(
267 'code' => $_response->get_error_code(),
268 'message' => $_response->get_error_message(),
269 'data' => $_response->get_error_data(),
270 ),
271 );
272 } else {
273 $response['create'][] = $wp_rest_server->response_to_data( $_response, '' );
274 }
275 }
276 }
277
278 if ( ! empty( $items['update'] ) ) {
279 foreach ( $items['update'] as $item ) {
280 $_item = new WP_REST_Request( 'PUT', $request->get_route() );
281 $_item->set_body_params( $item );
282
283 $allowed = $this->update_item_permissions_check( $_item );
284 if ( is_wp_error( $allowed ) ) {
285 $response['update'][] = array(
286 'id' => $_item['id'],
287 'error' => array(
288 'code' => $allowed->get_error_code(),
289 'message' => $allowed->get_error_message(),
290 'data' => $allowed->get_error_data(),
291 ),
292 );
293 continue;
294 }
295
296 $_response = $this->update_item( $_item );
297
298 if ( is_wp_error( $_response ) ) {
299 $response['update'][] = array(
300 'id' => $item['id'],
301 'error' => array(
302 'code' => $_response->get_error_code(),
303 'message' => $_response->get_error_message(),
304 'data' => $_response->get_error_data(),
305 ),
306 );
307 } else {
308 $response['update'][] = $wp_rest_server->response_to_data( $_response, '' );
309 }
310 }
311 }
312
313 if ( ! empty( $items['delete'] ) ) {
314 foreach ( $items['delete'] as $id ) {
315 $id = is_array( $id ) ? $id : (int) $id;
316
317 if ( 0 === $id ) {
318 continue;
319 }
320
321 $_item = new WP_REST_Request( 'DELETE', $request->get_route() );
322 if ( is_array( $id ) ) {
323 $id['force'] = true;
324 $_item->set_query_params( $id );
325 } else {
326 $_item->set_query_params(
327 array(
328 'id' => $id,
329 'force' => true,
330 )
331 );
332 }
333
334 $allowed = $this->delete_item_permissions_check( $_item );
335 if ( is_wp_error( $allowed ) ) {
336 $response['delete'][] = array(
337 'id' => $id,
338 'error' => array(
339 'code' => $allowed->get_error_code(),
340 'message' => $allowed->get_error_message(),
341 'data' => $allowed->get_error_data(),
342 ),
343 );
344 continue;
345 }
346
347 $_response = $this->delete_item( $_item );
348
349 if ( is_wp_error( $_response ) ) {
350 $response['delete'][] = array(
351 'id' => $id,
352 'error' => array(
353 'code' => $_response->get_error_code(),
354 'message' => $_response->get_error_message(),
355 'data' => $_response->get_error_data(),
356 ),
357 );
358 } else {
359 $response['delete'][] = $wp_rest_server->response_to_data( $_response, '' );
360 }
361 }
362 }
363
364 return $response;
365 }
366
367 /**
368 * Validate a text value for a text based setting.
369 *
370 * @since 3.0.0
371 * @param string $value Value.
372 * @param array $setting Setting.
373 * @return string
374 */
375 public function validate_setting_text_field( $value, $setting ) {
376 $value = is_null( $value ) ? '' : $value;
377 return wp_kses_post( trim( stripslashes( $value ) ) );
378 }
379
380 /**
381 * Validate select based settings.
382 *
383 * @since 3.0.0
384 * @param string $value Value.
385 * @param array $setting Setting.
386 * @return string|WP_Error
387 */
388 public function validate_setting_select_field( $value, $setting ) {
389 if ( array_key_exists( $value, $setting['options'] ) ) {
390 return $value;
391 } else {
392 return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) );
393 }
394 }
395
396 /**
397 * Validate multiselect based settings.
398 *
399 * @since 3.0.0
400 * @param array $values Values.
401 * @param array $setting Setting.
402 * @return array|WP_Error
403 */
404 public function validate_setting_multiselect_field( $values, $setting ) {
405 if ( empty( $values ) ) {
406 return array();
407 }
408
409 if ( ! is_array( $values ) ) {
410 return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) );
411 }
412
413 $final_values = array();
414 foreach ( $values as $value ) {
415 if ( array_key_exists( $value, $setting['options'] ) ) {
416 $final_values[] = $value;
417 }
418 }
419
420 return $final_values;
421 }
422
423 /**
424 * Validate image_width based settings.
425 *
426 * @since 3.0.0
427 * @param array $values Values.
428 * @param array $setting Setting.
429 * @return string|WP_Error
430 */
431 public function validate_setting_image_width_field( $values, $setting ) {
432 if ( ! is_array( $values ) ) {
433 return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) );
434 }
435
436 $current = $setting['value'];
437 if ( isset( $values['width'] ) ) {
438 $current['width'] = intval( $values['width'] );
439 }
440 if ( isset( $values['height'] ) ) {
441 $current['height'] = intval( $values['height'] );
442 }
443 if ( isset( $values['crop'] ) ) {
444 $current['crop'] = (bool) $values['crop'];
445 }
446 return $current;
447 }
448
449 /**
450 * Validate radio based settings.
451 *
452 * @since 3.0.0
453 * @param string $value Value.
454 * @param array $setting Setting.
455 * @return string|WP_Error
456 */
457 public function validate_setting_radio_field( $value, $setting ) {
458 return $this->validate_setting_select_field( $value, $setting );
459 }
460
461 /**
462 * Validate checkbox based settings.
463 *
464 * @since 3.0.0
465 * @param string $value Value.
466 * @param array $setting Setting.
467 * @return string|WP_Error
468 */
469 public function validate_setting_checkbox_field( $value, $setting ) {
470 if ( in_array( $value, array( 'yes', 'no' ) ) ) {
471 return $value;
472 } elseif ( empty( $value ) ) {
473 $value = isset( $setting['default'] ) ? $setting['default'] : 'no';
474 return $value;
475 } else {
476 return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) );
477 }
478 }
479
480 /**
481 * Validate textarea based settings.
482 *
483 * @since 3.0.0
484 * @since 9.0.0 No longer allows storing IFRAME, which was allowed for "ShareThis" integration no longer found in core.
485 * @param string $value Value.
486 * @param array $setting Setting.
487 * @return string
488 */
489 public function validate_setting_textarea_field( $value, $setting ) {
490 $value = is_null( $value ) ? '' : $value;
491 return wp_kses_post( trim( stripslashes( $value ) ) );
492 }
493
494 /**
495 * Add meta query.
496 *
497 * @since 3.0.0
498 * @param array $args Query args.
499 * @param array $meta_query Meta query.
500 * @return array
501 */
502 protected function add_meta_query( $args, $meta_query ) {
503 if ( empty( $args['meta_query'] ) ) {
504 $args['meta_query'] = array();
505 }
506
507 $args['meta_query'][] = $meta_query;
508
509 return $args['meta_query'];
510 }
511
512 /**
513 * Get the batch schema, conforming to JSON Schema.
514 *
515 * @return array
516 */
517 public function get_public_batch_schema() {
518 $schema = array(
519 '$schema' => 'http://json-schema.org/draft-04/schema#',
520 'title' => 'batch',
521 'type' => 'object',
522 'properties' => array(
523 'create' => array(
524 'description' => __( 'List of created resources.', 'woocommerce' ),
525 'type' => 'array',
526 'context' => array( 'view', 'edit' ),
527 'items' => array(
528 'type' => 'object',
529 ),
530 ),
531 'update' => array(
532 'description' => __( 'List of updated resources.', 'woocommerce' ),
533 'type' => 'array',
534 'context' => array( 'view', 'edit' ),
535 'items' => array(
536 'type' => 'object',
537 ),
538 ),
539 'delete' => array(
540 'description' => __( 'List of delete resources.', 'woocommerce' ),
541 'type' => 'array',
542 'context' => array( 'view', 'edit' ),
543 'items' => array(
544 'type' => 'integer',
545 ),
546 ),
547 ),
548 );
549
550 return $schema;
551 }
552
553 /**
554 * Gets an array of fields to be included on the response.
555 *
556 * Included fields are based on item schema and `_fields=` request argument.
557 * Updated from WordPress 5.3, included into this class to support old versions.
558 *
559 * @since 3.5.0
560 * @param WP_REST_Request $request Full details about the request.
561 * @return array Fields to be included in the response.
562 */
563 public function get_fields_for_response( $request ) {
564 // From xdebug profiling, this method could take upto 25% of request time in index calls.
565 // Cache it and make sure _fields was cached on current request object!
566 // TODO: Submit this caching behavior in core.
567 if ( isset( $this->_fields ) && is_array( $this->_fields ) && $request === $this->_request ) {
568 return $this->_fields;
569 }
570 $this->_request = $request;
571
572 $schema = $this->get_item_schema();
573 $properties = isset( $schema['properties'] ) ? $schema['properties'] : array();
574
575 $additional_fields = $this->get_additional_fields();
576
577 foreach ( $additional_fields as $field_name => $field_options ) {
578 // For back-compat, include any field with an empty schema
579 // because it won't be present in $this->get_item_schema().
580 if ( is_null( $field_options['schema'] ) ) {
581 $properties[ $field_name ] = $field_options;
582 }
583 }
584
585 // Exclude fields that specify a different context than the request context.
586 $context = $request['context'];
587 if ( $context ) {
588 foreach ( $properties as $name => $options ) {
589 if ( ! empty( $options['context'] ) && ! in_array( $context, $options['context'], true ) ) {
590 unset( $properties[ $name ] );
591 }
592 }
593 }
594
595 $fields = array_keys( $properties );
596
597 if ( ! isset( $request['_fields'] ) ) {
598 $this->_fields = $fields;
599 return $fields;
600 }
601 $requested_fields = wp_parse_list( $request['_fields'] );
602 if ( 0 === count( $requested_fields ) ) {
603 $this->_fields = $fields;
604 return $fields;
605 }
606 // Trim off outside whitespace from the comma delimited list.
607 $requested_fields = array_map( 'trim', $requested_fields );
608 // Always persist 'id', because it can be needed for add_additional_fields_to_object().
609 if ( in_array( 'id', $fields, true ) ) {
610 $requested_fields[] = 'id';
611 }
612 // Return the list of all requested fields which appear in the schema.
613 $this->_fields = array_reduce(
614 $requested_fields,
615 function ( $response_fields, $field ) use ( $fields ) {
616 if ( in_array( $field, $fields, true ) ) {
617 $response_fields[] = $field;
618 return $response_fields;
619 }
620 // Check for nested fields if $field is not a direct match.
621 $nested_fields = explode( '.', $field );
622 // A nested field is included so long as its top-level property
623 // is present in the schema.
624 if ( in_array( $nested_fields[0], $fields, true ) ) {
625 $response_fields[] = $field;
626 }
627 return $response_fields;
628 },
629 array()
630 );
631 return $this->_fields;
632 }
633
634 /**
635 * Limit the contents of the meta_data property based on certain request parameters.
636 *
637 * Note that if both `include_meta` and `exclude_meta` are present in the request,
638 * `include_meta` will take precedence.
639 *
640 * @param \WP_REST_Request $request The request.
641 * @param array $meta_data All of the meta data for an object.
642 *
643 * @return array
644 */
645 protected function get_meta_data_for_response( $request, $meta_data ) {
646 $fields = $this->get_fields_for_response( $request );
647 if ( ! in_array( 'meta_data', $fields, true ) ) {
648 return array();
649 }
650
651 $include = (array) $request['include_meta'];
652 $exclude = (array) $request['exclude_meta'];
653
654 if ( ! empty( $include ) ) {
655 $meta_data = array_filter(
656 $meta_data,
657 function ( WC_Meta_Data $item ) use ( $include ) {
658 $data = $item->get_data();
659 return in_array( $data['key'], $include, true );
660 }
661 );
662 } elseif ( ! empty( $exclude ) ) {
663 $meta_data = array_filter(
664 $meta_data,
665 function ( WC_Meta_Data $item ) use ( $exclude ) {
666 $data = $item->get_data();
667 return ! in_array( $data['key'], $exclude, true );
668 }
669 );
670 }
671
672 // Ensure the array indexes are reset so it doesn't get converted to an object in JSON.
673 return array_values( $meta_data );
674 }
675 }
676