/includes/abstracts/abstract-wc-rest-controller.php

  1. <?php 
  2.  
  3. if ( ! defined( 'ABSPATH' ) ) { 
  4. exit; 
  5.  
  6. /** 
  7. * Abstract Rest Controller Class 
  8. * 
  9. * @author WooThemes 
  10. * @category API 
  11. * @package WooCommerce/Abstracts 
  12. * @extends WP_REST_Controller 
  13. * @version 2.6.0 
  14. */ 
  15. abstract class WC_REST_Controller extends WP_REST_Controller { 
  16.  
  17. /** 
  18. * Endpoint namespace. 
  19. * 
  20. * @var string 
  21. */ 
  22. protected $namespace = 'wc/v1'; 
  23.  
  24. /** 
  25. * Route base. 
  26. * 
  27. * @var string 
  28. */ 
  29. protected $rest_base = ''; 
  30.  
  31. /** 
  32. * Add the schema from additional fields to an schema array. 
  33. * 
  34. * The type of object is inferred from the passed schema. 
  35. * 
  36. * @param array $schema Schema array. 
  37. */ 
  38. protected function add_additional_fields_schema( $schema ) { 
  39. if ( empty( $schema['title'] ) ) { 
  40. return $schema; 
  41.  
  42. /** 
  43. * Can't use $this->get_object_type otherwise we cause an inf loop. 
  44. */ 
  45. $object_type = $schema['title']; 
  46.  
  47. $additional_fields = $this->get_additional_fields( $object_type ); 
  48.  
  49. foreach ( $additional_fields as $field_name => $field_options ) { 
  50. if ( ! $field_options['schema'] ) { 
  51. continue; 
  52.  
  53. $schema['properties'][ $field_name ] = $field_options['schema']; 
  54.  
  55. $schema['properties'] = apply_filters( 'woocommerce_rest_' . $object_type . '_schema', $schema['properties'] ); 
  56.  
  57. return $schema; 
  58.  
  59. /** 
  60. * Get normalized rest base. 
  61. * 
  62. * @return string 
  63. */ 
  64. protected function get_normalized_rest_base() { 
  65. return preg_replace( '/\(.*\)\//i', '', $this->rest_base ); 
  66.  
  67. /** 
  68. * Check batch limit. 
  69. * 
  70. * @param array $items Request items. 
  71. * @return bool|WP_Error 
  72. */ 
  73. protected function check_batch_limit( $items ) { 
  74. $limit = apply_filters( 'woocommerce_rest_batch_items_limit', 100, $this->get_normalized_rest_base() ); 
  75. $total = 0; 
  76.  
  77. if ( ! empty( $items['create'] ) ) { 
  78. $total += count( $items['create'] ); 
  79.  
  80. if ( ! empty( $items['update'] ) ) { 
  81. $total += count( $items['update'] ); 
  82.  
  83. if ( ! empty( $items['delete'] ) ) { 
  84. $total += count( $items['delete'] ); 
  85.  
  86. if ( $total > $limit ) { 
  87. /** translators: %s: items limit */ 
  88. 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 ) ); 
  89.  
  90. return true; 
  91.  
  92. /** 
  93. * Bulk create, update and delete items. 
  94. * 
  95. * @param WP_REST_Request $request Full details about the request. 
  96. * @return array Of WP_Error or WP_REST_Response. 
  97. */ 
  98. public function batch_items( $request ) { 
  99. /** @var WP_REST_Server $wp_rest_server */ 
  100. global $wp_rest_server; 
  101.  
  102. // Get the request params. 
  103. $items = array_filter( $request->get_params() ); 
  104. $response = array(); 
  105.  
  106. // Check batch limit. 
  107. $limit = $this->check_batch_limit( $items ); 
  108. if ( is_wp_error( $limit ) ) { 
  109. return $limit; 
  110.  
  111. if ( ! empty( $items['create'] ) ) { 
  112. foreach ( $items['create'] as $item ) { 
  113. $_item = new WP_REST_Request( 'POST' ); 
  114.  
  115. // Default parameters. 
  116. $defaults = array(); 
  117. $schema = $this->get_public_item_schema(); 
  118. foreach ( $schema['properties'] as $arg => $options ) { 
  119. if ( isset( $options['default'] ) ) { 
  120. $defaults[ $arg ] = $options['default']; 
  121. $_item->set_default_params( $defaults ); 
  122.  
  123. // Set request parameters. 
  124. $_item->set_body_params( $item ); 
  125. $_response = $this->create_item( $_item ); 
  126.  
  127. if ( is_wp_error( $_response ) ) { 
  128. $response['create'][] = array( 
  129. 'id' => 0,  
  130. 'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ),  
  131. ); 
  132. } else { 
  133. $response['create'][] = $wp_rest_server->response_to_data( $_response, '' ); 
  134.  
  135. if ( ! empty( $items['update'] ) ) { 
  136. foreach ( $items['update'] as $item ) { 
  137. $_item = new WP_REST_Request( 'PUT' ); 
  138. $_item->set_body_params( $item ); 
  139. $_response = $this->update_item( $_item ); 
  140.  
  141. if ( is_wp_error( $_response ) ) { 
  142. $response['update'][] = array( 
  143. 'id' => $item['id'],  
  144. 'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ),  
  145. ); 
  146. } else { 
  147. $response['update'][] = $wp_rest_server->response_to_data( $_response, '' ); 
  148.  
  149. if ( ! empty( $items['delete'] ) ) { 
  150. foreach ( $items['delete'] as $id ) { 
  151. $id = (int) $id; 
  152.  
  153. if ( 0 === $id ) { 
  154. continue; 
  155.  
  156. $_item = new WP_REST_Request( 'DELETE' ); 
  157. $_item->set_query_params( array( 'id' => $id, 'force' => true ) ); 
  158. $_response = $this->delete_item( $_item ); 
  159.  
  160. if ( is_wp_error( $_response ) ) { 
  161. $response['delete'][] = array( 
  162. 'id' => $id,  
  163. 'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ),  
  164. ); 
  165. } else { 
  166. $response['delete'][] = $wp_rest_server->response_to_data( $_response, '' ); 
  167.  
  168. return $response; 
  169.  
  170. /** 
  171. * Validate a text value for a text based setting. 
  172. * 
  173. * @since 3.0.0 
  174. * @param string $value 
  175. * @param array $setting 
  176. * @return string 
  177. */ 
  178. public function validate_setting_text_field( $value, $setting ) { 
  179. $value = is_null( $value ) ? '' : $value; 
  180. return wp_kses_post( trim( stripslashes( $value ) ) ); 
  181. return $value; 
  182.  
  183. /** 
  184. * Validate select based settings. 
  185. * 
  186. * @since 3.0.0 
  187. * @param string $value 
  188. * @param array $setting 
  189. * @return string|WP_Error 
  190. */ 
  191. public function validate_setting_select_field( $value, $setting ) { 
  192. if ( array_key_exists( $value, $setting['options'] ) ) { 
  193. return $value; 
  194. } else { 
  195. return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); 
  196.  
  197. /** 
  198. * Validate multiselect based settings. 
  199. * 
  200. * @since 3.0.0 
  201. * @param array $values 
  202. * @param array $setting 
  203. * @return string|WP_Error 
  204. */ 
  205. public function validate_setting_multiselect_field( $values, $setting ) { 
  206. if ( empty( $values ) ) { 
  207. return array(); 
  208.  
  209. if ( ! is_array( $values ) ) { 
  210. return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); 
  211.  
  212. $final_values = array(); 
  213. foreach ( $values as $value ) { 
  214. if ( array_key_exists( $value, $setting['options'] ) ) { 
  215. $final_values[] = $value; 
  216.  
  217. return $final_values; 
  218.  
  219. /** 
  220. * Validate image_width based settings. 
  221. * 
  222. * @since 3.0.0 
  223. * @param array $value 
  224. * @param array $setting 
  225. * @return string|WP_Error 
  226. */ 
  227. public function validate_setting_image_width_field( $values, $setting ) { 
  228. if ( ! is_array( $values ) ) { 
  229. return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); 
  230.  
  231. $current = $setting['value']; 
  232. if ( isset( $values['width'] ) ) { 
  233. $current['width'] = intval( $values['width'] ); 
  234. if ( isset( $values['height'] ) ) { 
  235. $current['height'] = intval( $values['height'] ); 
  236. if ( isset( $values['crop'] ) ) { 
  237. $current['crop'] = (bool) $values['crop']; 
  238. return $current; 
  239.  
  240. /** 
  241. * Validate radio based settings. 
  242. * 
  243. * @since 3.0.0 
  244. * @param string $value 
  245. * @param array $setting 
  246. * @return string|WP_Error 
  247. */ 
  248. public function validate_setting_radio_field( $value, $setting ) { 
  249. return $this->validate_setting_select_field( $value, $setting ); 
  250.  
  251. /** 
  252. * Validate checkbox based settings. 
  253. * 
  254. * @since 3.0.0 
  255. * @param string $value 
  256. * @param array $setting 
  257. * @return string|WP_Error 
  258. */ 
  259. public function validate_setting_checkbox_field( $value, $setting ) { 
  260. if ( in_array( $value, array( 'yes', 'no' ) ) ) { 
  261. return $value; 
  262. } elseif ( empty( $value ) ) { 
  263. $value = isset( $setting['default'] ) ? $setting['default'] : 'no'; 
  264. return $value; 
  265. } else { 
  266. return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); 
  267.  
  268. /** 
  269. * Validate textarea based settings. 
  270. * 
  271. * @since 3.0.0 
  272. * @param string $value 
  273. * @param array $setting 
  274. * @return string 
  275. */ 
  276. public function validate_setting_textarea_field( $value, $setting ) { 
  277. $value = is_null( $value ) ? '' : $value; 
  278. return wp_kses( trim( stripslashes( $value ) ),  
  279. array_merge( 
  280. array( 
  281. 'iframe' => array( 'src' => true, 'style' => true, 'id' => true, 'class' => true ),  
  282. ),  
  283. wp_kses_allowed_html( 'post' ) 
  284. ); 
  285.  
  286. /** 
  287. * Add meta query. 
  288. * 
  289. * @since 3.0.0 
  290. * @param array $args Query args. 
  291. * @param array $meta_query Meta query. 
  292. * @return array 
  293. */ 
  294. protected function add_meta_query( $args, $meta_query ) { 
  295. if ( ! empty( $args['meta_query'] ) ) { 
  296. $args['meta_query'] = array(); 
  297.  
  298. $args['meta_query'][] = $meta_query; 
  299.  
  300. return $args['meta_query']; 
  301.  
  302. /** 
  303. * Get the batch schema, conforming to JSON Schema. 
  304. * 
  305. * @return array 
  306. */ 
  307. public function get_public_batch_schema() { 
  308. $schema = array( 
  309. '$schema' => 'http://json-schema.org/draft-04/schema#',  
  310. 'title' => 'batch',  
  311. 'type' => 'object',  
  312. 'properties' => array( 
  313. 'create' => array( 
  314. 'description' => __( 'List of created resources.', 'woocommerce' ),  
  315. 'type' => 'array',  
  316. 'context' => array( 'view', 'edit' ),  
  317. 'items' => array( 
  318. 'type' => 'object',  
  319. ),  
  320. ),  
  321. 'update' => array( 
  322. 'description' => __( 'List of updated resources.', 'woocommerce' ),  
  323. 'type' => 'array',  
  324. 'context' => array( 'view', 'edit' ),  
  325. 'items' => array( 
  326. 'type' => 'object',  
  327. ),  
  328. ),  
  329. 'delete' => array( 
  330. 'description' => __( 'List of delete resources.', 'woocommerce' ),  
  331. 'type' => 'array',  
  332. 'context' => array( 'view', 'edit' ),  
  333. 'items' => array( 
  334. 'type' => 'integer',  
  335. ),  
  336. ),  
  337. ),  
  338. ); 
  339.  
  340. return $schema; 
.