WC_REST_Product_Reviews_V1_Controller

REST API Product Reviews Controller Class.

Defined (1)

The class is defined in the following location(s).

/includes/api/v1/class-wc-rest-product-reviews-controller.php  
  1. class WC_REST_Product_Reviews_V1_Controller extends WC_REST_Controller { 
  2.  
  3. /** 
  4. * Endpoint namespace. 
  5. * @var string 
  6. */ 
  7. protected $namespace = 'wc/v1'; 
  8.  
  9. /** 
  10. * Route base. 
  11. * @var string 
  12. */ 
  13. protected $rest_base = 'products/(?P<product_id>[\d]+)/reviews'; 
  14.  
  15. /** 
  16. * Register the routes for product reviews. 
  17. */ 
  18. public function register_routes() { 
  19. register_rest_route( $this->namespace, '/' . $this->rest_base, array( 
  20. 'args' => array( 
  21. 'product_id' => array( 
  22. 'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),  
  23. 'type' => 'integer',  
  24. ),  
  25. 'id' => array( 
  26. 'description' => __( 'Unique identifier for the variation.', 'woocommerce' ),  
  27. 'type' => 'integer',  
  28. ),  
  29. ),  
  30. array( 
  31. 'methods' => WP_REST_Server::READABLE,  
  32. 'callback' => array( $this, 'get_items' ),  
  33. 'permission_callback' => array( $this, 'get_items_permissions_check' ),  
  34. 'args' => $this->get_collection_params(),  
  35. ),  
  36. array( 
  37. 'methods' => WP_REST_Server::CREATABLE,  
  38. 'callback' => array( $this, 'create_item' ),  
  39. 'permission_callback' => array( $this, 'create_item_permissions_check' ),  
  40. 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( 
  41. 'review' => array( 
  42. 'required' => true,  
  43. 'type' => 'string',  
  44. 'description' => __( 'Review content.', 'woocommerce' ),  
  45. ),  
  46. 'name' => array( 
  47. 'required' => true,  
  48. 'type' => 'string',  
  49. 'description' => __( 'Name of the reviewer.', 'woocommerce' ),  
  50. ),  
  51. 'email' => array( 
  52. 'required' => true,  
  53. 'type' => 'string',  
  54. 'description' => __( 'Email of the reviewer.', 'woocommerce' ),  
  55. ),  
  56. ) ),  
  57. ),  
  58. 'schema' => array( $this, 'get_public_item_schema' ),  
  59. ) ); 
  60.  
  61. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( 
  62. 'args' => array( 
  63. 'product_id' => array( 
  64. 'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),  
  65. 'type' => 'integer',  
  66. ),  
  67. 'id' => array( 
  68. 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),  
  69. 'type' => 'integer',  
  70. ),  
  71. ),  
  72. array( 
  73. 'methods' => WP_REST_Server::READABLE,  
  74. 'callback' => array( $this, 'get_item' ),  
  75. 'permission_callback' => array( $this, 'get_item_permissions_check' ),  
  76. 'args' => array( 
  77. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),  
  78. ),  
  79. ),  
  80. array( 
  81. 'methods' => WP_REST_Server::EDITABLE,  
  82. 'callback' => array( $this, 'update_item' ),  
  83. 'permission_callback' => array( $this, 'update_item_permissions_check' ),  
  84. 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),  
  85. ),  
  86. array( 
  87. 'methods' => WP_REST_Server::DELETABLE,  
  88. 'callback' => array( $this, 'delete_item' ),  
  89. 'permission_callback' => array( $this, 'delete_item_permissions_check' ),  
  90. 'args' => array( 
  91. 'force' => array( 
  92. 'default' => false,  
  93. 'type' => 'boolean',  
  94. 'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce' ),  
  95. ),  
  96. ),  
  97. ),  
  98. 'schema' => array( $this, 'get_public_item_schema' ),  
  99. ) ); 
  100.  
  101. /** 
  102. * Check whether a given request has permission to read webhook deliveries. 
  103. * @param WP_REST_Request $request Full details about the request. 
  104. * @return WP_Error|boolean 
  105. */ 
  106. public function get_items_permissions_check( $request ) { 
  107. if ( ! wc_rest_check_post_permissions( 'product', 'read' ) ) { 
  108. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  109.  
  110. return true; 
  111.  
  112. /** 
  113. * Check if a given request has access to read a product review. 
  114. * @param WP_REST_Request $request Full details about the request. 
  115. * @return WP_Error|boolean 
  116. */ 
  117. public function get_item_permissions_check( $request ) { 
  118. $post = get_post( (int) $request['product_id'] ); 
  119.  
  120. if ( $post && ! wc_rest_check_post_permissions( 'product', 'read', $post->ID ) ) { 
  121. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  122.  
  123. return true; 
  124.  
  125. /** 
  126. * Check if a given request has access to create a new product review. 
  127. * @param WP_REST_Request $request Full details about the request. 
  128. * @return WP_Error|boolean 
  129. */ 
  130. public function create_item_permissions_check( $request ) { 
  131. $post = get_post( (int) $request['product_id'] ); 
  132. if ( $post && ! wc_rest_check_post_permissions( 'product', 'create', $post->ID ) ) { 
  133. return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  134. return true; 
  135.  
  136. /** 
  137. * Check if a given request has access to update a product review. 
  138. * @param WP_REST_Request $request Full details about the request. 
  139. * @return WP_Error|boolean 
  140. */ 
  141. public function update_item_permissions_check( $request ) { 
  142. $post = get_post( (int) $request['product_id'] ); 
  143. if ( $post && ! wc_rest_check_post_permissions( 'product', 'edit', $post->ID ) ) { 
  144. return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  145. return true; 
  146.  
  147. /** 
  148. * Check if a given request has access to delete a product review. 
  149. * @param WP_REST_Request $request Full details about the request. 
  150. * @return WP_Error|boolean 
  151. */ 
  152. public function delete_item_permissions_check( $request ) { 
  153. $post = get_post( (int) $request['product_id'] ); 
  154. if ( $post && ! wc_rest_check_post_permissions( 'product', 'delete', $post->ID ) ) { 
  155. return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  156. return true; 
  157.  
  158. /** 
  159. * Get all reviews from a product. 
  160. * @param WP_REST_Request $request 
  161. * @return array 
  162. */ 
  163. public function get_items( $request ) { 
  164. $product_id = (int) $request['product_id']; 
  165.  
  166. if ( 'product' !== get_post_type( $product_id ) ) { 
  167. return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  168.  
  169. $reviews = get_approved_comments( $product_id ); 
  170. $data = array(); 
  171. foreach ( $reviews as $review_data ) { 
  172. $review = $this->prepare_item_for_response( $review_data, $request ); 
  173. $review = $this->prepare_response_for_collection( $review ); 
  174. $data[] = $review; 
  175.  
  176. return rest_ensure_response( $data ); 
  177.  
  178. /** 
  179. * Get a single product review. 
  180. * @param WP_REST_Request $request Full details about the request. 
  181. * @return WP_Error|WP_REST_Response 
  182. */ 
  183. public function get_item( $request ) { 
  184. $id = (int) $request['id']; 
  185. $product_id = (int) $request['product_id']; 
  186.  
  187. if ( 'product' !== get_post_type( $product_id ) ) { 
  188. return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  189.  
  190. $review = get_comment( $id ); 
  191.  
  192. if ( empty( $id ) || empty( $review ) || intval( $review->comment_post_ID ) !== $product_id ) { 
  193. return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  194.  
  195. $delivery = $this->prepare_item_for_response( $review, $request ); 
  196. $response = rest_ensure_response( $delivery ); 
  197.  
  198. return $response; 
  199.  
  200.  
  201. /** 
  202. * Create a product review. 
  203. * @param WP_REST_Request $request Full details about the request. 
  204. * @return WP_Error|WP_REST_Response 
  205. */ 
  206. public function create_item( $request ) { 
  207. $product_id = (int) $request['product_id']; 
  208.  
  209. if ( 'product' !== get_post_type( $product_id ) ) { 
  210. return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  211.  
  212. $prepared_review = $this->prepare_item_for_database( $request ); 
  213.  
  214. /** 
  215. * Filter a product review (comment) before it is inserted via the REST API. 
  216. * Allows modification of the comment right before it is inserted via `wp_insert_comment`. 
  217. * @param array $prepared_review The prepared comment data for `wp_insert_comment`. 
  218. * @param WP_REST_Request $request Request used to insert the comment. 
  219. */ 
  220. $prepared_review = apply_filters( 'rest_pre_insert_product_review', $prepared_review, $request ); 
  221.  
  222. $product_review_id = wp_insert_comment( $prepared_review ); 
  223. if ( ! $product_review_id ) { 
  224. return new WP_Error( 'rest_product_review_failed_create', __( 'Creating product review failed.', 'woocommerce' ), array( 'status' => 500 ) ); 
  225.  
  226. update_comment_meta( $product_review_id, 'rating', ( ! empty( $request['rating'] ) ? $request['rating'] : '0' ) ); 
  227.  
  228. $product_review = get_comment( $product_review_id ); 
  229. $this->update_additional_fields_for_object( $product_review, $request ); 
  230.  
  231. /** 
  232. * Fires after a single item is created or updated via the REST API. 
  233. * @param WP_Comment $product_review Inserted object. 
  234. * @param WP_REST_Request $request Request object. 
  235. * @param boolean $creating True when creating item, false when updating. 
  236. */ 
  237. do_action( "woocommerce_rest_insert_product_review", $product_review, $request, true ); 
  238.  
  239. $request->set_param( 'context', 'edit' ); 
  240. $response = $this->prepare_item_for_response( $product_review, $request ); 
  241. $response = rest_ensure_response( $response ); 
  242. $response->set_status( 201 ); 
  243. $base = str_replace( '(?P<product_id>[\d]+)', $product_id, $this->rest_base ); 
  244. $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $product_review_id ) ) ); 
  245.  
  246. return $response; 
  247.  
  248. /** 
  249. * Update a single product review. 
  250. * @param WP_REST_Request $request Full details about the request. 
  251. * @return WP_Error|WP_REST_Response 
  252. */ 
  253. public function update_item( $request ) { 
  254. $product_review_id = (int) $request['id']; 
  255. $product_id = (int) $request['product_id']; 
  256.  
  257. if ( 'product' !== get_post_type( $product_id ) ) { 
  258. return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  259.  
  260. $review = get_comment( $product_review_id ); 
  261.  
  262. if ( empty( $product_review_id ) || empty( $review ) || intval( $review->comment_post_ID ) !== $product_id ) { 
  263. return new WP_Error( 'woocommerce_rest_product_review_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  264.  
  265. $prepared_review = $this->prepare_item_for_database( $request ); 
  266.  
  267. $updated = wp_update_comment( $prepared_review ); 
  268. if ( 0 === $updated ) { 
  269. return new WP_Error( 'rest_product_review_failed_edit', __( 'Updating product review failed.', 'woocommerce' ), array( 'status' => 500 ) ); 
  270.  
  271. if ( ! empty( $request['rating'] ) ) { 
  272. update_comment_meta( $product_review_id, 'rating', $request['rating'] ); 
  273.  
  274. $product_review = get_comment( $product_review_id ); 
  275. $this->update_additional_fields_for_object( $product_review, $request ); 
  276.  
  277. /** 
  278. * Fires after a single item is created or updated via the REST API. 
  279. * @param WP_Comment $comment Inserted object. 
  280. * @param WP_REST_Request $request Request object. 
  281. * @param boolean $creating True when creating item, false when updating. 
  282. */ 
  283. do_action( "woocommerce_rest_insert_product_review", $product_review, $request, true ); 
  284.  
  285. $request->set_param( 'context', 'edit' ); 
  286. $response = $this->prepare_item_for_response( $product_review, $request ); 
  287.  
  288. return rest_ensure_response( $response ); 
  289.  
  290. /** 
  291. * Delete a product review. 
  292. * @param WP_REST_Request $request Full details about the request 
  293. * @return WP_Error|boolean 
  294. */ 
  295. public function delete_item( $request ) { 
  296. $product_review_id = absint( is_array( $request['id'] ) ? $request['id']['id'] : $request['id'] ); 
  297. $force = isset( $request['force'] ) ? (bool) $request['force'] : false; 
  298.  
  299. $product_review = get_comment( $product_review_id ); 
  300. if ( empty( $product_review_id ) || empty( $product_review->comment_ID ) || empty( $product_review->comment_post_ID ) ) { 
  301. return new WP_Error( 'woocommerce_rest_product_review_invalid_id', __( 'Invalid product review ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  302.  
  303. /** 
  304. * Filter whether a product review is trashable. 
  305. * Return false to disable trash support for the product review. 
  306. * @param boolean $supports_trash Whether the object supports trashing. 
  307. * @param WP_Post $product_review The object being considered for trashing support. 
  308. */ 
  309. $supports_trash = apply_filters( 'rest_product_review_trashable', ( EMPTY_TRASH_DAYS > 0 ), $product_review ); 
  310.  
  311. $request->set_param( 'context', 'edit' ); 
  312. $response = $this->prepare_item_for_response( $product_review, $request ); 
  313.  
  314. if ( $force ) { 
  315. $result = wp_delete_comment( $product_review_id, true ); 
  316. } else { 
  317. if ( ! $supports_trash ) { 
  318. return new WP_Error( 'rest_trash_not_supported', __( 'The product review does not support trashing.', 'woocommerce' ), array( 'status' => 501 ) ); 
  319.  
  320. if ( 'trash' === $product_review->comment_approved ) { 
  321. return new WP_Error( 'rest_already_trashed', __( 'The comment has already been trashed.', 'woocommerce' ), array( 'status' => 410 ) ); 
  322.  
  323. $result = wp_trash_comment( $product_review->comment_ID ); 
  324.  
  325. if ( ! $result ) { 
  326. return new WP_Error( 'rest_cannot_delete', __( 'The product review cannot be deleted.', 'woocommerce' ), array( 'status' => 500 ) ); 
  327.  
  328. /** 
  329. * Fires after a product review is deleted via the REST API. 
  330. * @param object $product_review The deleted item. 
  331. * @param WP_REST_Response $response The response data. 
  332. * @param WP_REST_Request $request The request sent to the API. 
  333. */ 
  334. do_action( 'rest_delete_product_review', $product_review, $response, $request ); 
  335.  
  336. return $response; 
  337.  
  338. /** 
  339. * Prepare a single product review output for response. 
  340. * @param WP_Comment $review Product review object. 
  341. * @param WP_REST_Request $request Request object. 
  342. * @return WP_REST_Response $response Response data. 
  343. */ 
  344. public function prepare_item_for_response( $review, $request ) { 
  345. $data = array( 
  346. 'id' => (int) $review->comment_ID,  
  347. 'date_created' => wc_rest_prepare_date_response( $review->comment_date_gmt ),  
  348. 'review' => $review->comment_content,  
  349. 'rating' => (int) get_comment_meta( $review->comment_ID, 'rating', true ),  
  350. 'name' => $review->comment_author,  
  351. 'email' => $review->comment_author_email,  
  352. 'verified' => wc_review_is_from_verified_owner( $review->comment_ID ),  
  353. ); 
  354.  
  355. $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 
  356. $data = $this->add_additional_fields_to_object( $data, $request ); 
  357. $data = $this->filter_response_by_context( $data, $context ); 
  358.  
  359. // Wrap the data in a response object. 
  360. $response = rest_ensure_response( $data ); 
  361.  
  362. $response->add_links( $this->prepare_links( $review, $request ) ); 
  363.  
  364. /** 
  365. * Filter product reviews object returned from the REST API. 
  366. * @param WP_REST_Response $response The response object. 
  367. * @param WP_Comment $review Product review object used to create response. 
  368. * @param WP_REST_Request $request Request object. 
  369. */ 
  370. return apply_filters( 'woocommerce_rest_prepare_product_review', $response, $review, $request ); 
  371.  
  372. /** 
  373. * Prepare a single product review to be inserted into the database. 
  374. * @param WP_REST_Request $request Request object. 
  375. * @return array|WP_Error $prepared_review 
  376. */ 
  377. protected function prepare_item_for_database( $request ) { 
  378. $prepared_review = array( 'comment_approved' => 1, 'comment_type' => 'review' ); 
  379.  
  380. if ( isset( $request['id'] ) ) { 
  381. $prepared_review['comment_ID'] = (int) $request['id']; 
  382.  
  383. if ( isset( $request['review'] ) ) { 
  384. $prepared_review['comment_content'] = $request['review']; 
  385.  
  386. if ( isset( $request['product_id'] ) ) { 
  387. $prepared_review['comment_post_ID'] = (int) $request['product_id']; 
  388.  
  389. if ( isset( $request['name'] ) ) { 
  390. $prepared_review['comment_author'] = $request['name']; 
  391.  
  392. if ( isset( $request['email'] ) ) { 
  393. $prepared_review['comment_author_email'] = $request['email']; 
  394.  
  395. return apply_filters( 'rest_preprocess_product_review', $prepared_review, $request ); 
  396.  
  397. /** 
  398. * Prepare links for the request. 
  399. * @param WP_Comment $review Product review object. 
  400. * @param WP_REST_Request $request Request object. 
  401. * @return array Links for the given product review. 
  402. */ 
  403. protected function prepare_links( $review, $request ) { 
  404. $product_id = (int) $request['product_id']; 
  405. $base = str_replace( '(?P<product_id>[\d]+)', $product_id, $this->rest_base ); 
  406. $links = array( 
  407. 'self' => array( 
  408. 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $review->comment_ID ) ),  
  409. ),  
  410. 'collection' => array( 
  411. 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ),  
  412. ),  
  413. 'up' => array( 
  414. 'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $product_id ) ),  
  415. ),  
  416. ); 
  417.  
  418. return $links; 
  419.  
  420. /** 
  421. * Get the Product Review's schema, conforming to JSON Schema. 
  422. * @return array 
  423. */ 
  424. public function get_item_schema() { 
  425. $schema = array( 
  426. '$schema' => 'http://json-schema.org/draft-04/schema#',  
  427. 'title' => 'product_review',  
  428. 'type' => 'object',  
  429. 'properties' => array( 
  430. 'id' => array( 
  431. 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),  
  432. 'type' => 'integer',  
  433. 'context' => array( 'view', 'edit' ),  
  434. 'readonly' => true,  
  435. ),  
  436. 'review' => array( 
  437. 'description' => __( 'The content of the review.', 'woocommerce' ),  
  438. 'type' => 'string',  
  439. 'context' => array( 'view', 'edit' ),  
  440. ),  
  441. 'date_created' => array( 
  442. 'description' => __( "The date the review was created, in the site's timezone.", 'woocommerce' ),  
  443. 'type' => 'date-time',  
  444. 'context' => array( 'view', 'edit' ),  
  445. ),  
  446. 'rating' => array( 
  447. 'description' => __( 'Review rating (0 to 5).', 'woocommerce' ),  
  448. 'type' => 'integer',  
  449. 'context' => array( 'view', 'edit' ),  
  450. ),  
  451. 'name' => array( 
  452. 'description' => __( 'Reviewer name.', 'woocommerce' ),  
  453. 'type' => 'string',  
  454. 'context' => array( 'view', 'edit' ),  
  455. ),  
  456. 'email' => array( 
  457. 'description' => __( 'Reviewer email.', 'woocommerce' ),  
  458. 'type' => 'string',  
  459. 'context' => array( 'view', 'edit' ),  
  460. ),  
  461. 'verified' => array( 
  462. 'description' => __( 'Shows if the reviewer bought the product or not.', 'woocommerce' ),  
  463. 'type' => 'boolean',  
  464. 'context' => array( 'view', 'edit' ),  
  465. 'readonly' => true,  
  466. ),  
  467. ),  
  468. ); 
  469.  
  470. return $this->add_additional_fields_schema( $schema ); 
  471.  
  472. /** 
  473. * Get the query params for collections. 
  474. * @return array 
  475. */ 
  476. public function get_collection_params() { 
  477. return array( 
  478. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),  
  479. );