PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/includes/api/class-wc-rest-order-notes-controller.php

https://gitlab.com/0072016/woocommerce
PHP | 412 lines | 234 code | 59 blank | 119 comment | 28 complexity | 30b85002912bffd6f93fd0728b02dc07 MD5 | raw file
  1. <?php
  2. /**
  3. * REST API Order Notes controller
  4. *
  5. * Handles requests to the /orders/<order_id>/notes endpoint.
  6. *
  7. * @author WooThemes
  8. * @category API
  9. * @package WooCommerce/API
  10. * @since 2.6.0
  11. */
  12. if ( ! defined( 'ABSPATH' ) ) {
  13. exit;
  14. }
  15. /**
  16. * REST API Order Notes controller class.
  17. *
  18. * @package WooCommerce/API
  19. * @extends WP_REST_Controller
  20. */
  21. class WC_REST_Order_Notes_Controller extends WP_REST_Controller {
  22. /**
  23. * Endpoint namespace.
  24. *
  25. * @var string
  26. */
  27. protected $namespace = 'wc/v1';
  28. /**
  29. * Route base.
  30. *
  31. * @var string
  32. */
  33. protected $rest_base = 'orders/(?P<order_id>[\d]+)/notes';
  34. /**
  35. * Register the routes for order notes.
  36. */
  37. public function register_routes() {
  38. register_rest_route( $this->namespace, '/' . $this->rest_base, array(
  39. array(
  40. 'methods' => WP_REST_Server::READABLE,
  41. 'callback' => array( $this, 'get_items' ),
  42. 'permission_callback' => array( $this, 'get_items_permissions_check' ),
  43. 'args' => $this->get_collection_params(),
  44. ),
  45. array(
  46. 'methods' => WP_REST_Server::CREATABLE,
  47. 'callback' => array( $this, 'create_item' ),
  48. 'permission_callback' => array( $this, 'create_item_permissions_check' ),
  49. 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
  50. 'note' => array(
  51. 'required' => true,
  52. ),
  53. ) ),
  54. ),
  55. 'schema' => array( $this, 'get_public_item_schema' ),
  56. ) );
  57. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', 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. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
  64. ),
  65. ),
  66. array(
  67. 'methods' => WP_REST_Server::DELETABLE,
  68. 'callback' => array( $this, 'delete_item' ),
  69. 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
  70. 'args' => array(
  71. 'force' => array(
  72. 'default' => false,
  73. 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),
  74. ),
  75. ),
  76. ),
  77. 'schema' => array( $this, 'get_public_item_schema' ),
  78. ) );
  79. }
  80. /**
  81. * Check whether a given request has permission to read order notes.
  82. *
  83. * @param WP_REST_Request $request Full details about the request.
  84. * @return WP_Error|boolean
  85. */
  86. public function get_items_permissions_check( $request ) {
  87. if ( ! wc_rest_check_post_permissions( 'shop_order', 'read' ) ) {
  88. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
  89. }
  90. return true;
  91. }
  92. /**
  93. * Check if a given request has access create order notes.
  94. *
  95. * @param WP_REST_Request $request Full details about the request.
  96. * @return boolean
  97. */
  98. public function create_item_permissions_check( $request ) {
  99. if ( ! wc_rest_check_post_permissions( 'shop_order', 'create' ) ) {
  100. return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
  101. }
  102. return true;
  103. }
  104. /**
  105. * Check if a given request has access to read a order note.
  106. *
  107. * @param WP_REST_Request $request Full details about the request.
  108. * @return WP_Error|boolean
  109. */
  110. public function get_item_permissions_check( $request ) {
  111. $post = get_post( (int) $request['order_id'] );
  112. if ( $post && ! wc_rest_check_post_permissions( 'shop_order', 'read', $post->ID ) ) {
  113. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
  114. }
  115. return true;
  116. }
  117. /**
  118. * Check if a given request has access delete a order note.
  119. *
  120. * @param WP_REST_Request $request Full details about the request.
  121. * @return boolean
  122. */
  123. public function delete_item_permissions_check( $request ) {
  124. $post = get_post( (int) $request['order_id'] );
  125. if ( $post && ! wc_rest_check_post_permissions( 'shop_order', 'delete', $post->ID ) ) {
  126. return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
  127. }
  128. return true;
  129. }
  130. /**
  131. * Get order notes from an order.
  132. *
  133. * @param WP_REST_Request $request
  134. * @return array
  135. */
  136. public function get_items( $request ) {
  137. $id = (int) $request['id'];
  138. $order = get_post( (int) $request['order_id'] );
  139. if ( empty( $order->post_type ) || 'shop_order' !== $order->post_type ) {
  140. return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
  141. }
  142. $args = array(
  143. 'post_id' => $order->ID,
  144. 'approve' => 'approve',
  145. 'type' => 'order_note',
  146. );
  147. remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
  148. $notes = get_comments( $args );
  149. add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
  150. $data = array();
  151. foreach ( $notes as $note ) {
  152. $order_note = $this->prepare_item_for_response( $note, $request );
  153. $order_note = $this->prepare_response_for_collection( $order_note );
  154. $data[] = $order_note;
  155. }
  156. return rest_ensure_response( $data );
  157. }
  158. /**
  159. * Create a single order note.
  160. *
  161. * @param WP_REST_Request $request Full details about the request.
  162. * @return WP_Error|WP_REST_Response
  163. */
  164. public function create_item( $request ) {
  165. if ( ! empty( $request['id'] ) ) {
  166. return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) );
  167. }
  168. $order = get_post( (int) $request['order_id'] );
  169. if ( empty( $order->post_type ) || 'shop_order' !== $order->post_type ) {
  170. return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
  171. }
  172. $order = wc_get_order( $order );
  173. // Create the note.
  174. $note_id = $order->add_order_note( $request['note'], $request['customer_note'] );
  175. if ( ! $note_id ) {
  176. return new WP_Error( 'woocommerce_api_cannot_create_order_note', __( 'Cannot create order note, please try again.', 'woocommerce' ), array( 'status' => 500 ) );
  177. }
  178. $note = get_comment( $note_id );
  179. $this->update_additional_fields_for_object( $note, $request );
  180. /**
  181. * Fires after a order note is created or updated via the REST API.
  182. *
  183. * @param WP_Comment $note New order note object.
  184. * @param WP_REST_Request $request Request object.
  185. * @param boolean $creating True when creating item, false when updating.
  186. */
  187. do_action( 'woocommerce_rest_insert_order_note', $note, $request, true );
  188. $request->set_param( 'context', 'edit' );
  189. $response = $this->prepare_item_for_response( $note, $request );
  190. $response = rest_ensure_response( $response );
  191. $response->set_status( 201 );
  192. $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, str_replace( '(?P<order_id>[\d]+)', $order->id, $this->rest_base ), $note_id ) ) );
  193. return $response;
  194. }
  195. /**
  196. * Get a single order note.
  197. *
  198. * @param WP_REST_Request $request Full details about the request.
  199. * @return WP_Error|WP_REST_Response
  200. */
  201. public function get_item( $request ) {
  202. $id = (int) $request['id'];
  203. $order = get_post( (int) $request['order_id'] );
  204. if ( empty( $order->post_type ) || 'shop_order' !== $order->post_type ) {
  205. return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
  206. }
  207. $note = get_comment( $id );
  208. if ( empty( $id ) || empty( $note ) || intval( $note->comment_post_ID ) !== intval( $order->ID ) ) {
  209. return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
  210. }
  211. $order_note = $this->prepare_item_for_response( $note, $request );
  212. $response = rest_ensure_response( $order_note );
  213. return $response;
  214. }
  215. /**
  216. * Delete a single order note.
  217. *
  218. * @param WP_REST_Request $request Full details about the request.
  219. * @return WP_REST_Response|WP_Error
  220. */
  221. public function delete_item( $request ) {
  222. $id = (int) $request['id'];
  223. $force = isset( $request['force'] ) ? (bool) $request['force'] : false;
  224. // We don't support trashing for this type, error out.
  225. if ( ! $force ) {
  226. return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Webhooks do not support trashing.', 'woocommerce' ), array( 'status' => 501 ) );
  227. }
  228. $order = get_post( (int) $request['order_id'] );
  229. if ( empty( $order->post_type ) || 'shop_order' !== $order->post_type ) {
  230. return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order id.', 'woocommerce' ), array( 'status' => 404 ) );
  231. }
  232. $note = get_comment( $id );
  233. if ( empty( $id ) || empty( $note ) || intval( $note->comment_post_ID ) !== intval( $order->ID ) ) {
  234. return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
  235. }
  236. $request->set_param( 'context', 'edit' );
  237. $response = $this->prepare_item_for_response( $note, $request );
  238. $result = wp_delete_comment( $note->comment_ID, true );;
  239. if ( ! $result ) {
  240. return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), 'order_note' ), array( 'status' => 500 ) );
  241. }
  242. /**
  243. * Fires after a order note is deleted or trashed via the REST API.
  244. *
  245. * @param WP_Comment $note The deleted or trashed order note.
  246. * @param WP_REST_Response $response The response data.
  247. * @param WP_REST_Request $request The request sent to the API.
  248. */
  249. do_action( 'woocommerce_rest_delete_order_note', $note, $response, $request );
  250. return $response;
  251. }
  252. /**
  253. * Prepare a single order note output for response.
  254. *
  255. * @param WP_Comment $note Order note object.
  256. * @param WP_REST_Request $request Request object.
  257. * @return WP_REST_Response $response Response data.
  258. */
  259. public function prepare_item_for_response( $note, $request ) {
  260. $data = array(
  261. 'id' => $note->comment_ID,
  262. 'date_created' => wc_rest_prepare_date_response( $note->comment_date_gmt ),
  263. 'note' => $note->comment_content,
  264. 'customer_note' => (bool) get_comment_meta( $note->comment_ID, 'is_customer_note', true ),
  265. );
  266. $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
  267. $data = $this->add_additional_fields_to_object( $data, $request );
  268. $data = $this->filter_response_by_context( $data, $context );
  269. // Wrap the data in a response object.
  270. $response = rest_ensure_response( $data );
  271. $response->add_links( $this->prepare_links( $note ) );
  272. /**
  273. * Filter order note object returned from the REST API.
  274. *
  275. * @param WP_REST_Response $response The response object.
  276. * @param WP_Comment $note Order note object used to create response.
  277. * @param WP_REST_Request $request Request object.
  278. */
  279. return apply_filters( 'woocommerce_rest_prepare_order_note', $response, $note, $request );
  280. }
  281. /**
  282. * Prepare links for the request.
  283. *
  284. * @param WP_Comment $note Delivery order_note object.
  285. * @return array Links for the given order note.
  286. */
  287. protected function prepare_links( $note ) {
  288. $order_id = (int) $note->comment_post_ID;
  289. $base = str_replace( '(?P<order_id>[\d]+)', $order_id, $this->rest_base );
  290. $links = array(
  291. 'self' => array(
  292. 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $note->comment_ID ) ),
  293. ),
  294. 'collection' => array(
  295. 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ),
  296. ),
  297. 'up' => array(
  298. 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $order_id ) ),
  299. ),
  300. );
  301. return $links;
  302. }
  303. /**
  304. * Get the Order Notes schema, conforming to JSON Schema.
  305. *
  306. * @return array
  307. */
  308. public function get_item_schema() {
  309. $schema = array(
  310. '$schema' => 'http://json-schema.org/draft-04/schema#',
  311. 'title' => 'tax',
  312. 'type' => 'order_note',
  313. 'properties' => array(
  314. 'id' => array(
  315. 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
  316. 'type' => 'integer',
  317. 'context' => array( 'view', 'edit' ),
  318. 'readonly' => true,
  319. ),
  320. 'date_created' => array(
  321. 'description' => __( "The date the order note was created, in the site's timezone.", 'woocommerce' ),
  322. 'type' => 'date-time',
  323. 'context' => array( 'view', 'edit' ),
  324. 'readonly' => true,
  325. ),
  326. 'note' => array(
  327. 'description' => __( 'Order note.', 'woocommerce' ),
  328. 'type' => 'string',
  329. 'context' => array( 'view', 'edit' ),
  330. ),
  331. 'customer_note' => array(
  332. 'description' => __( 'Shows/define if the note is only for reference or for the customer (the user will be notified).', 'woocommerce' ),
  333. 'type' => 'boolean',
  334. 'default' => false,
  335. 'context' => array( 'view', 'edit' ),
  336. ),
  337. ),
  338. );
  339. return $this->add_additional_fields_schema( $schema );
  340. }
  341. /**
  342. * Get the query params for collections.
  343. *
  344. * @return array
  345. */
  346. public function get_collection_params() {
  347. return array(
  348. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
  349. );
  350. }
  351. }