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

  1. <?php 
  2.  
  3. if ( ! defined( 'ABSPATH' ) ) { 
  4. exit; 
  5.  
  6. /** 
  7. * Abstract Rest Posts Controller Class 
  8. * 
  9. * @author WooThemes 
  10. * @category API 
  11. * @package WooCommerce/Abstracts 
  12. * @version 2.6.0 
  13. */ 
  14. abstract class WC_REST_Posts_Controller extends WC_REST_Controller { 
  15.  
  16. /** 
  17. * Endpoint namespace. 
  18. * 
  19. * @var string 
  20. */ 
  21. protected $namespace = 'wc/v1'; 
  22.  
  23. /** 
  24. * Route base. 
  25. * 
  26. * @var string 
  27. */ 
  28. protected $rest_base = ''; 
  29.  
  30. /** 
  31. * Post type. 
  32. * 
  33. * @var string 
  34. */ 
  35. protected $post_type = ''; 
  36.  
  37. /** 
  38. * Controls visibility on frontend. 
  39. * 
  40. * @var string 
  41. */ 
  42. protected $public = false; 
  43.  
  44. /** 
  45. * Check if a given request has access to read items. 
  46. * 
  47. * @param WP_REST_Request $request Full details about the request. 
  48. * @return WP_Error|boolean 
  49. */ 
  50. public function get_items_permissions_check( $request ) { 
  51. if ( ! wc_rest_check_post_permissions( $this->post_type, 'read' ) ) { 
  52. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  53.  
  54. return true; 
  55.  
  56. /** 
  57. * Check if a given request has access to create an item. 
  58. * 
  59. * @param WP_REST_Request $request Full details about the request. 
  60. * @return WP_Error|boolean 
  61. */ 
  62. public function create_item_permissions_check( $request ) { 
  63. if ( ! wc_rest_check_post_permissions( $this->post_type, 'create' ) ) { 
  64. return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  65.  
  66. return true; 
  67.  
  68. /** 
  69. * Check if a given request has access to read an item. 
  70. * 
  71. * @param WP_REST_Request $request Full details about the request. 
  72. * @return WP_Error|boolean 
  73. */ 
  74. public function get_item_permissions_check( $request ) { 
  75. $post = get_post( (int) $request['id'] ); 
  76.  
  77. if ( $post && ! wc_rest_check_post_permissions( $this->post_type, 'read', $post->ID ) ) { 
  78. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  79.  
  80. return true; 
  81.  
  82. /** 
  83. * Check if a given request has access to update an item. 
  84. * 
  85. * @param WP_REST_Request $request Full details about the request. 
  86. * @return WP_Error|boolean 
  87. */ 
  88. public function update_item_permissions_check( $request ) { 
  89. $post = get_post( (int) $request['id'] ); 
  90.  
  91. if ( $post && ! wc_rest_check_post_permissions( $this->post_type, 'edit', $post->ID ) ) { 
  92. return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  93.  
  94. return true; 
  95.  
  96. /** 
  97. * Check if a given request has access to delete an item. 
  98. * 
  99. * @param WP_REST_Request $request Full details about the request. 
  100. * @return bool|WP_Error 
  101. */ 
  102. public function delete_item_permissions_check( $request ) { 
  103. $post = get_post( (int) $request['id'] ); 
  104.  
  105. if ( $post && ! wc_rest_check_post_permissions( $this->post_type, 'delete', $post->ID ) ) { 
  106. return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  107.  
  108. return true; 
  109.  
  110. /** 
  111. * Check if a given request has access batch create, update and delete items. 
  112. * 
  113. * @param WP_REST_Request $request Full details about the request. 
  114. * @return boolean 
  115. */ 
  116. public function batch_items_permissions_check( $request ) { 
  117. if ( ! wc_rest_check_post_permissions( $this->post_type, 'batch' ) ) { 
  118. return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  119.  
  120. return true; 
  121.  
  122. /** 
  123. * Get a single item. 
  124. * 
  125. * @param WP_REST_Request $request Full details about the request. 
  126. * @return WP_Error|WP_REST_Response 
  127. */ 
  128. public function get_item( $request ) { 
  129. $id = (int) $request['id']; 
  130. $post = get_post( $id ); 
  131.  
  132. if ( ! empty( $post->post_type ) && 'product_variation' === $post->post_type && 'product' === $this->post_type ) { 
  133. return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce' ), array( 'status' => 404 ) ); 
  134. } elseif ( empty( $id ) || empty( $post->ID ) || $post->post_type !== $this->post_type ) { 
  135. return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) ); 
  136.  
  137. $data = $this->prepare_item_for_response( $post, $request ); 
  138. $response = rest_ensure_response( $data ); 
  139.  
  140. if ( $this->public ) { 
  141. $response->link_header( 'alternate', get_permalink( $id ), array( 'type' => 'text/html' ) ); 
  142.  
  143. return $response; 
  144.  
  145. /** 
  146. * Create a single item. 
  147. * 
  148. * @param WP_REST_Request $request Full details about the request. 
  149. * @return WP_Error|WP_REST_Response 
  150. */ 
  151. public function create_item( $request ) { 
  152. if ( ! empty( $request['id'] ) ) { 
  153. /** translators: %s: post type */ 
  154. return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) ); 
  155.  
  156. $post = $this->prepare_item_for_database( $request ); 
  157. if ( is_wp_error( $post ) ) { 
  158. return $post; 
  159.  
  160. $post->post_type = $this->post_type; 
  161. $post_id = wp_insert_post( $post, true ); 
  162.  
  163. if ( is_wp_error( $post_id ) ) { 
  164.  
  165. if ( in_array( $post_id->get_error_code(), array( 'db_insert_error' ) ) ) { 
  166. $post_id->add_data( array( 'status' => 500 ) ); 
  167. } else { 
  168. $post_id->add_data( array( 'status' => 400 ) ); 
  169. return $post_id; 
  170. $post->ID = $post_id; 
  171. $post = get_post( $post_id ); 
  172.  
  173. $this->update_additional_fields_for_object( $post, $request ); 
  174.  
  175. // Add meta fields. 
  176. $meta_fields = $this->add_post_meta_fields( $post, $request ); 
  177. if ( is_wp_error( $meta_fields ) ) { 
  178. // Remove post. 
  179. $this->delete_post( $post ); 
  180.  
  181. return $meta_fields; 
  182.  
  183. /** 
  184. * Fires after a single item is created or updated via the REST API. 
  185. * 
  186. * @param WP_Post $post Post object. 
  187. * @param WP_REST_Request $request Request object. 
  188. * @param boolean $creating True when creating item, false when updating. 
  189. */ 
  190. do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true ); 
  191.  
  192. $request->set_param( 'context', 'edit' ); 
  193. $response = $this->prepare_item_for_response( $post, $request ); 
  194. $response = rest_ensure_response( $response ); 
  195. $response->set_status( 201 ); 
  196. $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) ); 
  197.  
  198. return $response; 
  199.  
  200. /** 
  201. * Add post meta fields. 
  202. * 
  203. * @param WP_Post $post 
  204. * @param WP_REST_Request $request 
  205. * @return bool|WP_Error 
  206. */ 
  207. protected function add_post_meta_fields( $post, $request ) { 
  208. return true; 
  209.  
  210. /** 
  211. * Delete post. 
  212. * 
  213. * @param WP_Post $post 
  214. */ 
  215. protected function delete_post( $post ) { 
  216. wp_delete_post( $post->ID, true ); 
  217.  
  218. /** 
  219. * Update a single post. 
  220. * 
  221. * @param WP_REST_Request $request Full details about the request. 
  222. * @return WP_Error|WP_REST_Response 
  223. */ 
  224. public function update_item( $request ) { 
  225. $id = (int) $request['id']; 
  226. $post = get_post( $id ); 
  227.  
  228. if ( ! empty( $post->post_type ) && 'product_variation' === $post->post_type && 'product' === $this->post_type ) { 
  229. return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/<product_id>/variations/<id> endpoint.', 'woocommerce' ), array( 'status' => 404 ) ); 
  230. } elseif ( empty( $id ) || empty( $post->ID ) || $post->post_type !== $this->post_type ) { 
  231. return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) ); 
  232.  
  233. $post = $this->prepare_item_for_database( $request ); 
  234. if ( is_wp_error( $post ) ) { 
  235. return $post; 
  236. // Convert the post object to an array, otherwise wp_update_post will expect non-escaped input. 
  237. $post_id = wp_update_post( (array) $post, true ); 
  238. if ( is_wp_error( $post_id ) ) { 
  239. if ( in_array( $post_id->get_error_code(), array( 'db_update_error' ) ) ) { 
  240. $post_id->add_data( array( 'status' => 500 ) ); 
  241. } else { 
  242. $post_id->add_data( array( 'status' => 400 ) ); 
  243. return $post_id; 
  244.  
  245. $post = get_post( $post_id ); 
  246. $this->update_additional_fields_for_object( $post, $request ); 
  247.  
  248. // Update meta fields. 
  249. $meta_fields = $this->update_post_meta_fields( $post, $request ); 
  250. if ( is_wp_error( $meta_fields ) ) { 
  251. return $meta_fields; 
  252.  
  253. /** 
  254. * Fires after a single item is created or updated via the REST API. 
  255. * 
  256. * @param WP_Post $post Post object. 
  257. * @param WP_REST_Request $request Request object. 
  258. * @param boolean $creating True when creating item, false when updating. 
  259. */ 
  260. do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false ); 
  261.  
  262. $request->set_param( 'context', 'edit' ); 
  263. $response = $this->prepare_item_for_response( $post, $request ); 
  264. return rest_ensure_response( $response ); 
  265.  
  266. /** 
  267. * Get a collection of posts. 
  268. * 
  269. * @param WP_REST_Request $request Full details about the request. 
  270. * @return WP_Error|WP_REST_Response 
  271. */ 
  272. public function get_items( $request ) { 
  273. $args = array(); 
  274. $args['offset'] = $request['offset']; 
  275. $args['order'] = $request['order']; 
  276. $args['orderby'] = $request['orderby']; 
  277. $args['paged'] = $request['page']; 
  278. $args['post__in'] = $request['include']; 
  279. $args['post__not_in'] = $request['exclude']; 
  280. $args['posts_per_page'] = $request['per_page']; 
  281. $args['name'] = $request['slug']; 
  282. $args['post_parent__in'] = $request['parent']; 
  283. $args['post_parent__not_in'] = $request['parent_exclude']; 
  284. $args['s'] = $request['search']; 
  285.  
  286. $args['date_query'] = array(); 
  287. // Set before into date query. Date query must be specified as an array of an array. 
  288. if ( isset( $request['before'] ) ) { 
  289. $args['date_query'][0]['before'] = $request['before']; 
  290.  
  291. // Set after into date query. Date query must be specified as an array of an array. 
  292. if ( isset( $request['after'] ) ) { 
  293. $args['date_query'][0]['after'] = $request['after']; 
  294.  
  295. if ( 'wc/v1' === $this->namespace ) { 
  296. if ( is_array( $request['filter'] ) ) { 
  297. $args = array_merge( $args, $request['filter'] ); 
  298. unset( $args['filter'] ); 
  299.  
  300. // Force the post_type argument, since it's not a user input variable. 
  301. $args['post_type'] = $this->post_type; 
  302.  
  303. /** 
  304. * Filter the query arguments for a request. 
  305. * 
  306. * Enables adding extra arguments or setting defaults for a post 
  307. * collection request. 
  308. * 
  309. * @param array $args Key value array of query var to query value. 
  310. * @param WP_REST_Request $request The request used. 
  311. */ 
  312. $args = apply_filters( "woocommerce_rest_{$this->post_type}_query", $args, $request ); 
  313. $query_args = $this->prepare_items_query( $args, $request ); 
  314.  
  315. $posts_query = new WP_Query(); 
  316. $query_result = $posts_query->query( $query_args ); 
  317.  
  318. $posts = array(); 
  319. foreach ( $query_result as $post ) { 
  320. if ( ! wc_rest_check_post_permissions( $this->post_type, 'read', $post->ID ) ) { 
  321. continue; 
  322.  
  323. $data = $this->prepare_item_for_response( $post, $request ); 
  324. $posts[] = $this->prepare_response_for_collection( $data ); 
  325.  
  326. $page = (int) $query_args['paged']; 
  327. $total_posts = $posts_query->found_posts; 
  328.  
  329. if ( $total_posts < 1 ) { 
  330. // Out-of-bounds, run the query again without LIMIT for total count 
  331. unset( $query_args['paged'] ); 
  332. $count_query = new WP_Query(); 
  333. $count_query->query( $query_args ); 
  334. $total_posts = $count_query->found_posts; 
  335.  
  336. $max_pages = ceil( $total_posts / (int) $query_args['posts_per_page'] ); 
  337.  
  338. $response = rest_ensure_response( $posts ); 
  339. $response->header( 'X-WP-Total', (int) $total_posts ); 
  340. $response->header( 'X-WP-TotalPages', (int) $max_pages ); 
  341.  
  342. $request_params = $request->get_query_params(); 
  343. if ( ! empty( $request_params['filter'] ) ) { 
  344. // Normalize the pagination params. 
  345. unset( $request_params['filter']['posts_per_page'] ); 
  346. unset( $request_params['filter']['paged'] ); 
  347. $base = add_query_arg( $request_params, rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); 
  348.  
  349. if ( $page > 1 ) { 
  350. $prev_page = $page - 1; 
  351. if ( $prev_page > $max_pages ) { 
  352. $prev_page = $max_pages; 
  353. $prev_link = add_query_arg( 'page', $prev_page, $base ); 
  354. $response->link_header( 'prev', $prev_link ); 
  355. if ( $max_pages > $page ) { 
  356. $next_page = $page + 1; 
  357. $next_link = add_query_arg( 'page', $next_page, $base ); 
  358. $response->link_header( 'next', $next_link ); 
  359.  
  360. return $response; 
  361.  
  362. /** 
  363. * Delete a single item. 
  364. * 
  365. * @param WP_REST_Request $request Full details about the request. 
  366. * @return WP_REST_Response|WP_Error 
  367. */ 
  368. public function delete_item( $request ) { 
  369. $id = (int) $request['id']; 
  370. $force = (bool) $request['force']; 
  371. $post = get_post( $id ); 
  372.  
  373. if ( empty( $id ) || empty( $post->ID ) || $post->post_type !== $this->post_type ) { 
  374. return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 404 ) ); 
  375.  
  376. $supports_trash = EMPTY_TRASH_DAYS > 0; 
  377.  
  378. /** 
  379. * Filter whether an item is trashable. 
  380. * 
  381. * Return false to disable trash support for the item. 
  382. * 
  383. * @param boolean $supports_trash Whether the item type support trashing. 
  384. * @param WP_Post $post The Post object being considered for trashing support. 
  385. */ 
  386. $supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_trashable", $supports_trash, $post ); 
  387.  
  388. if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $post->ID ) ) { 
  389. /** translators: %s: post type */ 
  390. return new WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) ); 
  391.  
  392. $request->set_param( 'context', 'edit' ); 
  393. $response = $this->prepare_item_for_response( $post, $request ); 
  394.  
  395. // If we're forcing, then delete permanently. 
  396. if ( $force ) { 
  397. $result = wp_delete_post( $id, true ); 
  398. } else { 
  399. // If we don't support trashing for this type, error out. 
  400. if ( ! $supports_trash ) { 
  401. /** translators: %s: post type */ 
  402. return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ), array( 'status' => 501 ) ); 
  403.  
  404. // Otherwise, only trash if we haven't already. 
  405. if ( 'trash' === $post->post_status ) { 
  406. /** translators: %s: post type */ 
  407. return new WP_Error( 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ), array( 'status' => 410 ) ); 
  408.  
  409. // (Note that internally this falls through to `wp_delete_post` if 
  410. // the trash is disabled.) 
  411. $result = wp_trash_post( $id ); 
  412.  
  413. if ( ! $result ) { 
  414. /** translators: %s: post type */ 
  415. return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array( 'status' => 500 ) ); 
  416.  
  417. /** 
  418. * Fires after a single item is deleted or trashed via the REST API. 
  419. * 
  420. * @param object $post The deleted or trashed item. 
  421. * @param WP_REST_Response $response The response data. 
  422. * @param WP_REST_Request $request The request sent to the API. 
  423. */ 
  424. do_action( "woocommerce_rest_delete_{$this->post_type}", $post, $response, $request ); 
  425.  
  426. return $response; 
  427.  
  428. /** 
  429. * Prepare links for the request. 
  430. * 
  431. * @param WP_Post $post Post object. 
  432. * @param WP_REST_Request $request Request object. 
  433. * @return array Links for the given post. 
  434. */ 
  435. protected function prepare_links( $post, $request ) { 
  436. $links = array( 
  437. 'self' => array( 
  438. 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ),  
  439. ),  
  440. 'collection' => array( 
  441. 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),  
  442. ),  
  443. ); 
  444.  
  445. return $links; 
  446.  
  447. /** 
  448. * Determine the allowed query_vars for a get_items() response and 
  449. * prepare for WP_Query. 
  450. * 
  451. * @param array $prepared_args 
  452. * @param WP_REST_Request $request 
  453. * @return array $query_args 
  454. */ 
  455. protected function prepare_items_query( $prepared_args = array(), $request = null ) { 
  456.  
  457. $valid_vars = array_flip( $this->get_allowed_query_vars() ); 
  458. $query_args = array(); 
  459. foreach ( $valid_vars as $var => $index ) { 
  460. if ( isset( $prepared_args[ $var ] ) ) { 
  461. /** 
  462. * Filter the query_vars used in `get_items` for the constructed query. 
  463. * 
  464. * The dynamic portion of the hook name, $var, refers to the query_var key. 
  465. * 
  466. * @param mixed $prepared_args[ $var ] The query_var value. 
  467. * 
  468. */ 
  469. $query_args[ $var ] = apply_filters( "woocommerce_rest_query_var-{$var}", $prepared_args[ $var ] ); 
  470.  
  471. $query_args['ignore_sticky_posts'] = true; 
  472.  
  473. if ( 'include' === $query_args['orderby'] ) { 
  474. $query_args['orderby'] = 'post__in'; 
  475. } elseif ( 'id' === $query_args['orderby'] ) { 
  476. $query_args['orderby'] = 'ID'; // ID must be capitalized 
  477.  
  478. return $query_args; 
  479.  
  480. /** 
  481. * Get all the WP Query vars that are allowed for the API request. 
  482. * 
  483. * @return array 
  484. */ 
  485. protected function get_allowed_query_vars() { 
  486. global $wp; 
  487.  
  488. /** 
  489. * Filter the publicly allowed query vars. 
  490. * 
  491. * Allows adjusting of the default query vars that are made public. 
  492. * 
  493. * @param array Array of allowed WP_Query query vars. 
  494. */ 
  495. $valid_vars = apply_filters( 'query_vars', $wp->public_query_vars ); 
  496.  
  497. $post_type_obj = get_post_type_object( $this->post_type ); 
  498. if ( current_user_can( $post_type_obj->cap->edit_posts ) ) { 
  499. /** 
  500. * Filter the allowed 'private' query vars for authorized users. 
  501. * 
  502. * If the user has the `edit_posts` capability, we also allow use of 
  503. * private query parameters, which are only undesirable on the 
  504. * frontend, but are safe for use in query strings. 
  505. * 
  506. * To disable anyway, use 
  507. * `add_filter( 'woocommerce_rest_private_query_vars', '__return_empty_array' );` 
  508. * 
  509. * @param array $private_query_vars Array of allowed query vars for authorized users. 
  510. * } 
  511. */ 
  512. $private = apply_filters( 'woocommerce_rest_private_query_vars', $wp->private_query_vars ); 
  513. $valid_vars = array_merge( $valid_vars, $private ); 
  514. // Define our own in addition to WP's normal vars. 
  515. $rest_valid = array( 
  516. 'date_query',  
  517. 'ignore_sticky_posts',  
  518. 'offset',  
  519. 'post__in',  
  520. 'post__not_in',  
  521. 'post_parent',  
  522. 'post_parent__in',  
  523. 'post_parent__not_in',  
  524. 'posts_per_page',  
  525. 'meta_query',  
  526. 'tax_query',  
  527. 'meta_key',  
  528. 'meta_value',  
  529. 'meta_compare',  
  530. 'meta_value_num',  
  531. ); 
  532. $valid_vars = array_merge( $valid_vars, $rest_valid ); 
  533.  
  534. /** 
  535. * Filter allowed query vars for the REST API. 
  536. * 
  537. * This filter allows you to add or remove query vars from the final allowed 
  538. * list for all requests, including unauthenticated ones. To alter the 
  539. * vars for editors only. 
  540. * 
  541. * @param array { 
  542. * Array of allowed WP_Query query vars. 
  543. * 
  544. * @param string $allowed_query_var The query var to allow. 
  545. * } 
  546. */ 
  547. $valid_vars = apply_filters( 'woocommerce_rest_query_vars', $valid_vars ); 
  548.  
  549. return $valid_vars; 
  550.  
  551. /** 
  552. * Get the query params for collections of attachments. 
  553. * 
  554. * @return array 
  555. */ 
  556. public function get_collection_params() { 
  557. $params = parent::get_collection_params(); 
  558.  
  559. $params['context']['default'] = 'view'; 
  560.  
  561. $params['after'] = array( 
  562. 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce' ),  
  563. 'type' => 'string',  
  564. 'format' => 'date-time',  
  565. 'validate_callback' => 'rest_validate_request_arg',  
  566. ); 
  567. $params['before'] = array( 
  568. 'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'woocommerce' ),  
  569. 'type' => 'string',  
  570. 'format' => 'date-time',  
  571. 'validate_callback' => 'rest_validate_request_arg',  
  572. ); 
  573. $params['exclude'] = array( 
  574. 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),  
  575. 'type' => 'array',  
  576. 'items' => array( 
  577. 'type' => 'integer',  
  578. ),  
  579. 'default' => array(),  
  580. 'sanitize_callback' => 'wp_parse_id_list',  
  581. ); 
  582. $params['include'] = array( 
  583. 'description' => __( 'Limit result set to specific ids.', 'woocommerce' ),  
  584. 'type' => 'array',  
  585. 'items' => array( 
  586. 'type' => 'integer',  
  587. ),  
  588. 'default' => array(),  
  589. 'sanitize_callback' => 'wp_parse_id_list',  
  590. ); 
  591. $params['offset'] = array( 
  592. 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),  
  593. 'type' => 'integer',  
  594. 'sanitize_callback' => 'absint',  
  595. 'validate_callback' => 'rest_validate_request_arg',  
  596. ); 
  597. $params['order'] = array( 
  598. 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),  
  599. 'type' => 'string',  
  600. 'default' => 'desc',  
  601. 'enum' => array( 'asc', 'desc' ),  
  602. 'validate_callback' => 'rest_validate_request_arg',  
  603. ); 
  604. $params['orderby'] = array( 
  605. 'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),  
  606. 'type' => 'string',  
  607. 'default' => 'date',  
  608. 'enum' => array( 
  609. 'date',  
  610. 'id',  
  611. 'include',  
  612. 'title',  
  613. 'slug',  
  614. ),  
  615. 'validate_callback' => 'rest_validate_request_arg',  
  616. ); 
  617.  
  618. $post_type_obj = get_post_type_object( $this->post_type ); 
  619.  
  620. if ( isset( $post_type_obj->hierarchical ) && $post_type_obj->hierarchical ) { 
  621. $params['parent'] = array( 
  622. 'description' => __( 'Limit result set to those of particular parent IDs.', 'woocommerce' ),  
  623. 'type' => 'array',  
  624. 'items' => array( 
  625. 'type' => 'integer',  
  626. ),  
  627. 'sanitize_callback' => 'wp_parse_id_list',  
  628. 'default' => array(),  
  629. ); 
  630. $params['parent_exclude'] = array( 
  631. 'description' => __( 'Limit result set to all items except those of a particular parent ID.', 'woocommerce' ),  
  632. 'type' => 'array',  
  633. 'items' => array( 
  634. 'type' => 'integer',  
  635. ),  
  636. 'sanitize_callback' => 'wp_parse_id_list',  
  637. 'default' => array(),  
  638. ); 
  639.  
  640. if ( 'wc/v1' === $this->namespace ) { 
  641. $params['filter'] = array( 
  642. 'type' => 'object',  
  643. 'description' => __( 'Use WP Query arguments to modify the response; private query vars require appropriate authorization.', 'woocommerce' ),  
  644. ); 
  645.  
  646. return $params; 
  647.  
  648. /** 
  649. * Update post meta fields. 
  650. * 
  651. * @param WP_Post $post 
  652. * @param WP_REST_Request $request 
  653. * @return bool|WP_Error 
  654. */ 
  655. protected function update_post_meta_fields( $post, $request ) { 
  656. return true; 
.